vbMime.cls
上传用户:bcdefg2008
上传日期:2013-02-28
资源大小:144k
文件大小:39k
源码类别:

Email服务器

开发平台:

Visual Basic

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "vbMime"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = True
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. '
  15. '--------------------------------------------------------------------------
  16. Option Explicit
  17. Option Base 0
  18. 'Base64
  19. Private Const CHAR_EQUAL As Byte = 61
  20. Private Const CHAR_CR As Byte = 13
  21. Private Const CHAR_LF As Byte = 10
  22. Private m_ReverseIndex1(0 To 255) As Byte
  23. Private m_ReverseIndex2(0 To 255, 0 To 1) As Byte
  24. Private m_ReverseIndex3(0 To 255, 0 To 1) As Byte
  25. Private m_ReverseIndex4(0 To 255) As Byte
  26. 'Mime
  27. Private m_strMessageText     As String
  28. Private m_strMessageBody     As String
  29. Private m_strHeaders         As String
  30. 'Pop3 Class
  31. 'Dim intMailSelected As Integer
  32. Private Enum POP3States
  33.     POP3_Connect
  34.     POP3_USER
  35.     POP3_PASS
  36.     POP3_STAT
  37.     Pop3_retr
  38.     Pop3_dele
  39.     POP3_QUIT
  40. End Enum
  41. Private m_State       As POP3States
  42. Private m_strPop3Host As String
  43. Private m_strUsername As String
  44. Private m_strPassword As String
  45. Private bolDelMail As Boolean
  46. Private pbExitImmediately As Boolean
  47. Private bRaiseTimeOutError As Boolean
  48. Private pbConnected As Boolean
  49. Private intMessages          As Integer
  50. Private intCurrentMessage    As Integer
  51. Private strBuffer            As String
  52. Private DataPointer&
  53. Private Const BlockSize = 2048
  54. ' Class Events
  55. Private WithEvents Pop3sck As CSocket
  56. Attribute Pop3sck.VB_VarHelpID = -1
  57. Public Event ReceivedSuccesful()
  58. Public Event MimeFailed(Explanation As String)
  59. Public Event Pop3Status(Status As String)
  60. Public Event Progress(PercentComplete As Long)
  61. 'For WaitUntilTrue()
  62. Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
  63. Dim vbBase64 As New base64
  64. '==========
  65. ' Class_Initialize;
  66. ' initializes codec tables.
  67. '==========
  68. Private Sub Class_Initialize()
  69.   'Initiate Winsock
  70.     Set Pop3sck = New CSocket
  71.     
  72.     'initialize the base64 table
  73.     Dim I As Long
  74.     'Setup the encodeing and decoding lookup arrays.
  75.     'Essentially we speed up the routine by pre-shifting
  76.     'the data so it only needs combined with And and Or.
  77.     
  78.     m_ReverseIndex4(65) = 0 'Asc("A")
  79.     m_ReverseIndex4(66) = 1 'Asc("B")
  80.     m_ReverseIndex4(67) = 2 'Asc("C")
  81.     m_ReverseIndex4(68) = 3 'Asc("D")
  82.     m_ReverseIndex4(69) = 4 'Asc("E")
  83.     m_ReverseIndex4(70) = 5 'Asc("F")
  84.     m_ReverseIndex4(71) = 6 'Asc("G")
  85.     m_ReverseIndex4(72) = 7 'Asc("H")
  86.     m_ReverseIndex4(73) = 8 'Asc("I")
  87.     m_ReverseIndex4(74) = 9 'Asc("J")
  88.     m_ReverseIndex4(75) = 10 'Asc("K")
  89.     m_ReverseIndex4(76) = 11 'Asc("L")
  90.     m_ReverseIndex4(77) = 12 'Asc("M")
  91.     m_ReverseIndex4(78) = 13 'Asc("N")
  92.     m_ReverseIndex4(79) = 14 'Asc("O")
  93.     m_ReverseIndex4(80) = 15 'Asc("P")
  94.     m_ReverseIndex4(81) = 16 'Asc("Q")
  95.     m_ReverseIndex4(82) = 17 'Asc("R")
  96.     m_ReverseIndex4(83) = 18 'Asc("S")
  97.     m_ReverseIndex4(84) = 19 'Asc("T")
  98.     m_ReverseIndex4(85) = 20 'Asc("U")
  99.     m_ReverseIndex4(86) = 21 'Asc("V")
  100.     m_ReverseIndex4(87) = 22 'Asc("W")
  101.     m_ReverseIndex4(88) = 23 'Asc("X")
  102.     m_ReverseIndex4(89) = 24 'Asc("Y")
  103.     m_ReverseIndex4(90) = 25 'Asc("Z")
  104.     m_ReverseIndex4(97) = 26 'Asc("a")
  105.     m_ReverseIndex4(98) = 27 'Asc("b")
  106.     m_ReverseIndex4(99) = 28 'Asc("c")
  107.     m_ReverseIndex4(100) = 29 'Asc("d")
  108.     m_ReverseIndex4(101) = 30 'Asc("e")
  109.     m_ReverseIndex4(102) = 31 'Asc("f")
  110.     m_ReverseIndex4(103) = 32 'Asc("g")
  111.     m_ReverseIndex4(104) = 33 'Asc("h")
  112.     m_ReverseIndex4(105) = 34 'Asc("i")
  113.     m_ReverseIndex4(106) = 35 'Asc("j")
  114.     m_ReverseIndex4(107) = 36 'Asc("k")
  115.     m_ReverseIndex4(108) = 37 'Asc("l")
  116.     m_ReverseIndex4(109) = 38 'Asc("m")
  117.     m_ReverseIndex4(110) = 39 'Asc("n")
  118.     m_ReverseIndex4(111) = 40 'Asc("o")
  119.     m_ReverseIndex4(112) = 41 'Asc("p")
  120.     m_ReverseIndex4(113) = 42 'Asc("q")
  121.     m_ReverseIndex4(114) = 43 'Asc("r")
  122.     m_ReverseIndex4(115) = 44 'Asc("s")
  123.     m_ReverseIndex4(116) = 45 'Asc("t")
  124.     m_ReverseIndex4(117) = 46 'Asc("u")
  125.     m_ReverseIndex4(118) = 47 'Asc("v")
  126.     m_ReverseIndex4(119) = 48 'Asc("w")
  127.     m_ReverseIndex4(120) = 49 'Asc("x")
  128.     m_ReverseIndex4(121) = 50 'Asc("y")
  129.     m_ReverseIndex4(122) = 51 'Asc("z")
  130.     m_ReverseIndex4(48) = 52 'Asc("0")
  131.     m_ReverseIndex4(49) = 53 'Asc("1")
  132.     m_ReverseIndex4(50) = 54 'Asc("2")
  133.     m_ReverseIndex4(51) = 55 'Asc("3")
  134.     m_ReverseIndex4(52) = 56 'Asc("4")
  135.     m_ReverseIndex4(53) = 57 'Asc("5")
  136.     m_ReverseIndex4(54) = 58 'Asc("6")
  137.     m_ReverseIndex4(55) = 59 'Asc("7")
  138.     m_ReverseIndex4(56) = 60 'Asc("8")
  139.     m_ReverseIndex4(57) = 61 'Asc("9")
  140.     m_ReverseIndex4(43) = 62 'Asc("+")
  141.     m_ReverseIndex4(47) = 63 'Asc("/")
  142.     'Calculate the other arrays.
  143.     For I = 0 To 255
  144.         If m_ReverseIndex4(I) <> 0 Then
  145.             m_ReverseIndex1(I) = m_ReverseIndex4(I) * 4
  146.             m_ReverseIndex2(I, 0) = m_ReverseIndex4(I)  16
  147.             m_ReverseIndex2(I, 1) = (m_ReverseIndex4(I) And &HF) * 16
  148.             m_ReverseIndex3(I, 0) = m_ReverseIndex4(I)  4
  149.             m_ReverseIndex3(I, 1) = (m_ReverseIndex4(I) And &H3) * 64
  150.         End If
  151.     Next I
  152.     
  153. End Sub
  154. Private Sub Class_Terminate()
  155.   ' make sure sckMail is closed
  156.     If Pop3sck.State <> sckClosed Then
  157.         Pop3sck.CloseSocket
  158.     End If
  159.     ' release memory
  160.     Set Pop3sck = Nothing
  161. End Sub
  162. Public Sub GetMail(strUsername As String, strPassword As String, strHost As String, Optional intPort As Integer)
  163.     m_strPop3Host = strHost
  164.     m_strUsername = strUsername
  165.     m_strPassword = strPassword
  166.     'Change current state of session
  167.     m_State = POP3_Connect
  168.     '
  169.     'Reset current state of socket
  170.     Pop3sck.CloseSocket
  171.     '
  172.     'Reset local port value to prevent "Address in use" error
  173.     Pop3sck.LocalPort = 0
  174.     '
  175.     'POP3 server software is listening for client connection
  176.     'requests on 110 port, therefore we need connect to host
  177.     'on 110 port
  178.     If intPort = 0 Then
  179.         intPort = 110
  180.     End If
  181.     RaiseEvent Pop3Status("Connecting to Pop3 Server...")
  182.     
  183.     Pop3sck.Connect m_strPop3Host, intPort
  184.     
  185.     Call WaitUntilTrue(pbConnected, 30, True)
  186. End Sub
  187. Private Sub Pop3sck_OnConnect()
  188.     pbConnected = True
  189.     RaiseEvent Pop3Status("")
  190. End Sub
  191. 'Retrieves all waiting E-Mails and send the raw E-Mail to the
  192. 'ParseMail function
  193. Private Sub Pop3sck_OnDataArrival(ByVal lngBytesTotal As Long)
  194.   Dim strData As String
  195.     '  Static intMessages          As Integer
  196.     '  Static intCurrentMessage    As Integer
  197.     '  Static strBuffer            As String
  198.     'Dim intSwap As Integer
  199.     
  200.    ' On Error GoTo error
  201.     'Retrieve, received from server, data.
  202.     Pop3sck.GetData strData
  203.     If Left$(strData, 1) = "+" Or m_State = Pop3_retr Then
  204.         'If first symbol of server response is "+"
  205.         'server has accepted previous client command
  206.         'and it is waiting for next actions.
  207.         Select Case m_State
  208.             'This should be tohe most realistic case
  209.           Case Pop3_retr
  210.             '
  211.             'Accumulate message data in strBuffer static variable
  212.             'Set initial condition
  213.             If Len(strBuffer) = 0 Then DataPointer = 1
  214.             'Test to see if new string will fit within current strBuffer
  215.             If (DataPointer + Len(strData)) > Len(strBuffer) Then
  216.                 'If not, allocate more memory
  217.                 strBuffer = strBuffer & Space$(Len(strData) + BlockSize)
  218.             End If
  219.             'Assign the new data
  220.             Mid$(strBuffer, DataPointer, Len(strData)) = strData
  221.             'Move pointer to end of new data
  222.             DataPointer = DataPointer + Len(strData)
  223.             '
  224.             'Until we have been found single dot symbol on a line.
  225.             If InStr(1, strBuffer, vbLf & "." & vbCrLf) Then
  226.                 '
  227.                 'OK! We have received a message.
  228.                 '
  229.                 'Remove server response string
  230.                 strBuffer = Mid$(strBuffer, InStr(1, strBuffer, vbCrLf) + 2)
  231.                 '
  232.                 'Remove dot symbol that is at the end of a message
  233.                 strBuffer = Left$(strBuffer, Len(strBuffer) - 3)
  234.                 '
  235.                 RaiseEvent Pop3Status("Decode Mail..." & CStr(intCurrentMessage))
  236.                 ParseMail strBuffer, intCurrentMessage
  237.                 
  238.         
  239.                 '
  240.                 'Clear buffer for next message
  241.                 strBuffer = ""
  242.                 '
  243.                 If intCurrentMessage = intMessages Then
  244.                     '
  245.                     'We have received all messages, and
  246.                     'we need say QUIT
  247.                     AttachmentCounter = 0
  248.                     intCurrentMessage = 1
  249.                     
  250.                     If bolDelMail Then
  251.                         m_State = Pop3_dele
  252.                         RaiseEvent Pop3Status("All mails received!")
  253.                         Pop3sck.SendData "DELE " & intCurrentMessage & vbCrLf
  254.                     Else
  255.                         m_State = POP3_QUIT
  256.                         RaiseEvent Pop3Status("All mails received!")
  257.                         Pop3sck.SendData "QUIT" & vbCrLf
  258.                     End If
  259.                     
  260.                   Else
  261.                     '
  262.                     'We have messages to download
  263.                     'Increase message counter
  264.                     intCurrentMessage = intCurrentMessage + 1
  265.                     '
  266.                     'Change current state of session
  267.                     m_State = Pop3_retr
  268.                     '
  269.                     'Send RETR command to download next message
  270.                     RaiseEvent Pop3Status("Receive next mail...")
  271.                     Pop3sck.SendData "RETR " & _
  272.                                      CStr(intCurrentMessage) & vbCrLf
  273.                 End If
  274.             End If
  275.           Case POP3_Connect
  276.             '
  277.             'Reset message counter
  278.             intMessages = 0
  279.             intCurrentMessage = 0
  280.             '
  281.             'Change current state of session
  282.             m_State = POP3_USER
  283.             '
  284.             'Send to server USER command to tell him
  285.             'which mailbox we want check out
  286.             RaiseEvent Pop3Status("Authenticate User...")
  287.             Pop3sck.SendData "USER " & m_strUsername & vbCrLf
  288.           Case POP3_USER
  289.             '
  290.             'Change current state of session
  291.             m_State = POP3_PASS
  292.             '
  293.             'Send password with PASS command
  294.             RaiseEvent Pop3Status("Send Password...")
  295.             Pop3sck.SendData "PASS " & m_strPassword & vbCrLf
  296.           Case POP3_PASS
  297.             '
  298.             'Change current state of session
  299.             m_State = POP3_STAT
  300.             '
  301.             'Send STAT command to know how many
  302.             'messages in the mailbox
  303.             RaiseEvent Pop3Status("Get Number of E-Mails...")
  304.             Pop3sck.SendData "STAT" & vbCrLf
  305.           Case POP3_STAT
  306.             '
  307.             'Parse server response to get number
  308.             'of messages in the mailbox
  309.             intMessages = CInt(Mid$(strData, 5, _
  310.                           InStr(5, strData, " ") - 5))
  311.             If intMessages > 0 Then
  312.                 'Redim Buffer to download all Mails
  313.                 ReDim Mails(intMessages - 1)
  314.                 '
  315.                 'OK! We have one or more.
  316.                 'Change current state of session
  317.                 m_State = Pop3_retr
  318.                 '
  319.                 'Increase counter to know wich message
  320.                 'we will retrieving
  321.                 intCurrentMessage = intCurrentMessage + 1
  322.                 '
  323.                 'And send RETR command to download
  324.                 'first message
  325.                 Pop3sck.SendData "RETR 1" & vbCrLf
  326.               Else
  327.                 '
  328.                 'We have not any message in the mailbox.
  329.                 'Send QUIT command and show to user a message
  330.                 'that she or he has not mail.
  331.                 m_State = POP3_QUIT
  332.                 Pop3sck.SendData "QUIT" & vbCrLf
  333.                 RaiseEvent Pop3Status("You have not mail!")
  334.             End If
  335.             
  336.           Case Pop3_dele
  337.             If intCurrentMessage = intMessages Then
  338.                 m_State = POP3_QUIT
  339.                 Pop3sck.SendData "QUIT" & vbCrLf
  340.             Else
  341.                 m_State = Pop3_dele
  342.                 intCurrentMessage = intCurrentMessage + 1
  343.                 Pop3sck.SendData "DELE " & intCurrentMessage & vbCrLf
  344.                 
  345.             End If
  346.             
  347.           Case POP3_QUIT
  348.             AttachmentCounter = 0
  349.             RaiseEvent Pop3Status("")
  350.             RaiseEvent ReceivedSuccesful
  351.             Pop3sck.CloseSocket
  352.         End Select
  353.       Else
  354. error:
  355.         'Hide Status
  356.         RaiseEvent Pop3Status("")
  357.         'Show Error
  358.         RaiseEvent MimeFailed(strData)
  359.         Pop3sck.CloseSocket
  360.     End If
  361. End Sub
  362. Private Sub Pop3sck_OnError(ByVal intNumber As Integer, strDescription As String, ByVal lngScode As Long, ByVal strSource As String, ByVal strHelpFile As String, ByVal lngHelpContext As Long, fCancelDisplay As Boolean)
  363.     RaiseEvent MimeFailed("Winsock Error: #" & intNumber & "Desc: " & strDescription)
  364. End Sub
  365. Public Sub ParseMail(strMessage As String, MailCounter As Integer)
  366.   Dim intPosA         As Long
  367.   Dim intPosB         As Long
  368.   Dim intPos          As Long
  369.   Dim intCount        As Long
  370.   Dim intFrom         As Long
  371.   Dim intTo           As Long
  372.   Dim intTemp         As Long
  373.   Dim EndBoundary     As Long
  374.   'Dim Counter         As Long
  375.   Dim Counter2        As Long
  376.   Dim vHeaders        As Variant
  377.   Dim strTemp         As String
  378.   Dim BoundArray      As Variant
  379.   Dim strHeader       As String
  380.   Dim strHeaderName   As String
  381.   Dim strHeaderValue  As String
  382.   Dim TmpString       As String
  383.   Dim Boundary        As String
  384.   Dim BoundaryVal     As String
  385.   Dim strFilename     As String
  386.   Dim MimeHeaders()   As String
  387.     intPosA = InStr(1, strMessage, vbCrLf & vbCrLf)
  388.     'A little Error Check
  389.     If Not intPosA > 0 Then
  390.         Exit Sub
  391.     End If
  392.     'Only the Mail Headers
  393.     m_strHeaders = Left$(strMessage, intPosA - 1)
  394.     'E-Mail + Attachments
  395.     m_strMessageBody = Right$(strMessage, Len(strMessage) - intPosA - 3)
  396.     'Whole E-Mail (Header + Message + Attachments)
  397.     m_strMessageText = strMessage
  398.     'Hmm I try to unfold the Mail Header...
  399.     m_strHeaders = Replace(m_strHeaders, vbCrLf + Chr$(9), " ")
  400.     m_strHeaders = Replace(m_strHeaders, vbCrLf + Chr$(11), " ")
  401.     m_strHeaders = Replace(m_strHeaders, vbCrLf + Chr$(32), " ")
  402.     m_strHeaders = Replace(m_strHeaders, vbCrLf + Chr$(255), " ")
  403.     'Parse Mail Header and save data
  404.     vHeaders = Split(m_strHeaders, vbCrLf)
  405.     intFrom = LBound(vHeaders)
  406.     intTo = UBound(vHeaders)
  407.     For intTemp = intFrom To intTo
  408.         strHeader = vHeaders(intTemp)
  409.         intPosA = InStr(1, strHeader, ":")
  410.         If intPosA Then
  411.             strHeaderName = LCase$(Left$(strHeader, intPosA - 1))
  412.           Else
  413.             strHeaderName = ""
  414.         End If
  415.         strHeaderValue = Trim$(Right$(strHeader, Len(strHeader) - intPosA))
  416.         With Mails(MailCounter - 1)
  417.             Select Case LCase$(strHeaderName)
  418.               Case "from"
  419.                 .from = DecodeIso(strHeaderValue)
  420.               Case "to"
  421.                 .To = DecodeIso(strHeaderValue)
  422.               Case "subject"
  423.                 .Subject = DecodeIso(strHeaderValue)
  424.               Case "date"
  425.                 .Date = DecodeIso(strHeaderValue)
  426.             End Select
  427.         End With
  428.     Next  'VFIELD INTTEMP
  429.     intFrom = 0
  430.     intTo = 0
  431.     Mails(MailCounter - 1).Size = Len(m_strMessageText)
  432.     Mails(MailCounter - 1).Header = m_strHeaders
  433. '+++++++++++++++++++++ All Headers Processed, now decode the Mail!++++++++++++++++++
  434.     'Load the Mail line by line into an array
  435.     strlines = Split(m_strMessageText, vbCrLf)
  436.     'Free some Memory
  437.     m_strMessageText = ""
  438.     m_strHeaders = ""
  439.     'Search for Attachments
  440.     Boundary = "boundary="
  441.     intPosA = findLine(0, Boundary, strlines(), True)
  442.     'Check if the Mail have Mime Attachments
  443.     If intPosA = -1 Then
  444.         GoTo Plaintext
  445.     End If
  446.     'Get all boundary Strings
  447.     Do Until intPosA = -1
  448.         intPosA = findLine(intPosA, Boundary, strlines(), True)
  449.         If intPosA <> -1 Then
  450.             strTemp = GetInfo(intPosA, Boundary, strlines())
  451.             BoundaryVal = BoundaryVal + " " + "--" + strTemp
  452.             intPosA = intPosA + 1
  453.         End If
  454.     Loop
  455.     'Convert to Array
  456.     BoundArray = Split(Trim$(BoundaryVal), " ")
  457.     intFrom = LBound(BoundArray)
  458.     intTo = UBound(BoundArray)
  459.     'Now we extract all Attachments!
  460.     intTemp = findLine(0, Boundary, strlines())
  461.     
  462.     For Counter2 = intFrom To intTo
  463.         BoundaryVal = BoundArray(Counter2)
  464.         intPosA = intTemp
  465.         'Search Last Boundary
  466.         EndBoundary = RevfindLine(BoundaryVal + "--", strlines())
  467.         
  468.         If EndBoundary = -1 Then
  469.             EndBoundary = RevfindEmptyLine(strlines())
  470.         End If
  471.         Do Until intPosA >= EndBoundary
  472.             intPosA = findLine(intPosA, BoundaryVal, strlines())
  473.             intPosB = findLine(intPosA + 1, BoundaryVal, strlines())
  474.             
  475.             If intPosB = -1 Then
  476.                 intPosB = RevfindEmptyLine(strlines())
  477.             End If
  478.             
  479.             intPos = findLine(intPosA, "Content-Type:", strlines())
  480.             'Prevent extracting several "Sub"Attachments
  481.             If intPos <> -1 Then
  482.                 If InStr(LCase$(strlines(intPos)), "boundary=") > 0 Then
  483.                     GoTo Skip
  484.                 End If
  485.             End If
  486.             'Extract Attachment
  487.             'First copy Mail to temp Array
  488.             ptSpan = strlines
  489.             'Move temp Array to destination array
  490.             MoveStringArray ptSpan, strLine, intPosA + 1, intPosB - 1
  491.             intCount = 0
  492.             'This Part should be worked out => please Mail me your suggestions
  493.             'It's pure US Plaintext
  494.             If intPos = -1 Then
  495.                 TmpString = DecodeAttachment(strLine)
  496.                 Mails(MailCounter - 1).Message = TmpString
  497.                 GoTo Skip
  498.             End If
  499.             If InStr(LCase$(strlines(intPos)), "text/html") > 0 Then
  500.                 TmpString = DecodeAttachment(strLine)
  501.                 Mails(MailCounter - 1).HTMLMessage = TmpString
  502.                 GoTo Skip
  503.             End If
  504.             If InStr(LCase$(strlines(intPos)), "text") > 0 Then
  505.                 TmpString = DecodeAttachment(strLine)
  506.                 Mails(MailCounter - 1).Message = TmpString
  507.                 GoTo Skip
  508.             End If
  509.             If InStr(LCase$(strlines(intPos)), "multipart") > 0 Then
  510.                 TmpString = DecodeAttachment(strLine)
  511.                 Mails(MailCounter - 1).Message = TmpString
  512.                 GoTo Skip
  513.             End If
  514.             'Search the Filename
  515.             intPos = findEmptyLine(0, strLine)
  516.             If intPos <> -1 Then
  517.                 MimeHeaders = UnfoldArray(0, intPos, strLine)
  518.                 intPos = findLine(0, "name=", MimeHeaders, True)
  519.                 strFilename = GetInfo(intPos, "name=", MimeHeaders)
  520.               Else
  521.                 intPos = findLine(0, "name=", strLine(), True)
  522.                 strFilename = GetInfo(intPos, "name=", strLine())
  523.             End If
  524.             strFilename = DecodeIso(strFilename)
  525.             If strFilename = "" Then
  526.                 strFilename = "unnamed"
  527.             End If
  528.             'Save Attachment
  529.             AddAttachment MailCounter - 1, strLine, strFilename
  530.             AttachmentCounter = AttachmentCounter + 1
  531. Skip:
  532.             intPosA = intPosB
  533.         Loop
  534.     Next Counter2
  535.     
  536.     AttachmentCounter = 0
  537. Exit Sub
  538. Plaintext:
  539.     intPos = findLine(1, "Content-Type:", strlines())
  540.     m_strMessageBody = DecodeAttachment(strlines())
  541.     If intPos > 0 Then
  542.         If InStr(LCase$(strlines(intPos)), "text/html") > 0 Then
  543.             Mails(MailCounter - 1).HTMLMessage = m_strMessageBody
  544.           Else
  545.             Mails(MailCounter - 1).Message = m_strMessageBody
  546.         End If
  547.       Else
  548.         'Save the E-Mail
  549.         Mails(MailCounter - 1).Message = m_strMessageBody
  550.     End If
  551.     AttachmentCounter = 0
  552.     Erase strlines
  553. End Sub
  554. Public Function DecodeAttachment(ByRef Encoded() As String) As String
  555.   Dim tmpEncoding   As String
  556.   Dim tmpAttachment As String
  557.   Dim intPosA       As Long
  558.   Dim intPosB       As Long
  559.   'Dim Counter       As Long
  560.   Dim tmplong       As Long
  561.   Dim Attachment() As String
  562.     On Error GoTo error
  563.     Attachment = Encoded
  564.     tmplong = UBound(Attachment)
  565.     If Not tmplong > 0 Then
  566.         DecodeAttachment = ""
  567.         Exit Function
  568.     End If
  569.     '1. What kind of Attachment is it?
  570.     'Get Encoding-Type
  571.     intPosA = findLine(0, "Content-Transfer-Encoding:", Attachment())
  572.     If intPosA <> -1 Then
  573.         tmpEncoding = GetInfo(intPosA, "Content-Transfer-Encoding:", Attachment())
  574.       Else
  575.         intPosA = 0
  576.     End If
  577.     'After the empty line the attachment waits for us!
  578.     intPosA = findEmptyLine(intPosA, Attachment()) + 1
  579.     'Extract Attachment
  580.     '2. Decode it
  581.     Select Case True
  582.       Case InStr(LCase$(tmpEncoding), "base64") > 0
  583.         'Very Fast Array Copy Routine (about 10x)!
  584.         MoveStringArray Attachment, ptSpan, intPosA, tmplong
  585.         tmpAttachment = Join(ptSpan, "")
  586.         'tmpEncoding = tmpAttachment
  587.         
  588.         '2x times  faster (65 ms 120 ms)
  589.         tmpAttachment = Decode(tmpAttachment)
  590.         
  591.         
  592.       Case InStr(LCase$(tmpEncoding), "x-uue") > 0
  593.         tmplong = RevfindLine("end", Attachment) - 1
  594.         If tmplong = -1 Then
  595.             tmplong = UBound(Attachment)
  596.         End If
  597.         
  598.         'Very Fast Array Copy Routine (about 10x)!
  599.         MoveStringArray Attachment, ptSpan, intPosA, tmplong
  600.         
  601.         intPosB = 0
  602.         tmpAttachment = Join(ptSpan, vbCrLf)
  603.         tmpAttachment = Replace(tmpAttachment, Chr$(0), "")
  604.         tmpAttachment = DecodeUUE(tmpAttachment)
  605.       Case InStr(LCase$(tmpEncoding), "quoted-printable") > 0
  606.         'Very Fast Array Copy Routine (about 10x)!
  607.         MoveStringArray Attachment, ptSpan, intPosA, tmplong
  608.         tmpAttachment = Join(ptSpan, "=_")
  609.         tmpAttachment = Replace(tmpAttachment, Chr$(0), "")
  610.         tmpAttachment = DecodeQP(tmpAttachment)
  611.       Case Else
  612.         'Very Fast Array Copy Routine (about 10x)!
  613.         MoveStringArray Attachment, ptSpan, intPosA, tmplong
  614.         tmpAttachment = Join(ptSpan, vbCrLf)
  615.         tmpAttachment = Replace(tmpAttachment, Chr$(0), "")
  616.     End Select
  617.     DecodeAttachment = tmpAttachment
  618.     Erase ptSpan
  619. Exit Function
  620. error:
  621.     DecodeAttachment = ""
  622. End Function
  623. 'Saves the attachment into an UDT
  624. Private Sub AddAttachment(intMail As Integer, strLine() As String, strFilename As String)
  625.   Dim intElements As Integer
  626.   Dim intBlockSize As Integer
  627.   Dim intCounter As Integer
  628.     On Error GoTo error
  629.     intCounter = Mails(intMail).AttachedFiles + 1
  630.     intElements = UBound(Mails(intMail).Attachments())
  631.     If intElements > 0 Then
  632.         intBlockSize = 10
  633.         If intCounter - 1 > intElements Then
  634.             ReDim Preserve Mails(intMail).Attachments(intElements + intBlockSize)
  635.         End If
  636.       Else
  637.         'Initiate the Mail UDT for the first time
  638. error:
  639.         intBlockSize = 10
  640.         ReDim Mails(intMail).Attachments(intBlockSize - 1)
  641.     End If
  642.     intElements = UBound(Mails(intMail).Attachments())
  643.     'Save Attachment
  644.     Mails(intMail).Attachments(intCounter - 1).Data = strLine
  645.     Mails(intMail).Attachments(intCounter - 1).Name = DecodeIso(strFilename)
  646.     Mails(intMail).AttachedFiles = intCounter
  647. End Sub
  648. 'Clear all Mails
  649. Public Sub ClearMails()
  650.     Erase Mails
  651. End Sub
  652. ''**************************************************************************************
  653. ' Base64 Decode
  654. '
  655. ' This is an optimized version of the common Base 64 encode/decode.
  656. ' This version eliminates the repeditive calls to chr$() and asc(),
  657. ' as well as the linear searches I've seen in some routines.
  658. '
  659. ' This method does use a bit more memory in permanent lookup tables
  660. ' than most do.  However, this eliminates the need for using vb's
  661. ' rather slow method of bit shifting (multiplication and division).
  662. ' This appears not to make much difference in the IDE, but make
  663. ' a huge difference in the exe.
  664. '   Encodeing Index = 834 vs. 64 bytes standard
  665. '   Decoding Index  = 1536 vs. 64 to 256 standard
  666. '
  667. ' This routine also adds the CrLf on the fly rather than making
  668. ' a temporary copy of the encoded string then adding the crlf
  669. '
  670. ' Encoding/Decoding data from and to a file should be changed to
  671. ' use a fixed buffer to reduce the memory requirements of EncodeFile, etc.
  672. '
  673. ' All of this results in a speed increase:
  674. '   Encode:
  675. '         100 reps on a string of 28311 bytes
  676. '                               IDE      EXE
  677. '   Base64                      2824     300 (220 w/no overflow & array bound checks)
  678. '   Base64a (unknown author)  375500* 185300*
  679. '   Base64b (Wil Johnson)       2814     512 (410 w/no overflow & array bound checks)
  680. '     *Extrapolated (based on 1 rep, I didn't have time to wait 30 minutes for 100)
  681. '     *Unknown code is from ftp:altecdata.com/base64.cls
  682. '
  683. '  Decode
  684. '         100 reps on a string of 28311 bytes
  685. '                              IDE    EXE
  686. '   Base64                    3384     351 (271 w/no overflow & array bound checks)
  687. '   Base64a (unknown author)
  688. '   Base64b (Wil Johnson)     5969    1191 (981 w/no overflow & array bound checks)
  689. '   *Failed
  690. '   *Unknown code is from ftp:altecdata.com/base64.cls
  691. '
  692. '
  693. ' Author: Tim Arheit - tarheit@wcoil.com
  694. ' Version: 1.0
  695. '
  696. ' This code is provided as-is.  You are free to use and modify it
  697. ' as you wish.  Please report bugs, fixes and enhancements to the
  698. ' author.
  699. '
  700. ' History:
  701. '    11/13/00 - Code release. It appears to work.
  702. '
  703. '   09/02/02 I clean the source code and remove the encoding routines
  704. 'Decode a string to a string.
  705. Public Function Decode(sInput As String) As String
  706.   Dim bTemp() As Byte
  707.     'Convert to a byte array then convert.
  708.     'This is faster the repetitive calls to asc() or chr$()
  709.     bTemp = StrConv(sInput, vbFromUnicode)
  710.     Decode = StrConv(DecodeArr(bTemp), vbUnicode)
  711. End Function
  712. Public Sub DecodeToFile(sInput As String, sOutputFile As String)
  713.   Dim bTemp() As Byte
  714.   Dim fh As Long
  715.     bTemp = StrConv(sInput, vbFromUnicode)
  716.     bTemp = DecodeArr(bTemp)
  717.     fh = FreeFile(0)
  718.     Open sOutputFile For Binary Access Write As fh
  719.     Put fh, , bTemp
  720.     Close fh
  721. End Sub
  722. Public Sub DecodeFile(sInputFile As String, sOutputFile As String)
  723.   Dim bTemp() As Byte
  724.   Dim fh As Long
  725.     fh = FreeFile(0)
  726.     Open sInputFile For Binary Access Read As fh
  727.     ReDim bTemp(0 To LOF(fh) - 1)
  728.     Get fh, , bTemp
  729.     Close fh
  730.     bTemp = DecodeArr(bTemp)
  731.     Open sOutputFile For Binary Access Write As fh
  732.     Put fh, , bTemp
  733.     Close fh
  734. End Sub
  735. Private Function DecodeArr(bInput() As Byte) As Byte()
  736.   Dim bOutput() As Byte
  737.   Dim OutLength As Long
  738.   Dim CurrentOut As Long
  739.   Dim k As Long
  740.   Dim l As Long
  741.   Dim I As Long
  742.   
  743.   Dim b As Byte
  744.   Dim c As Byte
  745.   Dim d As Byte
  746.   Dim e As Byte
  747.     k = LBound(bInput)
  748.     l = UBound(bInput)
  749.     'Calculate the length of the input
  750.     I = l - k + 1
  751.     'Allocate the output
  752.   Dim BytesDataIn As Long ':(燤ove line to top of current Function
  753.   Dim BytesDataOut As Long ':(燤ove line to top of current Function
  754.   Dim ExtraBytes As Integer ':(燤ove line to top of current Function
  755.     If bInput(l) = 61 Then
  756.         ExtraBytes = 1
  757.         If bInput(l - 1) = 61 Then
  758.             ExtraBytes = 2
  759.         End If
  760.     End If
  761.     BytesDataIn = l + 1 'BytesDataIn of the string
  762.     BytesDataOut = (BytesDataIn * 0.75) - ExtraBytes ' how many bytes will the decoded string have
  763.     ReDim bOutput(BytesDataOut - 1)
  764.     CurrentOut = 0
  765.     For I = k To l
  766.         Select Case bInput(I)
  767.           Case CHAR_CR
  768.             'Do nothing
  769.           Case CHAR_LF
  770.             'Do nothing
  771.           Case Else
  772.             If l - I >= 3 Then
  773.                 b = bInput(I)
  774.                 c = bInput(I + 1)
  775.                 d = bInput(I + 2)
  776.                 e = bInput(I + 3)
  777.                 If e <> CHAR_EQUAL Then
  778.                     bOutput(CurrentOut) = m_ReverseIndex1(b) Or m_ReverseIndex2(c, 0)
  779.                     bOutput(CurrentOut + 1) = m_ReverseIndex2(c, 1) Or m_ReverseIndex3(d, 0)
  780.                     bOutput(CurrentOut + 2) = m_ReverseIndex3(d, 1) Or m_ReverseIndex4(e)
  781.                     CurrentOut = CurrentOut + 3
  782.                     I = I + 3 ':(燤odifies active For-Variable
  783.                   ElseIf d <> CHAR_EQUAL Then 'NOT E...
  784.                     bOutput(CurrentOut) = m_ReverseIndex1(b) Or m_ReverseIndex2(c, 0)
  785.                     bOutput(CurrentOut + 1) = m_ReverseIndex2(c, 1) Or m_ReverseIndex3(d, 0)
  786.                     CurrentOut = CurrentOut + 2
  787.                     I = I + 3 ':(燤odifies active For-Variable
  788.                   Else 'NOT D...
  789.                     bOutput(CurrentOut) = m_ReverseIndex1(b) Or m_ReverseIndex2(c, 0)
  790.                     CurrentOut = CurrentOut + 1
  791.                     I = I + 3 ':(燤odifies active For-Variable
  792.                 End If
  793.               Else 'NOT L...
  794.                 'Possible input code error, but may also be
  795.                 'an extra CrLf, so we will ignore it.
  796.             End If
  797.         End Select
  798.     Next I
  799.     'On properly formed input we should have to do this.
  800.     If OutLength <> CurrentOut + 1 Then
  801.         ReDim Preserve bOutput(0 To CurrentOut - 1)
  802.     End If
  803.     DecodeArr = bOutput
  804. End Function
  805. 'Saves a String to a File
  806. Public Sub SaveStr2File(strInput As String, strPathName As String)
  807.   Dim iFreeFile As Integer
  808.     '-----
  809.     ' Reference to a free file
  810.     '-----
  811.     iFreeFile = FreeFile
  812.     Open strPathName For Binary As iFreeFile
  813.     '-----
  814.     ' Save the total size of the array in a variable, this stops
  815.     ' VB to calculate the size each time it comes into the loop,
  816.     ' which of course, takes (much) more time then this sollution
  817.     '-----
  818.     Put iFreeFile, , strInput
  819.     Close iFreeFile
  820. End Sub
  821. '==========
  822. ' StrToAry;
  823. ' Convert the string into a byte array
  824. '==========
  825. Public Sub StringToByteArray(ByVal strIn As String, ByRef pbArrayOutput() As Byte)
  826.     pbArrayOutput = StrConv(strIn, vbFromUnicode)
  827. End Sub
  828. '==========
  829. ' AryToSr;
  830. ' Convert the byte array into a string
  831. '==========
  832. Public Sub ByteArrayToString(ByRef pbArrayInput() As Byte, ByRef strOut As String)
  833.     strOut = StrConv(pbArrayInput, vbUnicode)
  834. End Sub
  835. Public Function StringArrayToString(pbIn() As String) As String
  836.   Dim lSize     As Long
  837.   Dim lNow      As Long
  838.   Dim lTotal    As Long
  839.   Dim lNowArray As Long
  840.   Dim lNow2     As Long
  841.   Dim lTotal2   As Long
  842.   Dim tTemp     As String
  843.   Dim bTemp()   As Byte
  844.     '-----
  845.     ' Calculate size of inputarray
  846.     '-----
  847.     lSize = 0
  848.     lTotal = UBound(pbIn)
  849.     For lNow = 0 To lTotal
  850.         lSize = lSize + Len(pbIn(lNow))
  851.     Next lNow
  852.     '-----
  853.     ' Create byte array which is big
  854.     ' enough to hold all the bytes
  855.     '-----
  856.     ReDim bTemp(0 To lSize)
  857.     '-----
  858.     ' Convert the string array to a byte array
  859.     '-----
  860.     lNow = 0
  861.     lNowArray = 0
  862.     While lNow <> lSize
  863.         tTemp = pbIn(lNowArray)
  864.         lTotal2 = Len(tTemp)
  865.         '-----
  866.         ' Loop through the temp string
  867.         ' and place the byte character
  868.         ' in the correct position
  869.         ' Mid$(...) is faster then Mid$(...)
  870.         '-----
  871.         For lNow2 = 0 To lTotal2 - 1
  872.             bTemp(lNow + lNow2) = Asc(Mid$(tTemp, lNow2 + 1, 1))
  873.         Next lNow2
  874.         lNow = lNow + lTotal2
  875.         lNowArray = lNowArray + 1
  876.     Wend
  877.     '-----
  878.     ' Convert byte array to string
  879.     '-----
  880.     StringArrayToString = StrConv(bTemp(), vbUnicode)
  881. End Function
  882. '**************************************************************************************
  883. 'UUE decoding class
  884. '
  885. 'Author: PSC
  886. '
  887. 'Desc:
  888. '
  889. 'This class have several routines that support the decoding UU
  890. 'encoded attachments
  891. ''**************************************************************************************
  892. Public Function DecodeUUE(strUUCodeData As String) As String
  893.   Dim vDataLine   As Variant
  894.   Dim vDataLines  As Variant
  895.   Dim strDataLine As String
  896.   Dim intSymbols  As Integer
  897.   Dim strTemp     As String
  898.   Dim strUUDecode As String
  899.   Dim I As Long
  900.     On Error GoTo error
  901.     'remove begin marker
  902.     If Left$(strUUCodeData, 6) = "begin " Then
  903.         strUUCodeData = Mid$(strUUCodeData, InStr(1, strUUCodeData, vbLf) + 1)
  904.     End If
  905.     '
  906.     'remove end marker
  907.     If Right$(strUUCodeData, 5) = "end" + vbCrLf Then
  908.         strUUCodeData = Left$(strUUCodeData, Len(strUUCodeData) - 10)
  909.     End If
  910.     'Split encoded data to vDataLines array.
  911.     'Now each array member contains a line of encoded data
  912.     vDataLines = Split(strUUCodeData, vbCrLf)
  913.     For Each vDataLine In vDataLines
  914.         'Decode data line by line
  915.         '
  916.         strDataLine = CStr(vDataLine)
  917.         If strDataLine = "" Then
  918.             GoTo Skip
  919.         End If
  920.         'Get quantity of symbols in a line
  921.         intSymbols = Asc(Left$(strDataLine, 1)) - 32
  922.         'remove first symbol that just informs
  923.         'about quantity of symbols
  924.         strDataLine = Mid$(strDataLine, 2)
  925.         'replace "`" with " "
  926.         strDataLine = Replace(strDataLine, "`", " ")
  927.         'Convert every 4-byte chunk to 3-byte chunk by
  928.         For I = 1 To Len(strDataLine) Step 4
  929.             '1 byte
  930.             strTemp = strTemp + Chr$((Asc(Mid$(strDataLine, I, 1)) - 32) * 4 + _
  931.                       (Asc(Mid$(strDataLine, I + 1, 1)) - 32)  16)
  932.             '2 byte
  933.             strTemp = strTemp + Chr$((Asc(Mid$(strDataLine, I + 1, 1)) Mod 16) * 16 + _
  934.                       (Asc(Mid$(strDataLine, I + 2, 1)) - 32)  4)
  935.             '3 byte
  936.             strTemp = strTemp + Chr$((Asc(Mid$(strDataLine, I + 2, 1)) Mod 4) * 64 + _
  937.                       Asc(Mid$(strDataLine, I + 3, 1)) - 32)
  938.         Next I
  939.         '
  940.         strTemp = Left$(strTemp, intSymbols)
  941.         'write decoded line to the file
  942.         strUUDecode = strUUDecode + strTemp
  943.         'clear buffer for next line
  944.         strTemp = ""
  945. Skip:
  946.     Next vDataLine
  947.     DecodeUUE = strUUDecode
  948. error:
  949. End Function
  950. '**************************************************************************************
  951. 'Quoted printable decoding class
  952. '
  953. 'Author: PSC
  954. '
  955. 'Desc:
  956. '
  957. 'This class have several routines that support the decoding of quoted printable
  958. 'encoded attachments
  959. ''**************************************************************************************
  960. Public Function DecodeQP(ByRef StrToDecode As String) As String
  961.   Dim sTemp As String
  962.   Dim strChar As String
  963.   Dim I As Integer
  964.     sTemp = StrToDecode
  965.     sTemp = Replace(sTemp, "==_", "")
  966.     sTemp = Replace(sTemp, "=_", vbCrLf)
  967.     For I = 255 To 16 Step -1
  968.         strChar = UCase$(Hex$(I))
  969.         If InStr(1, sTemp, "=" & strChar) <> 0 Then sTemp = Replace(sTemp, "=" & strChar, Chr$(I) + Chr$(0))
  970.     Next I
  971.     For I = 15 To 1 Step -1
  972.         strChar = UCase$(Hex$(I))
  973.         If InStr(1, sTemp, "=" & "0" & strChar) <> 0 Then
  974.             sTemp = Replace(sTemp, "=" & "0" & strChar, Chr$(I) + Chr$(0))
  975.         End If
  976.     Next I
  977.     sTemp = Replace(sTemp, Chr$(0), "")
  978.     sTemp = Replace(sTemp, "=00", Chr$(0))
  979.     sTemp = Replace(sTemp, Chr$(255) & Chr$(254), "=")
  980.     DecodeQP = sTemp
  981. End Function
  982. '*************************************************************************************
  983. 'Function to decode ?iso? encoded Strings
  984. '
  985. '
  986. 'Author: David Bue Pedersen + Sebastian Fahrenkrog
  987. '*************************************************************************************
  988. Function DecodeIso(strEncoded As String)
  989.   'Dim StrtoReplace As String
  990.   'Dim StrReplacement As String
  991.   Dim StringtoDecode As String
  992.   Dim strLookup As String
  993.   Dim b As Boolean
  994.     On Error GoTo error
  995.     StringtoDecode = strEncoded
  996.     If IsNull(StringtoDecode) Then
  997.         Exit Function
  998.       ElseIf InStr(1, LCase$(StringtoDecode), "=?iso-") <= 0 Then
  999.         DecodeIso = StringtoDecode
  1000.         Exit Function
  1001.     End If
  1002.   Dim IsoArray As Variant
  1003.   Dim UCounter As Integer
  1004.   Dim Counter As Integer
  1005.   Dim Pattern As String
  1006.     IsoArray = StringtoDecode
  1007.     IsoArray = Split(StringtoDecode, "?")
  1008.     UCounter = UBound(IsoArray)
  1009.     For Counter = 0 To UCounter
  1010.         strLookup = IsoArray(Counter)
  1011.         Select Case strLookup
  1012.           Case "="
  1013.           Case "= ="
  1014.           Case "=="
  1015.           Case "Q"
  1016.             b = False
  1017.           Case "B"
  1018.             b = True
  1019.           Case Else
  1020.             Pattern = "ISO-" & "[0-9]" & "[0-9]" & "[0-9]" & "[0-9]" & "-" & "*"
  1021.             If Not UCase(IsoArray(Counter)) Like Pattern Then
  1022.                 If b Then 'Decode Base64
  1023.                     StringtoDecode = IsoArray(Counter)
  1024.                     StringtoDecode = Decode(StringtoDecode)
  1025.                     DecodeIso = DecodeIso + StringtoDecode
  1026.                   Else 'dann quoted printable
  1027.                     StringtoDecode = IsoArray(Counter)
  1028.                     StringtoDecode = DecodeQP(StringtoDecode)
  1029.                     DecodeIso = DecodeIso + StringtoDecode
  1030.                 End If
  1031.             End If
  1032.         End Select
  1033.     Next Counter
  1034. Exit Function
  1035. error:
  1036.     'Return original String
  1037.     DecodeIso = strEncoded
  1038. End Function
  1039. Public Property Let DelMail(bolDeleteMail As Boolean)
  1040.     bolDelMail = bolDeleteMail
  1041. End Property
  1042. Public Property Get DelMail() As Boolean
  1043.     DelMail = bolDelMail
  1044. End Property
  1045. Private Function WaitUntilTrue(ByRef Flag As Boolean, ByVal SecondsToWait As Long, Optional ByVal bRaiseTimeOutError As Boolean = True) As Boolean
  1046.   Dim fStart              As Single
  1047.   Dim fTimetoQuit         As Single
  1048.     If SecondsToWait < 1 Then Exit Function
  1049.     fStart = Timer
  1050.     ' Deal with timer being reset at Midnight
  1051.     If fStart + SecondsToWait < 86400 Then
  1052.         fTimetoQuit = fStart + SecondsToWait
  1053.       Else
  1054.         fTimetoQuit = (fStart - 86400) + SecondsToWait
  1055.     End If
  1056.     Do Until Flag = True
  1057.         If Timer >= fTimetoQuit Then
  1058.             If bRaiseTimeOutError Then Timeout
  1059.             Exit Function
  1060.         End If
  1061.         If pbExitImmediately Then Exit Function
  1062.         DoEvents
  1063.         Sleep (10)                                  ' added to reduce CPU load during wait periods
  1064.     Loop
  1065.     WaitUntilTrue = Flag
  1066. End Function
  1067. Private Sub Timeout()
  1068.   ' time out occured
  1069.   
  1070.         'Hide Status
  1071.         RaiseEvent Pop3Status("")
  1072.         'Show Error
  1073.         RaiseEvent MimeFailed("Can't connect to the server!")
  1074.         Pop3sck.CloseSocket
  1075.         
  1076.         
  1077. End Sub