1 /*
2      ATP QWK MAIL READER FOR READING AND REPLYING TO QWK MAIL PACKETS.
3      Copyright (C) 1992, 1993, 1997  Thomas McWilliams
4      Copyright (C) 1990  Rene Cougnenc
5 
6      This program is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published by
8      the Free Software Foundation; either version 2, or (at your option)
9      any later version.
10 
11      This program is distributed in the hope that it will be useful,
12      but WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14      GNU General Public License for more details.
15 
16      You should have received a copy of the GNU General Public License
17      along with this program; if not, write to the Free Software
18      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 /*
22 makemail.c
23 */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <fcntl.h>
29 
30 #include "reader.h"
31 #include "readlib.h"
32 #include "makemail.h"
33 #include "qlib.h"
34 #include "ansi.h"
35 
36 
37 static FILE *RepMsg;
38 
39 /*
40  * Creation du bloc d'entete  du fichier message correspondant au serveur
41  * FirstHeader, creates the opening header block for reply packet file.
42  */
43 static void
FirstHeader(void)44 FirstHeader(void)
45 {
46     char Block[BLKSIZE], tbuf[QWK_FIELD_LEN + 1];
47     (void) memcpy(tbuf, CurBoard, field_len);	/* Preserve lowercase name for */
48     tbuf[field_len] = NUL_CHAR;
49     (void) strupr(tbuf);	/* later use ....                */
50     (void) memset(Block, (int) SPC_CHAR, block_SIZE);	/* Fill with spaces      */
51     str2mem(Block, tbuf);	/* Insert BBS name for header    */
52     if (fwrite(Block, block_SIZE, one_record, RepMsg) != one_record) {
53 	printf("FirstHeader() %s\n", txt[73]);
54 	(void) sleep(3);
55     } else
56 	fflush(RepMsg);		/* Write this block to the file  */
57 }
58 
59 
60 /*
61  * DoRepExport, called by DoRep() to actually write out the reply.
62  */
63 static atp_BOOL_T
DoRepExport(const char * filemsg,const unsigned long MaxChars,const size_t NbBlocs)64 DoRepExport(const char *filemsg, const unsigned long MaxChars, const size_t NbBlocs)
65 {
66     /* only export messages not marked as "killed" */
67     atp_BOOL_T mrep = TRUE;
68     unsigned long lndx;
69     byte *ptr = (byte *) (rbuf + block_SIZE);
70     /* Translate to QWK style "pi" line feed  */
71     for (lndx = 0L; lndx < MaxChars; lndx++, ptr++) {  /*@-strictops */
72 	if (*ptr == (byte)'\n')
73 	    *ptr = QWK_LINE_FEED;
74 	else if (*ptr == DOS_SPACE)                    /*@=strictops */
75 	    *ptr = SPC_CHAR;
76     }
77     if (fwrite(rbuf, block_SIZE, NbBlocs + 1, RepMsg) != NbBlocs + 1) {
78 	/* "error writing file " */
79 	printf("%s %s\n", txt[73], filemsg);
80 	mrep = FALSE;
81     }
82     return mrep;
83 }
84 
85 static FILE *MsgFile, *IdxFile;
86 static char MessageFile[MAXPATHS];
87 
88 /*
89  * DoRepFill, load message into rbuf buffer and process.
90  *
91  * Note: Either a message will be skipped or packed in one atomic operation.
92  *       The only time count will be -1 is if there is some failure
93  *       in exporting a message that is marked for export.
94  */
95 ATP_INLINE int
DoRepFill(const char * filemsg,const char * msg_total_blocks,const char * export_status)96 DoRepFill(const char *filemsg, const char *msg_total_blocks, const char *export_status)
97 {
98     int count = -1;
99     const size_t text_blocks = (size_t) (atoi(msg_total_blocks) - 1);
100     const unsigned long TextChars = text_blocks * block_SIZE;
101     const unsigned long current_max = (unsigned long) get_RbufSize();
102 
103     if (current_max <= TextChars && !reup((size_t) TextChars + block_SIZE)) {
104         /* message too big */
105         printf("%s\n%s %lu\n", txt[1], txt[72], TextChars);
106     } else if (TextChars && fread(rbuf + header_SIZE, block_SIZE, text_blocks, MsgFile) != text_blocks) {
107         /* error reading file */
108         printf("max char %lu\n%s %s\n", TextChars, txt[58], MessageFile);
109         /*@-strictops */
110     } else if ((byte) (*export_status) > HIGH_ASCII) {
111         count = 0;              /* message skipped */
112     } else if (DoRepExport(filemsg, TextChars, text_blocks))
113         count = 1;              /* message exported */
114 
115     assert(-1 <= count && count <= 1);
116     return count;
117 }
118 
119 
120 /*
121  * DoRep, reads from reply conference then writes to messages.rep.
122  *
123  * Note: There are two ways to exit from the do loop. The first is if a
124  *       call to DoRepFill fails (result code of -1). The second is if fread()
125  *       fails (which is presumed to indicate that we are at the end of the
126  *       replies file). This function should return TRUE if export count is at
127  *       least 1, and result is not an error (-1);
128  */
129 
130 static atp_BOOL_T
DoRep(const char * filemsg)131 DoRep(const char *filemsg)
132 {
133     int count = 0, result = -1;
134     atp_BOOL_T mrep = FALSE;
135     char Qmail[HDRSIZE];
136 
137     do {
138 
139         if ((fread(Qmail, header_SIZE, one_record, MsgFile)) == one_record) {
140             (void) memcpy(rbuf, Qmail, block_SIZE);
141             result = DoRepFill(filemsg, Qmail + HSizeMsg, Qmail + HStatus);
142             count += result;
143         } else
144             break;
145 
146     } while (0 <= result);
147 
148     if (count != 0 && result != -1)
149         mrep = TRUE; /* no errors and at least one reply exported */
150     return mrep;
151 }
152 
153 
154 /*
155  * Cnf2Msg - convert reply ".cnf" file into ".msg" file for export.
156  *
157  */
158 atp_BOOL_T
Cnf2Msg(const char * filemsg)159 Cnf2Msg(const char *filemsg)
160 {
161     atp_BOOL_T mrep = FALSE;
162 
163     /* Open MsgFile and IdxFile */
164     if (OpenRepFile(pack_them)) {
165         if ((RepMsg = fopen(filemsg, "wb")) == NULL) {
166             /* "unable to open file" */
167             fprintf(stderr, "%s %s\n", txt[51], filemsg);
168             perror("Does 'workpath' specified in atprc exist? ");
169         } else {
170             FirstHeader();
171             /* copy .cnf to messpath */
172             rewind(MsgFile);
173             mrep = DoRep(filemsg);
174             fclose(RepMsg);
175             if (!mrep)
176                 do_unlink(filemsg);
177         }
178         /* close message path */
179         fclose(MsgFile);
180         fclose(IdxFile);
181     }
182     return mrep;
183 }
184 
185 
186 /*
187  * display_ORF_result, prints result message for OpenRepFile.
188  */
189 ATP_INLINE void
display_ORF_result(atp_BOOL_T ret_code,pakrep_t mode,atp_BOOL_T FileExist)190 display_ORF_result(atp_BOOL_T ret_code, pakrep_t mode, atp_BOOL_T FileExist)
191 {
192     if (!ret_code) {
193 	/* "unable to open file" */
194 	printf("%s %s\n", txt[51], MessageFile); /*@-strictops */
195     } else if (mode == add_reply) {              /*@=strictops */
196 	if (FileExist)
197 	    /* "Adding message to file" */
198 	    printf("%s %s \n", txt[76], MessageFile);
199 	else
200 	    /* "creating file" */
201 	    printf("%s %s \n", txt[77], MessageFile);
202     }
203 }
204 
205 static char IndexFile[MAXPATHS];
206 
207 /*
208  * Ouverture ou creation du fichier messages.
209  * OpenRepFile - open or create the message file for replies.
210  */
211 atp_BOOL_T
OpenRepFile(const pakrep_t mode)212 OpenRepFile(const pakrep_t mode)
213 {
214     atp_BOOL_T FileExist = FALSE, ret_code = TRUE;
215 
216     /* valid modes are "pack_them" and "add_reply" */   /*@-strictops */
217     assert(mode == pack_them || mode == add_reply);	/*@=strictops */
218     make_c_i_paths(MessageFile, IndexFile, REPL_CONF);
219 
220     if (access(MessageFile, F_OK) == SUCCESS)
221 	FileExist = TRUE;
222 
223     /* see if rep file exists and it is open */
224     if (FileExist && get_saved_conf() == RCONF_IDX) {
225 	MsgFile = fmsg;
226 	IdxFile = fidx;                                                  /*@-strictops */
227 	assert(MsgFile != NULL && IdxFile != NULL);
228     } else if (OpenCon(&MsgFile, NULL, MessageFile) == ATP_ERROR
229 	       || OpenCon(&IdxFile, &MsgFile, IndexFile) == ATP_ERROR) { /*@=strictops */
230 	ret_code = FALSE;
231     }
232     display_ORF_result(ret_code, mode, FileExist);
233     return ret_code;
234 }
235 
236 
237 /***** begin KodeMessage routines *****/
238 
239 /*
240  * KodeSubj, handle PCBoard style long subjects lines in replies.
241  *   Note that sprintf() returns a char pointer under SunOS but
242  *   an integer under POSIX. Therefore for portability, char_cnt
243  *   must be calculated in a separate operation.
244  */
245 static size_t
KodeSubj(char CONSPTR tampbuf)246 KodeSubj(char CONSPTR tampbuf)
247 {
248     size_t text_start_offset = 0;
249     char *long_subj = NULL ;
250 
251     /* if a long subject line was entered, format it PCBoard style */
252     if (PCBLONG && (long_subj = get_reply_lsubj()) != NULL) {
253 	byte CONSPTR net_flag = (byte *) tampbuf;
254 	char *buf_ptr = tampbuf;
255 	size_t char_cnt;
256 
257 	/* write head string and subject to reply buffer */
258 	sprintf(tampbuf, "%s%s", LSUBJ_HEAD, long_subj);
259 	free_string(long_subj);
260 
261 	/* guarantee temination before taking length */
262 	tampbuf[LSUBJ_HEAD_LEN + LSUBJ_BODY_LEN] = NUL_CHAR;
263 	char_cnt = strlen(tampbuf);
264 	buf_ptr += char_cnt;
265 
266 	/* adjust for FIDO network if needed */
267 	*net_flag = (byte) (fido ? SPC_CHAR : DOS_SPACE);
268 
269 	/* pad message with space characters */
270 	while (char_cnt < (size_t)(LSUBJ_HEAD_LEN + LSUBJ_LEN)) {
271 	    *buf_ptr++ = SPC_CHAR;
272 	    char_cnt++;
273 	}
274 #ifdef ATPDBG
275 	assert((STRING_LEN(LSUBJ_HEAD) + STRING_LEN(LSUBJ_TAIL) + LSUBJ_LEN) == LSUBJ_BUF_LEN);
276 	assert(STRING_LEN(LSUBJ_HEAD) == 10);
277 	assert(STRING_LEN(LSUBJ_TAIL) == 8);
278 	assert(buf_ptr == (tampbuf + 64));
279 #endif
280 	strcpy(buf_ptr, LSUBJ_TAIL);
281 	strcat(buf_ptr, "\n");
282 	text_start_offset = strlen(tampbuf);
283 	assert( text_start_offset == (LSUBJ_BUF_LEN + STRING_LEN("\n")));
284     }
285     return text_start_offset;
286 }
287 
288 static size_t CountBlocks;
289 static size_t CountTotalChars;
290 static size_t CountRecordChars;
291 static char *tampon, *tamp;
292 
293 /*
294  * KodeMsgTag, add the tagline to the reply message.
295  */
296 static void
KodeMsgTag(void)297 KodeMsgTag(void)
298 {
299     /*@only@*/ byte CONSPTR base_ptr = get_CurTag();
300 
301     if (base_ptr != NULL) {
302 	const byte *ptr = base_ptr;
303 	const atp_CODE_T chrset = get_charset();
304 
305 	/*@-strictops */
306 	while (*ptr != (byte) NUL_CHAR) {
307 	    if (chrset == ISOLAT1)	/*@=strictops */
308 		/* translate ISO Latin1 to DOS chars */
309 		*tamp = codepc[(unsigned) *ptr];
310 	    else
311 		*tamp = *ptr;
312 	    tamp++;
313 	    ptr++;
314 	    CountRecordChars++;
315 	    CountTotalChars++;
316 	    if (CountRecordChars > block_SIZE) {
317 		CountBlocks++;
318 		CountRecordChars = 1;
319 	    }
320 	}
321 	free_string((char *) base_ptr);
322     }
323 }
324 
325 /*
326  * KodeMsgFin, finish up by adding tagine and padding out last block
327  */
328 static void
KodeMsgFin(char * Qmail)329 KodeMsgFin(char *Qmail)
330 {
331 
332     /* Add the the tagline. Rajout de la signature du programme */
333     if (get_tag_flag())
334 	KodeMsgTag();
335 
336     /* Ajuste la taille du dernier bloc � 128 octets    */
337     /* Adjust the size of the last block to 128 bytes      */
338     while (CountRecordChars < block_SIZE) {
339 	*tamp = SPC_CHAR;
340 	tamp++;
341 	CountRecordChars++;
342 	CountTotalChars++;
343     }
344 
345     /* Inscrit dans le Header le nombre blocs de 128 octets */
346     /* Inscribe in the header the number of 128 byte blocks */
347     {
348 	char tmp[20];
349 	sprintf(tmp, "%lu", (unsigned long) CountBlocks);
350 	str2mem(Qmail + HSizeMsg, tmp);
351     }
352 }
353 
354 /*
355  * KodeXlat, translate the message from host to MSDOS character set.
356  */
357 static void
KodeXlat(FILE * TmpaFile)358 KodeXlat(FILE * TmpaFile)
359 {
360     byte ch;
361     unsigned LinCt = 0;		/* counts line length */
362     const atp_CODE_T chrset = get_charset();
363     rewind(TmpaFile);
364     while (fread(&ch, (size_t)1, one_record, TmpaFile) == one_record) {
365 	if (LinCt >= REPLY_LINE_LEN)
366 	    ch = '\n';
367 	/*@-strictops */                            /*@-usedef */
368 	LinCt = (ch == (byte)'\n') ? 0 : LinCt + 1; /*@=usedef */
369 
370 	if (chrset == ISOLAT1 && ch >= HIGH_ASCII)
371 	    ch = codepc[(unsigned)ch];	/* translate back to DOS set */
372 	ch = (byte)((ch == DOS_SPACE || ch == (byte)CNTRL_Z) ? SPC_CHAR : ch);
373 
374 	/* skip ^M carriage returns */
375 	if (ch != (byte)CR) {		 /*@=strictops */
376 	    *tamp = ch;
377 	    tamp++;
378 	    CountRecordChars++;
379 	    CountTotalChars++;
380 	    if (CountRecordChars > block_SIZE) {
381 		CountBlocks++;
382 		CountRecordChars = 1;
383 	    }
384 	}
385     }
386 }
387 
388 
389 /* Ecrit les fichiers conf et index.
390  * KodeWrite, write out newly encoded message and update .cnf and idx files.
391  */
392 static void
KodeWrite(char * Qmail,long klast)393 KodeWrite(char *Qmail, long klast)
394 {
395     /* Ecrit l'entete du message, suivi du message          */
396     /* Write the reply header followed by the reply itself  */
397 
398     printf("%s...\n", txt[75]);	/* "sauvegarde du message" */
399     rewind(MsgFile);
400     fseek(MsgFile, 0L, SEEK_END);
401     if (fwrite(Qmail, header_SIZE, one_record, MsgFile) != one_record ||
402     fwrite(tampon, CountTotalChars, one_record, MsgFile) != one_record) {
403 	printf("KodeWrite() %s\n", txt[73]);
404 	(void) sleep(3);
405     } else {
406 	fflush(MsgFile);
407 
408 	/* Update the index */
409 
410 	fseek(IdxFile, 0L, SEEK_END);	/*@-strictops */
411 	if (WriteIndex(IdxFile, (long) (ftell(IdxFile) / IDXSIZE), (block_SIZE * (CountBlocks - 1)), klast) == ATP_OK)	/*@=strictops */
412 	    fflush(IdxFile);
413     }
414 }
415 
416 
417 /*
418  * KodeXlatFin, clean up the tail end of the message.
419  */
420 static void
KodeXlatFin(void)421 KodeXlatFin(void)
422 {
423     /* point to last character */
424     if (tamp > tampon)
425 	tamp--;
426 
427     /* guarantee a non-empty message */
428     if (CountTotalChars == (size_t) 0 || (CountTotalChars == (size_t) 1 && /*@i@*/ *tampon == '\n')) {
429 	assert(tamp == tampon);
430 	*tamp = SPC_CHAR;
431 	CountTotalChars = CountRecordChars = (size_t) 1;
432     }
433     /*@-strictops */
434     if (*tamp != '\n') {	/*@=strictops */
435 	tamp++;
436 	CountRecordChars++;
437 	CountTotalChars++;
438     }
439     /* mark end of text proper */
440     *tamp = DOS_SPACE;
441     tamp++;
442     if (CountRecordChars > block_SIZE) {
443 	CountBlocks++;
444 	CountRecordChars = 1;
445     }
446 }
447 
448 
449 /*
450  * KodeDoFin, finish up and close files for KodeDo().
451  */
452 static void
KodeDoFin(long ksave_cnf,long ksave_idx)453 KodeDoFin(long ksave_cnf, long ksave_idx)
454 {
455     if (get_saved_conf() == RCONF_IDX) {
456 	fseek(fmsg, ksave_cnf, SEEK_SET);
457 	fseek(fidx, ksave_idx, SEEK_SET);
458     } else {
459 	fclose(MsgFile);
460 	fclose(IdxFile);
461     }
462     /* update list of active conferences */
463     ActvConf();
464 }
465 
466 
467 /* Codage du message dans le tampon.
468  * KodeDo, encode the reply with QWK standard characters.
469  */
470 static void
KodeDo(FILE * TmpaFile,char * Qmail)471 KodeDo(FILE * TmpaFile, char *Qmail)
472 {
473     long int klast, ksavec = 0L, ksavei = 0L;
474     CountBlocks = 2;
475 
476     /* if we are already in the Reply Conference, save position */
477     if ( get_saved_conf() == RCONF_IDX) {
478 	ksavec = ftell(fmsg);
479 	ksavei = ftell(fidx);
480     }
481     /* determine size of MsgFile */
482     fseek(MsgFile, 0L, SEEK_END);
483     klast = ftell(MsgFile);
484 
485     /* handle PCBoard long subjects */
486     CountTotalChars = CountRecordChars = KodeSubj(tampon);
487     tamp = tampon + CountRecordChars;
488 
489     /* translate the message from host to MSDOS character set */
490     KodeXlat(TmpaFile);
491 
492     /* clean-up the tail end of the message */
493     KodeXlatFin();
494 
495     /* apend tagline and finish up */
496     KodeMsgFin(Qmail);
497 
498     /* write out and update cnf and idx files */
499     KodeWrite(Qmail, klast);
500 
501     /* Close and erase the work file */
502      KodeDoFin(ksavec,ksavei);
503 }
504 
505 /*
506  *  Ecriture du message proprement dit, cod� selon le format PcBoard, c.a.d les cr/lf remplac�s par  '\343'
507  *
508  * KodeMessage - encodes reply in PcBoard/QWK format.
509  *  note: CR/LF are replaced with '\343', the DOS "pi" character.
510  */
511 atp_ERROR_T
KodeMessage(const char * fname,char * Qmail)512 KodeMessage(const char *fname, char *Qmail)
513 {
514     atp_ERROR_T ret_code = ATP_ERROR;
515     FILE *TmpaFile;
516 
517     /* Ouvre le fichier cr�� par l'�diteur */
518     /* Open the reply file created by the editor    */
519 
520     if ((TmpaFile = fopen(fname, "r")) == NULL) {
521 	printf("%s %s\n", txt[51], fname);	/* "unable to open file" */
522     } else {
523 	long int repsize;
524 	fseek(TmpaFile, 0L, SEEK_END);
525 	if ((repsize = ftell(TmpaFile)) >= 0L) {
526 	    const size_t tampon_size = (size_t)(repsize+1024L); /* !! why the 1024L? */
527 	    if (repsize > (long) (MAXSEND - 256)) {
528 		printf("\nERROR: Reply file exceeds %lu bytes%c\n", (unsigned long) MAXSEND, BELL);
529 		fclose(MsgFile);
530 	    } else if ((tampon = (char *) malloc(tampon_size)) == NULL) {
531 		printf("%s\n", txt[1]);		/* memory allocation error */
532 		fclose(MsgFile);
533 	    } else {
534 		KodeDo(TmpaFile, Qmail);
535 		ret_code = ATP_OK;
536 		free_buffer(tampon, tampon_size);
537 		tampon = NULL;
538 	    }
539 	}
540 	fclose(TmpaFile);
541     }
542     return ret_code;
543 }
544 /***** end of KodeMessage routines *****/
545 
546 /*
547  * codepc - table converts a LINUX screen code to an MS-DOS screen code.
548  */
549 const unsigned char codepc[] =
550 {
551 
552     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
553     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
554     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
555     0x18, 0x19, 0x20, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
556     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
557     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
558     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
559     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
560     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
561     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
562     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
563     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
564     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
565     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
566     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
567     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
568 
569     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,	/* 87 */
570     0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,	/* 8f */
571     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,	/* 97 */
572     0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,	/* 9f */
573     0x20, 0xad, 0x9b, 0x9c, 0xfe, 0x9d, 0x7c, 0xfe,	/* a7 */
574     0xfe, 0xfe, 0xa6, 0xae, 0xaa, 0x2d, 0xfe, 0xfe,	/* af */
575     0xf8, 0xf1, 0xfd, 0xfe, 0xfe, 0xe6, 0xfe, 0xf9,	/* b7 */
576     0xfe, 0xfe, 0x97, 0xaf, 0xac, 0xab, 0xfe, 0xa8,	/* bf */
577     0xfe, 0xfe, 0xfe, 0xfe, 0x8e, 0x8f, 0x92, 0x80,	/* c7 */
578     0xfe, 0x90, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,	/* cf */
579     0xfe, 0xa5, 0xfe, 0xfe, 0xfe, 0xfe, 0x99, 0xfe,	/* d7 */
580     0xfe, 0xfe, 0xfe, 0xfe, 0x9a, 0xfe, 0xfe, 0xe1,	/* df */
581     0x85, 0xa0, 0x83, 0xfe, 0x84, 0x86, 0x91, 0x87,	/* e7 */
582     0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,	/* ef */
583     0xfe, 0xa4, 0x95, 0xa2, 0x93, 0xfe, 0x94, 0xf6,	/* f7 */
584     0xfe, 0x97, 0xa3, 0x96, 0x81, 0xfe, 0xfe, 0x98};
585 
586 
587 /*
588  * codelu - table converts an MS_DOS screen code to a LINUX screen code.
589  */
590 const unsigned char codelu[] =
591 {
592 
593     0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
594     0x20, 0x09, 0x0a, 0x20, 0x20, 0x0d, 0x20, 0x20,
595     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
596     0x20, 0x20, 0x20, 0x1b, 0x20, 0x20, 0x20, 0x20,
597     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
598     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
599     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
600     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
601     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
602     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
603     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
604     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
605     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
606     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
607     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
608     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7e,
609 
610     0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7,	/* 87 */
611     0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5,	/* 8f */
612     0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9,	/* 97 */
613     0xff, 0xd6, 0xdc, 0xa2, 0xa3, 0xa5, 0x50, 0x66,	/* 9f */
614     0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba,	/* a7 */
615     0xbf, 0xad, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb,	/* af */
616     0xfe, 0xfe, 0xfe, 0xa6, 0xa6, 0xa6, 0xa6, 0xfe,	/* b7 */
617     0xfe, 0xa6, 0xa6, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,	/* bf */
618     0xfe, 0xad, 0xad, 0xa6, 0xad, 0x2b, 0xa6, 0xa6,	/* c7 */
619     0xfe, 0xfe, 0xad, 0xad, 0xa6, 0xad, 0x2b, 0xad,	/* cf */
620     0xad, 0xad, 0xad, 0xfe, 0xfe, 0xfe, 0xfe, 0x2b,	/* d7 */
621     0x2b, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,	/* df */
622     0xa3, 0xdf, 0xfe, 0xfe, 0x53, 0x73, 0xb5, 0x74,	/* e7 */
623     0xa7, 0x4f, 0x4f, 0x64, 0xad, 0x6f, 0xc6, 0xfe,	/* ef */
624     0xad, 0xb1, 0xfe, 0xfe, 0xa6, 0xa6, 0xf7, 0x7e,	/* f7 */
625     0xb0, 0xb7, 0xb7, 0x76, 0x6e, 0xb2, 0xfe, 0x20};
626 
627 
628 /*
629  * codevt - table generates MS_DOS line characters with VT102 codes.
630  */
631 const unsigned char codevt[] =
632 {
633 /* dummy 0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
634 /* dummy 1 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
635 /* dummy 2 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
636 /* dummy 3 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
637 /* dummy 4 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
638 /* dummy 5 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
639 /* dummy 6 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640 /* dummy 7 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
641 /* dummy 8 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
642 /* dummy 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
643 /* dummy a */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
644 /* 0xb0 */ 'a', 'a', 'a', 'x', 'u', 'u', 'u', 'k',
645 /* 0xb8 */ 'k', 'u', 'x', 'k', 'j', 'j', 'j', 'k',
646 /* 0xc0 */ 'm', 'v', 'w', 't', 'q', 'n', 't', 't',
647 /* 0xc8 */ 'm', 'l', 'v', 'w', 't', 'q', 'n', 'v',
648 /* 0xd0 */ 'v', 'w', 'w', 'm', 'm', 'l', 'l', 'n',
649 /* 0xd8 */ 'n', 'j', 'l', 'a', 'a', 'a', 'a', 'a'};
650 
651 
652 /*
653  * code7bit - table maps 8 bit MS_DOS codes to a 7bit approximation.
654  */
655 const unsigned char code7bit[] =
656 {
657 
658     0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
659     0x20, 0x09, 0x0a, 0x20, 0x20, 0x0d, 0x20, 0x20,
660     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
661     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
662     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
663     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
664     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
665     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
666     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
667     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
668     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
669     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
670     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
671     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
672     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
673     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
674 
675 /* 80 */ 'C', 'u', 'e', 'a', 'a', 'a', 'a', 'c',
676 /* 88 */ 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A',
677 /* 90 */ 'E', 'a', 'A', 'o', 'o', 'o', 'u', 'u',
678 /* 98 */ 'y', 'O', 'U', 'c', 'L', 'v', 'P', 'f',
679 /* a0 */ 'a', 'i', 'o', 'u', 'n', 'N', 'a', 'o',
680 /* a8 */ '?', '~', '~', '-', '-', '!', '<', '>',
681 /* b0 */ '#', '#', '#', '|', '+', '+', '+', '+',
682 /* b8 */ '+', '+', '|', '+', '+', '+', '+', '+',
683 /* c0 */ '+', '+', '+', '+', '-', '+', '+', '+',
684 /* c8 */ '+', '+', '+', '+', '+', '-', '+', '+',
685 /* d0 */ '+', '+', '+', '+', '+', '+', '+', '+',
686 /* d8 */ '+', '+', '+', '#', '#', '#', '#', '#',
687 /* e0 */ '8', 'B', 'G', 'p', 'S', 's', 'm', 't',
688 /* e8 */ 'o', 'O', 'O', 'd', '8', 'o', 'E', '-',
689 /* f0 */ '=', '#', '<', '>', '|', '|', '/', '=',
690 /* f8 */ 'o', 'o', '.', 'v', 'n', '2', '*', ' '};
691 
692 /* end of makemail.c */
693