From Kiril, 3 Years ago, written in C.
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <limits.h>
  6.  
  7. // don't change the buffer size
  8. #define CYRBUFER 512
  9.  
  10. //utf-8 cyrillic range
  11. #define MIN_CYR_16 0xd080
  12. #define MAX_CYR_16 0xd4af
  13.  
  14. //cp1251 cyrillic range
  15. #define MIN_CYR_8  0x80
  16. #define MAX_CYR_8  0xFF
  17.  
  18. #define END_OF_IT 0x00
  19.  
  20. /*
  21.  * function transalte utf8 to cp1251 bits
  22.  */
  23. unsigned char * utf8_to_cp1251(char *stext);
  24.  
  25. /*
  26.  * function transalte cp1251 to utf8 bits
  27.  */
  28. unsigned char * cp1251_to_utf8(char *stext);
  29.  
  30. /*
  31.  * character tables
  32.  */
  33. extern const unsigned char utf8[];
  34. extern const unsigned char cp1251[];
  35. // ------
  36.  
  37.  
  38. typedef struct seensrv_ seensrv_t;
  39.  
  40. struct seensrv_
  41. {
  42.   char *nick;                   /* the IRC client's nickname  */
  43.   char *user;                   /* the IRC client's username  */
  44.   char *host;                   /* the IRC client's hostname  */
  45.   char *real;                   /* the IRC client's realname  */
  46.  
  47.   bool fantasy;                     /* enable fantasy commands    */
  48.  
  49.   char *trigger;                        /* trigger, e.g. !, ` or .    */
  50.  
  51.   service_t *me;                /* our user_t struct          */
  52.  
  53.   unsigned int seenexpire;               /* SeenServ records expire in days */
  54. };
  55.  
  56. seensrv_t seensrv;
  57.  
  58. typedef struct seen_db_ seen_db_t;
  59.  
  60. struct seen_db_
  61. {
  62.         char purp[100];
  63.         char *host;
  64.         unsigned int time_in;
  65.         unsigned int time_out;
  66.         char *reason;
  67.         int recors;
  68.         bool exactm;
  69.         int starting;
  70.         int method;
  71.         int utf8str;
  72. };
  73.  
  74. const unsigned char ToLowerTabCyr[] = {
  75.         0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
  76.         0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
  77.         0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
  78.         0x1e, 0x1f,
  79.         ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
  80.         '*', '+', ',', '-', '.', '/',
  81.         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  82.         ':', ';', '<', '=', '>', '?',
  83.         '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
  84.         'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
  85.         't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
  86.         '_',
  87.         '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
  88.         'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
  89.         't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
  90.         0x7f,
  91.         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
  92.         0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  93.         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
  94.         0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
  95.         0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
  96.         0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
  97.         0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
  98.         0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
  99.        
  100.         0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
  101.         0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
  102.         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
  103.         0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
  104.        
  105.         0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
  106.         0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
  107.         0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
  108.         0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
  109. };
  110.  
  111. int strcicmp(char const *a, char const *b, seen_db_t *dbs)
  112. {
  113.     for (;; a++, b++) {
  114.                 int d;
  115.                 if (dbs->exactm == true)
  116.                 {
  117.                         d = *a - *b;
  118.                 } else {
  119.                         d = ToLowerTabCyr[(unsigned char)(*a)] - ToLowerTabCyr[(unsigned char)(*b)];
  120.                 }
  121.         if (d != 0 || !*a)
  122.             return d;
  123.     }
  124. }
  125.  
  126. bool match_seen_mask(char *first, char * second, seen_db_t *dbs)
  127. {
  128.     if (*first == '\0' && *second == '\0')
  129.         return true;
  130.  
  131.     if (*first == '*' && *(first+1) != '\0' && *second == '\0')
  132.         return false;
  133.        
  134.     if (*first == '?' || ToLowerTabCyr[(unsigned char)(*first)] == ToLowerTabCyr[(unsigned char)(*second)] && dbs->exactm == false || *first == *second && dbs->exactm == true)
  135.         return match_seen_mask(first+1, second+1, dbs);
  136.  
  137.     if (*first == '*')
  138.         return match_seen_mask(first+1, second, dbs) || match_seen_mask(first, second+1, dbs);
  139.     return false;
  140. }
  141.  
  142. char *time_ago_seen(time_t event, time_t basis)
  143. {
  144.         static char ret[128];
  145.         int years, weeks, days, hours, minutes, seconds;
  146.     //CURRTIME
  147.         event = basis - event;
  148.         years = weeks = days = hours = minutes = 0;
  149.  
  150.         while (event >= 60 * 60 * 24 * 365)
  151.         {
  152.                 event -= 60 * 60 * 24 * 365;
  153.                 years++;
  154.         }
  155.         while (event >= 60 * 60 * 24 * 7)
  156.         {
  157.                 event -= 60 * 60 * 24 * 7;
  158.                 weeks++;
  159.         }
  160.         while (event >= 60 * 60 * 24)
  161.         {
  162.                 event -= 60 * 60 * 24;
  163.                 days++;
  164.         }
  165.         while (event >= 60 * 60)
  166.         {
  167.                 event -= 60 * 60;
  168.                 hours++;
  169.         }
  170.         while (event >= 60)
  171.         {
  172.                 event -= 60;
  173.                 minutes++;
  174.         }
  175.  
  176.         seconds = event;
  177.  
  178.         if (years)
  179.                 snprintf(ret, sizeof(ret), "%dy %dw %dd", years, weeks, days);
  180.         else if (weeks)
  181.                 snprintf(ret, sizeof(ret), "%dw %dd %dh", weeks, days, hours);
  182.         else if (days)
  183.                 snprintf(ret, sizeof(ret), "%dd %dh %dm %ds", days, hours, minutes, seconds);
  184.         else if (hours)
  185.                 snprintf(ret, sizeof(ret), "%dh %dm %ds", hours, minutes, seconds);
  186.         else if (minutes)
  187.                 snprintf(ret, sizeof(ret), "%dm %ds", minutes, seconds);
  188.         else
  189.                 snprintf(ret, sizeof(ret), "%ds", seconds);
  190.  
  191.         return ret;
  192. }
  193.  
  194. static char *get_word(char *text_line, char separator, int iword)
  195. {
  196.         int nword = 0;
  197.     char *word = (char*)malloc(sizeof(char)*(BUFSIZE+1));
  198.     int i = 0; 
  199.         while(1){
  200.             while(*text_line != separator && *text_line != '\0' &&  *text_line != '\n')
  201.             {
  202.               if(iword == nword)
  203.                                   word[i++] = *text_line;
  204.                  
  205.               text_line++;
  206.             }
  207.                            
  208.             if(*text_line == '\0')
  209.                 break;
  210.  
  211.             text_line++;
  212.             nword++;
  213.         }
  214.                    if (i == 0)
  215.                    {
  216.                      return NULL;      
  217.                       } else {
  218.                          word[i] = '\0';         
  219.                      return word;                      
  220.                    }
  221. }
  222.  
  223. int get_record(FILE *in, FILE *out, seen_db_t *dbs)
  224. {
  225.         char line[BUFSIZE], newline[BUFSIZE], reason[BUFSIZE] = "", rreason[BUFSIZE] = "";
  226.         char *host_s;
  227.         int found_it = 0;
  228.         rewind(in);
  229.    while (fgets(line , sizeof(line) ,in ) != NULL)
  230.     {
  231.       if (strcicmp(dbs->host ,get_word(line,' ', 0), dbs) == 0)
  232.       {
  233.                   found_it = 1;
  234.                   if (strcmp(dbs->purp, "P") == 0) {
  235.           snprintf(newline, sizeof newline, "%s %s %d %s\n", dbs->host, get_word(line,' ', 1), dbs->time_out, dbs->reason);      
  236.                   }
  237.                   if (strcmp(dbs->purp, "S") == 0) {
  238.                    int s = 3;
  239.                    host_s = get_word(line,' ', 3);         
  240.                    while (host_s != NULL)
  241.             {
  242.                        snprintf(rreason, sizeof rreason, " %s", host_s);
  243.                strcat(reason, rreason);
  244.                s++;                        
  245.                host_s = get_word(line,' ', s);
  246.              }
  247.           snprintf(newline, sizeof newline, "%s %d %s%s\n", dbs->host, dbs->time_in, get_word(line,' ', 2), reason);
  248.                   }
  249.                   break;
  250.       }
  251.     }
  252.         if (found_it == 1)
  253.         {
  254.            fputs(newline, out);
  255.            return 1;
  256.           } else {
  257.            return 0;
  258.         }
  259. }
  260.  
  261.  
  262. void seen_write_to_db(const char *nick, seen_db_t *dbs) {
  263.      FILE *in, *out;
  264.         char line[BUFSIZE], linebuf[BUFSIZE], newline[BUFSIZE], reason[BUFSIZE] = "", rreason[BUFSIZE] = "";
  265.         char *host_s;
  266.         char name[BUFSIZE];
  267.         char name_temp[BUFSIZE];
  268.         snprintf(name, BUFSIZE, "%s/%s", datadir, "seenserv.db");
  269.         snprintf(name_temp, BUFSIZE, "%s/%s", datadir, "seenserv.temp");
  270.        
  271.         int found_it = 0;
  272.        
  273.         user_t *target_u;
  274.        
  275.    if (!strcmp(dbs->purp, "R") == 0) {
  276.          in = fopen(name, "r" );       
  277.         out = fopen(name_temp, "w+" );
  278.  
  279.         if (get_record(in, out, dbs) == 1)
  280.         {
  281.           found_it = 1;
  282.         }
  283.    rewind(in);
  284.    while (fgets(line , sizeof(line) ,in ) != NULL)
  285.     {
  286.           strcpy(linebuf, line);
  287.       if (strcicmp(dbs->host ,get_word(line,' ', 0), dbs) == 0)
  288.       {
  289.        } else {
  290.                   if (strlen(linebuf) > 0)
  291.                    {
  292.              target_u = user_find_named(get_word(linebuf,'!', 0));
  293.                    if ((atoi(get_word(linebuf,' ', 1)) + seensrv.seenexpire * 24 * 60 * 60) > CURRTIME)
  294.                      {
  295.                            fputs(linebuf, out);  
  296.                      } else if(target_u != NULL)
  297.                          {
  298.                            snprintf(reason, sizeof reason, "%s!%s@%s", target_u->nick, target_u->user, target_u->vhost);
  299.                            if(strcicmp(dbs->host ,reason, dbs) == 0)
  300.                            {
  301.                                 fputs(linebuf, out);
  302.                            }                               
  303.                          }
  304.                }
  305.             }
  306.      }
  307.           if(found_it == 0)
  308.           {
  309.                  snprintf(newline, sizeof newline, "%s %d 0 \n", dbs->host, dbs->time_in);
  310.                  fputs(newline, out);
  311.           }
  312.     fclose(in);
  313.         fclose(out);
  314.         remove(name);
  315.         rename(name_temp, name);
  316.    } else {
  317.         char *result[9];
  318.         char *hostc, *nick_s;
  319.         char lineto[BUFSIZE], fline[BUFSIZE], eline[BUFSIZE];
  320.     int count = 0, scount = 0, current = 0, mcount = 0;
  321.         myuser_t *mu;
  322.         time_t time_login, time_singout;
  323.         in = fopen( name, "r" );
  324.      while (fgets(line , sizeof(line) ,in ) != NULL)
  325.     {
  326.            strcpy(lineto, line);
  327.            nick_s = get_word(line,'!', 0);
  328.       if (match_seen_mask(dbs->host, get_word(line,' ', 0), dbs) && dbs->method == 1 || match_seen_mask(dbs->host, nick_s, dbs) && dbs->method == 0 || strcicmp(dbs->host, nick_s, dbs) == 0)
  329.       {
  330.                target_u = user_find_named(nick_s);
  331.               if (strcicmp(dbs->host, nick_s, dbs) == 0 && target_u)
  332.               {
  333.             goto isonlinenow;
  334.               }          
  335.                   if(mcount >= (dbs->starting - 1))
  336.                   {
  337.                   if (count < dbs->recors)
  338.                   {
  339.                         result[count] = (char*)malloc(1024*sizeof(char));
  340.                     strcpy(result[count], lineto);
  341.             current++;                 
  342.               }
  343.           count++;
  344.                  }
  345.             mcount++;
  346.           }
  347.          
  348.             if(scount > 100000)
  349.                   {
  350.                         break;                 
  351.                   }
  352.                scount++;
  353.     }
  354.         fclose(in);
  355.        
  356.         if (scount > 100000)
  357.         {
  358.      notice("SeenServ", nick, "There are more than\2 100000\2 matches to your query; please refine it to see any output");     
  359.         } else {
  360.           if (current == 0)
  361.           {
  362.             notice("SeenServ", nick, "No search results for \2%s", dbs->host);
  363.           }     else {
  364.            int i;
  365.            notice("SeenServ", nick, "There are \2%i\2 results in the database; displaying max \2%i\2 starting from number \2%i\2: ", (count + dbs->starting - 1 ), current, dbs->starting);
  366.            for (i = 0; i < current; i++)
  367.            {
  368.                  int m = 3;
  369.                  strcpy(eline, "");
  370.                  strcpy(lineto, result[i]);
  371.                  snprintf(fline, sizeof fline, "\2%s\2 ", get_word(lineto,'!', 0));      
  372.                  strcat(eline, fline);
  373.                  snprintf(fline, sizeof fline, "(\2%s\2) ", get_word(get_word(lineto,' ', 0), '!', 1));
  374.                  strcat(eline, fline);
  375.                                
  376.                  time_login = atoi(get_word(lineto,' ', 1));
  377.  
  378.                  time_singout = atoi(get_word(lineto,' ', 2));
  379.                  
  380.                  if (time_singout != 0)
  381.                  {
  382.                  snprintf(fline, sizeof fline, "was online \2%s\2 ago ", time_ago_seen(time_singout, CURRTIME));
  383.                  strcat(eline, fline); 
  384.            if (time_login < time_singout)
  385.                    {
  386.                      snprintf(fline, sizeof fline, "for \2%s\2", time_ago_seen(time_login, time_singout));
  387.                      strcat(eline, fline);                                 
  388.                    } else {
  389.                      snprintf(fline, sizeof fline, "for \2%s\2", time_ago_seen(time_login, CURRTIME));
  390.                      strcat(eline, fline);                                 
  391.                    }             
  392.                  } else {
  393.                  snprintf(fline, sizeof fline, "was online \2%s\2 ago ", time_ago_seen(time_login, CURRTIME));
  394.                  strcat(eline, fline);                           
  395.                  }
  396.  
  397.                  mu = myuser_find_ext(get_word(lineto,'!', 0));
  398.                   if (mu != NULL)
  399.                         {
  400.                           if(mu->lastlogin > time_login)
  401.                           {
  402.                          snprintf(fline, sizeof fline, " | NickServ: \2Yes\2 |");
  403.                          strcat(eline, fline);                                   
  404.                           } else {
  405.                          snprintf(fline, sizeof fline, " | NickServ: \2No\2 |");
  406.                          strcat(eline, fline);                                   
  407.                           }
  408.                         } else {
  409.                          snprintf(fline, sizeof fline, " | NickServ: \2No\2 |");
  410.                          strcat(eline, fline);                                         
  411.                         }
  412.                        
  413.                         hostc = get_word(lineto,' ', 3);               
  414.                         while (hostc != NULL)
  415.             {
  416.                         snprintf(fline, sizeof fline, " %s", hostc);
  417.                         strcat(eline, fline);
  418.                         m++;
  419.                         hostc = get_word(lineto,' ', m);
  420.                         }
  421.              notice("SeenServ", nick, "[%d] %s", (i + 1), eline);
  422.              free(result[i]);
  423.             }                    
  424.           }
  425.           goto endd;
  426.           isonlinenow:
  427.           notice("SeenServ", nick, "\2%s (%s@%s)\2 is currently online.", target_u->nick, target_u->user, target_u->vhost);
  428.           endd:;
  429.         }
  430.   }
  431. }
  432.  
  433. /*
  434.  * match_utf_cyr match the utf-8 character cyrillic range
  435.  */
  436.  
  437. int match_utf_cyr(char *stext)
  438. {
  439.     int i, m, s;
  440.     i = 0; m = 0; s = 0;
  441.         char text[CYRBUFER];
  442.         memset(text, 0, CYRBUFER);
  443.         strcpy(text, stext);
  444.         for (i = 0 ; i <  sizeof text; i++) {
  445.           if ((unsigned char)(text[i]) != END_OF_IT) {
  446.                 if (s == 0) {
  447.                 if (((((unsigned char)text[i]<<8) | (unsigned char)text[i+1]) >= 0xd090) && ((((unsigned char)text[i]<<8) | (unsigned char)text[i+1]) <= 0xd18f)) {
  448.           m++; s = 1;
  449.             } else if ((unsigned char)text[i] >= 0x80 && (unsigned char)text[i] <= 0xFF) {
  450.                   //return FALSE;      
  451.                 } else if ((unsigned char)text[i] >= 0x21 && (unsigned char)text[i] <= 0x7E && (unsigned char)text[i] != 0x2a && (unsigned char)text[i] != 0x3f) {
  452.                   //return FALSE;
  453.                 }
  454.            } else {
  455.                   if ((unsigned char)text[i] >= 0x21 && (unsigned char)text[i] <= 0x7E  && (unsigned char)text[i] != 0x2a && (unsigned char)text[i] != 0x3f) {
  456.                           //return FALSE;
  457.                   }
  458.             s = 0;
  459.             }
  460.            } else {break;}
  461.    }
  462.        if (m > 1) {return TRUE;} else {return FALSE;}
  463. }
  464.  
  465. /*
  466.  * cp1251_to_utf8 translate cyrillic range ONLY from cp1251 to utf-8
  467.  */
  468.  
  469. unsigned char * cp1251_to_utf8(char *stext)
  470. {
  471.         int i, m, s;
  472.         char text[CYRBUFER];
  473.         static unsigned char output[CYRBUFER];
  474.         memset(text, 0, CYRBUFER);
  475.         strcpy(text, stext);
  476.         s = 0;
  477.         for (i = 0 ; i <  sizeof text; i++) {
  478.                 if ((unsigned char)text[i] >= MIN_CYR_8 && (unsigned char)text[i] <= MAX_CYR_8) {
  479.             for (m = 0; m < strlen((char*)cp1251); m++) {
  480.               if ((unsigned char)text[i] == cp1251[m]) {
  481.                                 output[s] = utf8[m*2];
  482.                                 output[s+1] = utf8[m*2+1];
  483.                                 s+=2;
  484.                 // if the symbol does not exists in cp1251 do nothing
  485.                                 goto searchOK;
  486.                            }
  487.                      }
  488.                       searchOK:;
  489.                 } else {
  490.                     output[s] = text[i];
  491.                     s++;
  492.                  }
  493.    }
  494.         return output;
  495. }
  496.  
  497. /*
  498.  * cp1251_to_utf8 translate cyrillic range ONLY from utf-8 to cp1251
  499.  */
  500.  
  501. unsigned char * utf8_to_cp1251(char *stext)
  502. {
  503.         int i, m, s, sh;
  504.         char text[CYRBUFER];
  505.         static unsigned char output[CYRBUFER];
  506.         memset(output, 0, CYRBUFER);
  507.         memset(text, 0, CYRBUFER);
  508.         strcpy(text, stext);
  509.         sh = 0; s = 0;
  510.         for (i = 0 ; i <  sizeof text; i++) {
  511.                 if ((unsigned char)(text[i]) != END_OF_IT) {
  512.                 if ((((unsigned char)text[i]<<8) | (unsigned char)text[i+1]) >= MIN_CYR_16 && (((unsigned char)text[i]<<8) | (unsigned char)text[i+1]) <= MAX_CYR_16) {
  513.             for (m = 0; m < strlen((char*)utf8); m+= 2) {
  514.               if ((unsigned char)text[i] == utf8[m] && (unsigned char)text[i+1] == utf8[m + 1]) {
  515.                                 output[s] = cp1251[m/2];
  516.                                 s++;
  517.                                 sh = 1;
  518.                                 // if the symbol does not exists in utf-8 do nothing
  519.                                 goto searchOK;
  520.                            }
  521.                      }
  522.                       searchOK:;
  523.                 } else {
  524.                                 if (sh == 0) {
  525.                                     output[s] = text[i];
  526.                                     s++;
  527.                                 } else {
  528.                                         sh = 0;
  529.                                 }
  530.                  }
  531.          } else {break;}
  532.    }
  533.         return output;
  534. }
  535.  
  536. /*
  537.  * utf-8 cyrillic characters split by 8-bit
  538.  * two 8-bit values is equal to one utf-8 hexadecimal character
  539.  */
  540.  
  541. const unsigned char utf8[] = {
  542.            /*?*/       /*?*/       /*?*/       /*?*/
  543.     0xd0, 0x82, 0xd0, 0x83, 0xd1, 0x93, 0xd0, 0x89,
  544.        /*?*/       /*?*/       /*?*/       /*?*/
  545.     0xd0, 0x8a, 0xd0, 0x8c, 0xd0, 0x8b, 0xd0, 0x8f,
  546.        /*?*/       /*?*/       /*?*/       /*?*/
  547.     0xd1, 0x92, 0xd1, 0x99, 0xd1, 0x9a, 0xd1, 0x9c,
  548.        /*?*/       /*?*/       /*?*/       /*?*/
  549.     0xd1, 0x9b, 0xd1, 0x9f, 0xd0, 0x8e, 0xd1, 0x9e,
  550.        /*?*/       /*?*/       /*?*/       /*?*/
  551.     0xd0, 0x88, 0xd2, 0x90, 0xd0, 0x81, 0xd0, 0x84,
  552.        /*?*/       /*?*/       /*?*/       /*?*/
  553.     0xd0, 0x87, 0xd0, 0x86, 0xd1, 0x96, 0xd2, 0x91,
  554.        /*?*/       /*?*/       /*?*/       /*?*/
  555.     0xd1, 0x91, 0xd1, 0x94, 0xd1, 0x98, 0xd1, 0x95,
  556.        /*?*/       /*?*/       /*?*/       /*?*/
  557.     0xd1, 0x95, 0xd1, 0x97, 0xd0, 0x90, 0xd0, 0x91,
  558.        /*?*/       /*?*/       /*?*/       /*?*/
  559.     0xd0, 0x92, 0xd0, 0x93, 0xd0, 0x94, 0xd0, 0x95,
  560.        /*?*/       /*?*/       /*?*/       /*?*/
  561.     0xd0, 0x96, 0xd0, 0x97, 0xd0, 0x98, 0xd0, 0x99,
  562.        /*?*/       /*?*/       /*?*/       /*?*/
  563.     0xd0, 0x9a, 0xd0, 0x9b, 0xd0, 0x9c, 0xd0, 0x9d,
  564.        /*?*/       /*?*/       /*?*/       /*?*/
  565.     0xd0, 0x9e, 0xd0, 0x9f, 0xd0, 0xa0, 0xd0, 0xa1,
  566.        /*?*/       /*?*/       /*?*/       /*?*/
  567.     0xd0, 0xa2, 0xd0, 0xa3, 0xd0, 0xa4, 0xd0, 0xa5,
  568.        /*?*/       /*?*/       /*?*/       /*?*/
  569.     0xd0, 0xa6, 0xd0, 0xa7, 0xd0, 0xa8, 0xd0, 0xa9,
  570.        /*?*/       /*?*/       /*?*/       /*?*/
  571.     0xd0, 0xaa, 0xd0, 0xab, 0xd0, 0xac, 0xd0, 0xad,
  572.        /*?*/       /*?*/       /*?*/       /*?*/
  573.     0xd0, 0xae, 0xd0, 0xaf, 0xd0, 0xb0, 0xd0, 0xb1,
  574.        /*?*/       /*?*/       /*?*/       /*?*/
  575.     0xd0, 0xb2, 0xd0, 0xb3, 0xd0, 0xb4, 0xd0, 0xb5,
  576.        /*?*/       /*?*/       /*?*/       /*?*/
  577.     0xd0, 0xb6, 0xd0, 0xb7, 0xd0, 0xb8, 0xd0, 0xb9,
  578.        /*?*/       /*?*/       /*?*/       /*?*/
  579.     0xd0, 0xba, 0xd0, 0xbb, 0xd0, 0xbc, 0xd0, 0xbd,
  580.        /*?*/       /*?*/       /*?*/       /*?*/
  581.     0xd0, 0xbe, 0xd0, 0xbf, 0xd1, 0x80, 0xd1, 0x81,
  582.        /*?*/       /*?*/       /*?*/       /*?*/
  583.     0xd1, 0x82, 0xd1, 0x83, 0xd1, 0x84, 0xd1, 0x85,
  584.        /*?*/       /*?*/       /*?*/       /*?*/
  585.     0xd1, 0x86, 0xd1, 0x87, 0xd1, 0x88, 0xd1, 0x89,
  586.        /*?*/       /*?*/       /*?*/       /*?*/
  587.     0xd1, 0x8a, 0xd1, 0x8b, 0xd1, 0x8c, 0xd1, 0x8d,
  588.        /*?*/       /*?*/
  589.     0xd1, 0x8e, 0xd1, 0x8f
  590. };
  591.  
  592. /*
  593.  * cp1251 cyrillic characters in 8-bit
  594.  */
  595.  
  596. const unsigned char cp1251[] = {
  597.         /*?*/ /*?*/ /*?*/ /*?*/
  598.     0x80, 0x81, 0x83, 0x8a,
  599.     /*?*/ /*?*/ /*?*/ /*?*/
  600.     0x8c, 0x8d, 0x8e, 0x8f,
  601.     /*?*/ /*?*/ /*?*/ /*?*/
  602.     0x90, 0x9a, 0x9c, 0x9d,
  603.     /*?*/ /*?*/ /*?*/ /*?*/
  604.     0x9e, 0x9f, 0xa1, 0xa2,
  605.     /*?*/ /*?*/ /*?*/ /*?*/
  606.     0xa3, 0xa5, 0xa8, 0xaa,
  607.     /*?*/ /*?*/ /*?*/ /*?*/
  608.     0xaf, 0xb2, 0xb3, 0xb4,
  609.     /*?*/ /*?*/ /*?*/ /*?*/
  610.     0xb8, 0xba, 0xbc, 0xbd,
  611.     /*?*/ /*?*/ /*?*/ /*?*/
  612.     0xbe, 0xbf, 0xc0, 0xc1,
  613.     /*?*/ /*?*/ /*?*/ /*?*/
  614.     0xc2, 0xc3, 0xc4, 0xc5,
  615.     /*?*/ /*?*/ /*?*/ /*?*/
  616.     0xc6, 0xc7, 0xc8, 0xc9,
  617.     /*?*/ /*?*/ /*?*/ /*?*/
  618.     0xca, 0xcb, 0xcc, 0xcd,
  619.     /*?*/ /*?*/ /*?*/ /*?*/
  620.     0xce, 0xcf, 0xd0, 0xd1,
  621.     /*?*/ /*?*/ /*?*/ /*?*/
  622.     0xd2, 0xd3, 0xd4, 0xd5,
  623.     /*?*/ /*?*/ /*?*/ /*?*/
  624.     0xd6, 0xd7, 0xd8, 0xd9,
  625.     /*?*/ /*?*/ /*?*/ /*?*/
  626.     0xda, 0xdb, 0xdc, 0xdd,
  627.     /*?*/ /*?*/ /*?*/ /*?*/
  628.     0xde, 0xdf, 0xe0, 0xe1,
  629.     /*?*/ /*?*/ /*?*/ /*?*/
  630.     0xe2, 0xe3, 0xe4, 0xe5,
  631.     /*?*/ /*?*/ /*?*/ /*?*/
  632.     0xe6, 0xe7, 0xe8, 0xe9,
  633.     /*?*/ /*?*/ /*?*/ /*?*/
  634.     0xea, 0xeb, 0xec, 0xed,
  635.     /*?*/ /*?*/ /*?*/ /*?*/
  636.     0xee, 0xef, 0xf0, 0xf1,
  637.     /*?*/ /*?*/ /*?*/ /*?*/
  638.     0xf2, 0xf3, 0xf4, 0xf5,
  639.     /*?*/ /*?*/ /*?*/ /*?*/
  640.     0xf6, 0xf7, 0xf8, 0xf9,
  641.     /*?*/ /*?*/ /*?*/ /*?*/
  642.     0xfa, 0xfb, 0xfc, 0xfd,
  643.     /*?*/ /*?*/
  644.     0xfe, 0xff
  645. };
  646.  
captcha