1 ///###////////////////////////////////////////////////////////////////////////
2 //
3 // Burton Computer Corporation
4 // http://www.burton-computer.com
5 // http://www.cooldevtools.com
6 // $Id: HeaderPrefixList.cc 272 2007-01-06 19:37:27Z brian $
7 //
8 // Copyright (C) 2007 Burton Computer Corporation
9 // ALL RIGHTS RESERVED
10 //
11 // This program is open source software; you can redistribute it
12 // and/or modify it under the terms of the Q Public License (QPL)
13 // version 1.0. Use of this software in whole or in part, including
14 // linking it (modified or unmodified) into other programs is
15 // subject to the terms of the QPL.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // Q Public License for more details.
21 //
22 // You should have received a copy of the Q Public License
23 // along with this program; see the file LICENSE.txt.  If not, visit
24 // the Burton Computer Corporation or CoolDevTools web site
25 // QPL pages at:
26 //
27 //    http://www.burton-computer.com/qpl.html
28 //    http://www.cooldevtools.com/qpl.html
29 //
30 
31 #include "HeaderPrefixList.h"
32 
33 static const char *SKIPPED_HEADERS[] = {
34   "x-spam",
35   "x-razor",
36   "status",
37   "x-status",
38   "x-imap",
39   0
40 };
41 
42 const string PREFIX_START("H");
43 const string PREFIX_END("_");
44 
is_skipped_header(const string & line)45 static bool is_skipped_header(const string &line)
46 {
47   for (const char **s = SKIPPED_HEADERS; *s; ++s) {
48     if (starts_with(line, *s)) {
49       return true;
50     }
51   }
52   return false;
53 }
54 
getPrefixBody(const string & prefix)55 string HeaderPrefixList::const_iterator::getPrefixBody(const string &prefix)
56 {
57   return prefix.substr(PREFIX_START.length(), prefix.length() - PREFIX_START.length() - PREFIX_END.length());
58 }
59 
HeaderPrefixList()60 HeaderPrefixList::HeaderPrefixList()
61   : m_visitAllHeaders(false),
62     m_ignoreXHeaders(false),
63     m_forceBlankPrefixes(false)
64 {
65 }
66 
~HeaderPrefixList()67 HeaderPrefixList::~HeaderPrefixList()
68 {
69 }
70 
resetHeaderCounts()71 void HeaderPrefixList::resetHeaderCounts()
72 {
73   for (IteratorType i = m_values.begin(); i != m_values.end(); ++i) {
74     i->second.visit_count = 0;
75   }
76 }
77 
shouldProcessHeader(const string & name,string & prefix)78 bool HeaderPrefixList::shouldProcessHeader(const string &name,
79                                            string &prefix)
80 {
81   IteratorType i = m_values.find(name);
82   if (i != m_values.end()) {
83     HeaderData &hd(i->second);
84     hd.visit_count += 1;
85     if (m_forceBlankPrefixes) {
86       prefix.erase();
87     } else if (hd.visit_count > 1) {
88       prefix = hd.other_prefix;
89     } else {
90       prefix = hd.first_prefix;
91     }
92     return true;
93   }
94 
95   if (!m_visitAllHeaders) {
96     return false;
97   }
98 
99   if (m_ignoreXHeaders && starts_with(name, "x-")) {
100     return false;
101   }
102 
103   if (is_skipped_header(name)) {
104     return false;
105   }
106 
107   if (m_forceBlankPrefixes) {
108     prefix.erase();
109   } else {
110     prefix = PREFIX_START + name + PREFIX_END;
111   }
112   addHeaderPrefix(name, name, name);
113   return true;
114 }
115 
setBlankPrefixesMode()116 void HeaderPrefixList::setBlankPrefixesMode()
117 {
118   m_forceBlankPrefixes = true;
119 }
120 
setDefaultHeadersMode()121 void HeaderPrefixList::setDefaultHeadersMode()
122 {
123   m_visitAllHeaders = false;
124   m_ignoreXHeaders = false;
125   m_forceBlankPrefixes = false;
126   m_values.clear();
127 
128   addHeaderPrefix("reply-to", "reply-to", "reply-to");
129   addHeaderPrefix("sender", "sender", "sender");
130   addHeaderPrefix("originator", "originator", "originator");
131   addHeaderPrefix("subject", "subject", "subject");
132   addHeaderPrefix("from", "from", "from");
133   addHeaderPrefix("to", "to", "to");
134   addHeaderPrefix("cc", "cc", "cc");
135   addHeaderPrefix("message-id", "message-id", "message-id");
136   addHeaderPrefix("received", "recv", "recvx");
137   addHeaderPrefix("content-type", "", "");
138 }
139 
setNonXHeadersMode()140 void HeaderPrefixList::setNonXHeadersMode()
141 {
142   m_visitAllHeaders = true;
143   m_ignoreXHeaders = true;
144   m_forceBlankPrefixes = false;
145   m_values.clear();
146 }
147 
setAllHeadersMode()148 void HeaderPrefixList::setAllHeadersMode()
149 {
150   m_visitAllHeaders = true;
151   m_ignoreXHeaders = false;
152   m_forceBlankPrefixes = false;
153   m_values.clear();
154 }
155 
setNoHeadersMode()156 void HeaderPrefixList::setNoHeadersMode()
157 {
158   m_visitAllHeaders = false;
159   m_ignoreXHeaders = false;
160   m_forceBlankPrefixes = false;
161   m_values.clear();
162 }
163 
addSimpleHeaderPrefix(const string & name)164 void HeaderPrefixList::addSimpleHeaderPrefix(const string &name)
165 {
166   addHeaderPrefix(name, name, name);
167 }
168 
addHeaderPrefix(const string & name,const string & first_prefix,const string & other_prefix)169 void HeaderPrefixList::addHeaderPrefix(const string &name,
170                                        const string &first_prefix,
171                                        const string &other_prefix)
172 {
173   HeaderData hd;
174   if (first_prefix.length() > 0) {
175     hd.first_prefix = PREFIX_START + to_lower(first_prefix) + PREFIX_END;
176   }
177   if (other_prefix.length() > 0) {
178     hd.other_prefix = PREFIX_START + to_lower(other_prefix) + PREFIX_END;
179   }
180   hd.visit_count = 0;
181   m_values.insert(make_pair(to_lower(name), hd));
182 }
183 
removeHeaderPrefix(const string & name)184 void HeaderPrefixList::removeHeaderPrefix(const string &name)
185 {
186   string lower_name(to_lower(name));
187   MapType::iterator i = m_values.find(lower_name);
188   if (i != m_values.end()) {
189     m_values.erase(i);
190   }
191 }
192