1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "config.h"
18 #include "printf.h"
19 #include "message.h"
20 #include "util.h"
21 #include "content_type.h"
22 
23 static gdouble total_time = 0;
24 static gint total_parsed = 0;
25 static gint total_valid = 0;
26 static gint total_type = 0;
27 static gint total_subtype = 0;
28 static gint total_charset = 0;
29 static gint total_attrs = 0;
30 static gint total_boundaries = 0;
31 static gboolean verbose = 1;
32 
33 #define MODE_NORMAL 0
34 #define MODE_GMIME 1
35 #define MODE_COMPARE 2
36 
37 static void
rspamd_process_file(const gchar * fname,gint mode)38 rspamd_process_file (const gchar *fname, gint mode)
39 {
40 	rspamd_mempool_t *pool;
41 	GIOChannel *f;
42 	GError *err = NULL;
43 	GString *buf;
44 	struct rspamd_content_type *ct;
45 	gdouble t1, t2;
46 	rspamd_ftok_t t;
47 
48 	f = g_io_channel_new_file (fname, "r", &err);
49 
50 	if (!f) {
51 		rspamd_fprintf (stderr, "cannot open %s: %e\n", fname, err);
52 		g_error_free (err);
53 
54 		return;
55 	}
56 
57 	g_io_channel_set_encoding (f, NULL, NULL);
58 	buf = g_string_sized_new (8192);
59 	pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "test");
60 
61 	while (g_io_channel_read_line_string (f, buf, NULL, &err)
62 			== G_IO_STATUS_NORMAL) {
63 
64 		while (buf->len > 0 && g_ascii_isspace (buf->str[buf->len - 1])) {
65 			buf->len --;
66 		}
67 
68 		if (mode == MODE_NORMAL) {
69 			t1 = rspamd_get_virtual_ticks ();
70 			ct = rspamd_content_type_parse (buf->str, buf->len, pool);
71 			t2 = rspamd_get_virtual_ticks ();
72 		}
73 		else {
74 			rspamd_fprintf (stderr, "gmime is no longer supported\n");
75 			exit (EXIT_FAILURE);
76 		}
77 
78 		total_time += t2 - t1;
79 		total_parsed ++;
80 
81 		if (mode == MODE_NORMAL) {
82 
83 			if (ct) {
84 				total_valid ++;
85 
86 				if (ct->type.len > 0) {
87 					total_type ++;
88 				}
89 				if (ct->subtype.len > 0) {
90 					total_subtype ++;
91 				}
92 				if (ct->charset.len > 0) {
93 					total_charset ++;
94 				}
95 				if (ct->boundary.len > 0) {
96 					total_boundaries ++;
97 				}
98 				if (ct->attrs) {
99 					total_attrs ++;
100 				}
101 			}
102 		}
103 	}
104 
105 	if (err) {
106 		rspamd_fprintf (stderr, "cannot read %s: %e\n", fname, err);
107 		g_error_free (err);
108 	}
109 
110 	g_io_channel_unref (f);
111 	g_string_free (buf, TRUE);
112 	rspamd_mempool_delete (pool);
113 }
114 
115 int
main(int argc,char ** argv)116 main (int argc, char **argv)
117 {
118 	gint i, start = 1, mode = MODE_NORMAL;
119 
120 	if (argc > 2 && *argv[1] == '-') {
121 		start = 2;
122 
123 		if (argv[1][1] == 'g') {
124 			mode = MODE_GMIME;
125 		}
126 		else if (argv[1][1] == 'c') {
127 			mode = MODE_COMPARE;
128 		}
129 	}
130 
131 	for (i = start; i < argc; i ++) {
132 		if (argv[i]) {
133 			rspamd_process_file (argv[i], mode);
134 		}
135 	}
136 
137 	if (mode != MODE_COMPARE) {
138 		rspamd_printf ("Parsed %d received headers in %.3f seconds\n"
139 				"Total valid (has type): %d\n"
140 				"Total known type: %d\n"
141 				"Total known subtype: %d\n"
142 				"Total known charset: %d\n"
143 				"Total has attrs: %d\n"
144 				"Total has boundaries: %d\n",
145 				total_parsed, total_time,
146 				total_valid, total_type,
147 				total_subtype, total_charset,
148 				total_attrs,
149 				total_boundaries);
150 	}
151 	else {
152 		rspamd_printf ("Parsed %d received headers in %.3f seconds\n"
153 				"Total valid (parsed by both): %d\n"
154 				"Total same type: %d\n"
155 				"Total same subtype: %d\n"
156 				"Total same charset: %d\n"
157 				"Total same boundaries: %d\n",
158 				total_parsed, total_time,
159 				total_valid, total_type,
160 				total_subtype, total_charset,
161 				total_boundaries);
162 	}
163 
164 	return 0;
165 }
166