POP3Server.C 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /*
  24. *+SNOTICE
  25. *
  26. * $TOG: POP3Server.C /main/8 1998/11/10 17:09:21 mgreess $
  27. *
  28. * RESTRICTED CONFIDENTIAL INFORMATION:
  29. *
  30. * The information in this document is subject to special
  31. * restrictions in a confidential disclosure agreement between
  32. * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
  33. * document outside HP, IBM, Sun, USL, SCO, or Univel without
  34. * Sun's specific written approval. This document and all copies
  35. * and derivative works thereof must be returned or destroyed at
  36. * Sun's request.
  37. *
  38. * Copyright 1993, 1995, 1995 Sun Microsystems, Inc. All rights reserved.
  39. *
  40. *+ENOTICE
  41. */
  42. /*
  43. * Common Desktop Environment
  44. *
  45. * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
  46. * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
  47. * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
  48. * (c) Copyright 1993, 1994, 1995 Novell, Inc.
  49. * (c) Copyright 1995 Digital Equipment Corp.
  50. * (c) Copyright 1995 Fujitsu Limited
  51. * (c) Copyright 1995 Hitachi, Ltd.
  52. *
  53. *
  54. * RESTRICTED RIGHTS LEGEND
  55. *
  56. *Use, duplication, or disclosure by the U.S. Government is subject to
  57. *restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in
  58. *Technical Data and Computer Software clause in DFARS 252.227-7013. Rights
  59. *for non-DOD U.S. Government Departments and Agencies are as set forth in
  60. *FAR 52.227-19(c)(1,2).
  61. *Hewlett-Packard Company, 3000 Hanover Street, Palo Alto, CA 94304 U.S.A.
  62. *International Business Machines Corp., Route 100, Somers, NY 10589 U.S.A.
  63. *Sun Microsystems, Inc., 2550 Garcia Avenue, Mountain View, CA 94043 U.S.A.
  64. *Novell, Inc., 190 River Road, Summit, NJ 07901 U.S.A.
  65. *Digital Equipment Corp., 111 Powdermill Road, Maynard, MA 01754, U.S.A.
  66. *Fujitsu Limited, 1015, Kamikodanaka Nakahara-Ku, Kawasaki 211, Japan
  67. *Hitachi, Ltd., 6, Kanda Surugadai 4-Chome, Chiyoda-ku, Tokyo 101, Japan
  68. */
  69. #include <ctype.h>
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <strings.h>
  74. #include <sys/param.h>
  75. #include <unistd.h>
  76. #include <DtMail/DtMail.hh>
  77. #include <DtMail/DtMailError.hh>
  78. #include <DtMail/DtMailServer.hh>
  79. #include <DtMail/DtVirtArray.hh>
  80. #include <DtMail/IO.hh>
  81. POP3Server::POP3Server(
  82. char *folder,
  83. DtMail::Session *session,
  84. DtMail::MailBox *mailbox,
  85. DtMailAppendCallback append_mailbox_cb,
  86. void *append_mailbox_cb_data)
  87. : DtMailServer(folder, session, mailbox,
  88. append_mailbox_cb, append_mailbox_cb_data)
  89. {
  90. _lastretrieved = 0;
  91. _uidlist_old = NULL;
  92. _uidlist_current = NULL;
  93. _uidlist_file = NULL;
  94. }
  95. POP3Server::~POP3Server()
  96. {
  97. if (_uidlist_old)
  98. uidlist_destroy(_uidlist_old);
  99. _uidlist_old = NULL;
  100. if (_uidlist_current)
  101. uidlist_destroy(_uidlist_current);
  102. _uidlist_current = NULL;
  103. if (_uidlist_file)
  104. free(_uidlist_file);
  105. }
  106. //
  107. // Delete a given message.
  108. //
  109. DTMailError_t
  110. POP3Server::ptrans_delete(int msg)
  111. {
  112. if (_uidlist_current)
  113. {
  114. char *uidliststr;
  115. uidliststr = uidlist_find(_uidlist_current, msg, NULL);
  116. _uidlist_current->remove(uidliststr);
  117. free(uidliststr);
  118. }
  119. return do_transaction("DELE %d", msg);
  120. }
  121. //
  122. // Request nth message.
  123. //
  124. DTMailError_t
  125. POP3Server::ptrans_retrieve_start(int msg, int *lenp)
  126. {
  127. DTMailError_t ok;
  128. char buf[DTMAS_POPBUFSIZE+1];
  129. char *cp;
  130. ok = do_send("RETR %d", msg);
  131. if (DTME_NoError != ok) return ok;
  132. ok = ptrans_parse_response(buf);
  133. if (DTME_NoError != ok) return ok;
  134. // Look for "nnn octets" -- there may or may not be preceding cruft.
  135. if ((cp = strstr(buf, " octets")) == (char *)NULL)
  136. *lenp = 0;
  137. else
  138. {
  139. while (--cp > buf && isdigit(*cp))
  140. continue;
  141. *lenp = atoi(cp);
  142. }
  143. return DTME_NoError;
  144. }
  145. //
  146. // Apply for connection authorization.
  147. //
  148. DTMailError_t
  149. POP3Server::ptrans_authorize(char*)
  150. {
  151. static char *pname = "POP3Server::ptrans_authorize";
  152. DTMailError_t ok;
  153. ok = do_transaction("USER %s", _username);
  154. if (DTME_NoError != ok) return DTME_MailServerAccess_AuthorizationFailed;
  155. ok = do_transaction("PASS %s", _password);
  156. if (DTME_NoError != ok) return DTME_MailServerAccess_AuthorizationFailed;
  157. // We're approved.
  158. return DTME_NoError;
  159. }
  160. //
  161. // Get range of messages to be fetched.
  162. //
  163. DTMailError_t
  164. POP3Server::ptrans_fldstate_read(int *countp, int *newp)
  165. {
  166. static char *pname = "POP3Server::ptrans_fldstate_read";
  167. DTMailError_t ok;
  168. char buf[DTMAS_POPBUFSIZE+1];
  169. /* get the total message count */
  170. ok = do_send("STAT");
  171. if (DTME_NoError != ok) return ok;
  172. ok = ptrans_parse_response(buf);
  173. if (DTME_NoError != ok) return ok;
  174. sscanf(buf, "%d %*d", countp);
  175. /*
  176. * Newer, RFC-1725-conformant POP servers may not have the LAST command.
  177. * We work as hard as possible to hide this ugliness, but it makes
  178. * counting new messages intrinsically quadratic in the worst case.
  179. */
  180. *newp = -1;
  181. if (*countp > 0)
  182. {
  183. ok = do_send("LAST");
  184. if (DTME_NoError != ok) return ok;
  185. ok = ptrans_parse_response(buf);
  186. if (DTME_NoError == ok)
  187. {
  188. int last = 0;
  189. if (sscanf(buf, "%d", &last) == 0)
  190. _logger.logError(DTM_FALSE, "Protocol Error getting range");
  191. if (0 == _retrieveerrors) _lastretrieved = last;
  192. *newp = (*countp - _lastretrieved);
  193. }
  194. else
  195. {
  196. if (NULL == _uidlist_old)
  197. {
  198. _uidlist_old = uidlist_create();
  199. uidlist_read(_uidlist_old);
  200. }
  201. if (NULL == _uidlist_current)
  202. _uidlist_current = uidlist_create();
  203. /* grab the mailbox's UID list */
  204. ok = do_transaction("UIDL");
  205. if (DTME_NoError != ok)
  206. return ok;
  207. else
  208. {
  209. int curmsg;
  210. char curuidstr[DTMAS_IDSIZE+1];
  211. *newp = 0;
  212. while (SockGets(buf, sizeof(buf), _sockfp))
  213. {
  214. if (buf[strlen(buf)-1] == '\n')
  215. buf[strlen(buf)-1] = '\0';
  216. if (buf[strlen(buf)-1] == '\r')
  217. buf[strlen(buf)-1] = '\r';
  218. if (_protologging)
  219. _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
  220. if (buf[0] == '.')
  221. break;
  222. else if (sscanf(buf, "%d %s", &curmsg, curuidstr) == 2)
  223. {
  224. char *uidliststr = NULL;
  225. _uidlist_current->append(strdup(buf));
  226. uidliststr = uidlist_find(_uidlist_old, -1, curuidstr);
  227. if (uidliststr)
  228. (*newp)++;
  229. }
  230. }
  231. }
  232. }
  233. }
  234. return DTME_NoError;
  235. }
  236. //
  237. // Capture the sizes of all messages.
  238. //
  239. DTMailError_t
  240. POP3Server::ptrans_msgsizes(int, int *sizes)
  241. {
  242. static char *pname = "POP3Server::ptrans_msgsizes";
  243. char buf[DTMAS_POPBUFSIZE+1];
  244. DTMailError_t ok;
  245. ok = do_transaction("LIST");
  246. if (DTME_NoError != ok) return ok;
  247. while (SockGets(buf, sizeof(buf), _sockfp))
  248. {
  249. int curmsg, cursize;
  250. if (buf[strlen(buf)-1] == '\n')
  251. buf[strlen(buf)-1] = '\0';
  252. if (buf[strlen(buf)-1] == '\r')
  253. buf[strlen(buf)-1] = '\r';
  254. if (_protologging)
  255. _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
  256. if (buf[0] == '.')
  257. break;
  258. else if (sscanf(buf, "%d %d", &curmsg, &cursize) == 2)
  259. sizes[curmsg-1] = cursize;
  260. else
  261. sizes[curmsg-1] = -1;
  262. }
  263. return DTME_NoError;
  264. }
  265. //
  266. // Is the given message old?
  267. //
  268. int
  269. POP3Server::ptrans_msgisold(int msg)
  270. {
  271. if (NULL == _uidlist_old)
  272. return (msg <= _lastretrieved);
  273. else
  274. {
  275. char curuidstr[DTMAS_IDSIZE+1];
  276. int curmsg;
  277. char *uidliststr = NULL;
  278. uidliststr = uidlist_find(_uidlist_current, msg, NULL);
  279. if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
  280. uidliststr = uidlist_find(_uidlist_old, -1, curuidstr);
  281. else
  282. uidliststr = NULL;
  283. if (NULL != uidliststr)
  284. return 1;
  285. else
  286. return 0;
  287. }
  288. }
  289. //
  290. // parse command response.
  291. //
  292. DTMailError_t
  293. POP3Server::ptrans_parse_response (char *argbuf)
  294. {
  295. DTMailError_t ok;
  296. char buf[DTMAS_POPBUFSIZE+1];
  297. char *bufp;
  298. if (SockGets(buf, sizeof(buf), _sockfp))
  299. {
  300. if (buf[strlen(buf)-1] == '\n')
  301. buf[strlen(buf)-1] = '\0';
  302. if (buf[strlen(buf)-1] == '\r')
  303. buf[strlen(buf)-1] = '\r';
  304. if (_protologging)
  305. _logger.logError(DTM_FALSE, "%s< %s", proto_name(), buf);
  306. bufp = buf;
  307. if (*bufp == '+' || *bufp == '-')
  308. bufp++;
  309. else
  310. return DTME_MailServerAccess_ProtocolViolation;
  311. while (isalpha(*bufp)) bufp++;
  312. *(bufp++) = '\0';
  313. if (strcmp(buf,"+OK") == 0)
  314. {
  315. ok = DTME_NoError;
  316. }
  317. else if (strcmp(buf,"-ERR") == 0)
  318. {
  319. _logger.logError(DTM_FALSE, "Protocol Error reading response");
  320. ok = DTME_MailServerAccess_Error;
  321. }
  322. else
  323. {
  324. _logger.logError(DTM_FALSE, "Protocol Violation reading response");
  325. ok = DTME_MailServerAccess_ProtocolViolation;
  326. }
  327. if (argbuf != NULL)
  328. strcpy(argbuf,bufp);
  329. }
  330. else
  331. {
  332. _logger.logError(DTM_FALSE, "Socket Error reading response");
  333. ok = DTME_MailServerAccess_SocketIOError;
  334. }
  335. return ok;
  336. }
  337. //
  338. // Retrieve messages using POP3.
  339. //
  340. void
  341. POP3Server::retrieve_messages(DtMailEnv &error)
  342. {
  343. DtMailServer::retrieve_messages(error);
  344. uidlist_destroy(_uidlist_old);
  345. _uidlist_old = _uidlist_current;
  346. uidlist_write(_uidlist_old);
  347. _uidlist_current = NULL;
  348. }
  349. DtVirtArray<char*>*
  350. POP3Server::uidlist_create()
  351. {
  352. DtVirtArray<char*> *uidlist = new DtVirtArray<char*>(25);
  353. return uidlist;
  354. }
  355. void
  356. POP3Server::uidlist_destroy(DtVirtArray<char*> *uidlist)
  357. {
  358. int i, nuidliststr;
  359. char *uidliststr;
  360. if (NULL == uidlist) return;
  361. for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
  362. {
  363. uidliststr = (*uidlist)[i];
  364. if (NULL != uidliststr)
  365. free(uidliststr);
  366. }
  367. delete uidlist;
  368. }
  369. char*
  370. POP3Server::uidlist_find(
  371. DtVirtArray<char*> *uidlist,
  372. int msg,
  373. char *uidstr)
  374. {
  375. char *uidliststr;
  376. int i, nuidliststr;
  377. if (msg < 0 && NULL == uidstr) return NULL;
  378. for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
  379. {
  380. int curmsg;
  381. char curuidstr[DTMAS_IDSIZE+1];
  382. uidliststr = (*uidlist)[i];
  383. if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
  384. {
  385. if ((msg < 0 || msg == curmsg) &&
  386. (uidstr == NULL || 0 == strcasecmp(uidstr, curuidstr)))
  387. return uidliststr;
  388. }
  389. }
  390. return NULL;
  391. }
  392. void
  393. POP3Server::uidlist_read(DtVirtArray<char*> *uidlist)
  394. {
  395. static char *pname = "POP3Server::uidlist_read";
  396. DtMailEnv error;
  397. FILE *fp;
  398. if (NULL == uidlist) return;
  399. if (NULL == _uidlist_file)
  400. {
  401. char *path = new char[MAXPATHLEN+1];
  402. sprintf(path, "+/.%s@%s.uidlist", _folder, _servername);
  403. _uidlist_file = _session->expandPath(error, (const char*) path);
  404. if (NULL == _uidlist_file && error.isSet())
  405. {
  406. _logger.logError(
  407. DTM_FALSE,
  408. "%s: Failed to find uidlist file %s\n",
  409. pname, path);
  410. delete [] path;
  411. return;
  412. }
  413. delete [] path;
  414. }
  415. if (NULL != (fp = fopen(_uidlist_file, "r")))
  416. {
  417. char uidliststr[DTMAS_POPBUFSIZE+1];
  418. char curuidstr[DTMAS_IDSIZE+1];
  419. int curmsg;
  420. while (NULL != fgets(uidliststr, DTMAS_POPBUFSIZE, fp))
  421. if (sscanf(uidliststr, "%d %s", &curmsg, curuidstr) == 2)
  422. uidlist->append(strdup(uidliststr));
  423. fclose(fp);
  424. }
  425. }
  426. void
  427. POP3Server::uidlist_write(DtVirtArray<char*> *uidlist)
  428. {
  429. FILE *fp;
  430. char *uidliststr;
  431. int i, nuidliststr;
  432. if (NULL == uidlist || NULL == _uidlist_file) return;
  433. if (NULL != (fp = fopen(_uidlist_file, "w")))
  434. {
  435. for (i=0, nuidliststr=uidlist->length(); i<nuidliststr; i++)
  436. {
  437. uidliststr = (*uidlist)[i];
  438. fprintf(fp, "%s\n", uidliststr);
  439. }
  440. fclose(fp);
  441. }
  442. }