1/*
2 * Copyright (c) 1989 Regents of the University of California.
3 * All rights reserved.  The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#include <popper.h>
8RCSID("$Id$");
9
10int hangup = FALSE ;
11
12static RETSIGTYPE
13catchSIGHUP(int sig)
14{
15    hangup = TRUE ;
16
17    /* This should not be a problem on BSD systems */
18    signal(SIGHUP,  catchSIGHUP);
19    signal(SIGPIPE, catchSIGHUP);
20    SIGRETURN(0);
21}
22
23int     pop_timeout = POP_TIMEOUT;
24
25jmp_buf env;
26
27static RETSIGTYPE
28ring(int sig)
29{
30  longjmp(env,1);
31}
32
33/*
34 * fgets, but with a timeout
35 */
36static char *
37tgets(char *str, int size, FILE *fp, int timeout)
38{
39    char *ret;
40
41    signal(SIGALRM, ring);
42    alarm(timeout);
43    if (setjmp(env)) {
44	alarm(0);
45	signal(SIGALRM, SIG_DFL);
46	return NULL;
47    }
48    ret = fgets(str, size, fp);
49    alarm(0);
50    signal(SIGALRM, SIG_DFL);
51    return ret;
52}
53
54/*
55 *  popper: Handle a Post Office Protocol version 3 session
56 */
57int
58main (int argc, char **argv)
59{
60    POP                 p;
61    state_table     *   s;
62    char                message[MAXLINELEN];
63
64    signal(SIGHUP,  catchSIGHUP);
65    signal(SIGPIPE, catchSIGHUP);
66
67    /*  Start things rolling */
68    pop_init(&p,argc,argv);
69
70    /*  Tell the user that we are listenting */
71    pop_msg(&p,POP_SUCCESS, "POP3 server ready");
72
73    /*  State loop.  The POP server is always in a particular state in
74        which a specific suite of commands can be executed.  The following
75        loop reads a line from the client, gets the command, and processes
76        it in the current context (if allowed) or rejects it.  This continues
77        until the client quits or an error occurs. */
78
79    for (p.CurrentState=auth1;p.CurrentState!=halt&&p.CurrentState!=error;) {
80        if (hangup) {
81            pop_msg(&p, POP_FAILURE, "POP hangup: %s", p.myhost);
82            if (p.CurrentState > auth2 && !pop_updt(&p))
83                pop_msg(&p, POP_FAILURE,
84			"POP mailbox update failed: %s", p.myhost);
85            p.CurrentState = error;
86        } else if (tgets(message, MAXLINELEN, p.input, pop_timeout) == NULL) {
87	    pop_msg(&p, POP_FAILURE, "POP timeout: %s", p.myhost);
88	    if (p.CurrentState > auth2 && !pop_updt(&p))
89                pop_msg(&p,POP_FAILURE,
90			"POP mailbox update failed: %s", p.myhost);
91            p.CurrentState = error;
92        }
93        else {
94            /*  Search for the command in the command/state table */
95            if ((s = pop_get_command(&p,message)) == NULL) continue;
96
97            /*  Call the function associated with this command in
98                the current state */
99            if (s->function) p.CurrentState = s->result[(*s->function)(&p)];
100
101            /*  Otherwise assume NOOP and send an OK message to the client */
102            else {
103                p.CurrentState = s->success_state;
104                pop_msg(&p,POP_SUCCESS,"time passes");
105            }
106        }
107    }
108
109    /*  Say goodbye to the client */
110    pop_msg(&p,POP_SUCCESS,"Pop server at %s signing off.",p.myhost);
111
112    /*  Log the end of activity */
113    pop_log(&p,POP_PRIORITY,
114        "(v%s) Ending request from \"%s\" at %s\n",VERSION,p.client,p.ipaddr);
115
116    /*  Stop logging */
117    closelog();
118
119    return(0);
120}
121