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