Anope IRC Services  Version 1.8
anopesmtp.c
Go to the documentation of this file.
1 /* smtp stuff handler for win32.
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  * Written by Dominick Meglio <codemastr@unrealircd.com>
12  * *nix port by Trystan Scott Lee <trystan@nomadirc.net>
13  *
14  */
15 
16 #include "smtp.h"
17 
18 static FILE *logfile;
19 static int curday = 0;
20 
21 /*************************************************************************/
22 
23 #ifdef _WIN32
24 int strcasecmp(const char *s1, const char *s2)
25 {
26  register int c;
27 
28  while ((c = tolower(*s1)) == tolower(*s2)) {
29  if (c == 0)
30  return 0;
31  s1++;
32  s2++;
33  }
34  if (c < tolower(*s2))
35  return -1;
36  return 1;
37 }
38 #endif
39 
40 static int get_logname(char *name, int count, struct tm *tm)
41 {
42 
43  char timestamp[32];
44 
45  if (!tm) {
46  time_t t;
47 
48  time(&t);
49  tm = localtime(&t);
50  }
51 
52  strftime(timestamp, count, "%Y%m%d", tm);
53  snprintf(name, count, "logs/%s.%s", "anopesmtp", timestamp);
54  curday = tm->tm_yday;
55 
56  return 1;
57 }
58 
59 /*************************************************************************/
60 
61 /* Close the log file. */
62 
63 void close_log(void)
64 {
65  if (!logfile)
66  return;
67  fclose(logfile);
68  logfile = NULL;
69 }
70 
71 /*************************************************************************/
72 
73 static void remove_log(void)
74 {
75  time_t t;
76  struct tm tm;
77 
78  char name[PATH_MAX];
79 
80  time(&t);
81  t -= (60 * 60 * 24 * 30);
82  tm = *localtime(&t);
83 
84  if (!get_logname(name, sizeof(name), &tm))
85  return;
86  unlink(name);
87 }
88 
89 /*************************************************************************/
90 
91 /* Open the log file. Return -1 if the log file could not be opened, else
92  * return 0. */
93 
94 int open_log(void)
95 {
96  char name[PATH_MAX];
97 
98  if (logfile)
99  return 0;
100 
101  if (!get_logname(name, sizeof(name), NULL))
102  return 0;
103  logfile = fopen(name, "a");
104 
105  if (logfile)
106  setbuf(logfile, NULL);
107  return logfile != NULL ? 0 : -1;
108 }
109 
110 /*************************************************************************/
111 
112 static void checkday(void)
113 {
114  time_t t;
115  struct tm tm;
116 
117  time(&t);
118  tm = *localtime(&t);
119 
120  if (curday != tm.tm_yday) {
121  close_log();
122  remove_log();
123  open_log();
124  }
125 }
126 
127 /*************************************************************************/
128 
129 /* Log stuff to the log file with a datestamp. Note that errno is
130  * preserved by this routine and log_perror().
131  */
132 
133 void alog(const char *fmt, ...)
134 {
135  va_list args;
136  time_t t;
137  struct tm tm;
138  char buf[256];
139  int errno_save = errno;
140 
141  if (!smtp_debug) {
142  return;
143  }
144 
145  checkday();
146 
147  if (!fmt) {
148  return;
149  }
150 
151  va_start(args, fmt);
152  time(&t);
153  tm = *localtime(&t);
154  strftime(buf, sizeof(buf) - 1, "[%b %d %H:%M:%S %Y] ", &tm);
155  if (logfile) {
156  fputs(buf, logfile);
157  vfprintf(logfile, fmt, args);
158  fputc('\n', logfile);
159  }
160  va_end(args);
161  errno = errno_save;
162 }
163 
164 /*************************************************************************/
165 
166 /* Remove a trailing \r\n */
167 char *strip(char *buf)
168 {
169  char *c;
170  if ((c = strchr(buf, '\n')))
171  *c = 0;
172  if ((c = strchr(buf, '\r')))
173  *c = 0;
174  return buf;
175 }
176 
177 /*************************************************************************/
178 
179 /* Convert a trailing \n to \r\n
180  * The caller must free the allocated memory
181  */
182 char *lftocrlf(char *buf)
183 {
184  char *result = malloc(strlen(buf) + 2);
185  strip(buf);
186  strcpy(result, buf);
187  strcat(result, "\r\n");
188  return result;
189 }
190 
191 /*************************************************************************/
192 
193 /* Add a header to the list */
194 void smtp_add_header(char *header)
195 {
196  struct smtp_header *head = malloc(sizeof(struct smtp_header));
197 
198  head->header = lftocrlf(header);
199  head->next = NULL;
200 
201  if (!mail.smtp_headers) {
203  }
204  if (mail.smtp_headers_tail) {
206  }
208 }
209 
210 /*************************************************************************/
211 
212 /* Is the buffer a header? */
213 int smtp_is_header(char *buf)
214 {
215  char *tmp = strchr(buf, ' ');
216 
217  if (!tmp)
218  return 0;
219 
220  if (*(tmp - 1) == ':')
221  return 1;
222  return 0;
223 }
224 
225 /*************************************************************************/
226 
227 /* Parse a header into a name and value */
228 void smtp_parse_header(char *buf, char **header, char **value)
229 {
230  strip(buf);
231 
232  *header = strtok(buf, " ");
233  *value = strtok(NULL, "");
234  if (*header)
235  (*header)[strlen(*header) - 1] = 0;
236 }
237 
238 /*************************************************************************/
239 
240 /* Have we reached the end of input? */
241 int smtp_is_end(char *buf)
242 {
243  if (*buf == '.')
244  if (*(buf + 1) == '\r' || *(buf + 1) == '\n')
245  return 1;
246 
247  return 0;
248 }
249 
250 /*************************************************************************/
251 
252 /* Set who the email is from */
253 void smtp_set_from(char *from)
254 {
255  mail.from = strdup(from);
256 }
257 
258 /*************************************************************************/
259 
260 /* Set who the email is to */
261 void smtp_set_to(char *to)
262 {
263  char *c;
264 
265  if ((c = strrchr(to, '<')) && *(c + 1)) {
266  to = c + 1;
267  to[strlen(to) - 1] = 0;
268  }
269  mail.to = strdup(to);
270 }
271 
272 /*************************************************************************/
273 
274 /* Add a line of body text */
275 void smtp_add_body_line(char *line)
276 {
277  struct smtp_body_line *body;
278 
279  body = malloc(sizeof(struct smtp_body_line));
280 
281  body->line = lftocrlf(line);
282  body->next = NULL;
283 
284  if (!mail.smtp_body)
285  mail.smtp_body = body;
286  if (mail.smtp_body_tail)
287  mail.smtp_body_tail->next = body;
288  mail.smtp_body_tail = body;
289 
290 }
291 
292 /*************************************************************************/
293 
294 /* Establish a connection to the SMTP server */
295 int smtp_connect(char *host, unsigned short port)
296 {
297  struct sockaddr_in addr;
298 
299  if ((mail.sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
300  return 0;
301 
302  if ((addr.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
303  struct hostent *hent;
304  if (!(hent = gethostbyname(host)))
305  return 0;
306  memcpy(&addr.sin_addr, hent->h_addr, hent->h_length);
307  }
308  addr.sin_family = AF_INET;
309  addr.sin_port = htons(port ? port : 25);
310  if (connect(mail.sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == SOCKET_ERROR) {
312  return 0;
313  }
314 
315  return 1;
316 }
317 
318 /*************************************************************************/
319 
320 /* Send a line of text */
321 int smtp_send(char *text)
322 {
323  int result = ano_sockwrite(mail.sock, text, strlen(text));
324 
325  alog("SMTP: sent %s",text);
326 
327  if (result == SOCKET_ERROR)
329 
330  return result;
331 }
332 
333 /*************************************************************************/
334 
335 /* Read a line of text */
336 int smtp_read(char *buf, int len)
337 {
338  int result;
339 
340  memset(buf, 0, len);
341  result = ano_sockread(mail.sock, buf, len);
342 
343  if (result == SOCKET_ERROR)
345 
346  return result;
347 }
348 
349 /*************************************************************************/
350 
351 /* Retrieve a response code */
352 int smtp_get_code(char *text)
353 {
354  char *tmp = strtok(text, " ");
355 
356  if (!tmp)
357  return 0;
358 
359  return atol(tmp);
360 }
361 
362 /*************************************************************************/
363 
364 /* Send the email */
366 {
367  char buf[1024];
368  struct smtp_header *head;
369  struct smtp_body_line *body;
370  int code;
371  int skip_done = 0;
372 
373  if (!smtp_read(buf, 1024)) {
374  alog("SMTP: error reading buffer");
375  return 0;
376  }
377 
378  code = smtp_get_code(buf);
379  if (code != 220) {
380  alog("SMTP: error expected code 220 got %d",code);
381  return 0;
382  }
383 
384  if (!smtp_send("HELO anope\r\n")) {
385  alog("SMTP: error writting to socket");
386  return 0;
387  }
388 
389  if (!smtp_read(buf, 1024)) {
390  alog("SMTP: error reading buffer");
391  return 0;
392  }
393 
394  code = smtp_get_code(buf);
395  if (code != 250) {
396  alog("SMTP: error expected code 250 got %d",code);
397  return 0;
398  }
399 
400  strcpy(buf, "MAIL FROM: <");
401  strcat(buf, mail.from);
402  strcat(buf, ">\r\n");
403 
404  if (!smtp_send(buf)) {
405  alog("SMTP: error writting to socket");
406  return 0;
407  }
408 
409  if (!smtp_read(buf, 1024)) {
410  alog("SMTP: error reading buffer");
411  return 0;
412  }
413 
414  code = smtp_get_code(buf);
415  if (code != 250)
416  return 0;
417 
418  strcpy(buf, "RCPT TO: <");
419  strcat(buf, mail.to);
420  strcat(buf, ">\r\n");
421 
422  if (!smtp_send(buf)) {
423  alog("SMTP: error writting to socket");
424  return 0;
425  }
426 
427  if (!smtp_read(buf, 1024)) {
428  alog("SMTP: error reading buffer");
429  return 0;
430  }
431 
432  code = smtp_get_code(buf);
433  if (smtp_get_code(buf) != 250) {
434  alog("SMTP: error expected code 250 got %d",code);
435  return 0;
436  }
437 
438  if (!smtp_send("DATA\r\n")) {
439  alog("SMTP: error writting to socket");
440  return 0;
441  }
442 
443  if (!smtp_read(buf, 1024)) {
444  alog("SMTP: error reading buffer");
445  return 0;
446  }
447 
448  code = smtp_get_code(buf);
449  if (code != 354) {
450  alog("SMTP: error expected code 354 got %d",code);
451  return 0;
452  }
453 
454  for (head = mail.smtp_headers; head; head = head->next) {
455  if (!smtp_send(head->header)) {
456  alog("SMTP: error writting to socket");
457  return 0;
458  }
459  }
460 
461  if (!smtp_send("\r\n")) {
462  alog("SMTP: error writting to socket");
463  return 0;
464  }
465 
466  for (body = mail.smtp_body; body; body = body->next) {
467  if (skip_done) {
468  if (!smtp_send(body->line)) {
469  alog("SMTP: error writting to socket");
470  return 0;
471  }
472  } else {
473  skip_done = 1;
474  }
475  }
476 
477  if (!smtp_send("\r\n.\r\n")) {
478  alog("SMTP: error writting to socket");
479  return 0;
480  }
481 
482  return 1;
483 }
484 
485 /*************************************************************************/
486 
488 {
489  smtp_send("QUIT\r\n");
491 }
492 
493 /*************************************************************************/
494 
496 {
497  struct smtp_header *headers, *nexth;
498  struct smtp_body_line *body, *nextb;
499 
500  if (mail.from)
501  free(mail.from);
502  if (mail.to)
503  free(mail.to);
504 
505  headers = mail.smtp_headers;
506  while (headers) {
507  nexth = headers->next;
508  free(headers->header);
509  free(headers);
510  headers = nexth;
511  }
512 
513  body = mail.smtp_body;
514  while (body) {
515  nextb = body->next;
516  free(body->line);
517  free(body);
518  body = nextb;
519  }
520 }
521 
522 /*************************************************************************/
523 
524 int main(int argc, char *argv[])
525 {
526  char buf[8192];
527 /* These are somehow unused - why are they here? -GD
528 
529  struct smtp_body_line *b;
530  struct smtp_header *h;
531 */
532  int headers_done = 0;
533 /* Win32 stuff */
534 #ifdef _WIN32
535  WSADATA wsa;
536 #endif
537  char *server, *aport;
538  short port;
539 
540  if (argc == 1)
541  return 0;
542 
543  server = strtok(argv[1], ":");
544  if ((aport = strtok(NULL, ""))) {
545  port = atoi(aport);
546  } else {
547  port = 25;
548  }
549 
550  if (!server) {
551  alog("No Server");
552  /* Bad, bad, bad. This was a eturn from main with no value! -GD */
553  return 0;
554  } else {
555  alog("SMTP: server %s port %d",server,port);
556  }
557 
558  memset(&mail, 0, sizeof(mail));
559 
560 /* The WSAStartup function initiates use of WS2_32.DLL by a process. */
561 /* guessing we can skip it under *nix */
562 #ifdef _WIN32
563  if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
564  return 0;
565 #endif
566 
567  /* Read the message and parse it */
568  while (fgets(buf, 8192, stdin)) {
569  if (smtp_is_header(buf) && !headers_done) {
570  char *header, *value;
571  smtp_add_header(buf);
572  smtp_parse_header(buf, &header, &value);
573  if (!strcasecmp(header, "from")) {
574  alog("SMTP: from: %s",value);
575  smtp_set_from(value);
576  } else if (!strcasecmp(header, "to")) {
577  alog("SMTP: to: %s",value);
578  smtp_set_to(value);
579  } else if (smtp_is_end(buf)) {
580  break;
581  } else {
582  headers_done = 1;
583  smtp_add_body_line(buf);
584  }
585  } else {
586  smtp_add_body_line(buf);
587  }
588  }
589 
590  if (!smtp_connect(server, port)) {
591  alog("SMTP: failed to connect to %s:%d",server, port);
592  mail_cleanup();
593  return 0;
594  }
595  if (!smtp_send_email()) {
596  alog("SMTP: error during sending of mail");
597  mail_cleanup();
598  return 0;
599  }
600  smtp_disconnect();
601  mail_cleanup();
602 
603  return 1;
604 }
int smtp_get_code(char *text)
Definition: anopesmtp.c:352
struct smtp_body_line * smtp_body_tail
Definition: smtp.h:119
E char * strdup(const char *s)
Definition: compat.c:94
void close_log(void)
Definition: anopesmtp.c:63
int main(int argc, char *argv[])
Definition: anopesmtp.c:524
int open_log(void)
Definition: anopesmtp.c:94
#define SOCKET_ERROR
Definition: smtp.h:102
char * line
Definition: smtp.h:113
static void checkday(void)
Definition: anopesmtp.c:112
E int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: compat.c:37
void alog(const char *fmt,...)
Definition: anopesmtp.c:133
void smtp_set_to(char *to)
Definition: anopesmtp.c:261
struct smtp_body_line * smtp_body
Definition: smtp.h:119
void smtp_parse_header(char *buf, char **header, char **value)
Definition: anopesmtp.c:228
void mail_cleanup()
Definition: anopesmtp.c:495
ano_socket_t sock
Definition: smtp.h:122
HostCore * head
Definition: hostserv.c:24
static void remove_log(void)
Definition: anopesmtp.c:73
struct smtp_header * next
Definition: smtp.h:109
struct smtp_message mail
Definition: smtp.h:125
struct smtp_header * smtp_headers_tail
Definition: smtp.h:118
int smtp_is_header(char *buf)
Definition: anopesmtp.c:213
int smtp_send_email()
Definition: anopesmtp.c:365
#define ano_sockclose(fd)
Definition: sockets.h:35
int smtp_connect(char *host, unsigned short port)
Definition: anopesmtp.c:295
static int curday
Definition: anopesmtp.c:19
static FILE * logfile
Definition: anopesmtp.c:18
Command * c
Definition: ns_recover.c:17
struct smtp_header * smtp_headers
Definition: smtp.h:118
int smtp_send(char *text)
Definition: anopesmtp.c:321
char * lftocrlf(char *buf)
Definition: anopesmtp.c:182
int smtp_debug
Definition: smtp.h:128
MYSQL_RES * result
Definition: mypasql.c:6
static int get_logname(char *name, int count, struct tm *tm)
Definition: anopesmtp.c:40
void smtp_disconnect()
Definition: anopesmtp.c:487
void smtp_add_header(char *header)
Definition: anopesmtp.c:194
char * from
Definition: smtp.h:120
struct smtp_body_line * next
Definition: smtp.h:114
#define tolower
Definition: services.h:190
#define ano_sockread(fd, buf, len)
Definition: sockets.h:33
int smtp_is_end(char *buf)
Definition: anopesmtp.c:241
void smtp_add_body_line(char *line)
Definition: anopesmtp.c:275
char * strip(char *buf)
Definition: anopesmtp.c:167
int smtp_read(char *buf, int len)
Definition: anopesmtp.c:336
char * header
Definition: smtp.h:108
void smtp_set_from(char *from)
Definition: anopesmtp.c:253
char * to
Definition: smtp.h:121
#define ano_sockwrite(fd, buf, len)
Definition: sockets.h:34