00001
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "init.h"
00033
00034
00035 #include <rd/conf.h>
00036 #include <rd/log.h>
00037
00038 #define VF_VERSION "0.3.3"
00039 #define VF_READ_BUFSIZE 1024
00043 #define VF_DEFAULT_HOST "localhost"
00044 #define VF_DEFAULT_PORT 25
00045 #define VF_DEFAULT_LOGFILE "/var/log/veldfire.log"
00046 #define VF_DEFAULT_LOGLEVEL 3
00047 #define VF_DEFAULT_CONFIGFILE "/etc/veldfire/veldfire.conf"
00048 #define VF_DEFAULT_SECTION "veldfire"
00049 #define VF_DEFAULT_TIMEOUT 60
00050 #define VF_DEFAULT_MAXCONNECTION 128
00052
00053 #define VF_USER_CONFIGFILE ".veldfirerc"
00057 #define VF_ENV_FROM "VELDFIRE_FROM"
00058 #define VF_ENV_SUBJECT "VELDFIRE_SUBJECT"
00059 #define VF_ENV_HOST "VELDFIRE_HOST"
00060 #define VF_ENV_PORT "VELDFIRE_PORT"
00061 #define VF_ENV_LOGFILE "VELDFIRE_LOGFILE"
00062 #define VF_ENV_LOGLEVEL "VELDFIRE_LOGLEVEL"
00063 #define VF_ENV_CONFIGFILE "VELDFIRE_CONFIGFILE"
00064 #define VF_ENV_SECTION "VELDFIRE_SECTION"
00065 #define VF_ENV_REPORT "VELDFIRE_REPORT"
00066 #define VF_ENV_SENDTIMEOUT "VELDFIRE_SENDTIMEOUT"
00067 #define VF_ENV_RECVTIMEOUT "VELDFIRE_RECVTIMEOUT"
00068 #define VF_ENV_TIMEOUT "VELDFIRE_TIMEOUT"
00069 #define VF_ENV_MAXCONNECTION "VELDFIRE_MAXCONNECTION"
00070 #define VF_ENV_FOREGROUND "VELDFIRE_FOREGROUND"
00071 #define VF_ENV_PRINTLOG "VELDFIRE_PRINTLOG"
00073
00074
00076 #define VF_CONF_TO "to"
00077 #define VF_CONF_FROM "from"
00078 #define VF_CONF_SUBJECT "subject"
00079 #define VF_CONF_HOST "host"
00080 #define VF_CONF_PORT "port"
00081 #define VF_CONF_LOGFILE "logfile"
00082 #define VF_CONF_LOGLEVEL "loglevel"
00083 #define VF_CONF_REPORT "report"
00084 #define VF_CONF_MAXCONNECTION "maxconnection"
00085 #define VF_CONF_SENDTIMEOUT "sendtimeout"
00086 #define VF_CONF_RECVTIMEOUT "recvtimeout"
00087 #define VF_CONF_TIMEOUT "timeout"
00088 #define VF_CONF_BULK "bulk"
00089 #define VF_CONF_NOMESSAGE "nomessage"
00090 #define VF_CONF_DEBUG "debug"
00091 #define VF_CONF_FOREGROUND "foreground"
00092 #define VF_CONF_HEADER "header"
00093 #define VF_CONF_PRINTLOG "printlog"
00095
00096 #define VF_USERAGENT "User-Agent: Veldfire-" VF_VERSION
00099
00100 veldfire * __veldfire_init(void);
00101 void __veldfire_defaults(veldfire *v);
00102 void __veldfire_env(veldfire *v);
00103 void __veldfire_configfile(veldfire *v);
00104 void __veldfire_commandline(veldfire *v, int ac, char *av[]);
00105 char ** __veldfire_add_header(veldfire *v, char *header);
00106 void __veldfire_cleanup(veldfire *v);
00107
00116 veldfire *
00117 VF__init(int ac, char *av[])
00118 {
00119 veldfire *v = NULL;
00120
00121 if ( (v = __veldfire_init()) == NULL) {
00122 return NULL;
00123 }
00124
00125 __veldfire_defaults(v);
00126 __veldfire_env(v);
00127 __veldfire_commandline(v, ac, av);
00128 __veldfire_configfile(v);
00129 __veldfire_commandline(v, ac, av);
00130
00131 if (VF__check_config(v) < 0) {
00132 __veldfire_cleanup(v);
00133 v = NULL;
00134 } else {
00135 v->log = RD__log_init(v->logfile, v->loglevel, 0, 1, 0, 1, 1, v->printlog);
00136 }
00137
00138 return v;
00139 }
00140
00146 void VF__cleanup(veldfire *v) { __veldfire_cleanup(v); }
00147
00154 veldfire *
00155 __veldfire_init(void)
00156 {
00157 veldfire *v = NULL;
00158
00159 if ( (v = (veldfire *) malloc(sizeof(veldfire))) ) {
00160 memset(v, 0, sizeof(veldfire));
00161 }
00162
00163 return v;
00164 }
00165
00166
00172 void
00173 __veldfire_defaults(veldfire *v)
00174 {
00175 char *p = getenv("HOME");
00176
00177 v->host = VF_DEFAULT_HOST;
00178 v->port = VF_DEFAULT_PORT;
00179 v->logfile = VF_DEFAULT_LOGFILE;
00180 v->loglevel = VF_DEFAULT_LOGLEVEL;
00181 v->configfile = VF_DEFAULT_CONFIGFILE;
00182 v->section = VF_DEFAULT_SECTION;
00183 v->maxconnection = VF_DEFAULT_MAXCONNECTION;
00184 v->sendtimeout = VF_DEFAULT_TIMEOUT;
00185 v->recvtimeout = VF_DEFAULT_TIMEOUT;
00186
00187
00188
00189
00190 __veldfire_add_header(v, VF_USERAGENT);
00191
00192
00193
00194
00195
00196
00197 if (p) {
00198 int l = strlen(p) + strlen(VF_USER_CONFIGFILE) + 2;
00199 char *cf = (char *) malloc(l);
00200 struct stat st;
00201
00202 if (cf == NULL) {
00203
00204 return;
00205 }
00206
00207 snprintf(cf, l, "%s/%s", p, VF_USER_CONFIGFILE);
00208 if (stat(cf, &st) == 0) {
00209
00211 v->configfile = cf;
00212 } else {
00213 free(cf);
00214 }
00215 }
00216 }
00217
00218
00224 void
00225 __veldfire_env(veldfire *v)
00226 {
00227 char *p;
00228
00229 if ( (p = getenv(VF_ENV_FROM)) ) v->from = p;
00230 if ( (p = getenv(VF_ENV_SUBJECT)) ) v->subject = p;
00231 if ( (p = getenv(VF_ENV_HOST)) ) v->host = p;
00232 if ( (p = getenv(VF_ENV_PORT)) ) v->port = atoi(p);
00233 if ( (p = getenv(VF_ENV_LOGFILE)) ) v->logfile = p;
00234 if ( (p = getenv(VF_ENV_LOGLEVEL)) ) v->loglevel = atoi(p);
00235 if ( (p = getenv(VF_ENV_CONFIGFILE)) ) v->configfile = p;
00236 if ( (p = getenv(VF_ENV_SECTION)) ) v->section = p;
00237 if ( (p = getenv(VF_ENV_REPORT)) ) v->report = p;
00238 if ( (p = getenv(VF_ENV_MAXCONNECTION)) ) v->maxconnection = atoi(p);
00239 if ( (p = getenv(VF_ENV_TIMEOUT)) ) {
00240 v->sendtimeout = atoi(p);
00241 v->recvtimeout = atoi(p);
00242 }
00243 if ( (p = getenv(VF_ENV_SENDTIMEOUT)) ) v->sendtimeout = atoi(p);
00244 if ( (p = getenv(VF_ENV_RECVTIMEOUT)) ) v->recvtimeout = atoi(p);
00245 if ( (p = getenv(VF_ENV_FOREGROUND)) ) v->foreground = atoi(p);
00246 if ( (p = getenv(VF_ENV_PRINTLOG)) ) v->printlog = atoi(p);
00247 }
00248
00249
00255 void
00256 __veldfire_configfile(veldfire *v)
00257 {
00258 int i;
00259 char *p;
00260 char **cp;
00261
00262 v->c = RD__conf_read_section(v->configfile, v->section);
00263
00264 if (v->c == NULL) {
00265 return;
00266 }
00267
00268 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_TO))) {
00269 v->to = p;
00270 }
00271
00272 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_FROM))) {
00273 v->from = p;
00274 }
00275
00276 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_SUBJECT))) {
00277 v->subject = p;
00278 }
00279
00280 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_HOST))) {
00281 v->host = p;
00282 }
00283
00284 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_PORT)) > 0) {
00285 v->port = i;
00286 }
00287
00288 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_LOGFILE))) {
00289 v->logfile = p;
00290 }
00291
00292 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_LOGLEVEL)) > 0) {
00293 v->loglevel = i;
00294 }
00295
00296 if ( (p = RD__conf_get_val(v->c, v->section, VF_CONF_REPORT))) {
00297 v->report = p;
00298 }
00299
00300 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_MAXCONNECTION)) > 0) {
00301 v->maxconnection = i;
00302 }
00303
00304 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_TIMEOUT)) > 0) {
00305 v->sendtimeout = i;
00306 v->recvtimeout = i;
00307 }
00308
00309 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_SENDTIMEOUT)) > 0) {
00310 v->sendtimeout = i;
00311 }
00312
00313 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_RECVTIMEOUT)) > 0) {
00314 v->recvtimeout = i;
00315 }
00316
00317 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_BULK)) > 0) {
00318 v->bulk = i;
00319 }
00320
00321 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_NOMESSAGE)) > 0) {
00322 v->nomessage = i;
00323 }
00324
00325 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_DEBUG)) > 0) {
00326 v->debug = i;
00327 }
00328
00329 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_FOREGROUND)) > 0) {
00330 v->foreground = i;
00331 }
00332
00333 if ( (i = RD__conf_get_int(v->c, v->section, VF_CONF_PRINTLOG)) > 0) {
00334 v->printlog = i;
00335 }
00336
00337
00338
00339
00340
00341 if ( (cp = RD__conf_get_vals(v->c, v->section, VF_CONF_HEADER))) {
00342 int s = 0;
00343
00344
00345
00346
00347
00348 while (cp[s]) {
00349 __veldfire_add_header(v, cp[s]);
00350 s++;
00351 }
00352 }
00353
00354 }
00355
00356
00364 void
00365 __veldfire_commandline(veldfire *v, int ac, char *av[])
00366 {
00367 int i = 1;
00368 char *p;
00369
00370 v->prog = ( (p = strrchr(av[0], '/')) && *(p + 1)) ? p + 1 : av[0];
00371
00372
00373
00374
00375
00376 for (i = 1; i < ac; i++) {
00377 if (av[i][0] == '-') {
00378 if ( ++i >= ac &&
00379 av[i - 1][1] != 'x' &&
00380 av[i - 1][1] != 'd' &&
00381 av[i - 1][1] != 'g' &&
00382 av[i - 1][1] != 'i' &&
00383 av[i - 1][1] != 'v' &&
00384 av[i - 1][1] != 'h') {
00385 VF__help(v);
00386 }
00387
00388 switch (av[i - 1][1]) {
00389 case 'f' : v->from = av[i]; break;
00390 case 't' : v->to = av[i]; break;
00391 case 's' : v->subject = av[i]; break;
00392 case 'H' : __veldfire_add_header(v, av[i]); break;
00393 case 'm' : v->host = av[i]; break;
00394 case 'p' : v->port = atoi(av[i]); break;
00395 case 'l' : v->logfile = av[i]; break;
00396 case 'e' : v->loglevel = atoi(av[i]); break;
00397 case 'c' : v->configfile = av[i]; break;
00398 case 'n' : v->section = av[i]; break;
00399 case 'r' : v->report = av[i]; break;
00400 case 'o' : v->maxconnection = atoi(av[i]); break;
00401 case 'y' : v->sendtimeout = atoi(av[i]); break;
00402 case 'z' : v->recvtimeout = atoi(av[i]); break;
00403 case 'b' : v->bulk = 1; i--; break;
00404 case 'x' : v->nomessage = 1; i--; break;
00405 case 'd' : v->debug = 1; i--; break;
00406 case 'g' : v->foreground = 1; i--; break;
00407 case 'i' : v->printlog = 1; i--; break;
00408 case 'v' : VF__version(v); break;
00409 case 'h' :
00410 case '?' :
00411 default : VF__help(v);
00412 }
00413 } else {
00414
00415 v->files = &av[i];
00416 break;
00417 }
00418 }
00419 }
00420
00430 char **
00431 __veldfire_add_header(veldfire *v, char *header)
00432 {
00433 char **tmp = v->headers;
00434 int s = 0;
00435
00436
00437
00438
00439
00440 if (v->headers) {
00441 while (v->headers[s]) {
00442
00443 if (strcmp(v->headers[s], header) == 0) {
00444 return v->headers;
00445 }
00446 s++;
00447 }
00448 }
00449
00450 if ( (v->headers = (char **)
00451 realloc(v->headers,
00452 (s + 2) * sizeof(char *))) == NULL) {
00453
00454 v->headers = tmp;
00455 return NULL;
00456 }
00457
00458
00459
00460 v->headers[s++] = header;
00461 v->headers[s] = NULL;
00462
00463 return v->headers;
00464 }
00465
00466
00474 void
00475 VF__version(veldfire *v)
00476 {
00477 printf("Veldfire-%s by Jason Armstrong <ja@riverdrums.com>\n", VF_VERSION);
00478 __veldfire_cleanup(v);
00479 exit(0);
00480 }
00481
00487 void
00488 VF__help(veldfire *v)
00489 {
00490 printf(
00491 "usage: %s [options] [files to attach]\n"
00492 "\n"
00493 " -f FROM From address\n"
00494 " -t TO To address, or addresses separated by one of: ,:;\\t\\n\n"
00495 " or file containing one address per line\n"
00496 " -s SUBJECT Subject of the email\n"
00497 " -H HEADER Add custom header field (multiple values possible)\n"
00498 " -m HOST Mail host (default %s)\n"
00499 " -p PORT Port on mail host (default %d)\n"
00500 " -l LOGFILE Log File (default %s)\n"
00501 " -e LOGLEVEL Log Level (1-6) (default %d)\n"
00502 " -c CONFIGFILE Config file (default %s)\n"
00503 " -n SECTION Section in config file (default %s)\n"
00504 " -r REPORT Email address to send a report to\n"
00505 " -o MAXCONNECTION Maximum number of emails in one connection (default %d)\n"
00506 " -y SENDTIMEOUT Timeout for sending data\n"
00507 " -z RECVTIMEOUT Timeout for reading data\n"
00508
00509 " -x No message (don't wait for a msg on stdin)\n"
00510 " -g Foreground (don't fork to the background)\n"
00511 " -i Log to stdout as well as to the log file\n"
00512
00513 " -h Help\n"
00514 " -v Version\n"
00515 "\n"
00516 "Email format: J Smith <j@smith.com> | j@smith.com | <j@smith.com>\n"
00517 "Messages are read from stdin, and can be already formatted multi-part messages\n"
00518 "\n", v->prog,
00519 VF_DEFAULT_HOST, VF_DEFAULT_PORT,
00520 VF_DEFAULT_LOGFILE, VF_DEFAULT_LOGLEVEL,
00521 VF_DEFAULT_CONFIGFILE, VF_DEFAULT_SECTION,
00522 VF_DEFAULT_MAXCONNECTION);
00523
00524 __veldfire_cleanup(v);
00525 exit(0);
00526 }
00527
00533 void
00534 __veldfire_cleanup(veldfire *v)
00535 {
00536 if (v) {
00537 if (v->c) RD__conf_free(v->c);
00538 if (v->msg && v->freemsg) free(v->msg);
00539
00540
00541 if (v->headers) free(v->headers);
00542 if (v->log) RD__log_free(v->log);
00543 free(v);
00544 }
00545 }
00546
00557 int
00558 VF__check_config(veldfire *v)
00559 {
00560 int rc = 0;
00561
00562 if (v->to == NULL) {
00563 rc = -1;
00564 fprintf(stderr, "Missing 'to' address\n");
00565 }
00566
00567
00568
00569
00570
00571 if (v->files) {
00572 int s = 0;
00573 struct stat st;
00574
00575 while (v->files[s]) {
00576 if (stat(v->files[s], &st) < 0) {
00577 fprintf(stderr, "%s - %s\n", v->files[s], strerror(errno));
00578 rc = -1;
00579 } else {
00580 if ( !(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) ) {
00581 fprintf(stderr, "%s must be a file or a link to a file\n", v->files[s]);
00582 rc = -1;
00583 } else {
00584 FILE *fp = fopen(v->files[s], "r");
00585
00586
00587 if (fp == NULL) {
00588 fprintf(stderr, "%s - %s\n", v->files[s], strerror(errno));
00589 rc = -1;
00590 } else {
00591 fclose(fp);
00592 }
00593 }
00594 }
00595 s++;
00596 }
00597 }
00598
00599 if (rc < 0) {
00600 VF__help(v);
00601 }
00602
00603 return rc;
00604 }
00605
00612 char *
00613 VF__get_msg(veldfire *v)
00614 {
00615 char *r = NULL, *t = NULL;
00616 int c, s = 0, l = 0;
00617
00618 if (v->nomessage) {
00619 v->freemsg = 1;
00620 return (strdup(""));
00621 }
00622
00623 if (isatty(fileno(stdin))) {
00624 printf("Your message please, end with EOF (^D):\n");
00625 fflush(stdout);
00626 }
00627
00628 while ( (c = fgetc(stdin)) != EOF) {
00629 if (l >= s) {
00630 t = r;
00631 if ( (r = realloc(r, s + VF_READ_BUFSIZE + 3)) == NULL) {
00632 v->freemsg = 0;
00633 if (t) free(t);
00634 return NULL;
00635 }
00636 s += VF_READ_BUFSIZE + 1;
00637 }
00638
00639
00640 if ( (c == '\r' || c == '\n') && l > 2 &&
00641 r[l - 1] == '.' && r[l - 2] == '\n') {
00642 r[l++] = '.';
00643 }
00644
00645 r[l++] = c;
00646 }
00647
00648 if (r && l) {
00649 r[l] = 0;
00650 }
00651
00652 v->freemsg = 1;
00653
00654 return r;
00655 }
00656
00657 #ifdef INITTEST
00658
00659 void
00660 _print_vf(veldfire *v)
00661 {
00662 if (v == NULL) {
00663 return;
00664 }
00665 printf("Name : %s\n", v->prog ? v->prog : "(none)");
00666 printf("Config File : %s\n", v->configfile ? v->configfile : "(none)");
00667 printf("Section : %s\n", v->section ? v->section : "(none)");
00668 printf("LogFile : %s\n", v->logfile ? v->logfile : "(none)");
00669 printf("LogLevel : %d\n", v->loglevel);
00670 printf("Mail host : %s\n", v->host ? v->host : "(none)");
00671 printf("Mailport : %d\n", v->port);
00672 printf("From : %s\n", v->from ? v->from : "(none)");
00673 printf("To : %s\n", v->to ? v->to : "(none)");
00674 printf("Report : %s\n", v->report ? v->report : "(none)");
00675 printf("Subject : %s\n", v->subject ? v->subject : "(none)");
00676 printf("Bulk : %d\n", v->bulk);
00677 printf("No Message : %d\n", v->nomessage);
00678 printf("Debug : %d\n", v->debug);
00679 printf("Foreground : %d\n", v->foreground);
00680 printf("Printlog : %d\n", v->printlog);
00681 printf("MaxConnection : %d\n", v->maxconnection);
00682 printf("Timeout Snd : %d\n", v->sendtimeout);
00683 printf("Timeout Rcv : %d\n", v->recvtimeout);
00684 printf("Msg : %s\n", v->msg ? v->msg : "(none)");
00685
00686 if (v->files) {
00687 int s = 0;
00688 while (v->files[s]) {
00689 printf("File : %s\n", v->files[s++]);
00690 }
00691 }
00692
00693 if (v->headers) {
00694 int s = 0;
00695 while (v->headers[s]) {
00696 printf("Header: %s\n", v->headers[s++]);
00697 }
00698 }
00699 }
00700
00701 int main(int argc, char *argv[]) {
00702 veldfire *v = VF__init(argc, argv);
00703 if (v) {
00704 v->msg = VF__get_msg(v);
00705 _print_vf(v);
00706 }
00707 VF__cleanup(v);
00708
00709 return 0;
00710 }
00711
00712
00713 #endif