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