drv_imap.c 49 KB

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