Commit | Line | Data |
---|---|---|
237e0016 RS |
1 | /* movemail foo bar -- move file foo to file bar, |
2 | locking file foo the way /bin/mail respects. | |
9fd54390 | 3 | Copyright (C) 1986, 1992 Free Software Foundation, Inc. |
237e0016 RS |
4 | |
5 | This file is part of GNU Emacs. | |
6 | ||
93320c23 JA |
7 | GNU Emacs is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 1, or (at your option) | |
10 | any later version. | |
11 | ||
237e0016 | 12 | GNU Emacs is distributed in the hope that it will be useful, |
93320c23 JA |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
237e0016 | 16 | |
93320c23 JA |
17 | You should have received a copy of the GNU General Public License |
18 | along with GNU Emacs; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
237e0016 | 20 | |
08d0752f RS |
21 | /* Important notice: defining MAIL_USE_FLOCK *will cause loss of mail* |
22 | if you do it on a system that does not normally use flock as its way of | |
23 | interlocking access to inbox files. The setting of MAIL_USE_FLOCK | |
24 | *must agree* with the system's own conventions. | |
25 | It is not a choice that is up to you. | |
26 | ||
27 | So, if your system uses lock files rather than flock, then the only way | |
28 | you can get proper operation is to enable movemail to write lockfiles there. | |
29 | This means you must either give that directory access modes | |
30 | that permit everyone to write lockfiles in it, or you must make movemail | |
31 | a setuid or setgid program. */ | |
32 | ||
237e0016 RS |
33 | /* |
34 | * Modified January, 1986 by Michael R. Gretzinger (Project Athena) | |
35 | * | |
36 | * Added POP (Post Office Protocol) service. When compiled -DPOP | |
37 | * movemail will accept input filename arguments of the form | |
38 | * "po:username". This will cause movemail to open a connection to | |
39 | * a pop server running on $MAILHOST (environment variable). Movemail | |
40 | * must be setuid to root in order to work with POP. | |
41 | * | |
42 | * New module: popmail.c | |
43 | * Modified routines: | |
cfa191ff | 44 | * main - added code within #ifdef MAIL_USE_POP; added setuid (getuid ()) |
237e0016 RS |
45 | * after POP code. |
46 | * New routines in movemail.c: | |
47 | * get_errmsg - return pointer to system error message | |
48 | * | |
49 | */ | |
50 | ||
51 | #include <sys/types.h> | |
52 | #include <sys/stat.h> | |
53 | #include <sys/file.h> | |
54 | #include <errno.h> | |
55 | #define NO_SHORTNAMES /* Tell config not to load remap.h */ | |
56 | #include "../src/config.h" | |
57 | ||
58 | #ifdef USG | |
59 | #include <fcntl.h> | |
60 | #include <unistd.h> | |
4ec9a77a RS |
61 | #ifndef F_OK |
62 | #define F_OK 0 | |
63 | #define X_OK 1 | |
64 | #define W_OK 2 | |
65 | #define R_OK 4 | |
66 | #endif | |
237e0016 RS |
67 | #endif /* USG */ |
68 | ||
69 | #ifdef XENIX | |
70 | #include <sys/locking.h> | |
71 | #endif | |
72 | ||
4293ba7f RS |
73 | #ifdef MAIL_USE_MMDF |
74 | extern int lk_open (), lk_close (); | |
75 | #endif | |
76 | ||
237e0016 RS |
77 | /* Cancel substitutions made by config.h for Emacs. */ |
78 | #undef open | |
79 | #undef read | |
80 | #undef write | |
81 | #undef close | |
82 | ||
e97dd183 | 83 | char *malloc (); |
237e0016 | 84 | char *concat (); |
e97dd183 DM |
85 | char *xmalloc (); |
86 | #ifndef errno | |
237e0016 | 87 | extern int errno; |
e97dd183 | 88 | #endif |
237e0016 RS |
89 | |
90 | /* Nonzero means this is name of a lock file to delete on fatal error. */ | |
91 | char *delete_lockname; | |
92 | ||
93 | main (argc, argv) | |
94 | int argc; | |
95 | char **argv; | |
96 | { | |
97 | char *inname, *outname; | |
98 | int indesc, outdesc; | |
237e0016 RS |
99 | int nread; |
100 | ||
101 | #ifndef MAIL_USE_FLOCK | |
102 | struct stat st; | |
103 | long now; | |
104 | int tem; | |
105 | char *lockname, *p; | |
906ad89d | 106 | char *tempname; |
237e0016 RS |
107 | int desc; |
108 | #endif /* not MAIL_USE_FLOCK */ | |
109 | ||
110 | delete_lockname = 0; | |
111 | ||
112 | if (argc < 3) | |
113 | fatal ("two arguments required"); | |
114 | ||
115 | inname = argv[1]; | |
116 | outname = argv[2]; | |
117 | ||
4293ba7f RS |
118 | #ifdef MAIL_USE_MMDF |
119 | mmdf_init (argv[0]); | |
120 | #endif | |
121 | ||
b1ce62a8 | 122 | /* Check access to output file. */ |
237e0016 RS |
123 | if (access (outname, F_OK) == 0 && access (outname, W_OK) != 0) |
124 | pfatal_with_name (outname); | |
125 | ||
126 | /* Also check that outname's directory is writeable to the real uid. */ | |
127 | { | |
128 | char *buf = (char *) malloc (strlen (outname) + 1); | |
129 | char *p, q; | |
130 | strcpy (buf, outname); | |
131 | p = buf + strlen (buf); | |
132 | while (p > buf && p[-1] != '/') | |
133 | *--p = 0; | |
134 | if (p == buf) | |
135 | *p++ = '.'; | |
136 | if (access (buf, W_OK) != 0) | |
137 | pfatal_with_name (buf); | |
138 | free (buf); | |
139 | } | |
140 | ||
141 | #ifdef MAIL_USE_POP | |
142 | if (!bcmp (inname, "po:", 3)) | |
143 | { | |
144 | int status; char *user; | |
145 | ||
146 | user = (char *) rindex (inname, ':') + 1; | |
147 | status = popmail (user, outname); | |
148 | exit (status); | |
149 | } | |
150 | ||
cfa191ff | 151 | setuid (getuid ()); |
237e0016 RS |
152 | #endif /* MAIL_USE_POP */ |
153 | ||
b1ce62a8 RS |
154 | /* Check access to input file. */ |
155 | if (access (inname, R_OK | W_OK) != 0) | |
156 | pfatal_with_name (inname); | |
157 | ||
4293ba7f | 158 | #ifndef MAIL_USE_MMDF |
237e0016 RS |
159 | #ifndef MAIL_USE_FLOCK |
160 | /* Use a lock file named /usr/spool/mail/$USER.lock: | |
161 | If it exists, the mail file is locked. */ | |
06000e3c RS |
162 | /* Note: this locking mechanism is *required* by the mailer |
163 | (on systems which use it) to prevent loss of mail. | |
164 | ||
165 | On systems that use a lock file, extracting the mail without locking | |
166 | WILL occasionally cause loss of mail due to timing errors! | |
167 | ||
168 | So, if creation of the lock file fails | |
169 | due to access permission on /usr/spool/mail, | |
170 | you simply MUST change the permission | |
171 | and/or make movemail a setgid program | |
172 | so it can create lock files properly. | |
173 | ||
174 | You might also wish to verify that your system is one | |
175 | which uses lock files for this purpose. Some systems use other methods. | |
176 | ||
177 | If your system uses the `flock' system call for mail locking, | |
178 | define MAIL_USE_FLOCK in config.h or the s-*.h file | |
179 | and recompile movemail. If the s- file for your system | |
180 | should define MAIL_USE_FLOCK but does not, send a bug report | |
181 | to bug-gnu-emacs@prep.ai.mit.edu so we can fix it. */ | |
182 | ||
237e0016 | 183 | lockname = concat (inname, ".lock", ""); |
08564963 | 184 | tempname = strcpy (xmalloc (strlen (inname)+1), inname); |
237e0016 RS |
185 | p = tempname + strlen (tempname); |
186 | while (p != tempname && p[-1] != '/') | |
187 | p--; | |
188 | *p = 0; | |
189 | strcpy (p, "EXXXXXX"); | |
190 | mktemp (tempname); | |
cfa191ff | 191 | unlink (tempname); |
237e0016 RS |
192 | |
193 | while (1) | |
194 | { | |
195 | /* Create the lock file, but not under the lock file name. */ | |
196 | /* Give up if cannot do that. */ | |
197 | desc = open (tempname, O_WRONLY | O_CREAT, 0666); | |
198 | if (desc < 0) | |
06000e3c | 199 | pfatal_with_name ("lock file--see source file etc/movemail.c"); |
237e0016 RS |
200 | close (desc); |
201 | ||
202 | tem = link (tempname, lockname); | |
cfa191ff | 203 | unlink (tempname); |
237e0016 RS |
204 | if (tem >= 0) |
205 | break; | |
206 | sleep (1); | |
207 | ||
208 | /* If lock file is a minute old, unlock it. */ | |
209 | if (stat (lockname, &st) >= 0) | |
210 | { | |
211 | now = time (0); | |
212 | if (st.st_ctime < now - 60) | |
cfa191ff | 213 | unlink (lockname); |
237e0016 RS |
214 | } |
215 | } | |
216 | ||
217 | delete_lockname = lockname; | |
218 | #endif /* not MAIL_USE_FLOCK */ | |
219 | ||
220 | #ifdef MAIL_USE_FLOCK | |
221 | indesc = open (inname, O_RDWR); | |
222 | #else /* if not MAIL_USE_FLOCK */ | |
223 | indesc = open (inname, O_RDONLY); | |
224 | #endif /* not MAIL_USE_FLOCK */ | |
4293ba7f RS |
225 | #else /* MAIL_USE_MMDF */ |
226 | indesc = lk_open (inname, O_RDONLY, 0, 0, 10); | |
227 | #endif /* MAIL_USE_MMDF */ | |
228 | ||
237e0016 RS |
229 | if (indesc < 0) |
230 | pfatal_with_name (inname); | |
231 | ||
cfa191ff | 232 | #if defined (BSD) || defined (XENIX) |
237e0016 RS |
233 | /* In case movemail is setuid to root, make sure the user can |
234 | read the output file. */ | |
235 | /* This is desirable for all systems | |
236 | but I don't want to assume all have the umask system call */ | |
237 | umask (umask (0) & 0333); | |
238 | #endif /* BSD or Xenix */ | |
239 | outdesc = open (outname, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
240 | if (outdesc < 0) | |
241 | pfatal_with_name (outname); | |
242 | #ifdef MAIL_USE_FLOCK | |
243 | #ifdef XENIX | |
244 | if (locking (indesc, LK_RLCK, 0L) < 0) pfatal_with_name (inname); | |
245 | #else | |
246 | if (flock (indesc, LOCK_EX) < 0) pfatal_with_name (inname); | |
247 | #endif | |
248 | #endif /* MAIL_USE_FLOCK */ | |
249 | ||
08564963 JB |
250 | { |
251 | char buf[1024]; | |
252 | ||
253 | while (1) | |
254 | { | |
255 | nread = read (indesc, buf, sizeof buf); | |
256 | if (nread != write (outdesc, buf, nread)) | |
257 | { | |
258 | int saved_errno = errno; | |
259 | unlink (outname); | |
260 | errno = saved_errno; | |
261 | pfatal_with_name (outname); | |
262 | } | |
263 | if (nread < sizeof buf) | |
264 | break; | |
265 | } | |
266 | } | |
237e0016 RS |
267 | |
268 | #ifdef BSD | |
cfa191ff RS |
269 | if (fsync (outdesc) < 0) |
270 | pfatal_and_delete (outname); | |
237e0016 RS |
271 | #endif |
272 | ||
273 | /* Check to make sure no errors before we zap the inbox. */ | |
274 | if (close (outdesc) != 0) | |
cfa191ff | 275 | pfatal_and_delete (outname); |
237e0016 RS |
276 | |
277 | #ifdef MAIL_USE_FLOCK | |
cfa191ff | 278 | #if defined (STRIDE) || defined (XENIX) |
237e0016 | 279 | /* Stride, xenix have file locking, but no ftruncate. This mess will do. */ |
cfa191ff | 280 | close (open (inname, O_CREAT | O_TRUNC | O_RDWR, 0666)); |
237e0016 | 281 | #else |
cfa191ff | 282 | ftruncate (indesc, 0L); |
237e0016 RS |
283 | #endif /* STRIDE or XENIX */ |
284 | #endif /* MAIL_USE_FLOCK */ | |
4293ba7f RS |
285 | |
286 | #ifdef MAIL_USE_MMDF | |
287 | lk_close (indesc, 0, 0, 0); | |
288 | #else | |
237e0016 | 289 | close (indesc); |
4293ba7f | 290 | #endif |
237e0016 RS |
291 | |
292 | #ifndef MAIL_USE_FLOCK | |
293 | /* Delete the input file; if we can't, at least get rid of its contents. */ | |
e97dd183 DM |
294 | #ifdef MAIL_UNLINK_SPOOL |
295 | /* This is generally bad to do, because it destroys the permissions | |
296 | that were set on the file. Better to just empty the file. */ | |
297 | if (unlink (inname) < 0 && errno != ENOENT) | |
298 | #endif /* MAIL_UNLINK_SPOOL */ | |
299 | creat (inname, 0600); | |
4293ba7f RS |
300 | #ifndef MAIL_USE_MMDF |
301 | unlink (lockname); | |
302 | #endif /* not MAIL_USE_MMDF */ | |
237e0016 RS |
303 | #endif /* not MAIL_USE_FLOCK */ |
304 | exit (0); | |
305 | } | |
306 | \f | |
307 | /* Print error message and exit. */ | |
308 | ||
309 | fatal (s1, s2) | |
310 | char *s1, *s2; | |
311 | { | |
312 | if (delete_lockname) | |
313 | unlink (delete_lockname); | |
314 | error (s1, s2); | |
315 | exit (1); | |
316 | } | |
317 | ||
318 | /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
319 | ||
b1ce62a8 RS |
320 | error (s1, s2, s3) |
321 | char *s1, *s2, *s3; | |
237e0016 RS |
322 | { |
323 | printf ("movemail: "); | |
b1ce62a8 | 324 | printf (s1, s2, s3); |
237e0016 RS |
325 | printf ("\n"); |
326 | } | |
327 | ||
328 | pfatal_with_name (name) | |
329 | char *name; | |
330 | { | |
331 | extern int errno, sys_nerr; | |
332 | extern char *sys_errlist[]; | |
333 | char *s; | |
334 | ||
335 | if (errno < sys_nerr) | |
336 | s = concat ("", sys_errlist[errno], " for %s"); | |
337 | else | |
338 | s = "cannot open %s"; | |
339 | fatal (s, name); | |
340 | } | |
341 | ||
cfa191ff RS |
342 | pfatal_and_delete (name) |
343 | char *name; | |
344 | { | |
345 | extern int errno, sys_nerr; | |
346 | extern char *sys_errlist[]; | |
347 | char *s; | |
348 | ||
349 | if (errno < sys_nerr) | |
350 | s = concat ("", sys_errlist[errno], " for %s"); | |
351 | else | |
352 | s = "cannot open %s"; | |
353 | ||
354 | unlink (name); | |
355 | fatal (s, name); | |
356 | } | |
357 | ||
237e0016 RS |
358 | /* Return a newly-allocated string whose contents concatenate those of s1, s2, s3. */ |
359 | ||
360 | char * | |
361 | concat (s1, s2, s3) | |
362 | char *s1, *s2, *s3; | |
363 | { | |
364 | int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); | |
365 | char *result = (char *) xmalloc (len1 + len2 + len3 + 1); | |
366 | ||
367 | strcpy (result, s1); | |
368 | strcpy (result + len1, s2); | |
369 | strcpy (result + len1 + len2, s3); | |
370 | *(result + len1 + len2 + len3) = 0; | |
371 | ||
372 | return result; | |
373 | } | |
374 | ||
375 | /* Like malloc but get fatal error if memory is exhausted. */ | |
376 | ||
e97dd183 | 377 | char * |
237e0016 | 378 | xmalloc (size) |
e97dd183 | 379 | unsigned size; |
237e0016 | 380 | { |
e97dd183 | 381 | char *result = malloc (size); |
237e0016 RS |
382 | if (!result) |
383 | fatal ("virtual memory exhausted", 0); | |
384 | return result; | |
385 | } | |
386 | \f | |
387 | /* This is the guts of the interface to the Post Office Protocol. */ | |
388 | ||
389 | #ifdef MAIL_USE_POP | |
390 | ||
391 | #include <sys/socket.h> | |
392 | #include <netinet/in.h> | |
393 | #include <netdb.h> | |
394 | #include <stdio.h> | |
395 | ||
396 | #ifdef USG | |
397 | #include <fcntl.h> | |
398 | /* Cancel substitutions made by config.h for Emacs. */ | |
399 | #undef open | |
400 | #undef read | |
401 | #undef write | |
402 | #undef close | |
403 | #endif /* USG */ | |
404 | ||
405 | #define NOTOK (-1) | |
406 | #define OK 0 | |
407 | #define DONE 1 | |
408 | ||
409 | char *progname; | |
410 | FILE *sfi; | |
411 | FILE *sfo; | |
412 | char Errmsg[80]; | |
413 | ||
414 | static int debug = 0; | |
415 | ||
b1ce62a8 RS |
416 | char *get_errmsg (); |
417 | char *getenv (); | |
418 | int mbx_write (); | |
419 | ||
420 | popmail (user, outfile) | |
421 | char *user; | |
422 | char *outfile; | |
237e0016 | 423 | { |
b1ce62a8 RS |
424 | char *host; |
425 | int nmsgs, nbytes; | |
426 | char response[128]; | |
427 | register int i; | |
428 | int mbfi; | |
429 | FILE *mbf; | |
430 | ||
431 | host = getenv ("MAILHOST"); | |
432 | if (host == NULL) | |
433 | { | |
434 | fatal ("no MAILHOST defined"); | |
237e0016 RS |
435 | } |
436 | ||
b1ce62a8 RS |
437 | if (pop_init (host) == NOTOK) |
438 | { | |
cfa191ff | 439 | fatal (Errmsg); |
237e0016 RS |
440 | } |
441 | ||
b1ce62a8 RS |
442 | if (getline (response, sizeof response, sfi) != OK) |
443 | { | |
cfa191ff | 444 | fatal (response); |
237e0016 RS |
445 | } |
446 | ||
cfa191ff | 447 | if (pop_command ("USER %s", user) == NOTOK |
b1ce62a8 RS |
448 | || pop_command ("RPOP %s", user) == NOTOK) |
449 | { | |
b1ce62a8 | 450 | pop_command ("QUIT"); |
cfa191ff | 451 | fatal (Errmsg); |
237e0016 RS |
452 | } |
453 | ||
b1ce62a8 RS |
454 | if (pop_stat (&nmsgs, &nbytes) == NOTOK) |
455 | { | |
b1ce62a8 | 456 | pop_command ("QUIT"); |
cfa191ff | 457 | fatal (Errmsg); |
237e0016 RS |
458 | } |
459 | ||
b1ce62a8 RS |
460 | if (!nmsgs) |
461 | { | |
462 | pop_command ("QUIT"); | |
463 | return 0; | |
464 | } | |
465 | ||
466 | mbfi = open (outfile, O_WRONLY | O_CREAT | O_EXCL, 0666); | |
467 | if (mbfi < 0) | |
468 | { | |
469 | pop_command ("QUIT"); | |
cfa191ff | 470 | pfatal_and_delete (outfile); |
b1ce62a8 RS |
471 | } |
472 | fchown (mbfi, getuid (), -1); | |
473 | ||
474 | if ((mbf = fdopen (mbfi, "w")) == NULL) | |
475 | { | |
476 | pop_command ("QUIT"); | |
cfa191ff | 477 | pfatal_and_delete (outfile); |
b1ce62a8 RS |
478 | } |
479 | ||
480 | for (i = 1; i <= nmsgs; i++) | |
481 | { | |
482 | mbx_delimit_begin (mbf); | |
483 | if (pop_retr (i, mbx_write, mbf) != OK) | |
484 | { | |
b1ce62a8 RS |
485 | pop_command ("QUIT"); |
486 | close (mbfi); | |
cfa191ff RS |
487 | unlink (outfile); |
488 | fatal (Errmsg); | |
237e0016 | 489 | } |
b1ce62a8 RS |
490 | mbx_delimit_end (mbf); |
491 | fflush (mbf); | |
237e0016 RS |
492 | } |
493 | ||
cfa191ff RS |
494 | if (fsync (mbfi) < 0) |
495 | { | |
496 | pop_command ("QUIT"); | |
497 | pfatal_and_delete (outfile); | |
498 | } | |
499 | ||
500 | if (close (mbfi) == -1) | |
501 | { | |
502 | pop_command ("QUIT"); | |
503 | pfatal_and_delete (outfile); | |
504 | } | |
505 | ||
b1ce62a8 RS |
506 | for (i = 1; i <= nmsgs; i++) |
507 | { | |
508 | if (pop_command ("DELE %d", i) == NOTOK) | |
509 | { | |
cfa191ff | 510 | /* Better to ignore this failure. */ |
237e0016 RS |
511 | } |
512 | } | |
513 | ||
b1ce62a8 | 514 | pop_command ("QUIT"); |
cfa191ff | 515 | return (0); |
237e0016 RS |
516 | } |
517 | ||
b1ce62a8 RS |
518 | pop_init (host) |
519 | char *host; | |
237e0016 | 520 | { |
b1ce62a8 RS |
521 | register struct hostent *hp; |
522 | register struct servent *sp; | |
523 | int lport = IPPORT_RESERVED - 1; | |
524 | struct sockaddr_in sin; | |
525 | register int s; | |
526 | ||
527 | hp = gethostbyname (host); | |
528 | if (hp == NULL) | |
529 | { | |
530 | sprintf (Errmsg, "MAILHOST unknown: %s", host); | |
531 | return NOTOK; | |
237e0016 RS |
532 | } |
533 | ||
b1ce62a8 RS |
534 | sp = getservbyname ("pop", "tcp"); |
535 | if (sp == 0) | |
536 | { | |
537 | strcpy (Errmsg, "tcp/pop: unknown service"); | |
538 | return NOTOK; | |
237e0016 RS |
539 | } |
540 | ||
b1ce62a8 RS |
541 | sin.sin_family = hp->h_addrtype; |
542 | bcopy (hp->h_addr, (char *)&sin.sin_addr, hp->h_length); | |
543 | sin.sin_port = sp->s_port; | |
544 | s = rresvport (&lport); | |
545 | if (s < 0) | |
546 | { | |
547 | sprintf (Errmsg, "error creating socket: %s", get_errmsg ()); | |
548 | return NOTOK; | |
237e0016 RS |
549 | } |
550 | ||
b1ce62a8 RS |
551 | if (connect (s, (char *)&sin, sizeof sin) < 0) |
552 | { | |
553 | sprintf (Errmsg, "error during connect: %s", get_errmsg ()); | |
554 | close (s); | |
555 | return NOTOK; | |
237e0016 RS |
556 | } |
557 | ||
b1ce62a8 RS |
558 | sfi = fdopen (s, "r"); |
559 | sfo = fdopen (s, "w"); | |
560 | if (sfi == NULL || sfo == NULL) | |
561 | { | |
562 | sprintf (Errmsg, "error in fdopen: %s", get_errmsg ()); | |
563 | close (s); | |
564 | return NOTOK; | |
237e0016 RS |
565 | } |
566 | ||
b1ce62a8 | 567 | return OK; |
237e0016 RS |
568 | } |
569 | ||
b1ce62a8 RS |
570 | pop_command (fmt, a, b, c, d) |
571 | char *fmt; | |
237e0016 | 572 | { |
b1ce62a8 RS |
573 | char buf[128]; |
574 | char errmsg[64]; | |
237e0016 | 575 | |
b1ce62a8 | 576 | sprintf (buf, fmt, a, b, c, d); |
237e0016 | 577 | |
b1ce62a8 RS |
578 | if (debug) fprintf (stderr, "---> %s\n", buf); |
579 | if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK; | |
237e0016 | 580 | |
b1ce62a8 RS |
581 | if (getline (buf, sizeof buf, sfi) != OK) |
582 | { | |
583 | strcpy (Errmsg, buf); | |
584 | return NOTOK; | |
237e0016 RS |
585 | } |
586 | ||
cfa191ff RS |
587 | if (debug) |
588 | fprintf (stderr, "<--- %s\n", buf); | |
b1ce62a8 RS |
589 | if (*buf != '+') |
590 | { | |
591 | strcpy (Errmsg, buf); | |
592 | return NOTOK; | |
593 | } | |
594 | else | |
595 | { | |
596 | return OK; | |
237e0016 RS |
597 | } |
598 | } | |
599 | ||
600 | ||
b1ce62a8 RS |
601 | pop_stat (nmsgs, nbytes) |
602 | int *nmsgs, *nbytes; | |
237e0016 | 603 | { |
b1ce62a8 | 604 | char buf[128]; |
237e0016 | 605 | |
cfa191ff RS |
606 | if (debug) |
607 | fprintf (stderr, "---> STAT\n"); | |
608 | if (putline ("STAT", Errmsg, sfo) == NOTOK) | |
609 | return NOTOK; | |
237e0016 | 610 | |
b1ce62a8 RS |
611 | if (getline (buf, sizeof buf, sfi) != OK) |
612 | { | |
613 | strcpy (Errmsg, buf); | |
614 | return NOTOK; | |
237e0016 RS |
615 | } |
616 | ||
b1ce62a8 RS |
617 | if (debug) fprintf (stderr, "<--- %s\n", buf); |
618 | if (*buf != '+') | |
619 | { | |
620 | strcpy (Errmsg, buf); | |
621 | return NOTOK; | |
622 | } | |
623 | else | |
624 | { | |
625 | sscanf (buf, "+OK %d %d", nmsgs, nbytes); | |
626 | return OK; | |
237e0016 RS |
627 | } |
628 | } | |
629 | ||
b1ce62a8 RS |
630 | pop_retr (msgno, action, arg) |
631 | int (*action)(); | |
237e0016 | 632 | { |
b1ce62a8 | 633 | char buf[128]; |
237e0016 | 634 | |
b1ce62a8 RS |
635 | sprintf (buf, "RETR %d", msgno); |
636 | if (debug) fprintf (stderr, "%s\n", buf); | |
637 | if (putline (buf, Errmsg, sfo) == NOTOK) return NOTOK; | |
237e0016 | 638 | |
b1ce62a8 RS |
639 | if (getline (buf, sizeof buf, sfi) != OK) |
640 | { | |
641 | strcpy (Errmsg, buf); | |
642 | return NOTOK; | |
237e0016 RS |
643 | } |
644 | ||
b1ce62a8 RS |
645 | while (1) |
646 | { | |
647 | switch (multiline (buf, sizeof buf, sfi)) | |
648 | { | |
237e0016 | 649 | case OK: |
b1ce62a8 RS |
650 | (*action)(buf, arg); |
651 | break; | |
237e0016 | 652 | case DONE: |
b1ce62a8 | 653 | return OK; |
237e0016 | 654 | case NOTOK: |
b1ce62a8 RS |
655 | strcpy (Errmsg, buf); |
656 | return NOTOK; | |
237e0016 RS |
657 | } |
658 | } | |
659 | } | |
660 | ||
b1ce62a8 RS |
661 | getline (buf, n, f) |
662 | char *buf; | |
663 | register int n; | |
664 | FILE *f; | |
237e0016 | 665 | { |
b1ce62a8 RS |
666 | register char *p; |
667 | int c; | |
237e0016 | 668 | |
b1ce62a8 RS |
669 | p = buf; |
670 | while (--n > 0 && (c = fgetc (f)) != EOF) | |
671 | if ((*p++ = c) == '\n') break; | |
237e0016 | 672 | |
b1ce62a8 RS |
673 | if (ferror (f)) |
674 | { | |
675 | strcpy (buf, "error on connection"); | |
676 | return NOTOK; | |
237e0016 RS |
677 | } |
678 | ||
b1ce62a8 RS |
679 | if (c == EOF && p == buf) |
680 | { | |
681 | strcpy (buf, "connection closed by foreign host"); | |
682 | return DONE; | |
237e0016 RS |
683 | } |
684 | ||
b1ce62a8 RS |
685 | *p = NULL; |
686 | if (*--p == '\n') *p = NULL; | |
687 | if (*--p == '\r') *p = NULL; | |
688 | return OK; | |
237e0016 RS |
689 | } |
690 | ||
b1ce62a8 RS |
691 | multiline (buf, n, f) |
692 | char *buf; | |
693 | register int n; | |
694 | FILE *f; | |
237e0016 | 695 | { |
cfa191ff RS |
696 | if (getline (buf, n, f) != OK) |
697 | return NOTOK; | |
b1ce62a8 RS |
698 | if (*buf == '.') |
699 | { | |
700 | if (*(buf+1) == NULL) | |
cfa191ff | 701 | return DONE; |
b1ce62a8 | 702 | else |
cfa191ff | 703 | strcpy (buf, buf+1); |
237e0016 | 704 | } |
b1ce62a8 | 705 | return OK; |
237e0016 RS |
706 | } |
707 | ||
708 | char * | |
b1ce62a8 | 709 | get_errmsg () |
237e0016 | 710 | { |
b1ce62a8 RS |
711 | extern int errno, sys_nerr; |
712 | extern char *sys_errlist[]; | |
713 | char *s; | |
714 | ||
715 | if (errno < sys_nerr) | |
716 | s = sys_errlist[errno]; | |
717 | else | |
718 | s = "unknown error"; | |
719 | return (s); | |
237e0016 RS |
720 | } |
721 | ||
b1ce62a8 RS |
722 | putline (buf, err, f) |
723 | char *buf; | |
724 | char *err; | |
725 | FILE *f; | |
237e0016 | 726 | { |
b1ce62a8 RS |
727 | fprintf (f, "%s\r\n", buf); |
728 | fflush (f); | |
729 | if (ferror (f)) | |
730 | { | |
731 | strcpy (err, "lost connection"); | |
732 | return NOTOK; | |
237e0016 | 733 | } |
b1ce62a8 | 734 | return OK; |
237e0016 RS |
735 | } |
736 | ||
b1ce62a8 RS |
737 | mbx_write (line, mbf) |
738 | char *line; | |
739 | FILE *mbf; | |
237e0016 | 740 | { |
b1ce62a8 RS |
741 | fputs (line, mbf); |
742 | fputc (0x0a, mbf); | |
237e0016 RS |
743 | } |
744 | ||
b1ce62a8 RS |
745 | mbx_delimit_begin (mbf) |
746 | FILE *mbf; | |
237e0016 | 747 | { |
70da2b86 | 748 | fputs ("\f\n0, unseen,,\n", mbf); |
237e0016 RS |
749 | } |
750 | ||
b1ce62a8 RS |
751 | mbx_delimit_end (mbf) |
752 | FILE *mbf; | |
237e0016 | 753 | { |
b1ce62a8 | 754 | putc ('\037', mbf); |
237e0016 RS |
755 | } |
756 | ||
757 | #endif /* MAIL_USE_POP */ |