/[debian]/mimetic/branches/upstream/current/examples/engine.cxx
ViewVC logotype

Annotation of /mimetic/branches/upstream/current/examples/engine.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 128 - (hide annotations)
Sat Feb 25 16:49:20 2006 UTC (15 years, 6 months ago) by gregoa
File size: 12543 byte(s)
[svn-inject] Installing original source of mimetic
1 gregoa 128 #include <algorithm>
2     #include <iostream>
3     #include <string>
4     #include <cctype>
5     #include <sys/types.h>
6     #include <regex.h>
7     #ifdef HAS_PCRE
8     #include <pcreposix.h>
9     #endif
10    
11     #include "engine.h"
12    
13     using namespace std;
14     using namespace mimetic;
15    
16     engine::engine(const command_line& cl)
17     : m_cl(cl), m_pcre(false),
18     m_match_mode(match_type_none)
19     {
20     // set options
21     if(cl.is_set(p_match_shell) || cl.is_set(p_match_regex))
22     m_match_mode =
23     cl.is_set(p_match_shell) ?
24     match_type_shell :
25     match_type_regex;
26    
27     m_match_mode |=
28     cl.is_set(p_case_insensitive) ? match_flag_case_insensitive : 0;
29    
30     m_match_mode |=
31     cl.is_set(p_perl_regex) ? match_flag_perl_mode: 0;
32    
33     if((m_match_mode & match_type_mask) == match_type_none)
34     m_match_mode |= match_type_regex; // default
35     }
36    
37     int engine::posix_regex_match(const string& text, const string& pattern, int match_mode)
38     {
39     int r;
40     regex_t rex;
41     r = regcomp(&rex, pattern.c_str(),
42     ( match_mode & match_flag_case_insensitive ? REG_ICASE: 0));
43     if(r != 0)
44     {
45     char buf[256];
46     regerror(r, &rex, buf, 255);
47     die(buf);
48     }
49     r = regexec(&rex, text.c_str(), 0, 0, 0);
50     regfree(&rex);
51     return r == 0;
52     }
53    
54     int engine::perl_regex_match(const string& text, const string& pattern, int match_mode )
55     {
56     #ifdef HAS_PCRE
57     #else
58     die("uuh?");
59     #endif
60     return 0;
61     }
62    
63     int engine::pattern_match(const string& text, const string& pattern, int match_mode)
64     {
65     switch(match_mode & match_type_mask)
66     {
67     case match_type_none:
68     die("match_type_none");
69     case match_type_exact:
70     return exact_match(text, pattern, match_mode);
71     case match_type_regex:
72     return regex_match(text, pattern, match_mode);
73     case match_type_shell:
74     return shell_match(text, pattern, match_mode);
75     default:
76     die("uuh?");
77     }
78     return 0;
79     }
80    
81     int engine::shell_match(const string& text, const string& pattern, int match_mode)
82     {
83     die("not impl");
84     return 0;
85     }
86    
87     int engine::regex_match(const string& text, const string& pattern, int match_mode)
88     {
89     if(m_pcre)
90     return engine::perl_regex_match(text, pattern, match_mode);
91     else
92     return engine::posix_regex_match(text, pattern, match_mode);
93     }
94    
95     void engine::action_attach(MimeEntity& me, parts_hierarchy* ph, const string& fqn)
96     {
97     bool isMultipart = me.header().contentType().isMultipart();
98     bool isTopLevel = !ph->size();
99    
100     /*
101     1) me is multipart:
102     add the attach to me as the last part
103     2) me is not multipart
104     create a multipart/mixed with me and the attach childs
105     and put it in the same level/position of me
106     3) me is not multipart and is the top level entity
107     same as 2) but move all me fields to the new top-level
108     */
109     Attachment* pA = new Attachment(fqn);
110     if(!pA->isValid())
111     die("attach error");
112     if(isMultipart)
113     {
114     DBG( "isMultipart");
115     me.body().parts().push_back(pA);
116     } else {
117     MimeEntity *mm;
118     mm = new MultipartMixed;
119     mm->body().parts().push_back(&me);
120     mm->body().parts().push_back(pA);
121     if(!isTopLevel)
122     {
123     DBG( "!isTopLevel");
124     MimeEntity *parent = *ph->begin();
125     replace(parent->body().parts().begin(),
126     parent->body().parts().end(),
127     &me, mm);
128     } else {
129     DBG( "isTopLevel");
130     // add cp fields here
131     Header::iterator bit, eit, pos;
132     bit = me.header().begin(), me.header().end();
133     string name; // field name
134     pos = mm->header().begin(); // insert before others
135     for(; bit != eit; ++bit)
136     {
137     name = bit->name();
138     transform(name.begin(), name.end(),
139     name.begin(), ::tolower);
140     if(name.find("content-") == 0 || name == "mime-version")
141     continue;
142     mm->header().insert(pos, *bit);
143     }
144     }
145     }
146     }
147    
148     void engine::action(MimeEntity& me, parts_hierarchy* ph)
149     {
150     MimeEntity* parent = (ph->size() ? *ph->begin() : &me);
151     if(m_cl.is_set(p_add_header))
152     {
153     static const char* key = "add-header";
154     command_line::iterator bit, eit;
155     bit = m_cl.begin(key), eit = m_cl.end(key);
156     for(; bit != eit; ++bit)
157     {
158     Field f(bit->second);
159     parent->header().push_back(f);
160     }
161     }
162     if(m_cl.is_set(p_add_part_header)) {
163     static const char* key = "add-part-header";
164     command_line::iterator bit, eit;
165     bit = m_cl.begin(key), eit = m_cl.end(key);
166     for(; bit != eit; ++bit)
167     {
168     Field f(bit->second);
169     me.header().push_back(f);
170     }
171     }
172     if(m_cl.is_set(p_attach))
173     {
174     static const char* key = "attach";
175     command_line::iterator bit, eit;
176     bit = m_cl.begin(key), eit = m_cl.end(key);
177     for(; bit != eit; ++bit)
178     action_attach(me, ph, bit->second);
179     }
180    
181     if(m_cl.is_set(p_print_msg))
182     cout << *parent;
183     else if(m_cl.is_set(p_print_part))
184     cout << me;
185     }
186    
187    
188     int engine::exact_match(const string& text, const string& pattern, int match_mode)
189     {
190     if(match_mode & match_flag_case_insensitive)
191     {
192     istring is(text);
193     return is == pattern;
194     } else
195     return text == pattern;
196     }
197    
198    
199     /*
200     * expr: pat1 [=|~] pat2
201     * pat1 is the pattern that represents the field name
202     * pat2 is the pattern that represents the field value
203     */
204     int engine::pattern_field_match(const MimeEntity& me, const string& expr,
205     int match_mode)
206     {
207     int has_value = 0; // left part of the expr
208     char prev = 0; // previous char
209     string field_pat, value_pat;
210     char op;
211     for(size_t i = 0; i < expr.length(); ++i)
212     {
213     if( (expr[i] == '=' || expr[i] == '~') && prev != '\\')
214     {
215     has_value++; // right part
216     op = expr[i];
217     continue;
218     }
219     if(!has_value)
220     field_pat.append(1, expr[i]);
221     else
222     value_pat.append(1, expr[i]);
223     prev = expr[i];
224     }
225     field_pat = remove_external_blanks(field_pat);
226     value_pat = remove_external_blanks(value_pat);
227     // first try to find a field that match the field_pat pattern
228     const Header& h = me.header();
229     Header::const_iterator bit = h.begin(), eit = h.end();
230     for( ; bit != eit; ++bit)
231     {
232     if(pattern_match(bit->name(), field_pat, match_mode))
233     { // we've found a matching field, let's check the value
234     if(!has_value)
235     return 1;
236     else
237     if(pattern_match(bit->value(), value_pat, match_mode))
238     return 1;
239     }
240     }
241     return 0;
242     }
243    
244     string engine::remove_external_blanks(const string& str) const
245     {
246     // a dirty way to trim ext.blanks
247     string s = str;
248     for(int i = s.length() - 1; i >= 0; --i)
249     if(s[i] == ' ')
250     s.erase(i, 1);
251     else
252     break;
253     while(s.length() && s[0] == ' ')
254     s.erase(0, 1);
255     return s;
256     }
257    
258     int engine::fixed_field_match(const MimeEntity& me, const string& name, const string& value, int match_mode)
259     {
260     if(!me.header().hasField(name))
261     return 0;
262     if(value.length() == 0)
263     return 1; // it exists
264     const string& field_value = me.header().field(name).value();
265     return pattern_match(field_value, value, match_mode) ;
266     }
267    
268     int engine::has_binary_attach(const MimeEntity& me, const command_line_switch& cls)
269     {
270     const Header& h = me.header();
271     const ContentType& ct = h.contentType();
272     if(ct.type() == "text" || ct.type() == "multipart" || ct.type() == "message")
273     return 0;
274     const ContentTransferEncoding& cte = h.contentTransferEncoding();
275     if(cte.mechanism() == "base64")
276     return 1;
277     return 1;
278     }
279    
280     int engine::field_match(const MimeEntity& me, const command_line_switch& cls)
281     {
282     const string& name = cls.first, value = cls.second;
283     if(name == "field")
284     return pattern_field_match(me, value, m_match_mode);
285     else if (name == "ifield")
286     return pattern_field_match(me, value,
287     m_match_mode | match_flag_case_insensitive);
288     else
289     return fixed_field_match(me, name, value,
290     m_match_mode);
291     }
292    
293     int engine::has_field(const MimeEntity& me, const command_line_switch& cls)
294     {
295     return me.header().hasField(cls.second);
296     }
297    
298     int engine::match_filename(const string& filename, const string& pattern)
299     {
300     // convert shell pattern string to regex
301     string re_pattern;
302     char c;
303     for(size_t i = 0; i < pattern.length(); ++i)
304     {
305     c = pattern[i];
306     switch(c)
307     {
308     case '?':
309     re_pattern.append(".");
310     break;
311     case '*':
312     re_pattern.append(".*");
313     break;
314     case '[':
315     case '.':
316     case '=':
317     case '<':
318     case '>':
319     case '+':
320     case '_':
321     case '\\':
322     case '-':
323     case ']':
324     re_pattern.append(1, '\\');
325     re_pattern.append(1, c);
326     break;
327     default:
328     re_pattern.append(1, c);
329     }
330     }
331     return regex_match(filename, re_pattern, 0);
332     }
333    
334     int engine::attach_filename(const MimeEntity& me,const command_line_switch& cls)
335     {
336     typedef list<string> filename_list;
337     const Header& h = me.header();
338     const ContentType& ct = h.contentType();
339     const ContentDisposition& cd = h.contentDisposition();
340     string pattern = cls.second;
341     filename_list names;
342     // content-type params
343     names.push_back(ct.param("name"));
344     names.push_back(ct.param("filename")); // should not exists
345     // content-disposition params
346     names.push_back(cd.param("name"));
347     names.push_back(cd.param("filename")); // should not exists
348     filename_list::const_iterator bit = names.begin(), eit = names.end();
349     for( ; bit != eit; ++bit)
350     if(match_filename(*bit, pattern))
351     return 1;
352     return 0;
353     }
354    
355     MimeEntity* engine::match(MimeEntity& me, int level, parts_hierarchy* ph)
356     {
357     int matched = 1, child_match = 0, free = 0;
358    
359     if(ph == 0)
360     {
361     ph = new parts_hierarchy;
362     free++;
363     }
364     if(m_cl.is_set(p_recursive))
365     {
366     MimeEntityList& parts = me.body().parts();
367     if( parts.size() )
368     {
369     ++level;
370     MimeEntityList::iterator mbit, meit;
371     mbit = parts.begin(), meit = parts.end();
372     ph->insert(ph->begin(), &me);
373     for( ; mbit != meit; ++mbit)
374     child_match += (match(**mbit, level, ph ) ? 1 : 0);
375     ph->erase(ph->begin());
376     }
377     }
378     static char *std_fields[] = {
379     "from", "sender", "to", "sujbect", "cc", "bcc",
380     "user-agent", "date", "content-type",
381     "content-transfer-encoding", "content-disposition",
382     "content-description",
383     0
384     };
385     command_line::const_iterator bit = m_cl.begin(), eit = m_cl.end();
386     for(; bit != eit; ++bit)
387     {
388     const string& name = bit->first, value = bit->second;
389     if(name == "attach-filename") {
390     if(!attach_filename(me, *bit))
391     {
392     matched = 0;
393     break;
394     }
395     } else if(name == "has-field") {
396     if(!has_field(me, *bit))
397     {
398     matched = 0;
399     break;
400     }
401     } else if(name == "has-binary-attach") {
402     if(!has_binary_attach(me, *bit))
403     {
404     matched = 0;
405     break;
406     }
407     } else if(name == "field") {
408     if(!field_match(me, *bit))
409     {
410     matched = 0;
411     break;
412     }
413     } else if(name == "ifield") {
414     if(!field_match(me, *bit))
415     {
416     matched = 0;
417     break;
418     }
419     } else {
420     int break_loop = 0;
421     char **std_name = std_fields;
422     for( int i = 0 ; std_name[i] ; ++i)
423     {
424     if(name == std_name[i])
425     if(!field_match(me, *bit))
426     {
427     matched = 0;
428     break_loop++;
429     break;
430     }
431     }
432     if(break_loop)
433     break;
434     }
435     }
436     if(matched)
437     action(me, ph);
438     if(free)
439     delete ph;
440     return ( matched || child_match ? &me : 0);
441     }

  ViewVC Help
Powered by ViewVC 1.1.26