1 |
/* this is queries.c file, 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://brouits.free.fr/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 |
#ifdef WIN32 |
25 |
#include <winsock.h> |
26 |
#else |
27 |
#include <sys/socket.h> |
28 |
#endif |
29 |
|
30 |
#include <stdlib.h> |
31 |
#include <stdio.h> |
32 |
#include <string.h> |
33 |
|
34 |
#include <sys/time.h> |
35 |
#include <sys/types.h> |
36 |
#ifndef WIN32 |
37 |
#include <unistd.h> |
38 |
#endif |
39 |
|
40 |
#include "libspopc.h" |
41 |
|
42 |
#ifdef USE_SSL |
43 |
|
44 |
int pop3_recv (pop3sock_t sock, char* buf, int len){ |
45 |
return sock->ssl?SSL_read(sock->ssl,buf,len):recv(sock->sock,buf,len,0); |
46 |
} |
47 |
|
48 |
int pop3_send (pop3sock_t sock, char* buf, int len){ |
49 |
return sock->ssl?SSL_write(sock->ssl,buf,len):send(sock->sock,buf,len,0); |
50 |
} |
51 |
|
52 |
#else |
53 |
|
54 |
int pop3_recv (pop3sock_t sock, char* buf, int len){ |
55 |
return recv(sock,buf,len,0); |
56 |
} |
57 |
|
58 |
int pop3_send (pop3sock_t sock, char* buf, int len){ |
59 |
return send(sock,buf,len,0); |
60 |
} |
61 |
|
62 |
#endif |
63 |
|
64 |
char* pop3_query(pop3sock_t sock, const char* query){ |
65 |
/* performs a simple pop query and returns server's <=512 bytes resp */ |
66 |
int r=0; |
67 |
int bytes=0; |
68 |
char* buf=NULL; |
69 |
|
70 |
r=pop3_send(sock,(char *)query,strlen(query)); |
71 |
if(r==-1){ /* send timeout reached */ |
72 |
perror("pop3_query.pop3_send"); |
73 |
return(NULL); |
74 |
} |
75 |
buf=(char*)malloc(POPBUF); /* 512B + EOS */ |
76 |
if(!buf){ |
77 |
perror("pop3_query.malloc"); |
78 |
return(NULL); |
79 |
} |
80 |
do { |
81 |
r=pop3_recv(sock, buf+bytes, POPBUF-bytes-1); |
82 |
if (r>0) |
83 |
bytes+=r; |
84 |
else { /* closed (0) or timeout reached (-1) */ |
85 |
free(buf); |
86 |
return NULL; |
87 |
} |
88 |
} while (bytes < 2 || (buf[bytes-2] != '\r' && buf[bytes-1] != '\n')); |
89 |
buf[bytes]='\0'; |
90 |
return(buf); |
91 |
} |
92 |
|
93 |
char* pop3_user(pop3sock_t sock, const char* name){ |
94 |
/* performs "USER" pop query and returns server's <512 bytes response */ |
95 |
char query[POPBUF]; /* total "USER ****your_name****\n" is <= 512 */ |
96 |
|
97 |
snprintf(query,POPBUF,"USER %s\r\n",name); |
98 |
return(pop3_query(sock,query)); |
99 |
} |
100 |
|
101 |
char* pop3_pass(pop3sock_t sock, const char* pw){ |
102 |
/* performs "PASS" pop query and return server's <=512 bytes response */ |
103 |
char query[POPBUF]; /* total "PASS ****your_pass****\n" is <=512 */ |
104 |
|
105 |
snprintf(query,POPBUF,"PASS %s\r\n",pw); |
106 |
return(pop3_query(sock,query)); |
107 |
} |
108 |
|
109 |
char* pop3_quit(pop3sock_t sock){ |
110 |
/* performs "QUIT" pop query and returns server's <=512 bytes response */ |
111 |
char query[]="QUIT\r\n"; |
112 |
|
113 |
return(pop3_query(sock,query)); |
114 |
} |
115 |
|
116 |
char* pop3_stat(pop3sock_t sock){ |
117 |
/* performs "STAT" pop query and returns server's <=512 bytes response */ |
118 |
char query[]="STAT\r\n"; |
119 |
|
120 |
return(pop3_query(sock,query)); |
121 |
} |
122 |
|
123 |
char* recv_rest(pop3sock_t sock, char* buf, int cursize, int bufsize){ |
124 |
/* recv rest of data through sock, given a cs pre-filled buffer sized of bs. |
125 |
* end of data is assumed when data has a "\r\n.\r\n" string |
126 |
* recv() is TCPBUFLEN bytes stepped, Warning: after calling this function, |
127 |
* buf must never be used again -not even for a free(buf)- since it may be |
128 |
* reallocated. Use the return value instead: |
129 |
* usage example: buf=recv_rest(sock,buf,cs,bs); free(buf); |
130 |
*/ |
131 |
char* ret = NULL; |
132 |
char* cur = NULL; /* current position ready to receive */ |
133 |
int total; /* total received */ |
134 |
if(!buf){ |
135 |
return(NULL); |
136 |
} |
137 |
total = cursize; |
138 |
cur = buf; |
139 |
if(cursize == bufsize){ |
140 |
ret=(char*)realloc(buf,bufsize+1); |
141 |
if(!ret){ |
142 |
perror("recv_rest.realloc"); |
143 |
free(buf); |
144 |
return NULL; |
145 |
} |
146 |
cur = buf = ret; |
147 |
} |
148 |
cur[total]='\0'; |
149 |
while(!dotline(buf)){ /* recv until "\r\n.\r\n" */ |
150 |
if (total >= (bufsize - TCPBUFLEN)){ |
151 |
ret = (char*)realloc(buf, (bufsize *=2) +1); |
152 |
} |
153 |
if(!ret){ |
154 |
perror("recv_rest.realloc"); |
155 |
free(buf); |
156 |
return NULL; |
157 |
} |
158 |
buf = ret; |
159 |
cur = buf + total; |
160 |
/* we use blocking sockets WITH TIMEOUT: no need for select() */ |
161 |
cursize=pop3_recv(sock, cur, TCPBUFLEN); |
162 |
if (cursize <= 0){ /* timeout (-1) or closed (0) */ |
163 |
perror("recv_rest.pop3_recv"); |
164 |
free(buf); |
165 |
return(NULL); |
166 |
} /* else, we got some bytes */ |
167 |
total+=cursize; |
168 |
cur[cursize] = '\0'; |
169 |
/* SUGGEST: we can strdup to a callback here */ |
170 |
} |
171 |
return(buf); |
172 |
} |
173 |
|
174 |
char* pop3_list(pop3sock_t sock, int id){ |
175 |
/* performs a "LIST" pop query and returns server's (long) response */ |
176 |
int r; |
177 |
char query[POPBUF]; /* total query "LIST ID\n" string is <=512 */ |
178 |
char* buf; |
179 |
|
180 |
if(id>0){ |
181 |
snprintf(query,POPBUF,"LIST %d\r\n",id); |
182 |
}else{ |
183 |
snprintf(query,POPBUF,"LIST\r\n"); |
184 |
} |
185 |
r=pop3_send(sock,query,strlen(query)); |
186 |
if(r==-1){ |
187 |
perror("pop3_list.pop3_send"); |
188 |
return(NULL); |
189 |
} |
190 |
/* now prepare a first short 512 bytes recv() */ |
191 |
/* it might be now enough for recv() from "LIST X" */ |
192 |
buf=(char*)malloc(POPBUF); /* 512 chars + '\0' */ |
193 |
if(!buf){ |
194 |
perror("pop3_list.malloc"); |
195 |
return(NULL); |
196 |
} |
197 |
r=pop3_recv(sock,buf,POPBUF-1); |
198 |
if(r <= 0){ /* close (0) or timeout (-1) */ |
199 |
perror("pop3_list.pop3_recv"); |
200 |
free(buf); |
201 |
return(NULL); |
202 |
} /* else, got some bytes */ |
203 |
buf[r]='\0'; |
204 |
if(id>0){/* +OK id size */ |
205 |
return(buf); /* 512 bytes are enough as say RFC 1939 */ |
206 |
} |
207 |
/* else : +OK X messages (YYY octets)\n id size\n... */ |
208 |
if(pop3_error(buf)){ |
209 |
return(buf); |
210 |
} |
211 |
return(recv_rest(sock,buf,r,POPBUF-1)); |
212 |
} |
213 |
|
214 |
char* pop3_retr(pop3sock_t sock, int id){ |
215 |
/* performs a "RETR" pop query and returns server's (long) response */ |
216 |
int r; |
217 |
char query[POPBUF]; |
218 |
char *buf; |
219 |
|
220 |
snprintf(query, POPBUF, "RETR %d\r\n", id); |
221 |
r=pop3_send(sock, query, strlen(query)); |
222 |
if(r==-1){ |
223 |
perror("pop3_retr.pop3_send"); |
224 |
return(NULL); |
225 |
} |
226 |
buf=(char*)malloc(POPBUF);/* 512 chars + '\0' */ |
227 |
if(!buf) { |
228 |
perror("pop3_retr.malloc"); |
229 |
return(NULL); |
230 |
} |
231 |
/* using blocking sockets WITH TIMEOUT: no need for select() */ |
232 |
r=pop3_recv(sock, buf, POPBUF-1); |
233 |
if(r <= 0){ /* timeout (-1) or close (0) */ |
234 |
perror("pop3_retr.pop3_recv"); |
235 |
free(buf); |
236 |
return(NULL); |
237 |
} /* else, got some bytes */ |
238 |
if(pop3_error(buf)){ |
239 |
buf[r] = '\0'; |
240 |
return(buf); /* 512 are enough as say RFC 1939 */ |
241 |
} |
242 |
return(recv_rest(sock, buf, r, POPBUF-1)); |
243 |
} |
244 |
|
245 |
char* pop3_dele(pop3sock_t sock, int id){ |
246 |
/* performs a "DELE" pop query and returns server's <=512 bytes response */ |
247 |
char query[POPBUF]; /* total "DELE X\n" string <=512 */ |
248 |
|
249 |
if(id<=0){ |
250 |
return(NULL); |
251 |
} |
252 |
snprintf(query,POPBUF,"DELE %d\r\n",id); |
253 |
return(pop3_query(sock,query)); |
254 |
} |
255 |
|
256 |
char* pop3_noop(pop3sock_t sock){ |
257 |
/* performs a "NOOP" pop query and returns server's <=512 bytes response */ |
258 |
char query[]="NOOP\r\n"; |
259 |
|
260 |
return(pop3_query(sock,query)); |
261 |
} |
262 |
|
263 |
char* pop3_rset(pop3sock_t sock){ |
264 |
/* performs a "RSET" pop query and returns server's <=512 bytes response */ |
265 |
char query[]="RSET\r\n"; |
266 |
|
267 |
return(pop3_query(sock,query)); |
268 |
} |
269 |
|
270 |
char* pop3_top(pop3sock_t sock, int id, int lines){ |
271 |
/* performs a "TOP" pop query and returns server's (long) response */ |
272 |
int r; |
273 |
char query[POPBUF]; /* total "TOP X Y\n" is <=512 */ |
274 |
char* buf; |
275 |
|
276 |
snprintf(query,POPBUF,"TOP %d %d\r\n",id,lines); |
277 |
r=pop3_send(sock,query,strlen(query)); |
278 |
if(r==-1){ |
279 |
perror("pop3_top.pop3_send"); |
280 |
return(NULL); |
281 |
} |
282 |
/* prepare first recv() of 512 bytes */ |
283 |
buf=(char*)malloc(POPBUF); /* 512 chars + '\0' */ |
284 |
if(!buf){ |
285 |
perror("pop3_top.malloc"); |
286 |
return(NULL); |
287 |
} |
288 |
r=pop3_recv(sock,buf,POPBUF-1); |
289 |
if(r <= 0){ /* timeout (-1) or close (0) */ |
290 |
perror("pop3_top.pop3_recv"); |
291 |
free(buf); |
292 |
return(NULL); |
293 |
} /* else, got some bytes */ |
294 |
buf[r]='\0'; |
295 |
if(pop3_error(buf)){ |
296 |
return(buf); /* 512 bytes are enough as say RFC 1939 */ |
297 |
} |
298 |
return(recv_rest(sock,buf,r,POPBUF-1)); |
299 |
} |
300 |
|
301 |
char* pop3_uidl(pop3sock_t sock, int id){ |
302 |
/* performs a "UIDL" pop query and returns server's (long) response */ |
303 |
int r; |
304 |
char query[POPBUF]; /* total "UIDL X\n" is <=512 */ |
305 |
char* buf; |
306 |
|
307 |
if(id>0){ |
308 |
snprintf(query,POPBUF,"UIDL %d\r\n",id); |
309 |
}else{ |
310 |
snprintf(query,POPBUF,"UIDL\r\n"); |
311 |
} |
312 |
r=pop3_send(sock,query,strlen(query)); |
313 |
if(r==-1){ |
314 |
perror("pop3_uidl.pop3_send"); |
315 |
return(NULL); |
316 |
} |
317 |
/* prepare first 512 bytes for recv() */ |
318 |
/* i hope this is also enough for the 'one line' short response */ |
319 |
buf=(char*)malloc(POPBUF); /* 512 chars + '\0' */ |
320 |
if(!buf){ |
321 |
perror("pop3_uidl.malloc"); |
322 |
return(NULL); |
323 |
} |
324 |
memset(buf,0,POPBUF); |
325 |
r=pop3_recv(sock,buf,POPBUF-1); |
326 |
if (r <= 0){ /* timeout (-1) or close (0) */ |
327 |
perror("pop3_uidl.pop3_recv"); |
328 |
free(buf); |
329 |
return(NULL); |
330 |
} /* else, got some bytes */ |
331 |
buf[r]='\0'; |
332 |
if(id>0){/* +OK id sig */ |
333 |
/* return the short buf, error or not */ |
334 |
return(buf); /* 512 are enough as say RFC 1939 */ |
335 |
} |
336 |
/* else : +OK\n id sig\nid sig\nid sig\n... */ |
337 |
if(pop3_error(buf)){ |
338 |
return(buf); /* hope error msg were <=512 bytes */ |
339 |
} |
340 |
return(recv_rest(sock,buf,r,POPBUF-1)); |
341 |
} |
342 |
|
343 |
char* pop3_apop(pop3sock_t sock, const char* name, const char* digest){ |
344 |
/* performs a "APOP" secure query and returns server's <=512 bytes response */ |
345 |
char query[POPBUF]; /* total "APOP name digest\r\n" is <=512 */ |
346 |
|
347 |
snprintf(query,POPBUF,"APOP %s %s\r\n",name,digest); |
348 |
return(pop3_query(sock,query)); |
349 |
} |
350 |
|