Imap.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System.Net.Security;
  2. using System.Net.Sockets;
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. namespace MailFromWho
  6. {
  7. internal class Imap
  8. {
  9. #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
  10. private static StreamWriter _sw;
  11. private static TcpClient _tcpc;
  12. private static SslStream _ssl;
  13. #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
  14. private readonly Settings _settings;
  15. public Imap(Settings settings)
  16. {
  17. _settings = settings;
  18. }
  19. internal void GetAllAddresses()
  20. {
  21. try
  22. {
  23. var path = Environment.CurrentDirectory + $"{Path.DirectorySeparatorChar}{_settings.IntermediateFile}";
  24. var username = _settings.UserName;
  25. var imapServer = _settings.ImapServer;
  26. var sslPort = _settings.SslPort;
  27. var password = string.Empty;
  28. while (string.IsNullOrEmpty(password))
  29. {
  30. Console.Write($"Enter password of '{username}' @ '{imapServer}': ");
  31. var fgColour = Console.ForegroundColor;
  32. Console.ForegroundColor = Console.BackgroundColor;
  33. password = Console.ReadLine();
  34. Console.ForegroundColor = fgColour;
  35. }
  36. if (System.IO.File.Exists(path))
  37. {
  38. System.IO.File.Delete(path);
  39. }
  40. _sw = new System.IO.StreamWriter(System.IO.File.Create(path));
  41. // there should be no gap between the imap command and the \r\n
  42. // ssl.read() -- while ssl.readbyte!= eof does not work because there is no eof from server
  43. // cannot check for \r\n because in case of larger response from server ex:read email message
  44. // there are lot of lines so \r \n appears at the end of each line
  45. //ssl.timeout sets the underlying tcp connections timeout if the read or write
  46. //time out exceeds then the undelying connection is closed
  47. _tcpc = new System.Net.Sockets.TcpClient(imapServer, sslPort);
  48. _ssl = new System.Net.Security.SslStream(_tcpc.GetStream());
  49. _ssl.ReadTimeout = 200;
  50. _ssl.AuthenticateAsClient(imapServer);
  51. receiveResponse();
  52. sendRequest("$ LOGIN " + username + " " + password + "\r\n");
  53. receiveResponse();
  54. // Get all folders
  55. sendRequest("$ LIST " + "\"\"" + " \"*\"" + "\r\n");
  56. var foldersRaw = receiveResponse();
  57. var matches = Regex.Matches(foldersRaw, @"\s(INBOX.*?)\r\n");
  58. var folders = new List<string>();
  59. foreach (Match match in matches)
  60. {
  61. folders.Add(match.Groups[1].Value.Replace("\"", ""));
  62. }
  63. foreach (var folder in folders)
  64. {
  65. sendRequest($"$ SELECT \"{folder}\"\r\n");
  66. receiveResponse();
  67. sendRequest($"$ STATUS \"{folder}\" (MESSAGES)\r\n");
  68. var statusRaw = receiveResponse();
  69. var regex = new Regex(@"MESSAGES.(\d+)");
  70. var aantalBerichten = int.Parse(regex.Match(statusRaw).Groups[1].Value);
  71. var outputStr = $"FOLDER {folder} heeft {aantalBerichten} berichten";
  72. WriteOutput(outputStr, true);
  73. sendRequest("$ FETCH 1:* body[header.fields (from)]\r\n");
  74. var fromRaw = receiveResponse();
  75. // From: "flypacificblue.com" <reservations@flypacificblue.com>
  76. //matches = Regex.Matches(fromRaw, "From:\\s\\\"?(.[^\"]*?)\\\"?\\<(.*)\\>\r\n");
  77. matches = Regex.Matches(fromRaw, @"From:\s(.*)\r\n");
  78. var froms = new List<string>();
  79. foreach (Match match in matches)
  80. {
  81. var addressLine = match.Groups[1].Value;
  82. froms.Add(addressLine);
  83. WriteOutput(addressLine, true);
  84. }
  85. WriteOutput("", true);
  86. }
  87. receiveResponse();
  88. sendRequest("$ LOGOUT\r\n");
  89. receiveResponse();
  90. }
  91. catch (Exception ex)
  92. {
  93. Console.WriteLine("error: " + ex.Message);
  94. }
  95. finally
  96. {
  97. if (_sw != null)
  98. {
  99. _sw.WriteLine("");
  100. _sw.Close();
  101. _sw.Dispose();
  102. }
  103. if (_ssl != null)
  104. {
  105. _ssl.Close();
  106. _ssl.Dispose();
  107. }
  108. if (_tcpc != null)
  109. {
  110. _tcpc.Close();
  111. }
  112. }
  113. }
  114. private void WriteOutput(string outputStr, bool newline)
  115. {
  116. Console.Write(outputStr);
  117. _sw.Write(outputStr);
  118. if (newline)
  119. {
  120. Console.WriteLine("");
  121. _sw.WriteLine("");
  122. }
  123. }
  124. private void sendRequest(string command)
  125. {
  126. byte[] dummy;
  127. try
  128. {
  129. if (command != "")
  130. {
  131. if (_tcpc.Connected)
  132. {
  133. dummy = Encoding.ASCII.GetBytes(command);
  134. _ssl.Write(dummy, 0, dummy.Length);
  135. }
  136. else
  137. {
  138. throw new ApplicationException("TCP CONNECTION DISCONNECTED");
  139. }
  140. }
  141. _ssl.Flush();
  142. }
  143. catch (Exception ex)
  144. {
  145. throw new ApplicationException(ex.Message);
  146. }
  147. }
  148. private string receiveResponse()
  149. {
  150. var sb = new StringBuilder();
  151. byte[] buffer;
  152. try
  153. {
  154. var bytes = 0;
  155. // First wait for some data, but not too long...
  156. var waitTime = DateTime.Now.AddMilliseconds(200);
  157. while (bytes <= 0 && DateTime.Now < waitTime)
  158. {
  159. try
  160. {
  161. buffer = new byte[2048];
  162. bytes = _ssl.Read(buffer, 0, 2048);
  163. sb.Append(ReturnCleanASCII(Encoding.ASCII.GetString(buffer, 0, bytes)));
  164. }
  165. catch (IOException)
  166. {
  167. bytes = -1;
  168. }
  169. }
  170. while (bytes > 0)
  171. {
  172. try
  173. {
  174. buffer = new byte[2048];
  175. bytes = _ssl.Read(buffer, 0, 2048);
  176. sb.Append(ReturnCleanASCII(Encoding.ASCII.GetString(buffer, 0, bytes)));
  177. }
  178. catch (IOException)
  179. {
  180. bytes = -1;
  181. }
  182. }
  183. }
  184. catch (Exception ex)
  185. {
  186. throw new ApplicationException(ex.Message);
  187. }
  188. return sb.ToString();
  189. }
  190. private string ReturnCleanASCII(string s)
  191. {
  192. StringBuilder sb = new StringBuilder(s.Length);
  193. foreach (char c in s)
  194. {
  195. int i = (int)c;
  196. if (i > 127) // you probably don't want 127 either
  197. continue;
  198. if (i < 32 && (i != 10 && i != 13)) // I bet you don't want control characters
  199. continue;
  200. sb.Append(c);
  201. }
  202. return sb.ToString();
  203. }
  204. }
  205. }