1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2010-2021 Free Software Foundation, Inc.
3 
4    This library is free software; you can redistribute it and/or modify
5    it under the terms of the GNU Lesser General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <mailutils/cstr.h>
26 #include <mailutils/cctype.h>
27 #include <mailutils/diag.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/list.h>
30 #include <mailutils/smtp.h>
31 #include <mailutils/stream.h>
32 #include <mailutils/sys/smtp.h>
33 
34 int
mu_smtp_write(mu_smtp_t smtp,const char * fmt,...)35 mu_smtp_write (mu_smtp_t smtp, const char *fmt, ...)
36 {
37   va_list ap;
38   int rc;
39 
40   va_start (ap, fmt);
41   rc = mu_stream_vprintf (smtp->carrier, fmt, ap);
42   va_end (ap);
43   return rc;
44 }
45 
46 static int
_mu_smtp_init_mlist(mu_smtp_t smtp)47 _mu_smtp_init_mlist (mu_smtp_t smtp)
48 {
49   if (!smtp->mlrepl)
50     {
51       int rc = mu_list_create (&smtp->mlrepl);
52       if (rc == 0)
53 	mu_list_set_destroy_item (smtp->mlrepl, mu_list_free_item);
54       return rc;
55     }
56   else
57     mu_list_clear (smtp->mlrepl);
58   return 0;
59 }
60 
61 int
mu_smtp_response(mu_smtp_t smtp)62 mu_smtp_response (mu_smtp_t smtp)
63 {
64   int rc;
65   size_t n;
66 
67   rc = mu_stream_getline (smtp->carrier, &smtp->rdbuf, &smtp->rdsize, &n);
68   MU_SMTP_CHECK_ERROR (smtp, rc);
69   if (n == 0)
70     MU_SMTP_CHECK_ERROR (smtp, EIO);
71   n = mu_rtrim_class (smtp->rdbuf, MU_CTYPE_ENDLN);
72   if (n < 3 || !mu_isdigit (smtp->rdbuf[0]))
73     {
74       mu_diag_output (MU_DIAG_NOTICE,
75 		      "received invalid reply from SMTP server");
76       MU_SMTP_CHECK_ERROR (smtp, MU_ERR_BADREPLY);
77     }
78   memcpy (smtp->replcode, smtp->rdbuf, 3);
79   smtp->replcode[3] = 0;
80   if (smtp->rdbuf[3] == '-')
81     {
82       smtp->flags |= _MU_SMTP_MLREPL;
83       n -= 3;
84       if (smtp->flsize < n)
85 	{
86 	  char *p = realloc (smtp->flbuf, n);
87 	  if (!p)
88 	    MU_SMTP_CHECK_ERROR (smtp, ENOMEM);
89 	  smtp->flbuf = p;
90 	  smtp->flsize = n;
91 	}
92       memcpy (smtp->flbuf, smtp->rdbuf + 4, n - 1);
93       smtp->flbuf[n - 1] = 0;
94       smtp->replptr = smtp->flbuf;
95 
96       rc = _mu_smtp_init_mlist (smtp);
97       MU_SMTP_CHECK_ERROR (smtp, rc);
98       do
99 	{
100           char *p;
101 
102 	  rc = mu_stream_getline (smtp->carrier, &smtp->rdbuf, &smtp->rdsize,
103 				  &n);
104 	  MU_SMTP_CHECK_ERROR (smtp, rc);
105 	  if (n == 0)
106 	    MU_SMTP_CHECK_ERROR (smtp, EIO);
107 	  n = mu_rtrim_class (smtp->rdbuf, MU_CTYPE_ENDLN);
108 	  if (n < 3 || memcmp (smtp->rdbuf, smtp->replcode, 3))
109 	    {
110 	      mu_diag_output (MU_DIAG_NOTICE,
111 			      "received invalid reply from SMTP server");
112 	      MU_SMTP_CHECK_ERROR (smtp, MU_ERR_BADREPLY);
113 	    }
114 	  p = strdup (smtp->rdbuf + 4);
115 	  if (!p)
116             MU_SMTP_CHECK_ERROR (smtp, ENOMEM);
117 	  mu_list_append (smtp->mlrepl, p);
118 	}
119       while (smtp->rdbuf[3] == '-');
120     }
121   else
122     {
123       smtp->flags &= ~_MU_SMTP_MLREPL;
124       smtp->replptr = smtp->rdbuf + 4;
125     }
126   return 0;
127 }
128 
129 int
mu_smtp_replcode(mu_smtp_t smtp,char * buf)130 mu_smtp_replcode (mu_smtp_t smtp, char *buf)
131 {
132   if (!smtp || !buf)
133     return EINVAL;
134   strcpy (buf, smtp->replcode);
135   return 0;
136 }
137 
138 int
mu_smtp_sget_reply(mu_smtp_t smtp,const char ** pbuf)139 mu_smtp_sget_reply (mu_smtp_t smtp, const char **pbuf)
140 {
141   if (!smtp || !pbuf)
142     return EINVAL;
143   *pbuf = smtp->replptr;
144   return 0;
145 }
146 
147 int
mu_smtp_get_reply_iterator(mu_smtp_t smtp,mu_iterator_t * pitr)148 mu_smtp_get_reply_iterator (mu_smtp_t smtp, mu_iterator_t *pitr)
149 {
150   if (!smtp || !pitr)
151     return EINVAL;
152   return mu_list_get_iterator (smtp->mlrepl, pitr);
153 }
154