main.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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. static void
  81. crashHandler( int n )
  82. {
  83. int dpid;
  84. char pbuf[10], pabuf[20];
  85. close( 0 );
  86. open( "/dev/tty", O_RDWR );
  87. dup2( 0, 1 );
  88. dup2( 0, 2 );
  89. error( "*** " EXE " caught signal %d. Starting debugger ...\n", n );
  90. switch ((dpid = fork ())) {
  91. case -1:
  92. perror( "fork()" );
  93. break;
  94. case 0:
  95. sprintf( pbuf, "%d", Pid );
  96. sprintf( pabuf, "/proc/%d/exe", Pid );
  97. execlp( "gdb", "gdb", pabuf, pbuf, (char *)0 );
  98. perror( "execlp()" );
  99. _exit( 1 );
  100. default:
  101. waitpid( dpid, 0, 0 );
  102. break;
  103. }
  104. exit( 3 );
  105. }
  106. static int
  107. matches( const char *t, const char *p )
  108. {
  109. for (;;) {
  110. if (!*p)
  111. return !*t;
  112. if (*p == '*') {
  113. p++;
  114. do {
  115. if (matches( t, p ))
  116. return 1;
  117. } while (*t++);
  118. return 0;
  119. } else if (*p == '%') {
  120. p++;
  121. do {
  122. if (*t == '.' || *t == '/') /* this is "somewhat" hacky ... */
  123. return 0;
  124. if (matches( t, p ))
  125. return 1;
  126. } while (*t++);
  127. return 0;
  128. } else {
  129. if (*p != *t)
  130. return 0;
  131. p++, t++;
  132. }
  133. }
  134. }
  135. static string_list_t *
  136. filter_boxes( string_list_t *boxes, string_list_t *patterns )
  137. {
  138. string_list_t *nboxes = 0, *cpat;
  139. const char *ps;
  140. int not, fnot;
  141. for (; boxes; boxes = boxes->next) {
  142. fnot = 1;
  143. for (cpat = patterns; cpat; cpat = cpat->next) {
  144. ps = cpat->string;
  145. if (*ps == '!') {
  146. ps++;
  147. not = 1;
  148. } else
  149. not = 0;
  150. if (matches( boxes->string, ps )) {
  151. fnot = not;
  152. break;
  153. }
  154. }
  155. if (!fnot)
  156. add_string_list( &nboxes, boxes->string );
  157. }
  158. return nboxes;
  159. }
  160. static void
  161. merge_actions( channel_conf_t *chan, int ops[], int have, int mask, int def )
  162. {
  163. if (ops[M] & have) {
  164. chan->ops[M] &= ~mask;
  165. chan->ops[M] |= ops[M] & mask;
  166. chan->ops[S] &= ~mask;
  167. chan->ops[S] |= ops[S] & mask;
  168. } else if (!(chan->ops[M] & have)) {
  169. if (global_ops[M] & have) {
  170. chan->ops[M] |= global_ops[M] & mask;
  171. chan->ops[S] |= global_ops[S] & mask;
  172. } else {
  173. chan->ops[M] |= def;
  174. chan->ops[S] |= def;
  175. }
  176. }
  177. }
  178. typedef struct {
  179. int t[2];
  180. channel_conf_t *chan;
  181. driver_t *drv[2];
  182. store_t *ctx[2];
  183. string_list_t *boxes[2], *cboxes, *chanptr;
  184. const char *names[2];
  185. char **argv, *boxlist, *boxp;
  186. int oind, ret, multiple, all, list, ops[2], state[2];
  187. unsigned done:1, skip:1, cben:1;
  188. } main_vars_t;
  189. #define AUX &mvars->t[t]
  190. #define MVARS(aux) \
  191. int t = *(int *)aux; \
  192. main_vars_t *mvars = (main_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(main_vars_t, t));
  193. #define E_START 0
  194. #define E_OPEN 1
  195. #define E_SYNC 2
  196. static void sync_chans( main_vars_t *mvars, int ent );
  197. int
  198. main( int argc, char **argv )
  199. {
  200. main_vars_t mvars[1];
  201. group_conf_t *group;
  202. char *config = 0, *opt, *ochar;
  203. int cops = 0, op, pseudo = 0;
  204. gethostname( Hostname, sizeof(Hostname) );
  205. if ((ochar = strchr( Hostname, '.' )))
  206. *ochar = 0;
  207. Pid = getpid();
  208. if (!(Home = getenv("HOME"))) {
  209. fputs( "Fatal: $HOME not set\n", stderr );
  210. return 1;
  211. }
  212. Ontty = isatty( 1 ) && isatty( 2 );
  213. arc4_init();
  214. memset( mvars, 0, sizeof(*mvars) );
  215. for (mvars->oind = 1, ochar = 0; mvars->oind < argc; ) {
  216. if (!ochar || !*ochar) {
  217. if (argv[mvars->oind][0] != '-')
  218. break;
  219. if (argv[mvars->oind][1] == '-') {
  220. opt = argv[mvars->oind++] + 2;
  221. if (!*opt)
  222. break;
  223. if (!strcmp( opt, "config" )) {
  224. if (mvars->oind >= argc) {
  225. error( "--config requires an argument.\n" );
  226. return 1;
  227. }
  228. config = argv[mvars->oind++];
  229. } else if (!memcmp( opt, "config=", 7 ))
  230. config = opt + 7;
  231. else if (!strcmp( opt, "all" ))
  232. mvars->all = 1;
  233. else if (!strcmp( opt, "list" ))
  234. mvars->list = 1;
  235. else if (!strcmp( opt, "help" ))
  236. usage( 0 );
  237. else if (!strcmp( opt, "version" ))
  238. version();
  239. else if (!strcmp( opt, "quiet" )) {
  240. if (DFlags & QUIET)
  241. DFlags |= VERYQUIET;
  242. else
  243. DFlags |= QUIET;
  244. } else if (!strcmp( opt, "verbose" ))
  245. DFlags |= VERBOSE | QUIET;
  246. else if (!strcmp( opt, "debug" ))
  247. DFlags |= DEBUG | QUIET;
  248. else if (!strcmp( opt, "pull" ))
  249. cops |= XOP_PULL, mvars->ops[M] |= XOP_HAVE_TYPE;
  250. else if (!strcmp( opt, "push" ))
  251. cops |= XOP_PUSH, mvars->ops[M] |= XOP_HAVE_TYPE;
  252. else if (!memcmp( opt, "create", 6 )) {
  253. opt += 6;
  254. op = OP_CREATE|XOP_HAVE_CREATE;
  255. lcop:
  256. if (!*opt)
  257. cops |= op;
  258. else if (!strcmp( opt, "-master" ))
  259. mvars->ops[M] |= op, ochar++;
  260. else if (!strcmp( opt, "-slave" ))
  261. mvars->ops[S] |= op, ochar++;
  262. else
  263. goto badopt;
  264. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  265. } else if (!memcmp( opt, "expunge", 7 )) {
  266. opt += 7;
  267. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  268. goto lcop;
  269. } else if (!strcmp( opt, "no-expunge" ))
  270. mvars->ops[M] |= XOP_HAVE_EXPUNGE;
  271. else if (!strcmp( opt, "no-create" ))
  272. mvars->ops[M] |= XOP_HAVE_CREATE;
  273. else if (!strcmp( opt, "full" ))
  274. mvars->ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
  275. else if (!strcmp( opt, "noop" ))
  276. mvars->ops[M] |= XOP_HAVE_TYPE;
  277. else if (!memcmp( opt, "pull", 4 )) {
  278. op = XOP_PULL;
  279. lcac:
  280. opt += 4;
  281. if (!*opt)
  282. cops |= op;
  283. else if (*opt == '-') {
  284. opt++;
  285. goto rlcac;
  286. } else
  287. goto badopt;
  288. } else if (!memcmp( opt, "push", 4 )) {
  289. op = XOP_PUSH;
  290. goto lcac;
  291. } else {
  292. op = 0;
  293. rlcac:
  294. if (!strcmp( opt, "new" ))
  295. op |= OP_NEW;
  296. else if (!strcmp( opt, "renew" ))
  297. op |= OP_RENEW;
  298. else if (!strcmp( opt, "delete" ))
  299. op |= OP_DELETE;
  300. else if (!strcmp( opt, "flags" ))
  301. op |= OP_FLAGS;
  302. else {
  303. badopt:
  304. error( "Unknown option '%s'\n", argv[mvars->oind - 1] );
  305. return 1;
  306. }
  307. switch (op & XOP_MASK_DIR) {
  308. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  309. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  310. default: cops |= op; break;
  311. }
  312. mvars->ops[M] |= XOP_HAVE_TYPE;
  313. }
  314. continue;
  315. }
  316. ochar = argv[mvars->oind++] + 1;
  317. if (!*ochar) {
  318. error( "Invalid option '-'\n" );
  319. return 1;
  320. }
  321. }
  322. switch (*ochar++) {
  323. case 'a':
  324. mvars->all = 1;
  325. break;
  326. case 'l':
  327. mvars->list = 1;
  328. break;
  329. case 'c':
  330. if (*ochar == 'T') {
  331. ochar++;
  332. pseudo = 1;
  333. }
  334. if (mvars->oind >= argc) {
  335. error( "-c requires an argument.\n" );
  336. return 1;
  337. }
  338. config = argv[mvars->oind++];
  339. break;
  340. case 'C':
  341. op = OP_CREATE|XOP_HAVE_CREATE;
  342. cop:
  343. if (*ochar == 'm')
  344. mvars->ops[M] |= op, ochar++;
  345. else if (*ochar == 's')
  346. mvars->ops[S] |= op, ochar++;
  347. else if (*ochar == '-')
  348. ochar++;
  349. else
  350. cops |= op;
  351. mvars->ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
  352. break;
  353. case 'X':
  354. op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
  355. goto cop;
  356. case 'F':
  357. cops |= XOP_PULL|XOP_PUSH;
  358. case '0':
  359. mvars->ops[M] |= XOP_HAVE_TYPE;
  360. break;
  361. case 'n':
  362. case 'd':
  363. case 'f':
  364. case 'N':
  365. --ochar;
  366. op = 0;
  367. cac:
  368. for (;; ochar++) {
  369. if (*ochar == 'n')
  370. op |= OP_NEW;
  371. else if (*ochar == 'd')
  372. op |= OP_DELETE;
  373. else if (*ochar == 'f')
  374. op |= OP_FLAGS;
  375. else if (*ochar == 'N')
  376. op |= OP_RENEW;
  377. else
  378. break;
  379. }
  380. if (op & OP_MASK_TYPE)
  381. switch (op & XOP_MASK_DIR) {
  382. case XOP_PULL: mvars->ops[S] |= op & OP_MASK_TYPE; break;
  383. case XOP_PUSH: mvars->ops[M] |= op & OP_MASK_TYPE; break;
  384. default: cops |= op; break;
  385. }
  386. else
  387. cops |= op;
  388. mvars->ops[M] |= XOP_HAVE_TYPE;
  389. break;
  390. case 'L':
  391. op = XOP_PULL;
  392. goto cac;
  393. case 'H':
  394. op = XOP_PUSH;
  395. goto cac;
  396. case 'q':
  397. if (DFlags & QUIET)
  398. DFlags |= VERYQUIET;
  399. else
  400. DFlags |= QUIET;
  401. break;
  402. case 'V':
  403. DFlags |= VERBOSE | QUIET;
  404. break;
  405. case 'D':
  406. DFlags |= DEBUG | QUIET;
  407. break;
  408. case 'J':
  409. DFlags |= KEEPJOURNAL;
  410. break;
  411. case 'v':
  412. version();
  413. case 'h':
  414. usage( 0 );
  415. default:
  416. error( "Unknown option '-%c'\n", *(ochar - 1) );
  417. return 1;
  418. }
  419. }
  420. if (DFlags & DEBUG) {
  421. signal( SIGSEGV, crashHandler );
  422. signal( SIGBUS, crashHandler );
  423. signal( SIGILL, crashHandler );
  424. }
  425. if (merge_ops( cops, mvars->ops ))
  426. return 1;
  427. if (load_config( config, pseudo ))
  428. return 1;
  429. if (!mvars->all && !argv[mvars->oind]) {
  430. fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
  431. return 1;
  432. }
  433. if (!channels) {
  434. fputs( "No channels defined. Try 'man " EXE "'\n", stderr );
  435. return 1;
  436. }
  437. mvars->chan = channels;
  438. if (mvars->all)
  439. mvars->multiple = channels->next != 0;
  440. else if (argv[mvars->oind + 1])
  441. mvars->multiple = 1;
  442. else
  443. for (group = groups; group; group = group->next)
  444. if (!strcmp( group->name, argv[mvars->oind] )) {
  445. mvars->multiple = 1;
  446. break;
  447. }
  448. mvars->argv = argv;
  449. mvars->cben = 1;
  450. sync_chans( mvars, E_START );
  451. return mvars->ret;
  452. }
  453. #define ST_FRESH 0
  454. #define ST_OPEN 1
  455. #define ST_CLOSED 2
  456. static void store_opened( store_t *ctx, void *aux );
  457. static void store_listed( int sts, void *aux );
  458. static void done_sync_dyn( int sts, void *aux );
  459. static void done_sync( int sts, void *aux );
  460. static void
  461. sync_chans( main_vars_t *mvars, int ent )
  462. {
  463. group_conf_t *group;
  464. channel_conf_t *chan;
  465. store_t *store;
  466. string_list_t *mbox, *sbox, **mboxp, **sboxp;
  467. char *channame;
  468. int t;
  469. if (!mvars->cben)
  470. return;
  471. switch (ent) {
  472. case E_OPEN: goto opened;
  473. case E_SYNC: goto syncone;
  474. }
  475. for (;;) {
  476. mvars->boxlist = 0;
  477. if (!mvars->all) {
  478. if (mvars->chanptr)
  479. channame = mvars->chanptr->string;
  480. else {
  481. for (group = groups; group; group = group->next)
  482. if (!strcmp( group->name, mvars->argv[mvars->oind] )) {
  483. mvars->chanptr = group->channels;
  484. channame = mvars->chanptr->string;
  485. goto gotgrp;
  486. }
  487. channame = mvars->argv[mvars->oind];
  488. gotgrp: ;
  489. }
  490. if ((mvars->boxlist = strchr( channame, ':' )))
  491. *mvars->boxlist++ = 0;
  492. for (chan = channels; chan; chan = chan->next)
  493. if (!strcmp( chan->name, channame ))
  494. goto gotchan;
  495. error( "No channel or group named '%s' defined.\n", channame );
  496. mvars->ret = 1;
  497. goto gotnone;
  498. gotchan:
  499. mvars->chan = chan;
  500. }
  501. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
  502. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
  503. merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
  504. mvars->state[M] = mvars->state[S] = ST_FRESH;
  505. info( "Channel %s\n", mvars->chan->name );
  506. mvars->boxes[M] = mvars->boxes[S] = mvars->cboxes = 0;
  507. mvars->skip = mvars->cben = 0;
  508. for (t = 0; t < 2; t++) {
  509. mvars->drv[t] = mvars->chan->stores[t]->driver;
  510. if ((store = mvars->drv[t]->own_store( mvars->chan->stores[t] )))
  511. store_opened( store, AUX );
  512. }
  513. for (t = 0; t < 2 && !mvars->skip; t++)
  514. if (mvars->state[t] == ST_FRESH) {
  515. info( "Opening %s %s...\n", str_ms[t], mvars->chan->stores[t]->name );
  516. mvars->drv[t]->open_store( mvars->chan->stores[t], store_opened, AUX );
  517. }
  518. mvars->cben = 1;
  519. opened:
  520. if (mvars->skip)
  521. goto next;
  522. if (mvars->state[M] != ST_OPEN || mvars->state[S] != ST_OPEN)
  523. return;
  524. if (mvars->boxlist)
  525. mvars->boxp = mvars->boxlist;
  526. else if (mvars->chan->patterns) {
  527. mvars->boxes[M] = filter_boxes( mvars->ctx[M]->boxes, mvars->chan->patterns );
  528. mvars->boxes[S] = filter_boxes( mvars->ctx[S]->boxes, mvars->chan->patterns );
  529. for (mboxp = &mvars->boxes[M]; (mbox = *mboxp); ) {
  530. for (sboxp = &mvars->boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
  531. if (!strcmp( sbox->string, mbox->string )) {
  532. *sboxp = sbox->next;
  533. free( sbox );
  534. *mboxp = mbox->next;
  535. mbox->next = mvars->cboxes;
  536. mvars->cboxes = mbox;
  537. goto gotdupe;
  538. }
  539. mboxp = &mbox->next;
  540. gotdupe: ;
  541. }
  542. }
  543. if (mvars->list && mvars->multiple)
  544. printf( "%s:\n", mvars->chan->name );
  545. syncml:
  546. mvars->done = mvars->cben = 0;
  547. syncmlx:
  548. if (mvars->boxlist) {
  549. if ((mvars->names[S] = strsep( &mvars->boxp, ",\n" ))) {
  550. if (!mvars->list) {
  551. mvars->names[M] = mvars->names[S];
  552. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync, mvars );
  553. goto syncw;
  554. }
  555. puts( mvars->names[S] );
  556. goto syncmlx;
  557. }
  558. } else if (mvars->chan->patterns) {
  559. if ((mbox = mvars->cboxes)) {
  560. mvars->cboxes = mbox->next;
  561. if (!mvars->list) {
  562. mvars->names[M] = mvars->names[S] = mbox->string;
  563. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  564. goto syncw;
  565. }
  566. puts( mbox->string );
  567. free( mbox );
  568. goto syncmlx;
  569. }
  570. for (t = 0; t < 2; t++)
  571. if ((mbox = mvars->boxes[t])) {
  572. mvars->boxes[t] = mbox->next;
  573. if ((mvars->chan->ops[1-t] & OP_MASK_TYPE) && (mvars->chan->ops[1-t] & OP_CREATE)) {
  574. if (!mvars->list) {
  575. mvars->names[M] = mvars->names[S] = mbox->string;
  576. sync_boxes( mvars->ctx, mvars->names, mvars->chan, done_sync_dyn, mvars );
  577. goto syncw;
  578. }
  579. puts( mbox->string );
  580. }
  581. free( mbox );
  582. goto syncmlx;
  583. }
  584. } else {
  585. if (!mvars->list) {
  586. sync_boxes( mvars->ctx, mvars->chan->boxes, mvars->chan, done_sync, mvars );
  587. mvars->skip = 1;
  588. syncw:
  589. mvars->cben = 1;
  590. if (!mvars->done)
  591. return;
  592. syncone:
  593. if (!mvars->skip)
  594. goto syncml;
  595. } else
  596. printf( "%s <=> %s\n", mvars->chan->boxes[M], mvars->chan->boxes[S] );
  597. }
  598. next:
  599. for (t = 0; t < 2; t++)
  600. if (mvars->state[t] == ST_OPEN) {
  601. mvars->drv[t]->disown_store( mvars->ctx[t] );
  602. mvars->state[t] = ST_CLOSED;
  603. }
  604. if (mvars->state[M] != ST_CLOSED || mvars->state[S] != ST_CLOSED) {
  605. mvars->skip = mvars->cben = 1;
  606. return;
  607. }
  608. free_string_list( mvars->cboxes );
  609. free_string_list( mvars->boxes[M] );
  610. free_string_list( mvars->boxes[S] );
  611. if (mvars->all) {
  612. if (!(mvars->chan = mvars->chan->next))
  613. break;
  614. } else {
  615. if (mvars->chanptr && (mvars->chanptr = mvars->chanptr->next))
  616. continue;
  617. gotnone:
  618. if (!mvars->argv[++mvars->oind])
  619. break;
  620. }
  621. }
  622. for (t = 0; t < N_DRIVERS; t++)
  623. drivers[t]->cleanup();
  624. }
  625. static void
  626. store_opened( store_t *ctx, void *aux )
  627. {
  628. MVARS(aux)
  629. if (!ctx) {
  630. mvars->state[t] = ST_CLOSED;
  631. mvars->ret = mvars->skip = 1;
  632. return;
  633. }
  634. mvars->ctx[t] = ctx;
  635. if (mvars->skip) {
  636. mvars->state[t] = ST_OPEN;
  637. sync_chans( mvars, E_OPEN );
  638. return;
  639. }
  640. if (!mvars->boxlist && mvars->chan->patterns && !ctx->listed)
  641. mvars->drv[t]->list( ctx, store_listed, AUX );
  642. else {
  643. mvars->state[t] = ST_OPEN;
  644. sync_chans( mvars, E_OPEN );
  645. }
  646. }
  647. static void
  648. store_listed( int sts, void *aux )
  649. {
  650. MVARS(aux)
  651. mvars->state[t] = ST_OPEN;
  652. switch (sts) {
  653. case DRV_OK:
  654. if (mvars->ctx[t]->conf->map_inbox)
  655. add_string_list( &mvars->ctx[t]->boxes, mvars->ctx[t]->conf->map_inbox );
  656. break;
  657. case DRV_STORE_BAD:
  658. mvars->drv[t]->cancel_store( mvars->ctx[t] );
  659. mvars->state[t] = ST_CLOSED;
  660. default:
  661. mvars->ret = mvars->skip = 1;
  662. break;
  663. }
  664. sync_chans( mvars, E_OPEN );
  665. }
  666. static void
  667. done_sync_dyn( int sts, void *aux )
  668. {
  669. main_vars_t *mvars = (main_vars_t *)aux;
  670. free( ((char *)mvars->names[S]) - offsetof(string_list_t, string) );
  671. done_sync( sts, aux );
  672. }
  673. static void
  674. done_sync( int sts, void *aux )
  675. {
  676. main_vars_t *mvars = (main_vars_t *)aux;
  677. mvars->done = 1;
  678. if (sts) {
  679. mvars->ret = 1;
  680. if (sts & (SYNC_BAD(M) | SYNC_BAD(S))) {
  681. mvars->skip = 1;
  682. if (sts & SYNC_BAD(M))
  683. mvars->state[M] = ST_CLOSED;
  684. if (sts & SYNC_BAD(S))
  685. mvars->state[S] = ST_CLOSED;
  686. }
  687. }
  688. sync_chans( mvars, E_SYNC );
  689. }