Kannel: Open Source WAP and SMS gateway  svn-r5335
test_mime.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * test_mime.c: A simple program for testing the mime parser
59  *
60  * We add carriage returs to the source, so that output of some editors are
61  * acceptable and remove them from component files, in case someone likes to
62  * compile them (come on, this is only a test program).
63  * We panic on errors, so that this function can be used by a shell script
64  * for testing purposes.
65  *
66  * By Aarno Syvänen for Wiral Ltd
67  */
68 
69 #include <stdio.h>
70 
71 #include "gwlib/gwlib.h"
72 #include "gw/wap_push_pap_mime.h"
73 
74 static void prepend_crlf(Octstr **os)
75 {
76  octstr_insert(*os, octstr_imm("\r\n"), 0);
77 }
78 
79 static void append_crlf(Octstr *os)
80 {
81  octstr_append(os, octstr_imm("\r\n"));
82 }
83 
84 static void add_crs(Octstr *os)
85 {
86  long i;
87  Octstr *nos;
88 
89  if (os == NULL)
90  return;
91 
92  nos = octstr_format("%c", '\r');
93  i = 0;
94  while (i < octstr_len(os)) {
95  if (octstr_get_char(os, i) == '\n') {
96  octstr_insert(os, nos, i);
97  ++i;
98  }
99  ++i;
100  }
101 
102  octstr_destroy(nos);
103 }
104 
105 static void remove_crs(Octstr *os)
106 {
107  long i;
108 
109  if (os == NULL)
110  return;
111 
112  i = 0;
113  while (i < octstr_len(os)) {
114  if (octstr_get_char(os, i) == '\r') {
115  octstr_delete(os, i, 1);
116  --i;
117  }
118  ++i;
119  }
120 }
121 
122 static int skip_tail(Octstr **os, int delimiter)
123 {
124  long delimiter_pos;
125 
126  if ((delimiter_pos = octstr_search_char(*os, delimiter, 0)) == -1)
127  return 0;
128 
129  octstr_delete(*os, delimiter_pos, octstr_len(*os) - delimiter_pos);
130 
131  return 1;
132 }
133 
134 static void help(void)
135 {
136  info(0, "Usage: test_mime [options] source_file");
137  info(0, "Parse source file into component parts.");
138  info(0, "Source file has the following format:");
139  info(0, " boundary=<mime boundary>;");
140  info(0, " content=<mime content>;");
141  info(0, "Content headers are added into the content_file. This file has");
142  info(0, "following format:");
143  info(0, " headers=<content_headers>;");
144  info(0, " content=<push-content>;");
145  info(0, "And options are");
146  info(0, " -h");
147  info(0, "print this info");
148  info(0, " -d filename");
149  info(0, "store push data to file filename. Default test/data.txt");
150  info(0, " -c filename");
151  info(0, "store push control message to file filename. Default");
152  info(0, " test/pap.txt");
153  info(0, " -s");
154  info(0, "write push control message and push data to standard output");
155  info(0, "Default write it to the file.");
156 }
157 
158 int main(int argc, char **argv)
159 {
160  Octstr *mime_content,
161  *pap_content,
162  *push_data,
163  *rdf_content,
164  *boundary,
165  *push_content_file = NULL,
166  *this_header,
167  *pap_osname,
168  *data_osname;
169  List *content_headers,
170  *source_parts;
171  char *pap_content_file,
172  *push_data_file,
173  *rdf_content_file;
174  int ret,
175  std_out,
176  opt,
177  d_file,
178  c_file;
179  FILE *fp1,
180  *fp2,
181  *fp3;
182 
183  gwlib_init();
184  std_out = 0;
185  d_file = 0;
186  c_file = 0;
187  data_osname = NULL;
188  pap_osname = NULL;
189 
190  while ((opt = getopt(argc, argv, "hd:sc:")) != EOF) {
191  switch(opt) {
192  case 'h':
193  help();
194  exit(1);
195  break;
196 
197  case 'd':
198  d_file = 1;
199  data_osname = octstr_create(optarg);
200  break;
201 
202  case 'c':
203  c_file = 1;
204  pap_osname = octstr_create(optarg);
205  break;
206 
207  case 's':
208  std_out = 1;
209  break;
210 
211  case '?':
212  default:
213  error(0, "Invalid option %c", opt);
214  help();
215  panic(0, "Stopping");
216  break;
217  }
218  }
219 
220  if (optind >= argc) {
221  help();
222  panic(0, "missing arguments, stopping");
223  }
224 
225  if (!c_file)
226  pap_content_file = "test/pap.txt";
227  else
228  pap_content_file = octstr_get_cstr(pap_osname);
229  if (!d_file)
230  push_data_file = "test/data.txt";
231  else
232  push_data_file = octstr_get_cstr(data_osname);
233  rdf_content_file = "test/rdf.txt";
234 
235  mime_content = octstr_read_file(argv[optind]);
236  if (mime_content == NULL) {
237  octstr_destroy(mime_content);
238  error(0, "No MIME source");
239  panic(0, "Stopping");
240  }
241 
242  source_parts = octstr_split(mime_content, octstr_imm("content="));
243  if (gwlist_len(source_parts) == 1) { /* a hack to circumvent a bug */
244  error(0, "Badly formatted source:");
245  octstr_destroy(mime_content);
246  gwlist_destroy(source_parts, octstr_destroy_item);
247  panic(0, "Stopping");
248  }
249 
250  boundary = gwlist_extract_first(source_parts);
251  octstr_delete(boundary, 0, octstr_len(octstr_imm("boundary=")));
252  if (skip_tail(&boundary, ';') == 0) {
253  error(0, "Cannot determine boundary, no delimiter; possible");
254  octstr_dump(boundary, 0);
255  goto no_parse;
256  }
257 
258  octstr_destroy(mime_content);
259  mime_content = gwlist_extract_first(source_parts);
260  if (skip_tail(&mime_content, ';') == 0){
261  error(0, "Cannot determine mime content, no delimiter");
262  octstr_dump(mime_content, 0);
263  goto no_parse;
264  }
265  prepend_crlf(&mime_content);
266  add_crs(mime_content);
267  append_crlf(mime_content);
268 
269  ret = mime_parse(boundary, mime_content, &pap_content, &push_data,
270  &content_headers, &rdf_content);
271  if (ret == 0) {
272  error(0, "Mime_parse returned 0, cannot continue");
273  goto error;
274  }
275 
276  remove_crs(pap_content);
277  if (!std_out) {
278  fp1 = fopen(pap_content_file, "a");
279  if (fp1 == NULL) {
280  error(0, "Cannot open the file for pap control message");
281  goto error;
282  }
283  octstr_print(fp1, pap_content);
284  debug("test.mime", 0, "pap control message appended to the file");
285  fclose(fp1);
286  } else {
287  debug("test.mime", 0, "pap control message was");
288  octstr_dump(pap_content, 0);
289  }
290 
292  if (!std_out) {
293  fp2 = fopen(push_data_file, "a");
294  if (fp2 == NULL) {
295  error(0, "Cannot open the push data file");
296  goto error;
297  }
298  push_content_file = octstr_create("");
299  octstr_append(push_content_file, octstr_imm("headers="));
300  while (gwlist_len(content_headers) > 0) {
301  octstr_append(push_content_file,
302  this_header = gwlist_extract_first(content_headers));
303  octstr_format_append(push_content_file, "%c", ' ');
304  octstr_destroy(this_header);
305  }
306  octstr_append(push_content_file, octstr_imm(";\n"));
307  octstr_append(push_content_file, octstr_imm("content="));
308  octstr_append(push_content_file, push_data);
309  octstr_append(push_content_file, octstr_imm(";\n"));
310  octstr_print(fp2, push_content_file);
311  debug("test.mime", 0, "push content appended to the file");
312  fclose(fp2);
313  } else {
314  debug("test.mime", 0, "Content headers were");
315  http_header_dump(content_headers);
316  debug("test.mime", 0, "And push content itself");
318  }
319 
320  if (rdf_content != NULL)
321  remove_crs(rdf_content);
322  if (!std_out && rdf_content != NULL) {
323  fp3 = NULL;
324  if (rdf_content != NULL) {
325  fp3 = fopen(rdf_content_file, "a");
326  if (fp3 == NULL) {
327  error(0, "Cannot open the rdf file");
328  goto cerror;
329  }
330  octstr_print(fp3, rdf_content);
331  debug("test.mime", 0, "push caps message appended to the file");
332  fclose(fp3);
333  }
334  } else {
335  if (rdf_content != NULL) {
336  debug("test.mime", 0, "push caps message was");
337  octstr_dump(rdf_content, 0);
338  }
339  }
340 
342  octstr_destroy(mime_content);
343  octstr_destroy(pap_content);
345  octstr_destroy(rdf_content);
346  octstr_destroy(pap_osname);
347  octstr_destroy(data_osname);
348  http_destroy_headers(content_headers);
349  gwlist_destroy(source_parts, octstr_destroy_item);
350  octstr_destroy(push_content_file);
351  gwlib_shutdown();
352 
353  info(0, "MIME data parsed successfully");
354  return 0;
355 
356 no_parse:
357  octstr_destroy(mime_content);
358  octstr_destroy(pap_osname);
359  octstr_destroy(data_osname);
360  gwlist_destroy(source_parts, octstr_destroy_item);
362  gwlib_shutdown();
363  panic(0, "Stopping");
364 
365 error:
366  octstr_destroy(mime_content);
367  gwlist_destroy(source_parts, octstr_destroy_item);
369  octstr_destroy(pap_content);
371  octstr_destroy(pap_osname);
372  octstr_destroy(data_osname);
373  http_destroy_headers(content_headers);
374  octstr_destroy(rdf_content);
375  gwlib_shutdown();
376  panic(0, "Stopping");
377 
378 cerror:
379  octstr_destroy(mime_content);
380  gwlist_destroy(source_parts, octstr_destroy_item);
382  octstr_destroy(pap_content);
384  octstr_destroy(push_content_file);
385  octstr_destroy(pap_osname);
386  octstr_destroy(data_osname);
387  http_destroy_headers(content_headers);
388  octstr_destroy(rdf_content);
389  gwlib_shutdown();
390  panic(0, "Stopping");
391 /* return after panic always required by gcc */
392  return 1;
393 }
394 
395 
396 
397 
398 
399 
400 
401 
402 
403 
404 
405 
406 
void error(int err, const char *fmt,...)
Definition: log.c:648
static Octstr * delimiter
Definition: test_ppg.c:104
void info(int err, const char *fmt,...)
Definition: log.c:672
static void prepend_crlf(Octstr **os)
Definition: test_mime.c:74
static char ** push_data
Definition: test_ppg.c:96
static void remove_crs(Octstr *os)
Definition: test_mime.c:105
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1504
long gwlist_len(List *list)
Definition: list.c:166
static char * boundary
Definition: test_ppg.c:97
static int skip_tail(Octstr **os, int delimiter)
Definition: test_mime.c:122
int optind
Definition: attgetopt.c:80
int octstr_print(FILE *f, Octstr *ostr)
Definition: octstr.c:1191
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1012
void http_destroy_headers(List *headers)
Definition: http.c:2879
int getopt(int argc, char **argv, char *opts)
Definition: attgetopt.c:84
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
static void add_crs(Octstr *os)
Definition: test_mime.c:84
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1303
void * gwlist_extract_first(List *list)
Definition: list.c:305
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1527
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:336
Octstr * octstr_read_file(const char *filename)
Definition: octstr.c:1548
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
Definition: octstr.c:118
int main(int argc, char **argv)
Definition: test_mime.c:158
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
char * optarg
Definition: attgetopt.c:82
#define panic
Definition: log.h:87
static void append_crlf(Octstr *os)
Definition: test_mime.c:79
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2507
void gwlib_shutdown(void)
Definition: gwlib.c:94
void gwlib_init(void)
Definition: gwlib.c:78
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
static void help(void)
Definition: test_mime.c:134
List * octstr_split(const Octstr *os, const Octstr *sep)
Definition: octstr.c:1640
Definition: list.c:102
int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, Octstr **push_data, List **content_headers, Octstr **rdf_content)
void http_header_dump(List *headers)
Definition: http.c:3427
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.