/** * This function takes the current content that was copied * in to us and creates a final message with the email header * and the appended content. It will also attach any files * that were specified at the command line. **/ static void printHeaders(const char *border, dstrbuf *msg, CharSetType msg_cs) { char *subject=Mopts.subject; char *user_name = getConfValue("MY_NAME"); char *email_addr = getConfValue("MY_EMAIL"); char *sm_bin = getConfValue("SENDMAIL_BIN"); char *smtp_serv = getConfValue("SMTP_SERVER"); char *reply_to = getConfValue("REPLY_TO"); dstrbuf *dsb=NULL; if (subject) { if (Mopts.encoding) { CharSetType cs = getCharSet((u_char *)subject); if (cs == IS_UTF8) { dsb = encodeUtf8String((u_char *)subject, false); subject = dsb->str; } else if (cs == IS_PARTIAL_UTF8) { dsb = encodeUtf8String((u_char *)subject, true); subject = dsb->str; } } dsbPrintf(msg, "Subject: %s\r\n", subject); if (dsb) { dsbDestroy(dsb); } } printFromHeaders(user_name, email_addr, msg); printToHeaders(Mopts.to, Mopts.cc, msg); /** * We want to check here to see if we are sending mail by invoking sendmail * If so, We want to add the BCC line to the headers. Sendmail checks this * Line and makes sure it sends the mail to the BCC people, and then remove * the BCC addresses... Keep in mind that sending to an smtp servers takes * presidence over sending to sendmail incase both are mentioned. */ if (sm_bin && !smtp_serv) { printBccHeaders(Mopts.bcc, msg); } /* The rest of the standard headers */ printDateHeaders(msg); if (reply_to) { dsbPrintf(msg, "Reply-To: <%s>\r\n", reply_to); } printMimeHeaders(border, msg, msg_cs); dsbPrintf(msg, "X-Mailer: Cleancode.email v%s \r\n", EMAIL_VERSION); if (Mopts.priority) { dsbPrintf(msg, "X-Priority: 1\r\n"); } printExtraHeaders(Mopts.headers, msg); dsbPrintf(msg, "\r\n"); }
/** * will save the sent email if a place is specified in the * configuration file It will append each email to one particular * file called 'email.sent' **/ static int saveSentEmail(dstrbuf *msg) { FILE *save; char *save_file = NULL; dstrbuf *path; save_file = getConfValue("SAVE_SENT_MAIL"); if (!save_file) { return ERROR; } path = expandPath(save_file); dsbCat(path, "/email.sent"); if (!(save = fopen(path->str, "a"))) { warning("Could not open file: %s", path->str); dsbDestroy(path); return ERROR; } fputs(msg->str, save); fflush(save); fclose(save); return SUCCESS; }
/** * Gets the users smtp password from the configuration file. * if it does not exist, it will prompt them for it. **/ static char * getSmtpPass(void) { char *retval = getConfValue("SMTP_AUTH_PASS"); if (!retval) { retval = getpass("Enter your SMTP Password: "); } return retval; }
/** * This function does all the required SMTP connection * and commands. It will send the e-mail we specified * and use the remote smtp server if there is one, otherwise * it will get it out of the config variable **/ int sendmail(dstrbuf *mail) { int smtp_port; char *smtp_serv, *sm_bin; int index=0; int testprocess=0; smtp_serv = getConfValue("SMTP_SERVER"); sm_bin = getConfValue("SENDMAIL_BIN"); if (smtp_serv) { smtp_port = atoi(getConfValue("SMTP_PORT")); testprocess = processRemote(smtp_serv, smtp_port, mail) ; while(testprocess != 221 && index <10) { testprocess = processRemote(smtp_serv, smtp_port, mail) ; index++; if(index==10) { return ERROR; } } /* if (processRemote(smtp_serv, smtp_port, mail) == ERROR) { return ERROR; }*/ } #if 0 else if (sm_bin) { if (processInternal(sm_bin, mail) == ERROR) { return ERROR; } } else { fprintf(stderr, "No SMTP server specified!\n"); return ERROR; } #endif if (saveSentEmail(mail) == ERROR) { return ERROR; } return TRUE; }
static int writeResponse(dsocket *sd, char *line, ...) { va_list vp; int sval, size=MAXBUF, bytes=0; struct timeval tv; fd_set wfds; char *buf = xmalloc(size+1); char *timeout = getConfValue("TIMEOUT"); while (true) { va_start(vp, line); bytes = vsnprintf(buf, size, line, vp); va_end(vp); if (bytes > -1 && bytes < size) { /* String written properly */ break; } if (bytes > -1) { size += 1; } else { size *= 2; } buf = xrealloc(buf, size+1); } FD_ZERO(&wfds); FD_SET(dnetGetSock(sd), &wfds); if (timeout) { tv.tv_sec = atoi(timeout); } else { tv.tv_sec = 10; } tv.tv_usec = 0; sval = select(dnetGetSock(sd)+1, NULL, &wfds, NULL, &tv); if (sval == -1) { smtpSetErr("writeResponse: select error"); bytes = ERROR; } else if (sval) { dnetWrite(sd, buf, bytes); if (dnetErr(sd)) { smtpSetErr(dnetGetErr(sd)); bytes = ERROR; } } else { smtpSetErr("Timeout(10) trying to write to SMTP server."); bytes = ERROR; } xfree(buf); return bytes; }
/** * Reads a line from the smtp server using sgets(). * It will continue to read the response until the 4th character * in the line is found to be a space. Per the RFC 821 this means * that this will be the last line of response from the SMTP server * and the appropirate return value response. */ static int readResponse(dsocket *sd, dstrbuf *buf) { int retval=ERROR; dstrbuf *tmpbuf = DSB_NEW; struct timeval tv; fd_set rfds; char *timeout = getConfValue("TIMEOUT"); int readsize = 0; FD_ZERO(&rfds); FD_SET(dnetGetSock(sd), &rfds); if (timeout) { tv.tv_sec = atoi(timeout); } else { tv.tv_sec = 10; } tv.tv_usec = 0; (void) select(dnetGetSock(sd)+1, &rfds, NULL, NULL, &tv); if (FD_ISSET(dnetGetSock(sd), &rfds)) { do { dsbClear(tmpbuf); readsize = dnetReadline(sd, tmpbuf); if ((dnetErr(sd)) || (readsize <= 0)) { smtpSetErr("Lost connection with SMTP server"); retval = ERROR; break; } dsbCat(buf, tmpbuf->str); retval = SUCCESS; /* The last line of a response has a space in the 4th column */ } while (tmpbuf->str[3] != ' '); } else { smtpSetErr("Timeout(10) while trying to read from SMTP server"); retval = ERROR; } if (retval != ERROR) { retval = atoi(tmpbuf->str); } dsbDestroy(tmpbuf); return retval; }
int main(int argc, char **argv) { int get; int opt_index = 0; /* for getopt */ char *cc_string = NULL; char *bcc_string = NULL; const char *opts = "f:n:a:p:oVedvtb?c:s:r:u:i:g:m:H:x:"; /* Set certian global options to NULL */ conf_file = NULL; memset(&Mopts, 0, sizeof(struct mailer_options)); Mopts.encoding = true; /* Check if they need help */ if ((argc > 1) && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help"))) { if (argc == 3) { moduleUsage(argv[2]); } else if (argc == 2) { usage(); } else { fprintf(stderr, "Only specify one option with %s: \n", argv[1]); usage(); } } table = dhInit(28, defaultDestr); if (!table) { fprintf(stderr, "ERROR: Could not initialize Hash table.\n"); exit(0); } while ((get = getopt_long_only(argc, argv, opts, Gopts, &opt_index)) > EOF) { switch (get) { case 'n': setConfValue("MY_NAME", xstrdup(optarg)); break; case 'f': setConfValue("MY_EMAIL", xstrdup(optarg)); break; case 'a': if (!Mopts.attach) { Mopts.attach = dlInit(defaultDestr); } dlInsertTop(Mopts.attach, xstrdup(optarg)); break; case 'V': Mopts.verbose = true; break; case 'p': setConfValue("SMTP_PORT", xstrdup(optarg)); break; case 'o': Mopts.priority = 1; break; case 'e': Mopts.gpg_opts |= GPG_ENC; break; case 's': Mopts.subject = optarg; break; case 'r': setConfValue("SMTP_SERVER", xstrdup(optarg)); break; case 'c': conf_file = optarg; break; case 't': checkConfig(); printf("Configuration file is proper.\n"); dhDestroy(table); return (0); break; case 'v': printf("email - By Dean Jones; Version %s\n", EMAIL_VERSION); dhDestroy(table); exit(EXIT_SUCCESS); break; case 'b': Mopts.blank = 1; break; case 'u': setConfValue("SMTP_AUTH_USER", xstrdup(optarg)); break; case 'i': setConfValue("SMTP_AUTH_PASS", xstrdup(optarg)); break; case 'm': setConfValue("SMTP_AUTH", xstrdup(optarg)); break; case 'g': setConfValue("GPG_PASS", xstrdup(optarg)); break; case 'H': if (!Mopts.headers) { Mopts.headers = dlInit(defaultDestr); } dlInsertTop(Mopts.headers, xstrdup(optarg)); break; case 'x': setConfValue("TIMEOUT", xstrdup(optarg)); break; case '?': usage(); break; case 1: Mopts.html = 1; break; case 2: Mopts.gpg_opts |= GPG_SIG; break; case 3: cc_string = optarg; break; case 4: bcc_string = optarg; break; case 5: /* To name? */ break; case 6: setConfValue("USE_TLS", xstrdup("true")); break; case 7: Mopts.encoding = false; break; default: /* Print an error message here */ usage(); break; } } /* first let's check to make sure they specified some recipients */ if (optind == argc) { usage(); } configure(); /* Check to see if we need to attach a vcard. */ if (getConfValue("VCARD")) { dstrbuf *vcard = expandPath(getConfValue("VCARD")); if (!Mopts.attach) { Mopts.attach = dlInit(defaultDestr); } dlInsertTop(Mopts.attach, xstrdup(vcard->str)); dsbDestroy(vcard); } /* set to addresses if argc is > 1 */ if (!(Mopts.to = getNames(argv[optind]))) { fatal("You must specify at least one recipient!\n"); properExit(ERROR); } /* Set CC and BCC addresses */ if (cc_string) { Mopts.cc = getNames(cc_string); } if (bcc_string) { Mopts.bcc = getNames(bcc_string); } signal(SIGTERM, properExit); signal(SIGINT, properExit); signal(SIGPIPE, properExit); signal(SIGHUP, properExit); signal(SIGQUIT, properExit); createMail(); properExit(0); /* We never get here, but gcc will whine if i don't return something */ return 0; }
/** * This function will take the FILE and process it via a * Remote SMTP server... **/ int processRemote(const char *smtp_serv, int smtp_port, dstrbuf *msg) { dsocket *sd; int retval=0, bytes; char *smtp_auth=NULL; char *email_addr=NULL; char *use_tls=NULL; char *user=NULL, *pass=NULL; struct prbar *bar=NULL; char nodename[MAXBUF] = { 0 }; char *ptr = msg->str; struct addr *next=NULL; email_addr = getConfValue("MY_EMAIL"); if (gethostname(nodename, sizeof(nodename) - 1) < 0) { snprintf(nodename, sizeof(nodename) - 1, "geek"); } /* Get other possible configuration values */ smtp_auth = getConfValue("SMTP_AUTH"); if (smtp_auth) { user = getConfValue("SMTP_AUTH_USER"); if (!user) { fatal("You must set SMTP_AUTH_USER in order to user SMTP_AUTH\n"); return ERROR; } pass = getSmtpPass(); if (!pass) { fatal("Failed to get SMTP Password.\n"); return ERROR; } } bar = prbarInit(msg->len); if (Mopts.verbose) { printf("Connecting to server %s on port %d\n", smtp_serv, smtp_port); } sd = dnetConnect(smtp_serv, smtp_port); if (sd == NULL) { fatal("Could not connect to server: %s on port: %d", smtp_serv, smtp_port); return ERROR; } /* Start SMTP Communications */ if (smtpInit(sd, nodename) == ERROR) { printSmtpError(); goto end; } /* Use TLS? */ use_tls = getConfValue("USE_TLS"); #ifndef HAVE_LIBSSL if (use_tls) { warning("No SSL support compiled in. Disabling TLS.\n"); use_tls = NULL; } #endif if (use_tls && strcasecmp(use_tls, "true") == 0) { if (smtpStartTls(sd) != ERROR) { dnetUseTls(sd); dnetVerifyCert(sd); if (smtpInitAfterTLS(sd, nodename) == ERROR) { printSmtpError(); goto end; } } else { printSmtpError(); goto end; } } /* See if we're using SMTP_AUTH. */ if (smtp_auth) { retval = smtpInitAuth(sd, smtp_auth, user, pass); if (retval == ERROR) { printSmtpError(); goto end; } } retval = smtpSetMailFrom(sd, email_addr); if (retval == ERROR) { printSmtpError(); goto end; } while ((next = (struct addr *)dlGetNext(Mopts.to)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } while ((next = (struct addr *)dlGetNext(Mopts.cc)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } while ((next = (struct addr *)dlGetNext(Mopts.bcc)) != NULL) { retval = smtpSetRcpt(sd, next->email); if (retval == ERROR) { printSmtpError(); goto end; } } retval = smtpStartData(sd); if (retval == ERROR) { printSmtpError(); goto end; } while (*ptr != '\0') { bytes = strlen(ptr); if (bytes > CHUNK_BYTES) { bytes = CHUNK_BYTES; } retval = smtpSendData(sd, ptr, bytes); if (retval == ERROR) { goto end; } if (Mopts.verbose && bar != NULL) { prbarPrint(bytes, bar); } ptr += bytes; } retval = smtpEndData(sd); if (retval != ERROR) { retval = smtpQuit(sd); } end: prbarDestroy(bar); dnetClose(sd); return retval; }