main.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /*
  2. * mbsync - mailbox synchronizer
  3. * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
  4. * Copyright (C) 2002-2006 Oswald Buddenhagen <ossi@users.sf.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  19. *
  20. * As a special exception, mbsync may be linked with the OpenSSL library,
  21. * despite that library's more restrictive license.
  22. */
  23. #include "isync.h"
  24. #include <stdlib.h>
  25. #include <stddef.h>
  26. #include <unistd.h>
  27. #include <string.h>
  28. #include <fcntl.h>
  29. #include <signal.h>
  30. #include <sys/wait.h>
  31. int Pid; /* for maildir and imap */
  32. char Hostname[256]; /* for maildir */
  33. const char *Home; /* for config */
  34. static void
  35. version( void )
  36. {
  37. puts( PACKAGE " " VERSION );
  38. exit( 0 );
  39. }
  40. static void
  41. usage( int code )
  42. {
  43. fputs(
  44. PACKAGE " " VERSION " - mailbox synchronizer\n"
  45. "Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
  46. "Copyright (C) 2002-2006 Oswald Buddenhagen <ossi@users.sf.net>\n"
  47. "Copyright (C) 2004 Theodore Ts'o <tytso@mit.edu>\n"
  48. "usage:\n"
  49. " " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n"
  50. " -a, --all operate on all defined channels\n"
  51. " -l, --list list mailboxes instead of syncing them\n"
  52. " -n, --new propagate new messages\n"
  53. " -d, --delete propagate message deletions\n"
  54. " -f, --flags propagate message flag changes\n"
  55. " -N, --renew propagate previously not propagated new messages\n"
  56. " -L, --pull propagate from master to slave\n"
  57. " -H, --push propagate from slave to master\n"
  58. " -C, --create create mailboxes if nonexistent\n"
  59. " -X, --expunge expunge deleted messages\n"
  60. " -c, --config CONFIG read an alternate config file (default: ~/." EXE "rc)\n"
  61. " -D, --debug print debugging messages\n"
  62. " -V, --verbose verbose mode (display network traffic)\n"
  63. " -q, --quiet don't display progress info\n"
  64. " -v, --version display version\n"
  65. " -h, --help display this help message\n"
  66. "\nIf neither --pull nor --push are specified, both are active.\n"
  67. "If neither --new, --delete, --flags nor --renew are specified, all are active.\n"
  68. "Direction and operation can be concatenated like --pull-new, etc.\n"
  69. "--create and --expunge can be suffixed with -master/-slave. Read the man page.\n"
  70. "\nSupported mailbox formats are: IMAP4rev1, Maildir\n"
  71. "\nCompile time options:\n"
  72. #ifdef HAVE_LIBSSL
  73. " +HAVE_LIBSSL\n"
  74. #else
  75. " -HAVE_LIBSSL\n"
  76. #endif
  77. , code ? stderr : stdout );
  78. exit( code );
  79. }
  80. #ifdef __linux__
  81. static void
  82. crashHandler( int n )
  83. {
  84. int dpid;
  85. char pbuf[10], pabuf[20];
  86. close( 0 );
  87. open( "/dev/tty", O_RDWR );
  88. dup2( 0, 1 );
  89. dup2( 0, 2 );
  90. error( "*** " EXE " caught signal %d. Starting debugger ...\n", n );
  91. switch ((dpid = fork())) {
  92. case -1:
  93. perror( "fork()" );
  94. break;
  95. case 0:
  96. sprintf( pbuf, "%d", Pid );
  97. sprintf( pabuf, "/proc/%d/exe", Pid );
  98. execlp( "gdb", "gdb", pabuf, pbuf, (char *)0 );
  99. perror( "execlp()" );
  100. _exit( 1 );
  101. default:
  102. waitpid( dpid, 0, 0 );
  103. break;
  104. }
  105. exit( 3 );
  106. }
  107. #endif
  108. static int
  109. matches( const char *t, const char *p )
  110. {
  111. for (;;) {
  112. if (!*p)
  113. return !*t;
  114. if (*p == '*') {
  115. p++;
  116. do {
  117. if (matches( t, p ))
  118. return 1;
  119. } while (*t++);
  120. return 0;
  121. } else if (*p == '%') {
  122. p++;
  123. do {
  124. if (*t == '/')
  125. return 0;
  126. if (matches( t, p ))
  127. return 1;
  128. } while (*t++);
  129. return 0;
  130. } else {
  131. if (*p != *t)
  132. return 0;
  133. p++, t++;
  134. }
  135. }
  136. }
  137. static string_list_t *
  138. filter_boxes( string_list_t *boxes, string_list_t *patterns )
  139. {
  140. string_list_t *nboxes = 0, *cpat;
  141. const char *ps;
  142. int not, fnot;
  143. for (; boxes; boxes = boxes->next) {
  144. fnot = 1;
  145. for (cpat = patterns; cpat; cpat = cpat->next) {
  146. ps = cpat->string;
  147. if (*ps == '!') {
  148. ps++;
  149. not = 1;
  150. } else
  151. not = 0;
  152. if (matches( boxes->string, ps )) {
  153. fnot = not;
  154. break;
  155. }
  156. }
  157. if (!fnot)
  158. add_string_list( &nboxes, boxes->string );
  159. }
  160. return nboxes;
  161. }
  162. static void
  163. merge_actions( channel_conf_t *chan, int ops[], int have, int mask, int def )
  164. {
  165. if (ops[M] & have) {
  166. chan->ops[M] &= ~mask;
  167. chan->ops[M] |= ops[M] & mask;
  168. chan->ops[S] &= ~mask;
  169. chan->ops[S] |= ops[S] & mask;
  170. } else if (!(chan->ops[M] & have)) {
  171. if (global_ops[M] & have) {
  172. chan->ops[M] |= global_ops[M] & mask;
  173. chan->ops[S] |= global_ops[S] & mask;
  174. } else {
  175. chan->ops[M] |= def;
  176. chan->ops[S] |= def;
  177. }
  178. }
  179. }
  180. typedef struct {
  181. int t[2];
  182. channel_conf_t *chan;
  183. driver_t *drv[2];
  184. store_t *ctx[2];
  185. string_list_t *boxes[2], *cboxes, *chanptr;
  186. const char *names[2];
  187. char **argv, *boxlist, *boxp;
  188. int oind, ret, multiple, all, list, ops[2], state[2];
  189. unsigned done:1, skip:1, cben:1;
  190. } main_vars_t;
  191. #define AUX &mvars->t[t]
  192. #define MVARS(aux) \
  193. int t = *(int *)aux; \
  194. main_vars_t *mvars = (main_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(main_vars_t, t));
  195. #define E_START 0
  196. #define E_OPEN 1
  197. #define E_SYNC 2
  198. static void sync_chans( main_vars_t *mvars, int ent );
  199. int
  200. main( int argc, char **argv )
  201. {
  202. main_vars_t mvars[1];
  203. group_conf_t *group;
  204. char *config = 0, *opt, *ochar;
  205. int cops = 0, op, pseudo = 0;
  206. gethostname( Hostname, sizeof(Hostname) );
  207. if ((ochar = strchr( Hostname, '.' )))
  208. *ochar = 0;
  209. Pid = getpid();
  210. if (!(Home = getenv("HOME"))) {
  211. fputs( "Fatal: $HOME not set\n", stderr );
  212. return 1;
  213. }
  214. arc4_init();
  215. memset( mvars, 0, sizeof(*mvars) );
  216. mvars->t[1] = 1;
  217. for (mvars->oind = 1, ochar = 0; ; ) {
  218. if (!ochar || !*ochar) {
  219. if (mvars->oind >= argc)
  220. break;
  221. if (argv[mvars->oind][0] != '-')
  222. break;
  223. if (argv[mvars->oind][1] == '-') {
  224. opt = argv[mvars->oind++] + 2;
  225. if (!*opt)
  226. break;
  227. if (!strcmp( opt, "config" )) {
  228. if (mvars->oind >= argc) {
  229. error( "--config requires an argument.\n" );
  230. return 1;
  231. }
  232. config = argv[mvars->oind++];
  233. } else if (!memcmp( opt, "config=", 7 ))
  234. config = opt + 7;
  235. else if (!strcmp( opt, "all" ))
  236. mvars->all = 1;
  237. else if (!strcmp( opt, "list" ))
  238. mvars->list = 1;
  239. else if (!strcmp( opt, "help" ))
  240. usage( 0 );
  241. else if (!strcmp( opt, "version" ))
  242. version();
  243. else if (!strcmp( opt, "quiet" )) {
  244. if (DFlags & QUIET)
  245. DFlags |= VERYQUIET;
  246. else
  247. DFlags |= QUIET;
  248. } else if (!strcmp( opt, "verbose" )) {
  249. if (DFlags & VERBOSE)
  250. DFlags |= XVERBOSE;
  251. else
  252. DFlags |= VERBOSE | QUIET;
  253. } else if (!strcmp( opt, "debug" ))
  254. DFlags |= DEBUG | QUIET;
  255. else if (!strcmp( opt, "pull" ))
  256. cops |= XOP_PULL, mvars->ops[M] |= XOP_HAVE_TYPE;
  257. else if (!strcmp( opt, "push" ))
  258. cops |= XOP_PUSH, mvars->ops[M] |= XOP_HAVE_TYPE;
  259. else if (!memcmp( opt, "create", 6 )) {
  260. opt += 6;
  261. op = OP_CREATE|XOP_HAVE_CREATE;
  262. lcop:
  263. if (!*opt)
  264. cops |= op;
  265. else if (!strcmp( opt, "-master" ))
  266. mvars->ops[M] |= op, ochar++;
  267. else if (!strcmp( opt, "-slave" ))
  268. mvars->ops[S] |= op, ochar++;
  269. else
  270. goto badopt;
  271. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  272. } else if (!memcmp( opt, "expunge", 7 )) {
  273. opt += 7;
  274. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  275. goto lcop;
  276. } else if (!strcmp( opt, "no-expunge" ))
  277. mvars->ops[M] |= XOP_HAVE_EXPUNGE;
  278. else if (!strcmp( opt, "no-create" ))
  279. mvars->ops[M] |= XOP_HAVE_CREATE;
  280. else if (!strcmp( opt, "full" ))
  281. mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
  282. else if (!strcmp( opt, "noop" ))
  283. mvars->ops[M] |= XOP_HAVE_TYPE;
  284. else if (!memcmp( opt, "pull", 4 )) {
  285. op = XOP_PULL;
  286. lcac:
  287. opt += 4;
  288. if (!*opt)
  289. cops |= op;
  290. else if (*opt == '-') {
  291. opt++;
  292. goto rlcac;
  293. } else
  294. goto badopt;
  295. } else if (!memcmp( opt, "push", 4 )) {
  296. op = XOP_PUSH;
  297. goto lcac;
  298. } else {
  299. op = 0;
  300. rlcac:
  301. if (!strcmp( opt, "new" ))
  302. op |= OP_NEW;
  303. else if (!strcmp( opt, "renew" ))
  304. op |= OP_RENEW;
  305. else if (!strcmp( opt, "delete" ))
  306. op |= OP_DELETE;
  307. else if (!strcmp( opt, "flags" ))
  308. op |= OP_FLAGS;
  309. else {
  310. badopt:
  311. error( "Unknown option '%s'\n", argv[mvars->oind - 1] );
  312. return 1;
  313. }
  314. switch (op & XOP_MASK_DIR) {
  315. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  316. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  317. default: cops |= op; break;
  318. }
  319. mvars->ops[M] |= XOP_HAVE_TYPE;
  320. }
  321. continue;
  322. }
  323. ochar = argv[mvars->oind++] + 1;
  324. if (!*ochar) {
  325. error( "Invalid option '-'\n" );
  326. return 1;
  327. }
  328. }
  329. switch (*ochar++) {
  330. case 'a':
  331. mvars->all = 1;
  332. break;
  333. case 'l':
  334. mvars->list = 1;
  335. break;
  336. case 'c':
  337. if (*ochar == 'T') {
  338. ochar++;
  339. pseudo = 1;
  340. }
  341. if (mvars->oind >= argc) {
  342. error( "-c requires an argument.\n" );
  343. return 1;
  344. }
  345. config = argv[mvars->oind++];
  346. break;
  347. case 'C':
  348. op = OP_CREATE|XOP_HAVE_CREATE;
  349. cop:
  350. if (*ochar == 'm')
  351. mvars->ops[M] |= op, ochar++;
  352. else if (*ochar == 's')
  353. mvars->ops[S] |= op, ochar++;
  354. else if (*ochar == '-')
  355. ochar++;
  356. else
  357. cops |= op;
  358. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  359. break;
  360. case 'X':
  361. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  362. goto cop;
  363. case 'F':
  364. cops |= XOP_PULL|XOP_PUSH;
  365. case '0':
  366. mvars->ops[M] |= XOP_HAVE_TYPE;
  367. break;
  368. case 'n':
  369. case 'd':
  370. case 'f':
  371. case 'N':
  372. --ochar;
  373. op = 0;
  374. cac:
  375. for (;; ochar++) {
  376. if (*ochar == 'n')
  377. op |= OP_NEW;
  378. else if (*ochar == 'd')
  379. op |= OP_DELETE;
  380. else if (*ochar == 'f')
  381. op |= OP_FLAGS;
  382. else if (*ochar == 'N')
  383. op |= OP_RENEW;
  384. else
  385. break;
  386. }
  387. if (op & OP_MASK_TYPE)
  388. switch (op & XOP_MASK_DIR) {
  389. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  390. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  391. default: cops |= op; break;
  392. }
  393. else
  394. cops |= op;
  395. mvars->ops[M] |= XOP_HAVE_TYPE;
  396. break;
  397. case 'L':
  398. op = XOP_PULL;
  399. goto cac;
  400. case 'H':
  401. op = XOP_PUSH;
  402. goto cac;
  403. case 'q':
  404. if (DFlags & QUIET)
  405. DFlags |= VERYQUIET;
  406. else
  407. DFlags |= QUIET;
  408. break;
  409. case 'V':
  410. if (DFlags & VERBOSE)
  411. DFlags |= XVERBOSE;
  412. else
  413. DFlags |= VERBOSE | QUIET;
  414. break;
  415. case 'D':
  416. DFlags |= DEBUG | QUIET;
  417. break;
  418. case 'J':
  419. DFlags |= KEEPJOURNAL;
  420. break;
  421. case 'Z':
  422. DFlags |= ZERODELAY;
  423. break;
  424. case 'v':
  425. version();
  426. case 'h':
  427. usage( 0 );
  428. default:
  429. error( "Unknown option '-%c'\n", *(ochar - 1) );
  430. return 1;
  431. }
  432. }
  433. #ifdef __linux__
  434. if (DFlags & DEBUG) {
  435. signal( SIGSEGV, crashHandler );
  436. signal( SIGBUS, crashHandler );
  437. signal( SIGILL, crashHandler );
  438. }
  439. #endif
  440. if (merge_ops( cops, mvars->ops ))
  441. return 1;
  442. if (load_config( config, pseudo ))
  443. return 1;
  444. if (!mvars->all && !argv[mvars->oind]) {
  445. fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
  446. return 1;
  447. }
  448. if (!channels) {
  449. fputs( "No channels defined. Try 'man " EXE "'\n", stderr );
  450. return 1;
  451. }
  452. mvars->chan = channels;
  453. if (mvars->all)
  454. mvars->multiple = channels->next != 0;
  455. else if (argv[mvars->oind + 1])
  456. mvars->multiple = 1;
  457. else
  458. for (group = groups; group; group = group->next)
  459. if (!strcmp( group->name, argv[mvars->oind] )) {
  460. mvars->multiple = 1;
  461. break;
  462. }
  463. mvars->argv = argv;
  464. mvars->cben = 1;
  465. sync_chans( mvars, E_START );
  466. main_loop();
  467. return mvars->ret;
  468. }
  469. #define ST_FRESH 0
  470. #define ST_OPEN 1
  471. #define ST_CLOSED 2
  472. static void store_opened( store_t *ctx, void *aux );
  473. static void store_listed( int sts, void *aux );
  474. static void done_sync_dyn( int sts, void *aux );
  475. static void done_sync( int sts, void *aux );
  476. #define nz(a,b) ((a)?(a):(b))
  477. static void
  478. sync_chans( main_vars_t *mvars, int ent )
  479. {
  480. group_conf_t *group;
  481. channel_conf_t *chan;
  482. store_t *store;
  483. string_list_t *mbox, *sbox, **mboxp, **sboxp;
  484. char *channame;
  485. int t;
  486. if (!mvars->cben)
  487. return;
  488. switch (ent) {
  489. case E_OPEN: goto opened;
  490. case E_SYNC: goto syncone;
  491. }
  492. for (;;) {
  493. mvars->boxlist = 0;
  494. if (!mvars->all) {
  495. if (mvars->chanptr)
  496. channame = mvars->chanptr->string;
  497. else {
  498. for (group = groups; group; group = group->next)
  499. if (!strcmp( group->name, mvars->argv[mvars->oind] )) {
  500. mvars->chanptr = group->channels;
  501. channame = mvars->chanptr->string;
  502. goto gotgrp;
  503. }
  504. channame = mvars->argv[mvars->oind];
  505. gotgrp: ;
  506. }
  507. if ((mvars->boxlist = strchr( channame, ':' )))
  508. *mvars->boxlist++ = 0;
  509. for (chan = channels; chan; chan = chan->next)
  510. if (!strcmp( chan->name, channame ))
  511. goto gotchan;
  512. error( "No channel or group named '%s' defined.\n", channame );
  513. mvars->ret = 1;
  514. goto gotnone;
  515. gotchan:
  516. mvars->chan = chan;
  517. }
  518. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
  519. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
  520. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
  521. mvars->state[M] = mvars->state[S] = ST_FRESH;
  522. info( "Channel %s\n", mvars->chan->name );
  523. mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
  524. mvars->skip = mvars->cben = 0;
  525. for (t = 0; t < 2; t++) {
  526. mvars->drv[t] = mvars->chan->stores[t]->driver;
  527. if ((store = mvars->drv[t]->own_store( mvars->chan->stores[t] )))
  528. store_opened( store, AUX );
  529. }
  530. for (t = 0; t < 2 && !mvars->skip; t++)
  531. if (mvars->state[t] == ST_FRESH) {
  532. info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name );
  533. mvars->drv[t]->open_store( mvars->chan->stores[t], store_opened, AUX );
  534. }
  535. mvars->cben = 1;
  536. opened:
  537. if (mvars->skip)
  538. goto next;
  539. if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN)
  540. return;
  541. if (mvars->boxlist)
  542. mvars->boxp = mvars->boxlist;
  543. else if (mvars->chan->patterns) {
  544. mvars->boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->patterns );
  545. mvars->boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->patterns );
  546. for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
  547. for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
  548. if (!strcmp( sbox->string, mbox->string )) {
  549. *sboxp = sbox->next;
  550. free( sbox );
  551. *mboxp = mbox->next;
  552. mbox->next = mvars->cboxes;
  553. mvars->cboxes = mbox;
  554. goto gotdupe;
  555. }
  556. mboxp = &mbox->next;
  557. gotdupe: ;
  558. }
  559. }
  560. if (mvars->list && mvars->multiple)
  561. printf( "%s:\n", mvars->chan->name );
  562. syncml:
  563. mvars->done = mvars->cben = 0;
  564. syncmlx:
  565. if (mvars->boxlist) {
  566. if ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
  567. if (!*mvars->names[S])
  568. mvars->names[S] = 0;
  569. if (!mvars->list) {
  570. mvars->names[M] = mvars->names[S];
  571. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync, mvars );
  572. goto syncw;
  573. }
  574. puts( nz( mvars->names[S], "INBOX" ) );
  575. goto syncmlx;
  576. }
  577. } else if (mvars->chan->patterns) {
  578. if ((mbox = mvars->cboxes)) {
  579. mvars->cboxes = mbox->next;
  580. if (!mvars->list) {
  581. mvars->names[M] = mvars->names[S] = mbox->string;
  582. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  583. goto syncw;
  584. }
  585. puts( mbox->string );
  586. free( mbox );
  587. goto syncmlx;
  588. }
  589. for (t = 0; t < 2; t++)
  590. if ((mbox = mvars->boxes[t])) {
  591. mvars->boxes[t] = mbox->next;
  592. if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
  593. if (!mvars->list) {
  594. mvars->names[M] = mvars->names[S] = mbox->string;
  595. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  596. goto syncw;
  597. }
  598. puts( mbox->string );
  599. }
  600. free( mbox );
  601. goto syncmlx;
  602. }
  603. } else {
  604. if (!mvars->list) {
  605. sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan, done_sync, mvars );
  606. mvars->skip = 1;
  607. syncw:
  608. mvars->cben = 1;
  609. if (!mvars->done)
  610. return;
  611. syncone:
  612. if (!mvars->skip)
  613. goto syncml;
  614. } else
  615. printf( "%s <=> %s\n", nz( mvars->chan->boxes[M], "INBOX" ), nz( mvars->chan->boxes[S], "INBOX" ) );
  616. }
  617. next:
  618. for (t = 0; t < 2; t++)
  619. if (mvars->state[t] == ST_OPEN) {
  620. mvars->drv[t]->disown_store( mvars->ctx[t] );
  621. mvars->state[t] = ST_CLOSED;
  622. }
  623. if (mvars->state[M] != ST_CLOSED || mvars->state[S] != ST_CLOSED) {
  624. mvars->skip = mvars->cben = 1;
  625. return;
  626. }
  627. free_string_list( mvars->cboxes );
  628. free_string_list( mvars->boxes[M] );
  629. free_string_list( mvars->boxes[S] );
  630. if (mvars->all) {
  631. if (!(mvars->chan = mvars->chan->next))
  632. break;
  633. } else {
  634. if (mvars->chanptr && (mvars->chanptr = mvars->chanptr->next))
  635. continue;
  636. gotnone:
  637. if (!mvars->argv[++mvars->oind])
  638. break;
  639. }
  640. }
  641. for (t = 0; t < N_DRIVERS; t++)
  642. drivers[t]->cleanup();
  643. }
  644. static void
  645. store_bad( void *aux )
  646. {
  647. MVARS(aux)
  648. mvars->drv[t]->cancel_store( mvars->ctx[t] );
  649. mvars->ret = mvars->skip = 1;
  650. mvars->state[t] = ST_CLOSED;
  651. sync_chans( mvars, E_OPEN );
  652. }
  653. static void
  654. store_opened( store_t *ctx, void *aux )
  655. {
  656. MVARS(aux)
  657. string_list_t *cpat;
  658. int flags;
  659. if (!ctx) {
  660. mvars->ret = mvars->skip = 1;
  661. mvars->state[t] = ST_CLOSED;
  662. sync_chans( mvars, E_OPEN );
  663. return;
  664. }
  665. mvars->ctx[t] = ctx;
  666. if (!mvars->skip && !mvars->boxlist && mvars->chan->patterns && !ctx->listed) {
  667. for (flags = 0, cpat = mvars->chan->patterns; cpat; cpat = cpat->next) {
  668. const char *pat = cpat->string;
  669. if (*pat != '!')
  670. flags |= (!memcmp( pat, "INBOX", 5 ) && (!pat[5] || pat[5] == '/')) ? LIST_INBOX : LIST_PATH;
  671. }
  672. set_bad_callback( ctx, store_bad, AUX );
  673. mvars->drv[t]->list( ctx, flags, store_listed, AUX );
  674. } else {
  675. mvars->state[t] = ST_OPEN;
  676. sync_chans( mvars, E_OPEN );
  677. }
  678. }
  679. static void
  680. store_listed( int sts, void *aux )
  681. {
  682. MVARS(aux)
  683. string_list_t *box;
  684. switch (sts) {
  685. case DRV_CANCELED:
  686. return;
  687. case DRV_OK:
  688. mvars->ctx[t]->listed = 1;
  689. if (mvars->ctx[t]->conf->flat_delim) {
  690. for (box = mvars->ctx[t]->boxes; box; box = box->next) {
  691. if (map_name( box->string, mvars->ctx[t]->conf->flat_delim, '/' ) < 0) {
  692. error( "Error: flattened mailbox name '%s' contains canonical hierarchy delimiter\n", box->string );
  693. mvars->ret = mvars->skip = 1;
  694. }
  695. }
  696. }
  697. if (mvars->ctx[t]->conf->map_inbox)
  698. add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
  699. break;
  700. default:
  701. mvars->ret = mvars->skip = 1;
  702. break;
  703. }
  704. mvars->state[t] = ST_OPEN;
  705. sync_chans( mvars, E_OPEN );
  706. }
  707. static void
  708. done_sync_dyn( int sts, void *aux )
  709. {
  710. main_vars_t *mvars = (main_vars_t *)aux;
  711. free( ((char *)mvars->names[S]) - offsetof(string_list_t, string) );
  712. done_sync( sts, aux );
  713. }
  714. static void
  715. done_sync( int sts, void *aux )
  716. {
  717. main_vars_t *mvars = (main_vars_t *)aux;
  718. mvars->done = 1;
  719. if (sts) {
  720. mvars->ret = 1;
  721. if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) {
  722. if (sts & SYNC_BAD(M))
  723. mvars->state[M] = ST_CLOSED;
  724. if (sts & SYNC_BAD(S))
  725. mvars->state[S] = ST_CLOSED;
  726. mvars->skip = 1;
  727. } else if (sts & SYNC_FAIL_ALL) {
  728. mvars->skip = 1;
  729. }
  730. }
  731. sync_chans( mvars, E_SYNC );
  732. }