1: /* popsbr.c - POP client subroutines */ 2: 3: /* LINTLIBRARY */ 4: 5: #include "../h/strings.h" 6: #include <stdio.h> 7: #include <signal.h> 8: 9: 10: #define NOTOK (-1) 11: #define OK 0 12: #define DONE 1 13: 14: #define TRM "." 15: #define TRMLEN (sizeof TRM - 1) 16: 17: extern int errno; 18: extern int sys_nerr; 19: extern char *sys_errlist[]; 20: 21: static int poprint = 0; 22: static int pophack = 0; 23: 24: char response[BUFSIZ]; 25: 26: static FILE *input; 27: static FILE *output; 28: 29: /* */ 30: 31: #ifndef RPOP 32: int pop_init (host, user, pass, snoop) 33: #else RPOP 34: int pop_init (host, user, pass, snoop, rpop) 35: int rpop; 36: #endif RPOP 37: char *host, 38: *user, 39: *pass; 40: int snoop; 41: { 42: int fd1, 43: fd2; 44: #ifndef RPOP 45: int rpop = 0; 46: #endif RPOP 47: char buffer[BUFSIZ]; 48: 49: if ((fd1 = client (host, "tcp", "pop", rpop, response)) == NOTOK) 50: return NOTOK; 51: 52: if ((fd2 = dup (fd1)) == NOTOK) { 53: (void) sprintf (response, "unable to dup connection descriptor: %s", 54: errno > 0 && errno < sys_nerr ? sys_errlist[errno] 55: : "unknown error"); 56: (void) close (fd1); 57: return NOTOK; 58: } 59: if (pop_set (fd1, fd2, snoop) == NOTOK) 60: return NOTOK; 61: 62: (void) signal (SIGPIPE, SIG_IGN); 63: 64: switch (getline (response, sizeof response, input)) { 65: case OK: 66: if (poprint) 67: fprintf (stderr, "<--- %s\n", response); 68: if (*response == '+' 69: && command ("USER %s", user) != NOTOK 70: && command ("%s %s", rpop ? "RPOP" : (pophack++, "PASS"), 71: pass) != NOTOK) 72: return OK; 73: if (*response != '+') { 74: (void) strcpy (buffer, response); 75: (void) command ("QUIT"); 76: (void) strcpy (response, buffer); 77: } /* fall */ 78: 79: case NOTOK: 80: case DONE: 81: if (poprint) 82: fprintf (stderr, "%s\n", response); 83: (void) fclose (input); 84: (void) fclose (output); 85: return NOTOK; 86: } 87: /* NOTREACHED */ 88: } 89: 90: /* */ 91: 92: int pop_set (in, out, snoop) 93: int in, 94: out, 95: snoop; 96: { 97: if ((input = fdopen (in, "r")) == NULL 98: || (output = fdopen (out, "w")) == NULL) { 99: (void) strcpy (response, "fdopen failed on connection descriptor"); 100: if (input) 101: (void) fclose (input); 102: else 103: (void) close (in); 104: (void) close (out); 105: return NOTOK; 106: } 107: 108: poprint = snoop; 109: 110: return OK; 111: } 112: 113: 114: int pop_fd (in, out) 115: char *in, 116: *out; 117: { 118: (void) sprintf (in, "%d", fileno (input)); 119: (void) sprintf (out, "%d", fileno (output)); 120: return OK; 121: } 122: 123: /* */ 124: 125: int pop_stat (nmsgs, nbytes) 126: int *nmsgs, 127: *nbytes; 128: { 129: if (command ("STAT") == NOTOK) 130: return NOTOK; 131: 132: *nmsgs = *nbytes = 0; 133: (void) sscanf (response, "+OK %d %d", nmsgs, nbytes); 134: return OK; 135: } 136: 137: 138: #ifndef BPOP 139: int pop_list (msgno, nmsgs, msgs, bytes) 140: #else BPOP 141: int pop_list (msgno, nmsgs, msgs, bytes, ids) 142: int *ids; 143: #endif BPOP 144: int msgno, 145: *nmsgs, 146: *msgs, 147: *bytes; 148: { 149: int i; 150: #ifndef BPOP 151: int *ids = NULL; 152: #endif not BPOP 153: 154: if (msgno) { 155: if (command ("LIST %d", msgno) == NOTOK) 156: return NOTOK; 157: 158: *msgs = *bytes = 0; 159: if (ids) { 160: *ids = 0; 161: (void) sscanf (response, "+OK %d %d %d", msgs, bytes, ids); 162: } 163: else 164: (void) sscanf (response, "+OK %d %d", msgs, bytes); 165: return OK; 166: } 167: 168: if (command ("LIST") == NOTOK) 169: return NOTOK; 170: 171: for (i = 0; i < *nmsgs; i++) 172: switch (multiline ()) { 173: case NOTOK: 174: return NOTOK; 175: case DONE: 176: *nmsgs = ++i; 177: return OK; 178: case OK: 179: *msgs = *bytes = 0; 180: if (ids) { 181: *ids = 0; 182: (void) sscanf (response, "%d %d %d", 183: msgs++, bytes++, ids++); 184: } 185: else 186: (void) sscanf (response, "%d %d", msgs++, bytes++); 187: break; 188: } 189: for (;;) 190: switch (multiline ()) { 191: case NOTOK: 192: return NOTOK; 193: case DONE: 194: return OK; 195: case OK: 196: break; 197: } 198: } 199: 200: /* */ 201: 202: int pop_retr (msgno, action) 203: int msgno, 204: (*action) (); 205: { 206: return traverse (action, "RETR %d", msgno); 207: } 208: 209: 210: /* VARARGS2 */ 211: 212: static int traverse (action, fmt, a, b, c, d) 213: int (*action) (); 214: char *fmt, 215: *a, 216: *b, 217: *c, 218: *d; 219: { 220: char buffer[sizeof response]; 221: 222: if (command (fmt, a, b, c, d) == NOTOK) 223: return NOTOK; 224: (void) strcpy (buffer, response); 225: 226: for (;;) 227: switch (multiline ()) { 228: case NOTOK: 229: return NOTOK; 230: 231: case DONE: 232: (void) strcpy (response, buffer); 233: return OK; 234: 235: case OK: 236: (*action) (response); 237: break; 238: } 239: } 240: 241: /* */ 242: 243: int pop_dele (msgno) 244: int msgno; 245: { 246: return command ("DELE %d", msgno); 247: } 248: 249: 250: int pop_noop () { 251: return command ("NOOP"); 252: } 253: 254: 255: int pop_rset () { 256: return command ("RSET"); 257: } 258: 259: /* */ 260: 261: int pop_top (msgno, lines, action) 262: int msgno, 263: lines, 264: (*action) (); 265: { 266: return traverse (action, "TOP %d %d", msgno, lines); 267: } 268: 269: 270: #ifdef BPOP 271: int pop_xtnd (action, fmt, a, b, c, d) 272: int (*action) (); 273: char *fmt, 274: *a, 275: *b, 276: *c, 277: *d; 278: { 279: char buffer[BUFSIZ]; 280: 281: (void) sprintf (buffer, "XTND %s", fmt); 282: return traverse (action, buffer, a, b, c, d); 283: } 284: #endif BPOP 285: 286: /* */ 287: 288: int pop_quit () { 289: int i; 290: 291: i = command ("QUIT"); 292: (void) pop_done (); 293: 294: return i; 295: } 296: 297: 298: int pop_done () { 299: (void) fclose (input); 300: (void) fclose (output); 301: 302: return OK; 303: } 304: 305: /* */ 306: 307: /* VARARGS1 */ 308: 309: static int command (fmt, a, b, c, d) 310: char *fmt, 311: *a, 312: *b, 313: *c, 314: *d; 315: { 316: char *cp, 317: buffer[BUFSIZ]; 318: 319: (void) sprintf (buffer, fmt, a, b, c, d); 320: if (poprint) 321: if (pophack) { 322: if (cp = index (buffer, ' ')) 323: *cp = NULL; 324: fprintf (stderr, "---> %s ********\n", buffer); 325: if (cp) 326: *cp = ' '; 327: pophack = 0; 328: } 329: else 330: fprintf (stderr, "---> %s\n", buffer); 331: 332: if (putline (buffer, output) == NOTOK) 333: return NOTOK; 334: 335: switch (getline (response, sizeof response, input)) { 336: case OK: 337: if (poprint) 338: fprintf (stderr, "<--- %s\n", response); 339: return (*response == '+' ? OK : NOTOK); 340: 341: case NOTOK: 342: case DONE: 343: if (poprint) 344: fprintf (stderr, "%s\n", response); 345: return NOTOK; 346: } 347: /* NOTREACHED */ 348: } 349: 350: static int multiline () { 351: char buffer[BUFSIZ + TRMLEN]; 352: 353: if (getline (buffer, sizeof buffer, input) != OK) 354: return NOTOK; 355: if (strncmp (buffer, TRM, TRMLEN) == 0) { 356: if (buffer[TRMLEN] == NULL) 357: return DONE; 358: else 359: (void) strcpy (response, buffer + TRMLEN); 360: } 361: else 362: (void) strcpy (response, buffer); 363: 364: return OK; 365: } 366: 367: /* */ 368: 369: static int getline (s, n, iop) 370: char *s; 371: int n; 372: FILE * iop; 373: { 374: int c; 375: char *p; 376: 377: p = s; 378: while (--n > 0 && (c = fgetc (iop)) != EOF) 379: if ((*p++ = c) == '\n') 380: break; 381: if (ferror (iop)) { 382: (void) strcpy (response, "error on connection"); 383: return NOTOK; 384: } 385: if (c == EOF && p == s) { 386: (void) strcpy (response, "connection closed by foreign host"); 387: return DONE; 388: } 389: *p = NULL; 390: if (*--p == '\n') 391: *p = NULL; 392: if (*--p == '\r') 393: *p = NULL; 394: 395: return OK; 396: } 397: 398: 399: static putline (s, iop) 400: char *s; 401: FILE * iop; 402: { 403: (void) fprintf (iop, "%s\r\n", s); 404: (void) fflush (iop); 405: if (ferror (iop)) { 406: (void) strcpy (response, "lost connection"); 407: return NOTOK; 408: } 409: 410: return OK; 411: }