rev |
line source |
meillo@0
|
1 /* pop3_in.c, Copyright (C) 2000 by Oliver Kurth,
|
meillo@0
|
2 *
|
meillo@0
|
3 * This program is free software; you can redistribute it and/or modify
|
meillo@0
|
4 * it under the terms of the GNU General Public License as published by
|
meillo@0
|
5 * the Free Software Foundation; either version 2 of the License, or
|
meillo@0
|
6 * (at your option) any later version.
|
meillo@10
|
7 *
|
meillo@0
|
8 * This program is distributed in the hope that it will be useful,
|
meillo@0
|
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
meillo@0
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
meillo@0
|
11 * GNU General Public License for more details.
|
meillo@0
|
12 *
|
meillo@0
|
13 * You should have received a copy of the GNU General Public License
|
meillo@0
|
14 * along with this program; if not, write to the Free Software
|
meillo@0
|
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
meillo@0
|
16 */
|
meillo@0
|
17
|
meillo@0
|
18 /* see RFC 1725 */
|
meillo@0
|
19
|
meillo@15
|
20 #include <sys/wait.h>
|
meillo@15
|
21 #include <sys/stat.h>
|
meillo@15
|
22
|
meillo@0
|
23 #include "masqmail.h"
|
meillo@0
|
24 #include "pop3_in.h"
|
meillo@0
|
25 #include "readsock.h"
|
meillo@0
|
26
|
meillo@0
|
27 #ifdef USE_LIB_CRYPTO
|
meillo@0
|
28 #include <openssl/md5.h>
|
meillo@0
|
29 #else
|
meillo@0
|
30 #include "md5/global.h"
|
meillo@0
|
31 #include "md5/md5.h"
|
meillo@0
|
32 #endif
|
meillo@0
|
33
|
meillo@0
|
34 #ifdef ENABLE_POP3
|
meillo@0
|
35
|
meillo@0
|
36 /* experimental feature */
|
meillo@0
|
37 #define DO_WRITE_UIDL_EARLY 1
|
meillo@0
|
38
|
meillo@10
|
39 static gchar*
|
meillo@10
|
40 MD5String(char *string)
|
meillo@0
|
41 {
|
meillo@10
|
42 MD5_CTX context;
|
meillo@10
|
43 unsigned char digest[16];
|
meillo@10
|
44 char str_digest[33];
|
meillo@10
|
45 int i;
|
meillo@0
|
46
|
meillo@0
|
47 #ifdef USE_LIB_CRYPTO
|
meillo@10
|
48 MD5(string, strlen(string), digest);
|
meillo@0
|
49 #else
|
meillo@10
|
50 MD5Init(&context);
|
meillo@10
|
51 MD5Update(&context, string, strlen(string));
|
meillo@10
|
52 MD5Final(digest, &context);
|
meillo@0
|
53 #endif
|
meillo@10
|
54 for (i = 0; i < 16; i++)
|
meillo@10
|
55 sprintf(str_digest + 2 * i, "%02x", digest[i]);
|
meillo@0
|
56
|
meillo@10
|
57 return g_strdup(str_digest);
|
meillo@0
|
58 }
|
meillo@0
|
59
|
meillo@10
|
60 static pop3_base*
|
meillo@10
|
61 create_pop3base(gint sock, guint flags)
|
meillo@0
|
62 {
|
meillo@10
|
63 gint dup_sock;
|
meillo@0
|
64
|
meillo@10
|
65 pop3_base *popb = (pop3_base *) g_malloc(sizeof(pop3_base));
|
meillo@10
|
66 if (popb) {
|
meillo@10
|
67 memset(popb, 0, sizeof(pop3_base));
|
meillo@0
|
68
|
meillo@10
|
69 popb->error = pop3_ok;
|
meillo@0
|
70
|
meillo@10
|
71 popb->buffer = (gchar *) g_malloc(POP3_BUF_LEN);
|
meillo@0
|
72
|
meillo@10
|
73 dup_sock = dup(sock);
|
meillo@10
|
74 popb->out = fdopen(sock, "w");
|
meillo@10
|
75 popb->in = fdopen(dup_sock, "r");
|
meillo@10
|
76
|
meillo@10
|
77 popb->flags = flags;
|
meillo@10
|
78 }
|
meillo@10
|
79 return popb;
|
meillo@0
|
80 }
|
meillo@0
|
81
|
meillo@10
|
82 static void
|
meillo@10
|
83 pop3_printf(FILE * out, gchar * fmt, ...)
|
meillo@0
|
84 {
|
meillo@10
|
85 va_list args;
|
meillo@10
|
86 va_start(args, fmt);
|
meillo@0
|
87
|
meillo@10
|
88 DEBUG(4) {
|
meillo@10
|
89 gchar buf[256];
|
meillo@10
|
90 va_list args_copy;
|
meillo@0
|
91
|
meillo@10
|
92 va_copy(args_copy, args);
|
meillo@10
|
93 vsnprintf(buf, 255, fmt, args_copy);
|
meillo@10
|
94 va_end(args_copy);
|
meillo@0
|
95
|
meillo@10
|
96 debugf(">>>%s", buf);
|
meillo@10
|
97 }
|
meillo@0
|
98
|
meillo@10
|
99 vfprintf(out, fmt, args);
|
meillo@10
|
100 fflush(out);
|
meillo@0
|
101
|
meillo@10
|
102 va_end(args);
|
meillo@0
|
103 }
|
meillo@0
|
104
|
meillo@10
|
105 static gboolean
|
meillo@10
|
106 find_uid(pop3_base * popb, gchar * str)
|
meillo@0
|
107 {
|
meillo@10
|
108 GList *node, *node_next;
|
meillo@0
|
109
|
meillo@10
|
110 for (node = popb->list_uid_old; node; node = node_next) {
|
meillo@10
|
111 gchar *uid = (gchar *) (node->data);
|
meillo@10
|
112 node_next = node->next;
|
meillo@10
|
113 if (strcmp(uid, str) == 0) {
|
meillo@0
|
114 #if 1
|
meillo@10
|
115 popb->list_uid_old = g_list_remove_link(popb->list_uid_old, node);
|
meillo@10
|
116 g_list_free_1(node);
|
meillo@10
|
117 g_free(uid);
|
meillo@0
|
118 #endif
|
meillo@10
|
119 return TRUE;
|
meillo@10
|
120 }
|
meillo@10
|
121 }
|
meillo@10
|
122 return FALSE;
|
meillo@0
|
123 }
|
meillo@0
|
124
|
meillo@10
|
125 static gboolean
|
meillo@10
|
126 write_uidl(pop3_base * popb, gchar * user)
|
meillo@0
|
127 {
|
meillo@10
|
128 gboolean ok = FALSE;
|
meillo@10
|
129 GList *node;
|
meillo@10
|
130 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host);
|
meillo@10
|
131 gchar *tmpname = g_strdup_printf("%s.tmp", filename);
|
meillo@10
|
132 FILE *fptr = fopen(tmpname, "wt");
|
meillo@0
|
133
|
meillo@10
|
134 if (fptr) {
|
meillo@10
|
135 foreach(popb->drop_list, node) {
|
meillo@10
|
136 msg_info *info = (msg_info *) (node->data);
|
meillo@10
|
137 if (info->is_fetched || info->is_in_uidl)
|
meillo@10
|
138 fprintf(fptr, "%s\n", info->uid);
|
meillo@10
|
139 }
|
meillo@10
|
140 fclose(fptr);
|
meillo@10
|
141 ok = (rename(tmpname, filename) != -1);
|
meillo@10
|
142 }
|
meillo@10
|
143
|
meillo@10
|
144 g_free(tmpname);
|
meillo@10
|
145 g_free(filename);
|
meillo@10
|
146 return ok;
|
meillo@0
|
147 }
|
meillo@0
|
148
|
meillo@10
|
149 static gboolean
|
meillo@10
|
150 read_uidl_fname(pop3_base * popb, gchar * filename)
|
meillo@0
|
151 {
|
meillo@10
|
152 gboolean ok = FALSE;
|
meillo@10
|
153 FILE *fptr = fopen(filename, "rt");
|
meillo@10
|
154 gchar buf[256];
|
meillo@0
|
155
|
meillo@10
|
156 if (fptr) {
|
meillo@10
|
157 popb->list_uid_old = NULL;
|
meillo@10
|
158 while (fgets(buf, 255, fptr)) {
|
meillo@10
|
159 if (buf[strlen(buf) - 1] == '\n') {
|
meillo@10
|
160 g_strchomp(buf);
|
meillo@10
|
161 popb->list_uid_old = g_list_append(popb->list_uid_old, g_strdup(buf));
|
meillo@10
|
162 } else {
|
meillo@10
|
163 logwrite(LOG_ALERT, "broken uid: %s\n", buf);
|
meillo@10
|
164 break;
|
meillo@10
|
165 }
|
meillo@10
|
166 }
|
meillo@10
|
167 fclose(fptr);
|
meillo@10
|
168 ok = TRUE;
|
meillo@10
|
169 } else
|
meillo@10
|
170 logwrite(LOG_ALERT, "opening of %s failed: %s", filename, strerror(errno));
|
meillo@10
|
171 return ok;
|
meillo@0
|
172 }
|
meillo@0
|
173
|
meillo@10
|
174 static gboolean
|
meillo@10
|
175 read_uidl(pop3_base * popb, gchar * user)
|
meillo@0
|
176 {
|
meillo@10
|
177 gboolean ok = FALSE;
|
meillo@10
|
178 struct stat statbuf;
|
meillo@10
|
179 gchar *filename = g_strdup_printf("%s/popuidl/%s@%s", conf.spool_dir, user, popb->remote_host);
|
meillo@0
|
180
|
meillo@10
|
181 if (stat(filename, &statbuf) == 0) {
|
meillo@10
|
182 ok = read_uidl_fname(popb, filename);
|
meillo@10
|
183 if (ok) {
|
meillo@10
|
184 GList *drop_node;
|
meillo@10
|
185 foreach(popb->drop_list, drop_node) {
|
meillo@10
|
186 msg_info *info = (msg_info *) (drop_node->data);
|
meillo@10
|
187 if (find_uid(popb, info->uid)) {
|
meillo@10
|
188 DEBUG(5) debugf("msg with uid '%s' already known\n", info->uid);
|
meillo@10
|
189 info->is_in_uidl = TRUE;
|
meillo@10
|
190 popb->uidl_known_cnt++;
|
meillo@10
|
191 } else
|
meillo@10
|
192 DEBUG(5) debugf("msg with uid '%s' not known\n", info->uid);
|
meillo@10
|
193 }
|
meillo@10
|
194 }
|
meillo@10
|
195 } else {
|
meillo@10
|
196 logwrite(LOG_DEBUG, "no uidl file '%s' found\n", filename);
|
meillo@10
|
197 ok = TRUE;
|
meillo@10
|
198 }
|
meillo@0
|
199
|
meillo@10
|
200 g_free(filename);
|
meillo@10
|
201 return ok; /* return code is irrelevant, do not check... */
|
meillo@0
|
202 }
|
meillo@0
|
203
|
meillo@10
|
204 static gboolean
|
meillo@10
|
205 read_response(pop3_base * popb, int timeout)
|
meillo@0
|
206 {
|
meillo@10
|
207 gint len;
|
meillo@0
|
208
|
meillo@10
|
209 len = read_sockline(popb->in, popb->buffer, POP3_BUF_LEN, timeout, READSOCKL_CHUG);
|
meillo@0
|
210
|
meillo@10
|
211 if (len == -3) {
|
meillo@10
|
212 popb->error = pop3_timeout;
|
meillo@10
|
213 return FALSE;
|
meillo@10
|
214 } else if (len == -2) {
|
meillo@10
|
215 popb->error = pop3_syntax;
|
meillo@10
|
216 return FALSE;
|
meillo@10
|
217 } else if (len == -1) {
|
meillo@10
|
218 popb->error = pop3_eof;
|
meillo@10
|
219 return FALSE;
|
meillo@10
|
220 }
|
meillo@10
|
221
|
meillo@10
|
222 return TRUE;
|
meillo@0
|
223 }
|
meillo@0
|
224
|
meillo@10
|
225 static gboolean
|
meillo@10
|
226 check_response(pop3_base * popb)
|
meillo@0
|
227 {
|
meillo@10
|
228 char c = popb->buffer[0];
|
meillo@0
|
229
|
meillo@10
|
230 if (c == '+') {
|
meillo@10
|
231 popb->error = pop3_ok;
|
meillo@10
|
232 return TRUE;
|
meillo@10
|
233 } else if (c == '-')
|
meillo@10
|
234 popb->error = pop3_fail;
|
meillo@10
|
235 else
|
meillo@10
|
236 popb->error = pop3_syntax;
|
meillo@10
|
237 return FALSE;
|
meillo@0
|
238 }
|
meillo@0
|
239
|
meillo@10
|
240 static gboolean
|
meillo@10
|
241 strtoi(gchar * p, gchar ** pend, gint * val)
|
meillo@0
|
242 {
|
meillo@10
|
243 gchar buf[12];
|
meillo@10
|
244 gint i = 0;
|
meillo@0
|
245
|
meillo@10
|
246 while (*p && isspace(*p))
|
meillo@10
|
247 p++;
|
meillo@10
|
248 if (*p) {
|
meillo@10
|
249 while ((i < 11) && isdigit(*p))
|
meillo@10
|
250 buf[i++] = *(p++);
|
meillo@10
|
251 buf[i] = 0;
|
meillo@10
|
252 *val = atoi(buf);
|
meillo@10
|
253 *pend = p;
|
meillo@10
|
254 return TRUE;
|
meillo@10
|
255 }
|
meillo@10
|
256 return FALSE;
|
meillo@0
|
257 }
|
meillo@0
|
258
|
meillo@10
|
259 static gboolean
|
meillo@10
|
260 check_response_int_int(pop3_base * popb, gint * arg0, gint * arg1)
|
meillo@0
|
261 {
|
meillo@10
|
262 if (check_response(popb)) {
|
meillo@10
|
263 gchar *p = &(popb->buffer[3]);
|
meillo@10
|
264 gchar *pe;
|
meillo@0
|
265
|
meillo@10
|
266 if (strtoi(p, &pe, arg0)) {
|
meillo@10
|
267 DEBUG(5) debugf("arg0 = %d\n", *arg0);
|
meillo@10
|
268 p = pe;
|
meillo@10
|
269 if (strtoi(p, &pe, arg1))
|
meillo@10
|
270 DEBUG(5) debugf("arg1 = %d\n", *arg1);
|
meillo@10
|
271 return TRUE;
|
meillo@113
|
272 /* FIXME: Paolo's code has the return stmt
|
meillo@113
|
273 inside the if block right above it. What
|
meillo@113
|
274 is correct? */
|
meillo@10
|
275 }
|
meillo@10
|
276 popb->error = pop3_syntax;
|
meillo@10
|
277 }
|
meillo@10
|
278 return FALSE;
|
meillo@0
|
279 }
|
meillo@0
|
280
|
meillo@10
|
281 static gboolean
|
meillo@10
|
282 get_drop_listing(pop3_base * popb)
|
meillo@0
|
283 {
|
meillo@10
|
284 gchar buf[64];
|
meillo@0
|
285
|
meillo@10
|
286 DEBUG(5) debugf("get_drop_listing() entered\n");
|
meillo@0
|
287
|
meillo@10
|
288 while (1) {
|
meillo@10
|
289 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
|
meillo@10
|
290 if (len > 0) {
|
meillo@10
|
291 if (buf[0] == '.')
|
meillo@10
|
292 return TRUE;
|
meillo@10
|
293 else {
|
meillo@10
|
294 gint number, msg_size;
|
meillo@10
|
295 gchar *p = buf, *pe;
|
meillo@10
|
296 if (strtoi(p, &pe, &number)) {
|
meillo@10
|
297 p = pe;
|
meillo@10
|
298 if (strtoi(p, &pe, &msg_size)) {
|
meillo@10
|
299 msg_info *info = g_malloc(sizeof(msg_info));
|
meillo@10
|
300 info->number = number;
|
meillo@10
|
301 info->size = msg_size;
|
meillo@0
|
302
|
meillo@10
|
303 DEBUG(5) debugf ("get_drop_listing(), number = %d, msg_size = %d\n", number, msg_size);
|
meillo@0
|
304
|
meillo@10
|
305 info->uid = NULL;
|
meillo@10
|
306 info->is_fetched = FALSE;
|
meillo@10
|
307 info->is_in_uidl = FALSE;
|
meillo@10
|
308 popb->drop_list = g_list_append(popb->drop_list, info);
|
meillo@10
|
309 } else {
|
meillo@10
|
310 popb->error = pop3_syntax;
|
meillo@10
|
311 break;
|
meillo@10
|
312 }
|
meillo@10
|
313 } else {
|
meillo@10
|
314 popb->error = pop3_syntax;
|
meillo@10
|
315 break;
|
meillo@10
|
316 }
|
meillo@10
|
317 }
|
meillo@10
|
318 } else {
|
meillo@10
|
319 popb->error = (len == -1) ? pop3_eof : pop3_timeout;
|
meillo@10
|
320 return FALSE;
|
meillo@10
|
321 }
|
meillo@0
|
322 }
|
meillo@10
|
323 return FALSE;
|
meillo@0
|
324 }
|
meillo@0
|
325
|
meillo@10
|
326 static gboolean
|
meillo@10
|
327 get_uid_listing(pop3_base * popb)
|
meillo@0
|
328 {
|
meillo@10
|
329 gchar buf[64];
|
meillo@0
|
330
|
meillo@10
|
331 while (1) {
|
meillo@10
|
332 gint len = read_sockline(popb->in, buf, 64, POP3_CMD_TIMEOUT, READSOCKL_CHUG);
|
meillo@10
|
333 if (len > 0) {
|
meillo@10
|
334 if (buf[0] == '.')
|
meillo@10
|
335 return TRUE;
|
meillo@10
|
336 else {
|
meillo@10
|
337 gint number;
|
meillo@10
|
338 gchar *p = buf, *pe;
|
meillo@10
|
339 if (strtoi(p, &pe, &number)) {
|
meillo@10
|
340 msg_info *info = NULL;
|
meillo@10
|
341 GList *drop_node;
|
meillo@0
|
342
|
meillo@10
|
343 p = pe;
|
meillo@10
|
344 while (*p && isspace(*p))
|
meillo@10
|
345 p++;
|
meillo@0
|
346
|
meillo@10
|
347 foreach(popb->drop_list, drop_node) {
|
meillo@10
|
348 msg_info *curr_info = (msg_info *) (drop_node->data);
|
meillo@10
|
349 if (curr_info->number == number) {
|
meillo@10
|
350 info = curr_info;
|
meillo@10
|
351 break;
|
meillo@10
|
352 }
|
meillo@10
|
353 }
|
meillo@10
|
354 if (info) {
|
meillo@10
|
355 info->uid = g_strdup(p);
|
meillo@10
|
356 g_strchomp(info->uid);
|
meillo@10
|
357 }
|
meillo@0
|
358
|
meillo@10
|
359 } else {
|
meillo@10
|
360 popb->error = pop3_syntax;
|
meillo@10
|
361 break;
|
meillo@10
|
362 }
|
meillo@10
|
363 }
|
meillo@10
|
364 }
|
meillo@0
|
365 }
|
meillo@10
|
366 return FALSE;
|
meillo@0
|
367 }
|
meillo@0
|
368
|
meillo@10
|
369 static gboolean
|
meillo@10
|
370 check_init_response(pop3_base * popb)
|
meillo@0
|
371 {
|
meillo@10
|
372 if (check_response(popb)) {
|
meillo@10
|
373 gchar buf[256];
|
meillo@10
|
374 gchar *p = popb->buffer;
|
meillo@10
|
375 gint i = 0;
|
meillo@10
|
376 if (*p) {
|
meillo@10
|
377 while (*p && (*p != '<'))
|
meillo@10
|
378 p++;
|
meillo@10
|
379 while (*p && (*p != '>') && (i < 254))
|
meillo@10
|
380 buf[i++] = *(p++);
|
meillo@10
|
381 buf[i++] = '>';
|
meillo@15
|
382 buf[i] = '\0';
|
meillo@0
|
383
|
meillo@10
|
384 popb->timestamp = g_strdup(buf);
|
meillo@0
|
385
|
meillo@10
|
386 return TRUE;
|
meillo@10
|
387 }
|
meillo@10
|
388 }
|
meillo@10
|
389 return FALSE;
|
meillo@0
|
390 }
|
meillo@0
|
391
|
meillo@10
|
392 void
|
meillo@10
|
393 pop3_in_close(pop3_base * popb)
|
meillo@0
|
394 {
|
meillo@10
|
395 GList *node;
|
meillo@0
|
396
|
meillo@10
|
397 fclose(popb->in);
|
meillo@10
|
398 fclose(popb->out);
|
meillo@0
|
399
|
meillo@10
|
400 close(popb->sock);
|
meillo@0
|
401
|
meillo@10
|
402 foreach(popb->list_uid_old, node) {
|
meillo@10
|
403 gchar *uid = (gchar *) (node->data);
|
meillo@10
|
404 g_free(uid);
|
meillo@10
|
405 }
|
meillo@10
|
406 g_list_free(popb->list_uid_old);
|
meillo@0
|
407
|
meillo@10
|
408 foreach(popb->drop_list, node) {
|
meillo@10
|
409 msg_info *info = (msg_info *) (node->data);
|
meillo@10
|
410 if (info->uid)
|
meillo@10
|
411 g_free(info->uid);
|
meillo@10
|
412 g_free(info);
|
meillo@10
|
413 }
|
meillo@10
|
414 g_list_free(popb->drop_list);
|
meillo@0
|
415
|
meillo@10
|
416 if (popb->buffer)
|
meillo@10
|
417 g_free(popb->buffer);
|
meillo@10
|
418 if (popb->timestamp)
|
meillo@10
|
419 g_free(popb->timestamp);
|
meillo@0
|
420 }
|
meillo@0
|
421
|
meillo@10
|
422 pop3_base*
|
meillo@10
|
423 pop3_in_open(gchar * host, gint port, GList * resolve_list, guint flags)
|
meillo@0
|
424 {
|
meillo@10
|
425 pop3_base *popb;
|
meillo@10
|
426 gint sock;
|
meillo@10
|
427 mxip_addr *addr;
|
meillo@0
|
428
|
meillo@10
|
429 DEBUG(5) debugf("pop3_in_open entered, host = %s\n", host);
|
meillo@0
|
430
|
meillo@10
|
431 if ((addr = connect_resolvelist(&sock, host, port, resolve_list))) {
|
meillo@10
|
432 /* create structure to hold status data: */
|
meillo@10
|
433 popb = create_pop3base(sock, flags);
|
meillo@10
|
434 popb->remote_host = addr->name;
|
meillo@0
|
435
|
meillo@10
|
436 DEBUG(5) {
|
meillo@10
|
437 struct sockaddr_in name;
|
meillo@10
|
438 int len;
|
meillo@10
|
439 getsockname(sock, (struct sockaddr *) (&name), &len);
|
meillo@10
|
440 debugf("socket: name.sin_addr = %s\n", inet_ntoa(name.sin_addr));
|
meillo@10
|
441 }
|
meillo@10
|
442 return popb;
|
meillo@10
|
443 }
|
meillo@10
|
444 return NULL;
|
meillo@0
|
445 }
|
meillo@0
|
446
|
meillo@10
|
447 pop3_base*
|
meillo@10
|
448 pop3_in_open_child(gchar * cmd, guint flags)
|
meillo@0
|
449 {
|
meillo@10
|
450 pop3_base *popb;
|
meillo@10
|
451 gint sock;
|
meillo@0
|
452
|
meillo@10
|
453 DEBUG(5) debugf("pop3_in_open_child entered, cmd = %s\n", cmd);
|
meillo@10
|
454 sock = child(cmd);
|
meillo@10
|
455 if (sock > 0) {
|
meillo@10
|
456 popb = create_pop3base(sock, flags);
|
meillo@10
|
457 popb->remote_host = NULL;
|
meillo@10
|
458 return popb;
|
meillo@10
|
459 }
|
meillo@10
|
460 logwrite(LOG_ALERT, "child failed (sock = %d): %s\n", sock, strerror(errno));
|
meillo@0
|
461
|
meillo@10
|
462 return NULL;
|
meillo@0
|
463 }
|
meillo@0
|
464
|
meillo@10
|
465 gboolean
|
meillo@10
|
466 pop3_in_init(pop3_base * popb)
|
meillo@0
|
467 {
|
meillo@10
|
468 gboolean ok;
|
meillo@0
|
469
|
meillo@10
|
470 if ((ok = read_response(popb, POP3_INITIAL_TIMEOUT))) {
|
meillo@10
|
471 ok = check_init_response(popb);
|
meillo@10
|
472 }
|
meillo@10
|
473 if (!ok)
|
meillo@10
|
474 /* pop3_in_log_failure(popb, NULL); */
|
meillo@10
|
475 logwrite(LOG_ALERT, "pop3 failed\n");
|
meillo@10
|
476 return ok;
|
meillo@0
|
477 }
|
meillo@0
|
478
|
meillo@10
|
479 gboolean
|
meillo@10
|
480 pop3_in_login(pop3_base * popb, gchar * user, gchar * pass)
|
meillo@0
|
481 {
|
meillo@10
|
482 if (popb->flags & POP3_FLAG_APOP) {
|
meillo@0
|
483
|
meillo@10
|
484 gchar *string = g_strdup_printf("%s%s", popb->timestamp, pass);
|
meillo@10
|
485 gchar *digest = MD5String(string);
|
meillo@10
|
486 pop3_printf(popb->out, "APOP %s %s\r\n", user, digest);
|
meillo@10
|
487 g_free(string);
|
meillo@10
|
488 g_free(digest);
|
meillo@10
|
489 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
490 if (check_response(popb))
|
meillo@10
|
491 return TRUE;
|
meillo@10
|
492 else
|
meillo@10
|
493 popb->error = pop3_login_failure;
|
meillo@10
|
494 }
|
meillo@0
|
495
|
meillo@10
|
496 } else {
|
meillo@0
|
497
|
meillo@10
|
498 pop3_printf(popb->out, "USER %s\r\n", user);
|
meillo@10
|
499 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
500 if (check_response(popb)) {
|
meillo@10
|
501 pop3_printf(popb->out, "PASS %s\r\n", pass);
|
meillo@10
|
502 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
503 if (check_response(popb))
|
meillo@10
|
504 return TRUE;
|
meillo@10
|
505 else
|
meillo@10
|
506 popb->error = pop3_login_failure;
|
meillo@10
|
507 }
|
meillo@10
|
508 } else {
|
meillo@10
|
509 popb->error = pop3_login_failure;
|
meillo@10
|
510 }
|
meillo@10
|
511 }
|
meillo@0
|
512 }
|
meillo@10
|
513 return FALSE;
|
meillo@0
|
514 }
|
meillo@0
|
515
|
meillo@10
|
516 gboolean
|
meillo@10
|
517 pop3_in_stat(pop3_base * popb)
|
meillo@0
|
518 {
|
meillo@10
|
519 pop3_printf(popb->out, "STAT\r\n");
|
meillo@10
|
520 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
521 gint msg_cnt, mbox_size;
|
meillo@10
|
522 if (check_response_int_int(popb, &msg_cnt, &mbox_size)) {
|
meillo@10
|
523 popb->msg_cnt = msg_cnt;
|
meillo@10
|
524 popb->mbox_size = mbox_size;
|
meillo@0
|
525
|
meillo@10
|
526 return TRUE;
|
meillo@10
|
527 }
|
meillo@10
|
528 }
|
meillo@10
|
529 return FALSE;
|
meillo@0
|
530 }
|
meillo@0
|
531
|
meillo@10
|
532 gboolean
|
meillo@10
|
533 pop3_in_list(pop3_base * popb)
|
meillo@0
|
534 {
|
meillo@10
|
535 pop3_printf(popb->out, "LIST\r\n");
|
meillo@10
|
536 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
537 if (get_drop_listing(popb)) {
|
meillo@10
|
538 return TRUE;
|
meillo@10
|
539 }
|
meillo@10
|
540 }
|
meillo@10
|
541 return FALSE;
|
meillo@0
|
542 }
|
meillo@0
|
543
|
meillo@10
|
544 gboolean
|
meillo@10
|
545 pop3_in_dele(pop3_base * popb, gint number)
|
meillo@0
|
546 {
|
meillo@10
|
547 pop3_printf(popb->out, "DELE %d\r\n", number);
|
meillo@10
|
548 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
549 return TRUE;
|
meillo@10
|
550 }
|
meillo@10
|
551 return FALSE;
|
meillo@0
|
552 }
|
meillo@0
|
553
|
meillo@10
|
554 message*
|
meillo@10
|
555 pop3_in_retr(pop3_base * popb, gint number, address * rcpt)
|
meillo@0
|
556 {
|
meillo@10
|
557 accept_error err;
|
meillo@0
|
558
|
meillo@10
|
559 pop3_printf(popb->out, "RETR %d\r\n", number);
|
meillo@10
|
560 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
561 message *msg = create_message();
|
meillo@10
|
562 msg->received_host = popb->remote_host;
|
meillo@10
|
563 msg->received_prot = (popb->flags & POP3_FLAG_APOP) ? PROT_APOP : PROT_POP3;
|
meillo@10
|
564 msg->transfer_id = (popb->next_id)++;
|
meillo@10
|
565 msg->rcpt_list = g_list_append(NULL, copy_address(rcpt));
|
meillo@0
|
566
|
meillo@10
|
567 if ((err = accept_message(popb->in, msg, ACC_MAIL_FROM_HEAD
|
meillo@15
|
568 | (conf.do_save_envelope_to ? ACC_SAVE_ENVELOPE_TO : 0)))
|
meillo@10
|
569 == AERR_OK)
|
meillo@10
|
570 return msg;
|
meillo@0
|
571
|
meillo@10
|
572 destroy_message(msg);
|
meillo@10
|
573 }
|
meillo@10
|
574 return NULL;
|
meillo@0
|
575 }
|
meillo@0
|
576
|
meillo@10
|
577 gboolean
|
meillo@10
|
578 pop3_in_uidl(pop3_base * popb)
|
meillo@0
|
579 {
|
meillo@10
|
580 pop3_printf(popb->out, "UIDL\r\n");
|
meillo@10
|
581 if (read_response(popb, POP3_CMD_TIMEOUT)) {
|
meillo@10
|
582 if (get_uid_listing(popb)) {
|
meillo@10
|
583 return TRUE;
|
meillo@10
|
584 }
|
meillo@10
|
585 }
|
meillo@10
|
586 return FALSE;
|
meillo@10
|
587 }
|
meillo@0
|
588
|
meillo@10
|
589 gboolean
|
meillo@10
|
590 pop3_in_quit(pop3_base * popb)
|
meillo@10
|
591 {
|
meillo@10
|
592 pop3_printf(popb->out, "QUIT\r\n");
|
meillo@10
|
593 DEBUG(4) debugf("QUIT\n");
|
meillo@10
|
594 signal(SIGALRM, SIG_DFL);
|
meillo@10
|
595 return TRUE;
|
meillo@0
|
596 }
|
meillo@0
|
597
|
meillo@0
|
598 /* Send a DELE command for each message in (the old) uid listing.
|
meillo@0
|
599 This is to prevent mail from to be kept on server, if a previous
|
meillo@0
|
600 transaction was interupted. */
|
meillo@10
|
601 gboolean
|
meillo@10
|
602 pop3_in_uidl_dele(pop3_base * popb)
|
meillo@0
|
603 {
|
meillo@10
|
604 GList *drop_node;
|
meillo@0
|
605
|
meillo@10
|
606 foreach(popb->drop_list, drop_node) {
|
meillo@10
|
607 msg_info *info = (msg_info *) (drop_node->data);
|
meillo@10
|
608 /* if(find_uid(popb, info->uid)){ */
|
meillo@10
|
609 if (info->is_in_uidl) {
|
meillo@10
|
610 if (!pop3_in_dele(popb, info->number))
|
meillo@10
|
611 return FALSE;
|
meillo@10
|
612 /* TODO: it probably makes sense to also delete this uid from the listing */
|
meillo@10
|
613 }
|
meillo@10
|
614 }
|
meillo@10
|
615 return TRUE;
|
meillo@0
|
616 }
|
meillo@0
|
617
|
meillo@10
|
618 gboolean
|
meillo@15
|
619 pop3_get(pop3_base * popb, gchar * user, gchar * pass, address * rcpt, address * return_path,
|
meillo@15
|
620 gint max_count, gint max_size, gboolean max_size_delete)
|
meillo@0
|
621 {
|
meillo@10
|
622 gboolean ok = FALSE;
|
meillo@10
|
623 gint num_children = 0;
|
meillo@0
|
624
|
meillo@10
|
625 DEBUG(5) debugf("rcpt = %s@%s\n", rcpt->local_part, rcpt->domain);
|
meillo@0
|
626
|
meillo@10
|
627 signal(SIGCHLD, SIG_DFL);
|
meillo@0
|
628
|
meillo@10
|
629 if (pop3_in_init(popb)) {
|
meillo@10
|
630 if (pop3_in_login(popb, user, pass)) {
|
meillo@10
|
631 if (pop3_in_stat(popb)) {
|
meillo@10
|
632 if (popb->msg_cnt > 0) {
|
meillo@0
|
633
|
meillo@15
|
634 logwrite(LOG_NOTICE | LOG_VERBOSE, "%d message(s) for user %s at %s\n",
|
meillo@15
|
635 popb->msg_cnt, user, popb->remote_host);
|
meillo@0
|
636
|
meillo@10
|
637 if (pop3_in_list(popb)) {
|
meillo@10
|
638 gboolean do_get = !(popb->flags & POP3_FLAG_UIDL);
|
meillo@10
|
639 if (!do_get)
|
meillo@10
|
640 do_get = pop3_in_uidl(popb);
|
meillo@10
|
641 if (do_get) {
|
meillo@10
|
642 gint count = 0;
|
meillo@10
|
643 GList *drop_node;
|
meillo@0
|
644
|
meillo@10
|
645 if (popb->flags & POP3_FLAG_UIDL) {
|
meillo@10
|
646 read_uidl(popb, user);
|
meillo@10
|
647 logwrite(LOG_VERBOSE | LOG_NOTICE, "%d message(s) already in uidl.\n", popb->uidl_known_cnt);
|
meillo@10
|
648 }
|
meillo@10
|
649 if ((popb->flags & POP3_FLAG_UIDL) && (popb->flags & POP3_FLAG_UIDL_DELE))
|
meillo@10
|
650 pop3_in_uidl_dele(popb);
|
meillo@0
|
651
|
meillo@10
|
652 foreach(popb->drop_list, drop_node) {
|
meillo@0
|
653
|
meillo@10
|
654 msg_info *info = (msg_info *) (drop_node->data);
|
meillo@10
|
655 gboolean do_get_this = !(popb->flags & POP3_FLAG_UIDL);
|
meillo@10
|
656 /* if(!do_get_this) do_get_this = !find_uid(popb, info->uid); */
|
meillo@10
|
657 if (!do_get_this)
|
meillo@10
|
658 do_get_this = !(info->is_in_uidl);
|
meillo@10
|
659 if (do_get_this) {
|
meillo@0
|
660
|
meillo@10
|
661 if ((info->size < max_size) || (max_size == 0)) {
|
meillo@10
|
662 message *msg;
|
meillo@0
|
663
|
meillo@10
|
664 logwrite(LOG_VERBOSE | LOG_NOTICE, "receiving message %d\n", info->number);
|
meillo@10
|
665 msg = pop3_in_retr(popb, info->number, rcpt);
|
meillo@10
|
666
|
meillo@10
|
667 if (msg) {
|
meillo@10
|
668 if (return_path)
|
meillo@10
|
669 msg->return_path = copy_address(return_path);
|
meillo@10
|
670 if (spool_write(msg, TRUE)) {
|
meillo@10
|
671 pid_t pid;
|
meillo@10
|
672 logwrite(LOG_NOTICE, "%s <= %s host=%s with %s\n", msg->uid,
|
meillo@10
|
673 addr_string(msg->return_path), popb->remote_host,
|
meillo@10
|
674 (popb->flags & POP3_FLAG_APOP) ? prot_names [PROT_APOP] : prot_names [PROT_POP3]);
|
meillo@10
|
675 info->is_fetched = TRUE;
|
meillo@10
|
676 count++;
|
meillo@0
|
677 #if DO_WRITE_UIDL_EARLY
|
meillo@10
|
678 if (popb->flags & POP3_FLAG_UIDL)
|
meillo@10
|
679 write_uidl(popb, user);
|
meillo@0
|
680 #endif
|
meillo@10
|
681 if (!conf.do_queue) {
|
meillo@0
|
682
|
meillo@10
|
683 /* wait for child processes. If there are too many, we wait blocking, before we fork another one */
|
meillo@10
|
684 while (num_children > 0) {
|
meillo@10
|
685 int status, options = WNOHANG;
|
meillo@10
|
686 pid_t pid;
|
meillo@0
|
687
|
meillo@10
|
688 if (num_children >= POP3_MAX_CHILDREN) {
|
meillo@10
|
689 logwrite(LOG_NOTICE, "too many children - waiting\n");
|
meillo@10
|
690 options = 0;
|
meillo@10
|
691 }
|
meillo@10
|
692 if ((pid = waitpid(0, &status, options)) > 0) {
|
meillo@10
|
693 num_children--;
|
meillo@10
|
694 if (WEXITSTATUS(status) != EXIT_SUCCESS)
|
meillo@10
|
695 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS (status));
|
meillo@10
|
696 if (WIFSIGNALED(status))
|
meillo@10
|
697 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG (status));
|
meillo@10
|
698 } else if (pid < 0) {
|
meillo@10
|
699 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
|
meillo@10
|
700 }
|
meillo@10
|
701 }
|
meillo@0
|
702
|
meillo@10
|
703 if ((pid = fork()) == 0) {
|
meillo@10
|
704 deliver(msg);
|
meillo@10
|
705 _exit(EXIT_SUCCESS);
|
meillo@10
|
706 } else if (pid < 0) {
|
meillo@10
|
707 logwrite(LOG_ALERT | LOG_VERBOSE, "could not fork for delivery, id = %s: %s\n", msg->uid, strerror(errno));
|
meillo@10
|
708 } else
|
meillo@10
|
709 num_children++;
|
meillo@10
|
710 } else {
|
meillo@10
|
711 DEBUG(1) debugf("queuing forced by configuration or option.\n");
|
meillo@10
|
712 }
|
meillo@10
|
713 if (popb->flags & POP3_FLAG_DELETE)
|
meillo@10
|
714 pop3_in_dele(popb, info->number);
|
meillo@0
|
715
|
meillo@10
|
716 destroy_message(msg);
|
meillo@10
|
717 } /* if(spool_write(msg, TRUE)) */
|
meillo@10
|
718 } else {
|
meillo@10
|
719 logwrite(LOG_ALERT, "retrieving of message %d failed: %d\n", info->number, popb->error);
|
meillo@10
|
720 }
|
meillo@132
|
721 } else {
|
meillo@132
|
722 /* info->size > max_size */
|
meillo@10
|
723 logwrite(LOG_NOTICE | LOG_VERBOSE, "size of message #%d (%d) > max_size (%d)\n", info->number, info->size, max_size);
|
meillo@10
|
724 if (max_size_delete)
|
meillo@10
|
725 if (popb->flags & POP3_FLAG_DELETE)
|
meillo@10
|
726 pop3_in_dele(popb, info->number);
|
meillo@10
|
727 }
|
meillo@10
|
728 } /* if(do_get_this) ... */
|
meillo@10
|
729 else {
|
meillo@10
|
730 if (popb->flags & POP3_FLAG_UIDL) {
|
meillo@10
|
731 info->is_fetched = TRUE; /* obsolete? */
|
meillo@10
|
732 logwrite(LOG_VERBOSE, "message %d already known\n", info->number);
|
meillo@10
|
733 DEBUG(1) debugf("message %d (uid = %s) not fetched\n", info->number, info->uid);
|
meillo@0
|
734 #if 0
|
meillo@0
|
735 #if DO_WRITE_UIDL_EARLY
|
meillo@10
|
736 write_uidl(popb, user); /* obsolete? */
|
meillo@0
|
737 #endif
|
meillo@0
|
738 #endif
|
meillo@10
|
739 }
|
meillo@10
|
740 }
|
meillo@10
|
741 if ((max_count != 0) && (count >= max_count))
|
meillo@10
|
742 break;
|
meillo@10
|
743 } /* foreach() */
|
meillo@0
|
744 #if DO_WRITE_UIDL_EARLY
|
meillo@0
|
745 #else
|
meillo@10
|
746 if (popb->flags & POP3_FLAG_UIDL)
|
meillo@10
|
747 write_uidl(popb, user);
|
meillo@0
|
748 #endif
|
meillo@10
|
749 } /* if(pop3_in_uidl(popb) ... */
|
meillo@10
|
750 } /* if(pop3_in_list(popb)) */
|
meillo@10
|
751 } /* if(popb->msg_cnt > 0) */
|
meillo@10
|
752 else {
|
meillo@10
|
753 logwrite(LOG_NOTICE | LOG_VERBOSE, "no messages for user %s at %s\n", user, popb->remote_host);
|
meillo@10
|
754 }
|
meillo@10
|
755 ok = TRUE;
|
meillo@10
|
756 }
|
meillo@10
|
757 pop3_in_quit(popb);
|
meillo@10
|
758 } else {
|
meillo@10
|
759 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, popb->remote_host);
|
meillo@10
|
760 }
|
meillo@0
|
761 }
|
meillo@10
|
762 if (!ok) {
|
meillo@10
|
763 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 failed, error = %d\n", popb->error);
|
meillo@10
|
764 }
|
meillo@0
|
765
|
meillo@10
|
766 while (num_children > 0) {
|
meillo@10
|
767 int status;
|
meillo@10
|
768 pid_t pid;
|
meillo@10
|
769 if ((pid = wait(&status)) > 0) {
|
meillo@10
|
770 num_children--;
|
meillo@10
|
771 if (WEXITSTATUS(status) != EXIT_SUCCESS)
|
meillo@10
|
772 logwrite(LOG_WARNING, "delivery process with pid %d returned %d\n", pid, WEXITSTATUS(status));
|
meillo@10
|
773 if (WIFSIGNALED(status))
|
meillo@10
|
774 logwrite(LOG_WARNING, "delivery process with pid %d got signal: %d\n", pid, WTERMSIG(status));
|
meillo@10
|
775 } else {
|
meillo@10
|
776 logwrite(LOG_WARNING, "wait got error: %s\n", strerror(errno));
|
meillo@10
|
777 }
|
meillo@10
|
778 }
|
meillo@0
|
779
|
meillo@10
|
780 return ok;
|
meillo@0
|
781 }
|
meillo@0
|
782
|
meillo@0
|
783 /* function just to log into a pop server,
|
meillo@0
|
784 for pop_before_smtp (or is it smtp_after_pop?)
|
meillo@0
|
785 */
|
meillo@0
|
786
|
meillo@10
|
787 gboolean
|
meillo@10
|
788 pop3_login(gchar * host, gint port, GList * resolve_list, gchar * user, gchar * pass, guint flags)
|
meillo@0
|
789 {
|
meillo@10
|
790 gboolean ok = FALSE;
|
meillo@10
|
791 pop3_base *popb;
|
meillo@0
|
792
|
meillo@10
|
793 signal(SIGCHLD, SIG_IGN);
|
meillo@0
|
794
|
meillo@10
|
795 if ((popb = pop3_in_open(host, port, resolve_list, flags))) {
|
meillo@10
|
796 if (pop3_in_init(popb)) {
|
meillo@10
|
797 if (pop3_in_login(popb, user, pass))
|
meillo@10
|
798 ok = TRUE;
|
meillo@10
|
799 else
|
meillo@10
|
800 logwrite(LOG_ALERT | LOG_VERBOSE, "pop3 login failed for user %s, host = %s\n", user, host);
|
meillo@10
|
801 }
|
meillo@10
|
802 pop3_in_close(popb);
|
meillo@10
|
803 }
|
meillo@10
|
804 return ok;
|
meillo@0
|
805 }
|
meillo@0
|
806
|
meillo@0
|
807 #endif
|