glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / transport / plugin_transport_smtp.c
1 /*
2      This file is part of GNUnet
3      Copyright (C) 2003-2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Affero General Public License for more details.
14 */
15
16 /**
17  * @file transport/plugin_transport_smtp.c
18  * @brief Implementation of the SMTP transport service
19  * @author Christian Grothoff
20  * @author Renaldo Ferreira
21  */
22
23 #include "platform.h"
24 #include "gnunet_util.h"
25 #include "gnunet_constants.h"
26 #include "gnunet_protocols.h"
27 #include "gnunet_transport.h"
28 #include "gnunet_stats_service.h"
29 #include <libesmtp.h>
30 #include <signal.h>
31
32
33 /**
34  * The default maximum size of each outbound SMTP message.
35  */
36 #define SMTP_MESSAGE_SIZE 65528
37
38 #define DEBUG_SMTP GNUNET_EXTRA_LOGGING
39
40 #define FILTER_STRING_SIZE 64
41
42 /* how long can a line in base64 encoded
43    mime text be? (in characters, excluding "\n") */
44 #define MAX_CHAR_PER_LINE 76
45
46 #define EBUF_LEN 128
47
48 /**
49  * Host-Address in a SMTP network.
50  */
51 typedef struct
52 {
53
54   /**
55    * Filter line that every sender must include in the E-mails such
56    * that the receiver can effectively filter out the GNUnet traffic
57    * from the E-mail.
58    */
59   char filter[FILTER_STRING_SIZE];
60
61   /**
62    * Claimed E-mail address of the sender.
63    * Format is "foo@bar.com" with null termination, padded to be
64    * of a multiple of 8 bytes long.
65    */
66   char senderAddress[0];
67
68 } EmailAddress;
69
70 GNUNET_NETWORK_STRUCT_BEGIN
71
72 /**
73  * Encapsulation of a GNUnet message in the SMTP mail body (before
74  * base64 encoding).
75  */
76 typedef struct
77 {
78   GNUNET_MessageHeader header;
79
80   /**
81    * What is the identity of the sender (GNUNET_hash of public key)
82    */
83   GNUNET_PeerIdentity sender;
84
85 } SMTPMessage;
86 GNUNET_NETWORK_STRUCT_END
87
88 /* *********** globals ************* */
89
90 /**
91  * apis (our advertised API and the core api )
92  */
93 static GNUNET_CoreAPIForTransport *core_api;
94
95 static struct GNUNET_GE_Context *ectx;
96
97 /**
98  * Thread that listens for inbound messages
99  */
100 static struct GNUNET_ThreadHandle *dispatchThread;
101
102 /**
103  * Flag to indicate that server has been shut down.
104  */
105 static int smtp_shutdown = GNUNET_YES;
106
107 /**
108  * Set to the SMTP server hostname (and port) for outgoing messages.
109  */
110 static char *smtp_server_name;
111
112 static char *pipename;
113
114 /**
115  * Lock for uses of libesmtp (not thread-safe).
116  */
117 static struct GNUNET_Mutex *lock;
118
119 /**
120  * Old handler for SIGPIPE (kept to be able to restore).
121  */
122 static struct sigaction old_handler;
123
124 static char *email;
125
126 static GNUNET_TransportAPI smtpAPI;
127
128 static GNUNET_Stats_ServiceAPI *stats;
129
130 static int stat_bytesReceived;
131
132 static int stat_bytesSent;
133
134 static int stat_bytesDropped;
135
136 /**
137  * How many e-mails are we allowed to send per hour?
138  */
139 static unsigned long long rate_limit;
140
141 static GNUNET_CronTime last_transmission;
142
143
144 /* ********************* the real stuff ******************* */
145
146 #define strAUTOncmp(a,b) strncmp(a,b,strlen(b))
147
148 /**
149  * Listen to the pipe, decode messages and send to core.
150  */
151 static void *
152 listenAndDistribute (void *unused)
153 {
154   char *line;
155   unsigned int linesize;
156   SMTPMessage *mp;
157   FILE *fdes;
158   char *retl;
159   char *out;
160   unsigned int size;
161   GNUNET_TransportPacket *coreMP;
162   int fd;
163   unsigned int pos;
164
165   linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2) / MAX_CHAR_PER_LINE;      /* maximum size of a line supported */
166   line = GNUNET_malloc (linesize + 2);  /* 2 bytes for off-by-one errors, just to be safe... */
167
168 #define READLINE(l,limit) \
169   do { retl = fgets(l, (limit), fdes);                          \
170     if ( (retl == NULL) || (smtp_shutdown == GNUNET_YES)) {\
171       goto END; \
172     }\
173     if (core_api->load_monitor != NULL) \
174      GNUNET_network_monitor_notify_transmission(core_api->load_monitor, GNUNET_ND_DOWNLOAD, strlen(retl)); \
175   } while (0)
176
177
178   while (smtp_shutdown == GNUNET_NO)
179   {
180     fd = OPEN (pipename, O_RDONLY | O_ASYNC);
181     if (fd == -1)
182     {
183       if (smtp_shutdown == GNUNET_NO)
184         GNUNET_thread_sleep (5 * GNUNET_CRON_SECONDS);
185       continue;
186     }
187     fdes = fdopen (fd, "r");
188     while (smtp_shutdown == GNUNET_NO)
189     {
190       /* skip until end of header */
191       do
192       {
193         READLINE (line, linesize);
194       }
195       while ((line[0] != '\r') && (line[0] != '\n'));   /* expect newline */
196       READLINE (line, linesize);        /* read base64 encoded message; decode, process */
197       pos = 0;
198       while (1)
199       {
200         pos = strlen (line) - 1;        /* ignore new line */
201         READLINE (&line[pos], linesize - pos);  /* read base64 encoded message; decode, process */
202         if ((line[pos] == '\r') || (line[pos] == '\n'))
203           break;                /* empty line => end of message! */
204       }
205       size = GNUNET_STRINGS_base64_decode (line, pos, &out);
206       if (size < sizeof (SMTPMessage))
207       {
208         GNUNET_GE_BREAK (ectx, 0);
209         GNUNET_free (out);
210         goto END;
211       }
212
213       mp = (SMTPMessage *) &out[size - sizeof (SMTPMessage)];
214       if (ntohs (mp->header.size) != size)
215       {
216         GNUNET_GE_LOG (ectx,
217                        GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
218                        _("Received malformed message via %s. Ignored.\n"),
219                        "SMTP");
220 #if DEBUG_SMTP
221         GNUNET_GE_LOG (ectx,
222                        GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
223                        "Size returned by base64=%d, in the msg=%d.\n", size,
224                        ntohl (mp->size));
225 #endif
226         GNUNET_free (out);
227         goto END;
228       }
229       if (stats != NULL)
230         stats->change (stat_bytesReceived, size);
231       coreMP = GNUNET_new (GNUNET_TransportPacket);
232       coreMP->msg = out;
233       coreMP->size = size - sizeof (SMTPMessage);
234       coreMP->tsession = NULL;
235       coreMP->sender = mp->sender;
236 #if DEBUG_SMTP
237       GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
238                      "SMTP message passed to the core.\n");
239 #endif
240
241       core_api->receive (coreMP);
242     }
243 END:
244 #if DEBUG_SMTP
245     GNUNET_GE_LOG (ectx, GNUNET_GE_DEBUG | GNUNET_GE_REQUEST | GNUNET_GE_USER,
246                    "SMTP message processed.\n");
247 #endif
248     if (fdes != NULL)
249       fclose (fdes);
250   }
251   GNUNET_free (line);
252   return NULL;
253 }
254
255 /* *************** API implementation *************** */
256
257 /**
258  * Verify that a hello-Message is correct (a node is reachable at that
259  * address). Since the reply will be asynchronous, a method must be
260  * called on success.
261  *
262  * @param hello the hello message to verify
263  *        (the signature/crc have been verified before)
264  * @return GNUNET_OK on success, GNUNET_SYSERR on error
265  */
266 static int
267 api_verify_hello (const GNUNET_MessageHello * hello)
268 {
269   const EmailAddress *maddr;
270
271   maddr = (const EmailAddress *) &hello[1];
272   if ((ntohs (hello->header.size) !=
273        sizeof (GNUNET_MessageHello) + ntohs (hello->senderAddressSize)) ||
274       (maddr->senderAddress
275        [ntohs (hello->senderAddressSize) - 1 - FILTER_STRING_SIZE] != '\0'))
276   {
277     GNUNET_GE_BREAK (ectx, 0);
278     return GNUNET_SYSERR;       /* obviously invalid */
279   }
280   if (NULL == strstr (maddr->filter, ": "))
281     return GNUNET_SYSERR;
282   return GNUNET_OK;
283 }
284
285 /**
286  * Create a hello-Message for the current node. The hello is created
287  * without signature and without a timestamp. The GNUnet core will
288  * GNUNET_RSA_sign the message and add an expiration time.
289  *
290  * @return hello on success, NULL on error
291  */
292 static GNUNET_MessageHello *
293 api_create_hello ()
294 {
295   GNUNET_MessageHello *msg;
296   char *filter;
297   EmailAddress *haddr;
298   int i;
299
300   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "FILTER",
301                                             "X-mailer: GNUnet", &filter);
302   if (NULL == strstr (filter, ": "))
303   {
304     GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
305                    _("SMTP filter string to invalid, lacks ': '\n"));
306     GNUNET_free (filter);
307     return NULL;
308   }
309
310   if (strlen (filter) > FILTER_STRING_SIZE)
311   {
312     filter[FILTER_STRING_SIZE] = '\0';
313     GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
314                    _("SMTP filter string to long, capped to `%s'\n"), filter);
315   }
316   i = (strlen (email) + 8) & (~7);      /* make multiple of 8 */
317   msg =
318       GNUNET_malloc (sizeof (GNUNET_MessageHello) + sizeof (EmailAddress) + i);
319   memset (msg, 0, sizeof (GNUNET_MessageHello) + sizeof (EmailAddress) + i);
320   haddr = (EmailAddress *) &msg[1];
321   memset (&haddr->filter[0], 0, FILTER_STRING_SIZE);
322   strcpy (&haddr->filter[0], filter);
323   GNUNET_memcpy (&haddr->senderAddress[0], email, strlen (email) + 1);
324   msg->senderAddressSize = htons (strlen (email) + 1 + sizeof (EmailAddress));
325   msg->protocol = htons (GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP);
326   msg->MTU = htonl (smtpAPI.mtu);
327   msg->header.size = htons (GNUNET_sizeof_hello (msg));
328   if (api_verify_hello (msg) == GNUNET_SYSERR)
329     GNUNET_GE_ASSERT (ectx, 0);
330   GNUNET_free (filter);
331   return msg;
332 }
333
334 struct GetMessageClosure
335 {
336   unsigned int esize;
337   unsigned int pos;
338   char *ebody;
339 };
340
341 static const char *
342 get_message (void **buf, int *len, void *cls)
343 {
344   struct GetMessageClosure *gmc = cls;
345
346   *buf = NULL;
347   if (len == NULL)
348   {
349     gmc->pos = 0;
350     return NULL;
351   }
352   if (gmc->pos == gmc->esize)
353     return NULL;                /* done */
354   *len = gmc->esize;
355   gmc->pos = gmc->esize;
356   return gmc->ebody;
357 }
358
359 /**
360  * Send a message to the specified remote node.
361  *
362  * @param tsession the GNUNET_MessageHello identifying the remote node
363  * @param msg what to send
364  * @param size the size of the message
365  * @param important is this message important enough to override typical limits?
366  * @return GNUNET_SYSERR on error, GNUNET_OK on success
367  */
368 static int
369 api_send (GNUNET_TSession * tsession, const void *msg, const unsigned int size,
370           int important)
371 {
372   const GNUNET_MessageHello *hello;
373   const EmailAddress *haddr;
374   char *m;
375   char *filter;
376   char *fvalue;
377   SMTPMessage *mp;
378   struct GetMessageClosure gm_cls;
379   smtp_session_t session;
380   smtp_message_t message;
381   smtp_recipient_t recipient;
382
383 #define EBUF_LEN 128
384   char ebuf[EBUF_LEN];
385   GNUNET_CronTime now;
386
387   if (smtp_shutdown == GNUNET_YES)
388     return GNUNET_SYSERR;
389   if ((size == 0) || (size > smtpAPI.mtu))
390   {
391     GNUNET_GE_BREAK (ectx, 0);
392     return GNUNET_SYSERR;
393   }
394   now = GNUNET_get_time ();
395   if ((important != GNUNET_YES) &&
396       ((now - last_transmission) * rate_limit) < GNUNET_CRON_HOURS)
397     return GNUNET_NO;           /* rate too high */
398   last_transmission = now;
399
400   hello = (const GNUNET_MessageHello *) tsession->internal;
401   if (hello == NULL)
402     return GNUNET_SYSERR;
403   GNUNET_mutex_lock (lock);
404   session = smtp_create_session ();
405   if (session == NULL)
406   {
407     GNUNET_GE_LOG (ectx,
408                    GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
409                    GNUNET_GE_IMMEDIATE, _("SMTP: `%s' failed: %s.\n"),
410                    "smtp_create_session", smtp_strerror (smtp_errno (), ebuf,
411                                                          EBUF_LEN));
412     GNUNET_mutex_unlock (lock);
413     return GNUNET_SYSERR;
414   }
415   if (0 == smtp_set_server (session, smtp_server_name))
416   {
417     GNUNET_GE_LOG (ectx,
418                    GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER |
419                    GNUNET_GE_IMMEDIATE, _("SMTP: `%s' failed: %s.\n"),
420                    "smtp_set_server", smtp_strerror (smtp_errno (), ebuf,
421                                                      EBUF_LEN));
422     smtp_destroy_session (session);
423     GNUNET_mutex_unlock (lock);
424     return GNUNET_SYSERR;
425   }
426   haddr = (const EmailAddress *) &hello[1];
427   message = smtp_add_message (session);
428   if (message == NULL)
429   {
430     GNUNET_GE_LOG (ectx,
431                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
432                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
433                    "smtp_add_message", smtp_strerror (smtp_errno (), ebuf,
434                                                       EBUF_LEN));
435     smtp_destroy_session (session);
436     GNUNET_mutex_unlock (lock);
437     return GNUNET_SYSERR;
438   }
439   smtp_set_header (message, "To", NULL, haddr->senderAddress);
440   smtp_set_header (message, "From", NULL, email);
441
442   filter = GNUNET_strdup (haddr->filter);
443   fvalue = strstr (filter, ": ");
444   GNUNET_GE_ASSERT (NULL, NULL != fvalue);
445   fvalue[0] = '\0';
446   fvalue += 2;
447   if (0 == smtp_set_header (message, filter, fvalue))
448   {
449     GNUNET_GE_LOG (ectx,
450                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
451                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
452                    "smtp_set_header", smtp_strerror (smtp_errno (), ebuf,
453                                                      EBUF_LEN));
454     smtp_destroy_session (session);
455     GNUNET_mutex_unlock (lock);
456     GNUNET_free (filter);
457     return GNUNET_SYSERR;
458   }
459   GNUNET_free (filter);
460   m = GNUNET_malloc (size + sizeof (SMTPMessage));
461   GNUNET_memcpy (m, msg, size);
462   mp = (SMTPMessage *) &m[size];
463   mp->header.size = htons (size + sizeof (SMTPMessage));
464   mp->header.type = htons (0);
465   mp->sender = *core_api->my_identity;
466   gm_cls.ebody = NULL;
467   gm_cls.pos = 0;
468   gm_cls.esize = GNUNET_STRINGS_base64_encode (m, size + sizeof (SMTPMessage), &gm_cls.ebody);
469   GNUNET_free (m);
470   if (0 == smtp_size_set_estimate (message, gm_cls.esize))
471   {
472     GNUNET_GE_LOG (ectx,
473                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
474                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
475                    "smtp_size_set_estimate", smtp_strerror (smtp_errno (), ebuf,
476                                                             EBUF_LEN));
477   }
478   if (0 == smtp_set_messagecb (message, &get_message, &gm_cls))
479   {
480     GNUNET_GE_LOG (ectx,
481                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
482                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
483                    "smtp_set_messagecb", smtp_strerror (smtp_errno (), ebuf,
484                                                         EBUF_LEN));
485     smtp_destroy_session (session);
486     GNUNET_mutex_unlock (lock);
487     GNUNET_free (gm_cls.ebody);
488     return GNUNET_SYSERR;
489   }
490   recipient = smtp_add_recipient (message, haddr->senderAddress);
491   if (recipient == NULL)
492   {
493     GNUNET_GE_LOG (ectx,
494                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
495                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
496                    "smtp_add_recipient", smtp_strerror (smtp_errno (), ebuf,
497                                                         EBUF_LEN));
498     smtp_destroy_session (session);
499     GNUNET_mutex_unlock (lock);
500     return GNUNET_SYSERR;
501   }
502   if (0 == smtp_start_session (session))
503   {
504     GNUNET_GE_LOG (ectx,
505                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER |
506                    GNUNET_GE_BULK, _("SMTP: `%s' failed: %s.\n"),
507                    "smtp_start_session", smtp_strerror (smtp_errno (), ebuf,
508                                                         EBUF_LEN));
509     smtp_destroy_session (session);
510     GNUNET_mutex_unlock (lock);
511     GNUNET_free (gm_cls.ebody);
512     return GNUNET_SYSERR;
513   }
514   if (stats != NULL)
515     stats->change (stat_bytesSent, size);
516   if (core_api->load_monitor != NULL)
517     GNUNET_network_monitor_notify_transmission (core_api->load_monitor,
518                                                 GNUNET_ND_UPLOAD, gm_cls.esize);
519   smtp_message_reset_status (message);  /* this is needed to plug a 28-byte/message memory leak in libesmtp */
520   smtp_destroy_session (session);
521   GNUNET_mutex_unlock (lock);
522   GNUNET_free (gm_cls.ebody);
523   return GNUNET_OK;
524 }
525
526 /**
527  * Establish a connection to a remote node.
528  * @param hello the hello-Message for the target node
529  * @param tsessionPtr the session handle that is to be set
530  * @param may_reuse can we re-use an existing connection?
531  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
532  */
533 static int
534 api_connect (const GNUNET_MessageHello * hello, GNUNET_TSession ** tsessionPtr,
535              int may_reuse)
536 {
537   GNUNET_TSession *tsession;
538
539   tsession = GNUNET_new (GNUNET_TSession);
540   tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
541   tsession->peer = hello->senderIdentity;
542   GNUNET_memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
543   tsession->ttype = smtpAPI.protocol_number;
544   (*tsessionPtr) = tsession;
545   return GNUNET_OK;
546 }
547
548 /**
549  * Disconnect from a remote node.
550  *
551  * @param tsession the session that is closed
552  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
553  */
554 static int
555 api_disconnect (GNUNET_TSession * tsession)
556 {
557   if (tsession != NULL)
558   {
559     if (tsession->internal != NULL)
560       GNUNET_free (tsession->internal);
561     GNUNET_free (tsession);
562   }
563   return GNUNET_OK;
564 }
565
566 /**
567  * Start the server process to receive inbound traffic.
568  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
569  */
570 static int
571 api_start_transport_server ()
572 {
573   smtp_shutdown = GNUNET_NO;
574   /* initialize SMTP network */
575   dispatchThread = GNUNET_thread_create (&listenAndDistribute, NULL, 1024 * 4);
576   if (dispatchThread == NULL)
577   {
578     GNUNET_GE_DIE_STRERROR (ectx,
579                             GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
580                             "pthread_create");
581     return GNUNET_SYSERR;
582   }
583   return GNUNET_OK;
584 }
585
586 /**
587  * Shutdown the server process (stop receiving inbound traffic). Maybe
588  * restarted later!
589  */
590 static int
591 api_stop_transport_server ()
592 {
593   void *unused;
594
595   smtp_shutdown = GNUNET_YES;
596   GNUNET_thread_stop_sleep (dispatchThread);
597   GNUNET_thread_join (dispatchThread, &unused);
598   return GNUNET_OK;
599 }
600
601 /**
602  * Convert SMTP hello to an IP address (always fails).
603  */
604 static int
605 api_hello_to_address (const GNUNET_MessageHello * hello, void **sa,
606                       unsigned int *sa_len)
607 {
608   return GNUNET_SYSERR;
609 }
610
611 /**
612  * Always fails.
613  */
614 static int
615 api_associate (GNUNET_TSession * tsession)
616 {
617   return GNUNET_SYSERR;         /* SMTP connections can never be associated */
618 }
619
620 /**
621  * Always succeeds (for now; we should look at adding
622  * frequency limits to SMTP in the future!).
623  */
624 static int
625 api_test_would_try (GNUNET_TSession * tsession, unsigned int size,
626                     int important)
627 {
628   return GNUNET_OK;             /* we always try... */
629 }
630
631 /**
632  * The exported method. Makes the core api available via a global and
633  * returns the smtp transport API.
634  */
635 GNUNET_TransportAPI *
636 inittransport_smtp (struct GNUNET_CoreAPIForTransport * core)
637 {
638   unsigned long long mtu;
639   struct sigaction sa;
640
641   core_api = core;
642   ectx = core->ectx;
643   if (!GNUNET_GC_have_configuration_value (core_api->cfg, "SMTP", "EMAIL"))
644   {
645     GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
646                    _
647                    ("No email-address specified, can not start SMTP transport.\n"));
648     return NULL;
649   }
650   GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "MTU", 1200,
651                                             SMTP_MESSAGE_SIZE,
652                                             SMTP_MESSAGE_SIZE, &mtu);
653   GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "RATELIMIT",
654                                             0, 0, 1024 * 1024, &rate_limit);
655   stats = core_api->service_request ("stats");
656   if (stats != NULL)
657   {
658     stat_bytesReceived =
659         stats->create (gettext_noop ("# bytes received via SMTP"));
660     stat_bytesSent = stats->create (gettext_noop ("# bytes sent via SMTP"));
661     stat_bytesDropped =
662         stats->create (gettext_noop ("# bytes dropped by SMTP (outgoing)"));
663   }
664   GNUNET_GC_get_configuration_value_filename (core_api->cfg, "SMTP", "PIPE", &pipename);
665   UNLINK (pipename);
666   if (0 != mkfifo (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
667   {
668     GNUNET_GE_LOG_STRERROR (ectx,
669                             GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
670                             "mkfifo");
671     GNUNET_free (pipename);
672     core_api->service_release (stats);
673     stats = NULL;
674     return NULL;
675   }
676   /* we need to allow the mailer program to send us messages;
677    * easiest done by giving it write permissions (see Mantis #1142) */
678   if (0 != chmod (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
679     GNUNET_GE_LOG_STRERROR (ectx,
680                             GNUNET_GE_ADMIN | GNUNET_GE_BULK |
681                             GNUNET_GE_WARNING, "chmod");
682   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "EMAIL", NULL,
683                                             &email);
684   lock = GNUNET_mutex_create (GNUNET_NO);
685   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "SERVER",
686                                             "localhost:25", &smtp_server_name);
687   sa.sa_handler = SIG_IGN;
688   sigemptyset (&sa.sa_mask);
689   sa.sa_flags = 0;
690   sigaction (SIGPIPE, &sa, &old_handler);
691
692   smtpAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP;
693   smtpAPI.mtu = mtu - sizeof (SMTPMessage);
694   smtpAPI.cost = 50;
695   smtpAPI.hello_verify = &api_verify_hello;
696   smtpAPI.hello_create = &api_create_hello;
697   smtpAPI.connect = &api_connect;
698   smtpAPI.send = &api_send;
699   smtpAPI.associate = &api_associate;
700   smtpAPI.disconnect = &api_disconnect;
701   smtpAPI.server_start = &api_start_transport_server;
702   smtpAPI.server_stop = &api_stop_transport_server;
703   smtpAPI.hello_to_address = &api_hello_to_address;
704   smtpAPI.send_now_test = &api_test_would_try;
705   return &smtpAPI;
706 }
707
708 void
709 donetransport_smtp ()
710 {
711   sigaction (SIGPIPE, &old_handler, NULL);
712   GNUNET_free (smtp_server_name);
713   if (stats != NULL)
714   {
715     core_api->service_release (stats);
716     stats = NULL;
717   }
718   GNUNET_mutex_destroy (lock);
719   lock = NULL;
720   UNLINK (pipename);
721   GNUNET_free (pipename);
722   pipename = NULL;
723   GNUNET_free (email);
724   email = NULL;
725 }
726
727 /* end of smtp.c */