OSDN Git Service

separate submit function's file and add test.
[bbk/bchan.git] / src / submitutil.c
1 /*
2  * submitutil.c
3  *
4  * Copyright (c) 2010 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include        <basic.h>
28 #include        <bstdio.h>
29 #include        <bstring.h>
30
31 #include    "submitutil.h"
32 #include    "sjisstring.h"
33 #include    "parselib.h"
34
35 #define MAKEHEADER_ERR_LEN(dest, dest_len, src, len) \
36    err = sjstring_appendasciistring(dest, dest_len, src, len); \
37    if(err < 0){ \
38      return err; \
39    }
40
41 #define MAKEHEADER_ERR(dest, dest_len, src) MAKEHEADER_ERR_LEN(dest, dest_len, (src), strlen((src)))
42
43 #define MAKEHEADER_NUM_ERR(dest, dest_len, num) \
44    err = sjstring_appendUWstring(dest, dest_len, num); \
45    if(err < 0){ \
46      return err; \
47    }
48
49 EXPORT W submitutil_makeheaderstring(UB *host, W host_len, UB *board, W board_len, UB *thread, W thread_len, W content_length, UB **header, W *header_len)
50 {
51         UB *str = NULL;
52         W len = 0;
53         W err;
54
55         MAKEHEADER_ERR(&str, &len, "POST /test/bbs.cgi HTTP/1.1\r\n");
56         MAKEHEADER_ERR(&str, &len, "Host: ");
57         MAKEHEADER_ERR_LEN(&str, &len, host, host_len);
58         MAKEHEADER_ERR(&str, &len, "\r\n");
59         MAKEHEADER_ERR(&str, &len, "Accept: */*\r\n");
60         MAKEHEADER_ERR(&str, &len, "Referer: http://");
61         MAKEHEADER_ERR_LEN(&str, &len, host, host_len);
62         MAKEHEADER_ERR(&str, &len, "/test/read.cgi/");
63         MAKEHEADER_ERR_LEN(&str, &len, board, board_len);
64         MAKEHEADER_ERR(&str, &len, "/");
65         MAKEHEADER_ERR_LEN(&str, &len, thread, thread_len);
66         MAKEHEADER_ERR(&str, &len, "/\r\n");
67         MAKEHEADER_ERR(&str, &len, "Content-Length: ");
68         MAKEHEADER_NUM_ERR(&str, &len, content_length);
69         MAKEHEADER_ERR(&str, &len, "\r\n");
70         MAKEHEADER_ERR(&str, &len, "Content-Type: application/x-www-form-urlencoded\r\n");
71         MAKEHEADER_ERR(&str, &len, "Accept-Language: ja\r\nUser-Agent: Monazilla/1.00 (bchan/0.01)\r\nConnection: close\r\n\r\n");
72
73         *header = str;
74         *header_len = len;
75
76         return 0;
77 }
78
79 EXPORT submitutil_poststatus_t submitutil_checkresponse(UB *body, W len)
80 {
81         W cmp;
82         UB *ptr, *title_last, *found;
83         UB title_true[] = {0x82, 0xdc, 0x82, 0xb5, 0x82, 0xbd, '\0'};
84         UB title_error[] = {0x82, 0x64, 0x82, 0x71, 0x82, 0x71, '\0'};
85         UB title_cookie[] = {0x8a, 0x6d, 0x94, 0x46, '\0'};
86         UB title_ocha[] = {0x82, 0xa8, 0x92, 0x83, '\0'};
87
88         ptr = body;
89         for (;;) {
90                 ptr = strstr(ptr, "<!--");
91                 if (ptr == NULL) {
92                         break;
93                 }
94                 ptr++;
95                 for (;ptr < body + len;ptr++) {
96                         if (*ptr != ' ') {
97                                 break;
98                         }
99                 }
100                 cmp = strcmp(ptr, "2ch_X:true");
101                 if (cmp == 0) {
102                         return submitutil_poststatus_true;
103                 }
104                 cmp = strcmp(ptr, "2ch_X:false");
105                 if (cmp == 0) {
106                         return submitutil_poststatus_false;
107                 }
108                 cmp = strcmp(ptr, "2ch_X:error");
109                 if (cmp == 0) {
110                         return submitutil_poststatus_error;
111                 }
112                 cmp = strcmp(ptr, "2ch_X:check");
113                 if (cmp == 0) {
114                         return submitutil_poststatus_check;
115                 }
116                 cmp = strcmp(ptr, "2ch_X:cookie");
117                 if (cmp == 0) {
118                         return submitutil_poststatus_cookie;
119                 }
120         }
121
122         for (ptr = body;ptr < body + len; ptr++) {
123                 if (*ptr == '<') {
124                         cmp = strncasecmp(ptr, "<title>", 7);
125                         if (cmp != 0) {
126                                 continue;
127                         }
128                         ptr += 7;
129                         title_last = strstr(ptr, "</");
130                         if (title_last == NULL) {
131                                 return submitutil_poststatus_notfound;
132                         }
133                         found = strstr(ptr, title_true);
134                         if ((found != NULL)&&(found < title_last)) {
135                                 return submitutil_poststatus_true;
136                         }
137                         found = strstr(ptr, title_error);
138                         if ((found != NULL)&&(found < title_last)) {
139                                 return submitutil_poststatus_error;
140                         }
141                         found = strstr(ptr, title_cookie);
142                         if ((found != NULL)&&(found < title_last)) {
143                                 return submitutil_poststatus_cookie;
144                         }
145                         found = strstr(ptr, title_ocha);
146                         if ((found != NULL)&&(found < title_last)) {
147                                 return submitutil_poststatus_error;
148                         }
149                 }
150         }
151
152         return submitutil_poststatus_notfound;
153 }
154
155 #ifdef BCHAN_CONFIG_DEBUG
156 EXPORT VOID submitutil_poststatus_debugprint(submitutil_poststatus_t status)
157 {
158         switch (status) {
159         case submitutil_poststatus_notfound:
160                 printf("submitutil_poststatus_notfound\n");
161                 break;
162         case submitutil_poststatus_true:
163                 printf("submitutil_poststatus_true\n");
164                 break;
165         case submitutil_poststatus_false:
166                 printf("submitutil_poststatus_false\n");
167                 break;
168         case submitutil_poststatus_error:
169                 printf("submitutil_poststatus_error\n");
170                 break;
171         case submitutil_poststatus_check:
172                 printf("submitutil_poststatus_check\n");
173                 break;
174         case submitutil_poststatus_cookie:
175                 printf("submitutil_poststatus_cookie\n");
176                 break;
177         }
178 }
179 #endif
180
181 LOCAL W submitutil_appendstring_chref_before_urlencode(UB **dest, W *dlen, UB *src, W slen)
182 {
183         charreferparser_t parser;
184         charreferparser_result_t result;
185         UB *amp, *rem, ch_b;
186         W i, rem_len, ch_w, err;
187
188         rem = src;
189         rem_len = slen;
190
191         for (;;) {
192                 amp = sjstring_searchchar(rem, rem_len, '&');
193                 if (amp == NULL) {
194                         return sjstring_appendurlencodestring(dest, dlen, rem, rem_len);
195                 }
196                 err = sjstring_appendurlencodestring(dest, dlen, rem, amp - rem);
197                 if (err < 0) {
198                         return err;
199                 }
200
201                 rem_len -= amp - rem;
202
203                 err = charreferparser_initialize(&parser);
204                 if (err < 0) {
205                         return err;
206                 }
207                 for (i = 0; i < rem_len; i++) {
208                         result = charreferparser_parsechar(&parser, amp[i]);
209                         if (result == CHARREFERPARSER_RESULT_DETERMINE) {
210                                 ch_w = charreferparser_getcharnumber(&parser);
211                                 if ((ch_w >= 0)&&(ch_w < 256)) {
212                                         ch_b = ch_w & 0xff;
213                                         if (ch_b == 0x0a) { /* need more check ? */
214                                                 UB ch_b2 = 0x0d;
215                                                 err = sjstring_appendurlencodestring(dest, dlen, &ch_b2, 1);
216                                                 if (err < 0) {
217                                                         return err;
218                                                 }
219                                         }
220                                         err = sjstring_appendurlencodestring(dest, dlen, &ch_b, 1);
221                                         if (err < 0) {
222                                                 return err;
223                                         }
224                                 } else {
225                                         err = sjstring_appendurlencodestring(dest, dlen, amp, i+1);
226                                         if (err < 0) {
227                                                 return err;
228                                         }
229                                 }
230                                 i++;
231                                 break;
232                         }
233                         if (result == CHARREFERPARSER_RESULT_INVALID) {
234                                 break;
235                         }
236                 }
237                 charreferparser_finalize(&parser);
238
239                 rem_len -= i;
240                 rem = amp + i;
241
242                 if (rem_len <= 0) {
243                         break;
244                 }
245         }
246
247         return 0;
248 }
249
250 EXPORT W submitutil_makenextrequestbody(UB *prev_body, W prev_body_len, UB **next_body, W *next_len)
251 {
252         UB *ptr;
253         UB *newbody = NULL;
254         UB *name = NULL, *value = NULL;
255         W name_len = 0, value_len = 0;
256         W newbody_len = 0;
257         W err;
258         Bool first = True;
259
260         for (ptr = prev_body; ptr < prev_body + prev_body_len;) {
261                 ptr = strstr(ptr, "<input ");
262                 if (ptr == NULL) {
263                         break;
264                 }
265                 name = NULL;
266                 value = NULL;
267                 name_len = 0;
268                 value_len = 0;
269                 for (;ptr < prev_body + prev_body_len;) {
270                         for (;ptr < prev_body + prev_body_len;ptr++) {
271                                 if (*ptr != ' ') {
272                                         break;
273                                 }
274                         }
275                         if (*ptr == '>') {
276                                 if ((name == NULL)||(name_len == 0)) {
277                                         break;
278                                 }
279                                 if (first != True) {
280                                         err = sjstring_appendasciistring(&newbody, &newbody_len, "&", 1);
281                                         if (err < 0) {
282                                                 return err;
283                                         }
284                                 }
285                                 first = False;
286                                 err = sjstring_appendasciistring(&newbody, &newbody_len, name, name_len);
287                                 if (err < 0) {
288                                         return err;
289                                 }
290                                 sjstring_appendasciistring(&newbody, &newbody_len, "=", 1);
291                                 if (err < 0) {
292                                         return err;
293                                 }
294                                 err = submitutil_appendstring_chref_before_urlencode(&newbody, &newbody_len, value, value_len);
295                                 if (err < 0) {
296                                         return err;
297                                 }
298                                 break;
299                         }
300                         /* check attribute */
301                         if (strncasecmp(ptr, "name=\"", 6) == 0) {
302                                 ptr += 6;
303                                 name = ptr;
304                                 for (;ptr < prev_body + prev_body_len;ptr++) {
305                                         if (*ptr == '"') {
306                                                 break;
307                                         }
308                                 }
309                                 name_len = ptr - name;
310                                 ptr++;
311                         } else if (strncasecmp(ptr, "name=", 5) == 0) {
312                                 ptr += 5;
313                                 name = ptr;
314                                 for (;ptr < prev_body + prev_body_len;ptr++) {
315                                         if ((*ptr == ' ')||(*ptr == '>')) {
316                                                 break;
317                                         }
318                                 }
319                                 name_len = ptr - name;
320                         } else if (strncasecmp(ptr, "value=\"", 7) == 0) {
321                                 ptr += 7;
322                                 value = ptr;
323                                 for (;ptr < prev_body + prev_body_len;ptr++) {
324                                         if (*ptr == '"') {
325                                                 break;
326                                         }
327                                 }
328                                 value_len = ptr - value;
329                                 ptr++;
330                         } else if (strncasecmp(ptr, "value=", 6) == 0) {
331                                 ptr += 6;
332                                 value = ptr;
333                                 for (;ptr < prev_body + prev_body_len;ptr++) {
334                                         if ((*ptr == ' ')||(*ptr == '>')) {
335                                                 break;
336                                         }
337                                 }
338                                 value_len = ptr - value;
339                         } else {
340                                 /* skip attribute */
341                                 for (;ptr < prev_body + prev_body_len;ptr++) {
342                                         if (*ptr == ' ') {
343                                                 break;
344                                         }
345                                 }
346                         }
347                 }
348         }
349
350         *next_body = newbody;
351         *next_len = newbody_len;
352
353         return 0;
354 }
355
356 LOCAL W submitutil_makecookieheader(UB **str, W *len, UB *prev_header, W prev_header_len)
357 {
358         UB *ptr, *start;
359         W cookie_len, err;
360         Bool first = True;
361
362         for (ptr = prev_header; ptr < prev_header + prev_header_len;) {
363                 ptr = strstr(ptr, "Set-Cookie:");
364                 if (ptr == NULL) {
365                         break;
366                 }
367                 ptr += 11;
368                 for (;ptr < prev_header + prev_header_len; ptr++) {
369                         if (*ptr != ' ') {
370                                 break;
371                         }
372                 }
373                 start = ptr;
374                 for (;ptr < prev_header + prev_header_len; ptr++) {
375                         if (*ptr == ';') {
376                                 break;
377                         }
378                 }
379                 cookie_len = ptr + 1 - start;
380                 if (first == True) {
381                         MAKEHEADER_ERR(str, len, "Cookie: ");
382                         first = False;
383                 } else {
384                         MAKEHEADER_ERR(str, len, " ");
385                 }
386                 MAKEHEADER_ERR_LEN(str, len, start, cookie_len);
387         }
388
389         if (first == False) {
390                 MAKEHEADER_ERR(str, len, "\r\n");
391         }
392
393         return 0;
394 }
395
396 EXPORT W submitutil_makenextheader(UB *host, W host_len, UB *board, W board_len, UB *thread, W thread_len, W content_length, UB *prev_header, W prev_header_len, UB **header, W *header_len)
397 {
398         UB *str = NULL;
399         W len = 0;
400         W err;
401
402         MAKEHEADER_ERR(&str, &len, "POST /test/bbs.cgi HTTP/1.1\r\n");
403         MAKEHEADER_ERR(&str, &len, "Host: ");
404         MAKEHEADER_ERR_LEN(&str, &len, host, host_len);
405         MAKEHEADER_ERR(&str, &len, "\r\n");
406         MAKEHEADER_ERR(&str, &len, "Accept: */*\r\n");
407         MAKEHEADER_ERR(&str, &len, "Referer: http://");
408         MAKEHEADER_ERR_LEN(&str, &len, host, host_len);
409         MAKEHEADER_ERR(&str, &len, "/test/read.cgi/");
410         MAKEHEADER_ERR_LEN(&str, &len, board, board_len);
411         MAKEHEADER_ERR(&str, &len, "/");
412         MAKEHEADER_ERR_LEN(&str, &len, thread, thread_len);
413         MAKEHEADER_ERR(&str, &len, "/\r\n");
414         MAKEHEADER_ERR(&str, &len, "Content-Length: ");
415         MAKEHEADER_NUM_ERR(&str, &len, content_length);
416         MAKEHEADER_ERR(&str, &len, "\r\n");
417         err = submitutil_makecookieheader(&str, &len, prev_header, prev_header_len);
418         if (err < 0) {
419                 return err;
420         }
421         MAKEHEADER_ERR(&str, &len, "Content-Type: application/x-www-form-urlencoded\r\n");
422         MAKEHEADER_ERR(&str, &len, "Accept-Language: ja\r\nUser-Agent: Monazilla/1.00\r\nConnection: close\r\n\r\n");
423
424         *header = str;
425         *header_len = len;
426
427         return 0;
428 }