1 |
/* this is objects.c, part of the libspopc library sources |
2 |
* copyright © 2002- Benoit Rouits <brouits@free.fr> |
3 |
* released under the terms of the GNU Lesser General Public Licence. |
4 |
* |
5 |
* libspopc offers simple API for a pop3 client. |
6 |
* See RFC 1725 for pop3 specifications. |
7 |
* more information on http://herewe.servebeer.com/libspopc/ |
8 |
* |
9 |
* This library is free software; you can redistribute it and/or |
10 |
* modify it under the terms of the GNU Lesser General Public |
11 |
* License as published by the Free Software Foundation; either |
12 |
* version 2.1 of the License, or (at your option) any later version. |
13 |
* |
14 |
* This library is distributed in the hope that it will be useful, |
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 |
* Lesser General Public License for more details. |
18 |
* |
19 |
* You should have received a copy of the GNU Lesser General Public |
20 |
* License along with this library; if not, write to the Free Software |
21 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 |
*/ |
23 |
|
24 |
#include <stdlib.h> |
25 |
#include <string.h> |
26 |
#include <sys/types.h> |
27 |
|
28 |
#ifdef WIN32 |
29 |
#include <winsock.h> |
30 |
#else |
31 |
#include <sys/socket.h> |
32 |
#include <netdb.h> |
33 |
#endif |
34 |
|
35 |
#include "libspopc.h" |
36 |
|
37 |
/*************************************** |
38 |
* high-level methods for a simple mua * |
39 |
***************************************/ |
40 |
|
41 |
char* popbegin(const char* servername, const char* user, const char* pass, popsession** sp){ |
42 |
/* prepares, connect and get lists of messages stored on pop server */ |
43 |
/* you must give a valid servername, user and pass */ |
44 |
/* returns an error message if a problem occurs, else NULL */ |
45 |
char* resp=NULL; |
46 |
char* err=NULL; |
47 |
char *hostname, *ptr_port; |
48 |
int nport; |
49 |
popsession* s = NULL; |
50 |
|
51 |
if(!(servername && user && pass)){ |
52 |
err=strdup("popbegin: some NULL args !"); |
53 |
goto error; |
54 |
} |
55 |
s=(popsession*)malloc(sizeof(popsession)); |
56 |
if(!s){ |
57 |
err=strdup("popbegin.malloc: failed\n"); |
58 |
goto error; |
59 |
} |
60 |
/* basic default construction */ |
61 |
s->sock=BAD_SOCK; |
62 |
s->connection=NULL; |
63 |
s->server=NULL; |
64 |
s->list=NULL; |
65 |
s->uidl=NULL; |
66 |
s->bytes=-1; |
67 |
s->last=-1; |
68 |
s->num=-1; |
69 |
s->del=0; /* no deletion (by default) at this time */ |
70 |
s->sync=1; /* this is sync'ed at this time (no cnx yet) */ |
71 |
|
72 |
s->server=(struct hostent*)malloc(sizeof(struct hostent)); |
73 |
if(!(s->server)){ |
74 |
err=strdup("popbegin.malloc: failed\n"); |
75 |
goto error; |
76 |
} |
77 |
s->connection=(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in)); |
78 |
if(!(s->connection)){ |
79 |
err=strdup("popbegin.malloc: failed\n"); |
80 |
goto error; |
81 |
} |
82 |
hostname = strdup (servername); |
83 |
if (!hostname) { |
84 |
err=strdup("popbegin.strdup: failed\n"); /* ahem... */ |
85 |
goto error; |
86 |
} |
87 |
ptr_port = strchr (hostname, ':'); |
88 |
if (!ptr_port) |
89 |
nport = 110; |
90 |
else { |
91 |
*ptr_port = 0; |
92 |
nport = (int) strtoul (++ptr_port, NULL, 10); |
93 |
if (!nport) |
94 |
nport = 110; |
95 |
} |
96 |
s->sock=pop3_prepare(hostname,nport,s->connection,s->server); |
97 |
free (hostname); |
98 |
if(s->sock==BAD_SOCK){ |
99 |
err=strdup("popbegin.pop3_prepare: failed\n"); |
100 |
goto error; |
101 |
} |
102 |
resp=pop3_connect(s->sock,s->connection); |
103 |
if(!resp){ |
104 |
err=strdup("popbegin.pop3_connect: failed\n"); |
105 |
goto error; |
106 |
} |
107 |
free(resp); |
108 |
resp=pop3_user(s->sock,user); |
109 |
if((!resp) || pop3_error(resp)){ |
110 |
err=resp?resp:strdup("popbegin.pop3_user: failed\n"); |
111 |
goto error; |
112 |
} |
113 |
free(resp); |
114 |
resp=pop3_pass(s->sock,pass); |
115 |
if((!resp) || pop3_error(resp)){ |
116 |
err=resp?resp:strdup("popbegin.pop3_pass: failed\n"); |
117 |
goto error; |
118 |
} |
119 |
free(resp); |
120 |
resp=pop3_stat(s->sock); |
121 |
if((!resp) || pop3_error(resp)){ |
122 |
err=resp?resp:strdup("popbegin.pop3_stat: failed\n"); |
123 |
goto error; |
124 |
} |
125 |
s->bytes=stat2bytes(resp); |
126 |
s->num=stat2num(resp); |
127 |
s->last=stat2num(resp); /* safe here: we did not delete anything */ |
128 |
free(resp); |
129 |
resp=pop3_list(s->sock,0); |
130 |
if((!resp) || pop3_error(resp)){ |
131 |
err=resp?resp:strdup("popbegin.pop3_list: failed\n"); |
132 |
goto error; |
133 |
} |
134 |
s->list=list2array(resp); |
135 |
free(resp); |
136 |
resp=pop3_uidl(s->sock,0); |
137 |
if((!resp) || pop3_error(resp)){ |
138 |
err=resp?resp:strdup("popbegin.pop3_uidl: failed\n"); |
139 |
goto error; |
140 |
} |
141 |
s->uidl=uidl2array(resp); |
142 |
s->del=0; |
143 |
(*sp)=s; |
144 |
free(resp); |
145 |
return (NULL); |
146 |
|
147 |
error: |
148 |
if (s) { |
149 |
if (s->sock != BAD_SOCK) |
150 |
{ |
151 |
pop3_disconnect (s->sock, s->server); |
152 |
free(s->server); |
153 |
} |
154 |
free (s->connection); |
155 |
free(s); |
156 |
} |
157 |
return (err); |
158 |
} |
159 |
|
160 |
char* popgethead(popsession* session, int id){ |
161 |
/* returns the header of a message id between 1 and last or NULL if bad id or error */ |
162 |
char* resp; |
163 |
char* msg; |
164 |
if(!session){ |
165 |
return(NULL); |
166 |
} |
167 |
if((id > session->last) || (id < 1)){ |
168 |
return(NULL); |
169 |
} |
170 |
resp=pop3_top(session->sock,id,0); /* 0 means only header */ |
171 |
if((!resp) || pop3_error(resp)){ |
172 |
if(resp){ |
173 |
free(resp); |
174 |
} |
175 |
return(NULL); |
176 |
} |
177 |
msg=retr2msg(resp); |
178 |
if(!msg){ |
179 |
msg=resp; |
180 |
}else{ |
181 |
free(resp); |
182 |
} |
183 |
return(msg); |
184 |
} |
185 |
|
186 |
char* popgetmsg(popsession* session, int id){ |
187 |
/* returns a message id between 1 to last or NULL if bad id or error */ |
188 |
char* resp=NULL; |
189 |
char* msg=NULL; |
190 |
|
191 |
if(!session){ |
192 |
return(NULL); |
193 |
} |
194 |
if((id > session->last) || (id < 1)){ |
195 |
return(NULL); |
196 |
} |
197 |
resp=pop3_retr(session->sock,id); |
198 |
if((!resp) || pop3_error(resp)){ |
199 |
free(resp); |
200 |
return(NULL); |
201 |
} |
202 |
msg=retr2msg(resp); |
203 |
if(!msg){ |
204 |
msg=resp; |
205 |
}else{ |
206 |
free(resp); |
207 |
} |
208 |
if(session->del){ |
209 |
popdelmsg(session, id); |
210 |
} |
211 |
return(msg); |
212 |
} |
213 |
|
214 |
int popdelmsg(popsession* session, int id){ |
215 |
/* deletes a message 'id' on pop server */ |
216 |
/* returns -1 if no deletion (server error), 0 else */ |
217 |
/* sets session->sync to 0 if last id unsync-ed , 1 if OK */ |
218 |
char* resp; |
219 |
int ret; |
220 |
if(!session){ |
221 |
return -1; |
222 |
} |
223 |
if((id > session->last) || (id < 1)){ |
224 |
return -1; |
225 |
} |
226 |
/* actualy delete the email */ |
227 |
resp=pop3_dele(session->sock,id); |
228 |
if((!resp) || pop3_error(resp)){ |
229 |
free(resp); |
230 |
return -1; |
231 |
} |
232 |
free(resp); |
233 |
resp=pop3_stat(session->sock); |
234 |
if((!resp) || pop3_error(resp)){ |
235 |
session->sync=0; |
236 |
return -1; |
237 |
} |
238 |
ret = stat2bytes(resp); |
239 |
if (ret < 0) |
240 |
session->sync=0; |
241 |
|
242 |
else |
243 |
session->bytes=ret; |
244 |
ret = stat2num(resp); |
245 |
if (ret < 0) |
246 |
session->sync=0; |
247 |
else |
248 |
session->num=ret; |
249 |
free(resp); |
250 |
ret=poplast(session); /* check actual last id */ |
251 |
if (ret < 0){ |
252 |
session->sync=0; |
253 |
return -1; |
254 |
} |
255 |
session->last=ret; |
256 |
|
257 |
/* no more message of this id*/ |
258 |
session->list[id]=0; |
259 |
free(session->uidl[id]); |
260 |
session->uidl[id]=NULL; |
261 |
session->sync=1; |
262 |
return 0; |
263 |
} |
264 |
|
265 |
int popcancel(popsession* session){ |
266 |
/* cancel all previous deletions on pop server */ |
267 |
/* returns -1 if server error, 0 else */ |
268 |
char* resp; |
269 |
int ret; |
270 |
|
271 |
if(!session){ |
272 |
return(-1); |
273 |
} |
274 |
resp=pop3_rset(session->sock); |
275 |
if((!resp) || pop3_error(resp)){ |
276 |
free(resp); |
277 |
return(-1); |
278 |
} |
279 |
free(resp); |
280 |
resp=pop3_stat(session->sock); |
281 |
if((!resp) || pop3_error(resp)){ |
282 |
session->sync=0; |
283 |
return(-1); |
284 |
} |
285 |
/* sync number of bytes */ |
286 |
ret = stat2bytes(resp); |
287 |
if (ret < 0) |
288 |
session->sync=0; |
289 |
else |
290 |
session->bytes=ret; |
291 |
/* sync number of messages */ |
292 |
ret = stat2num(resp); |
293 |
if (ret < 0) |
294 |
session->sync=0; |
295 |
else |
296 |
session->num=ret; |
297 |
/* sync last mail id */ |
298 |
/* safe to use stat2num here since we cancel */ |
299 |
ret = stat2num(resp); |
300 |
if (ret < 0) |
301 |
session->sync=0; |
302 |
else |
303 |
session->last=ret; |
304 |
free(resp); |
305 |
resp=pop3_list(session->sock,0); |
306 |
if((!resp) || pop3_error(resp)){ |
307 |
session->sync=0; |
308 |
return -1; |
309 |
} |
310 |
freelistarray(session->list); |
311 |
session->list=list2array(resp); |
312 |
free(resp); |
313 |
resp=pop3_uidl(session->sock,0); |
314 |
if((!resp) || pop3_error(resp)){ |
315 |
session->sync=0; |
316 |
return -1; |
317 |
} |
318 |
freeuidlarray(session->uidl); |
319 |
session->uidl=uidl2array(resp); |
320 |
free(resp); |
321 |
session->sync=1; |
322 |
return 0; |
323 |
} |
324 |
|
325 |
void popend(popsession* session){ |
326 |
/* quit and destroys pop session */ |
327 |
int i; |
328 |
char* resp; |
329 |
|
330 |
if(!session) |
331 |
return; |
332 |
resp=pop3_quit(session->sock); |
333 |
free(resp); |
334 |
pop3_disconnect(session->sock, session->server); |
335 |
free(session->server); |
336 |
free(session->connection); |
337 |
free(session->list); |
338 |
for(i=0;i<=session->last;i++){ |
339 |
free(session->uidl[i]); |
340 |
} |
341 |
free(session->uidl); |
342 |
free(session); |
343 |
return; |
344 |
} |
345 |
|
346 |
int popnum(popsession* session){ |
347 |
/* returns the number of current (non-deleted) messages */ |
348 |
char* r=NULL; |
349 |
int n; |
350 |
|
351 |
if(!session) |
352 |
return -1; |
353 |
r=pop3_stat(session->sock); |
354 |
if(pop3_error(r)) { |
355 |
free(r); |
356 |
return -1; /* error (timeout, etc..) */ |
357 |
} |
358 |
n=stat2num(r); |
359 |
free(r); |
360 |
return(n); |
361 |
} |
362 |
|
363 |
int poplast(popsession* session){ |
364 |
/* return the id of the last downloadable (non-deleted) message */ |
365 |
/* thanks to Francesco Gennai <francesco.gennai@isti.cnr.it> */ |
366 |
int i=0; |
367 |
char* lines=NULL; |
368 |
char* p=NULL; |
369 |
|
370 |
if(!session) |
371 |
return -1; |
372 |
lines=pop3_list(session->sock, 0); /* 0 means 'all' */ |
373 |
if(pop3_error(lines)) { |
374 |
free(lines); |
375 |
return -1; /* error (timeout, etc..) */ |
376 |
} |
377 |
p=lines; |
378 |
p=nextline(p); /* skip +OK */ |
379 |
while (p[0]!='.'){ /* dot means list terminated */ |
380 |
i = atoi(p); /* first number is the id */ |
381 |
p=nextline(p); |
382 |
} |
383 |
/* i is now the greatest id */ |
384 |
free(lines); |
385 |
return(i); |
386 |
} |
387 |
|
388 |
int popchkmsg(popsession* session, int id) { |
389 |
/* check if the message 'id' is accessible in the current session */ |
390 |
/* thanks to Francesco Gennai <francesco.gennai@isti.cnr.it> */ |
391 |
if (popmsguid(session, id)) return 1; /* anything but 0 */ |
392 |
return 0; |
393 |
} |
394 |
|
395 |
/* re-synchronize the session object from the server */ |
396 |
int popsync(popsession* session) { |
397 |
char* resp; |
398 |
int ret; |
399 |
|
400 |
if(!session){ |
401 |
return(-1); |
402 |
} |
403 |
resp=pop3_stat(session->sock); |
404 |
if((!resp) || pop3_error(resp)){ |
405 |
session->sync=0; |
406 |
return(-1); |
407 |
} |
408 |
session->bytes=stat2bytes(resp); |
409 |
session->num=stat2num(resp); |
410 |
ret=poplast(session); /* check actual last id */ |
411 |
if (ret < 0){ |
412 |
session->sync=0; |
413 |
return(-1); |
414 |
} |
415 |
session->last=ret; |
416 |
free(resp); |
417 |
resp=pop3_list(session->sock,0); |
418 |
if((!resp) || pop3_error(resp)){ |
419 |
session->sync=0; |
420 |
return(-1); |
421 |
} |
422 |
freelistarray(session->list); |
423 |
session->list=list2array(resp); |
424 |
free(resp); |
425 |
resp=pop3_uidl(session->sock,0); |
426 |
if((!resp) || pop3_error(resp)){ |
427 |
session->sync=0; |
428 |
return(-1); |
429 |
} |
430 |
freeuidlarray(session->uidl); |
431 |
session->uidl=uidl2array(resp); |
432 |
free(resp); |
433 |
session->sync=1; |
434 |
return(0); |
435 |
} |
436 |
|