1 /*
2 * translat.c: Stuff for handling character translation tables
3 * and a digraph entry facility. Support an international IRC!
4 *
5 * I listen to Sex Pistols, so I assume everyone in this world,
6 * and more specifically, all servers, are using ISO 8859/1
7 * (Latin-1). And in case of doubt, please consult Jarkko 'Wiz'
8 * Oikarinen's document "Internet Relay Chat Protocol" (doc/Comms
9 * in the ircd package), paragraph 2.2. Besides, all of the sane
10 * world has already converted to this set. (X-Windows, Digital,
11 * MS-Windows, etc.)
12 * If someone please would forward me some documentation on other
13 * international sets, like 8859/2 - 8859/10 etc, please do so!
14 * Moreover, feedback on the tables in the definition files would
15 * be greatly appreciated!
16 * Another idea, to be implemented some beautiful day, would be
17 * to add transliteration of the Kanji/Katakana sets used in
18 * the far east. 8-)
19 * Tomten <tomten@solace.hsh.se> / <tomten@lysator.liu.se>
20 */
21
22 #include "irc.h"
23 static char cvsrevision[] = "$Id: translat.c 432 2013-11-07 03:00:24Z tcava $";
24 CVS_REVISION(translat_c)
25 #include "struct.h"
26
27 #if defined(TRANSLATE) || defined(HEBREW)
28 #include "vars.h"
29 #include "translat.h"
30 #include "ircaux.h"
31 #include "window.h"
32 #include "screen.h"
33 #include "output.h"
34 #include "hebrew.h"
35 #define MAIN_SOURCE
36 #include "modval.h"
37
38
39 #ifndef TRANSLATION_PATH
40 /* we have this here as a safety feature if for some reason TRANSLATION_PATH
41 * is not defined.
42 */
43 #define TRANSLATION_PATH "/usr/local/lib/bx/translation"
44 #endif
45
46
47 static unsigned char my_getarg (char **);
48
49 /* Globals */
50 unsigned char transToClient[256]; /* Server to client translation. */
51 unsigned char transFromClient[256]; /* Client to server translation. */
52 char translation = 0; /* 0 for transparent (no) translation. */
53 char digraph_changed = 0;
54
55 /*
56 * dig_table_lo[] and dig_table_hi[] contain the character pair that
57 * will result in the digraph in dig_table_di[]. To avoid searching
58 * both tables, I take the lower character of the pair, and only
59 * search dig_table_lo[]. Thus, dig_table_lo[] must always contain
60 * the lower character of the pair.
61 *
62 * The digraph tables are based on those in the excellent editor Elvis,
63 * with some additions for those, like me, who are used to VT320 or
64 * VT420 terminals.
65 */
66
67 #define DiLo(x) x,
68 #define DiHi(x)
69 #define DiDi(x)
70
71 /*
72 * Digraph tables. Note that, when adding a new digraph, the character
73 * of the pair with the lowest value, *must* be in the DiLo column.
74 * The higher of the pair goes in DiHi, and the digraph itself in DiDi.
75 */
76
77 unsigned char dig_table_lo[DIG_TABLE_SIZE] =
78 {
79 #include "digraph.inc"
80 0
81 };
82
83
84 #undef DiLo
85 #undef DiHi
86 #undef DiDi
87 #define DiLo(x)
88 #define DiHi(x) x,
89 #define DiDi(x)
90
91 unsigned char dig_table_hi[DIG_TABLE_SIZE] =
92 {
93 #include "digraph.inc"
94 0
95 };
96
97
98 #undef DiLo
99 #undef DiHi
100 #undef DiDi
101 #define DiLo(x)
102 #define DiHi(x)
103 #define DiDi(x) x,
104
105 unsigned char dig_table_di[DIG_TABLE_SIZE] =
106 {
107 #include "digraph.inc"
108 0
109 };
110
111
112 /*
113 * enter_digraph: The BIND function ENTER_DIGRAPH.
114 */
enter_digraph(char key,char * ptr)115 void enter_digraph(char key, char *ptr)
116 {
117 last_input_screen->digraph_hit = 1; /* Just stuff away first character. */
118 }
119
120 /*
121 * get_digraph: Called by edit_char() when a digraph entry is activated.
122 * Looks up a digraph given char c1 and the global char
123 * last_input_screen->digraph_hit.
124 */
get_digraph(unsigned char c1)125 unsigned char get_digraph(unsigned char c1)
126 {
127 int i = 0;
128 unsigned char c,
129 c2 = last_input_screen->digraph_first;
130
131 last_input_screen->digraph_hit = 0;
132 if (c1 > c2) /* Make sure we have the lowest one in c1. */
133 c = c1, c1 = c2, c2 = c;
134 while (dig_table_lo[i])
135 { /* Find digraph and return it. */
136 if ((dig_table_lo[i] == c1) && (dig_table_hi[i] == c2))
137 return dig_table_di[i];
138 i++;
139 }
140 return 0; /* Failed lookup. */
141 }
142
143
144 /*
145 * set_translation: Called when the TRANSLATION variable is SET.
146 * Attempts to load a new translation table.
147 */
set_translation(Window * win,char * tablename,int unused)148 void set_translation(Window *win, char *tablename, int unused)
149 {
150 FILE *table;
151 unsigned char temp_table[512];
152 char *filename = NULL, *s;
153 int inputs[8];
154 int j,
155 c = 0;
156 char buffer[BIG_BUFFER_SIZE + 1];
157
158 if (!tablename)
159 {
160 translation = 0;
161 return;
162 }
163 for (s = tablename; *s; s++)
164 {
165 if (isspace((unsigned char)*s))
166 {
167 *s = '\0';
168 break;
169 }
170 }
171
172 tablename = upper(tablename);
173
174 /* Check for transparent mode; ISO-8859/1, Latin-1 */
175 if (!strcmp("LATIN_1", tablename))
176 {
177 translation = 0;
178 return;
179 }
180
181 /* Else try loading the translation table from disk. */
182 malloc_strcpy(&filename, TRANSLATION_PATH "/");
183 malloc_strcat(&filename, tablename);
184 if ( !(table = uzfopen(&filename, ".", 0)) )
185 {
186 say("Cannot open character table definition \"%s\" !",
187 tablename);
188 set_string_var(TRANSLATION_VAR, NULL);
189 new_free(&filename);
190 return;
191 }
192
193 /* Any problems in the translation tables between hosts are
194 * almost certain to be caused here.
195 * many scanf implementations do not work as defined. In particular,
196 * scanf should ignore white space including new lines (many stop
197 * at the new line character, hence the fgets and sscanf workaround),
198 * many fail to read 0xab as a hexadecimal number (failing on the
199 * x) despite the 0x being defined as optionally existing on input,
200 * and others zero out all the output variables if there is trailing
201 * non white space in the format string which doesn't appear on the
202 * input. Overall, the standard I/O libraries have a tendancy not
203 * to be very standard.
204 */
205
206 while (fgets(buffer, 80, table))
207 {
208 sscanf(buffer, "0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x",
209 inputs+0, inputs+1, inputs+2, inputs+3,
210 inputs+4, inputs+5, inputs+6, inputs+7);
211 for (j = 0; j<8; j++)
212 temp_table[c++] = (unsigned char) inputs[j];
213 }
214 fclose(table);
215 new_free(&filename);
216 if (c == 512)
217 {
218 for (c = 0; c <= 255; c++)
219 {
220 transToClient[c] = temp_table[c];
221 transFromClient[c] = temp_table[c | 256];
222 }
223 #if 0
224 for (c = 0; c <= 255; c++)
225 transToClient[c] = c;
226 #endif
227
228 translation = 1;
229 }
230 else
231 {
232 say("Error loading translation table \"%s\" !", tablename);
233 set_string_var(TRANSLATION_VAR, NULL);
234 }
235 }
236
237 /*
238 * digraph: The /DIGRAPH command with facilities.
239 * This routine is *NOT* finished yet.
240 */
241
BUILT_IN_COMMAND(digraph)242 BUILT_IN_COMMAND(digraph)
243 {
244 char *arg;
245 u_char c1,
246 c2 = '\0',
247 c3 = '\0';
248 int len,
249 i;
250
251 if ((arg = next_arg(args, &args)) && (*arg == '-'))
252 {
253 arg++;
254 if ((len = strlen(arg)) == 0)
255 {
256 say("Unknown or missing flag.");
257 return;
258 }
259 if (my_strnicmp(arg, "add", len) == 0)
260 {
261 /*
262 * Add a digraph to the table.
263 * I *know*. This *is* a kludge.
264 */
265 if ((i = strlen((char *)dig_table_lo)) ==
266 DIG_TABLE_SIZE - 1)
267 say("Sorry, digraph table full.");
268 else
269 {
270 while ((c1 = my_getarg(&args)) &&
271 (c2 = my_getarg(&args)) &&
272 (c3 = my_getarg(&args)))
273 {
274 /* Pass c1 to get_digraph() */
275 last_input_screen->digraph_first = c1;
276 if (get_digraph(c2) == 0)
277 {
278 dig_table_di[i] = c3;
279 /* Make sure c1 <= c2 */
280 if (c1 > c2)
281 c3 = c1, c1 = c2, c2 = c3;
282 dig_table_lo[i] = c1;
283 dig_table_hi[i] = c2;
284 i++;
285 dig_table_lo[i] =
286 dig_table_hi[i] =
287 dig_table_di[i] =
288 (unsigned char) 0;
289 digraph_changed = 1;
290 say("Digraph added to table.");
291 }
292 else
293 {
294 say("Digraph already defined in table.");
295 break;
296 }
297 }
298 if (!c2 || !c3)
299 say("Unknown or missing argument.");
300 }
301
302 }
303 else if (my_strnicmp(arg, "remove", len) == 0)
304 {
305
306 /* Remove a digraph from the table. */
307 if ((i = strlen((char *)dig_table_lo)) == 0)
308 say("Digraph table is already empty.");
309 else
310 {
311 if ((c1 = my_getarg(&args)) &&
312 (c2 = my_getarg(&args)))
313 {
314 i = 0;
315 if (c1 > c2)
316 c3 = c1, c1 = c2, c2 = c3;
317 while (dig_table_lo[i])
318 {
319 if ((dig_table_lo[i] == c1) &&
320 (dig_table_hi[i] == c2))
321 /*
322 * strcpy() is not guaranteed for
323 * overlapping copying, but this one
324 * is high -> low. Ought to be fixed.
325 */
326 /* re-indent this block - phone, jan 1993. */
327 {
328 strcpy(((char *)dig_table_lo + i),
329 (char *)(dig_table_lo + (i + 1)));
330 strcpy((char *)(dig_table_hi + i),
331 (char *)(dig_table_hi + (i + 1)));
332 strcpy((char *)(dig_table_di + i),
333 (char *)(dig_table_di + (i + 1)));
334 digraph_changed = 1;
335 put_it("Digraph removed from table.");
336 return;
337 }
338 /* much better */
339 i++;
340 }
341 say("Digraph not found.");
342 }
343 }
344 }
345 else if (my_strnicmp(arg, "clear", len) == 0)
346 {
347
348 /* Clear digraph table. */
349 dig_table_lo[0] = dig_table_hi[0] = dig_table_di[0] =
350 (unsigned char) 0;
351 digraph_changed = 1;
352 say("Digraph table cleared.");
353
354 }
355 else
356 say("Unknown flag.");
357 }
358 else
359 {
360
361 /* Display digraph table. */
362 char buffer1[8];
363 char buffer2[192];
364
365 say("Digraph table:");
366 buffer2[0] = (char) 0;
367 i = 0;
368 while(dig_table_lo[i])
369 {
370 sprintf(buffer1, "%c%c %c ", dig_table_lo[i],
371 dig_table_hi[i], dig_table_di[i]);
372 strcat(buffer2, buffer1);
373 if ((++i % 10) == 0)
374 {
375 put_it(buffer2);
376 buffer2[0] = (char) 0;
377 }
378 }
379 if (buffer2[0])
380 put_it(buffer2);
381 sprintf(buffer2, "%d digraphs listed.", i);
382 say(buffer2);
383 }
384 }
385
my_getarg(char ** args)386 static unsigned char my_getarg(char **args)
387 {
388 unsigned char *arg;
389
390 arg = (unsigned char *)next_arg(*args, args);
391 if (!args || !*args || !arg)
392 return '\0';
393 /* Don't trust isdigit() with 8 bits. */
394 if ((*arg <= '9') && (*arg >= '0'))
395 {
396 unsigned char i = *arg & 0x0f;
397 while ( *(++arg) )
398 i = (i * 10) + (*arg & 0x0f);
399 return i;
400 }
401 else if ( (*arg == '!') && (*(arg + 1)) )
402 return *(arg + 1) | 0x80;
403 return *arg;
404 }
405
save_digraphs(FILE * fp)406 void save_digraphs(FILE *fp)
407 {
408 if (digraph_changed)
409 {
410 int i;
411
412 fputs("DIGRAPH -CLEAR", fp);
413 for (i = 0; dig_table_lo[i]; i++) {
414 if (!(i % 5))
415 fputs("\nDIGRAPH -ADD ", fp);
416 fprintf(fp, "%d %d %d ", dig_table_lo[i],
417 dig_table_hi[i], dig_table_di[i]);
418 }
419 fputc('\n', fp);
420 }
421 }
422
423 #endif
424