OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / user / gnugk / Toolkit.cxx
1 //////////////////////////////////////////////////////////////////
2 //
3 // Toolkit base class for the GnuGK
4 //
5 // This work is published under the GNU Public License (GPL)
6 // see file COPYING for details.
7 // We also explicitely grant the right to link this code
8 // with the OpenH323 library.
9 //
10 //////////////////////////////////////////////////////////////////
11
12 #if defined(_WIN32) && (_MSC_VER <= 1200)
13 #pragma warning(disable:4786) // warning about too long debug symbol off
14 #pragma warning(disable:4284)
15 #endif
16
17 #include <ptlib.h>
18 #include <ptclib/cypher.h>
19 #include <h323pdu.h>
20 #include <map>
21 #include "stl_supp.h"
22 #include "gktimer.h"
23 #include "h323util.h"
24 #include "gkconfig.h"
25 #if HAS_MYSQL || HAS_PGSQL
26 #include "gksql.h"
27 #endif
28 #include "clirw.h"
29 #include "capctrl.h"
30 #include "Toolkit.h"
31
32 using namespace std;
33
34 extern const char *ProxySection;
35 extern const char *RoutedSec;
36
37 namespace {
38
39 const PString paddingByteConfigKey("KeyFilled");
40 const BYTE AnyRawAddress[16] = {
41         255, 255, 255, 255, 255, 255, 255, 255,
42         255, 255, 255, 255, 255, 255, 255, 255
43 };
44
45 } /* namespace */
46
47 NetworkAddress::NetworkAddress() : m_address(0), m_netmask(0)
48 {
49 }
50
51 NetworkAddress::NetworkAddress(
52         const PIPSocket::Address &addr
53         ) : m_address(addr), m_netmask(addr.GetSize(), AnyRawAddress)
54 {
55 }
56
57 NetworkAddress::NetworkAddress(
58         const PIPSocket::Address &addr,
59         const PIPSocket::Address &nm
60         ) : m_netmask(nm)
61 {
62         // normalize the address
63         BYTE rawdata[16];
64         const unsigned sz = addr.GetSize();
65         for (unsigned i = 0; i < sz; i++)
66                 rawdata[i] = addr[i] & nm[i];
67         m_address = PIPSocket::Address(sz, rawdata);
68 }
69         
70 NetworkAddress::NetworkAddress(
71         const PString &str /// an address in a form A.B.C.D, A.B.C.D/24 or A.B.C.D/255.255.255.0
72         )
73 {
74         Toolkit::GetNetworkFromString(str, m_address, m_netmask);
75 }
76
77 unsigned NetworkAddress::GetNetmaskLen() const          
78 {
79         unsigned len = 0;
80         const unsigned sz = m_netmask.GetSize() * 8;
81         const char *rawdata = m_netmask.GetPointer();
82         
83         
84         for (int b = sz - 1; b >= 0; b--)
85                 if (rawdata[b >> 3] & (0x80 >> (b & 7)))
86                         break;
87                 else
88                         len++;
89                         
90         return sz - len;
91 }
92
93 bool NetworkAddress::operator==(const NetworkAddress &addr) const
94 {
95         if (m_address.GetSize() != addr.m_address.GetSize())
96                 return false;
97
98         const unsigned sz = m_address.GetSize();
99         for (unsigned i = 0; i < sz; i++)
100                 if (m_address[i] != addr.m_address[i] || m_netmask[i] != addr.m_netmask[i])
101                         return false;
102                         
103         return true;
104 }
105
106 bool NetworkAddress::operator==(const PIPSocket::Address &addr) const
107 {
108         if (m_address.GetSize() != addr.GetSize())
109                 return false;
110
111         const unsigned sz = m_address.GetSize();
112         for (unsigned i = 0; i < sz; i++)
113                 if (m_netmask[i] != 255 || m_address[i] != addr[i])
114                         return false;
115                         
116         return true;
117 }
118
119 bool NetworkAddress::operator>>(const NetworkAddress &addr) const
120 {
121         if (m_address.GetSize() != addr.m_address.GetSize())
122                 return false;
123
124         const unsigned sz = m_address.GetSize();
125         for (unsigned i = 0; i < sz; i++)
126                 if (m_netmask[i] != (addr.m_netmask[i] & m_netmask[i])
127                                 || m_address[i] != (addr.m_address[i] & m_netmask[i]))
128                         return false;
129                         
130         return true;
131 }
132         
133 bool NetworkAddress::operator<<(const NetworkAddress &addr) const
134 {
135         return addr >> *this;
136 }
137
138 bool NetworkAddress::operator>>(const PIPSocket::Address &addr) const
139 {
140         if (m_address.GetSize() != addr.GetSize())
141                 return false;
142
143         const unsigned sz = m_address.GetSize();
144         for (unsigned i = 0; i < sz; i++)
145                 if (m_address[i] != (addr[i] & m_netmask[i]))
146                         return false;
147                         
148         return true;
149 }
150
151 int NetworkAddress::Compare(const NetworkAddress &addr) const
152 {
153         int diff = m_address.GetSize() - addr.m_address.GetSize();
154         if (diff == 0) {
155                 diff = GetNetmaskLen() - addr.GetNetmaskLen();
156                 if (diff == 0) {
157                         const unsigned sz = m_address.GetSize();
158                         for (unsigned i = 0; i < sz; i++) {
159                                 diff = m_address[i] - addr.m_address[i];
160                                 if (diff != 0)
161                                         break;
162                         }
163                 }
164         }
165         return diff;
166 }
167
168 PString NetworkAddress::AsString() const
169 {
170         return m_address.AsString() + "/" + PString(GetNetmaskLen());
171 }
172
173 bool NetworkAddress::IsAny() const
174 {
175         return const_cast<NetworkAddress*>(this)->m_address.IsAny() ? true : false;
176 }
177
178 bool NetworkAddress::operator<(const NetworkAddress &addr) const
179 {
180         return Compare(addr) < 0;
181 }
182
183 bool NetworkAddress::operator<=(const NetworkAddress &addr) const
184 {
185         return Compare(addr) <= 0;
186 }
187
188 bool NetworkAddress::operator>(const NetworkAddress &addr) const
189 {
190         return Compare(addr) > 0;
191 }
192
193 bool NetworkAddress::operator>=(const NetworkAddress &addr) const
194 {
195         return Compare(addr) >= 0;
196 }
197
198 bool operator==(const PIPSocket::Address &addr, const NetworkAddress &net)
199 {
200         return net == addr;
201 }
202
203 bool operator<<(const PIPSocket::Address &addr, const NetworkAddress &net)
204 {
205         return net >> addr;
206 }
207
208
209 // class Toolkit::RouteTable::RouteEntry
210 Toolkit::RouteTable::RouteEntry::RouteEntry(
211         const PString & net
212 ) : PIPSocket::RouteEntry(0)
213 {
214         destination = net.Tokenise("/", FALSE)[0];
215         GetNetworkFromString(net, network, net_mask);
216 }
217
218 Toolkit::RouteTable::RouteEntry::RouteEntry(
219         const PIPSocket::RouteEntry & re,
220         const InterfaceTable & it
221 ) : PIPSocket::RouteEntry(re)
222 {
223         PINDEX i;
224         for (i = 0; i < it.GetSize(); ++i) {
225                 const Address & ip = it[i].GetAddress();
226                 if (Compare(&ip)) {
227                         destination = ip;
228                         return;
229                 }
230         }
231         for (i = 0; i < it.GetSize(); ++i)
232                 if (it[i].GetName() == interfaceName) {
233                         destination = it[i].GetAddress();
234                         return;
235                 }
236 }
237
238 inline bool Toolkit::RouteTable::RouteEntry::Compare(const Address *ip) const
239 {
240         return (*ip == destination) || ((*ip & net_mask) == network);
241 }
242
243 // class Toolkit::RouteTable
244 void Toolkit::RouteTable::InitTable()
245 {
246         // Workaround for OS doesn't support GetRouteTable
247         PIPSocket::GetHostAddress(defAddr);
248
249         ClearTable();
250         if (!CreateTable())
251                 return;
252
253         // Set default IP according to route table
254         PIPSocket::Address defGW;
255         PIPSocket::GetGatewayAddress(defGW);
256         defAddr = GetLocalAddress(defGW);
257
258 #if PTRACING
259         for (RouteEntry *entry = rtable_begin; entry != rtable_end; ++entry)
260                 PTRACE(2, "Network=" << entry->GetNetwork() << '/' << entry->GetNetMask() <<
261                           ", IP=" << entry->GetDestination());
262         PTRACE(2, "Default IP=" << defAddr);
263 #endif
264 }
265
266 void Toolkit::RouteTable::ClearTable()
267 {
268         if (rtable_begin) {
269                 for (RouteEntry *r = rtable_begin; r != rtable_end; ++r)
270                         r->~RouteEntry();
271                 ::free(rtable_begin);
272                 rtable_begin = 0;
273         }
274 }
275
276 // can't pass a reference of Address, or STL complains...
277 PIPSocket::Address Toolkit::RouteTable::GetLocalAddress(const Address & addr) const
278 {
279   // If a dynamic external IP retrieve external IP from DNS entries
280         if (DynExtIP && !addr.IsRFC1918()) {
281           PIPSocket::Address extip;
282           H323TransportAddress ex = H323TransportAddress(ExtIP);
283           ex.GetIpAddress(extip);
284           return extip;
285         }
286
287         RouteEntry *entry = find_if(rtable_begin, rtable_end,
288                         bind2nd(mem_fun_ref(&RouteEntry::Compare), &addr));
289         return (entry != rtable_end) ? entry->GetDestination() : defAddr;
290 }
291
292 bool Toolkit::RouteTable::CreateRouteTable(const PString & extroute)
293 {
294         InterfaceTable if_table;
295         if (!PIPSocket::GetInterfaceTable(if_table)) {
296                 PTRACE(1, "Error: Can't get interface table");
297                 return false;
298         }
299
300         PTRACE(4, "InterfaceTable:\n" << setfill('\n') << if_table << setfill(' '));
301         PIPSocket::RouteTable r_table;
302         if (!PIPSocket::GetRouteTable(r_table)) {
303                 PTRACE(1, "Error: Can't get route table");
304                 return false;
305         }
306
307         if (/*!extroute &&*/ AsBool(GkConfig()->GetString(ProxySection, "Enable", "0"))) {
308           for (PINDEX i = 0; i < r_table.GetSize(); ++i) {
309                 if (r_table[i].GetNetwork().IsRFC1918() && r_table[i].GetNetMask().AsString() != "255.255.255.255") {
310                   PString intAddr = r_table[i].GetNetwork().AsString() + "/" + r_table[i].GetNetMask().AsString();
311                   m_internalnetworks.resize( m_internalnetworks.size() + 1);
312                   m_internalnetworks[m_internalnetworks.size() - 1] = NetworkAddress(intAddr);
313                   PTRACE(2, "Internal Network Detected " << m_internalnetworks.back().AsString()); 
314                 } 
315           }
316         }
317
318         int i = (!extroute) ? r_table.GetSize()+1 : r_table.GetSize();
319
320         rtable_end = rtable_begin = static_cast<RouteEntry *>(::malloc(i * sizeof(RouteEntry)));
321         for (PINDEX r = 0; r < i ; ++r) {
322                 if (!extroute && (r==r_table.GetSize()))
323                         ::new (rtable_end++) RouteEntry(extroute);
324                 else {
325                   PIPSocket::RouteEntry & r_entry = r_table[r];
326                   if (r_entry.GetNetMask() != INADDR_ANY) 
327                         ::new (rtable_end++) RouteEntry(r_entry, if_table);
328                 }
329         }
330
331         return true;
332 }
333
334 bool Toolkit::VirtualRouteTable::CreateTable()
335 {
336         PString nets = GkConfig()->GetString("NetworkInterfaces", "");
337         if (!nets) {            
338            PStringArray networks(nets.Tokenise(" ,;\t", FALSE));
339            int i = networks.GetSize();
340            if (i > 0) {
341           rtable_end = rtable_begin = static_cast<RouteEntry *>(::malloc(i * sizeof(RouteEntry)));
342                   for (PINDEX r = 0; r < i ; ++r) 
343              ::new (rtable_end++) RouteEntry(networks[r]);
344        }
345            return true;
346         }
347
348         // If we have an external IP setting then load the detected Route Table and add a route for the external IP
349         // If dynamic IP then only store the PString value and resolve the DNS when required.
350         PString extip = GkConfig()->GetString("ExternalIP", "");
351         DynExtIP = AsBool(GkConfig()->GetString("ExternalIsDynamic", "0"));
352
353         PIPSocket::Address ext((DWORD)0);
354         H323TransportAddress ex = H323TransportAddress(extip);
355         ex.GetIpAddress(ext);
356         if (ext.IsValid() && !ext.IsRFC1918()) {
357            ExtIP = extip;
358            PString extroute = PString();
359            if (!DynExtIP) 
360                   extroute = ext.AsString() + "/0";
361
362            CreateRouteTable(extroute);
363            PTRACE(1,"External IP = " << ExtIP << " dynamic " << DynExtIP);
364            return true;
365         } else
366         DynExtIP = false;
367
368         return false;
369 }
370
371 bool Toolkit::VirtualRouteTable::IsMasquerade(PIPSocket::Address & addr)
372 {
373         if (!ExtIP) {
374           H323TransportAddress ex = H323TransportAddress(ExtIP);
375           ex.GetIpAddress(addr);
376           return true;
377         }
378
379         return false; 
380 }
381
382 // class Toolkit::ProxyCriterion
383 Toolkit::ProxyCriterion::ProxyCriterion() : m_enable(false)
384 {
385 }
386
387 Toolkit::ProxyCriterion::~ProxyCriterion()
388
389 }
390
391 void Toolkit::ProxyCriterion::LoadConfig(PConfig *config)
392 {
393         m_enable = AsBool(config->GetString(ProxySection, "Enable", "0"));
394         if (!m_enable) {
395                 PTRACE(2, "GK\tH.323 Proxy disabled");
396                 return;
397         }
398
399         PTRACE(2, "GK\tH.323 Proxy enabled");
400
401         m_networks.clear();
402
403         PStringArray networks(config->GetString(ProxySection, "InternalNetwork", "").Tokenise(" ,;\t", FALSE));
404
405         // if no networks specified then use the detected values
406         if (networks.GetSize() == 0) {
407           m_networks = Toolkit::Instance()->GetInternalNetworks();
408           for (unsigned j = 0; j < m_networks.size(); ++j) 
409                 PTRACE(2, "GK\tInternal Network " << j << " = " << m_networks[j].AsString());
410           return;
411         } 
412
413           for (PINDEX i = 0; i < networks.GetSize(); ++i) {
414                 m_networks.resize(m_networks.size() + 1);
415                 m_networks[m_networks.size() - 1] = NetworkAddress(networks[i]);
416                 PTRACE(2, "GK\tINI Internal Network " << i << " = " << m_networks.back().AsString());
417           }
418 }
419
420 bool Toolkit::ProxyCriterion::Required(const Address & ip1, const Address & ip2) const
421 {
422         return m_enable ? (m_networks.empty() || (IsInternal(ip1) != IsInternal(ip2))) : false;
423 }
424
425 int Toolkit::ProxyCriterion::IsInternal(const Address & ip) const
426 {
427    // Return the network Id. Addresses may be on different internal networks
428         int retval = 0;
429         std::vector<NetworkAddress>::const_iterator i = m_networks.begin();
430         while (i != m_networks.end()) {
431                 retval++;
432                 if (ip << *i++)
433                         return retval;
434     }
435         return 0;
436 }
437
438 // class Toolkit::RewriteTool
439
440 static const char *RewriteSection = "RasSrv::RewriteE164";
441 static const char *AliasRewriteSection = "RasSrv::RewriteAlias";
442
443 void Toolkit::RewriteData::AddSection(PConfig *config, const PString & section)
444 {
445         PStringToString cfgs(config->GetAllKeyValues(section));
446         PINDEX n_size = cfgs.GetSize();
447         if (n_size > 0) {
448                 std::map<PString, PString, pstr_prefix_lesser> rules;
449                 for (PINDEX i = 0; i < n_size; ++i) {
450                         PString key = cfgs.GetKeyAt(i);
451                         PCaselessString first = PCaselessString(key[0]);                                
452                         if (!key && (isdigit(key[0]) || (first.FindOneOf("!.%*#ABCDEFGHIGKLMNOPQRSTUVWXYZ") != P_MAX_INDEX)))                   
453                                 rules[key] = cfgs.GetDataAt(i);
454                 }
455                 // now the rules are ascendantly sorted by the keys
456                 if ((n_size = rules.size()) > 0) {
457                         // Add any existing rules to be resorted
458                         if (m_size > 0) {
459              for (PINDEX j = 0; j < m_size; ++j) {
460                                  rules[Key(j)] = Value(j);
461                          }
462                         }
463                         m_size = m_size + n_size;
464                         // replace array constructor with explicit memory allocation
465                         // and in-place new operators - workaround for VC compiler
466 //                      m_RewriteKey = new PString[m_size * 2];
467                         m_RewriteKey = (PString*)(new BYTE[sizeof(PString) * m_size * 2]);
468                         m_RewriteValue = m_RewriteKey + m_size;
469                         std::map<PString, PString, pstr_prefix_lesser>::iterator iter = rules.begin();
470                         
471                         // reverse the order
472                         for (int i = m_size; i-- > 0 ; ++iter) {
473 //                              m_RewriteKey[i] = iter->first;
474                                 ::new(m_RewriteKey + i) PString(iter->first);
475 //                              m_RewriteValue[i] = iter->second;
476                                 ::new(m_RewriteValue + i) PString(iter->second);
477                         }
478                 }
479         }
480 }
481 Toolkit::RewriteData::RewriteData(PConfig *config, const PString & section)
482 {
483         m_RewriteKey = NULL;
484         m_size= 0;
485     AddSection(config, section);
486 }
487
488 Toolkit::RewriteData::~RewriteData()
489 {
490 //      delete [] m_RewriteKey;
491         if (m_RewriteKey)
492                 for (int i = 0; i < m_size * 2; i++)
493                         (m_RewriteKey+i)->~PString();
494         delete[] ((BYTE*)m_RewriteKey);
495 }
496
497 void Toolkit::RewriteTool::LoadConfig(
498         PConfig *config
499         )
500 {
501         m_RewriteFastmatch = config->GetString(RewriteSection, "Fastmatch", "");
502         m_TrailingChar = config->GetString("RasSrv::ARQFeatures", "RemoveTrailingChar", " ")[0];
503         m_defaultDomain = config->GetString("Gatekeeper::Main", "DefaultDomain", "");
504         delete m_Rewrite;
505         m_Rewrite = new RewriteData(config, RewriteSection);
506         m_Rewrite->AddSection(config,AliasRewriteSection);
507 }
508
509 bool Toolkit::RewriteTool::RewritePString(PString & s) const
510 {
511         bool changed = false;
512
513         // If URL remove the domain if default domain
514          PINDEX at = s.Find('@');
515          if (at != P_MAX_INDEX) {
516                  PString num = s.Left(at);
517          // Check if we have a default domain and strip it
518                  if (s.Mid(at+1) == m_defaultDomain) {
519                    PTRACE(2, "\tRewriteDomain: " << s << " to " << num);
520                    s = num;
521                    changed = true;
522                  } else {
523                          // Check if all numeric then is E164 then strip the domain
524                          PINDEX j;
525                      for (j = 0; j < num.GetLength(); ++j)
526                                if (!isdigit(num[j]))
527                                          break;
528
529                          if (j >= num.GetLength()) { // is numeric
530                                 PTRACE(2, "\tRewriteToE164: " << s << " to " << num);
531                 s = num;
532                                 changed = true;
533                          }
534                  }
535          }
536
537         // remove trailing character
538         if (s.GetLength() > 1 && s[s.GetLength() - 1] == m_TrailingChar) {
539                 s = s.Left(s.GetLength() - 1);
540                 changed = true;
541         }
542         // startsWith?
543         if (strncmp(s, m_RewriteFastmatch, m_RewriteFastmatch.GetLength()) != 0)
544                 return changed;
545
546         PString t;
547         for (PINDEX i = 0; i < m_Rewrite->Size(); ++i) {
548                 const char *prefix = m_Rewrite->Key(i);
549                 if (prefix == s){
550                         s = m_Rewrite->Value(i);
551             return true;
552                 }
553                 const int len = MatchPrefix(s, prefix);
554                 // try a prefix match through all keys
555                 if (len > 0 || (len == 0 && prefix[0] == '!')) {
556                         // Rewrite to #t#. Append the suffix, too.
557                         // old:  01901234999
558                         //               999 Suffix
559                         //       0190        Fastmatch
560                         //       01901234    prefix, Config-Rule: 01901234=0521321
561                         // new:  0521321999
562
563                         const char *newprefix = m_Rewrite->Value(i);
564
565                         PString result;
566                         if (len > 0)
567                                 result = RewriteString(s, prefix, newprefix);
568                         else
569                                 result = newprefix + s;
570                                 
571                         PTRACE(2, "\tRewritePString: " << s << " to " << result);
572                         s = result;
573                         changed = true;
574
575                         break;
576                 }
577         }
578
579         return changed;
580 }
581
582 // class Toolkit::GWRewriteTool
583
584 static const char *GWRewriteSection = "RasSrv::GWRewriteE164";
585
586 Toolkit::GWRewriteTool::~GWRewriteTool() {
587         for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
588                 delete &(m_GWRewrite.GetDataAt(i));
589         }
590         m_GWRewrite.RemoveAll();
591 }
592
593 bool Toolkit::GWRewriteTool::RewritePString(PString gw, bool direction, PString &data) {
594
595         GWRewriteEntry *gw_entry;
596         PString key, value;
597
598         // First lookup the GW in the dictionary
599         gw_entry = m_GWRewrite.GetAt(gw);
600
601         if (gw_entry == NULL)
602                 return false;
603
604         std::vector<pair<PString,PString> >::iterator rule_iterator = direction
605                 ? gw_entry->m_entry_data.first.begin() : gw_entry->m_entry_data.second.begin();
606         std::vector<pair<PString,PString> >::iterator end_iterator = direction
607                 ? gw_entry->m_entry_data.first.end() : gw_entry->m_entry_data.second.end();
608
609         for (; rule_iterator != end_iterator; ++rule_iterator) {
610         
611                 key = (*rule_iterator).first;
612                         
613                 const int len = MatchPrefix(data, key);
614                 if (len > 0 || (len == 0 && key[0] == '!')) {
615                         // Start rewrite
616                         value = (*rule_iterator).second;
617                                 
618                         if (len > 0)
619                                 value = RewriteString(data, key, value);
620                         else
621                                 value = value + data;
622
623                         // Log
624                         PTRACE(2, "\tGWRewriteTool::RewritePString: " << data << " to " << value);
625
626                         // Finish rewrite
627                         data = value;
628                         return true;
629                 }
630         }
631
632         return false;
633 }
634
635 void Toolkit::GWRewriteTool::PrintData() {
636
637         std::vector<pair<PString,PString> >::iterator rule_iterator;
638
639         PTRACE(2, "GK\tLoaded per GW rewrite data:");
640
641         if (m_GWRewrite.GetSize() == 0) {
642                 PTRACE(2, "GK\tNo per GW data loaded");
643                 return;
644         }
645
646         for (PINDEX i = 0; i < m_GWRewrite.GetSize(); ++i) {
647
648                 // In
649                 for (rule_iterator = m_GWRewrite.GetDataAt(i).m_entry_data.first.begin(); rule_iterator != m_GWRewrite.GetDataAt(i).m_entry_data.first.end(); ++rule_iterator) {
650                         PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << " (in): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
651                 }
652
653                 // Out
654                 for (rule_iterator = m_GWRewrite.GetDataAt(i).m_entry_data.second.begin(); rule_iterator != m_GWRewrite.GetDataAt(i).m_entry_data.second.end(); ++rule_iterator) {
655                         PTRACE(3, "GK\t" << m_GWRewrite.GetKeyAt(i) << " (out): " << (*rule_iterator).first << " = " << (*rule_iterator).second);
656                 }
657
658         }
659
660         PTRACE(2, "GK\tLoaded " << m_GWRewrite.GetSize() << " GW entries with rewrite info");
661
662 }
663
664
665 void Toolkit::GWRewriteTool::LoadConfig(PConfig *config) {
666
667         PINDEX gw_size, i, j, lines_size;
668         PString key, cfg_value;
669         PStringArray lines, tokenised_line;
670         GWRewriteEntry *gw_entry;
671         std::map<PString,PString> in_strings, out_strings;
672         vector<std::pair<PString,PString> > sorted_in_strings, sorted_out_strings;
673         std::map<PString,PString>::reverse_iterator strings_iterator;
674         pair<PString,PString> rule;
675
676         PStringToString cfgs(config->GetAllKeyValues(GWRewriteSection));
677
678         // Clear old config
679         for (i = 0; i < m_GWRewrite.GetSize(); ++i) {
680                 delete &(m_GWRewrite.GetDataAt(i));
681         }
682         m_GWRewrite.RemoveAll();
683
684         gw_size = cfgs.GetSize();
685         if (gw_size > 0) {
686                 for (i = 0; i < gw_size; ++i) {
687
688                         // Get the config keys
689                         key = cfgs.GetKeyAt(i);
690                         cfg_value = cfgs[key];
691
692                         in_strings.clear();
693                         out_strings.clear();
694                         sorted_in_strings.clear();
695                         sorted_out_strings.clear();
696
697                         // Split the config data into seperate lines
698                         lines = cfg_value.Tokenise(PString(";"));
699
700                         lines_size = lines.GetSize();
701
702                         for (j = 0; j < lines_size; ++j) {
703
704                                 // Split the config line into three strings, direction, from string, to string
705                                 tokenised_line = lines[j].Tokenise(PString("="));
706
707                                 if (tokenised_line.GetSize() < 3) {
708                                         PTRACE(0, "GK\tSyntax error in the GWRewriteE164 rule - missing =, rule: " 
709                                                 << key << " => " << lines[j]
710                                                 );
711                                         continue;
712                                 }
713
714                                 // Put into appropriate std::map
715
716                                 if (tokenised_line[0] == "in")
717                                         in_strings[tokenised_line[1]] = tokenised_line[2];
718                                 else if (tokenised_line[0] == "out")
719                                         out_strings[tokenised_line[1]] = tokenised_line[2];
720                                 else
721                                         PTRACE(0, "GK\tSyntax error in the GWRewriteE164 rule - unknown rule type ("
722                                                 << tokenised_line[0] << ", rule: " << key << " => " << lines[j]
723                                                 );
724                         }
725
726                         // Put the map contents into reverse sorted vectors
727                         for (strings_iterator = in_strings.rbegin(); strings_iterator != in_strings.rend(); ++strings_iterator) {
728                                 rule = *strings_iterator;
729                                 sorted_in_strings.push_back(rule);
730                         }
731                         for (strings_iterator = out_strings.rbegin(); strings_iterator != out_strings.rend(); ++strings_iterator) {
732                                 rule = *strings_iterator;
733                                 sorted_out_strings.push_back(rule);
734                         }
735
736
737                         // Create the entry
738                         gw_entry = new GWRewriteEntry();
739                         gw_entry->m_entry_data.first = sorted_in_strings;
740                         gw_entry->m_entry_data.second = sorted_out_strings;
741
742
743                         // Add to PDictionary hash table
744                         m_GWRewrite.Insert(key,gw_entry);
745
746                 }
747         }
748
749         PrintData();
750 }
751
752
753
754
755 Toolkit::Toolkit() : Singleton<Toolkit>("Toolkit"), 
756         m_Config(NULL), m_ConfigDirty(false),
757         m_acctSessionCounter(0), m_acctSessionBase((long)time(NULL)),
758         m_timerManager(new GkTimerManager()),
759         m_timestampFormatStr("Cisco"),
760         m_encKeyPaddingByte(-1), m_encryptAllPasswords(false),
761         m_cliRewrite(NULL)
762 {
763         srand(time(0));
764 }
765
766 Toolkit::~Toolkit()
767 {
768         if (m_Config) {
769                 delete m_Config;
770                 PFile::Remove(m_tmpconfig);
771                 PFile::Remove(m_extConfigFilePath);
772         }
773         delete m_timerManager;
774         delete m_cliRewrite;
775 }
776
777 Toolkit::RouteTable *Toolkit::GetRouteTable(bool real)
778 {
779         return real ? &m_RouteTable : m_VirtualRouteTable.IsEmpty() ? &m_RouteTable : &m_VirtualRouteTable;
780 }
781
782 PConfig* Toolkit::Config()
783 {
784         // Make sure the config would not be called before SetConfig
785         PAssert(!m_ConfigDefaultSection, "Error: Call Config() before SetConfig()!");
786         return (m_Config == NULL) ? ReloadConfig() : m_Config;
787 }
788
789 PConfig* Toolkit::Config(const char *section)
790 {
791         Config()->SetDefaultSection(section);
792         return m_Config;
793 }
794
795 PConfig* Toolkit::SetConfig(const PFilePath &fp, const PString &section)
796 {
797         m_ConfigFilePath = fp;
798         m_ConfigDefaultSection = section;
799
800         return ReloadConfig();
801 }
802
803 void Toolkit::SetConfig(int act, const PString & sec, const PString & key, const PString & value)
804 {
805         // the original config
806         PConfig cfg(m_ConfigFilePath, m_ConfigDefaultSection);
807         switch (act)
808         {
809                 case 1:
810                         cfg.SetString(sec, key, value);
811                         m_Config->SetString(sec, key, value);
812                         break;
813                 case 2:
814                         cfg.DeleteKey(sec, key);
815                         m_Config->DeleteKey(sec, key);
816                         break;
817                 case 3:
818                         cfg.DeleteSection(sec);
819                         m_Config->DeleteSection(sec);
820                         break;
821         }
822
823         m_ConfigDirty = true;
824 }
825
826 PString Toolkit::GetTempDir() const
827 {
828         PString tmpdir;
829         
830 #ifndef _WIN32
831         // check if the directory exists and is accessible (access rights)
832         if (PFile::Exists("/tmp") && PFile::Access("/tmp", PFile::ReadWrite))
833                 tmpdir = "/tmp";
834         else 
835 #endif
836         {
837                 PConfig cfg(PConfig::Environment);
838                 
839                 if (cfg.HasKey("TMP"))
840                         tmpdir = cfg.GetString("TMP");
841                 else if (cfg.HasKey("TEMP"))
842                         tmpdir = cfg.GetString("TEMP");
843                 else if (cfg.HasKey("TMPDIR"))
844                         tmpdir = cfg.GetString("TMPDIR");
845         }
846         
847         if (!tmpdir.IsEmpty()) {
848                 // strip trailing separator
849                 if (tmpdir[tmpdir.GetLength()-1] == PDIR_SEPARATOR)
850                         tmpdir = tmpdir.Left(tmpdir.GetLength()-1);
851                         
852                 // check if the directory exists and is accessible (access rights)
853                 if (!(PFile::Exists(tmpdir) && PFile::Access(tmpdir, PFile::ReadWrite)))
854                         tmpdir = PString();
855         }
856         
857         return tmpdir;
858 }
859
860 void Toolkit::CreateConfig()
861 {
862         if (m_Config != NULL)
863                 PFile::Remove(m_tmpconfig);
864
865         PString tmpdir = GetTempDir();
866         
867 #ifdef _WIN32
868         if (tmpdir.IsEmpty())
869                 if (PFile::Access(".", PFile::ReadWrite))
870                         tmpdir = ".";
871                 else {
872                         const PFilePath fpath(m_ConfigFilePath);
873                         tmpdir = fpath.GetDirectory();
874                 }
875 #else
876         if (tmpdir.IsEmpty())
877                 tmpdir = ".";
878 #endif
879         
880         // generate a unique name
881         do {
882                 m_tmpconfig = tmpdir + PDIR_SEPARATOR + "gnugk.ini-" + PString(PString::Unsigned, rand()%10000);
883                 PTRACE(5, "GK\tTrying file name "<< m_tmpconfig << " for temp config");
884         } while (PFile::Exists(m_tmpconfig));
885
886 #ifdef _WIN32
887         // Does WIN32 support symlink?
888         if (PFile::Copy(m_ConfigFilePath, m_tmpconfig)) {
889 #else
890         if (symlink(m_ConfigFilePath, m_tmpconfig) == 0) {
891 #endif
892                 delete m_Config;
893                 m_Config = new PConfig(m_tmpconfig, m_ConfigDefaultSection);
894         } else { // Oops! Create temporary config file failed, use the original one
895                 PTRACE(0, "CONFIG\tCould not create/link config to a temporary file " << m_tmpconfig);
896                 delete m_Config;
897                 m_Config = new PConfig(m_ConfigFilePath, m_ConfigDefaultSection);
898         }
899
900         if (!m_extConfigFilePath)
901                 PFile::Remove(m_extConfigFilePath);
902         
903         // generate a unique name
904         do {
905                 m_extConfigFilePath = tmpdir + PDIR_SEPARATOR + "gnugk.ini-" + PString(PString::Unsigned, rand()%10000);
906                 PTRACE(5, "GK\tTrying file name "<< m_extConfigFilePath << " for external config");
907         } while (PFile::Exists(m_extConfigFilePath));
908
909         m_Config = new GatekeeperConfig(
910                 m_extConfigFilePath, m_ConfigDefaultSection, m_Config
911                 );
912 }
913
914 void Toolkit::ReloadSQLConfig()
915 {
916 #if HAS_MYSQL || HAS_PGSQL || HAS_FIREBIRD
917         if (m_Config->GetSections().GetStringsIndex("SQLConfig") == P_MAX_INDEX)
918                 return;
919
920         const PString driverName = m_Config->GetString("SQLConfig", "Driver", "");
921         if (driverName.IsEmpty()) {
922                 PTRACE(0, "SQLCONF\tFailed to read config settings from SQL: no driver specified");
923                 return;
924         }
925                 
926         GkSQLConnection *sqlConn = GkSQLConnection::Create(driverName, "SQLCONF");
927         if (sqlConn == NULL) {
928                 PTRACE(0, "SQLCONF\tFailed to create a connection: no driver found for "
929                                 << driverName << " database"
930                                 );
931                 return;
932         }
933         
934         if (!sqlConn->Initialize(m_Config, "SQLConfig")) {
935                 delete sqlConn;
936                 sqlConn = NULL;
937                 PTRACE(0, "SQLCONF\tFailed to read config settings from SQL: could not connect to the database");
938                 return;
939         }
940
941         PTRACE(3, "SQLCONF\tSQL config connection established");
942         
943         PString query;
944         GkSQLResult* queryResult;
945
946         query = m_Config->GetString("SQLConfig", "ConfigQuery", "");
947         if (!query.IsEmpty()) {
948                 PTRACE(4, "SQLCONF\tLoading config key=>value pairs from SQL database");
949                 PStringArray params;
950                 params += GKName();
951                 queryResult = sqlConn->ExecuteQuery(query, &params);
952                 if (queryResult == NULL)
953                         PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
954                                 "database: timeout or fatal error"
955                                 );
956                 else if (!queryResult->IsValid())
957                         PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
958                                 "database (" << queryResult->GetErrorCode() << "): " 
959                                 << queryResult->GetErrorMessage()
960                                 );
961                 else if (queryResult->GetNumFields() < 3)
962                         PTRACE(0, "SQLCONF\tFailed to load config key=>value pairs from SQL "
963                                 "database: at least 3 columns must be present in the result set"
964                                 );
965                 else {
966                         while (queryResult->FetchRow(params))
967                                 if (params[0].IsEmpty() || params[1].IsEmpty())
968                                         PTRACE(1, "SQLCONF\tInvalid config key=>value pair entry found "
969                                                 "in the SQL database: '[" << params[0] << "] " 
970                                                 << params[1] << '=' << params[1] << '\''
971                                                 );
972                                 else {
973                                         m_Config->SetString(params[0], params[1], params[2]);
974                                         PTRACE(6, "SQLCONF\tConfig entry read: '[" << params[0] 
975                                                 << "] " << params[1] << '=' << params[2] << '\''
976                                                 );
977                                 }
978                         PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() 
979                                 << " config key=>value pairs loaded from SQL database");
980                 }
981                 delete queryResult;
982                 queryResult = NULL;
983         }
984                         
985
986         query = m_Config->GetString("SQLConfig", "RewriteE164Query", "");
987         if (!query.IsEmpty()) {
988                 PTRACE(4, "SQLCONF\tLoading rewrite rules from SQL database");
989                 PStringArray params;
990                 params += GKName();
991                 queryResult = sqlConn->ExecuteQuery(query, &params);
992                 if (queryResult == NULL)
993                         PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database: "
994                                 "timeout or fatal error"
995                                 );
996                 else if (!queryResult->IsValid())
997                         PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database ("
998                                 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
999                                 );
1000                 else if (queryResult->GetNumFields() < 2)
1001                         PTRACE(0, "SQLCONF\tFailed to load rewrite rules from SQL database: "
1002                                 "at least 2 columns must be present in the result set"
1003                                 );
1004                 else {
1005                         while (queryResult->FetchRow(params))
1006                                 if (params[0].IsEmpty())
1007                                         PTRACE(1, "SQLCONF\tInvalid rewrite rule found in the SQL "
1008                                                 "database: '" << params[0] << '=' << params[1] << '\''
1009                                                 );
1010                                 else {
1011                                         m_Config->SetString("RasSrv::RewriteE164", params[0], params[1]);
1012                                         PTRACE(6, "SQLCONF\tRewrite rule read: '" << params[0] 
1013                                                 << '=' << params[1] << '\''
1014                                                 );
1015                                 }
1016                         PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " rewrite rules "
1017                                 "loaded from SQL database"
1018                                 );
1019                 }
1020                 delete queryResult;
1021                 queryResult = NULL;
1022         }
1023
1024         query = m_Config->GetString("SQLConfig", "NeighborsQuery", "");
1025         if (!query.IsEmpty()) {
1026                 PTRACE(4, "SQLCONF\tLoading neighbors from SQL database");
1027                 PStringArray params;
1028                 params += GKName();
1029                 queryResult = sqlConn->ExecuteQuery(query, &params);
1030                 if (queryResult == NULL)
1031                         PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database: "
1032                                 "timeout or fatal error"
1033                                 );
1034                 else if (!queryResult->IsValid())
1035                         PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database ("
1036                                 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
1037                                 );
1038                 else if (queryResult->GetNumFields() < 6)
1039                         PTRACE(0, "SQLCONF\tFailed to load neighbors from SQL database: "
1040                                 "at least 6 columns must be present in the result set"
1041                                 );
1042                 else {
1043                         while (queryResult->FetchRow(params)) {
1044                                 PString value;
1045                                 if (!params[5])
1046                                         value = ";" + params[5];
1047                                 if (!(params[4].IsEmpty() && value.IsEmpty()))
1048                                         value = ";" + params[4] + value;
1049                                 if (!(params[3].IsEmpty() && value.IsEmpty()))
1050                                         value = ";" + params[3] + value;
1051                                 if (!params[2])
1052                                         value = params[1] + ":" + params[2] + value;
1053                                 else
1054                                         value = params[1] + value;
1055                                 if (params[0].IsEmpty() || params[1].IsEmpty())
1056                                         PTRACE(1, "SQLCONF\tInvalid neighbor entry found in the SQL "
1057                                                 "database: '" << params[0] << '=' << value << '\''
1058                                                 );
1059                                 else {
1060                                         m_Config->SetString("RasSrv::Neighbors", params[0], value);
1061                                         PTRACE(6, "SQLCONF\tNeighbor entry read: '" << params[0] 
1062                                                 << '=' << value << '\''
1063                                                 );
1064                                 }
1065                         }
1066                         PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " neighbor entries "
1067                                 "loaded from SQL database"
1068                                 );
1069                 }
1070                 delete queryResult;
1071                 queryResult = NULL;
1072         }
1073
1074         query = m_Config->GetString("SQLConfig", "PermanentEndpointsQuery", "");
1075         if (!query.IsEmpty()) {
1076                 PTRACE(4, "SQLCONF\tLoading permanent endpoints from SQL database");
1077                 PStringArray params;
1078                 params += GKName();
1079                 queryResult = sqlConn->ExecuteQuery(query, &params);
1080                 if (queryResult == NULL)
1081                         PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL "
1082                                 "database: timeout or fatal error"
1083                                 );
1084                 else if (!queryResult->IsValid())
1085                         PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL database "
1086                                 "("     << queryResult->GetErrorCode() << "): " 
1087                                 << queryResult->GetErrorMessage()
1088                                 );
1089                 else if (queryResult->GetNumFields() < 4)
1090                         PTRACE(0, "SQLCONF\tFailed to load permanent endpoints from SQL database: "
1091                                 "at least 4 columns must be present in the result set"
1092                                 );
1093                 else {
1094                         PString key;
1095                         PString value;
1096                         while (queryResult->FetchRow(params)) {
1097                                 key = params[0];
1098                                 if (!params[1])
1099                                         key += ":" + params[1];
1100                                 value = params[2];
1101                                 if (!params[3])
1102                                         value += ";" + params[3];
1103                                 if (key.IsEmpty() || value.IsEmpty())
1104                                         PTRACE(1, "SQLCONF\tInvalid permanent endpoint entry found "
1105                                                 "in the SQL database: '" << key << '=' << value << '\''
1106                                                 );
1107                                 else {
1108                                         m_Config->SetString("RasSrv::PermanentEndpoints", key, value);
1109                                         PTRACE(6, "SQLCONF\tPermanent endpoint read: '" << key 
1110                                                 << '=' << value << '\''
1111                                                 );
1112                                 }
1113                         }
1114                         PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " permanent "
1115                                 "endpoints loaded from SQL database"
1116                                 );
1117                 }
1118                 delete queryResult;
1119                 queryResult = NULL;
1120         }
1121
1122         query = m_Config->GetString("SQLConfig", "GWPrefixesQuery", "");
1123         if (!query.IsEmpty()) {
1124                 PTRACE(4, "SQLCONF\tLoading gateway prefixes from SQL database");
1125                 PStringArray params;
1126                 params += GKName();
1127                 queryResult = sqlConn->ExecuteQuery(query, &params);
1128                 if (queryResult == NULL)
1129                         PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database: "
1130                                 "timeout or fatal error"
1131                                 );
1132                 else if (!queryResult->IsValid())
1133                         PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database ("
1134                                 << queryResult->GetErrorCode() << "): " << queryResult->GetErrorMessage()
1135                                 );
1136                 else if (queryResult->GetNumFields() < 2)
1137                         PTRACE(0, "SQLCONF\tFailed to load gateway prefixes from SQL database: "
1138                                 "at least 2 columns must be present in the result set"
1139                                 );
1140                 else {
1141                         while (queryResult->FetchRow(params))
1142                                 if (params[0].IsEmpty() || params[1].IsEmpty())
1143                                         PTRACE(1, "SQLCONF\tInvalid gateway prefixes entry found "
1144                                                 "in the SQL database: '" << params[0] << '=' 
1145                                                 << params[1] << '\''
1146                                                 );
1147                                 else {
1148                                         m_Config->SetString("RasSrv::GWPrefixes", 
1149                                                 params[0], params[1]
1150                                                 );
1151                                         PTRACE(6, "SQLCONF\tGateway prefixes read: '" << params[0]
1152                                                 << '=' << params[1] << '\''
1153                                                 );
1154                                 }
1155                         PTRACE(4, "SQLCONF\t" << queryResult->GetNumRows() << " gateway prefixes "
1156                                 "loaded from SQL database"
1157                                 );
1158                 }
1159                 delete queryResult;
1160                 queryResult = NULL;
1161         }
1162         
1163         delete sqlConn;
1164         sqlConn = NULL;
1165         PTRACE(3, "SQLCONF\tSQL config connection closed");
1166 #endif // HAS_MYSQL || HAS_PGSQL
1167 }
1168
1169 PConfig* Toolkit::ReloadConfig()
1170 {
1171         if (!m_ConfigDirty)
1172                 CreateConfig();
1173         else // the config have been changed via status port, use it directly
1174                 m_ConfigDirty = false;
1175
1176         m_GKName = Config()->GetString("Name", "OpenH323GK");
1177         
1178         m_encryptAllPasswords = Toolkit::AsBool(
1179                 Config()->GetString("EncryptAllPasswords", "0")
1180                 );
1181         if (Config()->HasKey(paddingByteConfigKey))
1182                 m_encKeyPaddingByte = Config()->GetInteger(paddingByteConfigKey, 0);
1183         else
1184                 m_encKeyPaddingByte = m_encryptAllPasswords ? 0 : -1;
1185                 
1186         ReloadSQLConfig();
1187         
1188         m_RouteTable.InitTable();
1189         m_VirtualRouteTable.InitTable();
1190         m_ProxyCriterion.LoadConfig(m_Config);
1191         m_Rewrite.LoadConfig(m_Config);
1192         m_GWRewrite.LoadConfig(m_Config);
1193         PString GKHome(m_Config->GetString("Home", ""));
1194         if (m_GKHome.empty() || !GKHome)
1195                 SetGKHome(GKHome.Tokenise(",:;", false));
1196         
1197         m_timestampFormatStr = Config()->GetString("TimestampFormat", "Cisco");
1198
1199         delete m_cliRewrite;
1200         m_cliRewrite = new CLIRewrite;
1201
1202         CapacityControl::Instance()->LoadConfig();
1203
1204         LoadCauseMap(m_Config);
1205
1206         LoadReasonMap(m_Config);
1207         
1208         return m_Config;
1209 }
1210
1211 void Toolkit::LoadCauseMap(
1212         PConfig *cfg
1213         )
1214 {
1215         memset(m_causeMap, 0, 16);
1216         
1217         if (! Toolkit::AsBool(cfg->GetString(RoutedSec, "ActivateFailover", "0")))
1218                 return;
1219
1220         PStringArray causes(cfg->GetString(RoutedSec, "FailoverCauses", "1-15,21-127").Tokenise(", \t", FALSE));
1221
1222         for (PINDEX i = 0; i < causes.GetSize(); ++i)
1223                 if (causes[i].Find('-') == P_MAX_INDEX) {
1224                         unsigned c = causes[i].AsUnsigned() & 0x7f;
1225                         m_causeMap[c >> 3] |= (1UL << (c & 7));
1226                 } else {
1227                         PStringArray causeRange(causes[i].Tokenise("- ", FALSE));
1228                         if (causeRange.GetSize() == 2) {
1229                                 unsigned cmin = causeRange[0].AsUnsigned() & 0x7f;
1230                                 unsigned cmax = causeRange[1].AsUnsigned() & 0x7f;
1231                                 for (; cmin <= cmax; ++cmin)
1232                                         m_causeMap[cmin >> 3] |= (1UL << (cmin & 7));
1233                         }
1234                 }
1235 }
1236
1237 // load H.225 reason to Q.931 cause mapping
1238 void Toolkit::LoadReasonMap(
1239         PConfig *cfg
1240         )
1241 {
1242         // default to ITU-T Recommendation H.225
1243         unsigned DefaultH225ReasonToQ931Cause[] =       {
1244                 34, 47, 3, 16, 88, 111, 38, 42, 28, 41, 17, 31, 16, 31, 20, 31, 47, 127,
1245                 31, 31, 31, 127
1246         };
1247         m_H225ReasonToQ931Cause.assign(&DefaultH225ReasonToQ931Cause[0], &DefaultH225ReasonToQ931Cause[22]);
1248
1249         for(int reason = 0; reason < H225_ReleaseCompleteReason::e_tunnelledSignallingRejected; reason++) {
1250                 PString str_reason;
1251                 str_reason.sprintf("%d", reason);
1252                 PString cause = cfg->GetString("H225toQ931", str_reason, "");
1253                 if (!cause.IsEmpty()) {
1254                         m_H225ReasonToQ931Cause[reason] = cause.AsInteger();
1255                 }
1256         }
1257
1258 }
1259
1260 BOOL Toolkit::MatchRegex(const PString &str, const PString &regexStr)
1261 {
1262         PINDEX pos=0;
1263         PRegularExpression regex(regexStr, PRegularExpression::Extended);
1264         if(regex.GetErrorCode() != PRegularExpression::NoError) {
1265                 PTRACE(2, "Errornous '"<< regex.GetErrorText() <<"' compiling regex: " << regexStr);
1266                 return FALSE;
1267         }
1268         if(!regex.Execute(str, pos)) {
1269                 PTRACE(5, "Gk\tRegex '"<<regexStr<<"' did not match '"<<str<<"'");
1270                 return FALSE;
1271         }
1272         return TRUE;
1273 }
1274
1275
1276
1277 bool Toolkit::RewriteE164(H225_AliasAddress &alias)
1278 {
1279         if ((alias.GetTag() != H225_AliasAddress::e_dialedDigits) &&
1280          (alias.GetTag() != H225_AliasAddress::e_h323_ID) &&
1281                  (alias.GetTag() != H225_AliasAddress::e_url_ID))
1282                 return FALSE;
1283
1284         PString E164 = ::AsString(alias, FALSE);
1285
1286         bool changed = RewritePString(E164);
1287         if (changed)
1288                 H323SetAliasAddress(E164, alias);
1289
1290         return changed;
1291 }
1292
1293 bool Toolkit::RewriteE164(H225_ArrayOf_AliasAddress & aliases)
1294 {
1295         bool changed = false;
1296         for (PINDEX n = 0; n < aliases.GetSize(); ++n)
1297                 changed |= RewriteE164(aliases[n]);
1298         return changed;
1299 }
1300
1301 bool Toolkit::GWRewriteE164(PString gw, bool direction, H225_AliasAddress &alias) {
1302
1303         PString E164;
1304         bool changed;
1305
1306         if (alias.GetTag() != H225_AliasAddress::e_dialedDigits) {
1307                 return false;
1308         }
1309
1310         E164 = ::AsString(alias, FALSE);
1311         changed = GWRewritePString(gw,direction,E164);
1312
1313         if (changed) {
1314                 H323SetAliasAddress(E164, alias);
1315         }
1316
1317         return changed;
1318 }
1319
1320 bool Toolkit::GWRewriteE164(PString gw, bool direction, H225_ArrayOf_AliasAddress &aliases) {
1321
1322         bool changed;
1323         PINDEX n;
1324
1325         changed = false;
1326         for (n = 0; n < aliases.GetSize(); ++n) {
1327                 changed |= GWRewriteE164(gw,direction,aliases[n]);
1328         }
1329
1330         return changed;
1331 }
1332
1333 bool Toolkit::isBehindNAT(PIPSocket::Address & externalIP) {
1334
1335    return (m_VirtualRouteTable.IsMasquerade(externalIP));
1336 }
1337
1338 std::vector<NetworkAddress> Toolkit::GetInternalNetworks() {
1339
1340     return GkConfig()->HasKey("ExternalIP") ? m_VirtualRouteTable.GetInternalNetworks() : m_RouteTable.GetInternalNetworks(); 
1341 }
1342
1343 PString Toolkit::GetGKHome(vector<PIPSocket::Address> & GKHome) const
1344 {
1345         GKHome = m_GKHome;
1346         PString result;
1347         int hsize = GKHome.size();
1348         for (int i = 0; i < hsize; ++i) {
1349                 result += GKHome[i].AsString();
1350                 if (i < hsize - 1)
1351                         result += ",";
1352         }
1353         return result;
1354 }
1355
1356 void Toolkit::SetGKHome(const PStringArray & home)
1357 {
1358         std::vector<PIPSocket::Address>::iterator begin;
1359         m_GKHome.clear();
1360         int n, i, size = home.GetSize();
1361         if (size > 0)
1362                 for (n = 0; n < size; ++n)
1363                         m_GKHome.push_back(home[n]);
1364
1365         PIPSocket::InterfaceTable it;
1366         if (PIPSocket::GetInterfaceTable(it)) {
1367                 int is = it.GetSize();
1368                 if (size > 0) {
1369                         // check if the interface is valid
1370                         for (n = 0; n < size; ++n) {
1371                                 for (i = 0; i < is; ++i)
1372                                         if (m_GKHome[n] == it[i].GetAddress())
1373                                                 break;
1374                                 if (i == is) {
1375                                         PTRACE(1, "GK\tAddress " << m_GKHome[n] << " not found"
1376                                                 " in the PWLib interface table"
1377                                                 );
1378                                         //begin = m_GKHome.begin();
1379                                         //copy(begin + n + 1, begin + size, begin + n);
1380                                         //--size, --n;
1381                                 }
1382                         }
1383                 }
1384                 if (size == 0) {
1385                         m_GKHome.clear();
1386                         size = is;
1387                         for (n = 0; n < size; ++n)
1388                                 m_GKHome.push_back(it[n].GetAddress());
1389                 }
1390                 // remove INADDR_ANY
1391                 for (n = 0; n < size; ++n)
1392                         if (m_GKHome[n] == INADDR_ANY) {
1393                                 begin = m_GKHome.begin();
1394                                 copy(begin + n + 1, begin + size, begin + n);
1395                                 --size, --n;
1396                         }
1397         }
1398
1399         // remove duplicate interfaces
1400         for (n = 0; n < size; ++n)
1401                 for (i = 0; i < n; ++i)
1402                         if (m_GKHome[n] == m_GKHome[i]) {
1403                                 begin = m_GKHome.begin();
1404                                 copy(begin + n + 1, begin + size, begin + n);
1405                                 --size, --n;
1406                                 break;
1407                         }
1408
1409         m_GKHome.resize(size);
1410         // put the default IP to the first
1411         begin = find(m_GKHome.begin(), m_GKHome.end(), m_RouteTable.GetLocalAddress());
1412         if (begin != m_GKHome.end())
1413                 swap(m_GKHome[0], *begin);
1414 }
1415
1416 int
1417 Toolkit::GetInternalExtensionCode( const unsigned &country,
1418                                    const unsigned &extension,
1419                                    const unsigned &manufacturer) const
1420 {
1421         switch (country) {
1422         case t35cOpenOrg:
1423                 switch (manufacturer) {
1424                 case t35mOpenOrg:
1425                         switch (extension) {
1426                                 case t35eFailoverRAS: return iecFailoverRAS;
1427                         }
1428                         break;
1429                 }
1430                 break;
1431                 
1432         case t35cPoland:
1433                 switch (manufacturer) {
1434                 case t35mGnuGk:
1435                         switch (extension) {
1436                         case t35eNeighborId:
1437                                 return iecNeighborId;
1438                         case t35eNATTraversal:
1439                                 return iecNATTraversal;
1440                         }
1441                         break;
1442                 }
1443                 break;
1444         }
1445
1446         // default for all other cases
1447         return iecUnknown;
1448 }
1449
1450 int Toolkit::GetInternalExtensionCode(const H225_H221NonStandard& data) const
1451 {
1452         return GetInternalExtensionCode(data.m_t35CountryCode,
1453                         data.m_t35Extension,
1454                         data.m_manufacturerCode);
1455 }
1456
1457 bool Toolkit::AsBool(const PString & str)
1458 {
1459         if (str.IsEmpty())
1460                 return false;
1461         const unsigned char c = (unsigned char)tolower(str[0]);
1462         return ( c=='t' || c=='1' || c=='y' || c=='a' );
1463 }
1464
1465 void Toolkit::GetNetworkFromString(
1466         const PString &s,
1467         PIPSocket::Address &network,
1468         PIPSocket::Address &netmask
1469         )
1470 {
1471         if (s *= "ALL") {
1472                 network = netmask = INADDR_ANY;
1473                 return;
1474         }
1475
1476         PINDEX slashPos = s.Find('/');
1477         if (slashPos == P_MAX_INDEX) {
1478                 // a single IP
1479                 static BYTE fullNetMask[16] = { 
1480                         255, 255, 255, 255, 255, 255, 255, 255,
1481                         255, 255, 255, 255, 255, 255, 255, 255
1482                         };
1483                 network = PIPSocket::Address(s);
1484                 netmask = PIPSocket::Address(network.GetSize(), fullNetMask);
1485         } else {
1486                 network = PIPSocket::Address(s.Left(slashPos));
1487                 
1488                 const PString netmaskString = s.Mid(slashPos + 1);
1489                 BYTE rawData[16];
1490                 
1491                 if (netmaskString.FindOneOf(".:") != P_MAX_INDEX) {
1492                         // netmask as a network address
1493                         netmask = PIPSocket::Address(netmaskString);
1494                 } else {
1495                         // netmask as an integer
1496                         const DWORD netmaskLen = netmaskString.AsUnsigned();
1497                         for (unsigned b = 0; b < (unsigned)(network.GetSize() * 8); b++)
1498                                 if (b < netmaskLen)
1499                                         rawData[b >> 3] |= 0x80U >> (b & 7);
1500                                 else
1501                                         rawData[b >> 3] &= ~(0x80U >> (b & 7));
1502                         netmask = PIPSocket::Address(network.GetSize(), rawData);
1503                 }
1504                 
1505                 // normalize the address
1506                 for (unsigned b = 0; b < (unsigned)(network.GetSize()); b++)
1507                         rawData[b] = network[b] & netmask[b];
1508                                 
1509                 network = PIPSocket::Address(network.GetSize(), rawData);
1510         }
1511 }
1512
1513 PString Toolkit::CypherDecode(const PString & key, const PString & crypto, int s)
1514 {
1515         size_t sz = key.GetLength();
1516         if (sz > sizeof(PTEACypher::Key))
1517                 sz = sizeof(PTEACypher::Key);
1518         PTEACypher::Key thekey;
1519         memset(&thekey, s, sizeof(PTEACypher::Key));
1520         memcpy(&thekey, (const char *)key, sz);
1521         PTEACypher cypher(thekey);
1522
1523         return cypher.Decode(crypto);
1524 }
1525
1526 PString Toolkit::GenerateAcctSessionId()
1527 {
1528         PWaitAndSignal lock( m_acctSessionMutex );
1529         return psprintf(PString("%08x%08x"),m_acctSessionBase,++m_acctSessionCounter);
1530 }
1531
1532 bool Toolkit::AsTimeInterval(
1533         /// formatted time interval string
1534         const char* inputString,
1535         /// variable to store calculated time interval on success
1536         PTimeInterval& interval
1537         )
1538 {
1539         if (inputString == NULL)
1540                 return false;
1541
1542         PTimeInterval result;
1543         bool process_next = true;
1544         bool valid = false;
1545                 
1546         while (process_next) {
1547                 char* strend = const_cast<char*>(inputString);
1548                 long val = strtol(inputString, &strend, 10);
1549                 
1550                 // no tokens found?
1551                 if (strend == inputString)
1552                         break;
1553                 
1554                 // integer range overflow
1555                 if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
1556                         valid = false;
1557                         break;
1558                 }
1559                 
1560                 valid = true;
1561                 inputString = strend;
1562                 
1563                 // the last token
1564                 if (*inputString == 0) {
1565                         result += PTimeInterval(val);
1566                         break;
1567                 }
1568
1569                 // unit specifier               
1570                 switch (*inputString)
1571                 {
1572                 case 's':
1573                         result += PTimeInterval(0,val);
1574                         break;
1575                 case 'm':
1576                         result += PTimeInterval(0,0,val);
1577                         break;
1578                 case 'h':
1579                         result += PTimeInterval(0,0,0,val);
1580                         break;
1581                 case 'd':
1582                         result += PTimeInterval(0,0,0,0,val);
1583                         break;
1584                 case 'w':
1585                         result += PTimeInterval(0,0,0,0,val*7);
1586                         break;
1587                 case 'M':
1588                         result += PTimeInterval(0,0,0,0,val*30);
1589                         break;
1590                 case 'y':
1591                         result += PTimeInterval(0,0,0,0,val*365);
1592                         break;
1593                 default:
1594                         result += PTimeInterval(val);
1595                         process_next = false;
1596                 }
1597                 
1598                 if (process_next)
1599                         inputString++;
1600         }
1601         
1602         if (valid)
1603                 interval = result;
1604         return valid;
1605 }
1606
1607 PString Toolkit::AsString(
1608         const PTime& tm, /// timestamp to convert into a string
1609         const PString& formatStr /// format string to use
1610         )
1611 {
1612         PString fmtStr = !formatStr ? formatStr : m_timestampFormatStr;
1613         if (fmtStr.IsEmpty())
1614                 return PString();
1615
1616         if (fmtStr *= "Cisco")
1617                 fmtStr = "%H:%M:%S.%u %Z %a %b %d %Y";
1618         else if (fmtStr *= "ISO8601")
1619                 return tm.AsString(PTime::LongISO8601);
1620         else if (fmtStr *= "RFC822")
1621                 return tm.AsString(PTime::RFC1123);
1622         else if (fmtStr *= "MySQL" )
1623                 fmtStr = "%Y-%m-%d %H:%M:%S";
1624         
1625         struct tm _tm;
1626         struct tm* tmptr = &_tm;
1627         time_t t = tm.GetTimeInSeconds();
1628
1629 #ifndef _WIN32
1630         if (localtime_r(&t, tmptr) != tmptr) {
1631 #else
1632         tmptr = localtime(&t);
1633         if (tmptr  == NULL) {
1634 #endif
1635                 PTRACE(0, "TOOLKIT\tCould not apply timestamp formatting - using default");
1636                 return tm.AsString( "hh:mm:ss.uuu z www MMM d yyyy" );
1637         }
1638
1639         // replace %u with microseconds - this is our extension
1640         PINDEX i = 0;
1641         PINDEX length = fmtStr.GetLength();
1642         do {
1643                 i = fmtStr.Find("%u", i);
1644                 if (i != P_MAX_INDEX) {
1645                         if (i > 0 && fmtStr[i-1] == '%') {
1646                                 i += 2;
1647                                 continue;
1648                         }
1649                         const PString us(PString::Printf, "%03d", (unsigned)tm.GetMicrosecond());
1650                         fmtStr.Splice(us, i, 2);
1651                         length += us.GetLength();
1652                         i += us.GetLength();
1653                         length -= 2;
1654                 }
1655         } while (i != P_MAX_INDEX && i < length);
1656         
1657         PString buf;
1658         
1659         buf.SetSize(128);
1660         if (strftime(buf.GetPointer(), 128, (const char*)fmtStr, tmptr) == 0) {
1661                 PTRACE(0, "TOOLKIT\tCould not apply timestamp formatting - using default");
1662                 return tm.AsString( "hh:mm:ss.uuu z www MMM d yyyy" );
1663         }
1664         
1665         buf.MakeMinimumSize();
1666         return buf;
1667 }
1668
1669 PString Toolkit::ReadPassword(
1670         const PString &cfgSection, /// config section to read
1671         const PString &cfgKey, /// config key to read an encrypted password from
1672         bool forceEncrypted
1673         )
1674 {
1675         if (cfgSection.IsEmpty() || cfgKey.IsEmpty())
1676                 return PString();
1677                 
1678         PConfig* const cfg = Config();
1679         if (!cfg->HasKey(cfgSection, cfgKey))
1680                 return PString();
1681
1682         int paddingByte = m_encKeyPaddingByte;
1683         if (cfg->HasKey(cfgSection, paddingByteConfigKey))
1684                 paddingByte = cfg->GetInteger(cfgSection, paddingByteConfigKey, 0);
1685
1686         if (paddingByte == -1)
1687                 if (forceEncrypted || m_encryptAllPasswords)
1688                         paddingByte = 0;
1689                 else
1690                         return cfg->GetString(cfgSection, cfgKey, "");
1691
1692         PTEACypher::Key encKey;
1693         memset(&encKey, paddingByte, sizeof(encKey));
1694
1695         const size_t keyLen = cfgKey.GetLength();
1696         if (keyLen > 0)
1697                 memcpy(&encKey, (const char*)cfgKey, min(keyLen, sizeof(encKey)));
1698
1699         PTEACypher cypher(encKey);
1700         PString s;
1701         if (!cypher.Decode(cfg->GetString(cfgSection, cfgKey, ""), s))
1702                 PTRACE(1, "GK\tFailed to decode config password for [" << cfgSection
1703                         << "] => " << cfgKey
1704                         );
1705         return s;
1706 }
1707
1708 void Toolkit::RewriteCLI(
1709         SetupMsg &msg
1710         ) const
1711 {
1712         m_cliRewrite->InRewrite(msg);
1713 }
1714
1715 void Toolkit::RewriteCLI(
1716         SetupMsg &msg,
1717         SetupAuthData &authData,
1718         const PIPSocket::Address &addr
1719         ) const
1720 {
1721         m_cliRewrite->OutRewrite(msg, authData, addr);
1722 }
1723
1724 void Toolkit::SetRerouteCauses(
1725         unsigned char *causeMap
1726         )
1727 {
1728         memcpy(causeMap, m_causeMap, 128/8);
1729 }
1730
1731
1732 unsigned Toolkit::MapH225ReasonToQ931Cause(
1733         int reason
1734         )
1735 {
1736         if( reason < 0 || reason > H225_ReleaseCompleteReason::e_tunnelledSignallingRejected )
1737                 return 0;
1738         else
1739                 return m_H225ReasonToQ931Cause[reason];
1740 }