Advertisement
Guest User

Untitled

a guest
Jul 8th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.92 KB | None | 0 0
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Net.Sockets;
  5.  
  6. using System.Collections.Generic;
  7. using System.Net.Security;
  8. using GmailViewer.Email.Folders;
  9. using GmailViewer.Email.Message;
  10. using GmailViewer.Email.Body;
  11.  
  12. namespace GmailViewer.Email
  13. {
  14. public delegate void GmailEvent<T>(GmailClient Client, T Parameter);
  15.  
  16. public enum GmailState
  17. {
  18. Closed,
  19. Connected,
  20. Authorized,
  21. Selected
  22. }
  23. public class GmailClient
  24. {
  25. private string Username;
  26. private string Password;
  27.  
  28.  
  29. private int CurrentCommand;
  30.  
  31. private StreamReader Reader;
  32. private Socket Connection;
  33. private SslStream Stream;
  34.  
  35. private GmailState State;
  36.  
  37. public GmailEvent<object> OnLogin;
  38. public GmailEvent<object> OnLogout;
  39. public GmailEvent<string> OnError;
  40.  
  41.  
  42. public GmailClient(string Username, string Password)
  43. {
  44. this.CurrentCommand = 0;
  45. this.Username = Username;
  46. this.Password = Password;
  47. this.State = GmailState.Closed;
  48. this.Connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  49. }
  50. public bool Connected()
  51. {
  52. return (State != GmailState.Closed);
  53. }
  54. public void Login()
  55. {
  56. if (State == GmailState.Closed)
  57. {
  58. Connection.BeginConnect("imap.gmail.com", 993, new AsyncCallback(ConnectionEstablished), this);
  59. }
  60. else
  61. {
  62. if (OnError != null)
  63. OnError.Invoke(this, "State != GmailState.Closed");
  64. }
  65. }
  66. private void ConnectionEstablished(IAsyncResult Result)
  67. {
  68. try
  69. {
  70. State = GmailState.Connected;
  71. Stream = new SslStream(new NetworkStream(Connection));
  72. Stream.AuthenticateAsClient("imap.gmail.com");
  73. Reader = new StreamReader(Stream, Encoding.ASCII);
  74. Authenticate();
  75. }
  76. catch (Exception Error)
  77. {
  78. if (OnError != null)
  79. OnError.Invoke(this, Error.ToString());
  80. }
  81. }
  82. private void Authenticate()
  83. {
  84. string Response;
  85. if (ValidResponse(Response = ReadLine()))
  86. {
  87. ExecuteCommand("CAPABILITY");
  88. if (ValidResponse(Response = ReadMultiline()))
  89. {
  90. ExecuteCommand(string.Format("LOGIN {0} {1}", Username, Password));
  91. if (ReadMultiline().EndsWith("(Success)"))
  92. {
  93. State = GmailState.Authorized;
  94. if (OnLogin != null)
  95. OnLogin.Invoke(this, null);
  96. }
  97. }
  98. }
  99. }
  100.  
  101. public Mailbox List()
  102. {
  103. ExecuteCommand("LIST \"\" *");
  104. return Mailbox.Parse(ReadMultiline());
  105. }
  106. public bool Select(string Folder, out FolderData Data)
  107. {
  108. Data = new FolderData(Folder);
  109.  
  110. Folder = Folder.Replace("Γ€", "&AOQ-");
  111. Folder = Folder.Replace("ΓΆ", "&APY-");
  112.  
  113. ExecuteCommand("SELECT " + Folder);
  114. string Response = ReadMultiline();
  115. if (Response.EndsWith("(Success)"))
  116. {
  117. FolderData.Parse(Data, Response);
  118. State = GmailState.Selected;
  119. return true;
  120. }
  121. return false;
  122. }
  123. public enum FetchType
  124. {
  125. Text,
  126. Html
  127. }
  128. private void FetchBody(ref EmailMessage Message, FetchType Type)
  129. {
  130. string Command = "FETCH " + Message.ID + " BODY[{0}]";
  131.  
  132. bool Continue = false;
  133. BodyPartEncoding ContentEncoding = BodyPartEncoding.UNKNOWN;
  134. Encoding BodyEncoding = Encoding.Default;
  135. switch (Type)
  136. {
  137. case FetchType.Text:
  138. if (Message.ContainsText())
  139. {
  140. BodyPart Part = Message.Parts[Message.TextIndex];
  141. ContentEncoding = Part.ContentEncoding;
  142. BodyEncoding = Part.BodyEncoding;
  143.  
  144. Command = string.Format(Command, Part.Index);
  145. Continue = true;
  146. }
  147. break;
  148. case FetchType.Html:
  149. {
  150. if (Message.ContainsHtml())
  151. {
  152. BodyPart Part = Message.Parts[Message.HtmlIndex];
  153. ContentEncoding = Part.ContentEncoding;
  154. BodyEncoding = Part.BodyEncoding;
  155.  
  156. Command = string.Format(Command, Part.Index);
  157. Continue = true;
  158. }
  159. }
  160. break;
  161. }
  162. if (Continue)
  163. {
  164. ExecuteCommand(Command);
  165.  
  166. string Response = ReadLine();
  167. string ServerFinished = string.Format("TP{0} OK", CurrentCommand - 1);
  168.  
  169. StringBuilder message = new StringBuilder();
  170. do
  171. {
  172. Response = ReadLine();
  173. if (Response.StartsWith(ServerFinished)) break;
  174.  
  175. if (ContentEncoding == BodyPartEncoding.BASE64)
  176. {
  177. message.Append(Response);
  178. }
  179. else if (ContentEncoding == BodyPartEncoding.QUOTEDPRINTABLE)
  180. {
  181. if (Response.EndsWith("=") || Response.EndsWith(")"))
  182. {
  183. message.Append(Response.Substring(0, Response.Length - 1));
  184. }
  185. else
  186. {
  187. message.AppendLine(Response);
  188. }
  189. }
  190. else
  191. message.AppendLine(Response);
  192. } while (true);
  193.  
  194. if (message.ToString().EndsWith(")"))
  195. message.Remove(message.Length - 1, 1);
  196.  
  197. string MessageContents = message.ToString();
  198.  
  199. if (ContentEncoding != BodyPartEncoding.BASE64)
  200. {
  201. MessageContents = Decoder.DecodeMessage(MessageContents, BodyEncoding);
  202. }
  203. if (Type == FetchType.Text)
  204. Message.Text = MessageContents;
  205. else
  206. Message.Html = MessageContents;
  207. }
  208. }
  209.  
  210.  
  211. public EmailMessage[] FetchLast(int Total, int Count)
  212. {
  213. List<EmailMessage> Emails = new List<EmailMessage>();
  214. for (int i = Total; i >= (Total - Count); i--)
  215. {
  216.  
  217. Emails.Add(Fetch(i));
  218. }
  219. return Emails.ToArray();
  220. }
  221.  
  222.  
  223. public EmailMessage Fetch(int Number)
  224. {
  225. EmailMessage Message = new EmailMessage();
  226. Message.ID = (uint)Number;
  227.  
  228. FetchBodystructure(ref Message);
  229. FetchHeaders(ref Message);
  230. FetchBody(ref Message, FetchType.Text);
  231. FetchBody(ref Message, FetchType.Html);
  232.  
  233. return Message;
  234. }
  235. private void FetchHeaders(ref EmailMessage Message)
  236. {
  237. ExecuteCommand(string.Format("FETCH {0} (BODY[HEADER.FIELDS (FROM SUBJECT DATE)])", Message.ID));
  238. string Response = ReadMultiline();
  239.  
  240. string[] Contents = Response.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
  241. for (int i = 0; i < Contents.Length; i++)
  242. {
  243. string Line = Contents[i];
  244. if (Line.StartsWith("Subject: "))
  245. {
  246. string Subject = Line.Substring(9);
  247. for (int Counter = i + 1; Counter < Contents.Length; Counter++)
  248. {
  249. string NextLine = Contents[Counter].TrimStart();
  250. if (NextLine.StartsWith(Subject.Substring(0, 2)))
  251. {
  252. Subject += NextLine;
  253. }
  254. else
  255. break;
  256. }
  257. Message.Subject = Decoder.DecodeMessage(Subject);
  258. }
  259. else if (Line.StartsWith("From: "))
  260. {
  261.  
  262. Message.From = EmailAddress.Parse(Decoder.DecodeMessage(Line.Substring(6)));
  263.  
  264. }
  265. else if (Line.StartsWith("Date: "))
  266. {
  267. int TimezoneIndex = Line.LastIndexOf(" ");
  268. string Date = Line.Substring(6, TimezoneIndex - 6);
  269. string Timezone = Line.Substring(TimezoneIndex + 1);
  270.  
  271. Timezone = Timezone.Substring(0, 3);
  272.  
  273.  
  274. DateTime Time;
  275. if (DateTime.TryParse(Date, out Time))
  276. {
  277. int TimeDifference;
  278. if (int.TryParse(Timezone, out TimeDifference))
  279. {
  280. Message.Time = new DateTimeOffset(Time, new TimeSpan(TimeDifference, 0, 0));
  281. }
  282. }
  283.  
  284. }
  285. }
  286. }
  287.  
  288. private void FetchBodystructure(ref EmailMessage Message)
  289. {
  290. ExecuteCommand(string.Format("FETCH {0} BODYSTRUCTURE", Message.ID));
  291. string Response = ReadMultiline();
  292.  
  293. // Email doesn't exists. Server sends only 'Finish'-Command
  294. if (ResponseEnd(Response)) return;
  295.  
  296. #region Remove all unneccesary data from Response
  297. Response = Response.Replace("\r\n", "");
  298. Response = Response.Remove(0, Response.IndexOf(" (", Response.IndexOf("BODYSTRUCTURE")));
  299. Response = Response.Remove(Response.LastIndexOf("TP"));
  300. Response = Response.Trim();
  301. Response = Response.Remove(Response.Length - 1);
  302. #endregion
  303.  
  304. Message.Parts = ParseBodystructure(Response);
  305. for (int i = 0; i < Message.Parts.Count; i++)
  306. {
  307. BodyPart Part = Message.Parts[i];
  308. if (Part.MediaType == "text/plain")
  309. {
  310. Message.TextIndex = i;
  311. }
  312. else if (Part.MediaType == "text/html")
  313. {
  314. Message.HtmlIndex = i;
  315. }
  316. }
  317. }
  318.  
  319. private BodyPartList ParseBodystructure(string Data)
  320. {
  321. BodyPartList Parts = new BodyPartList();
  322.  
  323. int counter = 0;
  324. int index = 1;
  325. int count = 0;
  326.  
  327. do
  328. {
  329. int next = index;
  330. do
  331. {
  332. if (Data[next] == '(')
  333. counter++;
  334. else if (Data[next] == ')')
  335. counter--;
  336. next++;
  337. } while (counter > 0 || Data[next - 1] != ')');
  338.  
  339. if (counter >= 0 && Data[index] == '(')
  340. {
  341. count++;
  342. if (Data.Substring(index, next - index).StartsWith("(("))
  343. {
  344. BodyPartList tmp = ParseBodystructure(Data.Substring(index, next));
  345. for (int j = 0; j < tmp.Count; j++)
  346. {
  347. tmp[j].Index = count.ToString() + "." + tmp[j].Index;
  348. Parts.Add(tmp[j]);
  349. }
  350. }
  351. else
  352. {
  353. BodyPart Part = new BodyPart(Data.Substring(index, next - index));
  354. Part.Index = count.ToString();
  355. Parts.Add(Part);
  356. }
  357. }
  358. else if (Parts.Count == 0)
  359. {
  360. BodyPart Part = new BodyPart(Data);
  361. Part.Index = "1";
  362. Parts.Add(Part);
  363. }
  364. index = next;
  365. } while (counter >= 0);
  366.  
  367. return Parts;
  368. }
  369.  
  370.  
  371. private void ExecuteCommand(string Command)
  372. {
  373. Command = string.Format("TP{0} {1}\r\n", CurrentCommand++, Command);
  374. Stream.Write(Encoding.ASCII.GetBytes(Command));
  375. Stream.Flush();
  376. }
  377. private string ReadLine()
  378. {
  379. return Reader.ReadLine();
  380. }
  381. private bool ResponseEnd(string Response)
  382. {
  383. string End = string.Format("TP{0} OK", CurrentCommand - 1);
  384. return Response.StartsWith(End);
  385. }
  386. private string ReadMultiline()
  387. {
  388. string Response = Reader.ReadLine();
  389. string ServerOk = string.Format("TP{0} OK", CurrentCommand - 1);
  390. string ServerBad = string.Format("TP{0} BAD", CurrentCommand - 1);
  391.  
  392. if (Response.StartsWith(ServerBad)) return "";
  393. while (!Response.StartsWith(ServerOk))
  394. {
  395. string CurrentLine = Reader.ReadLine();
  396. Response = Response + "\r\n" + CurrentLine;
  397. if (CurrentLine.StartsWith(ServerOk)) break;
  398. }
  399. return Response;
  400. }
  401. private bool ValidResponse(string Response)
  402. {
  403. return (Response.Length > 0 && Response[0] == '*');
  404. }
  405. }
  406. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement