]> code.citadel.org Git - citadel.git/blob - citadel/serv_pop3.c
* Started fleshing out the POP3 server (will need same code for SMTP sender!)
[citadel.git] / citadel / serv_pop3.c
1 /* $Id$ */
2
3 #include "sysdep.h"
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <fcntl.h>
8 #include <signal.h>
9 #include <pwd.h>
10 #include <errno.h>
11 #include <sys/types.h>
12 #include <sys/time.h>
13 #include <sys/wait.h>
14 #include <string.h>
15 #include <limits.h>
16 #include "citadel.h"
17 #include "server.h"
18 #include <time.h>
19 #include "sysdep_decls.h"
20 #include "citserver.h"
21 #include "support.h"
22 #include "config.h"
23 #include "dynloader.h"
24 #include "room_ops.h"
25 #include "user_ops.h"
26 #include "policy.h"
27 #include "database.h"
28 #include "msgbase.h"
29 #include "tools.h"
30 #include "internet_addressing.h"
31 #include "serv_pop3.h"
32
33
34 long SYM_POP3;
35
36
37 /*
38  * This cleanup function blows away the temporary memory and files used by
39  * the POP3 server.
40  */
41 void pop3_cleanup_function(void) {
42         int i;
43
44         /* Don't do this stuff if this is not a POP3 session! */
45         if (CC->h_command_function != pop3_command_loop) return;
46
47         lprintf(9, "Performing POP3 cleanup hook\n");
48
49         if (POP3->num_msgs > 0) for (i=0; i<POP3->num_msgs; ++i) {
50                 fclose(POP3->msgs[i].temp);
51         }
52         if (POP3->msgs != NULL) phree(POP3->msgs);
53
54         lprintf(9, "Finished POP3 cleanup hook\n");
55 }
56
57
58
59 /*
60  * Here's where our POP3 session begins its happy day.
61  */
62 void pop3_greeting(void) {
63
64         strcpy(CC->cs_clientname, "POP3 session");
65         CC->internal_pgm = 1;
66         CtdlAllocUserData(SYM_POP3, sizeof(struct citpop3));
67         POP3->msgs = NULL;
68         POP3->num_msgs = 0;
69
70         cprintf("+OK Welcome to the Citadel/UX POP3 server at %s\r\n",
71                 config.c_fqdn);
72 }
73
74
75 /*
76  * Specify user name (implements POP3 "USER" command)
77  */
78 void pop3_user(char *argbuf) {
79         char username[256];
80
81         if (CC->logged_in) {
82                 cprintf("-ERR You are already logged in.\r\n");
83                 return;
84         }
85
86         strcpy(username, argbuf);
87         striplt(username);
88
89         lprintf(9, "Trying <%s>\n", username);
90         if (CtdlLoginExistingUser(username) == login_ok) {
91                 cprintf("+OK Password required for %s\r\n", username);
92         }
93         else {
94                 cprintf("-ERR No such user.\r\n");
95         }
96 }
97
98
99
100 /*
101  * Back end for pop3_grab_mailbox()
102  */
103 void pop3_add_message(long msgnum) {
104         FILE *fp;
105         lprintf(9, "in pop3_add_message()\n");
106
107         ++POP3->num_msgs;
108         if (POP3->num_msgs < 2) POP3->msgs = mallok(sizeof(struct pop3msg));
109         else POP3->msgs = reallok(POP3->msgs, 
110                 (POP3->num_msgs * sizeof(struct pop3msg)) ) ;
111         POP3->msgs[POP3->num_msgs-1].msgnum = msgnum;
112         POP3->msgs[POP3->num_msgs-1].deleted = 0;
113         fp = tmpfile();
114         POP3->msgs[POP3->num_msgs-1].temp = fp;
115         CtdlOutputMsg(msgnum, MT_RFC822, 0, 0, fp, 0);
116         POP3->msgs[POP3->num_msgs-1].rfc822_length = ftell(fp);
117 }
118
119
120
121 /*
122  * Open the inbox and read its contents.
123  * (This should be called only once, by pop3_pass(), and returns the number
124  * of messages in the inbox, or -1 for error)
125  */
126 int pop3_grab_mailbox(void) {
127         if (getroom(&CC->quickroom, MAILROOM) != 0) return(-1);
128         CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, pop3_add_message);
129         return(POP3->num_msgs);
130 }
131
132 /*
133  * Authorize with password (implements POP3 "PASS" command)
134  */
135 void pop3_pass(char *argbuf) {
136         char password[256];
137         int msgs;
138
139         strcpy(password, argbuf);
140         striplt(password);
141
142         lprintf(9, "Trying <%s>\n", password);
143         if (CtdlTryPassword(password) == pass_ok) {
144                 msgs = pop3_grab_mailbox();
145                 if (msgs >= 0) {
146                         cprintf("+OK %s is logged in (%d messages)\r\n",
147                                 CC->usersupp.fullname, msgs);
148                         lprintf(9, "POP3 password login successful\n");
149                 }
150                 else {
151                         cprintf("-ERR Can't open your mailbox\r\n");
152                 }
153         }
154         else {
155                 cprintf("-ERR That is NOT the password!  Go away!\r\n");
156         }
157 }
158
159
160
161 /*
162  * list available msgs
163  */
164 void pop3_list(char *argbuf) {
165         cprintf("-ERR oops, not finished\r\n");
166 }
167
168
169
170
171 /* 
172  * Main command loop for POP3 sessions.
173  */
174 void pop3_command_loop(void) {
175         char cmdbuf[256];
176
177         time(&CC->lastcmd);
178         memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
179         if (client_gets(cmdbuf) < 1) {
180                 lprintf(3, "POP3 socket is broken.  Ending session.\r\n");
181                 CC->kill_me = 1;
182                 return;
183         }
184         lprintf(5, "citserver[%3d]: %s\r\n", CC->cs_pid, cmdbuf);
185         while (strlen(cmdbuf) < 5) strcat(cmdbuf, " ");
186
187         if (!strncasecmp(cmdbuf, "NOOP", 4)) {
188                 cprintf("+OK This command successfully did nothing.\r\n");
189         }
190
191         else if (!strncasecmp(cmdbuf, "QUIT", 4)) {
192                 cprintf("+OK Goodbye...\r\n");
193                 CC->kill_me = 1;
194                 return;
195         }
196
197         else if (!strncasecmp(cmdbuf, "USER", 4)) {
198                 pop3_user(&cmdbuf[5]);
199         }
200
201         else if (!strncasecmp(cmdbuf, "PASS", 4)) {
202                 pop3_pass(&cmdbuf[5]);
203         }
204
205         else if (!CC->logged_in) {
206                 cprintf("-ERR Not logged in.\r\n");
207         }
208
209         else if (!strncasecmp(cmdbuf, "LIST", 4)) {
210                 pop3_list(&cmdbuf[5]);
211         }
212
213         else {
214                 cprintf("500 I'm afraid I can't do that, Dave.\r\n");
215         }
216
217 }
218
219
220
221 char *Dynamic_Module_Init(void)
222 {
223         SYM_POP3 = CtdlGetDynamicSymbol();
224         CtdlRegisterServiceHook(POP3_PORT,
225                                 pop3_greeting,
226                                 pop3_command_loop);
227         CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP);
228         return "$Id$";
229 }