/** * just prints the to headers, and cc headers if available **/ static void printToHeaders(dlist to, dlist cc, dstrbuf *msg) { struct addr *a = (struct addr *)dlGetNext(to); dsbPrintf(msg, "To: "); while (a) { dstrbuf *tmp = formatEmailAddr(a->name, a->email); dsbPrintf(msg, "%s", tmp->str); dsbDestroy(tmp); a = (struct addr *)dlGetNext(to); if (a != NULL) { dsbPrintf(msg, ", "); } else { dsbPrintf(msg, "\r\n"); } } if (cc != NULL) { dsbPrintf(msg, "Cc: "); a = (struct addr *)dlGetNext(cc); while (a) { dstrbuf *tmp = formatEmailAddr(a->name, a->email); dsbPrintf(msg, "%s", tmp->str); dsbDestroy(tmp); a = (struct addr *)dlGetNext(cc); if (a != NULL) { dsbPrintf(msg, ", "); } else { dsbPrintf(msg, "\r\n"); } } } }
/** * Creates a plain text (or html) email and * specifies the necessary MIME types if needed * due to attaching base64 files. * when this function is done, it will rewind * the file position and return an open file **/ static dstrbuf * createPlainEmail(dstrbuf *msg) { dstrbuf *border=NULL; dstrbuf *buf=DSB_NEW; CharSetType cs; if (Mopts.attach) { border = mimeMakeBoundary(); } else { border = DSB_NEW; } if (Mopts.encoding) { cs = getCharSet((u_char *)msg->str); } else { cs = IS_ASCII; } printHeaders(border->str, buf, cs); if (makeMessage(msg, buf, border->str, cs) < 0) { dsbDestroy(buf); buf=NULL; } dsbDestroy(border); return buf; }
/** * this is the function that takes over from main(). * It will call all functions nessicary to finish off the * rest of the program and then return properly. **/ void createMail(void) { dstrbuf *msg=NULL, *full_msg=NULL; char subject[MAXBUF]={0}; /** * first let's check if someone has tried to send stuff in from STDIN * if they have, let's call a read to stdin */ if (isatty(STDIN_FILENO) == 0) { msg = readInput(); if (!msg) { fatal("Problem reading from STDIN redirect\n"); properExit(ERROR); } } else { /* If they aren't sending a blank email */ if (!Mopts.blank) { /* let's check if they want to add a subject or not */ if (Mopts.subject == NULL) { fprintf(stderr, "Subject: "); fgets(subject, sizeof(subject)-1, stdin); chomp(subject); Mopts.subject = subject; } /* Now we need to let them create a file */ msg = editEmail(); if (!msg) { properExit(ERROR); } } else { /* Create a blank message */ msg = DSB_NEW; } } /* Create a message according to the type */ if (Mopts.gpg_opts) { full_msg = createGpgEmail(msg, Mopts.gpg_opts); } else { full_msg = createPlainEmail(msg); } if (!full_msg) { deadLetter(msg); dsbDestroy(msg); properExit(ERROR); } dsbDestroy(msg); int retsend = sendmail(full_msg); dsbDestroy(full_msg); if (retsend == ERROR) { properExit(ERROR); } }
/** * ModuleUsage will take an argument for the specified * module and print out help information on the topic. * information is stored in a written file in the location * in Macro EMAIL_DIR. and also specified with EMAIL_HELP_FILE */ static void moduleUsage(const char *module) { FILE *help=NULL; short found=0; char *moduleptr=NULL; dstrbuf *buf = DSB_NEW; dstrbuf *help_file = expandPath(EMAIL_HELP_FILE); if (!(help = fopen(help_file->str, "r"))) { fatal("Could not open help file: %s", help_file->str); dsbDestroy(help_file); properExit(ERROR); } dsbDestroy(help_file); while (!feof(help)) { dsbReadline(buf, help); if ((buf->str[0] == '#') || (buf->str[0] == '\n')) { continue; } chomp(buf->str); moduleptr = strtok(buf->str, "|"); if (strcasecmp(moduleptr, module) != 0) { while ((moduleptr = strtok(NULL, "|")) != NULL) { if (strcasecmp(moduleptr, module) == 0) { found = 1; break; } } } else { found = 1; } if (!found) { continue; } while (!feof(help)) { dsbReadline(buf, help); if (!strcmp(buf->str, "EOH\n")) { break; } printf("%s", buf->str); } break; } if (feof(help)) { printf("There is no help in the module: %s\n", module); usage(); } dsbDestroy(buf); fclose(help); exit(0); }
int copyfile(const char *from, const char *to) { FILE *ffrom, *fto; dstrbuf *buf=NULL; ffrom = fopen(from, "r"); fto = fopen(to, "w"); if (!ffrom || !fto) { return -1; } buf = DSB_NEW; while (dsbFread(buf, MAXBUF, ffrom) > 0) { fwrite(buf->str, sizeof(char), buf->len, fto); dsbClear(buf); } dsbDestroy(buf); fclose(ffrom); fclose(fto); if (ferror(ffrom) || ferror(fto)) { return -1; } return 0; }
/** * Takes a string and breaks it up based on a specific character * and returns it in a dvector */ dvector explode(const char *str, const char *delim) { bool found=false; const char *ptr=str, *dtmp=NULL; dstrbuf *buf = dsbNew(100); dvector vec = dvCreate(5, __strexplodeDestr); while (*ptr != '\0') { dtmp = delim; while (*dtmp != '\0') { if (*ptr == *dtmp) { if (buf->len > 0) { dvAddItem(&vec, xstrdup(buf->str)); dsbClear(buf); } found = true; break; } dtmp++; } if (!found) { dsbCatChar(buf, *ptr); } else { found = false; } ptr++; } /* Add the last element if there was one. */ if (buf->len > 0) { dvAddItem(&vec, xstrdup(buf->str)); } dsbDestroy(buf); return vec; }
static int ehlo(dsocket *sd, const char *domain) { int retval; dstrbuf *rbuf = DSB_NEW; if (writeResponse(sd, "EHLO %s\r\n", domain) < 0) { smtpSetErr("Lost connection to SMTP server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n--> EHLO %s\r\n", domain); fflush(stdout); #endif retval = readResponse(sd, rbuf); if (retval != 250) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n<-- %s", rbuf->str); fflush(stdout); #endif end: dsbDestroy(rbuf); return retval; }
/** * 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; }
/** * Makes a message type specifically for gpg encryption and * signing. Specific MIME message descriptions are needed * when signing/encrypting a file before it is actuall signed * or encrypted. This function takes care of that. **/ static int makeGpgMessage(dstrbuf *in, dstrbuf *out, const char *border) { dstrbuf *qp=NULL; assert(in != NULL); assert(out != NULL); assert(border != NULL); if (Mopts.attach) { dsbPrintf(out, "Content-Type: multipart/mixed; " "boundary=\"%s\"\r\n\r\n", border); dsbPrintf(out, "\r\n--%s\r\n", border); } if (Mopts.html) { dsbPrintf(out, "Content-Type: text/html\r\n"); } else { dsbPrintf(out, "Content-Type: text/plain\r\n"); } dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n\r\n"); qp = mimeQpEncodeString((u_char *)in->str, true); dsbnCat(out, qp->str, qp->len); dsbDestroy(qp); if (Mopts.attach) { attachFiles(border, out); dsbPrintf(out, "\r\n--%s--\r\n", border); } return 0; }
/** Print From Headers **/ static void printFromHeaders(char *name, char *address, dstrbuf *msg) { dstrbuf *addr = formatEmailAddr(name, address); dsbPrintf(msg, "From: %s\r\n", addr->str); dsbDestroy(addr); }
int data(dsocket *sd) { int retval = 0; dstrbuf *rbuf = DSB_NEW; /* Create the DATA command and send it */ if (writeResponse(sd, "DATA\r\n") < 0) { smtpSetErr("Lost connection with SMTP server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n--> DATA\r\n"); #endif /* Read return message and let's return it's code */ retval = readResponse(sd, rbuf); if (retval != 354) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("<-- %s", rbuf->str); #endif end: dsbDestroy(rbuf); return retval; }
/** * Send the QUIT command */ static int quit(dsocket *sd) { int retval = 0; dstrbuf *rbuf = DSB_NEW; /* Create QUIT command and send it */ if (writeResponse(sd, "QUIT\r\n") < 0) { smtpSetErr("Lost Connection with SMTP server: Quit()"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("--> QUIT\r\n"); #endif retval = readResponse(sd, rbuf); if (retval != 221) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("<-- %s", rbuf->str); #endif end: dsbDestroy(rbuf); return retval; }
/** * Exit just handles all the signals and exiting of the * program by freeing the allocated memory and writing * the dead.letter if we had a sudden interrupt... **/ void properExit(int sig) { if (sig != 0 && global_msg) { deadLetter(); } dsbDestroy(global_msg); /* Free lists */ if (Mopts.attach) { dlDestroy(Mopts.attach); } if (Mopts.headers) { dlDestroy(Mopts.headers); } if (Mopts.to) { dlDestroy(Mopts.to); } if (Mopts.cc) { dlDestroy(Mopts.cc); } if (Mopts.bcc) { dlDestroy(Mopts.bcc); } dhDestroy(table); exit(sig); }
/** * Send the MAIL FROM: command to the smtp server */ static int mailFrom(dsocket *sd, const char *email) { int retval = 0; dstrbuf *rbuf = DSB_NEW; /* Create the MAIL FROM: command */ if (writeResponse(sd, "MAIL FROM:<%s>\r\n", email) < 0) { smtpSetErr("Lost connection with SMTP server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n--> MAIL FROM:<%s>\r\n", email); #endif /* read return message and let's return it's code */ retval = readResponse(sd, rbuf); if (retval != 250) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n<-- %s", rbuf->str); #endif end: dsbDestroy(rbuf); return retval; }
/** * set up the appropriate MIME and Base64 headers for * the attachment of file specified in Mopts.attach **/ static int attachFiles(const char *boundary, dstrbuf *out) { dstrbuf *file_name = NULL; dstrbuf *file_type = NULL; char *next_file = NULL; /* * What we will do here is parse Mopts.attach for comma delimited file * names. If there was only one file specified with no comma, then strtok() * will just return that file and the next call to strtok() will be NULL * which will allow use to break out of our loop of attaching base64 stuff. */ while ((next_file = (char *)dlGetNext(Mopts.attach)) != NULL) { FILE *current = fopen(next_file, "r"); if (!current) { #if 1 //Ren: to skip nonexistent file fprintf(stderr, "email: skip %s\n", next_file); continue; #else fatal("Could not open attachment: %s", next_file); return (ERROR); #endif } /* If the user specified an absolute path, just get the file name */ file_type = mimeFiletype(next_file); file_name = mimeFilename(next_file); /* Set our MIME headers */ dsbPrintf(out, "\r\n--%s\r\n", boundary); dsbPrintf(out, "Content-Transfer-Encoding: base64\r\n"); dsbPrintf(out, "Content-Type: %s; name=\"%s\"\r\n", file_type->str, file_name->str); dsbPrintf(out, "Content-Disposition: attachment; filename=\"%s\"\r\n", file_name->str); dsbPrintf(out, "\r\n"); /* Encode to 'out' */ mimeB64EncodeFile(current, out); dsbDestroy(file_type); dsbDestroy(file_name); } return SUCCESS; }
/** * Makes a message type specifically for gpg encryption and * signing. Specific MIME message descriptions are needed * when signing/encrypting a file before it is actuall signed * or encrypted. This function takes care of that. **/ static int makeGpgMessage(dstrbuf *in, dstrbuf *out, const char *border) { char *ptr=NULL; dstrbuf *qp=NULL; assert(in != NULL); assert(out != NULL); assert(border != NULL); if (Mopts.attach) { dsbPrintf(out, "Content-Type: multipart/mixed; " "boundary=\"%s\"\r\n\r\n", border); dsbPrintf(out, "\r\n--%s\r\n", border); } if (Mopts.html) { dsbPrintf(out, "Content-Type: text/html\r\n"); } else { dsbPrintf(out, "Content-Type: text/plain\r\n"); } dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n\r\n"); qp = mimeQpEncodeString((u_char *)in->str, true); /* Fix single dot on it's on line so we don't terminate the message prematurely. */ dstrbuf *formatted = DSB_NEW; char previous='\0'; for (ptr = qp->str; ptr && *ptr != '\0'; previous=*ptr, ptr++) { dsbCatChar(formatted, *ptr); /* If we have a dot starting on a newline. */ if ((previous == '\n' || previous == '\r') && *ptr == '.') { dsbCatChar(formatted, '.'); } } dsbDestroy(qp); dsbnCat(out, formatted->str, formatted->len); dsbDestroy(formatted); if (Mopts.attach) { attachFiles(border, out); dsbPrintf(out, "\r\n--%s--\r\n", border); } return 0; }
/** * Sends the QUIT\r\n signal to the smtp server. * * Params * sd - Socket Descriptor * * Return * - ERROR * - SUCCESS */ int smtpQuit(dsocket *sd) { int retval=0; printProgress("Sending QUIT..."); retval = quit(sd); dsbDestroy(errorstr); return retval; }
/** * 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"); }
/** * checks to see if the TEMP_FILE is around... if it is * it will move it to the users home directory as dead.letter. **/ static void deadLetter() { dstrbuf *path = expandPath("~/dead.letter"); FILE *out = fopen(path->str, "w"); if (!out || !global_msg) { warning("Could not save dead letter to %s", path->str); } else { fwrite(global_msg->str, sizeof(char), global_msg->len, out); } dsbDestroy(path); }
/** * takes a string that is a supposed file path, and * checks for certian wildcards ( like ~ for home directory ) * and resolves to an actual absolute path. **/ dstrbuf * expandPath(const char *path) { struct passwd *pw = NULL; dstrbuf *tmp = DSB_NEW; dstrbuf *ret = DSB_NEW; dsbCopy(tmp, path); if (tmp->len > 0 && tmp->str[0] == '&') { dsbCopy(ret, EMAIL_DIR); } else if (tmp->len > 0 && tmp->str[0] == '~') { if (tmp->str[1] == '/') { pw = getpwuid(getuid()); } else { int pos = strfind(tmp->str, '/'); if (pos >= 0) { char *p = substr(tmp->str, 1, pos-1); if (p) { pw = getpwnam(p); xfree(p); } } if (!pw) { pw = getpwuid(getuid()); } } if (pw) { dsbCopy(ret, pw->pw_dir); } } if (ret->len > 0) { int pos = strfind(tmp->str, '/'); if (pos > 0) { char *p = substr(tmp->str, pos, tmp->len); if (p) { dsbCat(ret, p); xfree(p); } } } else { dsbCopy(ret, path); } dsbDestroy(tmp); return ret; }
dstrbuf * encodeUtf8String(const u_char *str, bool use_qp) { const u_int max_blk_len = 45; u_int i=max_blk_len; dstrbuf *enc, *dsb = DSB_NEW; size_t len = strlen((char *)str); if (use_qp) { // TODO: We need to break this up so that we're not // creating extra long strings. enc = mimeQpEncodeString(str, false); dsbPrintf(dsb, "=?utf-8?q?%s?=", enc->str); i = len; // Just reset for now. } else { enc = mimeB64EncodeString(str, (len > max_blk_len ? max_blk_len : len), false); dsbPrintf(dsb, "=?utf-8?b?%s?=", enc->str); } dsbDestroy(enc); /* If we have anymore data to encode, we have to do it by adding a newline plus a space because each section can only be 75 chars long. */ while (i < len) { size_t newlen = strlen((char *)str + i); /* only allow max_blk_len sections */ if (newlen > max_blk_len) { newlen = max_blk_len; } enc = mimeB64EncodeString(str + i, newlen, false); dsbPrintf(dsb, "\r\n =?utf-8?b?%s?=", enc->str); dsbDestroy(enc); i += newlen; } return dsb; }
/** * Creates a signed message with gpg and takes into * account the correct MIME message types to add to * the message. **/ static dstrbuf * createGpgEmail(dstrbuf *msg, GpgCallType gpg_type) { dstrbuf *tmpbuf=DSB_NEW; dstrbuf *gpgdata=NULL, *buf=DSB_NEW; dstrbuf *border1=NULL, *border2=NULL; assert(msg != NULL); /* Create two borders if we're attaching files */ border1 = mimeMakeBoundary(); if (Mopts.attach) { border2 = mimeMakeBoundary(); } else { border2 = DSB_NEW; } if (makeGpgMessage(msg, tmpbuf, border2->str) < 0) { dsbDestroy(buf); buf=NULL; goto end; } gpgdata = callGpg(tmpbuf, gpg_type); if (!gpgdata) { dsbDestroy(buf); buf=NULL; goto end; } printHeaders(border1->str, buf, IS_ASCII); dsbPrintf(buf, "\r\n--%s\r\n", border1->str); if (gpg_type & GPG_ENC) { dsbPrintf(buf, "Content-Type: application/pgp-encrypted\r\n\r\n"); dsbPrintf(buf, "Version: 1\r\n"); dsbPrintf(buf, "\r\n--%s\r\n", border1->str); dsbPrintf(buf, "Content-type: application/octet-stream; " "name=encrypted.asc\r\n\r\n"); } else if (gpg_type & GPG_SIG) { dsbPrintf(buf, "%s\r\n", tmpbuf->str); dsbPrintf(buf, "\r\n--%s\r\n", border1->str); dsbPrintf(buf, "Content-Type: application/pgp-signature\r\n"); dsbPrintf(buf, "Content-Description: This is a digitally signed message\r\n\r\n"); } dsbPrintf(buf, "%s", gpgdata->str); dsbPrintf(buf, "\r\n--%s--\r\n", border1->str); end: dsbDestroy(tmpbuf); dsbDestroy(gpgdata); dsbDestroy(border1); dsbDestroy(border2); return buf; }
/** * Makes a standard plain text message while taking into * account the MIME message types and boundary's needed * if and when a file is attached. **/ static int makeMessage(dstrbuf *in, dstrbuf *out, const char *border, CharSetType charset) { dstrbuf *enc=NULL; if (Mopts.attach) { dsbPrintf(out, "--%s\r\n", border); if (charset == IS_UTF8 || charset == IS_PARTIAL_UTF8) { dsbPrintf(out, "Content-Type: text/plain; charset=utf-8\r\n"); if (IS_PARTIAL_UTF8) { dsbPrintf(out, "Content-Transfer-Encoding: quoted-printable\r\n"); enc = mimeQpEncodeString((u_char *)in->str, true); } else { dsbPrintf(out, "Content-Transfer-Encoding: base64\r\n"); enc = mimeB64EncodeString((u_char *)in->str, in->len, true); } dsbPrintf(out, "Content-Disposition: inline\r\n\r\n"); } else if (Mopts.html) { dsbPrintf(out, "Content-Type: text/html\r\n\r\n"); enc = DSB_NEW; dsbCat(enc, in->str); } else { dsbPrintf(out, "Content-Type: text/plain\r\n\r\n"); enc = DSB_NEW; dsbCat(enc, in->str); } } else { if (charset == IS_UTF8) { enc = mimeB64EncodeString((u_char *)in->str, in->len, true); } else if (charset == IS_PARTIAL_UTF8) { enc = mimeQpEncodeString((u_char *)in->str, true); } else { enc = DSB_NEW; dsbCat(enc, in->str); } } dsbPrintf(out, "%s\r\n", enc->str); if (Mopts.attach) { if (attachFiles(border, out) == ERROR) { return ERROR; } dsbPrintf(out, "\r\n\r\n--%s--\r\n", border); } dsbDestroy(enc); return 0; }
/** * 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; }
static int helo(dsocket *sd, const char *domain) { int retval; dstrbuf *rbuf = DSB_NEW; /* * We will be calling this function after ehlo() has already * been called. Since ehlo() already grabs the header, go * straight into sending the HELO */ if (writeResponse(sd, "HELO %s\r\n", domain) < 0) { smtpSetErr("Lost connection to SMTP server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("--> HELO\n"); fflush(stdout); #endif retval = readResponse(sd, rbuf); if (retval != 250) { if (retval != ERROR) { smtpSetErr(rbuf->str); } goto end; } #ifdef DEBUG_SMTP printf("<-- %s\n", rbuf->str); fflush(stdout); #endif end: dsbDestroy(rbuf); return retval; }
/** * Let's the SMTP server know it's the end of the data stream. * * Params * sd - Socket descriptor * * Return * - ERROR * - SUCCESS */ int smtpEndData(dsocket *sd) { int retval=ERROR; dstrbuf *rbuf = DSB_NEW; printProgress("Ending Data..."); if (writeResponse(sd, "\r\n.\r\n") != ERROR) { retval = readResponse(sd, rbuf); if (retval != 250) { if (retval != ERROR) { smtpSetErr(rbuf->str); retval = ERROR; } } } else { smtpSetErr("Lost Connection with SMTP server: smtpEndData()"); retval = ERROR; } dsbDestroy(rbuf); return retval; }
/** * Send the RSET command. */ static int rset(dsocket *sd) { int retval = 0; dstrbuf *rbuf = DSB_NEW; /* Send the RSET command */ if (writeResponse(sd, "RSET\r\n") < 0) { smtpSetErr("Socket write error: rset"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("--> RSET\n"); fflush(stdout); #endif retval = readResponse(sd, rbuf); if (retval != 250) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("<-- %s\n", rbuf->str); fflush(stdout); #endif end: dsbDestroy(rbuf); return retval; }
int smtpStartTls(dsocket *sd) { int retval=SUCCESS; #ifdef HAVE_LIBSSL dstrbuf *sb=DSB_NEW; printProgress("Starting TLS Communications..."); if (writeResponse(sd, "STARTTLS\r\n") < 0) { smtpSetErr("Lost connection to SMTP Server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("--> STARTTLS\n"); fflush(stdout); #endif retval = readResponse(sd, sb); if (retval != 220) { smtpSetErr(sb->str); retval = ERROR; } #ifdef DEBUG_SMTP printf("<-- %s\n", sb->str); fflush(stdout); #endif end: dsbDestroy(sb); #else sd = sd; #endif return retval; }
/** * will invoke the path specified to sendmail with any * options specified and it will send the mail via sendmail... **/ int processInternal(const char *sm_bin, dstrbuf *msgcon) { int written_bytes=0, bytes = 0; struct prbar *bar; FILE *open_sendmail; char *ptr = msgcon->str; dstrbuf *smpath; bar = prbarInit(msgcon->len); smpath = expandPath(sm_bin); open_sendmail = popen(smpath->str, "w"); dsbDestroy(smpath); if (!open_sendmail) { fatal("Could not open internal sendmail path: %s", smpath->str); return ERROR; } /* Loop through getting what's out of message and sending it to sendmail */ while (*ptr != '\0') { bytes = strlen(ptr); if (bytes > CHUNK_BYTES) { bytes = CHUNK_BYTES; } written_bytes = fwrite(ptr, sizeof(char), bytes, open_sendmail); if (Mopts.verbose && bar != NULL) { prbarPrint(written_bytes, bar); } ptr += written_bytes; } fflush(open_sendmail); fclose(open_sendmail); prbarDestroy(bar); return SUCCESS; }
/** * Send the RCPT TO: command to the smtp server */ static int rcpt(dsocket *sd, const char *email) { int retval = 0; dstrbuf *rbuf = DSB_NEW; if (writeResponse(sd, "RCPT TO: <%s>\r\n", email) < 0) { smtpSetErr("Lost connection with SMTP server"); retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n--> RCPT TO: <%s>\r\n", email); fflush(stdout); #endif /* Read return message and let's return it's code */ retval = readResponse(sd, rbuf); if ((retval != 250) && (retval != 251)) { if (retval != ERROR) { smtpSetErr(rbuf->str); } retval = ERROR; goto end; } #ifdef DEBUG_SMTP printf("\r\n<-- %s", rbuf->str); fflush(stdout); #endif end: dsbDestroy(rbuf); return retval; }