also config files
[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    * Filter line that every sender must include in the E-mails such
60    * that the receiver can effectively filter out the GNUnet traffic
61    * from the E-mail.
62    */
63   char filter[FILTER_STRING_SIZE];
64
65   /**
66    * Claimed E-mail address of the sender.
67    * Format is "foo@bar.com" with null termination, padded to be
68    * of a multiple of 8 bytes long.
69    */
70   char senderAddress[0];
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 } SMTPMessage;
88 GNUNET_NETWORK_STRUCT_END
89
90 /* *********** globals ************* */
91
92 /**
93  * apis (our advertised API and the core api )
94  */
95 static GNUNET_CoreAPIForTransport *core_api;
96
97 static struct GNUNET_GE_Context *ectx;
98
99 /**
100  * Thread that listens for inbound messages
101  */
102 static struct GNUNET_ThreadHandle *dispatchThread;
103
104 /**
105  * Flag to indicate that server has been shut down.
106  */
107 static int smtp_shutdown = GNUNET_YES;
108
109 /**
110  * Set to the SMTP server hostname (and port) for outgoing messages.
111  */
112 static char *smtp_server_name;
113
114 static char *pipename;
115
116 /**
117  * Lock for uses of libesmtp (not thread-safe).
118  */
119 static struct GNUNET_Mutex *lock;
120
121 /**
122  * Old handler for SIGPIPE (kept to be able to restore).
123  */
124 static struct sigaction old_handler;
125
126 static char *email;
127
128 static GNUNET_TransportAPI smtpAPI;
129
130 static GNUNET_Stats_ServiceAPI *stats;
131
132 static int stat_bytesReceived;
133
134 static int stat_bytesSent;
135
136 static int stat_bytesDropped;
137
138 /**
139  * How many e-mails are we allowed to send per hour?
140  */
141 static unsigned long long rate_limit;
142
143 static GNUNET_CronTime last_transmission;
144
145
146 /* ********************* the real stuff ******************* */
147
148 #define strAUTOncmp(a, b) strncmp (a, b, strlen (b))
149
150 /**
151  * Listen to the pipe, decode messages and send to core.
152  */
153 static void *
154 listenAndDistribute (void *unused)
155 {
156   char *line;
157   unsigned int linesize;
158   SMTPMessage *mp;
159   FILE *fdes;
160   char *retl;
161   char *out;
162   unsigned int size;
163   GNUNET_TransportPacket *coreMP;
164   int fd;
165   unsigned int pos;
166
167   linesize = ((GNUNET_MAX_BUFFER_SIZE * 4 / 3) + 8) * (MAX_CHAR_PER_LINE + 2)
168              / 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, \
178                                                      GNUNET_ND_DOWNLOAD, \
179                                                      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
261 /* *************** API implementation *************** */
262
263 /**
264  * Verify that a hello-Message is correct (a node is reachable at that
265  * address). Since the reply will be asynchronous, a method must be
266  * called on success.
267  *
268  * @param hello the hello message to verify
269  *        (the signature/crc have been verified before)
270  * @return GNUNET_OK on success, GNUNET_SYSERR on error
271  */
272 static int
273 api_verify_hello (const GNUNET_MessageHello *hello)
274 {
275   const EmailAddress *maddr;
276
277   maddr = (const EmailAddress *) &hello[1];
278   if ((ntohs (hello->header.size) !=
279        sizeof(GNUNET_MessageHello) + ntohs (hello->senderAddressSize)) ||
280       (maddr->senderAddress
281        [ntohs (hello->senderAddressSize) - 1 - FILTER_STRING_SIZE] != '\0'))
282   {
283     GNUNET_GE_BREAK (ectx, 0);
284     return GNUNET_SYSERR;       /* obviously invalid */
285   }
286   if (NULL == strstr (maddr->filter, ": "))
287     return GNUNET_SYSERR;
288   return GNUNET_OK;
289 }
290
291
292 /**
293  * Create a hello-Message for the current node. The hello is created
294  * without signature and without a timestamp. The GNUnet core will
295  * GNUNET_RSA_sign the message and add an expiration time.
296  *
297  * @return hello on success, NULL on error
298  */
299 static GNUNET_MessageHello *
300 api_create_hello ()
301 {
302   GNUNET_MessageHello *msg;
303   char *filter;
304   EmailAddress *haddr;
305   int i;
306
307   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "FILTER",
308                                             "X-mailer: GNUnet", &filter);
309   if (NULL == strstr (filter, ": "))
310   {
311     GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
312                    _ ("SMTP filter string to invalid, lacks ': '\n"));
313     GNUNET_free (filter);
314     return NULL;
315   }
316
317   if (strlen (filter) > FILTER_STRING_SIZE)
318   {
319     filter[FILTER_STRING_SIZE] = '\0';
320     GNUNET_GE_LOG (ectx, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER,
321                    _ ("SMTP filter string to long, capped to `%s'\n"), filter);
322   }
323   i = (strlen (email) + 8) & (~7);       /* make multiple of 8 */
324   msg =
325     GNUNET_malloc (sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
326   memset (msg, 0, sizeof(GNUNET_MessageHello) + sizeof(EmailAddress) + i);
327   haddr = (EmailAddress *) &msg[1];
328   memset (&haddr->filter[0], 0, FILTER_STRING_SIZE);
329   strcpy (&haddr->filter[0], filter);
330   GNUNET_memcpy (&haddr->senderAddress[0], email, strlen (email) + 1);
331   msg->senderAddressSize = htons (strlen (email) + 1 + sizeof(EmailAddress));
332   msg->protocol = htons (GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP);
333   msg->MTU = htonl (smtpAPI.mtu);
334   msg->header.size = htons (GNUNET_sizeof_hello (msg));
335   if (api_verify_hello (msg) == GNUNET_SYSERR)
336     GNUNET_GE_ASSERT (ectx, 0);
337   GNUNET_free (filter);
338   return msg;
339 }
340
341
342 struct GetMessageClosure
343 {
344   unsigned int esize;
345   unsigned int pos;
346   char *ebody;
347 };
348
349 static const char *
350 get_message (void **buf, int *len, void *cls)
351 {
352   struct GetMessageClosure *gmc = cls;
353
354   *buf = NULL;
355   if (len == NULL)
356   {
357     gmc->pos = 0;
358     return NULL;
359   }
360   if (gmc->pos == gmc->esize)
361     return NULL;                /* done */
362   *len = gmc->esize;
363   gmc->pos = gmc->esize;
364   return gmc->ebody;
365 }
366
367
368 /**
369  * Send a message to the specified remote node.
370  *
371  * @param tsession the GNUNET_MessageHello identifying the remote node
372  * @param msg what to send
373  * @param size the size of the message
374  * @param important is this message important enough to override typical limits?
375  * @return GNUNET_SYSERR on error, GNUNET_OK on success
376  */
377 static int
378 api_send (GNUNET_TSession *tsession, const void *msg, const unsigned int size,
379           int important)
380 {
381   const GNUNET_MessageHello *hello;
382   const EmailAddress *haddr;
383   char *m;
384   char *filter;
385   char *fvalue;
386   SMTPMessage *mp;
387   struct GetMessageClosure gm_cls;
388   smtp_session_t session;
389   smtp_message_t message;
390   smtp_recipient_t recipient;
391
392 #define EBUF_LEN 128
393   char ebuf[EBUF_LEN];
394   GNUNET_CronTime now;
395
396   if (smtp_shutdown == GNUNET_YES)
397     return GNUNET_SYSERR;
398   if ((size == 0) || (size > smtpAPI.mtu))
399   {
400     GNUNET_GE_BREAK (ectx, 0);
401     return GNUNET_SYSERR;
402   }
403   now = GNUNET_get_time ();
404   if ((important != GNUNET_YES) &&
405       ( ((now - last_transmission) * rate_limit) < GNUNET_CRON_HOURS) )
406     return GNUNET_NO;           /* rate too high */
407   last_transmission = now;
408
409   hello = (const GNUNET_MessageHello *) tsession->internal;
410   if (hello == NULL)
411     return GNUNET_SYSERR;
412   GNUNET_mutex_lock (lock);
413   session = smtp_create_session ();
414   if (session == NULL)
415   {
416     GNUNET_GE_LOG (ectx,
417                    GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
418                    | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
419                    "smtp_create_session", smtp_strerror (smtp_errno (), ebuf,
420                                                          EBUF_LEN));
421     GNUNET_mutex_unlock (lock);
422     return GNUNET_SYSERR;
423   }
424   if (0 == smtp_set_server (session, smtp_server_name))
425   {
426     GNUNET_GE_LOG (ectx,
427                    GNUNET_GE_ERROR | GNUNET_GE_ADMIN | GNUNET_GE_USER
428                    | GNUNET_GE_IMMEDIATE, _ ("SMTP: `%s' failed: %s.\n"),
429                    "smtp_set_server", smtp_strerror (smtp_errno (), ebuf,
430                                                      EBUF_LEN));
431     smtp_destroy_session (session);
432     GNUNET_mutex_unlock (lock);
433     return GNUNET_SYSERR;
434   }
435   haddr = (const EmailAddress *) &hello[1];
436   message = smtp_add_message (session);
437   if (message == NULL)
438   {
439     GNUNET_GE_LOG (ectx,
440                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
441                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
442                    "smtp_add_message", smtp_strerror (smtp_errno (), ebuf,
443                                                       EBUF_LEN));
444     smtp_destroy_session (session);
445     GNUNET_mutex_unlock (lock);
446     return GNUNET_SYSERR;
447   }
448   smtp_set_header (message, "To", NULL, haddr->senderAddress);
449   smtp_set_header (message, "From", NULL, email);
450
451   filter = GNUNET_strdup (haddr->filter);
452   fvalue = strstr (filter, ": ");
453   GNUNET_GE_ASSERT (NULL, NULL != fvalue);
454   fvalue[0] = '\0';
455   fvalue += 2;
456   if (0 == smtp_set_header (message, filter, fvalue))
457   {
458     GNUNET_GE_LOG (ectx,
459                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
460                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
461                    "smtp_set_header", smtp_strerror (smtp_errno (), ebuf,
462                                                      EBUF_LEN));
463     smtp_destroy_session (session);
464     GNUNET_mutex_unlock (lock);
465     GNUNET_free (filter);
466     return GNUNET_SYSERR;
467   }
468   GNUNET_free (filter);
469   m = GNUNET_malloc (size + sizeof(SMTPMessage));
470   GNUNET_memcpy (m, msg, size);
471   mp = (SMTPMessage *) &m[size];
472   mp->header.size = htons (size + sizeof(SMTPMessage));
473   mp->header.type = htons (0);
474   mp->sender = *core_api->my_identity;
475   gm_cls.ebody = NULL;
476   gm_cls.pos = 0;
477   gm_cls.esize = GNUNET_STRINGS_base64_encode (m, size + sizeof(SMTPMessage),
478                                                &gm_cls.ebody);
479   GNUNET_free (m);
480   if (0 == smtp_size_set_estimate (message, gm_cls.esize))
481   {
482     GNUNET_GE_LOG (ectx,
483                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
484                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
485                    "smtp_size_set_estimate", smtp_strerror (smtp_errno (), ebuf,
486                                                             EBUF_LEN));
487   }
488   if (0 == smtp_set_messagecb (message, &get_message, &gm_cls))
489   {
490     GNUNET_GE_LOG (ectx,
491                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
492                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
493                    "smtp_set_messagecb", smtp_strerror (smtp_errno (), ebuf,
494                                                         EBUF_LEN));
495     smtp_destroy_session (session);
496     GNUNET_mutex_unlock (lock);
497     GNUNET_free (gm_cls.ebody);
498     return GNUNET_SYSERR;
499   }
500   recipient = smtp_add_recipient (message, haddr->senderAddress);
501   if (recipient == NULL)
502   {
503     GNUNET_GE_LOG (ectx,
504                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
505                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
506                    "smtp_add_recipient", smtp_strerror (smtp_errno (), ebuf,
507                                                         EBUF_LEN));
508     smtp_destroy_session (session);
509     GNUNET_mutex_unlock (lock);
510     return GNUNET_SYSERR;
511   }
512   if (0 == smtp_start_session (session))
513   {
514     GNUNET_GE_LOG (ectx,
515                    GNUNET_GE_WARNING | GNUNET_GE_ADMIN | GNUNET_GE_USER
516                    | GNUNET_GE_BULK, _ ("SMTP: `%s' failed: %s.\n"),
517                    "smtp_start_session", smtp_strerror (smtp_errno (), ebuf,
518                                                         EBUF_LEN));
519     smtp_destroy_session (session);
520     GNUNET_mutex_unlock (lock);
521     GNUNET_free (gm_cls.ebody);
522     return GNUNET_SYSERR;
523   }
524   if (stats != NULL)
525     stats->change (stat_bytesSent, size);
526   if (core_api->load_monitor != NULL)
527     GNUNET_network_monitor_notify_transmission (core_api->load_monitor,
528                                                 GNUNET_ND_UPLOAD, gm_cls.esize);
529   smtp_message_reset_status (message);   /* this is needed to plug a 28-byte/message memory leak in libesmtp */
530   smtp_destroy_session (session);
531   GNUNET_mutex_unlock (lock);
532   GNUNET_free (gm_cls.ebody);
533   return GNUNET_OK;
534 }
535
536
537 /**
538  * Establish a connection to a remote node.
539  * @param hello the hello-Message for the target node
540  * @param tsessionPtr the session handle that is to be set
541  * @param may_reuse can we re-use an existing connection?
542  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
543  */
544 static int
545 api_connect (const GNUNET_MessageHello *hello, GNUNET_TSession **tsessionPtr,
546              int may_reuse)
547 {
548   GNUNET_TSession *tsession;
549
550   tsession = GNUNET_new (GNUNET_TSession);
551   tsession->internal = GNUNET_malloc (GNUNET_sizeof_hello (hello));
552   tsession->peer = hello->senderIdentity;
553   GNUNET_memcpy (tsession->internal, hello, GNUNET_sizeof_hello (hello));
554   tsession->ttype = smtpAPI.protocol_number;
555   (*tsessionPtr) = tsession;
556   return GNUNET_OK;
557 }
558
559
560 /**
561  * Disconnect from a remote node.
562  *
563  * @param tsession the session that is closed
564  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
565  */
566 static int
567 api_disconnect (GNUNET_TSession *tsession)
568 {
569   if (tsession != NULL)
570   {
571     if (tsession->internal != NULL)
572       GNUNET_free (tsession->internal);
573     GNUNET_free (tsession);
574   }
575   return GNUNET_OK;
576 }
577
578
579 /**
580  * Start the server process to receive inbound traffic.
581  * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
582  */
583 static int
584 api_start_transport_server ()
585 {
586   smtp_shutdown = GNUNET_NO;
587   /* initialize SMTP network */
588   dispatchThread = GNUNET_thread_create (&listenAndDistribute, NULL, 1024 * 4);
589   if (dispatchThread == NULL)
590   {
591     GNUNET_GE_DIE_STRERROR (ectx,
592                             GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
593                             "pthread_create");
594     return GNUNET_SYSERR;
595   }
596   return GNUNET_OK;
597 }
598
599
600 /**
601  * Shutdown the server process (stop receiving inbound traffic). Maybe
602  * restarted later!
603  */
604 static int
605 api_stop_transport_server ()
606 {
607   void *unused;
608
609   smtp_shutdown = GNUNET_YES;
610   GNUNET_thread_stop_sleep (dispatchThread);
611   GNUNET_thread_join (dispatchThread, &unused);
612   return GNUNET_OK;
613 }
614
615
616 /**
617  * Convert SMTP hello to an IP address (always fails).
618  */
619 static int
620 api_hello_to_address (const GNUNET_MessageHello *hello, void **sa,
621                       unsigned int *sa_len)
622 {
623   return GNUNET_SYSERR;
624 }
625
626
627 /**
628  * Always fails.
629  */
630 static int
631 api_associate (GNUNET_TSession *tsession)
632 {
633   return GNUNET_SYSERR;         /* SMTP connections can never be associated */
634 }
635
636
637 /**
638  * Always succeeds (for now; we should look at adding
639  * frequency limits to SMTP in the future!).
640  */
641 static int
642 api_test_would_try (GNUNET_TSession *tsession, unsigned int size,
643                     int important)
644 {
645   return GNUNET_OK;             /* we always try... */
646 }
647
648
649 /**
650  * The exported method. Makes the core api available via a global and
651  * returns the smtp transport API.
652  */
653 GNUNET_TransportAPI *
654 inittransport_smtp (struct GNUNET_CoreAPIForTransport *core)
655 {
656   unsigned long long mtu;
657   struct sigaction sa;
658
659   core_api = core;
660   ectx = core->ectx;
661   if (! GNUNET_GC_have_configuration_value (core_api->cfg, "SMTP", "EMAIL"))
662   {
663     GNUNET_GE_LOG (ectx, GNUNET_GE_ERROR | GNUNET_GE_BULK | GNUNET_GE_USER,
664                    _
665                    (
666                      "No email-address specified, can not start SMTP transport.\n"));
667     return NULL;
668   }
669   GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "MTU", 1200,
670                                             SMTP_MESSAGE_SIZE,
671                                             SMTP_MESSAGE_SIZE, &mtu);
672   GNUNET_GC_get_configuration_value_number (core_api->cfg, "SMTP", "RATELIMIT",
673                                             0, 0, 1024 * 1024, &rate_limit);
674   stats = core_api->service_request ("stats");
675   if (stats != NULL)
676   {
677     stat_bytesReceived =
678       stats->create (gettext_noop ("# bytes received via SMTP"));
679     stat_bytesSent = stats->create (gettext_noop ("# bytes sent via SMTP"));
680     stat_bytesDropped =
681       stats->create (gettext_noop ("# bytes dropped by SMTP (outgoing)"));
682   }
683   GNUNET_GC_get_configuration_value_filename (core_api->cfg, "SMTP", "PIPE",
684                                               &pipename);
685   unlink (pipename);
686   if (0 != mkfifo (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
687   {
688     GNUNET_GE_LOG_STRERROR (ectx,
689                             GNUNET_GE_ADMIN | GNUNET_GE_BULK | GNUNET_GE_FATAL,
690                             "mkfifo");
691     GNUNET_free (pipename);
692     core_api->service_release (stats);
693     stats = NULL;
694     return NULL;
695   }
696   /* we need to allow the mailer program to send us messages;
697    * easiest done by giving it write permissions (see Mantis #1142) */
698   if (0 != chmod (pipename, S_IWUSR | S_IRUSR | S_IWGRP | S_IWOTH))
699     GNUNET_GE_LOG_STRERROR (ectx,
700                             GNUNET_GE_ADMIN | GNUNET_GE_BULK
701                             | GNUNET_GE_WARNING, "chmod");
702   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "EMAIL",
703                                             NULL,
704                                             &email);
705   lock = GNUNET_mutex_create (GNUNET_NO);
706   GNUNET_GC_get_configuration_value_string (core_api->cfg, "SMTP", "SERVER",
707                                             "localhost:25", &smtp_server_name);
708   sa.sa_handler = SIG_IGN;
709   sigemptyset (&sa.sa_mask);
710   sa.sa_flags = 0;
711   sigaction (SIGPIPE, &sa, &old_handler);
712
713   smtpAPI.protocol_number = GNUNET_TRANSPORT_PROTOCOL_NUMBER_SMTP;
714   smtpAPI.mtu = mtu - sizeof(SMTPMessage);
715   smtpAPI.cost = 50;
716   smtpAPI.hello_verify = &api_verify_hello;
717   smtpAPI.hello_create = &api_create_hello;
718   smtpAPI.connect = &api_connect;
719   smtpAPI.send = &api_send;
720   smtpAPI.associate = &api_associate;
721   smtpAPI.disconnect = &api_disconnect;
722   smtpAPI.server_start = &api_start_transport_server;
723   smtpAPI.server_stop = &api_stop_transport_server;
724   smtpAPI.hello_to_address = &api_hello_to_address;
725   smtpAPI.send_now_test = &api_test_would_try;
726   return &smtpAPI;
727 }
728
729
730 void
731 donetransport_smtp ()
732 {
733   sigaction (SIGPIPE, &old_handler, NULL);
734   GNUNET_free (smtp_server_name);
735   if (stats != NULL)
736   {
737     core_api->service_release (stats);
738     stats = NULL;
739   }
740   GNUNET_mutex_destroy (lock);
741   lock = NULL;
742   unlink (pipename);
743   GNUNET_free (pipename);
744   pipename = NULL;
745   GNUNET_free (email);
746   email = NULL;
747 }
748
749
750 /* end of smtp.c */