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