anopesmtp.c

Go to the documentation of this file.
00001 /* smtp stuff handler for win32.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for furhter details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  * Written by Dominick Meglio <codemastr@unrealircd.com>
00012  * *nix port by Trystan Scott Lee <trystan@nomadirc.net>
00013  *
00014  */
00015 
00016 #include "smtp.h"
00017 
00018 static FILE *logfile;
00019 static int curday = 0;
00020 
00021 /*************************************************************************/
00022 
00023 #ifdef _WIN32
00024 int strcasecmp(const char *s1, const char *s2)
00025 {
00026     register int c;
00027 
00028     while ((c = tolower(*s1)) == tolower(*s2)) {
00029         if (c == 0)
00030             return 0;
00031         s1++;
00032         s2++;
00033     }
00034     if (c < tolower(*s2))
00035         return -1;
00036     return 1;
00037 }
00038 #endif
00039 
00040 static int get_logname(char *name, int count, struct tm *tm)
00041 {
00042 
00043     char timestamp[32];
00044 
00045     if (!tm) {
00046         time_t t;
00047 
00048         time(&t);
00049         tm = localtime(&t);
00050     }
00051 
00052     strftime(timestamp, count, "%Y%m%d", tm);
00053     snprintf(name, count, "logs/%s.%s", "anopesmtp", timestamp);
00054     curday = tm->tm_yday;
00055 
00056     return 1;
00057 }
00058 
00059 /*************************************************************************/
00060 
00061 /* Close the log file. */
00062 
00063 void close_log(void)
00064 {
00065     if (!logfile)
00066         return;
00067     fclose(logfile);
00068     logfile = NULL;
00069 }
00070 
00071 /*************************************************************************/
00072 
00073 static void remove_log(void)
00074 {
00075     time_t t;
00076     struct tm tm;
00077 
00078     char name[PATH_MAX];
00079 
00080     time(&t);
00081     t -= (60 * 60 * 24 * 30);
00082     tm = *localtime(&t);
00083 
00084     if (!get_logname(name, sizeof(name), &tm))
00085         return;
00086     unlink(name);
00087 }
00088 
00089 /*************************************************************************/
00090 
00091 /* Open the log file.  Return -1 if the log file could not be opened, else
00092  * return 0. */
00093 
00094 int open_log(void)
00095 {
00096     char name[PATH_MAX];
00097 
00098     if (logfile)
00099         return 0;
00100 
00101     if (!get_logname(name, sizeof(name), NULL))
00102         return 0;
00103     logfile = fopen(name, "a");
00104 
00105     if (logfile)
00106         setbuf(logfile, NULL);
00107     return logfile != NULL ? 0 : -1;
00108 }
00109 
00110 /*************************************************************************/
00111 
00112 static void checkday(void)
00113 {
00114     time_t t;
00115     struct tm tm;
00116 
00117     time(&t);
00118     tm = *localtime(&t);
00119 
00120     if (curday != tm.tm_yday) {
00121         close_log();
00122         remove_log();
00123         open_log();
00124     }
00125 }
00126 
00127 /*************************************************************************/
00128 
00129 /* Log stuff to the log file with a datestamp.  Note that errno is
00130  * preserved by this routine and log_perror().
00131  */
00132 
00133 void alog(const char *fmt, ...)
00134 {
00135     va_list args;
00136     time_t t;
00137     struct tm tm;
00138     char buf[256];
00139     int errno_save = errno;
00140 
00141     if (!smtp_debug) {
00142         return;
00143     }
00144 
00145     checkday();
00146 
00147     if (!fmt) {
00148         return;
00149     }
00150 
00151     va_start(args, fmt);
00152     time(&t);
00153     tm = *localtime(&t);
00154     strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
00155     if (logfile && args) {
00156         fputs(buf, logfile);
00157         vfprintf(logfile, fmt, args);
00158         fputc('\n', logfile);
00159     }
00160     va_end(args);
00161     errno = errno_save;
00162 }
00163 
00164 /*************************************************************************/
00165 
00166 /* Remove a trailing \r\n */
00167 char *strip(char *buf)
00168 {
00169     char *c;
00170     if ((c = strchr(buf, '\n')))
00171         *c = 0;
00172     if ((c = strchr(buf, '\r')))
00173         *c = 0;
00174     return buf;
00175 }
00176 
00177 /*************************************************************************/
00178 
00179 /* Convert a trailing \n to \r\n 
00180  * The caller must free the allocated memory
00181  */
00182 char *lftocrlf(char *buf)
00183 {
00184     char *result = malloc(strlen(buf) + 2);
00185     strip(buf);
00186     strcpy(result, buf);
00187     strcat(result, "\r\n");
00188     return result;
00189 }
00190 
00191 /*************************************************************************/
00192 
00193 /* Add a header to the list */
00194 void smtp_add_header(char *header)
00195 {
00196     struct smtp_header *head = malloc(sizeof(struct smtp_header));
00197 
00198     head->header = lftocrlf(header);
00199     head->next = NULL;
00200 
00201     if (!mail.smtp_headers) {
00202         mail.smtp_headers = head;
00203     }
00204     if (mail.smtp_headers_tail) {
00205         mail.smtp_headers_tail->next = head;
00206     }
00207     mail.smtp_headers_tail = head;
00208 }
00209 
00210 /*************************************************************************/
00211 
00212 /* Is the buffer a header? */
00213 int smtp_is_header(char *buf)
00214 {
00215     char *tmp = strchr(buf, ' ');
00216 
00217     if (!tmp)
00218         return 0;
00219 
00220     if (*(tmp - 1) == ':')
00221         return 1;
00222     return 0;
00223 }
00224 
00225 /*************************************************************************/
00226 
00227 /* Parse a header into a name and value */
00228 void smtp_parse_header(char *buf, char **header, char **value)
00229 {
00230     strip(buf);
00231 
00232     *header = strtok(buf, " ");
00233     *value = strtok(NULL, "");
00234     if (*header)
00235         (*header)[strlen(*header) - 1] = 0;
00236 }
00237 
00238 /*************************************************************************/
00239 
00240 /* Have we reached the end of input? */
00241 int smtp_is_end(char *buf)
00242 {
00243     if (*buf == '.')
00244         if (*(buf + 1) == '\r' || *(buf + 1) == '\n')
00245             return 1;
00246 
00247     return 0;
00248 }
00249 
00250 /*************************************************************************/
00251 
00252 /* Set who the email is from */
00253 void smtp_set_from(char *from)
00254 {
00255     mail.from = strdup(from);
00256 }
00257 
00258 /*************************************************************************/
00259 
00260 /* Set who the email is to */
00261 void smtp_set_to(char *to)
00262 {
00263     char *c;
00264 
00265     if ((c = strrchr(to, '<')) && *(c + 1)) {
00266         to = c + 1;
00267         to[strlen(to) - 1] = 0;
00268     }
00269     mail.to = strdup(to);
00270 }
00271 
00272 /*************************************************************************/
00273 
00274 /* Add a line of body text */
00275 void smtp_add_body_line(char *line)
00276 {
00277     struct smtp_body_line *body;
00278 
00279     body = malloc(sizeof(struct smtp_body_line));
00280 
00281     body->line = lftocrlf(line);
00282     body->next = NULL;
00283 
00284     if (!mail.smtp_body)
00285         mail.smtp_body = body;
00286     if (mail.smtp_body_tail)
00287         mail.smtp_body_tail->next = body;
00288     mail.smtp_body_tail = body;
00289 
00290 }
00291 
00292 /*************************************************************************/
00293 
00294 /* Establish a connection to the SMTP server */
00295 int smtp_connect(char *host, unsigned short port)
00296 {
00297     struct sockaddr_in addr;
00298 
00299     if ((mail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
00300         return 0;
00301 
00302     if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
00303         struct hostent *hent;
00304         if (!(hent = gethostbyname(host)))
00305             return 0;
00306         memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
00307     }
00308     addr.sin_family = AF_INET;
00309     addr.sin_port = htons(port ? port : 25);
00310     if (connect(mail.sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
00311         ano_sockclose(mail.sock);
00312         return 0;
00313     }
00314 
00315     return 1;
00316 }
00317 
00318 /*************************************************************************/
00319 
00320 /* Send a line of text */
00321 int smtp_send(char *text)
00322 {
00323     int result = ano_sockwrite(mail.sock, text, strlen(text));
00324 
00325     alog("SMTP: sent %s",text);
00326 
00327     if (result == SOCKET_ERROR)
00328         ano_sockclose(mail.sock);
00329 
00330     return result;
00331 }
00332 
00333 /*************************************************************************/
00334 
00335 /* Read a line of text */
00336 int smtp_read(char *buf, int len)
00337 {
00338     int result;
00339 
00340     memset(buf, 0, len);
00341     result = ano_sockread(mail.sock, buf, len);
00342 
00343     if (result == SOCKET_ERROR)
00344         ano_sockclose(mail.sock);
00345 
00346     return result;
00347 }
00348 
00349 /*************************************************************************/
00350 
00351 /* Retrieve a response code */
00352 int smtp_get_code(char *text)
00353 {
00354     char *tmp = strtok(text, " ");
00355 
00356     if (!tmp)
00357         return 0;
00358 
00359     return atol(tmp);
00360 }
00361 
00362 /*************************************************************************/
00363 
00364 /* Send the email */
00365 int smtp_send_email()
00366 {
00367     char buf[1024];
00368     struct smtp_header *head;
00369     struct smtp_body_line *body;
00370     int code;
00371     int skip_done = 0;
00372 
00373     if (!smtp_read(buf, 1024)) {
00374         alog("SMTP: error reading buffer");
00375         return 0;
00376     }
00377 
00378     code = smtp_get_code(buf);
00379     if (code != 220) {
00380         alog("SMTP: error expected code 220 got %d",code);
00381         return 0;
00382     }
00383 
00384     if (!smtp_send("HELO anope\r\n")) {
00385         alog("SMTP: error writting to socket");
00386         return 0;
00387     } 
00388 
00389     if (!smtp_read(buf, 1024)) {
00390     alog("SMTP: error reading buffer");
00391         return 0;
00392     }
00393 
00394     code = smtp_get_code(buf);
00395     if (code != 250) {
00396         alog("SMTP: error expected code 250 got %d",code);
00397         return 0;
00398     }
00399 
00400     strcpy(buf, "MAIL FROM: <");
00401     strcat(buf, mail.from);
00402     strcat(buf, ">\r\n");
00403 
00404     if (!smtp_send(buf)) {
00405         alog("SMTP: error writting to socket");
00406         return 0;
00407     }
00408 
00409     if (!smtp_read(buf, 1024)) {
00410         alog("SMTP: error reading buffer");
00411         return 0;
00412     }
00413 
00414     code = smtp_get_code(buf);
00415     if (code != 250)
00416         return 0;
00417 
00418     strcpy(buf, "RCPT TO: <");
00419     strcat(buf, mail.to);
00420     strcat(buf, ">\r\n");
00421 
00422     if (!smtp_send(buf)) {
00423         alog("SMTP: error writting to socket");
00424         return 0;
00425     }
00426 
00427     if (!smtp_read(buf, 1024)) {
00428         alog("SMTP: error reading buffer");
00429         return 0;
00430     }
00431 
00432     code = smtp_get_code(buf);
00433     if (smtp_get_code(buf) != 250) {
00434         alog("SMTP: error expected code 250 got %d",code);
00435         return 0;
00436     }
00437 
00438     if (!smtp_send("DATA\r\n")) {
00439         alog("SMTP: error writting to socket");
00440         return 0;
00441     }
00442 
00443     if (!smtp_read(buf, 1024)) {
00444         alog("SMTP: error reading buffer");
00445         return 0;
00446     }
00447 
00448     code = smtp_get_code(buf);
00449     if (code != 354) {
00450         alog("SMTP: error expected code 354 got %d",code);
00451         return 0;
00452     }
00453 
00454     for (head = mail.smtp_headers; head; head = head->next) {
00455         if (!smtp_send(head->header)) {
00456             alog("SMTP: error writting to socket");
00457             return 0;
00458         }
00459     }
00460 
00461     if (!smtp_send("\r\n")) {
00462         alog("SMTP: error writting to socket");
00463         return 0;
00464     }
00465 
00466     for (body = mail.smtp_body; body; body = body->next) {
00467         if (skip_done) {
00468             if (!smtp_send(body->line)) {
00469                 alog("SMTP: error writting to socket");
00470                 return 0;
00471             }
00472         } else {
00473             skip_done = 1;
00474         }
00475     }
00476 
00477     if (!smtp_send("\r\n.\r\n")) {
00478         alog("SMTP: error writting to socket");
00479         return 0;
00480     }
00481 
00482     return 1;
00483 }
00484 
00485 /*************************************************************************/
00486 
00487 void smtp_disconnect()
00488 {
00489     smtp_send("QUIT\r\n");
00490     ano_sockclose(mail.sock);
00491 }
00492 
00493 /*************************************************************************/
00494 
00495 void mail_cleanup()
00496 {
00497     struct smtp_header *headers, *nexth;
00498     struct smtp_body_line *body, *nextb;
00499     
00500     if (mail.from)
00501         free(mail.from);
00502     if (mail.to)
00503         free(mail.to);
00504     
00505     headers = mail.smtp_headers;
00506     while (headers) {
00507         nexth = headers->next;
00508         free(headers->header);
00509         free(headers);
00510         headers = nexth;
00511     }
00512     
00513     body = mail.smtp_body;
00514     while (body) {
00515         nextb = body->next;
00516         free(body->line);
00517         free(body);
00518         body = nextb;
00519     }
00520 }
00521 
00522 /*************************************************************************/
00523 
00524 int main(int argc, char *argv[])
00525 {
00526     char buf[8192];
00527 /*  These are somehow unused - why are they here? -GD
00528 
00529     struct smtp_body_line *b;
00530     struct smtp_header *h;
00531 */
00532     int headers_done = 0;
00533 /* Win32 stuff */
00534 #ifdef _WIN32
00535     WSADATA wsa;
00536 #endif
00537     char *server, *aport;
00538     short port;
00539 
00540     if (argc == 1)
00541         return 0;
00542 
00543     server = strtok(argv[1], ":");
00544     if ((aport = strtok(NULL, ""))) {
00545         port = atoi(aport);
00546     } else {
00547         port = 25;
00548     }
00549 
00550    if (!server) {
00551         alog("No Server");
00552     /* Bad, bad, bad. This was a eturn from main with no value! -GD */
00553         return 0;
00554     } else {
00555         alog("SMTP: server %s port %d",server,port);
00556     }
00557 
00558     memset(&mail, 0, sizeof(mail));
00559 
00560 /* The WSAStartup function initiates use of WS2_32.DLL by a process. */
00561 /* guessing we can skip it under *nix */
00562 #ifdef _WIN32
00563     if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
00564         return 0;
00565 #endif
00566 
00567     /* Read the message and parse it */
00568     while (fgets(buf, 8192, stdin)) {
00569         if (smtp_is_header(buf) && !headers_done) {
00570             char *header, *value;
00571             smtp_add_header(buf);
00572             smtp_parse_header(buf, &header, &value);
00573             if (!strcasecmp(header, "from")) {
00574                 alog("SMTP: from: %s",value);
00575                 smtp_set_from(value);
00576             } else if (!strcasecmp(header, "to")) {
00577                 alog("SMTP: to: %s",value);
00578                 smtp_set_to(value);
00579             } else if (smtp_is_end(buf)) {
00580                 break;
00581             } else {
00582                 headers_done = 1;
00583                 smtp_add_body_line(buf);
00584             }
00585         } else {
00586                 smtp_add_body_line(buf);
00587         }
00588     }
00589 
00590     if (!smtp_connect(server, port)) {
00591         alog("SMTP: failed to connect to %s:%d",server, port);
00592         mail_cleanup();
00593         return 0;
00594     }
00595     if (!smtp_send_email()) {
00596         alog("SMTP: error during sending of mail");
00597         mail_cleanup();
00598         return 0;
00599     }
00600     smtp_disconnect();
00601     mail_cleanup();
00602     
00603     return 1;
00604 }

Generated on Sun Dec 30 09:26:53 2007 for Anope by  doxygen 1.5.1-20070107