]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_nationalchars.cpp
Fix m_nationalchars using a copy and paste of my unsafe copy and paste algorithm...
[user/henk/code/inspircd.git] / src / modules / m_nationalchars.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *          the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 /* Contains a code of Unreal IRCd + Bynets patch ( http://www.unrealircd.com/ and http://www.bynets.org/ )
15    Changed at 2008-06-15 - 2008-12-15
16    by Chernov-Phoenix Alexey (Phoenix@RusNet) mailto:phoenix /email address separator/ pravmail.ru */
17
18 #include "inspircd.h"
19 #include "caller.h"
20 #include <fstream>
21
22 /* $ModDesc: Provides an ability to have non-RFC1459 nicks & support for national CASEMAPPING */
23
24 DEFINE_HANDLER2(lwbNickHandler, bool, const char*, size_t);
25
26                                                                  /*,m_reverse_additionalUp[256];*/
27 static unsigned char m_reverse_additional[256],m_additionalMB[256],m_additionalUtf8[256],m_additionalUtf8range[256];
28
29 char utf8checkrest(unsigned char * mb, unsigned char cnt)
30 {
31         for (unsigned char * tmp=mb; tmp<mb+cnt; tmp++)
32         {
33                 if ((*tmp<128)||(*tmp>191))
34                         return -1;
35         }
36         return cnt+1;
37 }
38
39
40 char utf8size(unsigned char * mb)
41 {
42         if (!*mb)
43                 return -1;
44         if (!(*mb & 128))
45                 return 1;
46         if ((*mb & 224)==192)
47                 return utf8checkrest(mb+1,1);
48         if ((*mb & 240)==224)
49                 return utf8checkrest(mb+1,2);
50         if ((*mb & 248)==240)
51                 return utf8checkrest(mb+1,3);
52         return -1;
53 }
54
55
56 /* Conditions added */
57 bool lwbNickHandler::Call(const char* n, size_t max)
58 {
59         if (!n || !*n)
60                 return false;
61
62         unsigned int p = 0;
63         for (const char* i = n; *i; i++, p++)
64         {
65                 /* 1. Multibyte encodings support:  */
66                 /* 1.1. 16bit char. areas, e.g. chinese:*/
67
68                 /* if current character is the last, we DO NOT check it against multibyte table */
69                                                                  /* if there are mbtable ranges, use ONLY them. No 8bit at all */
70                 if (i[1] && m_additionalMB[0])
71                 {
72                         /* otherwise let's take a look at the current character and the following one */
73                         bool found=false;
74                         for(unsigned char * mb=m_additionalMB; (*mb) && (mb<m_additionalMB+sizeof(m_additionalMB)); mb+=4)
75                         {
76                                 if ( (i[0]>=mb[0]) && (i[0]<=mb[1]) && (i[1]>=mb[2]) && (i[1]<=mb[3]) )
77                                 {
78                                         /* multibyte range character found */
79                                         i++;p++;
80                                         found=true;
81                                         break;
82                                 }
83                         }
84                         if (found)
85                                 /* next char! */
86                                 continue;
87                         else
88                                 /* there are ranges, but incorrect char (8bit?) given, sorry */
89                                 return false;
90                 }
91
92                 /* 2. 8bit character support */
93
94                 if ( ((*i >= 'A') && (*i <= '}'))
95                         || m_reverse_additional[(unsigned char)*i])
96                 {
97                         /* "A"-"}" can occur anywhere in a nickname */
98                         continue;
99                 }
100
101                 if ((((*i >= '0') && (*i <= '9')) || (*i == '-')) && (i > n))
102                 {
103                         /* "0"-"9", "-" can occur anywhere BUT the first char of a nickname */
104                         continue;
105                 }
106
107                 /* 3.1. Check against a simple UTF-8 characters enumeration */
108                 int cursize,ncursize;    /*size of a current character*/
109                 ncursize=utf8size((unsigned char *)i);
110                 /* do check only if current multibyte character is valid UTF-8 only */
111                 if (ncursize!=-1)
112                 {
113                         bool found=false;
114                         for(unsigned char * mb=m_additionalUtf8;
115                                 (utf8size(mb)!=-1) && (mb<m_additionalUtf8+sizeof(m_additionalUtf8));
116                                 mb+=cursize)
117                         {
118                                 cursize=utf8size(mb);
119                                 /* Size differs? Pick the next! */
120                                 if (cursize!=ncursize)
121                                         continue;
122                                 if (!strncmp(i,(char *)mb,cursize))
123                                 {
124                                         i+=cursize-1;
125                                         p+=cursize-1;
126                                         found=true;
127                                         break;
128                                 }
129                         }
130                         if (found)
131                                 continue;
132                         /* 3.2. Check against an UTF-8 ranges: <start character> and <lenght of the range>.
133                         Also char. is to be checked if it is a valid UTF-8 one */
134
135                         found=false;
136                         for(unsigned char * mb=m_additionalUtf8range;
137                                 (utf8size(mb)!=-1) && (mb<m_additionalUtf8range+sizeof(m_additionalUtf8range));
138                                 mb+=cursize+1)
139                         {
140                                 cursize=utf8size(mb);
141                                 /* Size differs? Pick the next! */
142                                 if ((cursize!=ncursize)||(!mb[cursize]))
143                                         continue;
144
145                                 unsigned char uright[5]={0,0,0,0,0};
146                                 strncpy((char *)uright,(char *)mb, cursize);
147
148                                 if((uright[cursize-1]+mb[cursize]-1>0xff) && (cursize!=1))
149                                 {
150                                         uright[cursize-2]+=1;
151                                 }
152                                 uright[cursize-1]=(uright[cursize-1]+mb[cursize]-1) % 0x100;
153
154                                 if ((strncmp(i,(char *)mb,cursize)>=0) && (strncmp(i,(char *)uright,cursize)<=0))
155                                 {
156                                         i+=cursize-1;
157                                         p+=cursize-1;
158                                         found=true;
159                                         break;
160                                 }
161                         }
162                         if (found)
163                                 continue;
164                 }
165
166                 /* invalid character! abort */
167                 return false;
168         }
169
170         /* too long? or not -- pointer arithmetic rocks */
171         return (p < max);
172 }
173
174
175 class ModuleNationalChars : public Module
176 {
177         private:
178                 InspIRCd* ServerInstance;
179                 lwbNickHandler * myhandler;
180                 std::string charset,casemapping;
181                 unsigned char  m_additional[256],m_additionalUp[256],m_lower[256], m_upper[256];
182                 caller2<bool, const char*, size_t> * rememberer;
183                 bool forcequit;
184                 const unsigned char * lowermap_rememberer;
185         public:
186                 ModuleNationalChars(InspIRCd* Me)
187                         : Module(Me)
188                 {
189                         rememberer=(caller2<bool, const char*, size_t> *) malloc(sizeof(rememberer));
190                         lowermap_rememberer=national_case_insensitive_map;
191                         memcpy(m_lower,rfc_case_insensitive_map,256);
192                         national_case_insensitive_map=m_lower;
193
194                         ServerInstance=Me;
195                         *rememberer=ServerInstance->IsNick;
196                         myhandler=new lwbNickHandler(ServerInstance);
197                         ServerInstance->IsNick=myhandler;
198                         Implementation eventlist[] = { I_OnRehash, I_On005Numeric };
199                         ServerInstance->Modules->Attach(eventlist, this, 2);
200                         OnRehash(NULL, "");
201                 }
202
203                 virtual void On005Numeric(std::string &output)
204                 {
205                         std::string tmp(casemapping);
206                         tmp.insert(0,"CASEMAPPING=");
207                         SearchAndReplace(output,"CASEMAPPING=rfc1459",tmp);
208                 }
209
210                 virtual void OnRehash(User* user, const std::string &parameter)
211                 {
212                         ConfigReader* conf = new ConfigReader(ServerInstance);
213                         charset = conf->ReadValue("nationalchars", "file", 0);
214                         casemapping = conf->ReadValue("nationalchars", "casemapping", charset, 0, false);
215                         charset.insert(0,"../locales/");
216                         unsigned char * tables[7]=
217                         {
218                                 m_additional,m_additionalMB,m_additionalUp,m_lower,m_upper,
219                                 m_additionalUtf8,m_additionalUtf8range
220                         };
221                         loadtables(charset,tables,7,5);
222                         forcequit = conf->ReadFlag("nationalchars", "forcequit", 0);
223                         CheckForceQuit("National character set changed");
224                         delete conf;
225                 }
226
227                 void CheckForceQuit(const char * message)
228                 {
229                         if (!forcequit)
230                                 return;
231
232                         std::vector<User*> purge;
233                         std::vector<User*>::iterator iter;
234                         purge.clear();
235                         for (iter=ServerInstance->Users->local_users.begin();iter!=ServerInstance->Users->local_users.end();++iter)
236                         {
237                                 if (!ServerInstance->IsNick((*iter)->nick.c_str(), ServerInstance->Config->Limits.NickMax))
238                                         purge.push_back(*iter);
239                         }
240                         for (iter=purge.begin();iter!=purge.end();++iter)
241                         {
242                                 ServerInstance->Users->QuitUser((*iter), message);
243                         }
244                 }
245                 virtual ~ModuleNationalChars()
246                 {
247                         delete myhandler;
248                         ServerInstance->IsNick= *rememberer;
249                         free(rememberer);
250                         national_case_insensitive_map=lowermap_rememberer;
251                         CheckForceQuit("National characters module unloaded");
252                 }
253
254                 virtual Version GetVersion()
255                 {
256                         return Version("$Id: m_nationalchars.cpp 0 2008-12-15 14:24:12SAMT phoenix $",VF_COMMON,API_VERSION);
257                 }
258
259                 /*make an array to check against it 8bit characters a bit faster. Whether allowed or uppercase (for your needs).*/
260
261                 void makereverse(unsigned char * from, unsigned  char * to, unsigned int cnt)
262                 {
263                         memset(to, 0, cnt);
264                         for(unsigned char * n=from; (*n) && ((*n)<cnt) && (n<from+cnt); n++)
265                         {
266                                 to[*n]=1;
267                         }
268                 }
269
270                 /*so Bynets Unreal distribution stuff*/
271                 void loadtables(std::string filename, unsigned char ** tables, unsigned char cnt, char faillimit)
272                 {
273                         std::ifstream ifs(filename.c_str());
274                         if (ifs.fail())
275                         {
276                                 ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for missing file: %s", filename.c_str());
277                                 return;
278                         }
279
280                         unsigned char n;
281                         for (n=0;n<cnt;n++)
282                         {
283                                 memset(tables[n], 0, 256);
284                         }
285
286                         memcpy(m_lower,rfc_case_insensitive_map,256);
287
288                         for (n=0;n<cnt;n++)
289                         {
290                                 if (loadtable(ifs, tables[n], 255) && (n<faillimit))
291                                 {
292                                         ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() called for illegal file: %s (line %d)", filename.c_str(), n+1);
293                                         return;
294                                 }
295                         }
296                         /*                      ServerInstance->Logs->Log("m_nationalchars",DEFAULT,"loadtables() : %s", ((char *)national_case_insensitive_map)+1);*/
297
298                         makereverse(m_additional, m_reverse_additional, sizeof(m_additional));
299                         /*      Do you need faster access to additional 8bit uppercase table? No? Oh, sorry :( Let's comment this out */
300                         /*      makereverse(m_additionalUp, m_reverse_additionalUp, sizeof(m_additional)); */
301                 }
302
303                 unsigned char symtoi(const char *t,unsigned char base)
304                 /* base = 16 for hexadecimal, 10 for decimal, 8 for octal ;) */
305                 {
306                         unsigned char tmp=0,current;
307                         while ((*t)&&(*t!=' ')&&(*t!=13)&&(*t!=10)&&(*t!=','))
308                         {
309                                 tmp*=base;
310                                 current=ascii_case_insensitive_map[(unsigned char)*t];
311                                 if (current>='a')
312                                         current=current-'a'+10;
313                                 else
314                                         current=current-'0';
315                                 tmp+=current;
316                                 t++;
317                         }
318                         return tmp;
319                 }
320
321                 int loadtable(std::ifstream &ifs , unsigned char *chartable, unsigned int maxindex)
322                 {
323                         std::string buf;
324                         getline(ifs, buf);
325
326                         unsigned int i=0;
327                         int fail=0;
328
329                         buf.erase(buf.find_last_not_of("\n")+1);
330
331                         if (buf[0]=='.')         /* simple plain-text string after dot */
332                         {
333                                 i=buf.size()-1;
334                                 if (i>(maxindex+1)) i=maxindex+1;
335                                 memcpy(chartable,buf.c_str()+1,i);
336                         }
337                         else
338                         {
339                                 const char * p=buf.c_str();
340                                 while (*p)
341                                 {
342                                         if (i>maxindex)
343                                         {
344                                                 fail=1;
345                                                 break;
346                                         }
347
348                                         if (*p!='\'')/* decimal or hexadecimal char code */
349                                         {
350                                                 if (*p=='0')
351                                                 {
352                                                         if (p[1]=='x')
353                                                                  /* hex with the leading "0x" */
354                                                                 chartable[i] = symtoi(p+2,16);
355                                                         else
356                                                                 chartable[i] = symtoi(p+1,8);
357                                                 }
358                                                                  /* hex form */
359                                                 else if (*p=='x')
360                                                 {
361                                                         chartable[i] = symtoi(p+1,16);
362                                                 }else    /* decimal form */
363                                                 {
364                                                         chartable[i] = symtoi(p,10);
365                                                 }
366                                         } else           /* plain-text char between '' */
367                                         {
368                                                 if (*(p+1)=='\\')
369                                                 {
370                                                         chartable[i] = *(p+2);
371                                                         p+=3;
372                                                 }else
373                                                 {
374                                                         chartable[i] = *(p+1);
375                                                         p+=2;
376                                                 }
377                                         }
378
379                                         while (*p&& (*p!=',')&&(*p!=' ')&&(*p!=13)&&(*p!=10) ) p++;
380                                         while (*p&&((*p==',')||(*p==' ')||(*p==13)||(*p==10))) p++;
381
382                                         i++;
383
384                                 }
385                         }
386
387                         return fail;
388                 }
389
390 };
391
392 MODULE_INIT(ModuleNationalChars)