~ubuntu-branches/ubuntu/trusty/libesmtp/trusty-proposed

« back to all changes in this revision

Viewing changes to protocol.c

  • Committer: Bazaar Package Importer
  • Author(s): Jeremy T. Bouse
  • Date: 2002-03-06 08:37:48 UTC
  • Revision ID: james.westby@ubuntu.com-20020306083748-ihmt32mddsslvg5i
Tags: upstream-0.8.11
ImportĀ upstreamĀ versionĀ 0.8.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  This file is part of libESMTP, a library for submission of RFC 2822
 
3
 *  formatted electronic mail messages using the SMTP protocol described
 
4
 *  in RFC 2821.
 
5
 *
 
6
 *  Copyright (C) 2001,2002  Brian Stafford  <brian@stafford.uklinux.net>
 
7
 *
 
8
 *  This library is free software; you can redistribute it and/or
 
9
 *  modify it under the terms of the GNU Lesser General Public
 
10
 *  License as published by the Free Software Foundation; either
 
11
 *  version 2.1 of the License, or (at your option) any later version.
 
12
 *
 
13
 *  This library is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 *  Lesser General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU Lesser General Public
 
19
 *  License along with this library; if not, write to the Free Software
 
20
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
21
 */
 
22
 
 
23
/* The SMTP protocol engine and handler functions for the core SMTP
 
24
   commands and their extended parameters.  Extended commands are mostly
 
25
   in files of their own. */
 
26
 
 
27
#ifdef HAVE_CONFIG_H
 
28
#include <config.h>
 
29
#endif
 
30
 
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
#include <ctype.h>
 
34
#include <stdarg.h>
 
35
#include <unistd.h>
 
36
#include <errno.h>
 
37
 
 
38
#include <missing.h> /* declarations for missing library functions */
 
39
 
 
40
#include <sys/socket.h>
 
41
#if HAVE_LWRES_NETDB_H
 
42
# include <lwres/netdb.h>
 
43
#elif !HAVE_GETADDRINFO
 
44
# include "getaddrinfo.h"
 
45
#else
 
46
# include <netdb.h>
 
47
#endif
 
48
 
 
49
#if HAVE_UNAME
 
50
#include <sys/utsname.h>
 
51
#endif
 
52
 
 
53
#include "libesmtp-private.h"
 
54
#include "message-source.h"
 
55
#include "siobuf.h"
 
56
#include "tokens.h"
 
57
#include "headers.h"
 
58
#include "protocol.h"
 
59
 
 
60
struct protocol_states
 
61
  {
 
62
    void (*cmd) (siobuf_t conn, smtp_session_t session);
 
63
    void (*rsp) (siobuf_t conn, smtp_session_t session);
 
64
  };
 
65
 
 
66
/* The following array of state handlers is indexed by the state (!)  */
 
67
struct protocol_states protocol_states[] =
 
68
  {
 
69
#define S(x)            { cmd_##x, rsp_##x, },
 
70
#include "protocol-states.h"
 
71
  };
 
72
 
 
73
static int
 
74
set_first_recipient (smtp_session_t session)
 
75
{
 
76
  smtp_recipient_t recipient;
 
77
 
 
78
  if (session->current_message == NULL)
 
79
    return 0;
 
80
  
 
81
  for (recipient = session->current_message->recipients;
 
82
       recipient != NULL;
 
83
       recipient = recipient->next)
 
84
    if (!recipient->complete)
 
85
      break;
 
86
  session->cmd_recipient = session->rsp_recipient = recipient;
 
87
  return recipient != NULL;
 
88
}
 
89
 
 
90
/* Return a pointer to the next unsent recipient.  This can't operate
 
91
   on the session structure directly as the other first/next functions
 
92
   do since there are two variables for the current recipient due to
 
93
   the implementation of PIPELINING.  */
 
94
static smtp_recipient_t
 
95
next_recipient (smtp_recipient_t recipient)
 
96
{
 
97
  while ((recipient = recipient->next) != NULL)
 
98
    if (!recipient->complete)
 
99
      break;
 
100
  return recipient;
 
101
}
 
102
 
 
103
/* Return a pointer to the next unsent message.
 
104
 */
 
105
static int
 
106
next_message (smtp_session_t session)
 
107
{
 
108
  while ((session->current_message = session->current_message->next) != NULL)
 
109
    if (set_first_recipient (session))
 
110
      return 1;
 
111
  return 0;
 
112
}
 
113
 
 
114
/* Set the current message to the first unsent message in the
 
115
   session.  */
 
116
static int
 
117
set_first_message (smtp_session_t session)
 
118
{
 
119
  for (session->current_message = session->messages;
 
120
       session->current_message != NULL;
 
121
       session->current_message = session->current_message->next)
 
122
    if (set_first_recipient (session))
 
123
      return 1;
 
124
  return 0;
 
125
}
 
126
 
 
127
/*****************************************************************************
 
128
 * The main protocol engine.
 
129
 *****************************************************************************/
 
130
 
 
131
int
 
132
do_session (smtp_session_t session)
 
133
{
 
134
  struct addrinfo hints, *res, *addrs;
 
135
  int err;
 
136
  int sd;
 
137
  siobuf_t conn;
 
138
  int nresp, status, want_flush, fast;
 
139
  char *nodename;
 
140
 
 
141
#if HAVE_UNAME
 
142
  if (session->localhost == NULL)
 
143
    {
 
144
      struct utsname name;
 
145
 
 
146
      if (uname (&name) < 0)
 
147
        {
 
148
          set_errno (errno);
 
149
          return 0;
 
150
        }
 
151
      session->localhost = strdup (name.nodename);
 
152
      if (session->localhost == NULL)
 
153
        {
 
154
          set_errno (ENOMEM);
 
155
          return 0;
 
156
        }
 
157
    }
 
158
#elif HAVE_GETHOSTNAME
 
159
  if (session->localhost == NULL)
 
160
    {
 
161
      char host[256];
 
162
 
 
163
      if (gethostname (host, sizeof host) < 0)
 
164
        {
 
165
          set_errno (errno);
 
166
          return 0;
 
167
        }
 
168
      session->localhost = strdup (host);
 
169
      if (session->localhost == NULL)
 
170
        {
 
171
          set_errno (ENOMEM);
 
172
          return 0;
 
173
        }
 
174
    }
 
175
#endif
 
176
 
 
177
  /* Initialise the current message and recipient variables in the
 
178
     session.  This returns zero if there is no work to do.  */
 
179
#ifndef USE_ETRN
 
180
  if (!set_first_message (session))
 
181
#else
 
182
  if (!set_first_message (session) && session->etrn_nodes == NULL)
 
183
#endif
 
184
    {
 
185
      set_error (SMTP_ERR_NOTHING_TO_DO);
 
186
      return 0;
 
187
    }
 
188
 
 
189
  /* Create a message source only if it is needed.
 
190
   */
 
191
  if (session->msg_source == NULL && session->current_message != NULL)
 
192
    {
 
193
      session->msg_source = msg_source_create ();
 
194
      if (session->msg_source == NULL)
 
195
        {
 
196
          set_errno (ENOMEM);
 
197
          return 0;
 
198
        }
 
199
    }
 
200
 
 
201
  /* Connect to the SMTP server.  The following code will only work for
 
202
     socket connections at present.  This will eventually change to
 
203
     permit connections on any type of file descriptor, e.g. for LMTP
 
204
     servers or forking an SMTP server which can run the protocol on
 
205
     its standard input. */
 
206
 
 
207
  errno = 0;
 
208
  nodename = (session->host == NULL || *session->host == '\0') ? NULL
 
209
                                                               : session->host;
 
210
  /* Use the RFC 2553/Posix resolver interface.  This allows for much
 
211
     cleaner code, protocol independence and thread safety. */
 
212
  memset (&hints, 0, sizeof hints);
 
213
  hints.ai_family = PF_UNSPEC;
 
214
  hints.ai_socktype = SOCK_STREAM;
 
215
  err = getaddrinfo (nodename, session->port, &hints, &res);
 
216
  if (err != 0)
 
217
    {
 
218
      set_herror (err);
 
219
      return 0;
 
220
    }
 
221
 
 
222
  /* Try to establish an SMTP session with each host in turn until one
 
223
     succeeds.  */
 
224
  for (addrs = res; addrs != NULL; addrs = addrs->ai_next)
 
225
    {
 
226
      sd = socket (addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
 
227
      if (sd < 0)
 
228
        {
 
229
          set_errno (errno);
 
230
          continue;
 
231
        }
 
232
      if (connect (sd, addrs->ai_addr, addrs->ai_addrlen) < 0)
 
233
        {
 
234
          /* Failed to connect.  Close the socket and try again.  */
 
235
          set_errno (errno);
 
236
          close (sd);
 
237
          continue;
 
238
        }
 
239
 
 
240
      /* Add buffering to the socket */
 
241
      conn = sio_attach (sd, sd, SIO_BUFSIZE);
 
242
      if (conn == NULL)
 
243
        {
 
244
          set_errno (ENOMEM);
 
245
          freeaddrinfo (res);
 
246
          close (sd);
 
247
          return 0;
 
248
        }
 
249
 
 
250
      /* If monitoring the protocol, pass the callback on to the sio_
 
251
         package. */
 
252
      if (session->monitor_cb != NULL)
 
253
        sio_set_monitorcb (conn, session->monitor_cb, session->monitor_cb_arg);
 
254
 
 
255
      if (session->event_cb != NULL)
 
256
        (*session->event_cb) (session, SMTP_EV_CONNECT, session->event_cb_arg);
 
257
 
 
258
      /* Outer loop of the protocol.  This is trickier than superficial
 
259
         examination of RFC 821 would suggest, however the complexity is
 
260
         required to handle batched commands and responses.  RFC 821 makes
 
261
         no comment on the underlying transport so it cannot be assumed that
 
262
         each command and its response is transported in a single packet on
 
263
         the network or that the network preserves packet boundaries (or,
 
264
         for that matter, that the underlying transport is even a network,
 
265
         e.g. it might be a pipe or a AF_UNIX socket).  Multiple commands
 
266
         may be sent in a single packet and similarly multiple responses
 
267
         may be returned in a single packet. RFC 2920 which describes the
 
268
         PIPELINING SMTP extension clarifies this for the case where the
 
269
         underlying transport is TCP/IP.
 
270
 
 
271
         In this implementation the outer loop will batch together as many
 
272
         commands as possible until the remote server sends a response (this
 
273
         will normally happen after the local transmit buffer is flushed)
 
274
         or a command has been sent which requires a response before the
 
275
         client can proceed.
 
276
 
 
277
         In order not to break certain SMTP server implementations, flushing
 
278
         is done after every command unless the PIPELINING keyword is received
 
279
         in response to the EHLO command.  Even when PIPELINING is in force
 
280
         certain commands *always* flush the transmit buffer.
 
281
 
 
282
         One good reason for wanting PIPELINING is that when submitting mail
 
283
         to an ISP's sluggish server, there will be a big performance boost
 
284
         since many round trips are eliminated.
 
285
 
 
286
         As the protocol engine advances through its states, it will walk
 
287
         through the messages and recipients within the session.
 
288
 
 
289
         The protocol functions set a few timeouts as they progress.  The
 
290
         values set are those reccommended in RFC 2821.
 
291
 
 
292
         [is it just me, or does everybody find that it's easier to implement
 
293
          protocols on the server side?]
 
294
       */
 
295
 
 
296
      /* Reset variables to their initial state before entering the protocol
 
297
         main loop. */
 
298
      session->extensions = 0;
 
299
      session->try_fallback_server = 0;
 
300
      reset_status (&session->mta_status);
 
301
      destroy_auth_mechanisms (session);
 
302
      session->authenticated = 0;
 
303
#ifdef USE_TLS
 
304
      session->using_tls = 0;
 
305
#endif
 
306
 
 
307
      nresp = 0;
 
308
      session->cmd_state = session->rsp_state = 0;
 
309
      while (session->rsp_state >= 0)
 
310
        {
 
311
          if (session->cmd_state == -1)
 
312
            session->cmd_state = session->rsp_state;
 
313
          (*protocol_states[session->cmd_state].cmd) (conn, session);
 
314
          sio_mark (conn);
 
315
          if (!(session->extensions & EXT_PIPELINING))
 
316
            session->cmd_state = -1;
 
317
          nresp++;
 
318
 
 
319
          if (session->rsp_state < 0)
 
320
            break;
 
321
 
 
322
          /* The following loop polls the server and reads or writes
 
323
             to it as required.
 
324
 
 
325
             When the command state is set to -1, this signals that no
 
326
             more commands can be issued until the response to the most
 
327
             recent command has been processed, therefore the write
 
328
             buffer must be explicitly flushed.  If the command state is
 
329
             not -1, more commands may be issued however, pending
 
330
             responses from the server should be processed.  When this
 
331
             is the case, sio_poll should return immediately if there is
 
332
             nothing to read.  `fast' requests this non-blocking poll.
 
333
 
 
334
             `want_flush' indicates that the write buffer should be
 
335
             sent to the server.  This flag remains set until the buffer
 
336
             has been written.
 
337
 
 
338
             After explicitly flushing the buffer, sio_poll blocks
 
339
             waiting to read data from the server since the server may
 
340
             take some time to complete the pending commands.
 
341
           */
 
342
          want_flush = (session->cmd_state == -1);
 
343
          fast = (session->cmd_state != -1);
 
344
          while ((status = sio_poll (conn, nresp > 0, want_flush, fast)) > 0)
 
345
            {
 
346
              if (status & SIO_READ)
 
347
                {
 
348
                  nresp--;
 
349
 
 
350
                  /* TODO: change so that the response line is parsed
 
351
                           here.  This means that the server 421
 
352
                           response which can be issued at any time may
 
353
                           be checked for here. */
 
354
 
 
355
                  /* When reading from the server in the response state
 
356
                     handlers the read call blocks.  Complete responses
 
357
                     must be read from the server before processing and
 
358
                     an individual response may be larger than the read
 
359
                     buffer.  */
 
360
                  (*protocol_states[session->rsp_state].rsp) (conn, session);
 
361
                }
 
362
              /* XXX - Here I assume that once the write fd becomes
 
363
                       available for writing, it stays that way until
 
364
                       it is written to.  I.e. a blocking read() or a
 
365
                       subsequent poll() will not revoke the writable
 
366
                       status.  Could somebody confirm that this is the
 
367
                       case? */
 
368
              if (status & SIO_WRITE)
 
369
                {
 
370
                  sio_flush (conn);
 
371
                  want_flush = 0;
 
372
                }
 
373
            }
 
374
          if (status < 0)
 
375
            {
 
376
              set_error (SMTP_ERR_DROPPED_CONNECTION);
 
377
              break;
 
378
            }
 
379
        }
 
380
 
 
381
      sio_detach (conn);
 
382
      close (sd);
 
383
 
 
384
      if (session->event_cb != NULL)
 
385
        (*session->event_cb) (session, SMTP_EV_DISCONNECT,
 
386
                              session->event_cb_arg);
 
387
 
 
388
      /* This flag will be set if the server was reached OK but was the
 
389
         wrong kind of server or the client is told to go away.  So if
 
390
         not set the protocol must have concluded sucessfully. */
 
391
      if (!session->try_fallback_server)
 
392
        {
 
393
          freeaddrinfo (res);
 
394
          return 1;
 
395
        }
 
396
    }
 
397
 
 
398
  /* If the loop terminated, couldn't work with any servers. */
 
399
  freeaddrinfo (res);
 
400
  return 0;
 
401
}
 
402
 
 
403
/*****************************************************************************
 
404
 * Response parser.
 
405
 *****************************************************************************/
 
406
 
 
407
static int
 
408
parse_status_triplet (char *p, char **ep, struct smtp_status *triplet)
 
409
{
 
410
  triplet->enh_class = strtol (p, &p, 10);
 
411
  if (*p++ != '.')
 
412
    return 0;
 
413
  triplet->enh_subject = strtol (p, &p, 10);
 
414
  if (*p++ != '.')
 
415
    return 0;
 
416
  triplet->enh_detail = strtol (p, &p, 10);
 
417
  *ep = p;
 
418
  return 1;
 
419
}
 
420
 
 
421
static int
 
422
compare_status_triplet (struct smtp_status *a, struct smtp_status *b)
 
423
{
 
424
  return a->enh_class == b->enh_class
 
425
         && a->enh_subject == b->enh_subject
 
426
         && a->enh_detail == b->enh_detail;
 
427
}
 
428
 
 
429
/* Free memory allocated in read_smtp_response()
 
430
   and clear the status structure */
 
431
void
 
432
reset_status (struct smtp_status *status)
 
433
{
 
434
  if (status->text != NULL)
 
435
    free ((void *) status->text);
 
436
  memset (status, 0, sizeof (struct smtp_status));
 
437
}
 
438
 
 
439
/* All SMTP responses have standard syntax.  This function could be
 
440
   called by the protocol engine above and the results from the parsed
 
441
   response passed to the response handler functions.  However certain
 
442
   commands involve extra intermediate exchanges with the server that
 
443
   may not correspond to the standard syntax.  The response handlers
 
444
   must therefore call this function themselves. */
 
445
int
 
446
read_smtp_response (siobuf_t conn, smtp_session_t session,
 
447
                    struct smtp_status *status,
 
448
                    int (*cb) (smtp_session_t, char *))
 
449
{
 
450
  struct catbuf text;
 
451
  char buf[1024];
 
452
  char *p, *nul;
 
453
  int code, more, want_enhanced, textlen;
 
454
  struct smtp_status triplet;
 
455
 
 
456
  /* First line of an SMTP response is the normal one.  Put it in a buffer.
 
457
     Save the status code and the enhanced status triplet if ENHSTATUSCODES
 
458
     is set.  The remainder of the line is the message from the server.
 
459
     If there are any continuation lines, get the status code and enhanced
 
460
     status triplet and check that they are the same as the first response
 
461
     line.  If not there is a protocol error.  Process the extra lines
 
462
     by calling a callback.  If not supplied, concatenate the lines
 
463
     (excluding the status info) with the first line. */
 
464
 
 
465
  reset_status (status);
 
466
  if ((p = sio_gets (conn, buf, sizeof buf)) == NULL)
 
467
    {
 
468
      set_error (SMTP_ERR_DROPPED_CONNECTION);
 
469
      return -1;
 
470
    }
 
471
  status->code = strtol (p, &p, 10);
 
472
  if (!(*p == ' ' || *p == '-'))
 
473
    {
 
474
      set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
475
      return -1;
 
476
    }
 
477
  more = *p++ == '-';
 
478
 
 
479
  /* RFC 2034 states that only 2xx, 4xx and 5xx responses are accompanied
 
480
     by enhanced status codes. */
 
481
  code = status->code / 100;
 
482
  want_enhanced = (session->extensions & EXT_ENHANCEDSTATUSCODES);
 
483
  if (code != 2 && code != 4 && code != 5)
 
484
    want_enhanced = 0;
 
485
 
 
486
  if (want_enhanced && !parse_status_triplet (p, &p, status))
 
487
    {
 
488
      set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
489
      return -1;
 
490
    }
 
491
  while (isspace (*p))
 
492
    p++;
 
493
 
 
494
  /* p points to the remainder of the line.  This is the text of the
 
495
     server message */
 
496
  cat_init (&text, 128);
 
497
  concatenate (&text, p, -1);
 
498
 
 
499
  while (more)
 
500
    {
 
501
      if ((p = sio_gets (conn, buf, sizeof buf)) == NULL)
 
502
        {
 
503
          cat_free (&text);
 
504
          set_error (SMTP_ERR_DROPPED_CONNECTION);
 
505
          return -1;
 
506
        }
 
507
      code = strtol (p, &p, 10);
 
508
      if (code != status->code)
 
509
        {
 
510
          cat_free (&text);
 
511
          set_error (SMTP_ERR_STATUS_MISMATCH);
 
512
          return -1;
 
513
        }
 
514
      if (!(*p == ' ' || *p == '-'))
 
515
        {
 
516
          cat_free (&text);
 
517
          set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
518
          return -1;
 
519
        }
 
520
      more = *p++ == '-';
 
521
      if (want_enhanced)
 
522
        {
 
523
          if (!parse_status_triplet (p, &p, &triplet))
 
524
            {
 
525
              cat_free (&text);
 
526
              set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
527
              return -1;
 
528
            }
 
529
          if (!compare_status_triplet (status, &triplet))
 
530
            {
 
531
              cat_free (&text);
 
532
              set_error (SMTP_ERR_STATUS_MISMATCH);
 
533
              return -1;
 
534
            }
 
535
        }
 
536
 
 
537
      /* Skip whitespace but don't wander over the CRLF */
 
538
      while (isspace (*p) && isprint (*p))
 
539
        p++;
 
540
 
 
541
      /* Check that the line is correctly terminated. */
 
542
      nul = strchr (p, '\0');
 
543
      if (nul == NULL || nul == p || nul[-1] != '\n')
 
544
        {
 
545
          cat_free (&text);
 
546
          set_error (SMTP_ERR_UNTERMINATED_RESPONSE);
 
547
          return -1;
 
548
        }
 
549
 
 
550
      /* `p' points to the remainder of the line.  Either process with the
 
551
         callback or concatenate with the first line. */
 
552
      if (cb != NULL)
 
553
        (*cb) (session, p);
 
554
      else
 
555
        concatenate (&text, p, nul - p);
 
556
 
 
557
      /* Check if the total text returned in a multiline response
 
558
         exceeds 4k.  Abort if this happens, this might be a DoS attack
 
559
         or a broken server. */
 
560
      textlen = 0;
 
561
      cat_buffer (&text, &textlen);
 
562
      if (textlen > 4096)
 
563
        {
 
564
          cat_free (&text);
 
565
          set_error (SMTP_ERR_UNTERMINATED_RESPONSE);
 
566
          return -1;
 
567
        }
 
568
    }
 
569
 
 
570
  /* Terminate and save the response text */
 
571
  concatenate (&text, "", 1);
 
572
  status->text = cat_shrink (&text, NULL);
 
573
 
 
574
  return status->code / 100;
 
575
}
 
576
 
 
577
/*****************************************************************************
 
578
 * Command and response handlers.  Return value is the next send/response
 
579
 * state.  If a cmd_xxxx() function returns -1, the response determines
 
580
 * the next state, implying that a flush is needed.
 
581
 *****************************************************************************/
 
582
 
 
583
/*****************************************************************************
 
584
 * Server Greeting
 
585
 *****************************************************************************/
 
586
 
 
587
/* If the response to the server greeting is not a 2xx status code,
 
588
   issue the QUIT command and terminate the session.  */
 
589
void
 
590
cmd_greeting (siobuf_t conn, smtp_session_t session)
 
591
{
 
592
  /* Set a five minute timeout. */
 
593
  sio_set_timeout (conn, 5 * 60 * 1000);
 
594
  session->cmd_state = -1;
 
595
}
 
596
 
 
597
void
 
598
rsp_greeting (siobuf_t conn, smtp_session_t session)
 
599
{
 
600
  int code;
 
601
 
 
602
  code = read_smtp_response (conn, session, &session->mta_status, NULL);
 
603
  if (code == 2 && session->mta_status.code == 220)
 
604
    session->rsp_state = S_ehlo;
 
605
  else if (code == 4 || code == 5)
 
606
    {
 
607
      session->rsp_state = S_quit;      /* Graceful exit using QUIT */
 
608
      session->try_fallback_server = 1;
 
609
    }
 
610
  else
 
611
    {
 
612
      session->rsp_state = -1;          /* Drop the connection and run */
 
613
      session->try_fallback_server = 1;
 
614
    }
 
615
 
 
616
  /* TODO: certain broken servers may break when the EHLO command is
 
617
           issued.  For example, one known behaviour is to close the
 
618
           connection after returning the 501 response.  This is wrong
 
619
           but it happens.
 
620
 
 
621
           An API option is needed to avoid using EHLO!
 
622
   */
 
623
}
 
624
 
 
625
/*****************************************************************************
 
626
 * EHLO 
 
627
 *****************************************************************************/
 
628
 
 
629
/* EHLO is the preferred client greeting to the server.  The parameter is
 
630
   the FQDN of the client host.  The server response is the greeting line
 
631
   followed by extra lines listing the server capabilities.  The additional
 
632
   lines are parsed and set the session capability flags.  If the response
 
633
   is "501 command not implemented", the HELO command should be used instead.
 
634
   Since the next command issued depends on the server response the output
 
635
   must be flushed.
 
636
 
 
637
   Next state is one of Auth, Helo, Mail.
 
638
 */
 
639
void
 
640
cmd_ehlo (siobuf_t conn, smtp_session_t session)
 
641
{
 
642
  sio_printf (conn, "EHLO %s\r\n", session->localhost);
 
643
  session->cmd_state = -1;
 
644
}
 
645
 
 
646
#define no_required_extension(s,e)      \
 
647
                (((s)->required_extensions & (e)) && !((s)->extensions & (e)))
 
648
 
 
649
static int
 
650
report_extensions (smtp_session_t session)
 
651
{
 
652
  int quit_now;
 
653
  unsigned long exts = 0;
 
654
 
 
655
  /* Report extensions that are required but not available.
 
656
   */
 
657
  if (no_required_extension (session, EXT_DSN))
 
658
    {
 
659
      quit_now = 0;
 
660
      if (session->event_cb != NULL)
 
661
        (*session->event_cb) (session, SMTP_EV_EXTNA_DSN,
 
662
                              session->event_cb_arg, &quit_now);
 
663
      if (quit_now)
 
664
        exts |= EXT_DSN;
 
665
    }
 
666
  if (no_required_extension (session, EXT_8BITMIME))
 
667
    {
 
668
      quit_now = 1;
 
669
      if (session->event_cb != NULL)
 
670
        (*session->event_cb) (session, SMTP_EV_EXTNA_8BITMIME,
 
671
                              session->event_cb_arg);
 
672
      if (quit_now)
 
673
        exts |= EXT_8BITMIME;
 
674
    }
 
675
#ifdef USE_ETRN
 
676
  if (no_required_extension (session, EXT_ETRN))
 
677
    {
 
678
      quit_now = 1;
 
679
      if (session->event_cb != NULL)
 
680
        (*session->event_cb) (session, SMTP_EV_EXTNA_ETRN,
 
681
                              session->event_cb_arg, &quit_now);
 
682
      if (quit_now)
 
683
        exts |= EXT_ETRN;
 
684
    }
 
685
#endif
 
686
  return !exts;
 
687
}
 
688
 
 
689
static int
 
690
cb_ehlo (smtp_session_t session, char *buf)
 
691
{
 
692
  const char *p;
 
693
  char token[32];
 
694
 
 
695
  if (!read_atom (skipblank (buf), &p, token, sizeof token))
 
696
    {
 
697
      /* expecting an atom - do nothing */
 
698
      return 0;
 
699
    }
 
700
 
 
701
  /* Since the session structure mostly just carries a bit for each of
 
702
     the extensions, there is no point #ifdefing out the extension
 
703
     keywords for omitted features.  Also extensions may be added
 
704
     in the future so it is not an error to have an unrecognised
 
705
     extension keyword. */
 
706
 
 
707
  if (strcasecmp (token, "ENHANCEDSTATUSCODES") == 0)   /* RFC 1893, RFC 2034 */
 
708
    session->extensions |= EXT_ENHANCEDSTATUSCODES;
 
709
  else if (strcasecmp (token, "PIPELINING") == 0)       /* RFC 2920 */
 
710
    session->extensions |= EXT_PIPELINING;
 
711
  else if (strcasecmp (token, "DSN") == 0)              /* RFC 1891 */
 
712
    session->extensions |= EXT_DSN;
 
713
  else if (strcasecmp (token, "AUTH") == 0)             /* RFC 2554 */
 
714
    {
 
715
      session->extensions |= EXT_AUTH;
 
716
      set_auth_mechanisms (session, p);
 
717
    }
 
718
#ifdef AUTH_ID_HACK
 
719
  else if (strncasecmp (token, "AUTH=", 5) == 0) /* non-standard syntax */
 
720
    {
 
721
      session->extensions |= EXT_AUTH;
 
722
      set_auth_mechanisms (session, token + 5);
 
723
      set_auth_mechanisms (session, p);
 
724
    }
 
725
#endif
 
726
  else if (strcasecmp (token, "STARTTLS") == 0)         /* RFC 2487 */
 
727
    session->extensions |= EXT_STARTTLS;
 
728
  else if (strcasecmp (token, "SIZE") == 0)             /* RFC 1870 */
 
729
    {
 
730
      session->extensions |= EXT_SIZE;
 
731
      session->size_limit = strtol (p, NULL, 10);
 
732
    }
 
733
  else if (strcasecmp (token, "CHUNKING") == 0)         /* RFC 3030 */
 
734
    session->extensions |= EXT_CHUNKING;
 
735
  else if (strcasecmp (token, "BINARYMIME") == 0)       /* RFC 3030 */
 
736
    session->extensions |= EXT_BINARYMIME;
 
737
  else if (strcasecmp (token, "8BITMIME") == 0)         /* RFC 1652 */
 
738
    session->extensions |= EXT_8BITMIME;
 
739
  else if (strcasecmp (token, "DELIVERBY") == 0)        /* RFC 2852 */
 
740
    {
 
741
      session->extensions |= EXT_DELIVERBY;
 
742
      session->min_by_time = strtol (p, NULL, 10);
 
743
    }
 
744
  else if (strcasecmp (token, "ETRN") == 0)             /* RFC 1985 */
 
745
    session->extensions |= EXT_ETRN;
 
746
#ifdef USE_XUSR
 
747
  else if (strcasecmp (token, "XUSR") == 0)     /* sendmail (I feel ill) */
 
748
    session->extensions |= EXT_XUSR;
 
749
#endif
 
750
  return 1;
 
751
}
 
752
 
 
753
 
 
754
void
 
755
rsp_ehlo (siobuf_t conn, smtp_session_t session)
 
756
{
 
757
  int code;
 
758
 
 
759
  session->extensions = 0;
 
760
  destroy_auth_mechanisms (session);
 
761
  code = read_smtp_response (conn, session, &session->mta_status, cb_ehlo);
 
762
  if (code == 0)
 
763
    {
 
764
      set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
765
      session->rsp_state = S_quit;
 
766
      return;
 
767
    }
 
768
 
 
769
  if (code != 2)
 
770
    session->extensions = 0;
 
771
 
 
772
  if (code == 4)
 
773
    {
 
774
      /* 4xx failure code.  Something is temporarily wrong.  Fail the
 
775
         entire session and let the application retry later. */
 
776
      session->rsp_state = S_quit;
 
777
      session->try_fallback_server = 1;
 
778
      return;
 
779
    }
 
780
  else if (code == 5)
 
781
    {
 
782
      /* 5xx failure code.  Something is permanently wrong.  There are
 
783
         a number of codes indicating that HELO is worth a try since
 
784
         the server did not understand EHLO.  Otherwise fail the entire
 
785
         session.  The application must correct something and retry later. */
 
786
      if (session->mta_status.code == 500 || session->mta_status.code == 501
 
787
          || session->mta_status.code == 502 || session->mta_status.code == 504)
 
788
        session->rsp_state = S_helo;
 
789
      else
 
790
        session->rsp_state = S_quit;
 
791
      return;
 
792
    }
 
793
  else if (code != 2)
 
794
    {
 
795
      /* Response must be 2xx, 4xx or 5xx */
 
796
      set_error (SMTP_ERR_INVALID_RESPONSE_STATUS);
 
797
      session->rsp_state = S_quit;
 
798
      return;
 
799
    }
 
800
 
 
801
#ifdef USE_TLS
 
802
  /* Totally ignore the TLS stuff if it's already in use */
 
803
  if (!session->using_tls && session->starttls_enabled != Starttls_DISABLED)
 
804
    {
 
805
      if (select_starttls (session))
 
806
        {
 
807
          session->rsp_state = S_starttls;
 
808
          return;
 
809
        }
 
810
      if (session->starttls_enabled == Starttls_REQUIRED)
 
811
        {
 
812
          if (session->event_cb != NULL)
 
813
            (*session->event_cb) (session, SMTP_EV_EXTNA_STARTTLS,
 
814
                                  session->event_cb_arg, NULL);
 
815
          session->rsp_state = S_quit;
 
816
          set_error (SMTP_ERR_EXTENSION_NOT_AVAILABLE);
 
817
          return;
 
818
        }
 
819
    }
 
820
#endif
 
821
  /* If AUTH is enabled but no mechanisms can be selected, move on to the
 
822
     MAIL command since the MTA is required to accept mail for its own
 
823
     domain. */
 
824
  if ((session->extensions & EXT_AUTH) && select_auth_mechanism (session))
 
825
    {
 
826
      session->rsp_state = S_auth;
 
827
      return;
 
828
    }
 
829
 
 
830
  /* Report extensions *after* starting TLS or doing AUTH since either
 
831
     of these can restart the session with different SMTP extensions
 
832
     being offered by the server. */
 
833
  if (!report_extensions (session))
 
834
    {
 
835
      set_error (SMTP_ERR_EXTENSION_NOT_AVAILABLE);
 
836
      session->rsp_state = S_quit;
 
837
      return;
 
838
    }
 
839
 
 
840
#ifdef USE_ETRN
 
841
  session->rsp_state = check_etrn (session)
 
842
                          ? S_etrn : initial_transaction_state (session);
 
843
#else
 
844
  session->rsp_state = initial_transaction_state (session);
 
845
#endif
 
846
}
 
847
 
 
848
/* Select the correct initial state after reading the EHLO response or
 
849
   after DATA or RSET in the previous transaction.  */
 
850
int
 
851
initial_transaction_state (smtp_session_t session)
 
852
{
 
853
#ifdef USE_XUSR
 
854
  if (session->extensions & EXT_XUSR)
 
855
    return S_xusr;
 
856
#endif
 
857
  return S_mail;
 
858
}
 
859
 
 
860
/*****************************************************************************
 
861
 * HELO 
 
862
 *****************************************************************************/
 
863
 
 
864
/* HELO is absolutely *not* the preferred client greeting to the server.
 
865
   The parameter is the FQDN of the client host.  The server response is
 
866
   the greeting line.  No capabilities are reported so all extensions
 
867
   are turned off.
 
868
 
 
869
   Next state is Mail.
 
870
 */
 
871
void
 
872
cmd_helo (siobuf_t conn, smtp_session_t session)
 
873
{
 
874
  sio_printf (conn, "HELO %s\r\n", session->localhost);
 
875
  session->cmd_state = -1;
 
876
}
 
877
 
 
878
void
 
879
rsp_helo (siobuf_t conn, smtp_session_t session)
 
880
{
 
881
  int code;
 
882
 
 
883
  session->extensions = 0;
 
884
  destroy_auth_mechanisms (session);
 
885
  code = read_smtp_response (conn, session, &session->mta_status, NULL);
 
886
  if (code == 0)
 
887
    {
 
888
      set_error (SMTP_ERR_INVALID_RESPONSE_SYNTAX);
 
889
      session->try_fallback_server = 1;
 
890
      session->rsp_state = S_quit;
 
891
      return;
 
892
    }
 
893
  if (code != 2)
 
894
    {
 
895
      if (code != 4 || code != 5)
 
896
        set_error (SMTP_ERR_INVALID_RESPONSE_STATUS);
 
897
      session->try_fallback_server = 1;
 
898
      session->rsp_state = S_quit;
 
899
      return;
 
900
    }
 
901
 
 
902
  /* There are no extensions.  Make sure none were required.
 
903
   */
 
904
  if (!report_extensions (session))
 
905
    {
 
906
      set_error (SMTP_ERR_EXTENSION_NOT_AVAILABLE);
 
907
      session->rsp_state = S_quit;
 
908
      return;
 
909
    }
 
910
 
 
911
  /* Unlike EHLO, the only next state can be Mail, since there are
 
912
     no extensions to check for message acceptability or options to set
 
913
     before proceeding. */
 
914
  session->rsp_state = initial_transaction_state (session);
 
915
}
 
916
 
 
917
/*****************************************************************************
 
918
 * MAIL FROM: 
 
919
 *****************************************************************************/
 
920
 
 
921
/* MAIL FROM: is the first step in sending a message.  Select the first
 
922
   or a subsequent message from the session structure.  The message sender
 
923
   is taken from the message structure.
 
924
 
 
925
   Next state is always Rcpt, therefore this command need not be flushed.
 
926
 */
 
927
void
 
928
cmd_mail (siobuf_t conn, smtp_session_t session)
 
929
{
 
930
  const char *mailbox;
 
931
  smtp_message_t message;
 
932
  char xtext[256];
 
933
 
 
934
  /* Set a five minute timeout.  This stays in force until the DATA
 
935
     command. */
 
936
  sio_set_timeout (conn, 5 * 60 * 1000);
 
937
 
 
938
  message = session->current_message;
 
939
  mailbox = message->reverse_path_mailbox;
 
940
  sio_printf (conn, "MAIL FROM:<%s>", (mailbox != NULL) ? mailbox : "");
 
941
 
 
942
  /* SIZE: SIZE=message-size-estimate */
 
943
  if ((session->extensions & EXT_SIZE) && message->size_estimate > 0)
 
944
    sio_printf (conn, " SIZE=%lu", message->size_estimate);
 
945
 
 
946
  /* DSN: RET=FULL/HDRS  ENVID=xtext */
 
947
  if (session->extensions & EXT_DSN)
 
948
    {
 
949
      static const char *ret[] = { NULL, "FULL", "HDRS" };
 
950
 
 
951
      if (message->dsn_ret != Ret_NOTSET)
 
952
        sio_printf (conn, " RET=%s", ret[message->dsn_ret]);
 
953
 
 
954
      if (message->dsn_envid != NULL)
 
955
        sio_printf (conn, " ENVID=%s",
 
956
                    encode_xtext (xtext, sizeof xtext, message->dsn_envid));
 
957
    }
 
958
 
 
959
  /* 8BITMIME: RET=FULL/HDRS  ENVID=xtext */
 
960
  if ((session->extensions & EXT_8BITMIME)
 
961
      && message->e8bitmime != E8bitmime_NOTSET)
 
962
    {
 
963
      sio_write (conn, " BODY=", -1);
 
964
      if (message->e8bitmime == E8bitmime_8BITMIME)
 
965
        sio_write (conn, "8BITMIME", -1);
 
966
      else if (message->e8bitmime == E8bitmime_7BIT)
 
967
        sio_write (conn, "7BIT", -1);
 
968
    }
 
969
 
 
970
  if ((session->extensions & EXT_DELIVERBY) && message->by_mode != By_NOTSET)
 
971
    {
 
972
      static char mode[] = { 'N', 'R', };
 
973
      long by_time;
 
974
 
 
975
      by_time = message->by_time;
 
976
      /* If the by_time is greater than the server's min_by_time, ask the
 
977
         application what to do.  If adjust is set > 0, the message's
 
978
         deliver by time is adjusted to be acceptable to the server.
 
979
         If not, the MAIL command will be failed by the server.  */
 
980
      if (session->min_by_time > 0 && by_time < session->min_by_time)
 
981
        {
 
982
          int adjust = 0;
 
983
 
 
984
          if (session->event_cb != NULL)
 
985
            (*session->event_cb) (session, SMTP_EV_DELIVERBY_EXPIRED,
 
986
                                  session->event_cb_arg,
 
987
                                  session->min_by_time - by_time, &adjust);
 
988
          if (adjust > 0)
 
989
            by_time = session->min_by_time + adjust;
 
990
        }
 
991
      sio_printf (conn, " BY=%ld%c%s", by_time,
 
992
                  mode[message->by_mode], (message->by_trace) ? "T" : "");
 
993
    }
 
994
 
 
995
  sio_write (conn, "\r\n", 2);
 
996
  /* TODO: until code to prevent issuing of further RCPT commands and to
 
997
           discard RCPT responses cascading from an error response to
 
998
           MAIL is in place, flush the mail command even when pipelining. */
 
999
#if 0
 
1000
  session->cmd_state = S_rcpt;
 
1001
#else
 
1002
  session->cmd_state = -1;
 
1003
#endif
 
1004
}
 
1005
 
 
1006
void
 
1007
rsp_mail (siobuf_t conn, smtp_session_t session)
 
1008
{
 
1009
  int code;
 
1010
  smtp_message_t message;
 
1011
 
 
1012
  message = session->current_message;
 
1013
  code = read_smtp_response (conn, session,
 
1014
                             &message->reverse_path_status, NULL);
 
1015
 
 
1016
  /* Notify the MAIL FROM: status */
 
1017
  if (session->event_cb != NULL)
 
1018
    (*session->event_cb) (session, SMTP_EV_MAILSTATUS, session->event_cb_arg,
 
1019
                          message->reverse_path_mailbox, message);
 
1020
  if (code != 2)
 
1021
    {
 
1022
      if (next_message (session))
 
1023
        session->rsp_state = initial_transaction_state (session);
 
1024
      else
 
1025
        session->rsp_state = S_quit;
 
1026
    }
 
1027
  else
 
1028
    {
 
1029
      message->valid_recipients = 0;
 
1030
#ifdef USE_REQUIRE_ALL_RECIPIENTS
 
1031
      message->failed_recipients = 0;
 
1032
#endif
 
1033
      session->rsp_state = S_rcpt;
 
1034
    }
 
1035
}
 
1036
 
 
1037
/*****************************************************************************
 
1038
 * RCPT TO:
 
1039
 *****************************************************************************/
 
1040
 
 
1041
/* Specify one message recipient.  This is taken from the recipient
 
1042
   parameters.  Many parameters are possible depending on the extensions
 
1043
   enabled.  For errors such as unknown recipient, or cannot relay,
 
1044
   just mark the offending recipient as failing and continue normally.
 
1045
 
 
1046
   Next state is Rcpt, Data or Bdat.  This depends on the number of
 
1047
   recipients for the message and the extensions enabled.  This selection
 
1048
   can be made without waiting for the server response therefore this
 
1049
   command need not be flushed.
 
1050
 */
 
1051
void
 
1052
cmd_rcpt (siobuf_t conn, smtp_session_t session)
 
1053
{
 
1054
  static struct { enum notify_flags mask; const char *flag; } masks[] =
 
1055
    {
 
1056
      { Notify_SUCCESS, "SUCCESS", },
 
1057
      { Notify_FAILURE, "FAILURE", },
 
1058
      { Notify_DELAY,   "DELAY", },
 
1059
    };
 
1060
  smtp_recipient_t recipient;
 
1061
  enum notify_flags notify;
 
1062
  char xtext[256];
 
1063
  int i;
 
1064
 
 
1065
  recipient = session->cmd_recipient;
 
1066
  sio_printf (conn, "RCPT TO:<%s>", recipient->mailbox);
 
1067
 
 
1068
  if (session->extensions & EXT_DSN)
 
1069
    {
 
1070
      /* DSN: NOTIFY=NEVER/SUCCESS,FAILURE,DELAY */
 
1071
      notify = recipient->dsn_notify;
 
1072
      if (notify != Notify_NOTSET)
 
1073
        {
 
1074
          sio_write (conn, " NOTIFY=", -1);
 
1075
          if (notify == Notify_NEVER)
 
1076
            sio_write (conn, "NEVER", -1);
 
1077
          else
 
1078
            for (i = 0; i < (int) (sizeof masks / sizeof masks[0]); i++)
 
1079
              if (notify & masks[i].mask)
 
1080
                {
 
1081
                  notify &= ~masks[i].mask;
 
1082
                  sio_write (conn, masks[i].flag, -1);
 
1083
                  if (notify != 0)
 
1084
                    sio_write (conn, ",", 1);
 
1085
                }
 
1086
        }
 
1087
 
 
1088
      /* DSN: ORCPT=type;address */
 
1089
      if (recipient->dsn_orcpt != NULL)
 
1090
        sio_printf (conn, " ORCPT=%s;%s", recipient->dsn_addrtype,
 
1091
                    encode_xtext (xtext, sizeof xtext, recipient->dsn_orcpt));
 
1092
    }
 
1093
  sio_write (conn, "\r\n", 2);
 
1094
 
 
1095
  session->cmd_recipient = next_recipient (session->cmd_recipient);
 
1096
  if (session->cmd_recipient != NULL)
 
1097
    session->cmd_state = S_rcpt;
 
1098
  else
 
1099
#ifdef USE_REQUIRE_ALL_RECIPIENTS
 
1100
  /* Ugly hack:  if requiring all recpients to succeed the decision can't
 
1101
                 be made here.  So PIPELINING's improvement is lost. */
 
1102
  if (session->require_all_recipients)
 
1103
    session->cmd_state = -1;
 
1104
  else
 
1105
#endif
 
1106
#if 0
 
1107
    session->cmd_state = (session->extensions & EXT_CHUNKING) ? S_bdat : S_data;
 
1108
#else
 
1109
    session->cmd_state = S_data;
 
1110
#endif
 
1111
}
 
1112
 
 
1113
void
 
1114
rsp_rcpt (siobuf_t conn, smtp_session_t session)
 
1115
{
 
1116
  int code;
 
1117
 
 
1118
  code = read_smtp_response (conn, session,
 
1119
                             &session->rsp_recipient->status, NULL);
 
1120
  if (code == 2)
 
1121
    session->current_message->valid_recipients += 1;
 
1122
#ifdef USE_REQUIRE_ALL_RECIPIENTS
 
1123
  else
 
1124
    session->current_message->failed_recipients += 1;
 
1125
#endif
 
1126
 
 
1127
  /* MTA will never accept this recipient.  Make sure it isn't used
 
1128
     again. */
 
1129
  if (code == 5)
 
1130
    session->rsp_recipient->complete = 1;
 
1131
 
 
1132
  /* Notify the RCPT TO: status */
 
1133
  if (session->event_cb != NULL)
 
1134
    (*session->event_cb) (session, SMTP_EV_RCPTSTATUS, session->event_cb_arg,
 
1135
                          session->rsp_recipient->mailbox,
 
1136
                          session->rsp_recipient);
 
1137
 
 
1138
  session->rsp_recipient = next_recipient (session->rsp_recipient);
 
1139
  if (session->rsp_recipient != NULL)
 
1140
    session->rsp_state = S_rcpt;
 
1141
  else
 
1142
#ifdef USE_REQUIRE_ALL_RECIPIENTS
 
1143
  /* Ugly hack:  if requiring all recpients to succeed make the decision to
 
1144
                 proceed now.  Using this option may make it impossible
 
1145
                 to send mail at all if some recipients are experiencing
 
1146
                 transient errors.  */
 
1147
  if (session->require_all_recipients
 
1148
      && session->current_message->failed_recipients > 0)
 
1149
    {
 
1150
      reset_status (&session->current_message->message_status);
 
1151
      session->rsp_state = next_message (session) ? S_rset : S_quit;
 
1152
    }
 
1153
  else
 
1154
#endif
 
1155
#if 0
 
1156
    session->rsp_state = (session->extensions & EXT_CHUNKING) ? S_bdat : S_data;
 
1157
#else
 
1158
    session->rsp_state = S_data;
 
1159
#endif
 
1160
}
 
1161
 
 
1162
/*****************************************************************************
 
1163
 * DATA
 
1164
 *****************************************************************************/
 
1165
 
 
1166
void
 
1167
cmd_data (siobuf_t conn, smtp_session_t session)
 
1168
{
 
1169
  sio_set_timeout (conn, 2 * 60 * 1000);
 
1170
  sio_write (conn, "DATA\r\n", -1);
 
1171
  session->cmd_state = -1;
 
1172
}
 
1173
 
 
1174
void
 
1175
rsp_data (siobuf_t conn, smtp_session_t session)
 
1176
{
 
1177
  int code;
 
1178
  smtp_message_t message;
 
1179
 
 
1180
  message = session->current_message;
 
1181
  code = read_smtp_response (conn, session, &message->message_status, NULL);
 
1182
  if (code == 4 || code == 5)
 
1183
    {
 
1184
      /* The server will not accept this message.
 
1185
       */
 
1186
 
 
1187
      /* N.B.  This is a bit tricky.  RFC 821 isn't clear and I can't
 
1188
         find any information in RFC 2821 either but what state is the
 
1189
         SMTP server supposed to be in when the DATA command fails a)
 
1190
         when the 354 response is expected and b) after the message is
 
1191
         copied to the server.
 
1192
 
 
1193
         Play safe and issue the RSET command.  */
 
1194
      if (next_message (session))
 
1195
        session->rsp_state = S_rset;
 
1196
      else
 
1197
        session->rsp_state = S_quit;
 
1198
    }
 
1199
  else if (code != 3)
 
1200
    {
 
1201
      set_error (SMTP_ERR_INVALID_RESPONSE_STATUS);
 
1202
      session->rsp_state = S_quit;
 
1203
    }
 
1204
  else
 
1205
    session->rsp_state = S_data2;
 
1206
 
 
1207
  /* Notify end of message here if not transferring anything */
 
1208
  if (code != 3 && session->event_cb != NULL)
 
1209
    (*session->event_cb) (session, SMTP_EV_MESSAGESENT,
 
1210
                          session->event_cb_arg, message);
 
1211
}
 
1212
 
 
1213
/* Read the message from the application using the callback.
 
1214
   Break into lines and copy to the server. */
 
1215
void
 
1216
cmd_data2 (siobuf_t conn, smtp_session_t session)
 
1217
{
 
1218
  const char *line, *header, *pline, *p;
 
1219
  int c, len;
 
1220
 
 
1221
  /* RFC 2920 - some servers may return a 354 response to DATA even
 
1222
     if there are no valid recipients.  If this happens just send a
 
1223
     line containing .\r\n to terminate the command.  It will then
 
1224
     fail as expected. */
 
1225
  if (session->current_message->valid_recipients == 0)
 
1226
    {
 
1227
      sio_write (conn, ".\r\n", 3);
 
1228
      session->cmd_state = -1;
 
1229
      return;
 
1230
    }
 
1231
 
 
1232
  sio_set_timeout (conn, 3 * 60 * 1000);
 
1233
 
 
1234
  /* Arrange to read the current message from the application. */
 
1235
  msg_source_set_cb (session->msg_source,
 
1236
                     session->current_message->cb,
 
1237
                     session->current_message->cb_arg);
 
1238
 
 
1239
  /* Arrange *not* to have the message contents monitored.  This is
 
1240
     purely to avoid overwhelming the application with data. */
 
1241
  sio_set_monitorcb (conn, NULL, NULL);
 
1242
 
 
1243
  /* Make sure we read the message from the beginning and get
 
1244
     the header processing right.  */
 
1245
  msg_rewind (session->msg_source);
 
1246
  reset_header_table (session->current_message);
 
1247
 
 
1248
  /* Read and process header lines from the application.
 
1249
     This step in processing
 
1250
     i)   removes headers provided by the application that should not be
 
1251
          present in the message, e.g. Return-Path: which is added by
 
1252
          an MTA during delivery but should not be present in a message
 
1253
          being submitted or which is in transit.
 
1254
     ii)  copies certain headers verbatim, e.g. MIME headers.
 
1255
     iii) alters the content of certain headers.  This will happen
 
1256
          according to library options set up by the application.
 
1257
   */
 
1258
  errno = 0;
 
1259
  while ((line = msg_gets (session->msg_source, &len, 0)) != NULL)
 
1260
    {
 
1261
      /* Header processing stops at a line containing only CRLF */
 
1262
      if (len == 2 && line[0] == '\r' && line[1] == '\n')
 
1263
        break;
 
1264
 
 
1265
      /* Check for continuation lines indicated by a blank or tab
 
1266
         at the start of the next line. */
 
1267
      while ((c = msg_nextc (session->msg_source)) != -1)
 
1268
        {
 
1269
          if (c != ' ' && c != '\t')
 
1270
            break;
 
1271
          line = msg_gets (session->msg_source, &len, 1);
 
1272
          if (line == NULL)
 
1273
            goto break_2;
 
1274
        }
 
1275
 
 
1276
      /* Line points to one or more lines of text forming an RFC 2822
 
1277
         header. */
 
1278
 
 
1279
      /* Header processing.  This function takes the "raw" header from
 
1280
         the application and returns a header which is to be written
 
1281
         to the remote MTA.   If header is NULL this header has been
 
1282
         deleted by the library.  If header == line it is passed
 
1283
         unchanged otherwise, header must be freed after use. */
 
1284
      header = process_header (session->current_message, line, &len);
 
1285
      if (header != NULL)
 
1286
        {
 
1287
          /* Notify byte count to the application. */
 
1288
          if (session->event_cb != NULL)
 
1289
            (*session->event_cb) (session, SMTP_EV_MESSAGEDATA,
 
1290
                                  session->event_cb_arg,
 
1291
                                  session->current_message, len);
 
1292
 
 
1293
          /* During data transfer, if we are monitoring the message
 
1294
             headers, call the monitor callback directly, once per header.
 
1295
             We don't bother with monitoring the dot stuffing.  Also set
 
1296
             the value of the writing parameter to 2 so that the app can
 
1297
             distinguish headers from data written in the sio_ package.  */
 
1298
          if (session->monitor_cb && session->monitor_cb_headers)
 
1299
            (*session->monitor_cb) (header, len, SMTP_CB_HEADERS,
 
1300
                                    session->monitor_cb_arg);
 
1301
 
 
1302
          /* Write the header using dot stuffing.  N.B. because of
 
1303
             dot stuffing, it is necessary to find the line breaks
 
1304
             during the copy. */
 
1305
          for (pline = header; pline < header + len; pline = p)
 
1306
            {
 
1307
              p = memchr (pline, '\n', header + len - pline);
 
1308
              if (p == NULL)
 
1309
                {
 
1310
                  set_errno (ERANGE);
 
1311
                  session->cmd_state = session->rsp_state = -1;
 
1312
                  return;
 
1313
                }
 
1314
              if (pline[0] == '.')
 
1315
                sio_write (conn, ".", 1);
 
1316
              sio_write (conn, pline, ++p - pline);
 
1317
            }
 
1318
        }
 
1319
      errno = 0;
 
1320
    }
 
1321
break_2:
 
1322
  if (errno != 0)
 
1323
    {
 
1324
      /* An error occurred during processing.  The only thing that can
 
1325
         be done is to drop the connection to the server since SMTP has
 
1326
         no way to recover gracefully from client errors while transferring
 
1327
         the message. */
 
1328
      set_errno (errno);
 
1329
      session->cmd_state = session->rsp_state = -1;
 
1330
      return;
 
1331
    }
 
1332
 
 
1333
  /* Now send missing headers.  This completes the processing started
 
1334
     above.  If the application did not supply certain headers that
 
1335
     should be present, the library will supply them here, e.g. Date:,
 
1336
     Message-Id: or To:/Cc:/Bcc: headers.  In the most extreme case the
 
1337
     application might just send a CRLF followed by the message body.
 
1338
     Libesmtp will then provide all the necessary headers. */
 
1339
  while ((header = missing_header (session->current_message, &len)) != NULL)
 
1340
    {
 
1341
      /* Notify byte count to the application. */
 
1342
      if (session->event_cb != NULL)
 
1343
        (*session->event_cb) (session, SMTP_EV_MESSAGEDATA,
 
1344
                              session->event_cb_arg,
 
1345
                              session->current_message, len);
 
1346
 
 
1347
      if (session->monitor_cb && session->monitor_cb_headers)
 
1348
        (*session->monitor_cb) (header, len, SMTP_CB_HEADERS,
 
1349
                                session->monitor_cb_arg);
 
1350
      for (pline = header; pline < header + len; pline = p)
 
1351
        {
 
1352
          p = memchr (pline, '\n', header + len - pline);
 
1353
          if (p == NULL)
 
1354
            {
 
1355
              set_errno (ERANGE);
 
1356
              session->cmd_state = session->rsp_state = -1;
 
1357
              return;
 
1358
            }
 
1359
          if (pline[0] == '.')
 
1360
            sio_write (conn, ".", 1);
 
1361
          sio_write (conn, pline, ++p - pline);
 
1362
        }
 
1363
    }
 
1364
 
 
1365
  /* ... and finally terminate the message headers */
 
1366
  sio_write (conn, "\r\n", 2);
 
1367
 
 
1368
  /* Read message body lines from the application and write them
 
1369
     to the remote MTA using dot stuffing. */
 
1370
  errno = 0;
 
1371
  while ((line = msg_gets (session->msg_source, &len, 0)) != NULL)
 
1372
    {
 
1373
      /* Notify byte count to the application. */
 
1374
      if (session->event_cb != NULL)
 
1375
        (*session->event_cb) (session, SMTP_EV_MESSAGEDATA,
 
1376
                              session->event_cb_arg,
 
1377
                              session->current_message, len);
 
1378
 
 
1379
      if (line[0] == '.')
 
1380
        sio_write (conn, ".", 1);
 
1381
      sio_write (conn, line, len);
 
1382
      errno = 0;
 
1383
    }
 
1384
  if (errno != 0)
 
1385
    {
 
1386
      set_errno (errno);
 
1387
      session->cmd_state = session->rsp_state = -1;
 
1388
      return;
 
1389
    }
 
1390
 
 
1391
  /* Terminate the DATA command.  Explicitly flush the buffer here.
 
1392
     This would have happened in the protocol loop anyway but doing it
 
1393
     here makes the output of strace more intuitive. */
 
1394
  sio_write (conn, ".\r\n", 3);
 
1395
  sio_flush (conn);
 
1396
 
 
1397
  sio_set_timeout (conn, 10 * 60 * 1000);
 
1398
  session->cmd_state = -1;
 
1399
}
 
1400
 
 
1401
void
 
1402
rsp_data2 (siobuf_t conn, smtp_session_t session)
 
1403
{
 
1404
  int code;
 
1405
  smtp_recipient_t recipient;
 
1406
 
 
1407
  /* Reinstate the protocol monitor. */
 
1408
  if (session->monitor_cb != NULL)
 
1409
    sio_set_monitorcb (conn, session->monitor_cb, session->monitor_cb_arg);
 
1410
 
 
1411
  code = read_smtp_response (conn, session,
 
1412
                             &session->current_message->message_status,
 
1413
                             NULL);
 
1414
 
 
1415
  if (code == 2)
 
1416
    {
 
1417
      /* Mark all the recipients complete for which the MTA has accepted
 
1418
         responsibility for delivery.  */
 
1419
      for (recipient = session->current_message->recipients;
 
1420
           recipient != NULL;
 
1421
           recipient = recipient->next)
 
1422
        if (!recipient->complete
 
1423
            && recipient->status.code >= 200 && recipient->status.code <= 299)
 
1424
          recipient->complete = 1;
 
1425
    }
 
1426
  else if (code == 5)
 
1427
    {
 
1428
      /* Mark all the recipients complete.  This message cannot be
 
1429
         accepted for any recipients.  */
 
1430
      for (recipient = session->current_message->recipients;
 
1431
           recipient != NULL;
 
1432
           recipient = recipient->next)
 
1433
        recipient->complete = 1;
 
1434
    }
 
1435
 
 
1436
 
 
1437
  if (session->event_cb != NULL)
 
1438
    (*session->event_cb) (session, SMTP_EV_MESSAGESENT,
 
1439
                          session->event_cb_arg, session->current_message);
 
1440
 
 
1441
  if (next_message (session))
 
1442
    session->rsp_state = (code == 2) ? initial_transaction_state (session)
 
1443
                                     : S_rset;
 
1444
  else
 
1445
    session->rsp_state = S_quit;
 
1446
}
 
1447
 
 
1448
/*****************************************************************************
 
1449
 * RSET
 
1450
 *****************************************************************************/
 
1451
 
 
1452
void
 
1453
cmd_rset (siobuf_t conn, smtp_session_t session)
 
1454
{
 
1455
  sio_write (conn, "RSET\r\n", 6);
 
1456
  if (session->current_message != NULL)
 
1457
    session->cmd_state = initial_transaction_state (session);
 
1458
  else
 
1459
    session->cmd_state = S_quit;
 
1460
}
 
1461
 
 
1462
void
 
1463
rsp_rset (siobuf_t conn, smtp_session_t session)
 
1464
{
 
1465
  struct smtp_status status;
 
1466
 
 
1467
  /* The RSET command should always succeed, since this client never
 
1468
     attempts to sent trailing whitespace or parameters to the command */
 
1469
  memset (&status, 0, sizeof status);
 
1470
  read_smtp_response (conn, session, &status, NULL);
 
1471
  reset_status (&status);
 
1472
  if (session->current_message != NULL)
 
1473
    session->rsp_state = initial_transaction_state (session);
 
1474
  else
 
1475
    session->rsp_state = S_quit;
 
1476
}
 
1477
 
 
1478
/*****************************************************************************
 
1479
 * QUIT
 
1480
 *****************************************************************************/
 
1481
 
 
1482
void
 
1483
cmd_quit (siobuf_t conn, smtp_session_t session)
 
1484
{
 
1485
  sio_write (conn, "QUIT\r\n", 6);
 
1486
  session->cmd_state = -1;
 
1487
}
 
1488
 
 
1489
void
 
1490
rsp_quit (siobuf_t conn, smtp_session_t session)
 
1491
{
 
1492
  struct smtp_status status;
 
1493
 
 
1494
  /* The QUIT command should always succeed.
 
1495
   */
 
1496
  memset (&status, 0, sizeof status);
 
1497
  read_smtp_response (conn, session, &status, NULL);
 
1498
  reset_status (&status);
 
1499
  session->rsp_state = -1;
 
1500
}
 
1501
 
 
1502
/*****************************************************************************
 
1503
 * Other crud.
 
1504
 *****************************************************************************/
 
1505
 
 
1506
#ifdef USE_XUSR
 
1507
void
 
1508
cmd_xusr (siobuf_t conn, smtp_session_t session)
 
1509
{
 
1510
  sio_write (conn, "XUSR\r\n", 6);
 
1511
  session->cmd_state = -1;
 
1512
}
 
1513
 
 
1514
void
 
1515
rsp_xusr (siobuf_t conn, smtp_session_t session)
 
1516
{
 
1517
  struct smtp_status status;
 
1518
 
 
1519
  /* The XUSR command should always succeed?  */
 
1520
  memset (&status, 0, sizeof status);
 
1521
  read_smtp_response (conn, session, &status, NULL);
 
1522
  reset_status (&status);
 
1523
  session->rsp_state = S_mail;
 
1524
}
 
1525
#endif