Merge branch 'development'
[NeonServV5.git] / src / lang.c
1 /* lang.c - NeonServ v5.6
2  * Copyright (C) 2011-2012  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17 #include "lang.h"
18 #include "UserNode.h"
19 #include "DBHelper.h"
20 #include "mysqlConn.h"
21 #include "tools.h"
22 #include "log.h"
23
24 #define DEFAULT_LANG_TAG "EN"
25 #define DEFAULT_LANG_NAME "English"
26
27 static struct language **langdict;
28 static struct language *lang_c;
29
30 void init_lang() {
31     langdict = calloc(MAXLANGUAGES, sizeof(*langdict));
32 }
33
34 void free_lang() {
35     
36 }
37
38 void load_languages() {
39     MYSQL_RES *res;
40     MYSQL_ROW row;
41     printf_mysql_query("SELECT `lang`, `text` FROM `language` WHERE `ident` = 'name'");
42     res = mysql_use();
43     while((row = mysql_fetch_row(res)) != NULL) {
44         load_language(row[0], row[1]);
45     }
46 }
47
48 static struct language* add_language(char *langtag, char *langname) {
49     int cindex;
50     for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
51         if(langdict[cindex] == NULL) break;
52         if(!strcmp(langdict[cindex]->langname, langname) || !strcmp(langdict[cindex]->langtag, langtag))
53             return langdict[cindex];
54     }
55     if(cindex == MAXLANGUAGES) return NULL;
56     struct language *lang = malloc(sizeof(*lang));
57     if (!lang) {
58         printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
59         return NULL;
60     }
61     lang->langtag = strdup(langtag);
62     lang->langname = strdup(langname);
63     struct language_table **entrys = calloc(27, sizeof(*entrys));
64     lang->entrys = entrys;
65     langdict[cindex] = lang;
66     return lang;
67 }
68
69 static int get_entry_index(const char *ident) {
70     const char *underscore = strstr(ident, "_");
71     if(!underscore || !(underscore[1] >= 65 && underscore[1] <= 90)) return 26;
72     return (underscore[1] - 'A');
73 }
74
75 void load_language(char *tag, char *name) {
76     struct language *lang = get_language_by_tag(tag);
77     if(lang == get_default_language()) return;
78     if(lang) {
79         //remove all entrys
80         int cindex;
81         struct language_table *entry, *next;
82         for(cindex = 0; cindex < 27; cindex++) {
83             for(entry = lang->entrys[cindex]; entry; entry = next) {
84                 next = entry->next;
85                 free(entry->ident);
86                 free(entry->text);
87                 free(entry);
88             }
89             lang->entrys[cindex] = NULL;
90         }
91     } else
92         lang = add_language(tag, name);
93     if(!lang) return;
94     MYSQL_RES *res;
95     MYSQL_ROW row;
96     printf_mysql_query("SELECT `ident`, `text` FROM `language` WHERE `lang` = '%s' AND `ident` != 'name'", escape_string(tag));
97     res = mysql_use();
98     while((row = mysql_fetch_row(res)) != NULL) {
99         register_language_string(lang, row[0], row[1]);
100     }
101 }
102
103 struct language* get_language_by_tag(char *tag) {
104     int cindex;
105     for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
106         if(langdict[cindex] == NULL) break;
107         if(!stricmp(langdict[cindex]->langtag, tag))
108             return langdict[cindex];
109     }
110     return NULL;
111 }
112
113 struct language* get_language_by_name(char *name) {
114     int cindex;
115     for(cindex = 0; cindex < MAXLANGUAGES; cindex++) {
116         if(langdict[cindex] == NULL) break;
117         if(!stricmp(langdict[cindex]->langname, name))
118             return langdict[cindex];
119     }
120     return NULL;
121 }
122
123 struct language* get_default_language() {
124     if(lang_c == NULL) 
125         lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
126     return lang_c;
127 }
128
129 void register_default_language_table(const struct default_language_entry *msgtab) {
130     if(lang_c == NULL) 
131         lang_c = add_language(DEFAULT_LANG_TAG, DEFAULT_LANG_NAME);
132     while(msgtab->ident) {
133         register_language_string(lang_c, msgtab->ident, msgtab->text);
134         msgtab++;
135     }
136 }
137
138 void register_language_string(struct language *lang, char *ident, char *text) {
139     int cindex = get_entry_index(ident);
140     struct language_table *lang_entry;
141     for(lang_entry = lang->entrys[cindex]; lang_entry; lang_entry = lang_entry->next) {
142         if(!strcmp(lang_entry->ident, ident)) break;
143     }
144     if(!lang_entry) {
145         lang_entry = malloc(sizeof(*lang_entry));
146         if (!lang_entry) {
147             printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
148             return;
149         }
150         lang_entry->ident = strdup(ident);
151         lang_entry->next = lang->entrys[cindex];
152         lang->entrys[cindex] = lang_entry;
153     } else
154         free(lang_entry->text); //free old text (new one will be set below)
155     //replace all:
156     //$b to \002
157     //$k to \003
158     char txt[MAXLEN];
159     strcpy(txt, text);
160     char tmp[MAXLEN];
161     int tmppos = 0;
162     char *a, *b = txt;
163     do {
164         a = strstr(b, "$");
165         if(a) *a = '\0';
166         tmppos += sprintf(tmp + tmppos, "%s", b);
167         if(a) {
168             switch(a[1]) {
169                 case 'b':
170                     tmp[tmppos++] = 2;
171                     break;
172                 case 'k':
173                     tmp[tmppos++] = 3;
174                     break;
175                 case 'u':
176                     tmp[tmppos++] = 31;
177                     break;
178                 default:
179                     //unknown - just write it
180                     tmppos += sprintf(tmp + tmppos, "$%c", a[1]);
181             }
182             b = a+2;
183         }
184     } while(a);
185     lang_entry->text = strdup(tmp);
186 }
187
188 char *get_language_string(struct UserNode *user, const char* msg_ident) {
189     struct language* lang;
190     if(user && (user->flags & USERFLAG_ISAUTHED)) {
191         loadUserSettings(user);
192         lang = user->language;
193     } else
194         lang = lang_c;
195     int cindex = get_entry_index(msg_ident);
196     struct language_table* entry;
197     for(entry = lang->entrys[cindex]; entry; entry = entry->next) {
198         if(!strcmp(entry->ident, msg_ident))
199             return entry->text;
200     }
201     if(lang == lang_c) return NULL;
202     for(entry = lang_c->entrys[cindex]; entry; entry = entry->next) {
203         if(!strcmp(entry->ident, msg_ident))
204             return entry->text;
205     }
206     return NULL;
207 }
208
209 char *build_language_string(struct UserNode *user, char *buffer, const char *msg_ident, ...) {
210     char *formatStr = get_language_string(user, msg_ident);
211     if(!formatStr) return NULL;
212     if(buffer == NULL) {
213         buffer = (char *)malloc((MAXLEN+1) * sizeof(char));
214         if (!buffer) {
215             printf_log("main", LOG_ERROR, "%s:%d malloc() failed", __FILE__, __LINE__);
216             return NULL;
217         }
218     }
219     int pos;
220     va_list arg_list;
221     buffer[0] = '\0';
222     va_start(arg_list, msg_ident);
223     pos = vsnprintf(buffer, MAXLEN - 2, formatStr, arg_list);
224     va_end(arg_list);
225     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
226     buffer[pos] = '\0';
227     return buffer;
228 }