drv_imap.c 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846
  1. /*
  2. * mbsync - mailbox synchronizer
  3. * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
  4. * Copyright (C) 2002-2006,2008 Oswald Buddenhagen <ossi@users.sf.net>
  5. * Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu>
  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 Foundation,
  19. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  20. *
  21. * As a special exception, mbsync 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 <stdlib.h>
  28. #include <stdio.h>
  29. #include <stddef.h>
  30. #include <limits.h>
  31. #include <errno.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. typedef struct imap_server_conf {
  35. struct imap_server_conf *next;
  36. char *name;
  37. server_conf_t sconf;
  38. char *user;
  39. char *pass;
  40. int max_in_progress;
  41. #ifdef HAVE_LIBSSL
  42. unsigned require_ssl:1;
  43. unsigned require_cram:1;
  44. #endif
  45. } imap_server_conf_t;
  46. typedef struct imap_store_conf {
  47. store_conf_t gen;
  48. imap_server_conf_t *server;
  49. unsigned use_namespace:1;
  50. } imap_store_conf_t;
  51. typedef struct imap_message {
  52. message_t gen;
  53. /* int seq; will be needed when expunges are tracked */
  54. } imap_message_t;
  55. #define NIL (void*)0x1
  56. #define LIST (void*)0x2
  57. typedef struct _list {
  58. struct _list *next, *child;
  59. char *val;
  60. int len;
  61. } list_t;
  62. struct imap_cmd;
  63. typedef struct imap_store {
  64. store_t gen;
  65. const char *prefix;
  66. int ref_count;
  67. int uidnext; /* from SELECT responses */
  68. unsigned trashnc:1; /* trash folder's existence is not confirmed yet */
  69. unsigned got_namespace:1;
  70. list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */
  71. message_t **msgapp; /* FETCH results */
  72. unsigned caps; /* CAPABILITY results */
  73. /* command queue */
  74. int nexttag, num_in_progress, literal_pending;
  75. struct imap_cmd *in_progress, **in_progress_append;
  76. /* Used during sequential operations like connect */
  77. enum { GreetingPending = 0, GreetingBad, GreetingOk, GreetingPreauth } greeting;
  78. union {
  79. void (*imap_open)( store_t *srv, void *aux );
  80. } callbacks;
  81. void *callback_aux;
  82. conn_t conn; /* this is BIG, so put it last */
  83. } imap_store_t;
  84. struct imap_cmd {
  85. struct imap_cmd *next;
  86. char *cmd;
  87. int tag;
  88. struct {
  89. /* Will be called on each continuation request until it resets this pointer.
  90. * Needs to invoke bad_callback and return -1 on error, otherwise return 0. */
  91. int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const char *prompt );
  92. void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response );
  93. char *data;
  94. int data_len;
  95. int uid; /* to identify fetch responses */
  96. unsigned
  97. to_trash:1, /* we are storing to trash, not current. */
  98. create:1, /* create the mailbox if we get an error ... */
  99. trycreate:1; /* ... but only if this is true or the server says so. */
  100. } param;
  101. };
  102. struct imap_cmd_simple {
  103. struct imap_cmd gen;
  104. void (*callback)( int sts, void *aux );
  105. void *callback_aux;
  106. };
  107. struct imap_cmd_fetch_msg {
  108. struct imap_cmd_simple gen;
  109. msg_data_t *msg_data;
  110. };
  111. struct imap_cmd_out_uid {
  112. struct imap_cmd gen;
  113. void (*callback)( int sts, int uid, void *aux );
  114. void *callback_aux;
  115. int out_uid;
  116. };
  117. struct imap_cmd_refcounted_state {
  118. void (*callback)( int sts, void *aux );
  119. void *callback_aux;
  120. int ref_count;
  121. int ret_val;
  122. };
  123. struct imap_cmd_refcounted {
  124. struct imap_cmd gen;
  125. struct imap_cmd_refcounted_state *state;
  126. };
  127. #define CAP(cap) (ctx->caps & (1 << (cap)))
  128. enum CAPABILITY {
  129. NOLOGIN = 0,
  130. UIDPLUS,
  131. LITERALPLUS,
  132. NAMESPACE,
  133. #ifdef HAVE_LIBSSL
  134. CRAM,
  135. STARTTLS,
  136. #endif
  137. };
  138. static const char *cap_list[] = {
  139. "LOGINDISABLED",
  140. "UIDPLUS",
  141. "LITERAL+",
  142. "NAMESPACE",
  143. #ifdef HAVE_LIBSSL
  144. "AUTH=CRAM-MD5",
  145. "STARTTLS",
  146. #endif
  147. };
  148. #define RESP_OK 0
  149. #define RESP_NO 1
  150. #define RESP_CANCEL 2
  151. static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd );
  152. static INLINE void imap_ref( imap_store_t *ctx ) { ++ctx->ref_count; }
  153. static int imap_deref( imap_store_t *ctx );
  154. static void imap_invoke_bad_callback( imap_store_t *ctx );
  155. static const char *Flags[] = {
  156. "Draft",
  157. "Flagged",
  158. "Answered",
  159. "Seen",
  160. "Deleted",
  161. };
  162. static struct imap_cmd *
  163. new_imap_cmd( int size )
  164. {
  165. struct imap_cmd *cmd = nfmalloc( size );
  166. memset( &cmd->param, 0, sizeof(cmd->param) );
  167. return cmd;
  168. }
  169. #define INIT_IMAP_CMD(type, cmdp, cb, aux) \
  170. cmdp = (struct type *)new_imap_cmd( sizeof(*cmdp) ); \
  171. cmdp->callback = cb; \
  172. cmdp->callback_aux = aux;
  173. #define INIT_IMAP_CMD_X(type, cmdp, cb, aux) \
  174. cmdp = (struct type *)new_imap_cmd( sizeof(*cmdp) ); \
  175. cmdp->gen.callback = cb; \
  176. cmdp->gen.callback_aux = aux;
  177. static struct imap_cmd *
  178. v_submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd,
  179. const char *fmt, va_list ap )
  180. {
  181. int bufl, litplus;
  182. const char *buffmt;
  183. char buf[1024];
  184. assert( ctx );
  185. assert( ctx->gen.bad_callback );
  186. assert( cmd );
  187. assert( cmd->param.done );
  188. while (ctx->literal_pending)
  189. if (get_cmd_result( ctx, 0 ) == RESP_CANCEL)
  190. goto bail2;
  191. cmd->tag = ++ctx->nexttag;
  192. if (fmt)
  193. nfvasprintf( &cmd->cmd, fmt, ap );
  194. if (!cmd->param.data) {
  195. buffmt = "%d %s\r\n";
  196. litplus = 0;
  197. } else if ((cmd->param.to_trash && ctx->trashnc) || !CAP(LITERALPLUS)) {
  198. buffmt = "%d %s{%d}\r\n";
  199. litplus = 0;
  200. } else {
  201. buffmt = "%d %s{%d+}\r\n";
  202. litplus = 1;
  203. }
  204. bufl = nfsnprintf( buf, sizeof(buf), buffmt,
  205. cmd->tag, cmd->cmd, cmd->param.data_len );
  206. if (DFlags & VERBOSE) {
  207. if (ctx->num_in_progress)
  208. printf( "(%d in progress) ", ctx->num_in_progress );
  209. if (memcmp( cmd->cmd, "LOGIN", 5 ))
  210. printf( ">>> %s", buf );
  211. else
  212. printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag );
  213. }
  214. if (socket_write( &ctx->conn, buf, bufl, KeepOwn ) < 0)
  215. goto bail;
  216. if (litplus) {
  217. char *p = cmd->param.data;
  218. cmd->param.data = 0;
  219. if (socket_write( &ctx->conn, p, cmd->param.data_len, GiveOwn ) < 0 ||
  220. socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0)
  221. goto bail;
  222. } else if (cmd->param.cont || cmd->param.data) {
  223. ctx->literal_pending = 1;
  224. }
  225. cmd->next = 0;
  226. *ctx->in_progress_append = cmd;
  227. ctx->in_progress_append = &cmd->next;
  228. ctx->num_in_progress++;
  229. return cmd;
  230. bail:
  231. imap_invoke_bad_callback( ctx );
  232. bail2:
  233. cmd->param.done( ctx, cmd, RESP_CANCEL );
  234. free( cmd->param.data );
  235. free( cmd->cmd );
  236. free( cmd );
  237. return NULL;
  238. }
  239. static struct imap_cmd *
  240. submit_imap_cmd( imap_store_t *ctx, struct imap_cmd *cmd, const char *fmt, ... )
  241. {
  242. struct imap_cmd *ret;
  243. va_list ap;
  244. va_start( ap, fmt );
  245. ret = v_submit_imap_cmd( ctx, cmd, fmt, ap );
  246. va_end( ap );
  247. return ret;
  248. }
  249. static void
  250. cancel_submitted_imap_cmds( imap_store_t *ctx )
  251. {
  252. struct imap_cmd *cmd;
  253. while ((cmd = ctx->in_progress)) {
  254. ctx->in_progress = cmd->next;
  255. /* don't update num_in_progress and in_progress_append - store is dead */
  256. cmd->param.done( ctx, cmd, RESP_CANCEL );
  257. free( cmd->param.data );
  258. free( cmd->cmd );
  259. free( cmd );
  260. }
  261. }
  262. static int
  263. imap_exec( imap_store_t *ctx, struct imap_cmd *cmdp,
  264. void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response ),
  265. const char *fmt, ... )
  266. {
  267. va_list ap;
  268. if (!cmdp)
  269. cmdp = new_imap_cmd( sizeof(*cmdp) );
  270. cmdp->param.done = done;
  271. va_start( ap, fmt );
  272. cmdp = v_submit_imap_cmd( ctx, cmdp, fmt, ap );
  273. va_end( ap );
  274. if (!cmdp)
  275. return RESP_CANCEL;
  276. return get_cmd_result( ctx, cmdp );
  277. }
  278. static void
  279. transform_box_response( int *response )
  280. {
  281. switch (*response) {
  282. case RESP_CANCEL: *response = DRV_CANCELED; break;
  283. case RESP_NO: *response = DRV_BOX_BAD; break;
  284. default: *response = DRV_OK; break;
  285. }
  286. }
  287. static void
  288. imap_done_simple_box( imap_store_t *ctx ATTR_UNUSED,
  289. struct imap_cmd *cmd, int response )
  290. {
  291. struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
  292. transform_box_response( &response );
  293. cmdp->callback( response, cmdp->callback_aux );
  294. }
  295. static void
  296. transform_msg_response( int *response )
  297. {
  298. switch (*response) {
  299. case RESP_CANCEL: *response = DRV_CANCELED; break;
  300. case RESP_NO: *response = DRV_MSG_BAD; break;
  301. default: *response = DRV_OK; break;
  302. }
  303. }
  304. static void
  305. imap_done_simple_msg( imap_store_t *ctx ATTR_UNUSED,
  306. struct imap_cmd *cmd, int response )
  307. {
  308. struct imap_cmd_simple *cmdp = (struct imap_cmd_simple *)cmd;
  309. transform_msg_response( &response );
  310. cmdp->callback( response, cmdp->callback_aux );
  311. }
  312. static struct imap_cmd_refcounted_state *
  313. imap_refcounted_new_state( void (*cb)( int, void * ), void *aux )
  314. {
  315. struct imap_cmd_refcounted_state *sts = nfmalloc( sizeof(*sts) );
  316. sts->callback = cb;
  317. sts->callback_aux = aux;
  318. sts->ref_count = 1; /* so forced sync does not cause an early exit */
  319. sts->ret_val = DRV_OK;
  320. return sts;
  321. }
  322. static struct imap_cmd *
  323. imap_refcounted_new_cmd( struct imap_cmd_refcounted_state *sts )
  324. {
  325. struct imap_cmd_refcounted *cmd = (struct imap_cmd_refcounted *)new_imap_cmd( sizeof(*cmd) );
  326. cmd->state = sts;
  327. sts->ref_count++;
  328. return &cmd->gen;
  329. }
  330. static void
  331. imap_refcounted_done( struct imap_cmd_refcounted_state *sts )
  332. {
  333. sts->callback( sts->ret_val, sts->callback_aux );
  334. free( sts );
  335. }
  336. /*
  337. static void
  338. drain_imap_replies( imap_store_t *ctx )
  339. {
  340. while (ctx->num_in_progress)
  341. get_cmd_result( ctx, 0 );
  342. }
  343. */
  344. static int
  345. process_imap_replies( imap_store_t *ctx )
  346. {
  347. while (ctx->num_in_progress > ((imap_store_conf_t *)ctx->gen.conf)->server->max_in_progress ||
  348. socket_pending( &ctx->conn ))
  349. if (get_cmd_result( ctx, 0 ) == RESP_CANCEL)
  350. return RESP_CANCEL;
  351. return RESP_OK;
  352. }
  353. static int
  354. is_atom( list_t *list )
  355. {
  356. return list && list->val && list->val != NIL && list->val != LIST;
  357. }
  358. static int
  359. is_list( list_t *list )
  360. {
  361. return list && list->val == LIST;
  362. }
  363. static void
  364. free_list( list_t *list )
  365. {
  366. list_t *tmp;
  367. for (; list; list = tmp) {
  368. tmp = list->next;
  369. if (is_list( list ))
  370. free_list( list->child );
  371. else if (is_atom( list ))
  372. free( list->val );
  373. free( list );
  374. }
  375. }
  376. static int
  377. parse_imap_list_l( imap_store_t *ctx, char **sp, list_t **curp, int level )
  378. {
  379. list_t *cur;
  380. char *s = *sp, *p;
  381. int n, bytes;
  382. for (;;) {
  383. while (isspace( (unsigned char)*s ))
  384. s++;
  385. if (level && *s == ')') {
  386. s++;
  387. break;
  388. }
  389. *curp = cur = nfmalloc( sizeof(*cur) );
  390. curp = &cur->next;
  391. cur->val = 0; /* for clean bail */
  392. if (*s == '(') {
  393. /* sublist */
  394. s++;
  395. cur->val = LIST;
  396. if (parse_imap_list_l( ctx, &s, &cur->child, level + 1 ))
  397. goto bail;
  398. } else if (ctx && *s == '{') {
  399. /* literal */
  400. bytes = cur->len = strtol( s + 1, &s, 10 );
  401. if (*s != '}')
  402. goto bail;
  403. s = cur->val = nfmalloc( cur->len );
  404. /* dump whats left over in the input buffer */
  405. n = ctx->conn.bytes - ctx->conn.offset;
  406. if (n > bytes)
  407. /* the entire message fit in the buffer */
  408. n = bytes;
  409. memcpy( s, ctx->conn.buf + ctx->conn.offset, n );
  410. s += n;
  411. bytes -= n;
  412. /* mark that we used part of the buffer */
  413. ctx->conn.offset += n;
  414. /* now read the rest of the message */
  415. while (bytes > 0) {
  416. if ((n = socket_read( &ctx->conn, s, bytes )) <= 0)
  417. goto bail;
  418. s += n;
  419. bytes -= n;
  420. }
  421. if (DFlags & XVERBOSE) {
  422. puts( "=========" );
  423. fwrite( cur->val, cur->len, 1, stdout );
  424. puts( "=========" );
  425. }
  426. if (buffer_gets( &ctx->conn, &s ))
  427. goto bail;
  428. } else if (*s == '"') {
  429. /* quoted string */
  430. s++;
  431. p = s;
  432. for (; *s != '"'; s++)
  433. if (!*s)
  434. goto bail;
  435. cur->len = s - p;
  436. s++;
  437. cur->val = nfmalloc( cur->len + 1 );
  438. memcpy( cur->val, p, cur->len );
  439. cur->val[cur->len] = 0;
  440. } else {
  441. /* atom */
  442. p = s;
  443. for (; *s && !isspace( (unsigned char)*s ); s++)
  444. if (level && *s == ')')
  445. break;
  446. cur->len = s - p;
  447. if (cur->len == 3 && !memcmp ("NIL", p, 3))
  448. cur->val = NIL;
  449. else {
  450. cur->val = nfmalloc( cur->len + 1 );
  451. memcpy( cur->val, p, cur->len );
  452. cur->val[cur->len] = 0;
  453. }
  454. }
  455. if (!level)
  456. break;
  457. if (!*s)
  458. goto bail;
  459. }
  460. *sp = s;
  461. *curp = 0;
  462. return 0;
  463. bail:
  464. *curp = 0;
  465. return -1;
  466. }
  467. static list_t *
  468. parse_imap_list( imap_store_t *ctx, char **sp )
  469. {
  470. list_t *head;
  471. if (!parse_imap_list_l( ctx, sp, &head, 0 ))
  472. return head;
  473. free_list( head );
  474. return NULL;
  475. }
  476. static list_t *
  477. parse_list( char **sp )
  478. {
  479. return parse_imap_list( 0, sp );
  480. }
  481. static int
  482. parse_fetch( imap_store_t *ctx, char *cmd ) /* move this down */
  483. {
  484. list_t *tmp, *list, *flags;
  485. char *body = 0;
  486. imap_message_t *cur;
  487. msg_data_t *msgdata;
  488. struct imap_cmd *cmdp;
  489. int uid = 0, mask = 0, status = 0, size = 0;
  490. unsigned i;
  491. list = parse_imap_list( ctx, &cmd );
  492. if (!is_list( list )) {
  493. error( "IMAP error: bogus FETCH response\n" );
  494. free_list( list );
  495. return -1;
  496. }
  497. for (tmp = list->child; tmp; tmp = tmp->next) {
  498. if (is_atom( tmp )) {
  499. if (!strcmp( "UID", tmp->val )) {
  500. tmp = tmp->next;
  501. if (is_atom( tmp ))
  502. uid = atoi( tmp->val );
  503. else
  504. error( "IMAP error: unable to parse UID\n" );
  505. } else if (!strcmp( "FLAGS", tmp->val )) {
  506. tmp = tmp->next;
  507. if (is_list( tmp )) {
  508. for (flags = tmp->child; flags; flags = flags->next) {
  509. if (is_atom( flags )) {
  510. if (flags->val[0] == '\\') { /* ignore user-defined flags for now */
  511. if (!strcmp( "Recent", flags->val + 1)) {
  512. status |= M_RECENT;
  513. goto flagok;
  514. }
  515. for (i = 0; i < as(Flags); i++)
  516. if (!strcmp( Flags[i], flags->val + 1 )) {
  517. mask |= 1 << i;
  518. goto flagok;
  519. }
  520. if (flags->val[1] == 'X' && flags->val[2] == '-')
  521. goto flagok; /* ignore system flag extensions */
  522. error( "IMAP warning: unknown system flag %s\n", flags->val );
  523. }
  524. flagok: ;
  525. } else
  526. error( "IMAP error: unable to parse FLAGS list\n" );
  527. }
  528. status |= M_FLAGS;
  529. } else
  530. error( "IMAP error: unable to parse FLAGS\n" );
  531. } else if (!strcmp( "RFC822.SIZE", tmp->val )) {
  532. tmp = tmp->next;
  533. if (is_atom( tmp ))
  534. size = atoi( tmp->val );
  535. else
  536. error( "IMAP error: unable to parse RFC822.SIZE\n" );
  537. } else if (!strcmp( "BODY[]", tmp->val )) {
  538. tmp = tmp->next;
  539. if (is_atom( tmp )) {
  540. body = tmp->val;
  541. tmp->val = 0; /* don't free together with list */
  542. size = tmp->len;
  543. } else
  544. error( "IMAP error: unable to parse BODY[]\n" );
  545. }
  546. }
  547. }
  548. if (body) {
  549. for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next)
  550. if (cmdp->param.uid == uid)
  551. goto gotuid;
  552. error( "IMAP error: unexpected FETCH response (UID %d)\n", uid );
  553. free_list( list );
  554. return -1;
  555. gotuid:
  556. msgdata = ((struct imap_cmd_fetch_msg *)cmdp)->msg_data;
  557. msgdata->data = body;
  558. msgdata->len = size;
  559. if (status & M_FLAGS)
  560. msgdata->flags = mask;
  561. } else if (uid) { /* ignore async flag updates for now */
  562. /* XXX this will need sorting for out-of-order (multiple queries) */
  563. cur = nfcalloc( sizeof(*cur) );
  564. *ctx->msgapp = &cur->gen;
  565. ctx->msgapp = &cur->gen.next;
  566. cur->gen.next = 0;
  567. cur->gen.uid = uid;
  568. cur->gen.flags = mask;
  569. cur->gen.status = status;
  570. cur->gen.size = size;
  571. }
  572. free_list( list );
  573. return 0;
  574. }
  575. static void
  576. parse_capability( imap_store_t *ctx, char *cmd )
  577. {
  578. char *arg;
  579. unsigned i;
  580. ctx->caps = 0x80000000;
  581. while ((arg = next_arg( &cmd )))
  582. for (i = 0; i < as(cap_list); i++)
  583. if (!strcmp( cap_list[i], arg ))
  584. ctx->caps |= 1 << i;
  585. }
  586. static int
  587. parse_response_code( imap_store_t *ctx, struct imap_cmd *cmd, char *s )
  588. {
  589. char *arg, *earg, *p;
  590. if (*s != '[')
  591. return RESP_OK; /* no response code */
  592. s++;
  593. if (!(p = strchr( s, ']' ))) {
  594. error( "IMAP error: malformed response code\n" );
  595. return RESP_CANCEL;
  596. }
  597. *p++ = 0;
  598. arg = next_arg( &s );
  599. if (!strcmp( "UIDVALIDITY", arg )) {
  600. if (!(arg = next_arg( &s )) ||
  601. (ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg))
  602. {
  603. error( "IMAP error: malformed UIDVALIDITY status\n" );
  604. return RESP_CANCEL;
  605. }
  606. } else if (!strcmp( "UIDNEXT", arg )) {
  607. if (!(arg = next_arg( &s )) || (ctx->uidnext = strtol( arg, &p, 10 ), *p)) {
  608. error( "IMAP error: malformed NEXTUID status\n" );
  609. return RESP_CANCEL;
  610. }
  611. } else if (!strcmp( "CAPABILITY", arg )) {
  612. parse_capability( ctx, s );
  613. } else if (!strcmp( "ALERT", arg )) {
  614. /* RFC2060 says that these messages MUST be displayed
  615. * to the user
  616. */
  617. for (; isspace( (unsigned char)*p ); p++);
  618. error( "*** IMAP ALERT *** %s\n", p );
  619. } else if (cmd && !strcmp( "APPENDUID", arg )) {
  620. if (!(arg = next_arg( &s )) ||
  621. (ctx->gen.uidvalidity = strtoll( arg, &earg, 10 ), *earg) ||
  622. !(arg = next_arg( &s )) ||
  623. !(((struct imap_cmd_out_uid *)cmd)->out_uid = atoi( arg )))
  624. {
  625. error( "IMAP error: malformed APPENDUID status\n" );
  626. return RESP_CANCEL;
  627. }
  628. }
  629. return RESP_OK;
  630. }
  631. static void
  632. parse_search( imap_store_t *ctx, char *cmd )
  633. {
  634. char *arg;
  635. struct imap_cmd *cmdp;
  636. int uid;
  637. if (!(arg = next_arg( &cmd )))
  638. uid = -1;
  639. else if (!(uid = atoi( arg ))) {
  640. error( "IMAP error: malformed SEARCH response\n" );
  641. return;
  642. } else if (next_arg( &cmd )) {
  643. warn( "IMAP warning: SEARCH returns multiple matches\n" );
  644. uid = -1; /* to avoid havoc */
  645. }
  646. /* Find the first command that expects a UID - this is guaranteed
  647. * to come in-order, as there are no other means to identify which
  648. * SEARCH response belongs to which request.
  649. */
  650. for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next)
  651. if (cmdp->param.uid == -1) {
  652. ((struct imap_cmd_out_uid *)cmdp)->out_uid = uid;
  653. return;
  654. }
  655. error( "IMAP error: unexpected SEARCH response (UID %u)\n", uid );
  656. }
  657. static void
  658. parse_list_rsp( imap_store_t *ctx, char *cmd )
  659. {
  660. char *arg;
  661. list_t *list, *lp;
  662. int l;
  663. list = parse_list( &cmd );
  664. if (list->val == LIST)
  665. for (lp = list->child; lp; lp = lp->next)
  666. if (is_atom( lp ) && !strcasecmp( lp->val, "\\NoSelect" )) {
  667. free_list( list );
  668. return;
  669. }
  670. free_list( list );
  671. (void) next_arg( &cmd ); /* skip delimiter */
  672. arg = next_arg( &cmd );
  673. l = strlen( ctx->gen.conf->path );
  674. if (memcmp( arg, ctx->gen.conf->path, l ))
  675. return;
  676. arg += l;
  677. if (!memcmp( arg + strlen( arg ) - 5, ".lock", 5 )) /* workaround broken servers */
  678. return;
  679. add_string_list( &ctx->gen.boxes, arg );
  680. }
  681. struct imap_cmd_trycreate {
  682. struct imap_cmd gen;
  683. struct imap_cmd *orig_cmd;
  684. };
  685. static void imap_open_store_greeted( imap_store_t * );
  686. static void get_cmd_result_p2( imap_store_t *, struct imap_cmd *, int );
  687. static int
  688. get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd )
  689. {
  690. struct imap_cmd *cmdp, **pcmdp;
  691. char *cmd, *arg, *arg1, *p;
  692. int resp, resp2, tag, greeted;
  693. greeted = ctx->greeting;
  694. for (;;) {
  695. if (buffer_gets( &ctx->conn, &cmd ))
  696. break;
  697. arg = next_arg( &cmd );
  698. if (*arg == '*') {
  699. arg = next_arg( &cmd );
  700. if (!arg) {
  701. error( "IMAP error: unable to parse untagged response\n" );
  702. break;
  703. }
  704. if (!strcmp( "NAMESPACE", arg )) {
  705. ctx->ns_personal = parse_list( &cmd );
  706. ctx->ns_other = parse_list( &cmd );
  707. ctx->ns_shared = parse_list( &cmd );
  708. } else if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) {
  709. ctx->greeting = GreetingPreauth;
  710. parse_response_code( ctx, 0, cmd );
  711. } else if (!strcmp( "OK", arg )) {
  712. ctx->greeting = GreetingOk;
  713. parse_response_code( ctx, 0, cmd );
  714. } else if (!strcmp( "BAD", arg ) || !strcmp( "NO", arg ) || !strcmp( "BYE", arg )) {
  715. ctx->greeting = GreetingBad;
  716. parse_response_code( ctx, 0, cmd );
  717. } else if (!strcmp( "CAPABILITY", arg ))
  718. parse_capability( ctx, cmd );
  719. else if (!strcmp( "LIST", arg ))
  720. parse_list_rsp( ctx, cmd );
  721. else if (!strcmp( "SEARCH", arg ))
  722. parse_search( ctx, cmd );
  723. else if ((arg1 = next_arg( &cmd ))) {
  724. if (!strcmp( "EXISTS", arg1 ))
  725. ctx->gen.count = atoi( arg );
  726. else if (!strcmp( "RECENT", arg1 ))
  727. ctx->gen.recent = atoi( arg );
  728. else if(!strcmp ( "FETCH", arg1 )) {
  729. if (parse_fetch( ctx, cmd ))
  730. break; /* stream is likely to be useless now */
  731. }
  732. } else {
  733. error( "IMAP error: unrecognized untagged response '%s'\n", arg );
  734. break; /* this may mean anything, so prefer not to spam the log */
  735. }
  736. if (greeted == GreetingPending) {
  737. imap_ref( ctx );
  738. imap_open_store_greeted( ctx );
  739. return imap_deref( ctx ) ? RESP_CANCEL : RESP_OK;
  740. }
  741. } else if (!ctx->in_progress) {
  742. error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" );
  743. break; /* this may mean anything, so prefer not to spam the log */
  744. } else if (*arg == '+') {
  745. /* This can happen only with the last command underway, as
  746. it enforces a round-trip. */
  747. cmdp = ctx->in_progress;
  748. if (cmdp->param.data) {
  749. if (cmdp->param.to_trash)
  750. ctx->trashnc = 0; /* Can't get NO [TRYCREATE] any more. */
  751. p = cmdp->param.data;
  752. cmdp->param.data = 0;
  753. if (socket_write( &ctx->conn, p, cmdp->param.data_len, GiveOwn ) < 0)
  754. break;
  755. } else if (cmdp->param.cont) {
  756. if (cmdp->param.cont( ctx, cmdp, cmd ))
  757. break;
  758. } else {
  759. error( "IMAP error: unexpected command continuation request\n" );
  760. break;
  761. }
  762. if (socket_write( &ctx->conn, "\r\n", 2, KeepOwn ) < 0)
  763. break;
  764. if (!cmdp->param.cont)
  765. ctx->literal_pending = 0;
  766. if (!tcmd)
  767. return RESP_OK;
  768. } else {
  769. tag = atoi( arg );
  770. for (pcmdp = &ctx->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next)
  771. if (cmdp->tag == tag)
  772. goto gottag;
  773. error( "IMAP error: unexpected tag %s\n", arg );
  774. break;
  775. gottag:
  776. if (!(*pcmdp = cmdp->next))
  777. ctx->in_progress_append = pcmdp;
  778. ctx->num_in_progress--;
  779. if (cmdp->param.cont || cmdp->param.data)
  780. ctx->literal_pending = 0;
  781. arg = next_arg( &cmd );
  782. if (!strcmp( "OK", arg )) {
  783. if (cmdp->param.to_trash)
  784. ctx->trashnc = 0; /* Can't get NO [TRYCREATE] any more. */
  785. resp = RESP_OK;
  786. } else {
  787. if (!strcmp( "NO", arg )) {
  788. if (cmdp->param.create &&
  789. (cmdp->param.trycreate ||
  790. (cmd && !memcmp( cmd, "[TRYCREATE]", 11 ))))
  791. { /* SELECT, APPEND or UID COPY */
  792. struct imap_cmd_trycreate *cmd2 =
  793. (struct imap_cmd_trycreate *)new_imap_cmd( sizeof(*cmd2) );
  794. cmd2->orig_cmd = cmdp;
  795. cmd2->gen.param.done = get_cmd_result_p2;
  796. p = strchr( cmdp->cmd, '"' );
  797. if (!submit_imap_cmd( ctx, &cmd2->gen, "CREATE %.*s", strchr( p + 1, '"' ) - p + 1, p ))
  798. return RESP_CANCEL;
  799. continue;
  800. }
  801. resp = RESP_NO;
  802. } else /*if (!strcmp( "BAD", arg ))*/
  803. resp = RESP_CANCEL;
  804. error( "IMAP command '%s' returned an error: %s %s\n",
  805. memcmp( cmdp->cmd, "LOGIN", 5 ) ? cmdp->cmd : "LOGIN <user> <pass>",
  806. arg, cmd ? cmd : "" );
  807. }
  808. if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp)
  809. resp = resp2;
  810. imap_ref( ctx );
  811. if (resp == RESP_CANCEL)
  812. imap_invoke_bad_callback( ctx );
  813. cmdp->param.done( ctx, cmdp, resp );
  814. if (imap_deref( ctx ))
  815. resp = RESP_CANCEL;
  816. free( cmdp->param.data );
  817. free( cmdp->cmd );
  818. free( cmdp );
  819. if (resp == RESP_CANCEL || !tcmd || tcmd == cmdp)
  820. return resp;
  821. }
  822. }
  823. imap_invoke_bad_callback( ctx );
  824. return RESP_CANCEL;
  825. }
  826. static void
  827. get_cmd_result_p2( imap_store_t *ctx, struct imap_cmd *cmd, int response )
  828. {
  829. struct imap_cmd_trycreate *cmdp = (struct imap_cmd_trycreate *)cmd;
  830. struct imap_cmd *ocmd = cmdp->orig_cmd;
  831. if (response != RESP_OK) {
  832. ocmd->param.done( ctx, ocmd, response );
  833. free( ocmd->param.data );
  834. free( ocmd->cmd );
  835. free( ocmd );
  836. } else {
  837. ctx->uidnext = 0;
  838. ocmd->param.create = 0;
  839. submit_imap_cmd( ctx, ocmd, 0 );
  840. }
  841. }
  842. /******************* imap_cancel_store *******************/
  843. static void
  844. imap_cancel_store( store_t *gctx )
  845. {
  846. imap_store_t *ctx = (imap_store_t *)gctx;
  847. socket_close( &ctx->conn );
  848. cancel_submitted_imap_cmds( ctx );
  849. free_generic_messages( ctx->gen.msgs );
  850. free_string_list( ctx->gen.boxes );
  851. free_list( ctx->ns_personal );
  852. free_list( ctx->ns_other );
  853. free_list( ctx->ns_shared );
  854. imap_deref( ctx );
  855. }
  856. static int
  857. imap_deref( imap_store_t *ctx )
  858. {
  859. if (!--ctx->ref_count) {
  860. free( ctx );
  861. return -1;
  862. }
  863. return 0;
  864. }
  865. static void
  866. imap_invoke_bad_callback( imap_store_t *ctx )
  867. {
  868. ctx->gen.bad_callback( ctx->gen.bad_callback_aux );
  869. }
  870. /******************* imap_disown_store & imap_own_store *******************/
  871. static store_t *unowned;
  872. static void
  873. imap_cancel_unowned( void *gctx )
  874. {
  875. store_t *store, **storep;
  876. for (storep = &unowned; (store = *storep); storep = &store->next)
  877. if (store == gctx) {
  878. *storep = store->next;
  879. break;
  880. }
  881. imap_cancel_store( gctx );
  882. }
  883. static void
  884. imap_disown_store( store_t *gctx )
  885. {
  886. free_generic_messages( gctx->msgs );
  887. gctx->msgs = 0;
  888. set_bad_callback( gctx, imap_cancel_unowned, gctx );
  889. gctx->next = unowned;
  890. unowned = gctx;
  891. }
  892. static store_t *
  893. imap_own_store( store_conf_t *conf )
  894. {
  895. store_t *store, **storep;
  896. for (storep = &unowned; (store = *storep); storep = &store->next)
  897. if (store->conf == conf) {
  898. *storep = store->next;
  899. return store;
  900. }
  901. return 0;
  902. }
  903. /******************* imap_cleanup *******************/
  904. static void imap_cleanup_p2( imap_store_t *, struct imap_cmd *, int );
  905. static void
  906. imap_cleanup( void )
  907. {
  908. store_t *ctx, *nctx;
  909. for (ctx = unowned; ctx; ctx = nctx) {
  910. nctx = ctx->next;
  911. set_bad_callback( ctx, (void (*)(void *))imap_cancel_store, ctx );
  912. imap_exec( (imap_store_t *)ctx, 0, imap_cleanup_p2, "LOGOUT" );
  913. }
  914. }
  915. static void
  916. imap_cleanup_p2( imap_store_t *ctx,
  917. struct imap_cmd *cmd ATTR_UNUSED, int response )
  918. {
  919. if (response != RESP_CANCEL)
  920. imap_cancel_store( &ctx->gen );
  921. }
  922. /******************* imap_open_store *******************/
  923. #ifdef HAVE_LIBSSL
  924. static int
  925. do_cram_auth( imap_store_t *ctx, struct imap_cmd *cmdp, const char *prompt )
  926. {
  927. imap_server_conf_t *srvc = ((imap_store_conf_t *)ctx->gen.conf)->server;
  928. char *resp;
  929. int l;
  930. cmdp->param.cont = 0;
  931. cram( prompt, srvc->user, srvc->pass, &resp, &l );
  932. if (DFlags & VERBOSE)
  933. printf( ">+> %s\n", resp );
  934. return socket_write( &ctx->conn, resp, l, GiveOwn );
  935. }
  936. #endif
  937. static void imap_open_store_p2( imap_store_t *, struct imap_cmd *, int );
  938. static void imap_open_store_authenticate( imap_store_t * );
  939. #ifdef HAVE_LIBSSL
  940. static void imap_open_store_authenticate_p2( imap_store_t *, struct imap_cmd *, int );
  941. static void imap_open_store_authenticate_p3( imap_store_t *, struct imap_cmd *, int );
  942. #endif
  943. static void imap_open_store_authenticate2( imap_store_t * );
  944. static void imap_open_store_authenticate2_p2( imap_store_t *, struct imap_cmd *, int );
  945. static void imap_open_store_namespace( imap_store_t * );
  946. static void imap_open_store_namespace_p2( imap_store_t *, struct imap_cmd *, int );
  947. static void imap_open_store_namespace2( imap_store_t * );
  948. static void imap_open_store_finalize( imap_store_t * );
  949. #ifdef HAVE_LIBSSL
  950. static void imap_open_store_ssl_bail( imap_store_t * );
  951. #endif
  952. static void imap_open_store_bail( imap_store_t * );
  953. static void
  954. imap_open_store( store_conf_t *conf,
  955. void (*cb)( store_t *srv, void *aux ), void *aux )
  956. {
  957. imap_store_conf_t *cfg = (imap_store_conf_t *)conf;
  958. imap_server_conf_t *srvc = cfg->server;
  959. imap_store_t *ctx;
  960. store_t **ctxp;
  961. for (ctxp = &unowned; (ctx = (imap_store_t *)*ctxp); ctxp = &ctx->gen.next)
  962. if (((imap_store_conf_t *)ctx->gen.conf)->server == srvc) {
  963. *ctxp = ctx->gen.next;
  964. /* One could ping the server here, but given that the idle timeout
  965. * is at least 30 minutes, this sounds pretty pointless. */
  966. free_string_list( ctx->gen.boxes );
  967. ctx->gen.boxes = 0;
  968. ctx->gen.listed = 0;
  969. ctx->gen.conf = conf;
  970. ctx->callbacks.imap_open = cb;
  971. ctx->callback_aux = aux;
  972. set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx );
  973. imap_open_store_namespace( ctx );
  974. return;
  975. }
  976. ctx = nfcalloc( sizeof(*ctx) );
  977. ctx->gen.conf = conf;
  978. ctx->conn.fd = -1;
  979. ctx->ref_count = 1;
  980. ctx->callbacks.imap_open = cb;
  981. ctx->callback_aux = aux;
  982. set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx );
  983. ctx->in_progress_append = &ctx->in_progress;
  984. if (!socket_connect( &srvc->sconf, &ctx->conn ))
  985. goto bail;
  986. #ifdef HAVE_LIBSSL
  987. if (srvc->sconf.use_imaps) {
  988. if (socket_start_tls( &srvc->sconf, &ctx->conn )) {
  989. imap_open_store_ssl_bail( ctx );
  990. return;
  991. }
  992. }
  993. #endif
  994. get_cmd_result( ctx, 0 );
  995. return;
  996. bail:
  997. imap_open_store_bail( ctx );
  998. }
  999. static void
  1000. imap_open_store_greeted( imap_store_t *ctx )
  1001. {
  1002. if (ctx->greeting == GreetingBad) {
  1003. error( "IMAP error: unknown greeting response\n" );
  1004. imap_open_store_bail( ctx );
  1005. return;
  1006. }
  1007. if (!ctx->caps)
  1008. imap_exec( ctx, 0, imap_open_store_p2, "CAPABILITY" );
  1009. else
  1010. imap_open_store_authenticate( ctx );
  1011. }
  1012. static void
  1013. imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
  1014. {
  1015. if (response != RESP_OK)
  1016. imap_open_store_bail( ctx );
  1017. else
  1018. imap_open_store_authenticate( ctx );
  1019. }
  1020. static void
  1021. imap_open_store_authenticate( imap_store_t *ctx )
  1022. {
  1023. if (ctx->greeting != GreetingPreauth) {
  1024. #ifdef HAVE_LIBSSL
  1025. imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
  1026. imap_server_conf_t *srvc = cfg->server;
  1027. if (!srvc->sconf.use_imaps &&
  1028. (srvc->sconf.use_sslv2 || srvc->sconf.use_sslv3 || srvc->sconf.use_tlsv1)) {
  1029. /* always try to select SSL support if available */
  1030. if (CAP(STARTTLS)) {
  1031. imap_exec( ctx, 0, imap_open_store_authenticate_p2, "STARTTLS" );
  1032. return;
  1033. } else {
  1034. if (srvc->require_ssl) {
  1035. error( "IMAP error: SSL support not available\n" );
  1036. imap_open_store_bail( ctx );
  1037. return;
  1038. } else {
  1039. warn( "IMAP warning: SSL support not available\n" );
  1040. }
  1041. }
  1042. }
  1043. #endif
  1044. imap_open_store_authenticate2( ctx );
  1045. } else {
  1046. imap_open_store_namespace( ctx );
  1047. }
  1048. }
  1049. #ifdef HAVE_LIBSSL
  1050. static void
  1051. imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
  1052. {
  1053. if (response != RESP_OK)
  1054. imap_open_store_bail( ctx );
  1055. else if (socket_start_tls( &((imap_server_conf_t *)ctx->gen.conf)->sconf, &ctx->conn ))
  1056. imap_open_store_ssl_bail( ctx );
  1057. else
  1058. imap_exec( ctx, 0, imap_open_store_authenticate_p3, "CAPABILITY" );
  1059. }
  1060. static void
  1061. imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
  1062. {
  1063. if (response != RESP_OK)
  1064. imap_open_store_bail( ctx );
  1065. else
  1066. imap_open_store_authenticate2( ctx );
  1067. }
  1068. #endif
  1069. static void
  1070. imap_open_store_authenticate2( imap_store_t *ctx )
  1071. {
  1072. imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
  1073. imap_server_conf_t *srvc = cfg->server;
  1074. char *arg;
  1075. info ("Logging in...\n");
  1076. if (!srvc->user) {
  1077. error( "Skipping account %s, no user\n", srvc->name );
  1078. goto bail;
  1079. }
  1080. if (!srvc->pass) {
  1081. char prompt[80];
  1082. sprintf( prompt, "Password (%s): ", srvc->name );
  1083. arg = getpass( prompt );
  1084. if (!arg) {
  1085. perror( "getpass" );
  1086. exit( 1 );
  1087. }
  1088. if (!*arg) {
  1089. error( "Skipping account %s, no password\n", srvc->name );
  1090. goto bail;
  1091. }
  1092. /*
  1093. * getpass() returns a pointer to a static buffer. make a copy
  1094. * for long term storage.
  1095. */
  1096. srvc->pass = nfstrdup( arg );
  1097. }
  1098. #ifdef HAVE_LIBSSL
  1099. if (CAP(CRAM)) {
  1100. struct imap_cmd *cmd = new_imap_cmd( sizeof(*cmd) );
  1101. info( "Authenticating with CRAM-MD5\n" );
  1102. cmd->param.cont = do_cram_auth;
  1103. imap_exec( ctx, cmd, imap_open_store_authenticate2_p2, "AUTHENTICATE CRAM-MD5" );
  1104. return;
  1105. }
  1106. if (srvc->require_cram) {
  1107. error( "IMAP error: CRAM-MD5 authentication is not supported by server\n" );
  1108. goto bail;
  1109. }
  1110. #endif
  1111. if (CAP(NOLOGIN)) {
  1112. error( "Skipping account %s, server forbids LOGIN\n", srvc->name );
  1113. goto bail;
  1114. }
  1115. #ifdef HAVE_LIBSSL
  1116. if (!ctx->conn.ssl)
  1117. #endif
  1118. warn( "*** IMAP Warning *** Password is being sent in the clear\n" );
  1119. imap_exec( ctx, 0, imap_open_store_authenticate2_p2,
  1120. "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass );
  1121. return;
  1122. bail:
  1123. imap_open_store_bail( ctx );
  1124. }
  1125. static void
  1126. imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
  1127. {
  1128. if (response != RESP_OK)
  1129. imap_open_store_bail( ctx );
  1130. else
  1131. imap_open_store_namespace( ctx );
  1132. }
  1133. static void
  1134. imap_open_store_namespace( imap_store_t *ctx )
  1135. {
  1136. imap_store_conf_t *cfg = (imap_store_conf_t *)ctx->gen.conf;
  1137. ctx->prefix = "";
  1138. if (*cfg->gen.path)
  1139. ctx->prefix = cfg->gen.path;
  1140. else if (cfg->use_namespace && CAP(NAMESPACE)) {
  1141. /* get NAMESPACE info */
  1142. if (!ctx->got_namespace)
  1143. imap_exec( ctx, 0, imap_open_store_namespace_p2, "NAMESPACE" );
  1144. else
  1145. imap_open_store_namespace2( ctx );
  1146. return;
  1147. }
  1148. imap_open_store_finalize( ctx );
  1149. }
  1150. static void
  1151. imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
  1152. {
  1153. if (response != RESP_OK) {
  1154. imap_open_store_bail( ctx );
  1155. } else {
  1156. ctx->got_namespace = 1;
  1157. imap_open_store_namespace2( ctx );
  1158. }
  1159. }
  1160. static void
  1161. imap_open_store_namespace2( imap_store_t *ctx )
  1162. {
  1163. /* XXX for now assume personal namespace */
  1164. if (is_list( ctx->ns_personal ) &&
  1165. is_list( ctx->ns_personal->child ) &&
  1166. is_atom( ctx->ns_personal->child->child ))
  1167. ctx->prefix = ctx->ns_personal->child->child->val;
  1168. imap_open_store_finalize( ctx );
  1169. }
  1170. static void
  1171. imap_open_store_finalize( imap_store_t *ctx )
  1172. {
  1173. set_bad_callback( &ctx->gen, 0, 0 );
  1174. ctx->trashnc = 1;
  1175. ctx->callbacks.imap_open( &ctx->gen, ctx->callback_aux );
  1176. }
  1177. #ifdef HAVE_LIBSSL
  1178. static void
  1179. imap_open_store_ssl_bail( imap_store_t *ctx )
  1180. {
  1181. /* This avoids that we try to send LOGOUT to an unusable socket. */
  1182. socket_close( &ctx->conn );
  1183. imap_open_store_bail( ctx );
  1184. }
  1185. #endif
  1186. static void
  1187. imap_open_store_bail( imap_store_t *ctx )
  1188. {
  1189. void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open;
  1190. void *aux = ctx->callback_aux;
  1191. imap_cancel_store( &ctx->gen );
  1192. cb( 0, aux );
  1193. }
  1194. /******************* imap_prepare_opts *******************/
  1195. static void
  1196. imap_prepare_opts( store_t *gctx, int opts )
  1197. {
  1198. gctx->opts = opts;
  1199. }
  1200. /******************* imap_select *******************/
  1201. static void
  1202. imap_select( store_t *gctx, int create,
  1203. void (*cb)( int sts, void *aux ), void *aux )
  1204. {
  1205. imap_store_t *ctx = (imap_store_t *)gctx;
  1206. struct imap_cmd_simple *cmd;
  1207. const char *prefix;
  1208. free_generic_messages( gctx->msgs );
  1209. gctx->msgs = 0;
  1210. if (!strcmp( gctx->name, "INBOX" )) {
  1211. prefix = "";
  1212. } else {
  1213. prefix = ctx->prefix;
  1214. }
  1215. ctx->uidnext = -1;
  1216. INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
  1217. cmd->gen.param.create = create;
  1218. cmd->gen.param.trycreate = 1;
  1219. imap_exec( ctx, &cmd->gen, imap_done_simple_box,
  1220. "SELECT \"%s%s\"", prefix, gctx->name );
  1221. }
  1222. /******************* imap_load *******************/
  1223. static int imap_submit_load( imap_store_t *, const char *, struct imap_cmd_refcounted_state *,
  1224. struct imap_cmd ** );
  1225. static void imap_load_p2( imap_store_t *, struct imap_cmd *, int );
  1226. static void
  1227. imap_load( store_t *gctx, int minuid, int maxuid, int *excs, int nexcs,
  1228. void (*cb)( int sts, void *aux ), void *aux )
  1229. {
  1230. imap_store_t *ctx = (imap_store_t *)gctx;
  1231. int i, j, bl;
  1232. char buf[1000];
  1233. if (!ctx->gen.count) {
  1234. free( excs );
  1235. cb( DRV_OK, aux );
  1236. } else {
  1237. struct imap_cmd *cmd2 = 0;
  1238. struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
  1239. ctx->msgapp = &ctx->gen.msgs;
  1240. sort_ints( excs, nexcs );
  1241. for (i = 0; i < nexcs; ) {
  1242. for (bl = 0; i < nexcs && bl < 960; i++) {
  1243. if (bl)
  1244. buf[bl++] = ',';
  1245. bl += sprintf( buf + bl, "%d", excs[i] );
  1246. j = i;
  1247. for (; i + 1 < nexcs && excs[i + 1] == excs[i] + 1; i++) {}
  1248. if (i != j)
  1249. bl += sprintf( buf + bl, ":%d", excs[i] );
  1250. }
  1251. if (imap_submit_load( ctx, buf, sts, &cmd2 ) < 0)
  1252. goto done;
  1253. }
  1254. if (maxuid == INT_MAX)
  1255. maxuid = ctx->uidnext >= 0 ? ctx->uidnext - 1 : 1000000000;
  1256. if (maxuid >= minuid) {
  1257. sprintf( buf, "%d:%d", minuid, maxuid );
  1258. imap_submit_load( ctx, buf, sts, &cmd2 );
  1259. }
  1260. done:
  1261. free( excs );
  1262. if (!--sts->ref_count)
  1263. imap_refcounted_done( sts );
  1264. else
  1265. get_cmd_result( ctx, cmd2 );
  1266. }
  1267. }
  1268. static int
  1269. imap_submit_load( imap_store_t *ctx, const char *buf, struct imap_cmd_refcounted_state *sts,
  1270. struct imap_cmd **cmdp )
  1271. {
  1272. struct imap_cmd *cmd = imap_refcounted_new_cmd( sts );
  1273. cmd->param.done = imap_load_p2;
  1274. *cmdp = cmd;
  1275. return submit_imap_cmd( ctx, cmd,
  1276. "UID FETCH %s (UID%s%s)", buf,
  1277. (ctx->gen.opts & OPEN_FLAGS) ? " FLAGS" : "",
  1278. (ctx->gen.opts & OPEN_SIZE) ? " RFC822.SIZE" : "" ) ? 0 : -1;
  1279. }
  1280. static void
  1281. imap_load_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response )
  1282. {
  1283. struct imap_cmd_refcounted_state *sts = ((struct imap_cmd_refcounted *)cmd)->state;
  1284. switch (response) {
  1285. case RESP_CANCEL:
  1286. sts->ret_val = DRV_CANCELED;
  1287. break;
  1288. case RESP_NO:
  1289. if (sts->ret_val == DRV_OK) /* Don't override cancelation. */
  1290. sts->ret_val = DRV_BOX_BAD;
  1291. break;
  1292. }
  1293. if (!--sts->ref_count)
  1294. imap_refcounted_done( sts );
  1295. }
  1296. /******************* imap_fetch_msg *******************/
  1297. static void
  1298. imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data,
  1299. void (*cb)( int sts, void *aux ), void *aux )
  1300. {
  1301. struct imap_cmd_fetch_msg *cmd;
  1302. INIT_IMAP_CMD_X(imap_cmd_fetch_msg, cmd, cb, aux)
  1303. cmd->gen.gen.param.uid = msg->uid;
  1304. cmd->msg_data = data;
  1305. imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_done_simple_msg,
  1306. "UID FETCH %d (%sBODY.PEEK[])",
  1307. msg->uid, (msg->status & M_FLAGS) ? "" : "FLAGS " );
  1308. }
  1309. /******************* imap_set_flags *******************/
  1310. static void imap_set_flags_p2( imap_store_t *, struct imap_cmd *, int );
  1311. static int
  1312. imap_make_flags( int flags, char *buf )
  1313. {
  1314. const char *s;
  1315. unsigned i, d;
  1316. for (i = d = 0; i < as(Flags); i++)
  1317. if (flags & (1 << i)) {
  1318. buf[d++] = ' ';
  1319. buf[d++] = '\\';
  1320. for (s = Flags[i]; *s; s++)
  1321. buf[d++] = *s;
  1322. }
  1323. buf[0] = '(';
  1324. buf[d++] = ')';
  1325. return d;
  1326. }
  1327. static int
  1328. imap_flags_helper( imap_store_t *ctx, int uid, char what, int flags,
  1329. struct imap_cmd_refcounted_state *sts )
  1330. {
  1331. char buf[256];
  1332. struct imap_cmd *cmd = imap_refcounted_new_cmd( sts );
  1333. cmd->param.done = imap_set_flags_p2;
  1334. buf[imap_make_flags( flags, buf )] = 0;
  1335. if (!submit_imap_cmd( ctx, cmd, "UID STORE %d %cFLAGS.SILENT %s", uid, what, buf ))
  1336. return -1;
  1337. return process_imap_replies( ctx ) == RESP_CANCEL ? -1 : 0;
  1338. }
  1339. static void
  1340. imap_set_flags( store_t *gctx, message_t *msg, int uid, int add, int del,
  1341. void (*cb)( int sts, void *aux ), void *aux )
  1342. {
  1343. imap_store_t *ctx = (imap_store_t *)gctx;
  1344. if (msg) {
  1345. uid = msg->uid;
  1346. add &= ~msg->flags;
  1347. del &= msg->flags;
  1348. msg->flags |= add;
  1349. msg->flags &= ~del;
  1350. }
  1351. if (add || del) {
  1352. struct imap_cmd_refcounted_state *sts = imap_refcounted_new_state( cb, aux );
  1353. if ((add && imap_flags_helper( ctx, uid, '+', add, sts ) < 0) ||
  1354. (del && imap_flags_helper( ctx, uid, '-', del, sts ) < 0)) {}
  1355. if (!--sts->ref_count)
  1356. imap_refcounted_done( sts );
  1357. } else {
  1358. cb( DRV_OK, aux );
  1359. }
  1360. }
  1361. static void
  1362. imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response )
  1363. {
  1364. struct imap_cmd_refcounted_state *sts = ((struct imap_cmd_refcounted *)cmd)->state;
  1365. switch (response) {
  1366. case RESP_CANCEL:
  1367. sts->ret_val = DRV_CANCELED;
  1368. break;
  1369. case RESP_NO:
  1370. if (sts->ret_val == DRV_OK) /* Don't override cancelation. */
  1371. sts->ret_val = DRV_MSG_BAD;
  1372. break;
  1373. }
  1374. if (!--sts->ref_count)
  1375. imap_refcounted_done( sts );
  1376. }
  1377. /******************* imap_close *******************/
  1378. static void
  1379. imap_close( store_t *ctx,
  1380. void (*cb)( int sts, void *aux ), void *aux )
  1381. {
  1382. struct imap_cmd_simple *cmd;
  1383. INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
  1384. imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_done_simple_box, "CLOSE" );
  1385. }
  1386. /******************* imap_trash_msg *******************/
  1387. static void
  1388. imap_trash_msg( store_t *gctx, message_t *msg,
  1389. void (*cb)( int sts, void *aux ), void *aux )
  1390. {
  1391. imap_store_t *ctx = (imap_store_t *)gctx;
  1392. struct imap_cmd_simple *cmd;
  1393. INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
  1394. cmd->gen.param.create = 1;
  1395. cmd->gen.param.to_trash = 1;
  1396. imap_exec( ctx, &cmd->gen, imap_done_simple_msg,
  1397. "UID COPY %d \"%s%s\"",
  1398. msg->uid, ctx->prefix, gctx->conf->trash );
  1399. }
  1400. /******************* imap_store_msg *******************/
  1401. static void imap_store_msg_p2( imap_store_t *, struct imap_cmd *, int );
  1402. static void
  1403. imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash,
  1404. void (*cb)( int sts, int uid, void *aux ), void *aux )
  1405. {
  1406. imap_store_t *ctx = (imap_store_t *)gctx;
  1407. struct imap_cmd_out_uid *cmd;
  1408. const char *prefix, *box;
  1409. int d;
  1410. char flagstr[128];
  1411. d = 0;
  1412. if (data->flags) {
  1413. d = imap_make_flags( data->flags, flagstr );
  1414. flagstr[d++] = ' ';
  1415. }
  1416. flagstr[d] = 0;
  1417. INIT_IMAP_CMD(imap_cmd_out_uid, cmd, cb, aux)
  1418. cmd->gen.param.data_len = data->len;
  1419. cmd->gen.param.data = data->data;
  1420. cmd->out_uid = -2;
  1421. if (to_trash) {
  1422. box = gctx->conf->trash;
  1423. prefix = ctx->prefix;
  1424. cmd->gen.param.create = 1;
  1425. cmd->gen.param.to_trash = 1;
  1426. } else {
  1427. box = gctx->name;
  1428. prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix;
  1429. }
  1430. imap_exec( ctx, &cmd->gen, imap_store_msg_p2,
  1431. "APPEND \"%s%s\" %s", prefix, box, flagstr );
  1432. }
  1433. static void
  1434. imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response )
  1435. {
  1436. struct imap_cmd_out_uid *cmdp = (struct imap_cmd_out_uid *)cmd;
  1437. transform_msg_response( &response );
  1438. cmdp->callback( response, cmdp->out_uid, cmdp->callback_aux );
  1439. }
  1440. /******************* imap_find_msg *******************/
  1441. static void imap_find_msg_p2( imap_store_t *, struct imap_cmd *, int );
  1442. static void
  1443. imap_find_msg( store_t *gctx, const char *tuid,
  1444. void (*cb)( int sts, int uid, void *aux ), void *aux )
  1445. {
  1446. imap_store_t *ctx = (imap_store_t *)gctx;
  1447. struct imap_cmd_out_uid *cmd;
  1448. INIT_IMAP_CMD(imap_cmd_out_uid, cmd, cb, aux)
  1449. cmd->gen.param.uid = -1; /* we're looking for a UID */
  1450. cmd->out_uid = -1; /* in case we get no SEARCH response at all */
  1451. imap_exec( ctx, &cmd->gen, imap_find_msg_p2,
  1452. "UID SEARCH HEADER X-TUID %." stringify(TUIDL) "s", tuid );
  1453. }
  1454. static void
  1455. imap_find_msg_p2( imap_store_t *ctx ATTR_UNUSED, struct imap_cmd *cmd, int response )
  1456. {
  1457. struct imap_cmd_out_uid *cmdp = (struct imap_cmd_out_uid *)cmd;
  1458. transform_msg_response( &response );
  1459. if (response != DRV_OK)
  1460. cmdp->callback( response, -1, cmdp->callback_aux );
  1461. else
  1462. cmdp->callback( cmdp->out_uid <= 0 ? DRV_MSG_BAD : DRV_OK,
  1463. cmdp->out_uid, cmdp->callback_aux );
  1464. }
  1465. /******************* imap_list *******************/
  1466. static void
  1467. imap_list( store_t *gctx,
  1468. void (*cb)( int sts, void *aux ), void *aux )
  1469. {
  1470. imap_store_t *ctx = (imap_store_t *)gctx;
  1471. struct imap_cmd_simple *cmd;
  1472. INIT_IMAP_CMD(imap_cmd_simple, cmd, cb, aux)
  1473. imap_exec( ctx, &cmd->gen, imap_done_simple_box,
  1474. "LIST \"\" \"%s%%\"", ctx->prefix );
  1475. }
  1476. /******************* imap_cancel *******************/
  1477. static void
  1478. imap_cancel( store_t *gctx,
  1479. void (*cb)( void *aux ), void *aux )
  1480. {
  1481. (void)gctx;
  1482. cb( aux );
  1483. }
  1484. /******************* imap_commit *******************/
  1485. static void
  1486. imap_commit( store_t *gctx )
  1487. {
  1488. (void)gctx;
  1489. }
  1490. /******************* imap_parse_store *******************/
  1491. imap_server_conf_t *servers, **serverapp = &servers;
  1492. static int
  1493. imap_parse_store( conffile_t *cfg, store_conf_t **storep, int *err )
  1494. {
  1495. imap_store_conf_t *store;
  1496. imap_server_conf_t *server, *srv, sserver;
  1497. int acc_opt = 0;
  1498. if (!strcasecmp( "IMAPAccount", cfg->cmd )) {
  1499. server = nfcalloc( sizeof(*server) );
  1500. server->name = nfstrdup( cfg->val );
  1501. *serverapp = server;
  1502. serverapp = &server->next;
  1503. store = 0;
  1504. *storep = 0;
  1505. } else if (!strcasecmp( "IMAPStore", cfg->cmd )) {
  1506. store = nfcalloc( sizeof(*store) );
  1507. store->gen.driver = &imap_driver;
  1508. store->gen.name = nfstrdup( cfg->val );
  1509. store->use_namespace = 1;
  1510. *storep = &store->gen;
  1511. memset( &sserver, 0, sizeof(sserver) );
  1512. server = &sserver;
  1513. } else
  1514. return 0;
  1515. #ifdef HAVE_LIBSSL
  1516. /* this will probably annoy people, but its the best default just in
  1517. * case people forget to turn it on
  1518. */
  1519. server->require_ssl = 1;
  1520. server->sconf.use_tlsv1 = 1;
  1521. #endif
  1522. server->max_in_progress = 50;
  1523. while (getcline( cfg ) && cfg->cmd) {
  1524. if (!strcasecmp( "Host", cfg->cmd )) {
  1525. /* The imap[s]: syntax is just a backwards compat hack. */
  1526. #ifdef HAVE_LIBSSL
  1527. if (!memcmp( "imaps:", cfg->val, 6 )) {
  1528. cfg->val += 6;
  1529. server->sconf.use_imaps = 1;
  1530. server->sconf.use_sslv2 = 1;
  1531. server->sconf.use_sslv3 = 1;
  1532. } else
  1533. #endif
  1534. {
  1535. if (!memcmp( "imap:", cfg->val, 5 ))
  1536. cfg->val += 5;
  1537. }
  1538. if (!memcmp( "//", cfg->val, 2 ))
  1539. cfg->val += 2;
  1540. server->sconf.host = nfstrdup( cfg->val );
  1541. }
  1542. else if (!strcasecmp( "User", cfg->cmd ))
  1543. server->user = nfstrdup( cfg->val );
  1544. else if (!strcasecmp( "Pass", cfg->cmd ))
  1545. server->pass = nfstrdup( cfg->val );
  1546. else if (!strcasecmp( "Port", cfg->cmd ))
  1547. server->sconf.port = parse_int( cfg );
  1548. else if (!strcasecmp( "PipelineDepth", cfg->cmd )) {
  1549. if ((server->max_in_progress = parse_int( cfg )) < 1) {
  1550. error( "%s:%d: PipelineDepth must be at least 1\n", cfg->file, cfg->line );
  1551. *err = 1;
  1552. }
  1553. }
  1554. #ifdef HAVE_LIBSSL
  1555. else if (!strcasecmp( "CertificateFile", cfg->cmd )) {
  1556. server->sconf.cert_file = expand_strdup( cfg->val );
  1557. if (access( server->sconf.cert_file, R_OK )) {
  1558. error( "%s:%d: CertificateFile '%s': %s\n",
  1559. cfg->file, cfg->line, server->sconf.cert_file, strerror( errno ) );
  1560. *err = 1;
  1561. }
  1562. } else if (!strcasecmp( "RequireSSL", cfg->cmd ))
  1563. server->require_ssl = parse_bool( cfg );
  1564. else if (!strcasecmp( "UseIMAPS", cfg->cmd ))
  1565. server->sconf.use_imaps = parse_bool( cfg );
  1566. else if (!strcasecmp( "UseSSLv2", cfg->cmd ))
  1567. server->sconf.use_sslv2 = parse_bool( cfg );
  1568. else if (!strcasecmp( "UseSSLv3", cfg->cmd ))
  1569. server->sconf.use_sslv3 = parse_bool( cfg );
  1570. else if (!strcasecmp( "UseTLSv1", cfg->cmd ))
  1571. server->sconf.use_tlsv1 = parse_bool( cfg );
  1572. else if (!strcasecmp( "RequireCRAM", cfg->cmd ))
  1573. server->require_cram = parse_bool( cfg );
  1574. #endif
  1575. else if (!strcasecmp( "Tunnel", cfg->cmd ))
  1576. server->sconf.tunnel = nfstrdup( cfg->val );
  1577. else if (store) {
  1578. if (!strcasecmp( "Account", cfg->cmd )) {
  1579. for (srv = servers; srv; srv = srv->next)
  1580. if (srv->name && !strcmp( srv->name, cfg->val ))
  1581. goto gotsrv;
  1582. error( "%s:%d: unknown IMAP account '%s'\n", cfg->file, cfg->line, cfg->val );
  1583. *err = 1;
  1584. continue;
  1585. gotsrv:
  1586. store->server = srv;
  1587. } else if (!strcasecmp( "UseNamespace", cfg->cmd ))
  1588. store->use_namespace = parse_bool( cfg );
  1589. else if (!strcasecmp( "Path", cfg->cmd ))
  1590. store->gen.path = nfstrdup( cfg->val );
  1591. else
  1592. parse_generic_store( &store->gen, cfg, err );
  1593. continue;
  1594. } else {
  1595. error( "%s:%d: unknown/misplaced keyword '%s'\n", cfg->file, cfg->line, cfg->cmd );
  1596. *err = 1;
  1597. continue;
  1598. }
  1599. acc_opt = 1;
  1600. }
  1601. if (!store || !store->server) {
  1602. if (!server->sconf.tunnel && !server->sconf.host) {
  1603. if (store)
  1604. error( "IMAP store '%s' has incomplete/missing connection details\n", store->gen.name );
  1605. else
  1606. error( "IMAP account '%s' has incomplete/missing connection details\n", server->name );
  1607. *err = 1;
  1608. return 1;
  1609. }
  1610. }
  1611. if (store) {
  1612. if (!store->server) {
  1613. store->server = nfmalloc( sizeof(sserver) );
  1614. memcpy( store->server, &sserver, sizeof(sserver) );
  1615. store->server->name = store->gen.name;
  1616. } else if (acc_opt) {
  1617. error( "IMAP store '%s' has both Account and account-specific options\n", store->gen.name );
  1618. *err = 1;
  1619. }
  1620. }
  1621. return 1;
  1622. }
  1623. struct driver imap_driver = {
  1624. DRV_CRLF,
  1625. imap_parse_store,
  1626. imap_cleanup,
  1627. imap_open_store,
  1628. imap_disown_store,
  1629. imap_own_store,
  1630. imap_cancel_store,
  1631. imap_list,
  1632. imap_prepare_opts,
  1633. imap_select,
  1634. imap_load,
  1635. imap_fetch_msg,
  1636. imap_store_msg,
  1637. imap_find_msg,
  1638. imap_set_flags,
  1639. imap_trash_msg,
  1640. imap_close,
  1641. imap_cancel,
  1642. imap_commit,
  1643. };