]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/uip/popsbr.c
sbr/mts.c: Delete mmdlm2; use same-valued mmdlm1 instead.
[nmh] / docs / historical / mh-6.8.5 / uip / popsbr.c
1 /* popsbr.c - POP client subroutines */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: popsbr.c,v 2.7 1994/04/19 20:12:14 jromine Exp shettich $";
4 #endif lint
5
6 #if defined(NNTP) && !defined(PSHSBR)
7 #undef NNTP
8 #endif
9
10 /* LINTLIBRARY */
11
12 #include "../h/strings.h"
13 #ifdef NNTP /* building pshsbr.o from popsbr.c */
14 #include "../h/nntp.h"
15 #endif /* NNTP */
16 #include <stdio.h>
17 #include <signal.h>
18
19 #ifndef POPSERVICE
20 #define POPSERVICE "pop"
21 #endif
22
23 #define NOTOK (-1)
24 #define OK 0
25 #define DONE 1
26
27 #define TRM "."
28 #define TRMLEN (sizeof TRM - 1)
29
30 extern int errno;
31 #ifndef BSD44
32 extern int sys_nerr;
33 extern char *sys_errlist[];
34 #endif
35
36 static int poprint = 0;
37 static int pophack = 0;
38
39 char response[BUFSIZ];
40
41 static FILE *input;
42 static FILE *output;
43
44 #ifdef __STDC__
45 static int traverse (int (*)(), const char*, char *, char *, char *, char *);
46 #define targ_t char *
47 #else
48 static int traverse();
49 #define targ_t int
50 #endif
51
52 #if !defined(NNTP) && defined(MPOP)
53 #define command pop_command
54 #define multiline pop_multiline
55 int command(), multiline();
56 #else
57 static int command(), multiline();
58 #endif
59
60 static int getline();
61 static putline();
62
63 #ifdef NNTP
64 #ifdef BPOP /* stupid */
65 static int xtnd_last = -1,
66 xtnd_first = 0;
67 static char xtnd_name[512]; /* INCREDIBLE HACK!! */
68 #endif
69 #endif /* NNTP */
70
71 /* \f */
72
73 #ifndef NNTP
74 #ifdef APOP
75 #include "md5.c"
76
77 static char *pop_auth (user, pass)
78 char *user,
79 *pass;
80 {
81 register char *cp,
82 *lp;
83 register unsigned char *dp;
84 unsigned char *ep,
85 digest[16];
86 MD5_CTX mdContext;
87 static char buffer[BUFSIZ];
88
89 if ((cp = index (response, '<')) == NULL
90 || (lp = index (cp, '>')) == NULL) {
91 (void) sprintf (buffer, "APOP not available: %s", response);
92 (void) strcpy (response, buffer);
93 return NULL;
94 }
95
96 *++lp = NULL;
97 (void) sprintf (buffer, "%s%s", cp, pass);
98
99 MD5Init (&mdContext);
100 MD5Update (&mdContext, (unsigned char *) buffer,
101 (unsigned int) strlen (buffer));
102 MD5Final (digest, &mdContext);
103
104 (void) sprintf (cp = buffer, "%s ", user);
105 cp += strlen (cp);
106 for (ep = (dp = digest) + sizeof digest / sizeof digest[0];
107 dp < ep;
108 cp += 2)
109 (void) sprintf (cp, "%02x", *dp++ & 0xff);
110 *cp = NULL;
111
112 return buffer;
113 }
114 #endif /* APOP */
115 #endif /* !NNTP */
116
117 /* \f */
118
119 #if defined(APOP)
120 int pop_init (host, user, pass, snoop)
121 #else
122 int pop_init (host, user, pass, snoop)
123 #endif
124 char *host,
125 *user,
126 *pass;
127 int snoop;
128 {
129 #ifdef APOP
130 int apop;
131 #else
132 #endif
133 int fd1,
134 fd2;
135 char buffer[BUFSIZ];
136
137 #ifndef NNTP
138 #ifndef KPOP
139 if ((fd1 = client (host, "tcp", POPSERVICE, response)) == NOTOK)
140 #else /* KPOP */
141 (void) sprintf (buffer, "%s/%s", POPSERVICE, "kpop");
142 if ((fd1 = client (host, "tcp", buffer, response)) == NOTOK)
143 #endif
144 #else /* NNTP */
145 if ((fd1 = client (host, "tcp", "nntp", response)) == NOTOK)
146 #endif
147 return NOTOK;
148
149 if ((fd2 = dup (fd1)) == NOTOK) {
150 (void) sprintf (response, "unable to dup connection descriptor: %s",
151 errno > 0 && errno < sys_nerr ? sys_errlist[errno]
152 : "unknown error");
153 (void) close (fd1);
154 return NOTOK;
155 }
156 #ifndef NNTP
157 if (pop_set (fd1, fd2, snoop) == NOTOK)
158 #else /* NNTP */
159 if (pop_set (fd1, fd2, snoop, (char *)0) == NOTOK)
160 #endif /* NNTP */
161 return NOTOK;
162
163 (void) signal (SIGPIPE, SIG_IGN);
164
165 switch (getline (response, sizeof response, input)) {
166 case OK:
167 if (poprint)
168 fprintf (stderr, "<--- %s\n", response);
169 #ifndef NNTP
170 if (*response == '+') {
171 #ifndef KPOP
172 #ifdef APOP
173 if (apop < 0) {
174 char *cp = pop_auth (user, pass);
175
176 if (cp && command ("APOP %s", cp) != NOTOK)
177 return OK;
178 }
179 else
180 #endif /* apop */
181 if (command ("USER %s", user) != NOTOK
182 && command ("%s %s", (pophack++, "PASS"),
183 pass) != NOTOK)
184 return OK;
185 #else /* KPOP */
186 if (command ("USER %s", user) != NOTOK
187 && command ("PASS %s", pass) != NOTOK)
188 return OK;
189 #endif
190 }
191 #else /* NNTP */
192 if (*response < CHAR_ERR) {
193 (void) command ("MODE READER");
194 #ifdef NEWSAUTH
195 if (getenv("NEWSAUTH")) /* special for IDENT protocol */
196 command("MODE IDENTIFY");
197 #endif
198 return OK;
199 }
200 #endif /* NNTP */
201 (void) strcpy (buffer, response);
202 (void) command ("QUIT");
203 (void) strcpy (response, buffer);
204 /* and fall */
205
206 case NOTOK:
207 case DONE:
208 if (poprint)
209 fprintf (stderr, "%s\n", response);
210 (void) fclose (input);
211 (void) fclose (output);
212 return NOTOK;
213 }
214 /* NOTREACHED */
215 }
216 /* \f */
217
218 #ifndef NNTP
219 int pop_set (in, out, snoop)
220 #else /* NNTP */
221 int pop_set (in, out, snoop, myname)
222 char *myname;
223 #endif /* NNTP */
224 int in,
225 out,
226 snoop;
227 {
228 #ifdef NNTP
229 if (myname && *myname)
230 strcpy (xtnd_name, myname); /* interface from bbc to msh */
231
232 #endif /* NNTP */
233 if ((input = fdopen (in, "r")) == NULL
234 || (output = fdopen (out, "w")) == NULL) {
235 (void) strcpy (response, "fdopen failed on connection descriptor");
236 if (input)
237 (void) fclose (input);
238 else
239 (void) close (in);
240 (void) close (out);
241 return NOTOK;
242 }
243
244 poprint = snoop;
245
246 return OK;
247 }
248
249
250 int pop_fd (in, out)
251 char *in,
252 *out;
253 {
254 (void) sprintf (in, "%d", fileno (input));
255 (void) sprintf (out, "%d", fileno (output));
256 return OK;
257 }
258
259 /* \f */
260
261 int pop_stat (nmsgs, nbytes)
262 int *nmsgs,
263 *nbytes;
264 {
265 #ifdef NNTP
266 char **ap;
267 extern char **brkstring();
268 #endif /* NNTP */
269
270 #ifndef NNTP
271 if (command ("STAT") == NOTOK)
272 return NOTOK;
273
274 *nmsgs = *nbytes = 0;
275 (void) sscanf (response, "+OK %d %d", nmsgs, nbytes);
276
277 #else /* NNTP */
278 if (xtnd_last < 0) { /* in msh, xtnd_name is set from myname */
279 if (command("GROUP %s", xtnd_name) == NOTOK)
280 return NOTOK;
281
282 ap = brkstring (response, " ", "\n"); /* "211 nart first last ggg" */
283 xtnd_first = atoi (ap[2]);
284 xtnd_last = atoi (ap[3]);
285 }
286
287 /* nmsgs is not the real nart, but an incredible simuation */
288 if (xtnd_last > 0)
289 *nmsgs = xtnd_last - xtnd_first + 1; /* because of holes... */
290 else
291 *nmsgs = 0;
292 *nbytes = xtnd_first; /* for subtracting offset in msh() */
293 #endif /* NNTP */
294
295 return OK;
296 }
297
298 #ifdef NNTP
299 int pop_exists (action)
300 int (*action) ();
301 {
302 #ifdef XMSGS /* hacked into NNTP 1.5 */
303 if (traverse (action, "XMSGS %d-%d",
304 (targ_t)xtnd_first, (targ_t)xtnd_last, 0, 0) == OK)
305 return OK;
306 #endif
307 if (traverse (action, "LISTGROUP", /* provided by INN 1.4 */
308 0, 0, 0, 0) == OK)
309 return OK;
310 return traverse (action, "XHDR NONAME %d-%d",
311 (targ_t)xtnd_first, (targ_t)xtnd_last, 0, 0);
312 }
313 #endif /* NNTP */
314
315 #ifndef BPOP
316 int pop_list (msgno, nmsgs, msgs, bytes)
317 #else BPOP
318 int pop_list (msgno, nmsgs, msgs, bytes, ids)
319 int *ids;
320 #endif BPOP
321 int msgno,
322 *nmsgs,
323 *msgs,
324 *bytes;
325 {
326 int i;
327 #ifndef BPOP
328 int *ids = NULL;
329 #endif
330
331 if (msgno) {
332 #ifndef NNTP
333 if (command ("LIST %d", msgno) == NOTOK)
334 return NOTOK;
335 *msgs = *bytes = 0;
336 if (ids) {
337 *ids = 0;
338 (void) sscanf (response, "+OK %d %d %d", msgs, bytes, ids);
339 }
340 else
341 (void) sscanf (response, "+OK %d %d", msgs, bytes);
342 #else /* NNTP */
343 *msgs = *bytes = 0;
344 if (command ("STAT %d", msgno) == NOTOK)
345 return NOTOK;
346 if (ids) {
347 *ids = msgno;
348 }
349 #endif /* NNTP */
350 return OK;
351 }
352
353 #ifndef NNTP
354 if (command ("LIST") == NOTOK)
355 return NOTOK;
356
357 for (i = 0; i < *nmsgs; i++)
358 switch (multiline ()) {
359 case NOTOK:
360 return NOTOK;
361 case DONE:
362 *nmsgs = ++i;
363 return OK;
364 case OK:
365 *msgs = *bytes = 0;
366 if (ids) {
367 *ids = 0;
368 (void) sscanf (response, "%d %d %d",
369 msgs++, bytes++, ids++);
370 }
371 else
372 (void) sscanf (response, "%d %d", msgs++, bytes++);
373 break;
374 }
375 for (;;)
376 switch (multiline ()) {
377 case NOTOK:
378 return NOTOK;
379 case DONE:
380 return OK;
381 case OK:
382 break;
383 }
384 #else /* NNTP */
385 return NOTOK;
386 #endif /* NNTP */
387 }
388
389 /* \f */
390
391 int pop_retr (msgno, action)
392 int msgno,
393 (*action) ();
394 {
395 #ifndef NNTP
396 return traverse (action, "RETR %d", (targ_t)msgno, 0, 0, 0);
397 #else /* NNTP */
398 return traverse (action, "ARTICLE %d", (targ_t)msgno, 0, 0, 0);
399 #endif /* NNTP */
400 }
401
402
403 /* VARARGS2 */
404
405 static int traverse (action, fmt, a, b, c, d)
406 int (*action) ();
407 #ifdef __STDC__
408 const char *fmt;
409 #else
410 char *fmt;
411 #endif
412 char *a,
413 *b,
414 *c,
415 *d;
416 {
417 char buffer[sizeof response];
418
419 if (command (fmt, a, b, c, d) == NOTOK)
420 return NOTOK;
421 (void) strcpy (buffer, response);
422
423 for (;;)
424 switch (multiline ()) {
425 case NOTOK:
426 return NOTOK;
427
428 case DONE:
429 (void) strcpy (response, buffer);
430 return OK;
431
432 case OK:
433 (*action) (response);
434 break;
435 }
436 }
437
438 /* \f */
439
440 int pop_dele (msgno)
441 int msgno;
442 {
443 return command ("DELE %d", msgno);
444 }
445
446
447 int pop_noop () {
448 return command ("NOOP");
449 }
450
451
452 #ifndef NNTP
453 #ifdef MPOP
454 int pop_last () {
455 return command ("LAST");
456 }
457 #endif /* MPOP */
458 #endif /* !NNTP */
459
460 int pop_rset () {
461 return command ("RSET");
462 }
463
464 /* \f */
465
466 int pop_top (msgno, lines, action)
467 int msgno,
468 lines,
469 (*action) ();
470 {
471 #ifndef NNTP
472 return traverse (action, "TOP %d %d", (targ_t)msgno, (targ_t)lines, 0, 0);
473 #else /* NNTP */
474 return traverse (action, "HEAD %d", (targ_t)msgno, 0, 0, 0);
475 #endif /* NNTP */
476 }
477
478
479 #ifdef BPOP
480 int pop_xtnd (action, fmt, a, b, c, d)
481 int (*action) ();
482 char *fmt,
483 *a,
484 *b,
485 *c,
486 *d;
487 {
488 char buffer[BUFSIZ];
489 #ifdef NNTP
490 extern char **brkstring();
491 char **ap;
492 #endif /* NNTP */
493
494 #ifndef NNTP
495 (void) sprintf (buffer, "XTND %s", fmt);
496 return traverse (action, buffer, a, b, c, d);
497 #else /* NNTP */
498 sprintf (buffer, fmt, a, b, c, d);
499 ap = brkstring (buffer, " ", "\n"); /* a hack, i know... */
500
501 if (uleq(ap[0], "x-bboards")) { /* XTND "X-BBOARDS group */
502 /* most of these parameters are meaningless under NNTP.
503 * bbc.c was modified to set AKA and LEADERS as appropriate,
504 * the rest are left blank.
505 */
506 return OK;
507 }
508 if (uleq (ap[0], "archive") && ap[1]) {
509 sprintf (xtnd_name, "%s", ap[1]); /* save the name */
510 xtnd_last = 0;
511 xtnd_first = 1; /* setup to fail in pop_stat */
512 return OK;
513 }
514 if (uleq (ap[0], "bboards")) {
515
516 if (ap[1]) { /* XTND "BBOARDS group" */
517 sprintf (xtnd_name, "%s", ap[1]); /* save the name */
518 if (command("GROUP %s", xtnd_name) == NOTOK)
519 return NOTOK;
520
521 strcpy (buffer, response); /* action must ignore extra args */
522 ap = brkstring (response, " ", "\n");/* "211 nart first last g" */
523 xtnd_first = atoi (ap[2]);
524 xtnd_last = atoi (ap[3]);
525
526 (*action) (buffer);
527 return OK;
528
529 } else { /* XTND "BBOARDS" */
530 return traverse (action, "LIST", a, b, c, d);
531 }
532 }
533 return NOTOK; /* unknown XTND command */
534 #endif /* NNTP */
535 }
536 #endif BPOP
537
538 /* \f */
539
540 int pop_quit () {
541 int i;
542
543 i = command ("QUIT");
544 (void) pop_done ();
545
546 return i;
547 }
548
549
550 int pop_done () {
551 (void) fclose (input);
552 (void) fclose (output);
553
554 return OK;
555 }
556
557 /* \f */
558
559 /* VARARGS1 */
560
561 #if defined(MPOP) && !defined(NNTP)
562 int command (fmt, a, b, c, d)
563 #else
564 static int command (fmt, a, b, c, d)
565 #endif
566 char *fmt,
567 *a,
568 *b,
569 *c,
570 *d;
571 {
572 char *cp,
573 buffer[BUFSIZ];
574
575 (void) sprintf (buffer, fmt, a, b, c, d);
576 if (poprint)
577 if (pophack) {
578 if (cp = index (buffer, ' '))
579 *cp = 0;
580 fprintf (stderr, "---> %s ********\n", buffer);
581 if (cp)
582 *cp = ' ';
583 pophack = 0;
584 }
585 else
586 fprintf (stderr, "---> %s\n", buffer);
587
588 if (putline (buffer, output) == NOTOK)
589 return NOTOK;
590
591 switch (getline (response, sizeof response, input)) {
592 case OK:
593 if (poprint)
594 fprintf (stderr, "<--- %s\n", response);
595 #ifndef NNTP
596 return (*response == '+' ? OK : NOTOK);
597 #else /* NNTP */
598 return (*response < CHAR_ERR ? OK : NOTOK);
599 #endif /* NNTP */
600
601 case NOTOK:
602 case DONE:
603 if (poprint)
604 fprintf (stderr, "%s\n", response);
605 return NOTOK;
606 }
607 /* NOTREACHED */
608 }
609
610 #if defined(MPOP) && !defined(NNTP)
611 int multiline () {
612 #else
613 static int multiline () {
614 #endif
615 char buffer[BUFSIZ + TRMLEN];
616
617 if (getline (buffer, sizeof buffer, input) != OK)
618 return NOTOK;
619 #ifdef DEBUG
620 if (poprint)
621 fprintf (stderr, "<--- %s\n", response);
622 #endif DEBUG
623 if (strncmp (buffer, TRM, TRMLEN) == 0) {
624 if (buffer[TRMLEN] == 0)
625 return DONE;
626 else
627 (void) strcpy (response, buffer + TRMLEN);
628 }
629 else
630 (void) strcpy (response, buffer);
631
632 return OK;
633 }
634
635 /* \f */
636
637 static int getline (s, n, iop)
638 char *s;
639 int n;
640 FILE * iop;
641 {
642 int c;
643 char *p;
644
645 p = s;
646 while (--n > 0 && (c = fgetc (iop)) != EOF)
647 if ((*p++ = c) == '\n')
648 break;
649 if (ferror (iop) && c != EOF) {
650 (void) strcpy (response, "error on connection");
651 return NOTOK;
652 }
653 if (c == EOF && p == s) {
654 (void) strcpy (response, "connection closed by foreign host");
655 return DONE;
656 }
657 *p = 0;
658 if (*--p == '\n')
659 *p = 0;
660 if (*--p == '\r')
661 *p = 0;
662
663 return OK;
664 }
665
666
667 static putline (s, iop)
668 char *s;
669 FILE * iop;
670 {
671 (void) fprintf (iop, "%s\r\n", s);
672 (void) fflush (iop);
673 if (ferror (iop)) {
674 (void) strcpy (response, "lost connection");
675 return NOTOK;
676 }
677
678 return OK;
679 }