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