GCC Code Coverage Report


Directory: src/gate/
File: src/gate/net/pop3clients.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 0 164 0.0%
Functions: 0 11 0.0%
Branches: 0 78 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #include "gate/net/pop3clients.h"
30 #include "gate/results.h"
31
32 static gate_result_t write_line(gate_stream_t* pop3stream, gate_string_t const* text)
33 {
34 gate_result_t ret;
35 char const* ptr = gate_string_ptr(text, 0);
36 gate_size_t len = gate_string_length(text);
37 gate_size_t written = 0;
38 ret = gate_stream_write_block(pop3stream, ptr, len, &written);
39 if (GATE_SUCCEEDED(ret))
40 {
41 if (written != len)
42 {
43 ret = GATE_RESULT_INVALIDOUTPUT;
44 }
45 }
46 return ret;
47 }
48
49 static gate_result_t write_line_builder(gate_stream_t* pop3stream, gate_strbuilder_t* builder)
50 {
51 char const* ptr = gate_strbuilder_ptr(builder, 0);
52 gate_size_t len = gate_strbuilder_length(builder);
53 gate_size_t written = 0;
54 gate_result_t ret = gate_stream_write_block(pop3stream, ptr, len, &written);
55 if (GATE_SUCCEEDED(ret))
56 {
57 if (written != len)
58 {
59 ret = GATE_RESULT_INVALIDOUTPUT;
60 }
61 }
62 gate_strbuilder_release(builder);
63 return ret;
64 }
65
66 static gate_result_t read_line(gate_stream_t* pop3stream, gate_string_t* text)
67 {
68 gate_result_t ret = GATE_RESULT_FAILED;
69 gate_strbuilder_t builder = GATE_INIT_EMPTY;
70 char chr = 0;
71 char prev_chr = 0;
72 gate_size_t retrieved = 0;
73
74 do
75 {
76 gate_strbuilder_create(&builder, 12);
77
78 while ((prev_chr != 13) || (chr != 10))
79 {
80 prev_chr = chr;
81 ret = gate_stream_read(pop3stream, &chr, 1, &retrieved);
82 GATE_BREAK_IF_FAILED(ret);
83
84 if (retrieved != 1)
85 {
86 ret = GATE_RESULT_ENDOFSTREAM;
87 break;
88 }
89
90 if (0 == gate_strbuilder_append_chars(&builder, 1, chr))
91 {
92 ret = GATE_RESULT_OUTOFMEMORY;
93 break;
94 }
95 }
96 GATE_BREAK_IF_FAILED(ret);
97
98 if (NULL == gate_strbuilder_to_string(&builder, text))
99 {
100 ret = GATE_RESULT_OUTOFMEMORY;
101 break;
102 }
103
104 /* success case: */
105 ret = GATE_RESULT_OK;
106 } while (0);
107
108 gate_strbuilder_release(&builder);
109 return ret;
110 }
111
112 static gate_string_t const pop3_response_ok = GATE_STRING_INIT_STATIC("+OK");
113 static gate_string_t const pop3_response_nok = GATE_STRING_INIT_STATIC("-ERR");
114
115
116 static gate_result_t read_ok_line(gate_stream_t* pop3stream)
117 {
118 gate_result_t ret;
119 gate_string_t line = GATE_STRING_INIT_EMPTY;
120
121 do
122 {
123 ret = read_line(pop3stream, &line);
124 GATE_BREAK_IF_FAILED(ret);
125
126 if (gate_string_starts_with(&line, &pop3_response_ok))
127 {
128 ret = GATE_RESULT_OK;
129 }
130 else
131 {
132 ret = GATE_RESULT_INVALIDSTATE;
133 }
134 } while (0);
135
136 gate_string_release(&line);
137 return ret;
138 }
139
140
141 gate_result_t gate_pop3stream_init(gate_stream_t* pop3stream)
142 {
143 return read_ok_line(pop3stream);
144 }
145
146 gate_result_t gate_pop3stream_login(gate_stream_t* pop3stream, gate_string_t const* user, gate_string_t const* pass)
147 {
148 gate_result_t ret = GATE_RESULT_FAILED;
149 gate_strbuilder_t builder = GATE_INIT_EMPTY;
150
151 do
152 {
153 /* send USER command */
154 gate_strbuilder_create(&builder, 24);
155 gate_strbuilder_append_cstr(&builder, "USER ");
156 gate_strbuilder_append_string(&builder, user);
157 gate_strbuilder_append_cstr(&builder, "\r\n");
158
159 ret = write_line_builder(pop3stream, &builder);
160 GATE_BREAK_IF_FAILED(ret);
161 gate_strbuilder_release(&builder);
162
163 /* expect OK response */
164 ret = read_ok_line(pop3stream);
165 GATE_BREAK_IF_FAILED(ret);
166
167 /* send PASS command */
168 gate_strbuilder_create(&builder, 24);
169 gate_strbuilder_append_cstr(&builder, "PASS ");
170 gate_strbuilder_append_string(&builder, pass);
171 gate_strbuilder_append_cstr(&builder, "\r\n");
172
173 ret = write_line_builder(pop3stream, &builder);
174 GATE_BREAK_IF_FAILED(ret);
175 gate_strbuilder_release(&builder);
176
177 /* expect OK response */
178 ret = read_ok_line(pop3stream);
179 GATE_BREAK_IF_FAILED(ret);
180 } while (0);
181
182 gate_strbuilder_release(&builder);
183 return ret;
184 }
185
186 static gate_string_t const msg_end_token = GATE_STRING_INIT_STATIC(".\r\n");
187
188 gate_result_t gate_pop3stream_list(gate_stream_t* pop3stream, gate_pop3stream_list_callback_t callback, void* param)
189 {
190 static gate_string_t const list_cmd = GATE_STRING_INIT_STATIC("LIST\r\n");
191 gate_result_t ret = GATE_RESULT_FAILED;
192 gate_bool_t end_msg_reached = false;
193 gate_string_t line = GATE_STRING_INIT_EMPTY;
194 gate_int64_t num;
195 gate_size_t len_parsed;
196 gate_int32_t pop3id;
197 gate_size_t pop3size;
198
199 do
200 {
201 if (!pop3stream || !callback)
202 {
203 ret = GATE_RESULT_INVALIDARG;
204 break;
205 }
206
207 ret = write_line(pop3stream, &list_cmd);
208 GATE_BREAK_IF_FAILED(ret);
209 ret = read_ok_line(pop3stream);
210 GATE_BREAK_IF_FAILED(ret);
211
212 while (!end_msg_reached)
213 {
214 ret = read_line(pop3stream, &line);
215 GATE_BREAK_IF_FAILED(ret);
216
217 if (gate_string_equals(&line, &msg_end_token))
218 {
219 end_msg_reached = true;
220 }
221 else
222 {
223 num = 0;
224 len_parsed = gate_string_parse_int(&line, &num);
225 if (0 == len_parsed)
226 {
227 ret = GATE_RESULT_INVALIDDATA;
228 break;
229 }
230 pop3id = (gate_int32_t)num;
231 gate_string_substr(&line, &line, len_parsed, GATE_STR_NPOS);
232 gate_string_ltrim(&line, &line);
233
234 num = 0;
235 len_parsed = gate_string_parse_int(&line, &num);
236 if (0 == len_parsed)
237 {
238 ret = GATE_RESULT_INVALIDDATA;
239 break;
240 }
241 pop3size = (gate_size_t)num;
242
243 callback(pop3id, pop3size, param);
244 }
245 gate_string_release(&line);
246 }
247 } while (0);
248
249 gate_string_release(&line);
250 return ret;
251 }
252
253 gate_result_t gate_pop3stream_retrieve(gate_stream_t* pop3stream, gate_int32_t id, gate_stream_t* mailoutstream)
254 {
255 gate_result_t ret = GATE_RESULT_FAILED;
256 gate_strbuilder_t builder = GATE_INIT_EMPTY;
257 gate_bool_t end_msg_reached = false;
258 gate_string_t line = GATE_STRING_INIT_EMPTY;
259 static gate_string_t const double_period = GATE_STRING_INIT_STATIC("..");
260
261 do
262 {
263 if (!pop3stream || (id < 0))
264 {
265 ret = GATE_RESULT_INVALIDARG;
266 break;
267 }
268
269 gate_strbuilder_create(&builder, 16);
270 gate_strbuilder_append_cstr(&builder, "RETR ");
271 gate_strbuilder_append_int32(&builder, id);
272 gate_strbuilder_append_cstr(&builder, "\r\n");
273 ret = write_line_builder(pop3stream, &builder);
274 GATE_BREAK_IF_FAILED(ret);
275
276 ret = read_ok_line(pop3stream);
277
278 while (!end_msg_reached)
279 {
280 ret = read_line(pop3stream, &line);
281 GATE_BREAK_IF_FAILED(ret);
282
283 if (gate_string_equals(&line, &msg_end_token))
284 {
285 end_msg_reached = true;
286 }
287 else
288 {
289 if (gate_string_starts_with(&line, &double_period))
290 {
291 gate_string_substr(&line, &line, 1, GATE_STR_NPOS);
292 }
293 ret = gate_stream_print_string(mailoutstream, &line);
294 GATE_BREAK_IF_FAILED(ret);
295 }
296 gate_string_release(&line);
297 }
298
299 } while (0);
300
301 gate_strbuilder_release(&builder);
302 gate_string_release(&line);
303 return ret;
304 }
305
306 gate_result_t gate_pop3stream_delete(gate_stream_t* pop3stream, gate_int32_t id)
307 {
308 gate_result_t ret = GATE_RESULT_FAILED;
309 gate_strbuilder_t builder = GATE_INIT_EMPTY;
310 do
311 {
312 if (!pop3stream || (id < 0))
313 {
314 ret = GATE_RESULT_INVALIDARG;
315 break;
316 }
317
318 gate_strbuilder_create(&builder, 16);
319 gate_strbuilder_append_cstr(&builder, "DELE ");
320 gate_strbuilder_append_int32(&builder, id);
321 gate_strbuilder_append_cstr(&builder, "\r\n");
322 ret = write_line_builder(pop3stream, &builder);
323 GATE_BREAK_IF_FAILED(ret);
324
325 ret = read_ok_line(pop3stream);
326 } while (0);
327
328 gate_strbuilder_release(&builder);
329 return ret;
330 }
331
332 gate_result_t gate_pop3stream_reset(gate_stream_t* pop3stream)
333 {
334 static gate_string_t const rset_cmd = GATE_STRING_INIT_STATIC("RSET\r\n");
335 gate_result_t ret = write_line(pop3stream, &rset_cmd);
336 GATE_RETURN_IF_FAILED(ret);
337 ret = read_ok_line(pop3stream);
338 return ret;
339 }
340
341 gate_result_t gate_pop3stream_quit(gate_stream_t* pop3stream)
342 {
343 static gate_string_t const quit_cmd = GATE_STRING_INIT_STATIC("QUIT\r\n");
344 gate_result_t ret = write_line(pop3stream, &quit_cmd);
345 GATE_RETURN_IF_FAILED(ret);
346 ret = read_ok_line(pop3stream);
347 return ret;
348 }
349