main.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  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. #if 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 == '.' || *t == '/') /* this is "somewhat" hacky ... */
  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. Ontty = isatty( 1 ) && isatty( 2 );
  215. arc4_init();
  216. memset( mvars, 0, sizeof(*mvars) );
  217. mvars->t[1] = 1;
  218. for (mvars->oind = 1, ochar = 0; mvars->oind < argc; ) {
  219. if (!ochar || !*ochar) {
  220. if (argv[mvars->oind][0] != '-')
  221. break;
  222. if (argv[mvars->oind][1] == '-') {
  223. opt = argv[mvars->oind++] + 2;
  224. if (!*opt)
  225. break;
  226. if (!strcmp( opt, "config" )) {
  227. if (mvars->oind >= argc) {
  228. error( "--config requires an argument.\n" );
  229. return 1;
  230. }
  231. config = argv[mvars->oind++];
  232. } else if (!memcmp( opt, "config=", 7 ))
  233. config = opt + 7;
  234. else if (!strcmp( opt, "all" ))
  235. mvars->all = 1;
  236. else if (!strcmp( opt, "list" ))
  237. mvars->list = 1;
  238. else if (!strcmp( opt, "help" ))
  239. usage( 0 );
  240. else if (!strcmp( opt, "version" ))
  241. version();
  242. else if (!strcmp( opt, "quiet" )) {
  243. if (DFlags & QUIET)
  244. DFlags |= VERYQUIET;
  245. else
  246. DFlags |= QUIET;
  247. } else if (!strcmp( opt, "verbose" ))
  248. DFlags |= VERBOSE | QUIET;
  249. else if (!strcmp( opt, "debug" ))
  250. DFlags |= DEBUG | QUIET;
  251. else if (!strcmp( opt, "pull" ))
  252. cops |= XOP_PULL, mvars->ops[M] |= XOP_HAVE_TYPE;
  253. else if (!strcmp( opt, "push" ))
  254. cops |= XOP_PUSH, mvars->ops[M] |= XOP_HAVE_TYPE;
  255. else if (!memcmp( opt, "create", 6 )) {
  256. opt += 6;
  257. op = OP_CREATE|XOP_HAVE_CREATE;
  258. lcop:
  259. if (!*opt)
  260. cops |= op;
  261. else if (!strcmp( opt, "-master" ))
  262. mvars->ops[M] |= op, ochar++;
  263. else if (!strcmp( opt, "-slave" ))
  264. mvars->ops[S] |= op, ochar++;
  265. else
  266. goto badopt;
  267. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  268. } else if (!memcmp( opt, "expunge", 7 )) {
  269. opt += 7;
  270. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  271. goto lcop;
  272. } else if (!strcmp( opt, "no-expunge" ))
  273. mvars->ops[M] |= XOP_HAVE_EXPUNGE;
  274. else if (!strcmp( opt, "no-create" ))
  275. mvars->ops[M] |= XOP_HAVE_CREATE;
  276. else if (!strcmp( opt, "full" ))
  277. mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
  278. else if (!strcmp( opt, "noop" ))
  279. mvars->ops[M] |= XOP_HAVE_TYPE;
  280. else if (!memcmp( opt, "pull", 4 )) {
  281. op = XOP_PULL;
  282. lcac:
  283. opt += 4;
  284. if (!*opt)
  285. cops |= op;
  286. else if (*opt == '-') {
  287. opt++;
  288. goto rlcac;
  289. } else
  290. goto badopt;
  291. } else if (!memcmp( opt, "push", 4 )) {
  292. op = XOP_PUSH;
  293. goto lcac;
  294. } else {
  295. op = 0;
  296. rlcac:
  297. if (!strcmp( opt, "new" ))
  298. op |= OP_NEW;
  299. else if (!strcmp( opt, "renew" ))
  300. op |= OP_RENEW;
  301. else if (!strcmp( opt, "delete" ))
  302. op |= OP_DELETE;
  303. else if (!strcmp( opt, "flags" ))
  304. op |= OP_FLAGS;
  305. else {
  306. badopt:
  307. error( "Unknown option '%s'\n", argv[mvars->oind - 1] );
  308. return 1;
  309. }
  310. switch (op & XOP_MASK_DIR) {
  311. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  312. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  313. default: cops |= op; break;
  314. }
  315. mvars->ops[M] |= XOP_HAVE_TYPE;
  316. }
  317. continue;
  318. }
  319. ochar = argv[mvars->oind++] + 1;
  320. if (!*ochar) {
  321. error( "Invalid option '-'\n" );
  322. return 1;
  323. }
  324. }
  325. switch (*ochar++) {
  326. case 'a':
  327. mvars->all = 1;
  328. break;
  329. case 'l':
  330. mvars->list = 1;
  331. break;
  332. case 'c':
  333. if (*ochar == 'T') {
  334. ochar++;
  335. pseudo = 1;
  336. }
  337. if (mvars->oind >= argc) {
  338. error( "-c requires an argument.\n" );
  339. return 1;
  340. }
  341. config = argv[mvars->oind++];
  342. break;
  343. case 'C':
  344. op = OP_CREATE|XOP_HAVE_CREATE;
  345. cop:
  346. if (*ochar == 'm')
  347. mvars->ops[M] |= op, ochar++;
  348. else if (*ochar == 's')
  349. mvars->ops[S] |= op, ochar++;
  350. else if (*ochar == '-')
  351. ochar++;
  352. else
  353. cops |= op;
  354. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  355. break;
  356. case 'X':
  357. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  358. goto cop;
  359. case 'F':
  360. cops |= XOP_PULL|XOP_PUSH;
  361. case '0':
  362. mvars->ops[M] |= XOP_HAVE_TYPE;
  363. break;
  364. case 'n':
  365. case 'd':
  366. case 'f':
  367. case 'N':
  368. --ochar;
  369. op = 0;
  370. cac:
  371. for (;; ochar++) {
  372. if (*ochar == 'n')
  373. op |= OP_NEW;
  374. else if (*ochar == 'd')
  375. op |= OP_DELETE;
  376. else if (*ochar == 'f')
  377. op |= OP_FLAGS;
  378. else if (*ochar == 'N')
  379. op |= OP_RENEW;
  380. else
  381. break;
  382. }
  383. if (op & OP_MASK_TYPE)
  384. switch (op & XOP_MASK_DIR) {
  385. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  386. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  387. default: cops |= op; break;
  388. }
  389. else
  390. cops |= op;
  391. mvars->ops[M] |= XOP_HAVE_TYPE;
  392. break;
  393. case 'L':
  394. op = XOP_PULL;
  395. goto cac;
  396. case 'H':
  397. op = XOP_PUSH;
  398. goto cac;
  399. case 'q':
  400. if (DFlags & QUIET)
  401. DFlags |= VERYQUIET;
  402. else
  403. DFlags |= QUIET;
  404. break;
  405. case 'V':
  406. DFlags |= VERBOSE | QUIET;
  407. break;
  408. case 'D':
  409. DFlags |= DEBUG | QUIET;
  410. break;
  411. case 'J':
  412. DFlags |= KEEPJOURNAL;
  413. break;
  414. case 'v':
  415. version();
  416. case 'h':
  417. usage( 0 );
  418. default:
  419. error( "Unknown option '-%c'\n", *(ochar - 1) );
  420. return 1;
  421. }
  422. }
  423. #ifdef __linux__
  424. if (DFlags & DEBUG) {
  425. signal( SIGSEGV, crashHandler );
  426. signal( SIGBUS, crashHandler );
  427. signal( SIGILL, crashHandler );
  428. }
  429. #endif
  430. if (merge_ops( cops, mvars->ops ))
  431. return 1;
  432. if (load_config( config, pseudo ))
  433. return 1;
  434. if (!mvars->all && !argv[mvars->oind]) {
  435. fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
  436. return 1;
  437. }
  438. if (!channels) {
  439. fputs( "No channels defined. Try 'man " EXE "'\n", stderr );
  440. return 1;
  441. }
  442. mvars->chan = channels;
  443. if (mvars->all)
  444. mvars->multiple = channels->next != 0;
  445. else if (argv[mvars->oind + 1])
  446. mvars->multiple = 1;
  447. else
  448. for (group = groups; group; group = group->next)
  449. if (!strcmp( group->name, argv[mvars->oind] )) {
  450. mvars->multiple = 1;
  451. break;
  452. }
  453. mvars->argv = argv;
  454. mvars->cben = 1;
  455. sync_chans( mvars, E_START );
  456. return mvars->ret;
  457. }
  458. #define ST_FRESH 0
  459. #define ST_OPEN 1
  460. #define ST_CLOSED 2
  461. static void store_opened( store_t *ctx, void *aux );
  462. static void store_listed( int sts, void *aux );
  463. static void done_sync_dyn( int sts, void *aux );
  464. static void done_sync( int sts, void *aux );
  465. #define nz(a,b) ((a)?(a):(b))
  466. static void
  467. sync_chans( main_vars_t *mvars, int ent )
  468. {
  469. group_conf_t *group;
  470. channel_conf_t *chan;
  471. store_t *store;
  472. string_list_t *mbox, *sbox, **mboxp, **sboxp;
  473. char *channame;
  474. int t;
  475. if (!mvars->cben)
  476. return;
  477. switch (ent) {
  478. case E_OPEN: goto opened;
  479. case E_SYNC: goto syncone;
  480. }
  481. for (;;) {
  482. mvars->boxlist = 0;
  483. if (!mvars->all) {
  484. if (mvars->chanptr)
  485. channame = mvars->chanptr->string;
  486. else {
  487. for (group = groups; group; group = group->next)
  488. if (!strcmp( group->name, mvars->argv[mvars->oind] )) {
  489. mvars->chanptr = group->channels;
  490. channame = mvars->chanptr->string;
  491. goto gotgrp;
  492. }
  493. channame = mvars->argv[mvars->oind];
  494. gotgrp: ;
  495. }
  496. if ((mvars->boxlist = strchr( channame, ':' )))
  497. *mvars->boxlist++ = 0;
  498. for (chan = channels; chan; chan = chan->next)
  499. if (!strcmp( chan->name, channame ))
  500. goto gotchan;
  501. error( "No channel or group named '%s' defined.\n", channame );
  502. mvars->ret = 1;
  503. goto gotnone;
  504. gotchan:
  505. mvars->chan = chan;
  506. }
  507. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
  508. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
  509. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
  510. mvars->state[M] = mvars->state[S] = ST_FRESH;
  511. info( "Channel %s\n", mvars->chan->name );
  512. mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
  513. mvars->skip = mvars->cben = 0;
  514. for (t = 0; t < 2; t++) {
  515. mvars->drv[t] = mvars->chan->stores[t]->driver;
  516. if ((store = mvars->drv[t]->own_store( mvars->chan->stores[t] )))
  517. store_opened( store, AUX );
  518. }
  519. for (t = 0; t < 2 && !mvars->skip; t++)
  520. if (mvars->state[t] == ST_FRESH) {
  521. info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name );
  522. mvars->drv[t]->open_store( mvars->chan->stores[t], store_opened, AUX );
  523. }
  524. mvars->cben = 1;
  525. opened:
  526. if (mvars->skip)
  527. goto next;
  528. if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN)
  529. return;
  530. if (mvars->boxlist)
  531. mvars->boxp = mvars->boxlist;
  532. else if (mvars->chan->patterns) {
  533. mvars->boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->patterns );
  534. mvars->boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->patterns );
  535. for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
  536. for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
  537. if (!strcmp( sbox->string, mbox->string )) {
  538. *sboxp = sbox->next;
  539. free( sbox );
  540. *mboxp = mbox->next;
  541. mbox->next = mvars->cboxes;
  542. mvars->cboxes = mbox;
  543. goto gotdupe;
  544. }
  545. mboxp = &mbox->next;
  546. gotdupe: ;
  547. }
  548. }
  549. if (mvars->list && mvars->multiple)
  550. printf( "%s:\n", mvars->chan->name );
  551. syncml:
  552. mvars->done = mvars->cben = 0;
  553. syncmlx:
  554. if (mvars->boxlist) {
  555. if ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
  556. if (!*mvars->names[S])
  557. mvars->names[S] = 0;
  558. if (!mvars->list) {
  559. mvars->names[M] = mvars->names[S];
  560. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync, mvars );
  561. goto syncw;
  562. }
  563. puts( nz( mvars->names[S], "INBOX" ) );
  564. goto syncmlx;
  565. }
  566. } else if (mvars->chan->patterns) {
  567. if ((mbox = mvars->cboxes)) {
  568. mvars->cboxes = mbox->next;
  569. if (!mvars->list) {
  570. mvars->names[M] = mvars->names[S] = mbox->string;
  571. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  572. goto syncw;
  573. }
  574. puts( mbox->string );
  575. free( mbox );
  576. goto syncmlx;
  577. }
  578. for (t = 0; t < 2; t++)
  579. if ((mbox = mvars->boxes[t])) {
  580. mvars->boxes[t] = mbox->next;
  581. if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
  582. if (!mvars->list) {
  583. mvars->names[M] = mvars->names[S] = mbox->string;
  584. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  585. goto syncw;
  586. }
  587. puts( mbox->string );
  588. }
  589. free( mbox );
  590. goto syncmlx;
  591. }
  592. } else {
  593. if (!mvars->list) {
  594. sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan, done_sync, mvars );
  595. mvars->skip = 1;
  596. syncw:
  597. mvars->cben = 1;
  598. if (!mvars->done)
  599. return;
  600. syncone:
  601. if (!mvars->skip)
  602. goto syncml;
  603. } else
  604. printf( "%s <=> %s\n", nz( mvars->chan->boxes[M], "INBOX" ), nz( mvars->chan->boxes[S], "INBOX" ) );
  605. }
  606. next:
  607. for (t = 0; t < 2; t++)
  608. if (mvars->state[t] == ST_OPEN) {
  609. mvars->drv[t]->disown_store( mvars->ctx[t] );
  610. mvars->state[t] = ST_CLOSED;
  611. }
  612. if (mvars->state[M] != ST_CLOSED || mvars->state[S] != ST_CLOSED) {
  613. mvars->skip = mvars->cben = 1;
  614. return;
  615. }
  616. free_string_list( mvars->cboxes );
  617. free_string_list( mvars->boxes[M] );
  618. free_string_list( mvars->boxes[S] );
  619. if (mvars->all) {
  620. if (!(mvars->chan = mvars->chan->next))
  621. break;
  622. } else {
  623. if (mvars->chanptr && (mvars->chanptr = mvars->chanptr->next))
  624. continue;
  625. gotnone:
  626. if (!mvars->argv[++mvars->oind])
  627. break;
  628. }
  629. }
  630. for (t = 0; t < N_DRIVERS; t++)
  631. drivers[t]->cleanup();
  632. }
  633. static void
  634. store_opened( store_t *ctx, void *aux )
  635. {
  636. MVARS(aux)
  637. if (!ctx) {
  638. mvars->state[t] = ST_CLOSED;
  639. mvars->ret = mvars->skip = 1;
  640. return;
  641. }
  642. mvars->ctx[t] = ctx;
  643. if (mvars->skip) {
  644. mvars->state[t] = ST_OPEN;
  645. sync_chans( mvars, E_OPEN );
  646. return;
  647. }
  648. if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed)
  649. mvars->drv[t]->list( ctx, store_listed, AUX );
  650. else {
  651. mvars->state[t] = ST_OPEN;
  652. sync_chans( mvars, E_OPEN );
  653. }
  654. }
  655. static void
  656. store_listed( int sts, void *aux )
  657. {
  658. MVARS(aux)
  659. mvars->state[t] = ST_OPEN;
  660. switch (sts) {
  661. case DRV_OK:
  662. if (mvars->ctx[t]->conf->map_inbox)
  663. add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
  664. break;
  665. case DRV_STORE_BAD:
  666. mvars->drv[t]->cancel_store( mvars->ctx[t] );
  667. mvars->state[t] = ST_CLOSED;
  668. default:
  669. mvars->ret = mvars->skip = 1;
  670. break;
  671. }
  672. sync_chans( mvars, E_OPEN );
  673. }
  674. static void
  675. done_sync_dyn( int sts, void *aux )
  676. {
  677. main_vars_t *mvars = (main_vars_t *)aux;
  678. free( ((char *)mvars->names[S]) - offsetof(string_list_t, string) );
  679. done_sync( sts, aux );
  680. }
  681. static void
  682. done_sync( int sts, void *aux )
  683. {
  684. main_vars_t *mvars = (main_vars_t *)aux;
  685. mvars->done = 1;
  686. if (sts) {
  687. mvars->ret = 1;
  688. if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) {
  689. mvars->skip = 1;
  690. if (sts & SYNC_BAD(M))
  691. mvars->state[M] = ST_CLOSED;
  692. if (sts & SYNC_BAD(S))
  693. mvars->state[S] = ST_CLOSED;
  694. }
  695. }
  696. sync_chans( mvars, E_SYNC );
  697. }