dmc.c (20345B)
1 /* dmc - dynamic mail client 2 * See LICENSE file for copyright and license details. 3 */ 4 #include <stdio.h> 5 #include <string.h> 6 #include <dirent.h> 7 #include <unistd.h> 8 #include <stdlib.h> 9 #include <stdarg.h> 10 #include <sys/stat.h> 11 #include <sys/wait.h> 12 #include <sys/types.h> 13 #include "config.h" 14 15 static char *editor; 16 static char dmcdir[128]; 17 static char **dmcaccounts(); 18 static char prompt[64]; 19 static char **acc, *defacc = NULL; 20 static int dmc_in[2], dmc_out[2], dmc_err[2]; 21 static int dmc_pid = -1; 22 static fd_set rfds, wfds; 23 24 typedef struct { 25 char *out; 26 char *err; 27 int errlen; 28 } DmcQuery; 29 30 static DmcQuery reply; 31 32 static void dmcstop(); 33 static int dmcsend(const char *file); 34 static int dmcstore(const char *body); 35 static int fexist(const char *path); 36 37 #if 0 38 static char *dmcnamegen(const char *file) { 39 // return filename from mail 40 // Name is YYYYMMDDhhmm## -- name sort by date 41 // if no Date..use file timestamp 42 // well. we just need at the end.. a unique incremental ID 43 // interesting mails are the last ones in mail server 44 return NULL; 45 } 46 47 static int dmcstore() { 48 // TODO 49 return 0; 50 } 51 #endif 52 53 static const char* wd(const char *fmt, ...) { 54 va_list ap; 55 int len; 56 static char ret[512]; 57 va_start (ap, fmt); 58 len = strlen (dmcdir); 59 memcpy (ret, dmcdir, len); 60 vsnprintf (ret+len, sizeof (ret)-len, fmt, ap); 61 va_end (ap); 62 return ret; 63 } 64 65 static const char *abspath(const char *file) { 66 static char filepath[512]; 67 char cwd[128]; 68 if (*file=='/') 69 return file; 70 getcwd (cwd, sizeof (cwd)); 71 snprintf (filepath, sizeof (filepath)-strlen (file)-3, "%s", cwd); 72 strcat (filepath, "/"); 73 strcat (filepath, file); 74 return filepath; 75 } 76 77 static const char *dmcalias(const char *filter) { 78 static char line[64]; 79 FILE *fd = fopen (wd ("addrbook"), "r"); 80 if (fd) { 81 for (;;) { 82 fgets (line, sizeof (line), fd); 83 if (feof (fd)) 84 break; 85 if (strstr (line, filter)) { 86 line[strlen(line)-1] = 0; 87 return line; 88 } 89 } 90 fclose (fd); 91 } 92 return filter; 93 } 94 95 static const char *dmcmailpath(const char *name) { 96 static char path[256]; 97 /* check ./%s */ 98 if (fexist (name)) 99 return name; 100 // TODO: simplify in loop and use wd() 101 /* check DMCDIR/box/$acc/in/%s.eml */ 102 snprintf (path, sizeof (path), "%s/box/%s/in/%s.eml", dmcdir, defacc, name); 103 if (fexist (path)) 104 return path; 105 /* check DMCDIR/box/$acc/in/%s */ 106 snprintf (path, sizeof (path), "%s/box/%s/in/%s", dmcdir, defacc, name); 107 if (fexist (path)) 108 return path; 109 /* check DMCDIR/box/$acc/%s */ 110 snprintf (path, sizeof (path), "%s/box/%s/%s", dmcdir, defacc, name); 111 if (fexist (path)) 112 return path; 113 /* check DMCDIR/box/%s */ 114 snprintf (path, sizeof (path), "%s/box/%s", dmcdir, name); 115 if (fexist (path)) 116 return path; 117 /* not found */ 118 return NULL; 119 } 120 121 static int dmccat(const char *file) { 122 char line[128]; 123 const char *f = dmcmailpath (file); // XXX dup? 124 if (f && fexist (f)) { 125 snprintf (line, sizeof (line), "cat '%s'", f); 126 system (line); // implement native cat 127 return 1; 128 } else fprintf (stderr, "Cannot find '%s'\n", file); 129 return 0; 130 } 131 132 static char *gethdr(const char *path, const char *file, const char *hdr) { 133 char line[1024], *ret = NULL; 134 FILE *fd; 135 int i; 136 snprintf (line, sizeof (line), "%s/%s", path, file); 137 fd = fopen (line, "r"); 138 if (fd) { 139 int len = strlen (hdr); 140 while (!feof (fd)) { 141 fgets (line, sizeof (line), fd); 142 if (!memcmp (line, hdr, len)) { 143 i = strlen (line)-1; 144 if (i>len) { 145 line[i--] = '\0'; 146 if (line[i]=='\r'||line[i]=='\n') 147 line[i] = '\0'; 148 ret = strdup (line+len); 149 } else ret = strdup (""); 150 break; 151 } 152 } 153 fclose (fd); 154 } 155 return ret; 156 } 157 158 static int dmcls(const char *path) { 159 struct dirent *de; 160 DIR *dir; 161 if ((dir = opendir (path))) { 162 while ((de = readdir (dir))) { 163 if (*de->d_name!='.') { 164 char *subj = gethdr (path, de->d_name, "Subject: "); 165 char *from = gethdr (path, de->d_name, "From: "); 166 printf ("%s:\t%s\n\t%s\n", de->d_name, subj, from); 167 free (from); 168 free (subj); 169 } 170 } 171 closedir (dir); 172 return 1; 173 } 174 return 0; 175 } 176 177 static void dmcinit() { 178 char *tmp = getenv ("EDITOR"); 179 editor = tmp? tmp: EDITOR; 180 if (!(tmp = getenv ("HOME"))) { 181 fprintf (stderr, "Cannot find HOME\n"); 182 exit (1); 183 } 184 snprintf (dmcdir, sizeof (dmcdir), "/%s/"DMCDIR"/", tmp); 185 if (!fexist (dmcdir)) 186 if (mkdir (dmcdir, DIRPERM) == -1) { 187 fprintf (stderr, "Cannot create \"%s\"\n", dmcdir); 188 exit (1); 189 } 190 mkdir (wd ("tmp"), DIRPERM); 191 mkdir (wd ("box"), DIRPERM); 192 mkdir (wd ("acc"), DIRPERM); 193 acc = dmcaccounts (); 194 defacc = acc[0]; 195 signal (SIGINT, dmcstop); 196 atexit (dmcstop); 197 reply.out = reply.err = NULL; 198 } 199 200 static char *cfgget(const char *key) { 201 FILE *fd; 202 char line[128], *ptr, *ret = NULL; 203 if ((fd = fopen (wd ("acc/%s", defacc), "r"))) { 204 int len = strlen (key); 205 while (!feof (fd)) { 206 fgets (line, sizeof (line), fd); 207 if (!memcmp (line, key, len)) { 208 ptr = strchr (line, '#'); 209 if (ptr) { 210 for (*ptr=0, ptr--; ptr != line && (*ptr==' ' || *ptr=='\t'); ptr--) 211 *ptr = 0; 212 } else line [strlen (line)-1] = 0; 213 ret = strdup (line+len); 214 break; 215 } 216 } 217 fclose (fd); 218 } 219 return ret; 220 } 221 222 /* server */ 223 static int dmcstart(const char *name) { 224 char a0[512], a1[32]; 225 char *host, *port, *prot, *ssl; 226 pipe (dmc_in); 227 pipe (dmc_out); 228 pipe (dmc_err); 229 dmc_pid = fork (); 230 signal (SIGPIPE, SIG_IGN); 231 switch (dmc_pid) { 232 case -1: 233 fprintf (stderr, "Cannot fork\n"); 234 exit (1); 235 case 0: 236 dup2 (dmc_in[0], 0); 237 close (dmc_in[0]); 238 close (dmc_in[1]); 239 240 dup2 (dmc_out[1], 1); 241 close (dmc_out[0]); 242 close (dmc_out[1]); 243 244 dup2 (dmc_err[1], 2); 245 close (dmc_err[0]); 246 close (dmc_err[1]); 247 248 host = cfgget ("HOST="); 249 port = cfgget ("PORT="); 250 prot = cfgget ("PROTOCOL="); 251 ssl = cfgget ("SSL="); 252 ssl = ssl? atoi (ssl)? "1": NULL: NULL; 253 snprintf (a0, sizeof (a0), PREFIX"/bin/dmc-%s", prot); 254 snprintf (a1, sizeof (a1), "dmc-%s", prot); 255 printf ("(%s)\n", a0); 256 execl (a0, a1, host, port, ssl, NULL); 257 free (host); 258 free (port); 259 exit (1); 260 default: 261 close (dmc_out[1]); 262 close (dmc_err[1]); 263 close (dmc_in[0]); 264 break; 265 } 266 return 0; 267 } 268 269 static void dmckill(int sig) { 270 fprintf (stderr, "Killed.\n"); 271 kill (dmc_pid, SIGKILL); 272 } 273 274 static void dmcstop() { 275 if (dmc_pid != -1) { 276 const char *cmd = "exit\n"; 277 write (dmc_in[1], cmd, strlen (cmd)); 278 signal (SIGALRM, dmckill); 279 alarm (2); 280 waitpid (dmc_pid, NULL, 0); 281 signal (SIGALRM, NULL); 282 alarm (0); 283 dmc_pid = -1; 284 285 // duppy 286 close (dmc_in[0]); 287 close (dmc_in[1]); 288 close (dmc_out[0]); 289 close (dmc_out[1]); 290 close (dmc_err[0]); 291 close (dmc_err[1]); 292 } 293 } 294 295 static int dmccmd(const char *cmd) { 296 static char buf[128]; 297 int ret, nfd; 298 299 if (dmc_pid == -1) { 300 printf ("Use 'on' or '?'\n"); 301 return 0; 302 } 303 free (reply.out); 304 reply.out = NULL; 305 free (reply.err); 306 reply.err = NULL; 307 reply.errlen = 0; 308 for (;;) { 309 FD_ZERO (&rfds); 310 FD_ZERO (&wfds); 311 FD_SET (dmc_out[0], &rfds); 312 FD_SET (dmc_err[0], &rfds); 313 FD_SET (dmc_in[1], &wfds); 314 nfd = select (dmc_err[0] + 1, &rfds, &wfds, NULL, NULL); 315 if (nfd < 0) 316 break; 317 if (FD_ISSET (dmc_out[0], &rfds)) { 318 ret = read (dmc_out[0], buf, sizeof (buf)-1); 319 if (ret>0) { 320 buf[ret-1] = 0; 321 reply.out = strdup (buf); // XXX 322 //printf ("-(out)-> (%s)\n", buf); 323 break; 324 } 325 } else 326 if (FD_ISSET (dmc_err[0], &rfds)) { 327 ret = read (dmc_err[0], buf, sizeof (buf)-1); 328 if (ret>0) { 329 buf[ret-1] = 0; 330 reply.err = realloc (reply.err, reply.errlen+ret+1); 331 memcpy (reply.err+reply.errlen, buf, ret); 332 reply.errlen += ret-1; 333 //printf ("-(err)-> (%s)\n", buf); 334 } 335 } else 336 if (FD_ISSET (dmc_in[1], &wfds)) { 337 if (cmd && *cmd && *cmd != '\n') { 338 snprintf (buf, sizeof (buf), "%s\n", cmd); 339 write (dmc_in[1], buf, strlen (buf)); 340 if (DEBUG) printf ("-(wri)-> (%s)\n", cmd); 341 cmd = NULL; 342 } 343 } 344 } 345 return 1; 346 } 347 348 static void dmcpush(const char *name) { 349 struct dirent *de; 350 char path[256], file[512]; 351 DIR *dir; 352 int i; 353 354 for (i=0; acc[i]; i++) { 355 snprintf (path, sizeof (path), "%s/box/%s/out", dmcdir, acc[i]); 356 dir = opendir (path); 357 while ((de = readdir (dir))) { 358 char *n = de->d_name; 359 if (*n != '.' && !strstr (n, ".d")) { 360 snprintf (file, sizeof (file), "%s/%s", path, n); 361 printf ("%s: ", file); 362 fflush (stdout); 363 if (dmcsend (file)) { 364 snprintf (path, sizeof (path), "mv %s* '%s'", 365 file, wd ("box/%s/sent", defacc)); 366 system (path); // do not use system() 367 } 368 } 369 } 370 closedir (dir); 371 } 372 } 373 374 static int fexist(const char *path) { 375 struct stat st; 376 int ret = path? stat (path, &st): -1; 377 return (ret != -1); 378 } 379 380 static int fsize(const char *path) { 381 FILE *fd = fopen (path, "r"); 382 int len = 0; 383 if (fd) { 384 fseek (fd, 0, SEEK_END); 385 len = ftell (fd); 386 fclose (fd); 387 } 388 return len; 389 } 390 391 static char *parsedate(const char *str) { 392 static char buf[256]; 393 char *ch; 394 strncpy (buf, str, sizeof (buf)); 395 if ((ch = strchr (buf, ','))) { 396 int year, month, day = atoi (ch+1); 397 if (!day) 398 return 0; 399 ch = strchr (ch+2, ' '); 400 while (*ch==' ')ch++; 401 if (ch) { 402 char *q, *p = strchr (ch+3, ' '); 403 if (p) { 404 *p = 0; 405 printf ("MONTH (%c%c%c)\n", ch[0], ch[1], ch[2]); 406 month = 0; // TODO 407 year = atoi (p+1); 408 if (year) { 409 q = strchr (p+1, ' '); 410 if (q) { 411 int h,m,s; 412 *q = 0; 413 sscanf (p+1, "%d:%d:%d", &h, &m, &s); 414 snprintf (buf, sizeof (buf), 415 "%s/box/%s/in/%04d%02d%02d-%02d%02d%02d", 416 dmcdir, defacc, year, month, day, h, m, s); 417 /* return 0: FUCK YEAH!!1 */ 418 } else return 0; 419 } else return 0; 420 } else return 0; 421 } else return 0; 422 } else return 0; 423 return buf; 424 } 425 426 // TODO: support to store only the header, not full mail 427 static int dmcstore(const char *body) { 428 char dmctag[512], *file, *end, *ptr = strstr (body, "Date: "); // TODO: use gethdr..on buffer, not file 429 if (ptr) { 430 ptr = ptr + 6; 431 end = strchr (ptr, '\n'); 432 // generate filename from date 433 file = parsedate (ptr); 434 if (file) { 435 printf ("FILE IS =%s\n", file); 436 if (!fexist (file)) { 437 FILE *fd = fopen (file, "w"); 438 if (fd) { 439 fputs (body, fd); 440 fclose (fd); 441 // TODO extract attachments 442 // TODO save only body 443 snprintf (dmctag, sizeof (dmctag), 444 "dmc-tag '%s' new `dmc-tag %s`", file, file); 445 system (dmctag); 446 return 1; 447 } else fprintf (stderr, "Cannot write file '%s'\n", file); 448 } else fprintf (stderr, "Already downloaded.\n"); 449 } else fprintf (stderr, "Cannot generate file name for (%s)\n", body); 450 } else fprintf (stderr, "Cannot find date header.\n"); 451 return 0; 452 } 453 454 static int dmcpull(int num, int lim, int dir) { 455 int ret, count = 0; 456 char cmd[64]; 457 char *slimit = cfgget ("LIMIT="); 458 int limit = slimit? atoi (slimit): LIMIT; 459 for (;num!=lim && (!limit||count<limit);num+=dir) { 460 snprintf (cmd, sizeof (cmd), "cat %d\n", num); 461 ret = dmccmd (cmd); 462 printf ("RETURN IS = %d\n", ret); 463 ret = dmcstore (reply.err); // TODO: add support for folders 464 printf ("dmcstore ret = %d\n", ret); 465 if (!ret) 466 break; 467 count ++; 468 } 469 printf ("%d new messages\n", count); 470 return count; 471 } 472 473 static char **dmcaccounts() { 474 struct dirent *de; 475 static char *accounts[MAXACC]; 476 char buf[256], *defacc = NULL; 477 DIR *dir; 478 int acc = 0; 479 memset (buf, 0, sizeof (buf)); 480 if (readlink (wd ("acc.default"), buf, sizeof (buf))!=-1) { 481 defacc = buf + strlen (buf)-1; 482 while (*defacc != '/') 483 defacc--; 484 accounts[acc++] = strdup (++defacc); 485 } else fprintf (stderr, "No default account defined.\n"); 486 dir = opendir (wd ("acc")); 487 while ((de = readdir (dir)) && acc<MAXACC-2) 488 if (*de->d_name != '.' && (!defacc || strcmp (de->d_name, defacc))) 489 accounts[acc++] = strdup (de->d_name); 490 closedir (dir); 491 accounts[acc] = NULL; 492 return accounts; 493 } 494 495 static void charrfree(char **ptr) { 496 char **p = ptr; 497 while (*p) { 498 free(*p); 499 p++; 500 } 501 *ptr = NULL; 502 } 503 504 static int dmcsend(const char *file) { 505 char line[512]; 506 char *user = cfgget ("USER="); 507 char *mail = cfgget ("MAIL="); 508 char *to = gethdr ((*file=='/')?"/":"./", file, "To: "); 509 /* TODO: Implement non-msmtp method */ 510 snprintf (line, sizeof (line), 511 "dmc-pack `ls %s.d/* 2>/dev/null` < %s " 512 "| msmtp --user=\"%s\" --from=\"%s\" \"%s\"", 513 file, file, user, mail, to); 514 if (system (line) != 0) { 515 fprintf (stderr, "Error ocurred while sending %s\n", file); 516 return 0; 517 } else fprintf (stderr, "Sent.\n"); 518 return 1; 519 } 520 521 static int dmcline(const char *line) { 522 int ret = 1; 523 char cmd[128]; 524 if (!strcmp (line, "?")) { 525 printf ("Usage: on off push pull exit ls lsd cat ..\n"); 526 } else 527 if (!strcmp (line, "login")) { 528 char *user = cfgget ("USER="); 529 char *pass = cfgget ("PASS="); 530 snprintf (cmd, sizeof (cmd), "login %s %s\n", user, pass); 531 if (!dmccmd (cmd)) 532 printf ("Error.\n"); 533 free (user); 534 free (pass); 535 } else 536 if (!strcmp (line, "on")) { 537 dmcstart (acc[0]); 538 if (!dmccmd (NULL)) 539 printf ("Error.\n"); 540 } else 541 if (!memcmp (line, "get ", 4)) { 542 snprintf (cmd, sizeof (cmd), "cat %s", line+4); 543 if (dmc_pid != -1) { 544 dmccmd (cmd); 545 printf ("CHECK (%s)\n", reply.out); 546 // TODO. if (check).. 547 dmcstore (reply.err); 548 } else fprintf (stderr, "Not connected.\n"); 549 } else 550 if (!strcmp (line, "off")) { 551 dmcstop (); 552 } else 553 if (!strcmp (line, "ls")) { 554 if (dmc_pid != -1) 555 dmccmd ("ls\n"); 556 else dmcls (wd ("box/%s/in", defacc)); 557 } else 558 if (!memcmp (line, "cat ", 4)) { 559 if (dmc_pid != -1) 560 dmccmd (line); // bypass 561 else dmccat (line+4); 562 } else 563 if (!strcmp (line, "push")) { 564 dmcpush (defacc); 565 } else 566 if (!strcmp (line, "pull")) { 567 dmcpull (5, 9, 1); // pop3 test 568 } else 569 if (!strcmp (line, "exit")) { 570 return 0; 571 } else { 572 /* bypass to child */ 573 if (!dmccmd (line)) { 574 fprintf (stderr, "## No reply\n"); 575 ret = 0; 576 } 577 } 578 if (ret) { 579 printf ("-(out)-> %s\n", reply.out); 580 //printf ("-(err)-> %s\n", reply.err); 581 } 582 return 1; 583 } 584 585 static int usage(const char *argv0, int lon) { 586 fprintf (stderr, "Usage: %s [-hv] [-c [cmd] [-s file] [-e acc] [-A file ..]\n" 587 "\t[-a addr] [-m [a [s [..]] [-f m a] [-r m a] [-l [box]]\n", argv0); 588 if (lon) fprintf (stderr, 589 " -m [a [s]..] create mail [addr [subj [file1 file2 ..]]]\n" 590 " -c [cmd] command shell\n" 591 " -e [acc] list/edit/set default accounts\n" 592 " -a [addr] grep in addressbook\n" 593 " -A [file .] attach files to ~/.dmc/mail.last done by 'dmc -m'\n" 594 " -l [box] list mails in specified box of def account\n" 595 " -s [file] send mail\n" 596 " -f m [addr] forward mail to addr\n" 597 " -r m [addr] reply mail to addr\n" 598 " -v show version\n" 599 ""); 600 return 0; 601 } 602 603 static int dmcmail(const char *addr, const char *subj, const char *slurp, const char *slurptitle) { 604 const char *from = cfgget("MAIL="); 605 char file[128], line[128]; 606 int fd, ret = 0; 607 snprintf (file, sizeof (file), "%s/box/%s/out/mail.XXXXXX", dmcdir, acc[0]); 608 fd = mkstemp (file); 609 if (fd != -1) { 610 // TODO: fchmod or mkostemp 611 snprintf (line, sizeof (line), 612 "X-Mailer: dmc v"VERSION"\n" 613 "From: %s\n" 614 "To: %s\n" 615 "Subject: %s\n\n\n", from, addr, subj); 616 write (fd, line, strlen (line)); 617 if (slurp) { 618 FILE *sfd = fopen (slurp, "r"); 619 if (sfd) { 620 int body = 0; 621 write (fd, "\n\n", 2); 622 if (slurptitle) 623 write (fd, slurptitle, strlen (slurptitle)); 624 for (;;) { 625 fgets (line, sizeof (line), sfd); 626 if (feof (sfd)) break; 627 if (body) { 628 write (fd, "> ", 2); 629 write (fd, line, strlen (line)); 630 } else if (strlen (line)<4) body = 1; 631 } 632 } 633 } 634 close (fd); 635 snprintf (line, sizeof (line), EDITOR" '%s'", file); 636 system (line); 637 if (fsize (file)<32) { 638 fprintf (stderr, "Aborted\n"); 639 unlink (file); 640 } else { 641 snprintf (line, sizeof (line), "%s/mail.last", dmcdir); 642 unlink (line); 643 symlink (file, line); 644 ret = 1; 645 } 646 } else fprintf (stderr, "Cannot create '%s'\n", file); 647 return ret; 648 } 649 650 static void dmcattach(const char *file) { 651 char path[256]; 652 const char *name = file + strlen (file)-1; 653 while (*name!='/' && name>file) 654 name--; 655 name++; 656 path[0] = 0; 657 memset (path, 0, sizeof(path)); 658 if (readlink (wd ("mail.last"), path, sizeof (path)-strlen (name)-2)!=-1) { 659 strcat (path, ".d/"); 660 mkdir (path, 0750); 661 strcat (path, name); 662 symlink (abspath (file), path); 663 } else fprintf (stderr, "Cannot attach '%s'\n", file); 664 } 665 666 static char *evalstr(const char *mail, const char *str) { 667 int outi = 0; 668 char *out, *tmp; 669 const char *ptr = str; 670 out = malloc (1024); // XXX overflow 671 while (*ptr) { 672 if (*ptr == '{') { 673 int dsti = 0; 674 char dst[1024]; 675 ptr++; 676 while (*ptr && *ptr != '}' && dsti<sizeof(dst)-1) { 677 dst[dsti++] = *ptr; 678 ptr++; 679 } 680 dst[dsti] = 0; 681 tmp = gethdr ("/", mail, dst); 682 if (tmp) { 683 strcpy (out+outi, tmp); 684 outi += strlen (tmp); 685 free (tmp); 686 } 687 ptr++; 688 continue; 689 } 690 out[outi++] = *ptr; 691 ptr++; 692 } 693 out[outi] = 0; 694 return out; 695 } 696 697 static void dmcfwd(const char *file, const char *addr, const char *msg, const char *sub) { 698 if (file) { 699 char *m, *subj, *msub = gethdr ("/", file, "Subject: "); 700 if (msub) { 701 char *s = evalstr (file, sub); 702 subj = malloc (strlen (msub) + strlen (s) + 2); 703 strcpy (subj, s); 704 strcat (subj, msub); 705 free (s); 706 } else { 707 subj = strdup (sub); 708 } 709 if (addr && *addr) 710 addr = dmcalias (addr); 711 m = evalstr (file, msg); 712 dmcmail (addr, subj, file, m); 713 free (m); 714 free (subj); 715 } else fprintf (stderr, "Mail not found.\n"); 716 } 717 718 int main(int argc, char **argv) { 719 char file[128], line[128]; 720 int i; 721 722 if (argc < 2) 723 return usage (argv[0], 0); 724 725 dmcinit (); 726 if (strcmp (argv[1], "-e")) { 727 if (!acc[0]) { 728 fprintf (stderr, "Use 'dmc -e' to configure the account\n"); 729 return 1; 730 } 731 } 732 733 if (argv[1][0] == '-') 734 switch (argv[1][1]) { 735 case 'l': 736 if (argc>2) { 737 if (dmccat (argv[2])) 738 break; 739 snprintf (line, sizeof (line), "%s/box/%s", dmcdir, argv[2]); 740 } else snprintf (line, sizeof (line), "%s/box/%s/in", dmcdir, acc[0]); 741 dmcls (line); 742 break; 743 case 'A': 744 for (i=2; i<argc; i++) 745 dmcattach (argv[i]); 746 break; 747 case 'v': 748 printf ("dmc v"VERSION"\n"); 749 break; 750 case 's': 751 if (argc>2) 752 dmcsend (argv[2]); 753 else fprintf (stderr, "Usage: dmc-cmd [-s file]\n"); 754 break; 755 case 'm': 756 { 757 const char *addr = ""; 758 const char *subj = ""; 759 if (argc>2) 760 addr = argv[2]; 761 if (argc>3) 762 subj = argv[3]; 763 if (addr && !strchr (addr, '@')) 764 addr = dmcalias (addr); 765 if (dmcmail (addr, subj, NULL, NULL)) 766 for (i=4; argv[i]; i++) 767 dmcattach (argv[i]); 768 } 769 break; 770 case 'e': 771 if (argc<3) { 772 for (i=0; acc[i]; i++) 773 printf ("%s\n", acc[i]); 774 } else { 775 snprintf (file, sizeof (file), "%s/acc/%s", dmcdir, argv[2]); 776 if (!fexist (file)) { 777 /* create template */ 778 FILE *fd = fopen (file, "w"); 779 if (fd) { 780 fprintf (fd, 781 "LIMIT=50 # get only 50 mails for each folder\n" 782 "PROTOCOL=pop3 # imap4\n" 783 "HOST=serverhost.com\n" 784 "PORT=110\n" 785 "SSL=0\n" 786 "#SEND=acc-name\n" 787 "SEND=!msmtp\n" 788 "MAIL=username@domain.com\n" 789 "USER=username\n" 790 "PASS=password\n"); 791 fclose (fd); 792 } else { 793 fprintf (stderr, "Cannot write in %s\n", file); 794 return 1; 795 } 796 } 797 snprintf (line, sizeof (line), EDITOR" %s", file); 798 system (line); 799 if (fsize(file)<32) { 800 printf ("Abort\n"); 801 unlink (file); 802 } else { 803 printf ("Default account has changed.\n"); 804 unlink (wd ("acc.default")); 805 symlink (file, wd ("acc.default")); 806 mkdir (wd ("box/%s", argv[2]), DIRPERM); 807 mkdir (wd ("box/%s/out", argv[2]), DIRPERM); 808 mkdir (wd ("box/%s/in", argv[2]), DIRPERM); 809 mkdir (wd ("box/%s/sent", argv[2]), DIRPERM); 810 } 811 } 812 break; 813 case 'a': 814 if (argc<3) { 815 snprintf (line, sizeof (line), "%s '%s'", editor, wd ("addrbook")); 816 system (line); 817 } else { 818 const char *mail = dmcalias (argv[2]); 819 if (mail) 820 puts (mail); 821 } 822 break; 823 case 'c': 824 if (argc<3) { 825 strcpy (prompt, "dmc> "); 826 do { 827 write (1, prompt, strlen (prompt)); 828 fgets(line, sizeof (line), stdin); 829 if (feof (stdin)) 830 strcpy (line, "exit"); 831 else line[strlen (line)-1] = '\0'; 832 } while (dmcline (line)); 833 } else { 834 strcpy (prompt, ""); 835 for (i=2; i<argc; i++) 836 dmcline (argv[i]); 837 } 838 dmcstop (); 839 break; 840 case 'r': 841 dmcfwd (dmcmailpath (argv[2]), argc>3?argv[3]:"", REPMSG, REPSUB); 842 break; 843 case 'f': 844 dmcfwd (dmcmailpath (argv[2]), argc>3?argv[3]:"", FWDMSG, FWDSUB); 845 break; 846 default: 847 return usage (argv[0], 1); 848 } 849 850 charrfree (acc); 851 return 0; 852 }