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