imap.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394
  1. /* $Id$
  2. *
  3. * isync - IMAP4 to maildir mailbox synchronizer
  4. * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
  5. * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * As a special exception, isync may be linked with the OpenSSL library,
  22. * despite that library's more restrictive license.
  23. */
  24. #include "isync.h"
  25. #include <assert.h>
  26. #include <unistd.h>
  27. #include <sys/mman.h>
  28. #include <sys/time.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <stdarg.h>
  32. #include <errno.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <sys/socket.h>
  36. #include <netinet/in.h>
  37. #include <arpa/inet.h>
  38. #include <netdb.h>
  39. #if HAVE_LIBSSL
  40. # include <openssl/err.h>
  41. #endif
  42. static int Tag;
  43. const char *Flags[] = {
  44. "\\Seen",
  45. "\\Answered",
  46. "\\Deleted",
  47. "\\Flagged",
  48. "\\Recent",
  49. "\\Draft"
  50. };
  51. void
  52. free_message (message_t * msg)
  53. {
  54. message_t *tmp;
  55. while (msg)
  56. {
  57. tmp = msg;
  58. msg = msg->next;
  59. if (tmp->file)
  60. free (tmp->file);
  61. free (tmp);
  62. }
  63. }
  64. #if HAVE_LIBSSL
  65. #define MAX_DEPTH 1
  66. SSL_CTX *SSLContext = 0;
  67. /* this gets called when a certificate is to be verified */
  68. static int
  69. verify_cert (SSL * ssl)
  70. {
  71. X509 *cert;
  72. int err;
  73. char buf[256];
  74. int ret = -1;
  75. BIO *bio;
  76. cert = SSL_get_peer_certificate (ssl);
  77. if (!cert)
  78. {
  79. fprintf (stderr, "Error, no server certificate\n");
  80. return -1;
  81. }
  82. err = SSL_get_verify_result (ssl);
  83. if (err == X509_V_OK)
  84. return 0;
  85. fprintf (stderr, "Error, can't verify certificate: %s (%d)\n",
  86. X509_verify_cert_error_string (err), err);
  87. X509_NAME_oneline (X509_get_subject_name (cert), buf, sizeof (buf));
  88. info ("\nSubject: %s\n", buf);
  89. X509_NAME_oneline (X509_get_issuer_name (cert), buf, sizeof (buf));
  90. info ("Issuer: %s\n", buf);
  91. bio = BIO_new (BIO_s_mem ());
  92. ASN1_TIME_print (bio, X509_get_notBefore (cert));
  93. memset (buf, 0, sizeof (buf));
  94. BIO_read (bio, buf, sizeof (buf) - 1);
  95. info ("Valid from: %s\n", buf);
  96. ASN1_TIME_print (bio, X509_get_notAfter (cert));
  97. memset (buf, 0, sizeof (buf));
  98. BIO_read (bio, buf, sizeof (buf) - 1);
  99. BIO_free (bio);
  100. info (" to: %s\n", buf);
  101. fprintf (stderr,
  102. "\n*** WARNING *** There is no way to verify this certificate. It is\n"
  103. " possible that a hostile attacker has replaced the\n"
  104. " server certificate. Continue at your own risk!\n"
  105. "\nAccept this certificate anyway? [no]: ");
  106. if (fgets (buf, sizeof (buf), stdin) && (buf[0] == 'y' || buf[0] == 'Y'))
  107. {
  108. ret = 0;
  109. fprintf (stderr, "\n*** Fine, but don't say I didn't warn you!\n\n");
  110. }
  111. return ret;
  112. }
  113. static int
  114. init_ssl (config_t * conf)
  115. {
  116. SSL_METHOD *method;
  117. int options = 0;
  118. if (!conf->cert_file)
  119. {
  120. fprintf (stderr, "Error, CertificateFile not defined\n");
  121. return -1;
  122. }
  123. SSL_library_init ();
  124. SSL_load_error_strings ();
  125. if (conf->use_tlsv1 && !conf->use_sslv2 && !conf->use_sslv3)
  126. method = TLSv1_client_method ();
  127. else
  128. method = SSLv23_client_method ();
  129. SSLContext = SSL_CTX_new (method);
  130. if (access (conf->cert_file, R_OK))
  131. {
  132. if (errno != ENOENT)
  133. {
  134. perror ("access");
  135. return -1;
  136. }
  137. warn ("*** Warning: CertificateFile doesn't exist, can't verify server certificates\n");
  138. }
  139. else
  140. if (!SSL_CTX_load_verify_locations
  141. (SSLContext, conf->cert_file, NULL))
  142. {
  143. fprintf (stderr, "Error, SSL_CTX_load_verify_locations: %s\n",
  144. ERR_error_string (ERR_get_error (), 0));
  145. return -1;
  146. }
  147. if (!conf->use_sslv2)
  148. options |= SSL_OP_NO_SSLv2;
  149. if (!conf->use_sslv3)
  150. options |= SSL_OP_NO_SSLv3;
  151. if (!conf->use_tlsv1)
  152. options |= SSL_OP_NO_TLSv1;
  153. SSL_CTX_set_options (SSLContext, options);
  154. /* we check the result of the verification after SSL_connect() */
  155. SSL_CTX_set_verify (SSLContext, SSL_VERIFY_NONE, 0);
  156. return 0;
  157. }
  158. #endif /* HAVE_LIBSSL */
  159. static int
  160. socket_read (Socket_t * sock, char *buf, size_t len)
  161. {
  162. #if HAVE_LIBSSL
  163. if (sock->use_ssl)
  164. return SSL_read (sock->ssl, buf, len);
  165. #endif
  166. return read (sock->fd, buf, len);
  167. }
  168. static int
  169. socket_write (Socket_t * sock, char *buf, size_t len)
  170. {
  171. #if HAVE_LIBSSL
  172. if (sock->use_ssl)
  173. return SSL_write (sock->ssl, buf, len);
  174. #endif
  175. return write (sock->fd, buf, len);
  176. }
  177. static void
  178. socket_perror (const char *func, Socket_t *sock, int ret)
  179. {
  180. #if HAVE_LIBSSL
  181. int err;
  182. if (sock->use_ssl)
  183. {
  184. switch ((err = SSL_get_error (sock->ssl, ret)))
  185. {
  186. case SSL_ERROR_SYSCALL:
  187. case SSL_ERROR_SSL:
  188. if ((err = ERR_get_error ()) == 0)
  189. {
  190. if (ret == 0)
  191. fprintf (stderr, "SSL_%s:got EOF\n", func);
  192. else
  193. fprintf (stderr, "SSL_%s:%d:%s\n", func,
  194. errno, strerror (errno));
  195. }
  196. else
  197. fprintf (stderr, "SSL_%s:%d:%s\n", func, err,
  198. ERR_error_string (err, 0));
  199. return;
  200. default:
  201. fprintf (stderr, "SSL_%s:%d:unhandled SSL error\n", func, err);
  202. break;
  203. }
  204. return;
  205. }
  206. #else
  207. (void) sock;
  208. #endif
  209. if (ret)
  210. perror (func);
  211. else
  212. fprintf (stderr, "%s: unexpected EOF\n", func);
  213. }
  214. /* simple line buffering */
  215. static int
  216. buffer_gets (buffer_t * b, char **s)
  217. {
  218. int n;
  219. int start = b->offset;
  220. *s = b->buf + start;
  221. for (;;)
  222. {
  223. /* make sure we have enough data to read the \r\n sequence */
  224. if (b->offset + 1 >= b->bytes)
  225. {
  226. if (start != 0)
  227. {
  228. /* shift down used bytes */
  229. *s = b->buf;
  230. assert (start <= b->bytes);
  231. n = b->bytes - start;
  232. if (n)
  233. memmove (b->buf, b->buf + start, n);
  234. b->offset -= start;
  235. b->bytes = n;
  236. start = 0;
  237. }
  238. n =
  239. socket_read (b->sock, b->buf + b->bytes,
  240. sizeof (b->buf) - b->bytes);
  241. if (n <= 0)
  242. {
  243. socket_perror ("read", b->sock, n);
  244. return -1;
  245. }
  246. b->bytes += n;
  247. }
  248. if (b->buf[b->offset] == '\r')
  249. {
  250. assert (b->offset + 1 < b->bytes);
  251. if (b->buf[b->offset + 1] == '\n')
  252. {
  253. b->buf[b->offset] = 0; /* terminate the string */
  254. b->offset += 2; /* next line */
  255. if (Verbose) {
  256. puts (*s);
  257. fflush (stdout);
  258. }
  259. return 0;
  260. }
  261. }
  262. b->offset++;
  263. }
  264. /* not reached */
  265. }
  266. static int
  267. parse_fetch (imap_t * imap, list_t * list)
  268. {
  269. list_t *tmp;
  270. unsigned int uid = 0;
  271. unsigned int mask = 0;
  272. unsigned int size = 0;
  273. message_t *cur;
  274. if (!is_list (list))
  275. return -1;
  276. for (tmp = list->child; tmp; tmp = tmp->next)
  277. {
  278. if (is_atom (tmp))
  279. {
  280. if (!strcmp ("UID", tmp->val))
  281. {
  282. tmp = tmp->next;
  283. if (is_atom (tmp))
  284. {
  285. uid = atoi (tmp->val);
  286. if (uid < imap->minuid)
  287. {
  288. /* already saw this message */
  289. return 0;
  290. }
  291. else if (uid > imap->maxuid)
  292. imap->maxuid = uid;
  293. }
  294. else
  295. fprintf (stderr, "IMAP error: unable to parse UID\n");
  296. }
  297. else if (!strcmp ("FLAGS", tmp->val))
  298. {
  299. tmp = tmp->next;
  300. if (is_list (tmp))
  301. {
  302. list_t *flags = tmp->child;
  303. for (; flags; flags = flags->next)
  304. {
  305. if (is_atom (flags))
  306. {
  307. if (!strcmp ("\\Seen", flags->val))
  308. mask |= D_SEEN;
  309. else if (!strcmp ("\\Flagged", flags->val))
  310. mask |= D_FLAGGED;
  311. else if (!strcmp ("\\Deleted", flags->val))
  312. mask |= D_DELETED;
  313. else if (!strcmp ("\\Answered", flags->val))
  314. mask |= D_ANSWERED;
  315. else if (!strcmp ("\\Draft", flags->val))
  316. mask |= D_DRAFT;
  317. else if (!strcmp ("\\Recent", flags->val))
  318. mask |= D_RECENT;
  319. else
  320. fprintf (stderr, "IMAP error: unknown flag %s\n",
  321. flags->val);
  322. }
  323. else
  324. fprintf (stderr, "IMAP error: unable to parse FLAGS list\n");
  325. }
  326. }
  327. else
  328. fprintf (stderr, "IMAP error: unable to parse FLAGS\n");
  329. }
  330. else if (!strcmp ("RFC822.SIZE", tmp->val))
  331. {
  332. tmp = tmp->next;
  333. if (is_atom (tmp))
  334. size = atol (tmp->val);
  335. }
  336. }
  337. }
  338. cur = calloc (1, sizeof (message_t));
  339. cur->next = imap->msgs;
  340. imap->msgs = cur;
  341. if (mask & D_DELETED)
  342. imap->deleted++;
  343. cur->uid = uid;
  344. cur->flags = mask;
  345. cur->size = size;
  346. return 0;
  347. }
  348. static void
  349. parse_response_code (imap_t * imap, char *s)
  350. {
  351. char *arg;
  352. if (*s != '[')
  353. return; /* no response code */
  354. s++;
  355. arg = next_arg (&s);
  356. if (!strcmp ("UIDVALIDITY", arg))
  357. {
  358. arg = next_arg (&s);
  359. imap->uidvalidity = atol (arg);
  360. }
  361. else if (!strcmp ("ALERT", arg))
  362. {
  363. /* RFC2060 says that these messages MUST be displayed
  364. * to the user
  365. */
  366. fprintf (stderr, "*** IMAP ALERT *** %s\n", s);
  367. }
  368. }
  369. static int
  370. imap_exec (imap_t * imap, const char *fmt, ...)
  371. {
  372. va_list ap;
  373. char tmp[256];
  374. char buf[256];
  375. char *cmd;
  376. char *arg;
  377. char *arg1;
  378. config_t *box;
  379. int n;
  380. va_start (ap, fmt);
  381. vsnprintf (tmp, sizeof (tmp), fmt, ap);
  382. va_end (ap);
  383. snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp);
  384. if (Verbose) {
  385. printf (">>> %s", buf);
  386. fflush (stdout);
  387. }
  388. n = socket_write (imap->sock, buf, strlen (buf));
  389. if (n <= 0)
  390. {
  391. socket_perror ("write", imap->sock, n);
  392. return -1;
  393. }
  394. for (;;)
  395. {
  396. next:
  397. if (buffer_gets (imap->buf, &cmd))
  398. return -1;
  399. arg = next_arg (&cmd);
  400. if (*arg == '*')
  401. {
  402. arg = next_arg (&cmd);
  403. if (!arg)
  404. {
  405. fprintf (stderr, "IMAP error: unable to parse untagged response\n");
  406. return -1;
  407. }
  408. if (!strcmp ("NAMESPACE", arg))
  409. {
  410. imap->ns_personal = parse_list (cmd, &cmd);
  411. imap->ns_other = parse_list (cmd, &cmd);
  412. imap->ns_shared = parse_list (cmd, 0);
  413. }
  414. else if (!strcmp ("OK", arg) || !strcmp ("BAD", arg) ||
  415. !strcmp ("NO", arg) || !strcmp ("BYE", arg) ||
  416. !strcmp ("PREAUTH", arg))
  417. {
  418. parse_response_code (imap, cmd);
  419. }
  420. else if (!strcmp ("CAPABILITY", arg))
  421. {
  422. while ((arg = next_arg (&cmd)))
  423. {
  424. if (!strcmp ("UIDPLUS", arg))
  425. imap->have_uidplus = 1;
  426. else if (!strcmp ("NAMESPACE", arg))
  427. imap->have_namespace = 1;
  428. #if HAVE_LIBSSL
  429. else if (!strcmp ("STARTTLS", arg))
  430. imap->have_starttls = 1;
  431. else if (!strcmp ("AUTH=CRAM-MD5", arg))
  432. imap->have_cram = 1;
  433. #endif
  434. }
  435. }
  436. else if (!strcmp ("LIST", arg))
  437. {
  438. list_t *list, *lp;
  439. int l;
  440. list = parse_list (cmd, &cmd);
  441. if (list->val == LIST)
  442. for (lp = list->child; lp; lp = lp->next)
  443. if (is_atom (lp) &&
  444. !strcasecmp (lp->val, "\\NoSelect"))
  445. {
  446. free_list (list);
  447. goto next;
  448. }
  449. free_list (list);
  450. (void) next_arg (&cmd); /* skip delimiter */
  451. arg = next_arg (&cmd);
  452. l = strlen (global.folder);
  453. if (memcmp (arg, global.folder, l))
  454. goto next;
  455. arg += l;
  456. if (!memcmp (arg + strlen (arg) - 5, ".lock", 5))
  457. goto next;
  458. for (box = boxes; box; box = box->next)
  459. if (!strcmp (box->box, arg))
  460. goto next;
  461. box = malloc (sizeof (config_t));
  462. memcpy (box, &global, sizeof (config_t));
  463. box->path = strdup (arg);
  464. box->box = box->path;
  465. box->next = boxes;
  466. boxes = box;
  467. }
  468. else if ((arg1 = next_arg (&cmd)))
  469. {
  470. if (!strcmp ("EXISTS", arg1))
  471. imap->count = atoi (arg);
  472. else if (!strcmp ("RECENT", arg1))
  473. imap->recent = atoi (arg);
  474. else if (!strcmp ("FETCH", arg1))
  475. {
  476. list_t *list;
  477. list = parse_list (cmd, 0);
  478. if (parse_fetch (imap, list))
  479. {
  480. free_list (list);
  481. return -1;
  482. }
  483. free_list (list);
  484. }
  485. }
  486. else
  487. {
  488. fprintf (stderr, "IMAP error: unable to parse untagged response\n");
  489. return -1;
  490. }
  491. }
  492. #if HAVE_LIBSSL
  493. else if (*arg == '+')
  494. {
  495. char *resp;
  496. if (!imap->cram)
  497. {
  498. fprintf (stderr, "IMAP error, not doing CRAM-MD5 authentication\n");
  499. return -1;
  500. }
  501. resp = cram (cmd, imap->box->user, imap->box->pass);
  502. if (Verbose) {
  503. printf (">+> %s\n", resp);
  504. fflush (stdout);
  505. }
  506. n = socket_write (imap->sock, resp, strlen (resp));
  507. free (resp);
  508. if (n <= 0)
  509. {
  510. socket_perror ("write", imap->sock, n);
  511. return -1;
  512. }
  513. n = socket_write (imap->sock, "\r\n", 2);
  514. if (n <= 0)
  515. {
  516. socket_perror ("write", imap->sock, n);
  517. return -1;
  518. }
  519. imap->cram = 0;
  520. }
  521. #endif
  522. else if (atoi (arg) != Tag)
  523. {
  524. fprintf (stderr, "IMAP error: wrong tag\n");
  525. return -1;
  526. }
  527. else
  528. {
  529. arg = next_arg (&cmd);
  530. parse_response_code (imap, cmd);
  531. if (!strcmp ("OK", arg))
  532. return 0;
  533. return -1;
  534. }
  535. }
  536. /* not reached */
  537. }
  538. #ifdef HAVE_LIBSSL
  539. static int
  540. start_tls (imap_t *imap, config_t * cfg)
  541. {
  542. int ret;
  543. /* initialize SSL */
  544. if (init_ssl (cfg))
  545. return 1;
  546. imap->sock->ssl = SSL_new (SSLContext);
  547. SSL_set_fd (imap->sock->ssl, imap->sock->fd);
  548. if ((ret = SSL_connect (imap->sock->ssl)) <= 0)
  549. {
  550. socket_perror ("connect", imap->sock, ret);
  551. return 1;
  552. }
  553. /* verify the server certificate */
  554. if (verify_cert (imap->sock->ssl))
  555. return 1;
  556. imap->sock->use_ssl = 1;
  557. puts ("SSL support enabled");
  558. return 0;
  559. }
  560. #endif
  561. imap_t *
  562. imap_connect (config_t * cfg)
  563. {
  564. int s;
  565. struct sockaddr_in addr;
  566. struct hostent *he;
  567. imap_t *imap;
  568. char *arg, *rsp;
  569. int preauth;
  570. #if HAVE_LIBSSL
  571. int use_ssl;
  572. #endif
  573. int a[2];
  574. imap = calloc (1, sizeof (imap_t));
  575. imap->box = cfg;
  576. imap->sock = calloc (1, sizeof (Socket_t));
  577. imap->buf = calloc (1, sizeof (buffer_t));
  578. imap->buf->sock = imap->sock;
  579. imap->sock->fd = -1;
  580. /* open connection to IMAP server */
  581. if (cfg->tunnel)
  582. {
  583. info ("Starting tunnel '%s'...", cfg->tunnel);
  584. fflush (stdout);
  585. if (socketpair (PF_UNIX, SOCK_STREAM, 0, a))
  586. {
  587. perror ("socketpair");
  588. exit (1);
  589. }
  590. if (fork () == 0)
  591. {
  592. if (dup2 (a[0], 0) == -1 || dup2 (a[0], 1) == -1)
  593. {
  594. _exit (127);
  595. }
  596. close (a[0]);
  597. close (a[1]);
  598. execl ("/bin/sh", "sh", "-c", cfg->tunnel, 0);
  599. _exit (127);
  600. }
  601. close (a[0]);
  602. imap->sock->fd = a[1];
  603. info ("ok\n");
  604. }
  605. else
  606. {
  607. memset (&addr, 0, sizeof (addr));
  608. addr.sin_port = htons (cfg->port);
  609. addr.sin_family = AF_INET;
  610. info ("Resolving %s... ", cfg->host);
  611. fflush (stdout);
  612. he = gethostbyname (cfg->host);
  613. if (!he)
  614. {
  615. perror ("gethostbyname");
  616. goto bail;
  617. }
  618. info ("ok\n");
  619. addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]);
  620. s = socket (PF_INET, SOCK_STREAM, 0);
  621. info ("Connecting to %s:%hu... ", inet_ntoa (addr.sin_addr),
  622. ntohs (addr.sin_port));
  623. fflush (stdout);
  624. if (connect (s, (struct sockaddr *) &addr, sizeof (addr)))
  625. {
  626. close (s);
  627. perror ("connect");
  628. goto bail;
  629. }
  630. info ("ok\n");
  631. imap->sock->fd = s;
  632. }
  633. #if HAVE_LIBSSL
  634. use_ssl = 0;
  635. if (cfg->use_imaps) {
  636. if (start_tls (imap, cfg))
  637. goto bail;
  638. use_ssl = 1;
  639. }
  640. #endif
  641. /* read the greeting string */
  642. if (buffer_gets (imap->buf, &rsp))
  643. {
  644. fprintf (stderr, "IMAP error: no greeting response\n");
  645. goto bail;
  646. }
  647. arg = next_arg (&rsp);
  648. if (!arg || *arg != '*' || (arg = next_arg (&rsp)) == NULL)
  649. {
  650. fprintf (stderr, "IMAP error: invalid greeting response\n");
  651. goto bail;
  652. }
  653. preauth = 0;
  654. if (!strcmp ("PREAUTH", arg))
  655. preauth = 1;
  656. else if (strcmp ("OK", arg) != 0)
  657. {
  658. fprintf (stderr, "IMAP error: unknown greeting response\n");
  659. goto bail;
  660. }
  661. /* let's see what this puppy can do... */
  662. if (imap_exec (imap, "CAPABILITY"))
  663. goto bail;
  664. if (!preauth)
  665. {
  666. #if HAVE_LIBSSL
  667. if (!cfg->use_imaps)
  668. {
  669. if (cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1)
  670. {
  671. /* always try to select SSL support if available */
  672. if (imap->have_starttls)
  673. {
  674. if (imap_exec (imap, "STARTTLS"))
  675. goto bail;
  676. if (start_tls (imap, cfg))
  677. goto bail;
  678. use_ssl = 1;
  679. /* to conform to RFC2595 we need to forget all information
  680. * retrieved from CAPABILITY invocations before STARTTLS.
  681. */
  682. imap->have_uidplus = 0;
  683. imap->have_namespace = 0;
  684. imap->have_cram = 0;
  685. /* imap->have_starttls = 0; */
  686. if (imap_exec (imap, "CAPABILITY"))
  687. goto bail;
  688. }
  689. else
  690. {
  691. if (cfg->require_ssl)
  692. {
  693. fprintf (stderr, "IMAP error: SSL support not available\n");
  694. goto bail;
  695. }
  696. else
  697. warn ("IMAP warning: SSL support not available\n");
  698. }
  699. }
  700. }
  701. #endif
  702. info ("Logging in...\n");
  703. if (!cfg->pass)
  704. {
  705. /*
  706. * if we don't have a global password set, prompt the user for
  707. * it now.
  708. */
  709. if (!global.pass)
  710. {
  711. char prompt[80];
  712. sprintf(prompt, "Password (mailbox %s@%s/%s): ",
  713. cfg->user, cfg->host, cfg->box);
  714. global.pass = getpass (prompt);
  715. if (!global.pass)
  716. {
  717. perror ("getpass");
  718. exit (1);
  719. }
  720. if (!*global.pass)
  721. {
  722. fprintf (stderr, "Skipping %s, no password\n", cfg->path);
  723. global.pass = NULL; /* force retry */
  724. goto bail;
  725. }
  726. /*
  727. * getpass() returns a pointer to a static buffer. make a copy
  728. * for long term storage.
  729. */
  730. global.pass = strdup (global.pass);
  731. }
  732. cfg->pass = strdup (global.pass);
  733. }
  734. #if HAVE_LIBSSL
  735. if (imap->have_cram)
  736. {
  737. info ("Authenticating with CRAM-MD5\n");
  738. imap->cram = 1;
  739. if (imap_exec (imap, "AUTHENTICATE CRAM-MD5"))
  740. goto bail;
  741. }
  742. else if (imap->box->require_cram)
  743. {
  744. fprintf (stderr, "IMAP error: CRAM-MD5 authentication is not supported by server\n");
  745. goto bail;
  746. }
  747. else
  748. #endif
  749. {
  750. #if HAVE_LIBSSL
  751. if (!use_ssl)
  752. #endif
  753. warn ("*** IMAP Warning *** Password is being sent in the clear\n");
  754. if (imap_exec (imap, "LOGIN \"%s\" \"%s\"", cfg->user, cfg->pass))
  755. {
  756. fprintf (stderr, "IMAP error: LOGIN failed\n");
  757. goto bail;
  758. }
  759. }
  760. } /* !preauth */
  761. /* get NAMESPACE info */
  762. if (cfg->use_namespace && imap->have_namespace)
  763. {
  764. if (imap_exec (imap, "NAMESPACE"))
  765. goto bail;
  766. }
  767. return imap;
  768. bail:
  769. imap_close (imap);
  770. return 0;
  771. }
  772. static int
  773. mstrcmp (const char *s1, const char *s2)
  774. {
  775. if (s1 == s2)
  776. return 0;
  777. if (!s1 || !s2)
  778. return 1;
  779. return strcmp (s1, s2);
  780. }
  781. /* `box' is the config info for the maildrop to sync. `minuid' is the
  782. * minimum UID to consider. in normal mode this will be 1, but in --fast
  783. * mode we only fetch messages newer than the last one seen in the local
  784. * mailbox.
  785. */
  786. imap_t *
  787. imap_open (config_t * box, unsigned int minuid, imap_t * imap, int imap_flags)
  788. {
  789. if (imap)
  790. {
  791. /* determine whether or not we can reuse the existing session */
  792. if (mstrcmp (box->tunnel, imap->box->tunnel) ||
  793. mstrcmp (box->host, imap->box->host) ||
  794. mstrcmp (box->user, imap->box->user) ||
  795. box->port != imap->box->port
  796. #if HAVE_LIBSSL
  797. /* ensure that security requirements are met */
  798. || (box->require_ssl ^ imap->box->require_ssl)
  799. || (box->require_cram ^ imap->box->require_cram)
  800. #endif
  801. )
  802. {
  803. /* can't reuse */
  804. imap_close (imap);
  805. }
  806. else
  807. {
  808. /* reset mailbox-specific state info */
  809. imap->box = box;
  810. imap->recent = 0;
  811. imap->deleted = 0;
  812. imap->count = 0;
  813. imap->maxuid = 0;
  814. free_message (imap->msgs);
  815. imap->msgs = 0;
  816. goto gotimap;
  817. }
  818. }
  819. if (!(imap = imap_connect (box)))
  820. return 0;
  821. gotimap:
  822. if (global.folder)
  823. imap->prefix = !strcmp (box->box, "INBOX") ? "" : global.folder;
  824. else
  825. {
  826. imap->prefix = "";
  827. /* XXX for now assume personal namespace */
  828. if (imap->box->use_namespace &&
  829. is_list (imap->ns_personal) &&
  830. is_list (imap->ns_personal->child) &&
  831. is_atom (imap->ns_personal->child->child))
  832. imap->prefix = imap->ns_personal->child->child->val;
  833. }
  834. info ("Selecting IMAP mailbox... ");
  835. fflush (stdout);
  836. if (imap_exec (imap, "SELECT \"%s%s\"", imap->prefix, box->box)) {
  837. if (imap_flags & IMAP_CREATE) {
  838. if (imap_exec (imap, "CREATE \"%s%s\"", imap->prefix, box->box))
  839. goto bail;
  840. if (imap_exec (imap, "SELECT \"%s%s\"", imap->prefix, box->box))
  841. goto bail;
  842. } else
  843. goto bail;
  844. }
  845. info ("%d messages, %d recent\n", imap->count, imap->recent);
  846. info ("Reading IMAP mailbox index\n");
  847. imap->minuid = minuid;
  848. if (imap->count > 0)
  849. {
  850. if (imap_exec (imap, "UID FETCH %d:* (FLAGS%s)", minuid,
  851. (imap_flags & IMAP_GET_SIZE) ? " RFC822.SIZE" : ""))
  852. goto bail;
  853. }
  854. return imap;
  855. bail:
  856. imap_close (imap);
  857. return 0;
  858. }
  859. void
  860. imap_close (imap_t * imap)
  861. {
  862. if (imap)
  863. {
  864. if (imap->sock->fd != -1)
  865. {
  866. imap_exec (imap, "LOGOUT");
  867. close (imap->sock->fd);
  868. }
  869. free (imap->sock);
  870. free (imap->buf);
  871. free_message (imap->msgs);
  872. memset (imap, 0xff, sizeof (imap_t));
  873. free (imap);
  874. }
  875. }
  876. /* write a buffer stripping all \r bytes */
  877. static int
  878. write_strip (int fd, char *buf, size_t len)
  879. {
  880. size_t start = 0;
  881. size_t end = 0;
  882. ssize_t n;
  883. while (start < len)
  884. {
  885. while (end < len && buf[end] != '\r')
  886. end++;
  887. n = write (fd, buf + start, end - start);
  888. if (n == -1)
  889. {
  890. perror ("write");
  891. return -1;
  892. }
  893. else if ((size_t) n != end - start)
  894. {
  895. /* short write, try again */
  896. start += n;
  897. }
  898. else
  899. {
  900. /* write complete */
  901. end++;
  902. start = end;
  903. }
  904. }
  905. return 0;
  906. }
  907. static int
  908. send_server (Socket_t * sock, const char *fmt, ...)
  909. {
  910. char buf[128];
  911. char cmd[128];
  912. va_list ap;
  913. int n;
  914. va_start (ap, fmt);
  915. vsnprintf (buf, sizeof (buf), fmt, ap);
  916. va_end (ap);
  917. snprintf (cmd, sizeof (cmd), "%d %s\r\n", ++Tag, buf);
  918. if (Verbose) {
  919. printf (">>> %s", cmd);
  920. fflush (stdout);
  921. }
  922. n = socket_write (sock, cmd, strlen (cmd));
  923. if (n <= 0)
  924. {
  925. socket_perror ("write", sock, n);
  926. return -1;
  927. }
  928. return 0;
  929. }
  930. int
  931. imap_fetch_message (imap_t * imap, unsigned int uid, int fd)
  932. {
  933. char *cmd;
  934. char *arg;
  935. size_t bytes;
  936. size_t n;
  937. char buf[1024];
  938. send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid);
  939. for (;;)
  940. {
  941. if (buffer_gets (imap->buf, &cmd))
  942. return -1;
  943. if (*cmd == '*')
  944. {
  945. /* need to figure out how long the message is
  946. * * <msgno> FETCH (RFC822 {<size>}
  947. */
  948. next_arg (&cmd); /* * */
  949. next_arg (&cmd); /* <msgno> */
  950. arg = next_arg (&cmd); /* FETCH */
  951. if (strcasecmp ("FETCH", arg) != 0)
  952. {
  953. /* this is likely an untagged response, such as when new
  954. * mail arrives in the middle of the session. just skip
  955. * it for now.
  956. *
  957. * eg.,
  958. * "* 4000 EXISTS"
  959. * "* 2 RECENT"
  960. *
  961. */
  962. info ("IMAP info: skipping untagged response: %s\n", arg);
  963. continue;
  964. }
  965. while ((arg = next_arg (&cmd)) && *arg != '{')
  966. ;
  967. if (!arg)
  968. {
  969. fprintf (stderr, "IMAP error: parse error getting size\n");
  970. return -1;
  971. }
  972. bytes = strtol (arg + 1, 0, 10);
  973. /* dump whats left over in the input buffer */
  974. n = imap->buf->bytes - imap->buf->offset;
  975. if (n > bytes)
  976. {
  977. /* the entire message fit in the buffer */
  978. n = bytes;
  979. }
  980. /* ick. we have to strip out the \r\n line endings, so
  981. * i can't just dump the raw bytes to disk.
  982. */
  983. if (write_strip (fd, imap->buf->buf + imap->buf->offset, n))
  984. {
  985. /* write failed, message is not delivered */
  986. return -1;
  987. }
  988. bytes -= n;
  989. /* mark that we used part of the buffer */
  990. imap->buf->offset += n;
  991. /* now read the rest of the message */
  992. while (bytes > 0)
  993. {
  994. n = bytes;
  995. if (n > sizeof (buf))
  996. n = sizeof (buf);
  997. n = socket_read (imap->sock, buf, n);
  998. if (n > 0)
  999. {
  1000. if (write_strip (fd, buf, n))
  1001. {
  1002. /* write failed */
  1003. return -1;
  1004. }
  1005. bytes -= n;
  1006. }
  1007. else
  1008. {
  1009. socket_perror ("read", imap->sock, n);
  1010. return -1;
  1011. }
  1012. }
  1013. buffer_gets (imap->buf, &cmd);
  1014. }
  1015. else
  1016. {
  1017. arg = next_arg (&cmd);
  1018. if (!arg || atoi (arg) != Tag)
  1019. {
  1020. fprintf (stderr, "IMAP error: wrong tag\n");
  1021. return -1;
  1022. }
  1023. arg = next_arg (&cmd);
  1024. if (!strcmp ("OK", arg))
  1025. return 0;
  1026. return -1;
  1027. }
  1028. }
  1029. /* not reached */
  1030. }
  1031. /* add flags to existing flags */
  1032. int
  1033. imap_set_flags (imap_t * imap, unsigned int uid, unsigned int flags)
  1034. {
  1035. char buf[256];
  1036. int i;
  1037. buf[0] = 0;
  1038. for (i = 0; i < D_MAX; i++)
  1039. {
  1040. if (flags & (1 << i))
  1041. snprintf (buf + strlen (buf),
  1042. sizeof (buf) - strlen (buf), "%s%s",
  1043. (buf[0] != 0) ? " " : "", Flags[i]);
  1044. }
  1045. return imap_exec (imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf);
  1046. }
  1047. int
  1048. imap_expunge (imap_t * imap)
  1049. {
  1050. return imap_exec (imap, "EXPUNGE");
  1051. }
  1052. int
  1053. imap_copy_message (imap_t * imap, unsigned int uid, const char *mailbox)
  1054. {
  1055. return imap_exec (imap, "UID COPY %u \"%s%s\"", uid, imap->prefix,
  1056. mailbox);
  1057. }
  1058. int
  1059. imap_append_message (imap_t * imap, int fd, message_t * msg)
  1060. {
  1061. char *fmap;
  1062. int extra, uid, tuidl = 0;
  1063. char flagstr[128], tuid[128];
  1064. char *s;
  1065. size_t i;
  1066. size_t start;
  1067. size_t len, sbreak = 0, ebreak = 0;
  1068. char *arg;
  1069. struct timeval tv;
  1070. pid_t pid = getpid();
  1071. len = msg->size;
  1072. /* ugh, we need to count the number of newlines */
  1073. fmap = (char *)mmap (0, len, PROT_READ, MAP_PRIVATE, fd, 0);
  1074. if (!fmap)
  1075. {
  1076. perror ("mmap");
  1077. return -1;
  1078. }
  1079. extra = 0, i = 0;
  1080. if (!imap->have_uidplus)
  1081. {
  1082. nloop:
  1083. start = i;
  1084. while (i < len)
  1085. if (fmap[i++] == '\n')
  1086. {
  1087. extra++;
  1088. if (i - 1 == start)
  1089. {
  1090. sbreak = ebreak = i - 1;
  1091. goto mktid;
  1092. }
  1093. if (!memcmp (fmap + start, "X-TUID: ", 8))
  1094. {
  1095. extra -= (ebreak = i) - (sbreak = start) + 1;
  1096. goto mktid;
  1097. }
  1098. goto nloop;
  1099. }
  1100. /* invalid mesasge */
  1101. goto bail;
  1102. mktid:
  1103. gettimeofday (&tv, 0);
  1104. tuidl = sprintf (tuid, "X-TUID: %08lx%05lx%04x\r\n",
  1105. tv.tv_sec, tv.tv_usec, pid);
  1106. extra += tuidl;
  1107. }
  1108. for (; i < len; i++)
  1109. if (fmap[i] == '\n')
  1110. extra++;
  1111. flagstr[0] = 0;
  1112. if (msg->flags)
  1113. {
  1114. if (msg->flags & D_DELETED)
  1115. strcat (flagstr," \\Deleted");
  1116. if (msg->flags & D_ANSWERED)
  1117. strcat (flagstr," \\Answered");
  1118. if (msg->flags & D_SEEN)
  1119. strcat (flagstr," \\Seen");
  1120. if (msg->flags & D_FLAGGED)
  1121. strcat (flagstr," \\Flagged");
  1122. if (msg->flags & D_DRAFT)
  1123. strcat (flagstr," \\Draft");
  1124. flagstr[0] = '(';
  1125. strcat (flagstr,") ");
  1126. }
  1127. send_server (imap->sock, "APPEND %s%s %s{%d}",
  1128. imap->prefix, imap->box->box, flagstr, len + extra);
  1129. if (buffer_gets (imap->buf, &s))
  1130. goto bail;
  1131. if (*s != '+')
  1132. {
  1133. fprintf (stderr, "IMAP error: expected `+' from server (aborting)\n");
  1134. goto bail;
  1135. }
  1136. i = 0;
  1137. if (!imap->have_uidplus)
  1138. {
  1139. n1loop:
  1140. start = i;
  1141. while (i < sbreak)
  1142. if (fmap[i++] == '\n')
  1143. {
  1144. socket_write (imap->sock, fmap + start, i - 1 - start);
  1145. socket_write (imap->sock, "\r\n", 2);
  1146. goto n1loop;
  1147. }
  1148. socket_write (imap->sock, tuid, tuidl);
  1149. i = ebreak;
  1150. }
  1151. n2loop:
  1152. start = i;
  1153. while (i < len)
  1154. if (fmap[i++] == '\n')
  1155. {
  1156. socket_write (imap->sock, fmap + start, i - 1 - start);
  1157. socket_write (imap->sock, "\r\n", 2);
  1158. goto n2loop;
  1159. }
  1160. socket_write (imap->sock, fmap + start, len - start);
  1161. socket_write (imap->sock, "\r\n", 2);
  1162. munmap (fmap, len);
  1163. for (;;)
  1164. {
  1165. if (buffer_gets (imap->buf, &s))
  1166. return -1;
  1167. arg = next_arg (&s);
  1168. if (*arg == '*')
  1169. {
  1170. /* XXX just ignore it for now */
  1171. }
  1172. else if (atoi (arg) != Tag)
  1173. {
  1174. fprintf (stderr, "IMAP error: wrong tag\n");
  1175. return -1;
  1176. }
  1177. else
  1178. {
  1179. arg = next_arg (&s);
  1180. if (strcmp (arg, "OK"))
  1181. return -1;
  1182. arg = next_arg (&s);
  1183. if (*arg != '[')
  1184. break;
  1185. arg++;
  1186. if (strcasecmp ("APPENDUID", arg))
  1187. {
  1188. fprintf (stderr, "IMAP error: expected APPENDUID\n");
  1189. break;
  1190. }
  1191. arg = next_arg (&s);
  1192. if (!arg)
  1193. break;
  1194. if (atoi (arg) != (int) imap->uidvalidity)
  1195. {
  1196. fprintf (stderr, "IMAP error: UIDVALIDITY doesn't match APPENDUID\n");
  1197. return -1;
  1198. }
  1199. arg = next_arg (&s);
  1200. if (!arg)
  1201. break;
  1202. uid = strtol (arg, &s, 10);
  1203. if (*s != ']')
  1204. {
  1205. /* parse error */
  1206. break;
  1207. }
  1208. return uid;
  1209. }
  1210. }
  1211. /* didn't receive an APPENDUID */
  1212. send_server (imap->sock,
  1213. "UID SEARCH HEADER X-TUID %08lx%05lx%04x",
  1214. tv.tv_sec, tv.tv_usec, pid);
  1215. uid = 0;
  1216. for (;;)
  1217. {
  1218. if (buffer_gets (imap->buf, &s))
  1219. return -1;
  1220. arg = next_arg (&s);
  1221. if (*arg == '*')
  1222. {
  1223. arg = next_arg (&s);
  1224. if (!strcmp (arg, "SEARCH"))
  1225. {
  1226. arg = next_arg (&s);
  1227. if (!arg)
  1228. fprintf (stderr, "IMAP error: incomplete SEARCH response\n");
  1229. else
  1230. uid = atoi (arg);
  1231. }
  1232. }
  1233. else if (atoi (arg) != (int) Tag)
  1234. {
  1235. fprintf (stderr, "IMAP error: wrong tag\n");
  1236. return -1;
  1237. }
  1238. else
  1239. {
  1240. arg = next_arg (&s);
  1241. if (strcmp (arg, "OK"))
  1242. return -1;
  1243. return uid;
  1244. }
  1245. }
  1246. return 0;
  1247. bail:
  1248. munmap (fmap, len);
  1249. return -1;
  1250. }
  1251. int
  1252. imap_list (imap_t * imap)
  1253. {
  1254. return imap_exec (imap, "LIST \"\" \"%s*\"", global.folder);
  1255. }