1 /* $OpenBSD: pop_trans.c,v 1.4 2003/05/12 19:28:22 camield Exp $ */
2
3 /*
4 * TRANSACTION state handling.
5 */
6
7 #include <stdio.h>
8 #include <syslog.h>
9
10 #include "params.h"
11 #include "protocol.h"
12 #include "database.h"
13 #include "mailbox.h"
14
pop_trans_quit(char * params)15 static int pop_trans_quit(char *params)
16 {
17 if (params) return POP_ERROR;
18 return POP_STATE;
19 }
20
pop_trans_noop(char * params)21 static int pop_trans_noop(char *params)
22 {
23 if (params) return POP_ERROR;
24 return POP_OK;
25 }
26
pop_trans_stat(char * params)27 static int pop_trans_stat(char *params)
28 {
29 if (params) return POP_ERROR;
30 if (pop_reply("+OK %u %lu", db.visible_count, db.visible_size))
31 return POP_CRASH_NETFAIL;
32 return POP_QUIET;
33 }
34
pop_trans_list_or_uidl_all(int uidl)35 static int pop_trans_list_or_uidl_all(int uidl)
36 {
37 unsigned int number;
38 struct db_message *msg;
39
40 if (pop_reply_ok()) return POP_CRASH_NETFAIL;
41 for (number = 1; number <= db.total_count; number++) {
42 msg = db.array[number - 1];
43 if (msg->flags & MSG_DELETED) continue;
44 if (uidl) {
45 if (pop_reply("%u "
46 "%02x%02x%02x%02x%02x%02x%02x%02x",
47 number,
48 msg->hash[3], msg->hash[2],
49 msg->hash[1], msg->hash[0],
50 msg->hash[7], msg->hash[6],
51 msg->hash[5], msg->hash[4]))
52 return POP_CRASH_NETFAIL;
53 } else
54 if (pop_reply("%u %lu", number, msg->size))
55 return POP_CRASH_NETFAIL;
56 }
57 if (pop_reply_terminate()) return POP_CRASH_NETFAIL;
58 return POP_QUIET;
59 }
60
pop_trans_list_or_uidl(char * params,int uidl)61 static int pop_trans_list_or_uidl(char *params, int uidl)
62 {
63 int number;
64 struct db_message *msg;
65
66 if (!params)
67 return pop_trans_list_or_uidl_all(uidl);
68
69 number = pop_get_int(¶ms);
70 if (number < 1 || number > db.total_count || params)
71 return POP_ERROR;
72 msg = db.array[number - 1];
73 if (msg->flags & MSG_DELETED) return POP_ERROR;
74 if (uidl) {
75 if (pop_reply("+OK %d "
76 "%02x%02x%02x%02x%02x%02x%02x%02x",
77 number,
78 msg->hash[3], msg->hash[2],
79 msg->hash[1], msg->hash[0],
80 msg->hash[7], msg->hash[6],
81 msg->hash[5], msg->hash[4]))
82 return POP_CRASH_NETFAIL;
83 } else
84 if (pop_reply("+OK %d %lu", number, msg->size))
85 return POP_CRASH_NETFAIL;
86 return POP_QUIET;
87 }
88
pop_trans_list(char * params)89 static int pop_trans_list(char *params)
90 {
91 return pop_trans_list_or_uidl(params, 0);
92 }
93
pop_trans_uidl(char * params)94 static int pop_trans_uidl(char *params)
95 {
96 return pop_trans_list_or_uidl(params, 1);
97 }
98
pop_trans_retr(char * params)99 static int pop_trans_retr(char *params)
100 {
101 int number;
102 struct db_message *msg;
103 int event;
104
105 number = pop_get_int(¶ms);
106 if (number < 1 || number > db.total_count || params) return POP_ERROR;
107 msg = db.array[number - 1];
108 if (msg->flags & MSG_DELETED) return POP_ERROR;
109 if ((event = mailbox_get(msg, -1)) != POP_OK) return event;
110 #if POP_SUPPORT_LAST
111 if (number > db.last) db.last = number;
112 #endif
113 return POP_QUIET;
114 }
115
pop_trans_top(char * params)116 static int pop_trans_top(char *params)
117 {
118 int number, lines;
119 struct db_message *msg;
120 int event;
121
122 number = pop_get_int(¶ms);
123 if (number < 1 || number > db.total_count) return POP_ERROR;
124 lines = pop_get_int(¶ms);
125 if (lines < 0 || params) return POP_ERROR;
126 msg = db.array[number - 1];
127 if (msg->flags & MSG_DELETED) return POP_ERROR;
128 if ((event = mailbox_get(msg, lines)) != POP_OK) return event;
129 return POP_QUIET;
130 }
131
pop_trans_dele(char * params)132 static int pop_trans_dele(char *params)
133 {
134 int number;
135 struct db_message *msg;
136
137 number = pop_get_int(¶ms);
138 if (number < 1 || number > db.total_count || params) return POP_ERROR;
139 msg = db.array[number - 1];
140 if (db_delete(msg)) return POP_ERROR;
141 #if POP_SUPPORT_LAST
142 if (number > db.last) db.last = number;
143 #endif
144 return POP_OK;
145 }
146
pop_trans_rset(char * params)147 static int pop_trans_rset(char *params)
148 {
149 struct db_message *msg;
150
151 if (params) return POP_ERROR;
152
153 if ((msg = db.head))
154 do {
155 msg->flags &= ~MSG_DELETED;
156 } while ((msg = msg->next));
157
158 db.visible_count = db.total_count;
159 db.visible_size = db.total_size;
160 db.flags &= ~DB_DIRTY;
161 #if POP_SUPPORT_LAST
162 db.last = 0;
163 #endif
164
165 return POP_OK;
166 }
167
168 #if POP_SUPPORT_LAST
pop_trans_last(char * params)169 static int pop_trans_last(char *params)
170 {
171 if (params) return POP_ERROR;
172 if (pop_reply("+OK %u", db.last)) return POP_CRASH_NETFAIL;
173 return POP_QUIET;
174 }
175 #endif
176
177 static struct pop_command pop_trans_commands[] = {
178 {"QUIT", pop_trans_quit},
179 {"NOOP", pop_trans_noop},
180 {"STAT", pop_trans_stat},
181 {"LIST", pop_trans_list},
182 {"UIDL", pop_trans_uidl},
183 {"RETR", pop_trans_retr},
184 {"TOP", pop_trans_top},
185 {"DELE", pop_trans_dele},
186 {"RSET", pop_trans_rset},
187 #if POP_SUPPORT_LAST
188 {"LAST", pop_trans_last},
189 #endif
190 {NULL, NULL}
191 };
192
db_load(char * spool,char * mailbox)193 static int db_load(char *spool, char *mailbox)
194 {
195 db_init();
196
197 if (mailbox_open(spool, mailbox)) return 1;
198
199 if (db_fix()) {
200 mailbox_close();
201 return 1;
202 }
203
204 return 0;
205 }
206
do_pop_trans(char * spool,char * mailbox)207 int do_pop_trans(char *spool, char *mailbox)
208 {
209 int event;
210
211 if (!pop_sane()) return 1;
212
213 if (db_load(spool, mailbox)) {
214 syslog(SYSLOG_PRI_HI,
215 "Failed or refused to load %s/%s",
216 spool, mailbox);
217 pop_reply_error();
218 return 0;
219 }
220
221 syslog(SYSLOG_PRI_LO, "%u message%s (%lu byte%s) loaded",
222 db.total_count, db.total_count == 1 ? "" : "s",
223 db.total_size, db.total_size == 1 ? "" : "s");
224
225 if (pop_reply_ok())
226 event = POP_CRASH_NETFAIL;
227 else
228 switch ((event = pop_handle_state(pop_trans_commands))) {
229 case POP_STATE:
230 if (mailbox_update()) {
231 if (db.flags & DB_STALE) break;
232 syslog(SYSLOG_PRI_ERROR,
233 "Failed to update %s/%s",
234 spool, mailbox);
235 pop_reply_error();
236 break;
237 }
238
239 syslog(SYSLOG_PRI_LO, "%u (%lu) deleted, %u (%lu) left",
240 db.total_count - db.visible_count,
241 db.total_size - db.visible_size,
242 db.visible_count,
243 db.visible_size);
244 pop_reply_ok();
245 break;
246
247 case POP_CRASH_NETFAIL:
248 syslog(SYSLOG_PRI_LO, "Premature disconnect");
249 break;
250
251 case POP_CRASH_NETTIME:
252 syslog(SYSLOG_PRI_LO, "Connection timed out");
253 }
254
255 if (db.flags & DB_STALE)
256 syslog(SYSLOG_PRI_LO, "Another MUA active, giving up");
257 else
258 if (event == POP_CRASH_SERVER)
259 syslog(SYSLOG_PRI_ERROR,
260 "Server failure accessing %s/%s",
261 spool, mailbox);
262
263 mailbox_close();
264
265 return 0;
266 }
267