Commit 23b38a51 23b38a51e5c21829b7c9972390af4369757c710a by Wojciech Polak

Moved to ../libproto/mailer/

1 parent 0e9867f7
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #ifdef ENABLE_SENDMAIL
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include <sys/types.h>
34 #include <sys/wait.h>
35
36 #include <mailutils/address.h>
37 #include <mailutils/debug.h>
38 #include <mailutils/message.h>
39 #include <mailutils/observer.h>
40 #include <mailutils/property.h>
41 #include <mailutils/stream.h>
42 #include <mailutils/url.h>
43 #include <mailutils/header.h>
44 #include <mailutils/body.h>
45 #include <mailutils/errno.h>
46
47 #include <mailer0.h>
48 #include <registrar0.h>
49
50 static struct _mu_record _sendmail_record =
51 {
52 MU_SENDMAIL_PRIO,
53 MU_SENDMAIL_SCHEME,
54 _url_sendmail_init, /* url init. */
55 NULL, /* Mailbox entry. */
56 _mailer_sendmail_init, /* Mailer entry. */
57 NULL, /* Folder entry. */
58 NULL, /* No need for a back pointer. */
59 NULL, /* _is_scheme method. */
60 NULL, /* _get_url method. */
61 NULL, /* _get_mailbox method. */
62 NULL, /* _get_mailer method. */
63 NULL /* _get_folder method. */
64 };
65 /* We export, url parsing and the initialisation of
66 the mailbox, via the register entry/record. */
67 mu_record_t mu_sendmail_record = &_sendmail_record;
68
69 struct _sendmail
70 {
71 int dsn;
72 char *path;
73 pid_t pid;
74 off_t offset;
75 int fd;
76 enum sendmail_state { SENDMAIL_CLOSED, SENDMAIL_OPEN, SENDMAIL_SEND } state;
77 };
78
79 typedef struct _sendmail * sendmail_t;
80
81 static void sendmail_destroy (mu_mailer_t);
82 static int sendmail_open (mu_mailer_t, int);
83 static int sendmail_close (mu_mailer_t);
84 static int sendmail_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
85
86 int
87 _mailer_sendmail_init (mu_mailer_t mailer)
88 {
89 sendmail_t sendmail;
90
91 /* Allocate memory specific to sendmail mailer. */
92 sendmail = mailer->data = calloc (1, sizeof (*sendmail));
93 if (mailer->data == NULL)
94 return ENOMEM;
95 sendmail->state = SENDMAIL_CLOSED;
96 mailer->_destroy = sendmail_destroy;
97 mailer->_open = sendmail_open;
98 mailer->_close = sendmail_close;
99 mailer->_send_message = sendmail_send_message;
100
101 /* Set our properties. */
102 {
103 mu_property_t property = NULL;
104 mu_mailer_get_property (mailer, &property);
105 mu_property_set_value (property, "TYPE", "SENDMAIL", 1);
106 }
107 return 0;
108 }
109
110 static void
111 sendmail_destroy(mu_mailer_t mailer)
112 {
113 sendmail_t sendmail = mailer->data;
114 if (sendmail)
115 {
116 if (sendmail->path)
117 free (sendmail->path);
118 free (sendmail);
119 mailer->data = NULL;
120 }
121 }
122
123 static int
124 sendmail_open (mu_mailer_t mailer, int flags)
125 {
126 sendmail_t sendmail = mailer->data;
127 int status;
128 char *path;
129
130 /* Sanity checks. */
131 if (sendmail == NULL)
132 return EINVAL;
133
134 mailer->flags = flags;
135
136 if ((status = mu_url_aget_path (mailer->url, &path)))
137 return status;
138
139 if (access (path, X_OK) == -1)
140 {
141 free (path);
142 return errno;
143 }
144 sendmail->path = path;
145 sendmail->state = SENDMAIL_OPEN;
146 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE, "sendmail (%s)\n", sendmail->path);
147 return 0;
148 }
149
150 static int
151 sendmail_close (mu_mailer_t mailer)
152 {
153 sendmail_t sendmail = mailer->data;
154
155 /* Sanity checks. */
156 if (sendmail == NULL)
157 return EINVAL;
158
159 if(sendmail->path)
160 free(sendmail->path);
161
162 sendmail->path = NULL;
163 sendmail->state = SENDMAIL_CLOSED;
164
165 return 0;
166 }
167
168 static int
169 mailer_property_is_set (mu_mailer_t mailer, const char *name)
170 {
171 mu_property_t property = NULL;
172
173 mu_mailer_get_property (mailer, &property);
174 return mu_property_is_set (property, name);
175 }
176
177
178 /* Close FD unless it is part of pipe P */
179 #define SCLOSE(fd,p) if (p[0]!=fd&&p[1]!=fd) close(fd)
180
181 static int
182 sendmail_send_message (mu_mailer_t mailer, mu_message_t msg, mu_address_t from,
183 mu_address_t to)
184 {
185 sendmail_t sendmail = mailer->data;
186 int status = 0;
187
188 if (sendmail == NULL || msg == NULL)
189 return EINVAL;
190
191 switch (sendmail->state)
192 {
193 case SENDMAIL_CLOSED:
194 return EINVAL;
195 case SENDMAIL_OPEN:
196 {
197 int tunnel[2];
198 int argc = 0;
199 const char **argvec = NULL;
200 size_t tocount = 0;
201 const char *emailfrom = NULL;
202
203 /* Count the length of the arg vec: */
204
205 argc++; /* terminating NULL */
206 argc++; /* sendmail */
207 argc++; /* -oi (do not treat '.' as message
208 terminator) */
209
210 if (from)
211 {
212 if ((status = mu_address_sget_email (from, 1, &emailfrom)) != 0)
213 goto OPEN_STATE_CLEANUP;
214
215 if (!emailfrom)
216 {
217 /* the address wasn't fully qualified, choke (for now) */
218 status = EINVAL;
219
220 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
221 "envelope from (%s) not fully qualifed\n",
222 emailfrom);
223
224 goto OPEN_STATE_CLEANUP;
225 }
226
227 argc += 2; /* -f from */
228 }
229
230 if (to)
231 {
232 status = mu_address_get_email_count (to, &tocount);
233
234 assert (!status);
235 assert (tocount);
236
237 argc += tocount; /* 1 per to address */
238 }
239
240 argc++; /* -t */
241
242 /* Allocate arg vec: */
243 if ((argvec = calloc (argc, sizeof (*argvec))) == 0)
244 {
245 status = ENOMEM;
246 goto OPEN_STATE_CLEANUP;
247 }
248
249 argc = 0;
250
251 argvec[argc++] = sendmail->path;
252 argvec[argc++] = "-oi";
253
254 if (from)
255 {
256 argvec[argc++] = "-f";
257 argvec[argc++] = emailfrom;
258 }
259
260 if (!to || mailer_property_is_set (mailer, "READ_RECIPIENTS"))
261 {
262 argvec[argc++] = "-t";
263 }
264 else
265 {
266 int i = 1;
267 size_t count = 0;
268
269 mu_address_get_count (to, &count);
270
271 for (; i <= count; i++)
272 {
273 const char *email;
274 if ((status = mu_address_sget_email (to, i, &email)) != 0)
275 goto OPEN_STATE_CLEANUP;
276 if (!email)
277 {
278 /* the address wasn't fully qualified, choke (for now) */
279 status = EINVAL;
280
281 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
282 "envelope to (%s) not fully qualifed\n",
283 email);
284
285 goto OPEN_STATE_CLEANUP;
286 }
287 argvec[argc++] = email;
288 }
289 }
290
291 assert (argvec[argc] == NULL);
292
293 if (pipe (tunnel) == 0)
294 {
295 sendmail->fd = tunnel[1];
296 sendmail->pid = vfork ();
297 if (sendmail->pid == 0) /* Child. */
298 {
299 SCLOSE (STDIN_FILENO, tunnel);
300 SCLOSE (STDOUT_FILENO, tunnel);
301 SCLOSE (STDERR_FILENO, tunnel);
302 close (tunnel[1]);
303 dup2 (tunnel[0], STDIN_FILENO);
304 execv (sendmail->path, (char**) argvec);
305 exit (errno);
306 }
307 else if (sendmail->pid == -1)
308 {
309 status = errno;
310
311 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
312 "vfork() failed: %s\n", strerror (status));
313 }
314 }
315 else
316 {
317 status = errno;
318 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
319 "pipe() failed: %s\n", strerror (status));
320 }
321
322 OPEN_STATE_CLEANUP:
323 MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "exec argv:");
324 for (argc = 0; argvec && argvec[argc]; argc++)
325 {
326 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE, " %s", argvec[argc]);
327 }
328 MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "\n");
329 free (argvec);
330 close (tunnel[0]);
331
332 if (status != 0)
333 {
334 close (sendmail->fd);
335 break;
336 }
337 sendmail->state = SENDMAIL_SEND;
338 }
339
340 case SENDMAIL_SEND:
341 {
342 mu_stream_t stream = NULL;
343 char buffer[512];
344 size_t len = 0;
345 int rc;
346 size_t offset = 0;
347 mu_header_t hdr;
348 mu_body_t body;
349 int found_nl = 0;
350 int exit_status;
351
352 mu_message_get_header (msg, &hdr);
353 mu_header_get_stream (hdr, &stream);
354
355 MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "Sending headers...\n");
356 while ((status = mu_stream_readline (stream, buffer, sizeof (buffer),
357 offset, &len)) == 0
358 && len != 0)
359 {
360 if (strncasecmp (buffer, MU_HEADER_FCC,
361 sizeof (MU_HEADER_FCC) - 1))
362 {
363 MAILER_DEBUG1 (mailer, MU_DEBUG_PROT,
364 "Header: %s", buffer);
365 if (write (sendmail->fd, buffer, len) == -1)
366 {
367 status = errno;
368
369 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
370 "write() failed: %s\n", strerror (status));
371
372 break;
373 }
374 }
375 found_nl = (len == 1 && buffer[0] == '\n');
376
377 offset += len;
378 sendmail->offset += len;
379 }
380
381 if (!found_nl)
382 {
383 if (write (sendmail->fd, "\n", 1) == -1)
384 {
385 status = errno;
386
387 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
388 "write() failed: %s\n", strerror (status));
389 }
390 }
391
392 mu_message_get_body (msg, &body);
393 mu_body_get_stream (body, &stream);
394
395 MAILER_DEBUG0 (mailer, MU_DEBUG_TRACE, "Sending body...\n");
396 offset = 0;
397 while ((status = mu_stream_read (stream, buffer, sizeof (buffer),
398 offset, &len)) == 0
399 && len != 0)
400 {
401 if (write (sendmail->fd, buffer, len) == -1)
402 {
403 status = errno;
404
405 MAILER_DEBUG1 (mailer, MU_DEBUG_TRACE,
406 "write() failed: %s\n", strerror (status));
407
408 break;
409 }
410 offset += len;
411 sendmail->offset += len;
412 }
413 if (status == EAGAIN)
414 return status;
415
416 close (sendmail->fd);
417
418 rc = waitpid (sendmail->pid, &exit_status, 0);
419
420 if (rc < 0)
421 {
422 if (errno == ECHILD)
423 status = 0;
424 else
425 {
426 status = errno;
427 MAILER_DEBUG2 (mailer, MU_DEBUG_TRACE,
428 "waitpid(%d) failed: %s\n",
429 sendmail->pid, strerror (status));
430 }
431 }
432 else if (WIFEXITED (exit_status))
433 {
434 exit_status = WEXITSTATUS (exit_status);
435 MAILER_DEBUG2 (mailer, MU_DEBUG_TRACE,
436 "%s exited with: %d\n",
437 sendmail->path, exit_status);
438 status = (exit_status == 0) ? 0 : MU_ERR_PROCESS_EXITED;
439 }
440 else if (WIFSIGNALED (exit_status))
441 status = MU_ERR_PROCESS_SIGNALED;
442 else
443 status = MU_ERR_PROCESS_UNKNOWN_FAILURE;
444
445 /* Shouldn't this notification only happen on success? */
446 mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT);
447 }
448 default:
449 break;
450 }
451
452 sendmail->state = (status == 0) ? SENDMAIL_OPEN : SENDMAIL_CLOSED;
453
454 return status;
455 }
456
457 #else
458 #include <stdio.h>
459 #include <registrar0.h>
460 mu_record_t mu_sendmail_record = NULL;
461 #endif
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001, 2004, 2005,
3 2006, 2007 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 3 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General
16 Public License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA */
19
20 /** @file smtp.c
21 @brief an SMTP mailer
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #ifdef ENABLE_SMTP
29
30 #include <errno.h>
31 #include <ctype.h>
32 #include <netdb.h>
33 #include <pwd.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include <mailutils/address.h>
41 #include <mailutils/debug.h>
42 #include <mailutils/errno.h>
43 #include <mailutils/header.h>
44 #include <mailutils/body.h>
45 #include <mailutils/message.h>
46 #include <mailutils/mutil.h>
47 #include <mailutils/observer.h>
48 #include <mailutils/property.h>
49 #include <mailutils/stream.h>
50 #include <mailutils/url.h>
51 #include <mailutils/tls.h>
52
53 #include <mailer0.h>
54 #include <registrar0.h>
55
56 static struct _mu_record _smtp_record = {
57 MU_SMTP_PRIO,
58 MU_SMTP_SCHEME,
59 _url_smtp_init, /* url init. */
60 NULL, /* Mailbox init. */
61 &_mailer_smtp_init, /* Mailer init. */
62 NULL, /* Folder init. */
63 NULL, /* No need for a back pointer. */
64 NULL, /* _is_scheme method. */
65 NULL, /* _get_url method. */
66 NULL, /* _get_mailbox method. */
67 NULL, /* _get_mailer method. */
68 NULL /* _get_folder method. */
69 };
70 /* We export : url parsing and the initialisation of
71 the mailbox, via the register entry/record. */
72 mu_record_t mu_smtp_record = &_smtp_record;
73
74 struct _smtp
75 {
76 mu_mailer_t mailer;
77 char *mailhost;
78 char *localhost;
79
80 /* IO buffering. */
81 char *buffer; /* Must be freed. */
82 size_t buflen;
83
84 char *ptr;
85 char *nl;
86 off_t s_offset;
87
88 enum smtp_state
89 {
90 SMTP_NO_STATE, SMTP_OPEN, SMTP_GREETINGS, SMTP_EHLO, SMTP_EHLO_ACK,
91 SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM,
92 SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO,
93 SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK,
94 SMTP_SEND_DOT, SMTP_STARTTLS, SMTP_STARTTLS_ACK
95 }
96 state;
97
98 int extended;
99 unsigned long capa; /* Server capabilities */
100
101 const char *mail_from;
102 mu_address_t rcpt_to; /* Destroy this if not the same as argto below. */
103 mu_address_t rcpt_bcc;
104 size_t rcpt_to_count;
105 size_t rcpt_bcc_count;
106 size_t rcpt_index;
107 size_t rcpt_count;
108 int bccing;
109 mu_message_t msg; /* Destroy this if not same argmsg. */
110
111 off_t offset;
112
113 /* The mu_mailer_send_message() args. */
114 mu_message_t argmsg;
115 mu_address_t argfrom;
116 mu_address_t argto;
117 };
118
119 typedef struct _smtp *smtp_t;
120
121 /* ESMTP capabilities */
122 #define CAPA_STARTTLS 0x00000001
123 #define CAPA_8BITMIME 0x00000002
124
125 static void smtp_destroy (mu_mailer_t);
126 static int smtp_open (mu_mailer_t, int);
127 static int smtp_close (mu_mailer_t);
128 static int smtp_send_message (mu_mailer_t, mu_message_t, mu_address_t, mu_address_t);
129 static int smtp_writeline (smtp_t smtp, const char *format, ...);
130 static int smtp_readline (smtp_t);
131 static int smtp_read_ack (smtp_t);
132 static int smtp_parse_ehlo_ack (smtp_t);
133 static int smtp_write (smtp_t);
134 static int smtp_starttls (smtp_t);
135
136 static int _smtp_set_rcpt (smtp_t, mu_message_t, mu_address_t);
137
138 /* Useful little macros, since these are very repetitive. */
139
140 static void
141 CLEAR_STATE (smtp_t smtp)
142 {
143 smtp->ptr = NULL;
144 smtp->nl = NULL;
145 smtp->s_offset = 0;
146
147 smtp->state = SMTP_NO_STATE;
148
149 smtp->extended = 0;
150
151 if (smtp->mail_from)
152 smtp->mail_from = NULL;
153
154 if (smtp->rcpt_to != smtp->argto)
155 mu_address_destroy (&smtp->rcpt_to);
156
157 smtp->rcpt_to = NULL;
158
159 mu_address_destroy (&smtp->rcpt_bcc);
160
161 smtp->rcpt_to_count = 0;
162 smtp->rcpt_bcc_count = 0;
163 smtp->rcpt_index = 0;
164 smtp->rcpt_count = 0;
165 smtp->bccing = 0;
166
167 if (smtp->msg != smtp->argmsg)
168 mu_message_destroy (&smtp->msg, NULL);
169
170 smtp->msg = NULL;
171
172 smtp->offset = 0;
173
174 smtp->argmsg = NULL;
175 smtp->argfrom = NULL;
176 smtp->argto = NULL;
177 }
178
179 /* If we are resuming, we should be resuming the SAME operation
180 as that which is ongoing. Check this. */
181 static int
182 smtp_check_send_resumption (smtp_t smtp,
183 mu_message_t msg, mu_address_t from, mu_address_t to)
184 {
185 if (smtp->state == SMTP_NO_STATE)
186 return 0;
187
188 /* FIXME: state should be one of the "send" states if its not
189 "no state" */
190 if (msg != smtp->argmsg)
191 return MU_ERR_BAD_RESUMPTION;
192
193 if (from != smtp->argfrom)
194 return MU_ERR_BAD_RESUMPTION;
195
196 if (to != smtp->argto)
197 return MU_ERR_BAD_RESUMPTION;
198
199 return 0;
200 }
201
202 #define CHECK_SEND_RESUME(smtp, msg, from, to) \
203 do { \
204 if((status = smtp_check_send_resumption(smtp, msg, from, to)) != 0) \
205 return status; \
206 } while (0)
207
208 /* Clear the state and close the stream. */
209 #define CHECK_ERROR_CLOSE(mailer, smtp, status) \
210 do \
211 { \
212 if (status != 0) \
213 { \
214 mu_stream_close (mailer->stream); \
215 CLEAR_STATE (smtp); \
216 return status; \
217 } \
218 } \
219 while (0)
220
221 /* Clear the state. */
222 #define CHECK_ERROR(smtp, status) \
223 do \
224 { \
225 if (status != 0) \
226 { \
227 CLEAR_STATE (smtp); \
228 return status; \
229 } \
230 } \
231 while (0)
232
233 /* Clear the state for non recoverable error. */
234 #define CHECK_EAGAIN(smtp, status) \
235 do \
236 { \
237 if (status != 0) \
238 { \
239 if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
240 { \
241 CLEAR_STATE (smtp); \
242 } \
243 return status; \
244 } \
245 } \
246 while (0)
247
248 int
249 _mailer_smtp_init (mu_mailer_t mailer)
250 {
251 smtp_t smtp;
252
253 /* Allocate memory specific to smtp mailer. */
254 smtp = mailer->data = calloc (1, sizeof (*smtp));
255 if (mailer->data == NULL)
256 return ENOMEM;
257
258 smtp->mailer = mailer; /* Back pointer. */
259 smtp->state = SMTP_NO_STATE;
260
261 mailer->_destroy = smtp_destroy;
262 mailer->_open = smtp_open;
263 mailer->_close = smtp_close;
264 mailer->_send_message = smtp_send_message;
265
266 /* Set our properties. */
267 {
268 mu_property_t property = NULL;
269 mu_mailer_get_property (mailer, &property);
270 mu_property_set_value (property, "TYPE", "SMTP", 1);
271 }
272
273 return 0;
274 }
275
276 static void
277 smtp_destroy (mu_mailer_t mailer)
278 {
279 smtp_t smtp = mailer->data;
280
281 CLEAR_STATE (smtp);
282
283 /* Not our responsability to close. */
284
285 if (smtp->mailhost)
286 free (smtp->mailhost);
287 if (smtp->localhost)
288 free (smtp->localhost);
289 if (smtp->buffer)
290 free (smtp->buffer);
291
292 free (smtp);
293
294 mailer->data = NULL;
295 }
296
297 /** Open an SMTP mailer.
298 An SMTP mailer must be opened before any messages can be sent.
299 @param mailer the mailer created by smtp_create()
300 @param flags the mailer flags
301 */
302 static int
303 smtp_open (mu_mailer_t mailer, int flags)
304 {
305 smtp_t smtp = mailer->data;
306 int status;
307 long port;
308
309 /* Sanity checks. */
310 if (!smtp)
311 return EINVAL;
312
313 mailer->flags = flags;
314
315 if ((status = mu_url_get_port (mailer->url, &port)) != 0)
316 return status;
317
318 switch (smtp->state)
319 {
320 case SMTP_NO_STATE:
321 if (smtp->mailhost)
322 {
323 free (smtp->mailhost);
324 smtp->mailhost = NULL;
325 }
326
327 /* Fetch the mailer server name and the port in the mu_url_t. */
328 if ((status = mu_url_aget_host (mailer->url, &smtp->mailhost)) != 0)
329 return status;
330
331 if (smtp->localhost)
332 {
333 free (smtp->localhost);
334 smtp->localhost = NULL;
335 }
336 /* Fetch our local host name. */
337
338 status = mu_get_host_name (&smtp->localhost);
339
340 if (status != 0)
341 {
342 /* gethostname failed, abort. */
343 free (smtp->mailhost);
344 smtp->mailhost = NULL;
345 return status;
346 }
347
348 /* allocate a working io buffer. */
349 if (smtp->buffer == NULL)
350 {
351 smtp->buflen = 512; /* Initial guess. */
352 smtp->buffer = malloc (smtp->buflen + 1);
353 if (smtp->buffer == NULL)
354 {
355 CHECK_ERROR (smtp, ENOMEM);
356 }
357 smtp->ptr = smtp->buffer;
358 }
359
360 /* Create a TCP stack if one is not given. */
361 if (mailer->stream == NULL)
362 {
363 status =
364 mu_tcp_stream_create (&mailer->stream, smtp->mailhost, port,
365 mailer->flags);
366 CHECK_ERROR (smtp, status);
367 mu_stream_setbufsiz (mailer->stream, BUFSIZ);
368 }
369 CHECK_ERROR (smtp, status);
370 smtp->state = SMTP_OPEN;
371
372 case SMTP_OPEN:
373 MAILER_DEBUG2 (mailer, MU_DEBUG_PROT, "smtp_open (host: %s port: %ld)\n",
374 smtp->mailhost, port);
375 status = mu_stream_open (mailer->stream);
376 CHECK_EAGAIN (smtp, status);
377 smtp->state = SMTP_GREETINGS;
378
379 case SMTP_GREETINGS:
380 /* Swallow the greetings. */
381 status = smtp_read_ack (smtp);
382 CHECK_EAGAIN (smtp, status);
383
384 if (smtp->buffer[0] != '2')
385 {
386 mu_stream_close (mailer->stream);
387 return EACCES;
388 }
389 status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost);
390 CHECK_ERROR (smtp, status);
391
392 smtp->state = SMTP_EHLO;
393
394 case SMTP_EHLO:
395 /* We first try Extended SMTP. */
396 status = smtp_write (smtp);
397 CHECK_EAGAIN (smtp, status);
398 smtp->state = SMTP_EHLO_ACK;
399
400 case SMTP_EHLO_ACK:
401 status = smtp_parse_ehlo_ack (smtp);
402 CHECK_EAGAIN (smtp, status);
403
404 if (smtp->buffer[0] != '2')
405 {
406 smtp->extended = 0;
407 status = smtp_writeline (smtp, "HELO %s\r\n", smtp->localhost);
408 CHECK_ERROR (smtp, status);
409 smtp->state = SMTP_HELO;
410 }
411 else
412 {
413 smtp->extended = 1;
414
415 if (smtp->capa & CAPA_STARTTLS)
416 smtp->state = SMTP_STARTTLS;
417 else
418 break;
419 }
420
421 case SMTP_STARTTLS:
422 case SMTP_STARTTLS_ACK:
423 smtp_starttls (smtp);
424 break;
425
426 case SMTP_HELO:
427 if (!smtp->extended) /* FIXME: this will always be false! */
428 {
429 status = smtp_write (smtp);
430 CHECK_EAGAIN (smtp, status);
431 }
432 smtp->state = SMTP_HELO_ACK;
433
434 case SMTP_HELO_ACK:
435 if (!smtp->extended)
436 {
437 status = smtp_read_ack (smtp);
438 CHECK_EAGAIN (smtp, status);
439
440 if (smtp->buffer[0] != '2')
441 {
442 mu_stream_close (mailer->stream);
443 CLEAR_STATE (smtp);
444 return EACCES;
445 }
446 }
447
448 default:
449 break;
450 }
451
452 CLEAR_STATE (smtp);
453
454 return 0;
455 }
456
457 static int
458 smtp_close (mu_mailer_t mailer)
459 {
460 smtp_t smtp = mailer->data;
461 int status;
462 switch (smtp->state)
463 {
464 case SMTP_NO_STATE:
465 status = smtp_writeline (smtp, "QUIT\r\n");
466 CHECK_ERROR (smtp, status);
467
468 smtp->state = SMTP_QUIT;
469
470 case SMTP_QUIT:
471 status = smtp_write (smtp);
472 CHECK_EAGAIN (smtp, status);
473 smtp->state = SMTP_QUIT_ACK;
474
475 case SMTP_QUIT_ACK:
476 status = smtp_read_ack (smtp);
477 CHECK_EAGAIN (smtp, status);
478
479 default:
480 break;
481 }
482 return mu_stream_close (mailer->stream);
483 }
484
485 /*
486 Client side STARTTLS support.
487 */
488
489 static int
490 smtp_reader (void *iodata)
491 {
492 int status = 0;
493 smtp_t iop = iodata;
494 status = smtp_read_ack (iop);
495 CHECK_EAGAIN (iop, status);
496 return status;
497 }
498
499 static int
500 smtp_writer (void *iodata, char *buf)
501 {
502 smtp_t iop = iodata;
503 int status;
504 if (strncasecmp (buf, "EHLO", 4) == 0)
505 status = smtp_writeline (iop, "%s %s\r\n", buf, iop->localhost);
506 else
507 status = smtp_writeline (iop, "%s\r\n", buf);
508 CHECK_ERROR (iop, status);
509 status = smtp_write (iop);
510 CHECK_EAGAIN (iop, status);
511 return status;
512 }
513
514 static void
515 smtp_stream_ctl (void *iodata, mu_stream_t *pold, mu_stream_t new)
516 {
517 smtp_t iop = iodata;
518 if (pold)
519 *pold = iop->mailer->stream;
520 if (new)
521 iop->mailer->stream = new;
522 }
523
524 static int
525 smtp_starttls (smtp_t smtp)
526 {
527 #ifdef WITH_TLS
528 int status;
529 mu_mailer_t mailer = smtp->mailer;
530 char *keywords[] = { "STARTTLS", "EHLO", NULL };
531
532 if (!mu_tls_enable || !(smtp->capa & CAPA_STARTTLS))
533 return -1;
534
535 smtp->capa = 0;
536 status = mu_tls_begin (smtp, smtp_reader, smtp_writer,
537 smtp_stream_ctl, keywords);
538
539 MAILER_DEBUG1 (mailer, MU_DEBUG_PROT, "TLS negotiation %s\n",
540 status == 0 ? "succeeded" : "failed");
541
542 return status;
543 #else
544 return -1;
545 #endif /* WITH_TLS */
546 }
547
548 static int
549 message_set_header_value (mu_message_t msg, const char *field, const char *value)
550 {
551 int status = 0;
552 mu_header_t hdr = NULL;
553
554 if ((status = mu_message_get_header (msg, &hdr)))
555 return status;
556
557 if ((status = mu_header_set_value (hdr, field, value, 1)))
558 return status;
559
560 return status;
561 }
562
563 static int
564 message_has_bcc (mu_message_t msg)
565 {
566 int status;
567 mu_header_t header = NULL;
568 size_t bccsz = 0;
569
570 if ((status = mu_message_get_header (msg, &header)))
571 return status;
572
573 status = mu_header_get_value (header, MU_HEADER_BCC, NULL, 0, &bccsz);
574
575 /* MU_ERR_NOENT, or there was a Bcc: field. */
576 return status == MU_ERR_NOENT ? 0 : 1;
577 }
578
579 /*
580
581 The smtp mailer doesn't deal with mail like:
582
583 To: public@com, pub2@com
584 Bcc: hidden@there, two@there
585
586 It just sends the message to all the addresses, making the
587 "blind" cc not particularly blind.
588
589 The correct algorithm is
590
591 - open smtp connection
592 - look as msg, figure out addrto&cc, and addrbcc
593 - deliver to the to & cc addresses:
594 - if there are bcc addrs, remove the bcc field
595 - send the message to to & cc addrs:
596 mail from: me
597 rcpt to: public@com
598 rcpt to: pub2@com
599 data
600 ...
601
602 - deliver to the bcc addrs:
603
604 for a in (bccaddrs)
605 do
606 - add header field to msg, bcc: $a
607 - send the msg:
608 mail from: me
609 rcpt to: $a
610 data
611 ...
612 done
613
614 - quit smtp connection
615
616 */
617
618 static int
619 smtp_send_message (mu_mailer_t mailer, mu_message_t argmsg, mu_address_t argfrom,
620 mu_address_t argto)
621 {
622 smtp_t smtp = NULL;
623 int status;
624
625 if (mailer == NULL)
626 return EINVAL;
627
628 smtp = mailer->data;
629 if (!smtp)
630 return EINVAL;
631
632 CHECK_SEND_RESUME (smtp, argmsg, argfrom, argto);
633
634 switch (smtp->state)
635 {
636 case SMTP_NO_STATE:
637 if (argmsg == NULL || argfrom == NULL)
638 return EINVAL;
639
640 smtp->argmsg = smtp->msg = argmsg;
641 smtp->argfrom = argfrom;
642 smtp->argto = argto;
643
644 status = mu_address_sget_email (smtp->argfrom, 1, &smtp->mail_from);
645 CHECK_ERROR (smtp, status);
646
647 status = _smtp_set_rcpt (smtp, smtp->argmsg, smtp->argto);
648 CHECK_ERROR (smtp, status);
649
650 /* Clear the Bcc: field if we found one. */
651 if (message_has_bcc (smtp->argmsg))
652 {
653 smtp->msg = NULL;
654 status = mu_message_create_copy (&smtp->msg, smtp->argmsg);
655 CHECK_ERROR (smtp, status);
656
657 status = message_set_header_value (smtp->msg, MU_HEADER_BCC, NULL);
658 CHECK_ERROR (smtp, status);
659 }
660
661 /* Begin bccing if there are not To: recipients. */
662 if (smtp->rcpt_to_count == 0)
663 smtp->bccing = 1;
664
665 smtp->rcpt_index = 1;
666
667 smtp->state = SMTP_ENV_FROM;
668
669 case SMTP_ENV_FROM:
670 ENV_FROM:
671 {
672 status = smtp_writeline (smtp, "MAIL FROM: <%s>\r\n", smtp->mail_from);
673 CHECK_ERROR (smtp, status);
674 smtp->state = SMTP_MAIL_FROM;
675 }
676
677 /* We use a goto, since we may have multiple messages,
678 we come back here and doit all over again ... Not pretty. */
679 case SMTP_MAIL_FROM:
680 status = smtp_write (smtp);
681 CHECK_EAGAIN (smtp, status);
682 smtp->state = SMTP_MAIL_FROM_ACK;
683
684 case SMTP_MAIL_FROM_ACK:
685 status = smtp_read_ack (smtp);
686 CHECK_EAGAIN (smtp, status);
687 if (smtp->buffer[0] != '2')
688 {
689 mu_stream_close (mailer->stream);
690 CLEAR_STATE (smtp);
691 return EACCES;
692 }
693
694 /* We use a goto, since we may have multiple recipients,
695 we come back here and do it all over again ... Not pretty. */
696 case SMTP_ENV_RCPT:
697 ENV_RCPT:
698 {
699 mu_address_t addr = smtp->rcpt_to;
700 const char *to = NULL;
701
702 if (smtp->bccing)
703 addr = smtp->rcpt_bcc;
704 status = mu_address_sget_email (addr, smtp->rcpt_index, &to);
705
706 CHECK_ERROR (smtp, status);
707
708 /* Add the Bcc: field back in for recipient. */
709 if (smtp->bccing)
710 {
711 status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to);
712 CHECK_ERROR (smtp, status);
713 }
714
715 status = smtp_writeline (smtp, "RCPT TO: <%s>\r\n", to);
716
717 CHECK_ERROR (smtp, status);
718
719 smtp->state = SMTP_RCPT_TO;
720 smtp->rcpt_index++;
721 }
722
723 case SMTP_RCPT_TO:
724 status = smtp_write (smtp);
725 CHECK_EAGAIN (smtp, status);
726 smtp->state = SMTP_RCPT_TO_ACK;
727
728 case SMTP_RCPT_TO_ACK:
729 status = smtp_read_ack (smtp);
730 CHECK_EAGAIN (smtp, status);
731 if (smtp->buffer[0] != '2')
732 {
733 mu_stream_close (mailer->stream);
734 CLEAR_STATE (smtp);
735 return MU_ERR_SMTP_RCPT_FAILED;
736 }
737 /* Redo the receipt sequence for every To: and Cc: recipient. */
738 if (!smtp->bccing && smtp->rcpt_index <= smtp->rcpt_to_count)
739 goto ENV_RCPT;
740
741 /* We are done with the rcpt. */
742 status = smtp_writeline (smtp, "DATA\r\n");
743 CHECK_ERROR (smtp, status);
744 smtp->state = SMTP_DATA;
745
746 case SMTP_DATA:
747 status = smtp_write (smtp);
748 CHECK_EAGAIN (smtp, status);
749 smtp->state = SMTP_DATA_ACK;
750
751 case SMTP_DATA_ACK:
752 status = smtp_read_ack (smtp);
753 CHECK_EAGAIN (smtp, status);
754 if (smtp->buffer[0] != '3')
755 {
756 mu_stream_close (mailer->stream);
757 CLEAR_STATE (smtp);
758 return EACCES;
759 }
760 smtp->offset = 0;
761 smtp->state = SMTP_SEND;
762
763 if ((smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) == 0)
764 MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_PROT, "> (data...)\n");
765
766 case SMTP_SEND:
767 {
768 mu_stream_t stream;
769 size_t n = 0;
770 char data[256] = "";
771 mu_header_t hdr;
772 mu_body_t body;
773 int found_nl;
774
775 /* We may be here after an EAGAIN so check if we have something
776 in the buffer and flush it. */
777 status = smtp_write (smtp);
778 CHECK_EAGAIN (smtp, status);
779
780 mu_message_get_header (smtp->msg, &hdr);
781 mu_header_get_stream (hdr, &stream);
782 while ((status = mu_stream_readline (stream, data, sizeof (data),
783 smtp->offset, &n)) == 0 && n > 0)
784 {
785 int nl;
786
787 found_nl = (n == 1 && data[0] == '\n');
788 if ((nl = (data[n - 1] == '\n')))
789 data[n - 1] = '\0';
790 if (data[0] == '.')
791 {
792 status = smtp_writeline (smtp, ".%s", data);
793 CHECK_ERROR (smtp, status);
794 }
795 else if (strncasecmp (data, MU_HEADER_FCC,
796 sizeof (MU_HEADER_FCC) - 1))
797 {
798 status = smtp_writeline (smtp, "%s", data);
799 CHECK_ERROR (smtp, status);
800 status = smtp_write (smtp);
801 CHECK_EAGAIN (smtp, status);
802 }
803 else
804 nl = 0;
805
806 if (nl)
807 {
808 status = smtp_writeline (smtp, "\r\n");
809 CHECK_ERROR (smtp, status);
810 status = smtp_write (smtp);
811 CHECK_EAGAIN (smtp, status);
812 }
813 smtp->offset += n;
814 }
815
816 if (!found_nl)
817 {
818 status = smtp_writeline (smtp, "\r\n");
819 CHECK_ERROR (smtp, status);
820 status = smtp_write (smtp);
821 CHECK_EAGAIN (smtp, status);
822 }
823
824 mu_message_get_body (smtp->msg, &body);
825 mu_body_get_stream (body, &stream);
826 smtp->offset = 0;
827 while ((status = mu_stream_readline (stream, data, sizeof (data) - 1,
828 smtp->offset, &n)) == 0 && n > 0)
829 {
830 if (data[n - 1] == '\n')
831 data[n - 1] = '\0';
832 if (data[0] == '.')
833 status = smtp_writeline (smtp, ".%s\r\n", data);
834 else
835 status = smtp_writeline (smtp, "%s\r\n", data);
836 CHECK_ERROR (smtp, status);
837 status = smtp_write (smtp);
838 CHECK_EAGAIN (smtp, status);
839 smtp->offset += n;
840 }
841
842 smtp->offset = 0;
843 status = smtp_writeline (smtp, ".\r\n");
844 CHECK_ERROR (smtp, status);
845 smtp->state = SMTP_SEND_DOT;
846 }
847
848 case SMTP_SEND_DOT:
849 status = smtp_write (smtp);
850 CHECK_EAGAIN (smtp, status);
851 smtp->state = SMTP_SEND_ACK;
852
853 case SMTP_SEND_ACK:
854 status = smtp_read_ack (smtp);
855 CHECK_EAGAIN (smtp, status);
856 if (smtp->buffer[0] != '2')
857 {
858 mu_stream_close (mailer->stream);
859 CLEAR_STATE (smtp);
860 return EACCES;
861 }
862
863 /* Decide whether we need to loop again, to deliver to Bcc:
864 recipients. */
865 if (!smtp->bccing)
866 {
867 smtp->bccing = 1;
868 smtp->rcpt_index = 1;
869 }
870 if (smtp->rcpt_index <= smtp->rcpt_bcc_count)
871 goto ENV_FROM;
872
873 mu_observable_notify (mailer->observable, MU_EVT_MAILER_MESSAGE_SENT);
874
875 default:
876 break;
877 }
878 CLEAR_STATE (smtp);
879 return 0;
880 }
881
882 int
883 smtp_address_add (mu_address_t *paddr, const char *value)
884 {
885 mu_address_t addr = NULL;
886 int status;
887
888 status = mu_address_create (&addr, value);
889 if (status)
890 return status;
891 status = mu_address_union (paddr, addr);
892 mu_address_destroy (&addr);
893 return status;
894 }
895
896 static int
897 _smtp_property_is_set (smtp_t smtp, const char *name)
898 {
899 mu_property_t property = NULL;
900
901 mu_mailer_get_property (smtp->mailer, &property);
902 return mu_property_is_set (property, name);
903 }
904
905 static int
906 _smtp_set_rcpt (smtp_t smtp, mu_message_t msg, mu_address_t to)
907 {
908 int status = 0;
909 mu_header_t header = NULL;
910 char *value;
911
912 /* Get RCPT_TO from TO, or the message. */
913
914 if (to)
915 {
916 /* Use the specified mu_address_t. */
917 if ((status = mu_mailer_check_to (to)) != 0)
918 {
919 MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_ERROR,
920 "mu_mailer_send_message(): explicit to not valid\n");
921 return status;
922 }
923 smtp->rcpt_to = to;
924 mu_address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count);
925
926 if (status)
927 return status;
928 }
929
930 if (!to || _smtp_property_is_set (smtp, "READ_RECIPIENTS"))
931 {
932 if ((status = mu_message_get_header (msg, &header)))
933 return status;
934
935 status = mu_header_aget_value (header, MU_HEADER_TO, &value);
936
937 if (status == 0)
938 {
939 smtp_address_add (&smtp->rcpt_to, value);
940 free (value);
941 }
942 else if (status != MU_ERR_NOENT)
943 goto end;
944
945 status = mu_header_aget_value (header, MU_HEADER_CC, &value);
946
947 if (status == 0)
948 {
949 smtp_address_add (&smtp->rcpt_to, value);
950 free (value);
951 }
952 else if (status != MU_ERR_NOENT)
953 goto end;
954
955 status = mu_header_aget_value (header, MU_HEADER_BCC, &value);
956 if (status == 0)
957 {
958 smtp_address_add (&smtp->rcpt_bcc, value);
959 free (value);
960 }
961 else if (status != MU_ERR_NOENT)
962 goto end;
963
964 /* If to or bcc is present, the must be OK. */
965 if (smtp->rcpt_to && (status = mu_mailer_check_to (smtp->rcpt_to)))
966 goto end;
967
968 if (smtp->rcpt_bcc && (status = mu_mailer_check_to (smtp->rcpt_bcc)))
969 goto end;
970 }
971
972 end:
973
974 if (status)
975 {
976 mu_address_destroy (&smtp->rcpt_to);
977 mu_address_destroy (&smtp->rcpt_bcc);
978 }
979 else
980 {
981 if (smtp->rcpt_to)
982 mu_address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count);
983
984 if (smtp->rcpt_bcc)
985 mu_address_get_count (smtp->rcpt_bcc, &smtp->rcpt_bcc_count);
986
987 if (smtp->rcpt_to_count + smtp->rcpt_bcc_count == 0)
988 status = MU_ERR_MAILER_NO_RCPT_TO;
989 }
990
991 return status;
992 }
993
994 /* C99 says that a conforming implementations of snprintf ()
995 should return the number of char that would have been call
996 but many GNU/Linux && BSD implementations return -1 on error.
997 Worse QNX/Neutrino actually does not put the terminal
998 null char. So let's try to cope. */
999 static int
1000 smtp_writeline (smtp_t smtp, const char *format, ...)
1001 {
1002 int len;
1003 va_list ap;
1004 int done = 1;
1005
1006 va_start (ap, format);
1007 do
1008 {
1009 len = vsnprintf (smtp->buffer, smtp->buflen - 1, format, ap);
1010 if (len < 0 || (len >= (int) smtp->buflen)
1011 || !memchr (smtp->buffer, '\0', len + 1))
1012 {
1013 char *buffer = NULL;
1014 size_t buflen = smtp->buflen * 2;
1015 buffer = realloc (smtp->buffer, buflen);
1016 if (smtp->buffer == NULL)
1017 return ENOMEM;
1018 smtp->buffer = buffer;
1019 smtp->buflen = buflen;
1020 done = 0;
1021 }
1022 else
1023 done = 1;
1024 }
1025 while (!done);
1026
1027 va_end (ap);
1028
1029 smtp->ptr = smtp->buffer + len;
1030
1031 while (len > 0 && isspace (smtp->buffer[len - 1]))
1032 len--;
1033
1034 if ((smtp->state != SMTP_SEND && smtp->state != SMTP_SEND_DOT)
1035 || smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA)
1036 {
1037 MAILER_DEBUG2 (smtp->mailer, MU_DEBUG_PROT, "> %.*s\n", len,
1038 smtp->buffer);
1039 }
1040
1041 return 0;
1042 }
1043
1044 static int
1045 smtp_write (smtp_t smtp)
1046 {
1047 int status = 0;
1048 size_t len;
1049 if (smtp->ptr > smtp->buffer)
1050 {
1051 len = smtp->ptr - smtp->buffer;
1052 status = mu_stream_write (smtp->mailer->stream, smtp->buffer, len,
1053 0, &len);
1054 if (status == 0)
1055 {
1056 memmove (smtp->buffer, smtp->buffer + len, len);
1057 smtp->ptr -= len;
1058 }
1059 }
1060 else
1061 {
1062 smtp->ptr = smtp->buffer;
1063 len = 0;
1064 }
1065 return status;
1066 }
1067
1068 static int
1069 smtp_read_ack (smtp_t smtp)
1070 {
1071 int status;
1072 int multi;
1073
1074 do
1075 {
1076 multi = 0;
1077 status = smtp_readline (smtp);
1078 if ((smtp->ptr - smtp->buffer) > 4 && smtp->buffer[3] == '-')
1079 multi = 1;
1080 if (status == 0)
1081 smtp->ptr = smtp->buffer;
1082 }
1083 while (multi && status == 0);
1084
1085 if (status == 0)
1086 smtp->ptr = smtp->buffer;
1087 return status;
1088 }
1089
1090 static int
1091 smtp_parse_ehlo_ack (smtp_t smtp)
1092 {
1093 int status;
1094 int multi;
1095
1096 do
1097 {
1098 multi = 0;
1099 status = smtp_readline (smtp);
1100 if ((smtp->ptr - smtp->buffer) > 4 && smtp->buffer[3] == '-')
1101 multi = 1;
1102 if (status == 0) {
1103 smtp->ptr = smtp->buffer;
1104
1105 if (!strncasecmp (smtp->buffer, "250-STARTTLS", 12))
1106 smtp->capa |= CAPA_STARTTLS;
1107 }
1108 }
1109 while (multi && status == 0);
1110
1111 if (status == 0)
1112 smtp->ptr = smtp->buffer;
1113 return status;
1114 }
1115
1116 /* Read a complete line form the pop server. Transform CRLF to LF,
1117 put a null in the buffer when done. */
1118 static int
1119 smtp_readline (smtp_t smtp)
1120 {
1121 size_t n = 0;
1122 size_t total = smtp->ptr - smtp->buffer;
1123 int status;
1124
1125 /* Must get a full line before bailing out. */
1126 do
1127 {
1128 status = mu_stream_readline (smtp->mailer->stream, smtp->buffer + total,
1129 smtp->buflen - total, smtp->s_offset, &n);
1130 if (status != 0)
1131 return status;
1132
1133 /* Server went away, consider this like an error. */
1134 if (n == 0)
1135 return EIO;
1136
1137 total += n;
1138 smtp->s_offset += n;
1139 smtp->nl = memchr (smtp->buffer, '\n', total);
1140 if (smtp->nl == NULL) /* Do we have a full line. */
1141 {
1142 /* Allocate a bigger buffer ? */
1143 if (total >= smtp->buflen - 1)
1144 {
1145 smtp->buflen *= 2;
1146 smtp->buffer = realloc (smtp->buffer, smtp->buflen + 1);
1147 if (smtp->buffer == NULL)
1148 return ENOMEM;
1149 }
1150 }
1151 smtp->ptr = smtp->buffer + total;
1152 }
1153 while (smtp->nl == NULL);
1154
1155 /* \r\n --> \n\0 */
1156 if (smtp->nl > smtp->buffer)
1157 {
1158 *(smtp->nl - 1) = '\n';
1159 *(smtp->nl) = '\0';
1160 smtp->ptr = smtp->nl;
1161 }
1162
1163 MAILER_DEBUG1 (smtp->mailer, MU_DEBUG_PROT, "< %s", smtp->buffer);
1164
1165 return 0;
1166 }
1167
1168 #else
1169 #include <stdio.h>
1170 #include <registrar0.h>
1171 mu_record_t mu_smtp_record = NULL;
1172 #endif