Guest
Public paste!

Untitled

By: a guest | Mar 15th, 2010 | Syntax: None | Size: 22.31 KB | Hits: 16 | Expires: Never
Copy text to clipboard
  1. //------------------------------------------------------------------------------
  2. // File    : MailPop3.cs
  3. // Version : 1.10
  4. // Date    : 17. November 2002
  5. // Author  : Karavaev Denis,                 Bruno Podetti
  6. // Email   : karavaev_denis@hotmail.com,     Podetti@gmx.net
  7. // Web     : http://wasp.elcat.kg,           -
  8. //
  9. // Special
  10. // This version has only a limitted error handling. Also reading e-Mail and
  11. // parsing the mailbody may have some faults.
  12. //
  13. // To do
  14. // Extracting mail attachment, and supporting differenet mime types and content
  15. // types.
  16. //------------------------------------------------------------------------------
  17.  
  18. using System;
  19. using System.Net;
  20. using System.Net.Sockets;
  21. using System.IO;
  22. using System.Collections;
  23. using System.Text;
  24.  
  25. namespace Mail
  26. {
  27.   class MailMessage
  28.   {
  29.     public string contentType;
  30.     public string contentTransferEncoding;
  31.     public string message;
  32.   };
  33.  
  34.   class MailHeader
  35.   {
  36.     public int number;
  37.     public int size;
  38.     public string received;
  39.     public string received2;
  40.     public string received3;
  41.     public string from;
  42.     public string to;
  43.     public string subject;
  44.     public string date;
  45.     public string messageID;
  46.     public string mimeVersion;
  47.     public string contentType;
  48.     public string boundary;
  49.     public string X_Priority;
  50.     public string X_MSMail_Priority;
  51.     public string X_Mailer;
  52.     public string importance;
  53.     public string X_MimeOLE;
  54.     public string X_RCPT_TO;
  55.     public string X_UIDL;
  56.     public string status;
  57.  
  58.     public ArrayList messages;
  59.   };
  60.  
  61.   /// <summary>
  62.   /// Minimal POP3 Commands:
  63.   ///
  64.   /// USER name               valid in the AUTHORIZATION state
  65.   /// PASS string
  66.   /// QUIT
  67.   ///
  68.   /// STAT                    valid in the TRANSACTION state
  69.   /// LIST [msg]
  70.   /// RETR msg
  71.   /// DELE msg
  72.   /// NOOP
  73.   /// RSET
  74.   /// QUIT
  75.   ///
  76.   /// Optional POP3 Commands:
  77.   /// APOP name digest        valid in the AUTHORIZATION state
  78.   /// TOP msg n               valid in the TRANSACTION state
  79.   /// UIDL [msg]
  80.   ///
  81.   /// POP3 Replies:
  82.   /// +OK
  83.   /// -ERR
  84.   /// </summary>
  85.   class MailPOP3
  86.   {
  87.     // variables for pop3 class
  88.     public TcpClient tcpClient;
  89.     public NetworkStream netStream;
  90.     public StreamReader  streamReader;
  91.  
  92.     /// <summary>
  93.     /// Connect and authorized user.
  94.     /// </summary>
  95.     /// <param name="pop3host">
  96.     /// Pop3 Mailserver
  97.     /// </param>
  98.     /// <param name="port">
  99.     /// Port of the mailserver, normaly 110
  100.     /// </param>
  101.     /// <param name="user">
  102.     /// a string identifying a mailbox (required), which is of
  103.     /// significance ONLY to the server
  104.     /// </param>
  105.     /// <param name="pwd">
  106.     /// a server/mailbox-specific password (required)
  107.     /// </param>
  108.     /// <returns></returns>
  109.     public string DoConnect(string pop3host,int port, string user, string pwd)
  110.     {
  111.       try
  112.       {
  113.         // create POP3 connection
  114.         tcpClient = new TcpClient(pop3host,port);
  115.  
  116.         // initialization
  117.         netStream = tcpClient.GetStream();
  118.         streamReader = new StreamReader(tcpClient.GetStream());
  119.         string retVal = streamReader.ReadLine();
  120.         if(!retVal.StartsWith("+OK"))
  121.           return retVal;
  122.  
  123.         // send login
  124.         retVal = SendCommand("USER "+ user + "\r\n");
  125.         // Possible Responses:
  126.         // +OK name is a valid mailbox
  127.         // -ERR never heard of mailbox name
  128.         if(!retVal.StartsWith("+OK"))
  129.           return retVal;
  130.  
  131.         // send password
  132.         // Possible Responses:
  133.         // +OK maildrop locked and ready
  134.         // -ERR invalid password
  135.         // -ERR unable to lock maildrop
  136.         return SendCommand("PASS " + pwd + "\r\n");
  137.       }
  138.       catch(Exception err)
  139.       {
  140.         return ("-ERR " + err.ToString());
  141.       }
  142.     }
  143.  
  144.     /// <summary>
  145.     /// Send a command to the pop3 server
  146.     /// </summary>
  147.     /// <param name="command">
  148.     /// command string
  149.     /// </param>
  150.     /// <returns></returns>
  151.     string SendCommand(string command)
  152.     {
  153.       try
  154.       {
  155.         byte[] bData = System.Text.Encoding.ASCII.GetBytes(command.ToCharArray());
  156.         netStream.Write(bData,0,bData.Length);
  157.         return streamReader.ReadLine();
  158.       }
  159.       catch (Exception err)
  160.       {
  161.         return ("-ERR " + err.ToString());
  162.       }
  163.     }
  164.  
  165.     /// <summary>
  166.     /// </summary>
  167.     /// <param name="command"></param>
  168.     /// <returns></returns>
  169.     public string GetCommandBlock(string command)
  170.     {
  171.       StringBuilder CommandBlock = new StringBuilder();
  172.       try
  173.       {
  174.         string sTemp = SendCommand(command);
  175.         if(sTemp.StartsWith("+OK"))
  176.         {
  177.           do
  178.           {
  179.             CommandBlock.Append(sTemp+"\r\n");
  180.             sTemp = streamReader.ReadLine();
  181.           }while(sTemp != ".");
  182.         }
  183.         else
  184.         {
  185.           return sTemp;
  186.         }
  187.       }
  188.       catch(Exception err)
  189.       {
  190.         return ("-ERR " + err.ToString());
  191.       }
  192.       return CommandBlock.ToString();
  193.     }
  194.  
  195.     /// <summary>
  196.     /// Restrictions:
  197.     ///  may only be given in the TRANSACTION state
  198.     ///
  199.     /// The POP3 server issues a positive response with a line
  200.     /// containing information for the maildrop.  This line is
  201.     /// called a "drop listing" for that maildrop.
  202.     /// In order to simplify parsing, all POP3 servers are
  203.     /// required to use a certain format for drop listings.  The
  204.     /// positive response consists of "+OK" followed by a single
  205.     /// space, the number of messages in the maildrop, a single
  206.     /// space, and the size of the maildrop in octets.  This memo
  207.     /// makes no requirement on what follows the maildrop size.
  208.     /// Minimal implementations should just end that line of the
  209.     /// response with a CRLF pair.  More advanced implementations
  210.     /// may include other information.
  211.     /// NOTE: This memo STRONGLY discourages implementations
  212.     /// from supplying additional information in the drop
  213.     /// listing.  Other, optional, facilities are discussed
  214.     /// later on which permit the client to parse the messages
  215.     /// in the maildrop.
  216.     /// Note that messages marked as deleted are not counted in
  217.     /// either total.
  218.     /// </summary>
  219.     /// <returns>
  220.     /// Possible Responses:
  221.     /// +OK nn mm
  222.     /// </returns>
  223.     public string GetStat()
  224.     {
  225.       // Send STAT command to get number of mail and total size
  226.       return SendCommand("STAT\r\n");
  227.     }
  228.  
  229.     public string GetList()// Send LIST command with no parametrs to get all information
  230.     {
  231.       // For saving 'list' results
  232.       return GetCommandBlock("LIST\r\n");
  233.     }
  234.  
  235.     /// <summary>
  236.     /// Restrictions:
  237.     ///   may only be given in the TRANSACTION state
  238.     ///
  239.     /// If an argument was given and the POP3 server issues a
  240.     /// positive response with a line containing information for
  241.     /// that message.  This line is called a "scan listing" for
  242.     /// that message.
  243.     /// If no argument was given and the POP3 server issues a
  244.     /// positive response, then the response given is multi-line.
  245.     /// After the initial +OK, for each message in the maildrop,
  246.     /// the POP3 server responds with a line containing
  247.     /// information for that message.  This line is also called a
  248.     /// "scan listing" for that message.  If there are no
  249.     /// messages in the maildrop, then the POP3 server responds
  250.     /// with no scan listings--it issues a positive response
  251.     /// followed by a line containing a termination octet and a
  252.     /// CRLF pair.
  253.     /// In order to simplify parsing, all POP3 servers are
  254.     /// required to use a certain format for scan listings. A
  255.     /// scan listing consists of the message-number of the
  256.     /// message, followed by a single space and the exact size of
  257.     /// the message in octets. This memo makes no requirement on
  258.     /// what follows the message size in the scan listing. Minimal
  259.     /// implementations should just end that line of the response
  260.     /// with a CRLF pair.  More advanced implementations may
  261.     /// include other information, as parsed from the message.
  262.     ///
  263.     /// NOTE: This memo STRONGLY discourages implementations
  264.     /// from supplying additional information in the scan
  265.     /// listing.  Other, optional, facilities are discussed
  266.     /// later on which permit the client to parse the messages
  267.     /// in the maildrop.
  268.     /// Note that messages marked as deleted are not listed.
  269.     /// </summary>
  270.     /// <param name="num">
  271.     /// a message-number (optional), which, if present, may NOT
  272.     /// refer to a message marked as deleted
  273.     /// </param>
  274.     /// <returns>
  275.     /// Possible Responses:
  276.     /// +OK scan listing follows
  277.     /// -ERR no such message
  278.     /// </returns>
  279.     public string GetList(int num)
  280.     {
  281.       return SendCommand("LIST " + num + "\r\n");
  282.     }
  283.  
  284.     /// <summary>
  285.     /// Read each part of a multipart message
  286.     /// </summary>
  287.     /// <param name="mailHeader">
  288.     /// </param>
  289.     /// <returns>
  290.     /// </returns>
  291.     bool ReadMessage(MailHeader mailHeader)
  292.     {
  293.       if(mailHeader.messages==null)
  294.       {
  295.         mailHeader.messages = new ArrayList();
  296.       }
  297.  
  298.       MailMessage mailMessage = new MailMessage();
  299.       string delimiter = "--" + mailHeader.boundary;
  300.  
  301.       StringBuilder sBody = new StringBuilder();
  302.  
  303.       string sTemp = streamReader.ReadLine();
  304.  
  305.       sBody.Append(sTemp);
  306.       bool readHeder = true;
  307.       while(true)
  308.       {
  309.         sTemp = streamReader.ReadLine();
  310.         if(readHeder)
  311.         {
  312.           if(sTemp.Length>0 && sTemp[0]<=' ')
  313.           {
  314.             sBody.Append(sTemp);
  315.             continue;
  316.           }
  317.  
  318.           string key = sBody.ToString();
  319.           sBody.Length = 0;
  320.           if(sTemp.Length==0)
  321.           {
  322.             readHeder=false;
  323.           }
  324.           else
  325.           {
  326.             sBody.Append(sTemp);
  327.           }
  328.  
  329.           if(key.StartsWith("Content-Type: "))
  330.           {
  331.             mailMessage.contentType = key.Remove(0,14);
  332.           }
  333.           else if(key.StartsWith("Content-Transfer-Encoding: "))
  334.           {
  335.             mailMessage.contentTransferEncoding = key.Remove(0,27);
  336.           }
  337.         }
  338.         else if(sTemp.StartsWith(delimiter))
  339.         {
  340.           mailMessage.message = sBody.ToString();
  341.           mailHeader.messages.Add(mailMessage);
  342.  
  343.           if(sTemp.Remove(0,delimiter.Length)=="--")
  344.           {
  345.             return true;
  346.           }
  347.  
  348.           mailMessage = new MailMessage();
  349.           sBody.Length = 0;
  350.           sBody.Append(streamReader.ReadLine());
  351.           readHeder = true;
  352.         }
  353.         else
  354.         {
  355.           sBody.Append(sTemp);
  356.           sBody.Append("\r\n");
  357.         }
  358.       }
  359.     }
  360.  
  361.     bool SetMailHeader(MailHeader mailHeader, string key)
  362.     {
  363.       if(key.StartsWith("Received: "))
  364.       {
  365.         if (mailHeader.received==null)
  366.         {
  367.           mailHeader.received = key.Remove(0,10);
  368.         }
  369.         else if (mailHeader.received2==null)
  370.         {
  371.           mailHeader.received2 = key.Remove(0,10);
  372.         }
  373.         else if (mailHeader.received3==null)
  374.         {
  375.           mailHeader.received3 = key.Remove(0,10);
  376.         }
  377.       }
  378.       else if(key.StartsWith("From: "))
  379.       {
  380.         mailHeader.from = key.Remove(0,6);
  381.       }
  382.       else if(key.StartsWith("To: "))
  383.       {
  384.         mailHeader.to = key.Remove(0,4);
  385.       }
  386.       else if(key.StartsWith("Subject: "))
  387.       {
  388.         mailHeader.subject = key.Remove(0,9);
  389.       }
  390.       else if(key.StartsWith("Date: "))
  391.       {
  392.         mailHeader.date = key.Remove(0,6);
  393.       }
  394.       else if(key.StartsWith("Message-ID: "))
  395.       {
  396.         mailHeader.messageID = key.Remove(0,12);
  397.       }
  398.       else if(key.StartsWith("MIME-Version: "))
  399.       {
  400.         mailHeader.mimeVersion = key.Remove(0,14);
  401.       }
  402.       else if(key.StartsWith("Content-Type: "))
  403.       {  
  404.         int index = key.IndexOf("boundary=");
  405.         mailHeader.boundary = "";
  406.  
  407.         if(index!=-1)
  408.         {
  409.           if(key[index+9]=='\"')
  410.           {
  411.             int index2 = key.IndexOf("\"",index+10);
  412.             mailHeader.boundary = key.Substring(index+10,index2-index-10);
  413.           }
  414.           key = key.Substring(0,index);
  415.         }
  416.         mailHeader.contentType = key.Remove(0,14);
  417.       }
  418.       else if(key.StartsWith("X-Priority: "))
  419.       {
  420.         mailHeader.X_Priority = key.Remove(0,12);
  421.       }
  422.       else if(key.StartsWith("X-MSMail-Priority: "))
  423.       {
  424.         mailHeader.X_MSMail_Priority = key.Remove(0,19);
  425.       }
  426.       else if(key.StartsWith("X-Mailer: "))
  427.       {
  428.         mailHeader.X_Mailer = key.Remove(0,10);
  429.       }
  430.       else if(key.StartsWith("Importance: "))
  431.       {
  432.         mailHeader.importance = key.Remove(0,12);
  433.       }
  434.       else if(key.StartsWith("X-MimeOLE: "))
  435.       {
  436.         mailHeader.X_MimeOLE = key.Remove(0,11);
  437.       }
  438.       else if(key.StartsWith("X-RCPT-TO: "))
  439.       {
  440.         mailHeader.X_RCPT_TO = key.Remove(0,11);
  441.       }
  442.       else if(key.StartsWith("X-UIDL: "))
  443.       {
  444.         mailHeader.X_UIDL = key.Remove(0,8);
  445.       }
  446.       else if(key.StartsWith("Status: "))
  447.       {
  448.         mailHeader.status = key.Remove(0,8);
  449.       }
  450.       else
  451.         return false;
  452.  
  453.       return true;
  454.     }
  455.  
  456.     /// <summary>
  457.     /// Get all mails form the pop3 server.
  458.     /// </summary>
  459.     /// <param name="body">
  460.     /// If set it returns mailheader and message.
  461.     /// </param>
  462.     /// <returns></returns>
  463.     public MailHeader[] GetMails(bool body)
  464.     {
  465.       string list = GetList();
  466.       if(list==null || list.Length==0 || !list.StartsWith("+OK"))
  467.         return null;
  468.  
  469.       string[] param = list.Split('\n');
  470.       string[] listHeader = param[0].Split(' ');
  471.  
  472.       int count = int.Parse(listHeader[1]);
  473.  
  474.       MailHeader[] myHeader = new MailHeader[count];
  475.       for (int n=0;n<count;n++)
  476.       {
  477.         string[] msg = param[n+1].Split(' ');
  478.  
  479.         myHeader[n] = GetMail(int.Parse(msg[0]),body);
  480.       }
  481.       return myHeader;
  482.     }
  483.  
  484.     public MailHeader GetMail(int num, bool body)
  485.     {
  486.       MailHeader mailHeader = null;
  487.       try
  488.       {
  489.         string sTemp;
  490.         if(body==true)
  491.           sTemp = SendCommand("RETR " + num + "\r\n");
  492.         else
  493.           sTemp = SendCommand("TOP " + num + "\r\n");
  494.  
  495.         if(sTemp.StartsWith("+OK"))
  496.         {
  497.           string []param = sTemp.Split(' ');
  498.  
  499.           string delimiter = "--";
  500.           mailHeader = new MailHeader();
  501.           mailHeader.number = num;
  502.           mailHeader.size = int.Parse(param[1]);  
  503.  
  504.           StringBuilder sBody = new StringBuilder();
  505.  
  506.           while(true)
  507.           {
  508.             sTemp = streamReader.ReadLine();
  509.             if(sTemp==".")
  510.             {
  511.               SetMailHeader(mailHeader,sBody.ToString());  
  512.               break;
  513.             }
  514.             else if(sTemp.Length>0 && sTemp[0]<=' ')
  515.             {
  516.               sBody.Append(sTemp);
  517.             }
  518.               // Begin off message body
  519.             else if (sTemp.StartsWith(delimiter))
  520.             {
  521.               // new Message
  522.               ReadMessage(mailHeader);
  523.             }
  524.             else
  525.             {
  526.               if(sBody.Length>0)
  527.               {
  528.                 SetMailHeader(mailHeader,sBody.ToString());
  529.                 delimiter = "--" + mailHeader.boundary;
  530.               }
  531.  
  532.               sBody = new StringBuilder(sTemp);
  533.             }
  534.           }
  535.           // . - is the end of the server response
  536.         }
  537.       }
  538.       catch(Exception)
  539.       {
  540.         return null;
  541.       }
  542.       return mailHeader;
  543.     }
  544.  
  545.     /// <summary>
  546.     /// If the POP3 server issues a positive response, then the
  547.     /// response given is multi-line.  After the initial +OK, the
  548.     /// POP3 server sends the message corresponding to the given
  549.     /// message-number, being careful to byte-stuff the termination
  550.     /// character (as with all multi-line responses).
  551.     /// </summary>
  552.     /// <param name="num">
  553.     /// a message-number (required) which may NOT refer to a
  554.     /// message marked as deleted
  555.     /// </param>
  556.     /// <returns>
  557.     /// Possible Responses:
  558.     /// +OK message follows
  559.     /// -ERR no such message
  560.     /// </returns>
  561.     public string Retr(int num)
  562.     {
  563.       return GetCommandBlock("RETR " + num + "\r\n");
  564.     }
  565.  
  566.     /// <summary>
  567.     /// The POP3 server marks the message as deleted.  Any future
  568.     /// reference to the message-number associated with the message
  569.     /// in a POP3 command generates an error.  The POP3 server does
  570.     /// not actually delete the message until the POP3 session
  571.     /// enters the UPDATE state.
  572.     /// </summary>
  573.     /// <param name="num">
  574.     /// a message-number (required) which may NOT refer to a
  575.     /// message marked as deleted
  576.     /// </param>
  577.     /// <returns>
  578.     /// Possible Responses:
  579.     /// +OK message deleted
  580.     /// -ERR no such message
  581.     /// </returns>
  582.     public string Dele(int num)
  583.     {
  584.       return SendCommand("DELE " + num + "\r\n");
  585.     }
  586.  
  587.     /// <summary>
  588.     /// The POP3 server does nothing, it merely replies with a
  589.     /// positive response.
  590.     /// </summary>
  591.     /// <returns>
  592.     /// Possible Responses:
  593.     /// +OK
  594.     /// </returns>
  595.     public string GetNoop()
  596.     {
  597.       return SendCommand("NOOP\r\n");
  598.     }
  599.  
  600.     /// <summary>
  601.     /// If any messages have been marked as deleted by the POP3
  602.     /// server, they are unmarked.  The POP3 server then replies
  603.     /// Send RSET command to unmark all deleteting messages
  604.     /// </summary>
  605.     /// <returns>
  606.     /// Possible Responses:
  607.     /// +OK
  608.     /// </returns>
  609.     public string Rset()
  610.     {
  611.       return SendCommand("RSET\r\n");
  612.     }
  613.  
  614.     /// <summary>
  615.     /// The POP3 server removes all messages marked as deleted
  616.     /// from the maildrop and replies as to the status of this
  617.     /// operation.  If there is an error, such as a resource
  618.     /// shortage, encountered while removing messages, the
  619.     /// maildrop may result in having some or none of the messages
  620.     /// marked as deleted be removed.  In no case may the server
  621.     /// remove any messages not marked as deleted.
  622.     /// Whether the removal was successful or not, the server
  623.     /// then releases any exclusive-access lock on the maildrop
  624.     /// and closes the TCP connection.
  625.     /// </summary>
  626.     /// <returns>
  627.     /// Possible Responses:
  628.     /// +OK
  629.     /// -ERR some deleted messages not removed
  630.     /// </returns>
  631.     public string Quit()
  632.     {
  633.       if( netStream==null || streamReader==null)
  634.       {
  635.         return ("-ERR no connection");
  636.       }
  637.       string tmp = SendCommand("QUIT\r\n");;
  638.       netStream.Close();
  639.       streamReader.Close();
  640.       return tmp;
  641.     }
  642.  
  643.     /// <summary>
  644.     /// If the POP3 server issues a positive response, then the
  645.     /// response given is multi-line.  After the initial +OK, the
  646.     /// POP3 server sends the headers of the message, the blank
  647.     /// line separating the headers from the body, and then the
  648.     /// number of lines of the indicated message's body, being
  649.     /// careful to byte-stuff the termination character (as with
  650.     /// all multi-line responses).
  651.     /// Note that if the number of lines requested by the POP3
  652.     /// client is greater than than the number of lines in the
  653.     /// body, then the POP3 server sends the entire message.
  654.     /// </summary>
  655.     /// <param name="num_mess">
  656.     /// a message-number (required) which may NOT refer to to a
  657.     /// message marked as deleted, and
  658.     /// </param>
  659.     /// <param name="num_strok">
  660.     ///  a non-negative number of lines (required)
  661.     /// </param>
  662.     /// <returns>
  663.     /// Possible Responses:
  664.     /// +OK top of message follows
  665.     /// -ERR no such message
  666.     /// </returns>
  667.     public string GetTop(int num_mess, int num_strok)
  668.     {
  669.       return GetCommandBlock("TOP " + num_mess + " " + num_strok + "\r\n");
  670.     }
  671.  
  672.     public string GetTop(int num)
  673.     {
  674.       return GetCommandBlock("TOP "+ num + "\r\n");
  675.     }
  676.  
  677.     /// <summary>
  678.     /// If an argument was given and the POP3 server issues a positive
  679.     /// response with a line containing information for that message.
  680.     /// This line is called a "unique-id listing" for that message.
  681.     /// If no argument was given and the POP3 server issues a positive
  682.     /// response, then the response given is multi-line.  After the
  683.     /// initial +OK, for each message in the maildrop, the POP3 server
  684.     /// responds with a line containing information for that message.
  685.     /// This line is called a "unique-id listing" for that message.
  686.     /// In order to simplify parsing, all POP3 servers are required to
  687.     /// use a certain format for unique-id listings.  A unique-id
  688.     /// listing consists of the message-number of the message,
  689.     /// followed by a single space and the unique-id of the message.
  690.     /// No information follows the unique-id in the unique-id listing.
  691.     /// The unique-id of a message is an arbitrary server-determined
  692.     /// string, consisting of one to 70 characters in the range 0x21
  693.     /// to 0x7E, which uniquely identifies a message within a
  694.     /// maildrop and which persists across sessions.  This
  695.     /// persistence is required even if a session ends without
  696.     /// entering the UPDATE state.  The server should never reuse an
  697.     /// unique-id in a given maildrop, for as long as the entity
  698.     /// using the unique-id exists.
  699.     /// Note that messages marked as deleted are not listed.
  700.     /// While it is generally preferable for server implementations
  701.     /// to store arbitrarily assigned unique-ids in the maildrop,
  702.     /// this specification is intended to permit unique-ids to be
  703.     /// calculated as a hash of the message.  Clients should be able
  704.     /// to handle a situation where two identical copies of a
  705.     /// message in a maildrop have the same unique-id.
  706.     /// </summary>
  707.     /// <param name="num">
  708.     /// a message-number (optional), which, if present, may NOT
  709.     /// refer to a message marked as deleted
  710.     /// </param>
  711.     /// <returns>
  712.     /// Possible Responses:
  713.     /// +OK unique-id listing follows
  714.     /// -ERR no such message
  715.     /// </returns>
  716.     public string GetUidl(int num)
  717.     {
  718.       return SendCommand( "UIDL " + num + "\r\n");
  719.     }
  720.  
  721.     public string GetUidl()
  722.     {
  723.       return GetCommandBlock("UIDL\r\n");
  724.     }
  725.   }
  726. }