home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / rconv112.zip / richconv / richconv.c < prev    next >
C/C++ Source or Header  |  1998-10-17  |  42KB  |  1,429 lines

  1. /* richconv.c,v 1.12 1998-10-14 23:24:10-04 rl Exp */
  2.  
  3. /*************************************************************************
  4.  *                                                                       *
  5.  * richconv.c                                                            *
  6.  * Convert text/enriched (RFC 1896) MIME emails                          *
  7.  * 1998-01-10, Rolf Lochbuehler                                          *
  8.  *                                                                       *
  9.  *************************************************************************/
  10.  
  11. /*
  12.  
  13. Assumptions:
  14. (1) The original email file is of text/enriched type.
  15. (2) The original email file has a header line saying "Content-Type: text/enriched"
  16. (3) The original email file may be PGP signed.
  17. (3) As specified in RFC-822, a null line marks the end of the email header.
  18.  
  19. */
  20.  
  21.  
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <sys/stat.h>
  28. #include <sys/types.h>
  29.  
  30.  
  31. #define AUTHOR "Rolf Lochbuehler"
  32. #define AUTHOR_HTML "Rolf Lochbühler"
  33. #define EMAIL "rolf@together.net"
  34. #define PROGRAM "RichConv"
  35. #define VERSION "1.12"
  36.  
  37.  
  38. #define RET_OK 0
  39. #define RET_HELP 1
  40. #define RET_ARGUMENT 2
  41. #define RET_FILE_NAME 3
  42. #define RET_FILE_SIZE 4
  43.  
  44.  
  45. #define NO 0
  46. #define YES 1
  47. #define OFF 0
  48. #define ON 1
  49. #define EQUAL 0
  50.  
  51.  
  52. /* multipart/alternative */
  53.  
  54. /* Max 70 characters: .........1.........2.........3.........4.........5.........6.........7 */
  55. #define BOUNDARY_STR "richconv_vnochcir_richconv_vnochcir_richconv_vnochcir_richconv_vnochci"
  56.  
  57.  
  58. /* text/enriched */
  59. #define BOLD_START "bold"
  60. #define BOLD_END  "/bold"
  61. #define BIGGER_START "bigger"
  62. #define BIGGER_END  "/bigger"
  63. #define CENTER_START "center"
  64. #define CENTER_END  "/center"
  65. #define COLOR_START "color"
  66. #define COLOR_END  "/color"
  67. #define EXCERPT_START "excerpt"
  68. #define EXCERPT_END  "/excerpt"
  69. #define FIXED_START "fixed"
  70. #define FIXED_END  "/fixed"
  71. #define FLUSHBOTH_START "flushboth"
  72. #define FLUSHBOTH_END  "/flushboth"
  73. #define FLUSHLEFT_START "flushleft"
  74. #define FLUSHLEFT_END  "/flushleft"
  75. #define FLUSHRIGHT_START "flushright"
  76. #define FLUSHRIGHT_END  "/flushright"
  77. #define FONTFAMILY_START "fontfamily"
  78. #define FONTFAMILY_END  "/fontfamily"
  79. #define ITALIC_START "italic"
  80. #define ITALIC_END  "/italic"
  81. #define LANG_START "lang"
  82. #define LANG_END  "/lang"
  83. #define NOFILL_START "nofill"
  84. #define NOFILL_END  "/nofill"
  85. #define PARAINDENT_START "paraindent"
  86. #define PARAINDENT_END  "/paraindent"
  87. #define PARAM_START "param"
  88. #define PARAM_END  "/param"
  89. #define SMALLER_START "smaller"
  90. #define SMALLER_END  "/smaller"
  91. #define UNDERLINE_START "underline"
  92. #define UNDERLINE_END  "/underline"
  93.  
  94.  
  95. /* MIME */
  96. #define CONTENT_TYPE "Content-Type:"
  97. #define SUBJECT "Subject:"
  98.  
  99.  
  100. /* text/html */
  101. #define FONTSIZE_MAX 7
  102. #define FONTSIZE_MIN 1
  103. #define FONTSIZE_DEFAULT 3
  104.  
  105.  
  106. /* Functions */
  107. char* convcolor  ( char* richcolor, char* htmlcolor );
  108. void  help       ( void );
  109. void  html       ( FILE* file, char* start, char* end );
  110. void  header     ( FILE* file, char* start, char* end, char* boundarystr );
  111. char* itox       ( int n, char* hex );
  112. void  multipart  ( FILE* file, char* start, char* end, int nohtml, int simple );
  113. void  enriched   ( FILE* file, char* start, char* end );
  114. void  plain      ( FILE* file, char* start, char* end, int simple );
  115. void  changefont ( FILE* file, int size, char* color, int bold, int italic, int underline, int teletype );
  116. int   xtoi       ( char* hex );
  117.  
  118.  
  119. /************************************************************************* 
  120.  *                                                                       * 
  121.  * main()                                                                * 
  122.  * Parse command line options and open/read/write/close files            * 
  123.  *                                                                       * 
  124.  *************************************************************************/
  125. int main ( int argc, char** argv )
  126.   {
  127.  
  128.   int c;
  129.   FILE *file;
  130.   char filename[FILENAME_MAX];
  131.   int filesize;
  132.   struct stat filebuf;
  133.   char* start;
  134.   char* end;
  135.   char* p;
  136.   int nohtml = NO;
  137.   int i;
  138.   int maxsize;
  139.   int sizelimit = NO;
  140.   int simple = NO;
  141.  
  142.   if( (argc <= 1) || (7 <= argc) )
  143.     {
  144.     help();
  145.     return( RET_ARGUMENT );
  146.     }
  147.  
  148.   for( i = 1; i < argc; i += 1 )
  149.     {
  150.  
  151.     if( (EQUAL == stricmp(argv[i],"/h")) || (EQUAL == stricmp(argv[i],"-h")) )
  152.       {
  153.       help();
  154.       return( RET_HELP );
  155.       }
  156.  
  157.     if( (EQUAL == stricmp(argv[i],"/nohtml")) || (EQUAL == stricmp(argv[i],"-nohtml")) )
  158.       nohtml = YES;  
  159.  
  160.     else if( (EQUAL == stricmp(argv[i],"/max")) || (EQUAL == stricmp(argv[i],"-max")) )
  161.       {
  162.       sizelimit = YES;
  163.       maxsize = atoi( argv[++i] );
  164.       if( maxsize <= 0 )
  165.         {
  166.         help();
  167.         return( RET_FILE_SIZE );
  168.         }
  169.       }
  170.  
  171.     else if( (EQUAL == stricmp(argv[i],"/simple")) || (EQUAL == stricmp(argv[i],"-simple")) )
  172.       simple = YES;  
  173.  
  174.     else
  175.       strcpy( filename, argv[i] );
  176.  
  177.     }
  178.  
  179.   /* Open input file */
  180.   file = fopen( filename, "r" );
  181.   if( NULL == file )
  182.     return RET_FILE_NAME;
  183.  
  184.   /* Get size of file */
  185.   fstat( fileno(file), &filebuf );
  186.   filesize = filebuf.st_size;
  187.   if( (YES == sizelimit) && (filesize > maxsize) )
  188.     {
  189.     fclose( file );
  190.     return RET_FILE_SIZE;
  191.     }
  192.  
  193.   /* Allocate memory */
  194.   start = (char*) _alloca( filesize );
  195.  
  196.   /* Read input file */
  197.   p = start;
  198.   while( (c = fgetc(file)) != EOF ) 
  199.     {
  200.     *p = (char) c;
  201.     p += 1;
  202.     }
  203.   end = p - 1;
  204.  
  205.   /* Erase contents of input file */
  206.   fclose( file );
  207.   remove( filename );
  208.   file = fopen( filename, "w" );
  209.  
  210.   /* Write back converted input file */
  211.   multipart( file, start, end, nohtml, simple );
  212.  
  213.   /* Close input file */
  214.   fclose( file );
  215.  
  216.   /* Don't need to free memory, used _alloca() */
  217.  
  218.   return RET_OK;
  219.  
  220.   }
  221.  
  222.  
  223. /************************************************************************* 
  224.  *                                                                       * 
  225.  * help()                                                                * 
  226.  * Print help info for user                                              * 
  227.  *                                                                       * 
  228.  *************************************************************************/
  229. void help ( void )
  230.   {
  231.   puts(
  232.     "\n"
  233.     PROGRAM" "VERSION", "AUTHOR" <"EMAIL">\n"
  234.     "Purpose:\n"
  235.     "  Converts a text/enriched (RFC 1896) email to a multipart/alternative\n"
  236.     "  (RFC 1341) email that additionally has a text/plain version of the\n"
  237.     "  original text/enriched part. PMMail will display the text/plain part\n"
  238.     "  of the multipart/alternative email. Additionally, a text/html version\n"
  239.     "  is generated as part of the multipart/alternative email by default.\n"
  240.     "Usage:\n"
  241.     "  "PROGRAM" [/h] [/nohtml] [/max N] [/simple] [File]\n"
  242.     "Arguments:\n"
  243.     "  (none)             Display this help info, then exit\n"
  244.     "  /h, -h             Display this help info, then exit\n"
  245.     "  /nohtml, -nohtml   Don't generate text/html part\n"
  246.     "  /max N, -max N     Don't convert files larger than N byte (default: no limit)\n"
  247.     "                     Note: space is required between /max and N\n"
  248.     "  /simple, -simple   Simple text/plain (default: emphasized text to uppercase)\n"
  249.     "  File               The email file to be converted\n"
  250.     "Note:\n"
  251.     "  The input file will be substituted by the converted file, but the\n"
  252.     "  original email will not be altered and will become the last part\n"
  253.     "  of the multipart/alternative email."
  254.     );
  255.   return;
  256.   }
  257.  
  258.  
  259. /************************************************************************* 
  260.  *                                                                       * 
  261.  * multipart()                                                           * 
  262.  * Convert email to multipart/alternative                                * 
  263.  *                                                                       * 
  264.  *************************************************************************/
  265. void multipart ( FILE* file, char* start, char* end, int nohtml, int simple )
  266.   {
  267.  
  268.   char* p;
  269.  
  270.   header( file, start, end, BOUNDARY_STR );
  271.   fputs( "\n--"BOUNDARY_STR"\n", file );
  272.  
  273.   plain( file, start, end, simple );
  274.   fputs( "\n--"BOUNDARY_STR"\n", file );
  275.  
  276.   if( NO == nohtml )
  277.     {
  278.     html( file, start, end );
  279.     fputs( "\n--"BOUNDARY_STR"\n", file );
  280.     }
  281.  
  282.   enriched( file, start, end );
  283.   fputs( "\n--"BOUNDARY_STR"--\n", file );
  284.  
  285.   return;
  286.  
  287.   }
  288.  
  289.  
  290. /************************************************************************* 
  291.  *                                                                       * 
  292.  * header()                                                              * 
  293.  * Write top level header of multipart/alternative email                 * 
  294.  *                                                                       * 
  295.  *************************************************************************/
  296. void header ( FILE* file, char* start, char* end, char* boundarystr )
  297.   {
  298.  
  299.   char* p;
  300.   int strobe;
  301.  
  302.   strobe = ON;
  303.   p = start;
  304.  
  305.   while( ('\n' != *p) || ('\n' != *(p+1)) ) 
  306.     {
  307.  
  308.     /* Ignore subject line */
  309.     if( ('s' == tolower(*p)) && (EQUAL == strnicmp(SUBJECT,p,strlen(SUBJECT))) )
  310.       strobe = OFF;
  311.     if( (OFF == strobe) && ('\n' == *p) )
  312.       strobe = ON;
  313.  
  314.     /* Change content type */
  315.     if( (ON == strobe) && ('c' == tolower(*p)) && (EQUAL == strnicmp(CONTENT_TYPE,p,strlen(CONTENT_TYPE))) )
  316.       {
  317.       fputs( CONTENT_TYPE" multipart/alternative; boundary=", file );
  318.       fputs( boundarystr, file );
  319.       while( (';' != *p) && ('\n' != *p) )
  320.         p += 1;
  321.       continue;
  322.       }
  323.     else
  324.       fputc( *p, file );
  325.  
  326.     p += 1;
  327.  
  328.     }
  329.  
  330.   fputs( "\nX-Filtered: Converted from text/enriched to multipart/alternative by "PROGRAM" ("VERSION", "AUTHOR" <"EMAIL">)\n", file );
  331.  
  332.   fputc( '\n', file );
  333.  
  334.   return;
  335.  
  336.   }
  337.  
  338.  
  339. /************************************************************************* 
  340.  *                                                                       * 
  341.  * enriched()                                                            * 
  342.  * Write original email file content as text/enriched part of            * 
  343.  * multipart/alternative email                                           * 
  344.  *                                                                       * 
  345.  *************************************************************************/
  346. void enriched ( FILE* file, char* start, char* end )
  347.   {
  348.  
  349.   char* p;
  350.  
  351.   p = start;
  352.   while( p <= end ) 
  353.     {
  354.     fputc( *p, file );
  355.     p += 1;
  356.     }
  357.  
  358.   return;
  359.  
  360.   }
  361.  
  362.  
  363. /************************************************************************* 
  364.  *                                                                       * 
  365.  * plain()                                                               * 
  366.  * Write text/plain part of multipart/alternative email                  * 
  367.  *                                                                       * 
  368.  *************************************************************************/
  369. void plain ( FILE* file, char* start, char* end, int simple )
  370.   {
  371.  
  372.   char* p;             /* Memory pointer */
  373.   int italic = 0;      /* Level of <italic>...</italic> */
  374.   int bold = 0;        /* Level of <bold>...</bold> */
  375.   int underline = 0;   /* Level of <underline>...</underline> */
  376.   int excerpt = 0;     /* Level of <excerpt>...</excerpt> */
  377.   int param = 0;       /* Level of <param>...</param> */
  378.   int nofill = 0;      /* Level of <nofill>...</nofill> */
  379.   int strobe = ON;    
  380.   int linebreak = 0;   /* Number of linebreaks */
  381.   int i;               /* All purpose index variable */
  382.  
  383.   p = start;
  384.  
  385.   /* Header */
  386.  
  387.   while( ('\n' != *p) || ('\n' != *(p+1)) ) 
  388.     {
  389.  
  390.     /* Ignore subject line */
  391.     if( ('s' == tolower(*p)) && (EQUAL == strnicmp(SUBJECT,p,strlen(SUBJECT))) )
  392.       strobe = OFF;
  393.     if( (OFF == strobe) && ('\n' == *p) )
  394.       strobe = ON;
  395.  
  396.     /* Change content type */
  397.     if( (ON == strobe) && ('c' == tolower(*p)) && (EQUAL == strnicmp(CONTENT_TYPE,p,strlen(CONTENT_TYPE))) )
  398.       {
  399.       fputs( CONTENT_TYPE" text/plain", file );
  400.       while( (';' != *p) && ('\n' != *p) )
  401.         p += 1;
  402.       continue;
  403.       }
  404.     else
  405.       fputc( *p, file );
  406.  
  407.     p += 1;
  408.  
  409.     }
  410.  
  411.   fputs( "\n\n", file );
  412.  
  413.   /* Go to the '\n' at the end of the empty line that marks the end of the header */
  414.   p += 1;
  415.  
  416.   /* Body */
  417.  
  418.   while( ++p <= end )
  419.     {
  420.  
  421.     /* Line breaks */
  422.  
  423.     if( nofill <= 0 )
  424.       {
  425.  
  426.       if( '\n' == *p ) 
  427.         {
  428.   
  429.         if( (p < end) && ('\n' == *(p+1)) )
  430.           {
  431.   
  432.           /* Substitute N linebreaks by N-1 linebreaks */
  433.   
  434.           while( (p < end) && ('\n' == *(p+1)) )
  435.             {
  436.             fputc( '\n', file );
  437.             p += 1;
  438.             }
  439.           continue;
  440.   
  441.           }
  442.         else
  443.           {
  444.   
  445.           if( 0 == linebreak )
  446.             /* Substitute a single linebreak by a single space character */
  447.             fputc( ' ', file );
  448.           else
  449.             {
  450.             /* Some formatting commands force a linebreak */
  451.             fputc( '\n', file );
  452.             linebreak = 0;
  453.             }
  454.           continue;
  455.   
  456.           }
  457.   
  458.         }
  459.       else if( linebreak > 0 )
  460.         {
  461.         fputc( '\n', file );
  462.         linebreak = 0;
  463.         /* No 'continue' here, since *p != '\n' */
  464.         }
  465.  
  466.       }   /* end if */
  467.  
  468.     /* Formatting commands */
  469.  
  470.     if( '<' == *p ) 
  471.       {
  472.  
  473.       if( '<' == *(p+1) )
  474.         {
  475.         fputc( '<', file );
  476.         p += 1;
  477.         continue;
  478.         }
  479.  
  480.       else if( EQUAL == strnicmp(p+1,BOLD_START,strlen(BOLD_START)) )
  481.         {
  482.         bold += 1;
  483.         p += 1 + strlen(BOLD_START);
  484.         continue;
  485.         }
  486.       else if( EQUAL == strnicmp(p+1,BOLD_END,strlen(BOLD_END)) )
  487.         {
  488.         bold -= 1;
  489.         p += 1 + strlen(BOLD_END);
  490.         continue;
  491.         }
  492.  
  493.       else if( EQUAL == strnicmp(p+1,CENTER_START,strlen(CENTER_START)) )
  494.         {
  495.         p += 1 + strlen(CENTER_START);
  496.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(CENTER_START))) )
  497.           linebreak += 1;
  498.         continue;
  499.         }
  500.       else if( EQUAL == strnicmp(p+1,CENTER_END,strlen(CENTER_END)) )
  501.         {
  502.         p += 1 + strlen(CENTER_END);
  503.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(CENTER_END))) )
  504.           linebreak += 1;
  505.         continue;
  506.         }
  507.  
  508.       else if( EQUAL == strnicmp(p+1,EXCERPT_START,strlen(EXCERPT_START)) )
  509.         {
  510.         excerpt += 1;
  511.         p += 1 + strlen(EXCERPT_START);
  512.         fputs( "\n\n\"...", file );
  513.         continue;
  514.         }
  515.       else if( EQUAL == strnicmp(p+1,EXCERPT_END,strlen(EXCERPT_END)) )
  516.         {
  517.         excerpt -= 1;
  518.         p += 1 + strlen(EXCERPT_END);
  519.         fputs( "...\"\n\n", file );
  520.         continue;
  521.         }
  522.  
  523.       else if( EQUAL == strnicmp(p+1,FLUSHBOTH_START,strlen(FLUSHBOTH_START)) )
  524.         {
  525.         p += 1 + strlen(FLUSHBOTH_START);
  526.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHBOTH_START))) )
  527.           linebreak += 1;
  528.         continue;
  529.         }
  530.       else if( EQUAL == strnicmp(p+1,FLUSHBOTH_END,strlen(FLUSHBOTH_END)) )
  531.         {
  532.         p += 1 + strlen(FLUSHBOTH_END);
  533.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHBOTH_END))) )
  534.           linebreak += 1;
  535.         continue;
  536.         }
  537.  
  538.       else if( EQUAL == strnicmp(p+1,FLUSHLEFT_START,strlen(FLUSHLEFT_START)) )
  539.         {
  540.         p += 1 + strlen(FLUSHLEFT_START);
  541.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHLEFT_START))) )
  542.           linebreak += 1;
  543.         continue;
  544.         }
  545.       else if( EQUAL == strnicmp(p+1,FLUSHLEFT_END,strlen(FLUSHLEFT_END)) )
  546.         {
  547.         p += 1 + strlen(FLUSHLEFT_END);
  548.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHLEFT_END))) )
  549.           linebreak += 1;
  550.         continue;
  551.         }
  552.  
  553.       else if( EQUAL == strnicmp(p+1,FLUSHRIGHT_START,strlen(FLUSHRIGHT_START)) )
  554.         {
  555.         p += 1 + strlen(FLUSHRIGHT_START);
  556.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHRIGHT_START))) )
  557.           linebreak += 1;
  558.         continue;
  559.         }
  560.       else if( EQUAL == strnicmp(p+1,FLUSHRIGHT_END,strlen(FLUSHRIGHT_END)) )
  561.         {
  562.         p += 1 + strlen(FLUSHRIGHT_END);
  563.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHRIGHT_END))) )
  564.           linebreak += 1;
  565.         continue;
  566.         }
  567.  
  568.       else if( EQUAL == strnicmp(p+1,ITALIC_START,strlen(ITALIC_START)) )
  569.         {
  570.         italic += 1;
  571.         p += 1 + strlen(ITALIC_START);
  572.         continue;
  573.         }
  574.       else if( EQUAL == strnicmp(p+1,ITALIC_END,strlen(ITALIC_END)) )
  575.         {
  576.         italic -= 1;
  577.         p += 1 + strlen(ITALIC_END);
  578.         continue;
  579.         }
  580.  
  581.       else if( EQUAL == strnicmp(p+1,NOFILL_START,strlen(NOFILL_START)) )
  582.         {
  583.         nofill += 1;
  584.         p += 1 + strlen(NOFILL_START);
  585.         continue;
  586.         }
  587.       else if( EQUAL == strnicmp(p+1,NOFILL_END,strlen(NOFILL_END)) )
  588.         {
  589.         nofill -= 1;
  590.         p += 1 + strlen(NOFILL_END);
  591.         continue;
  592.         }
  593.  
  594.       else if( EQUAL == strnicmp(p+1,PARAM_START,strlen(PARAM_START)) )
  595.         {
  596.         param += 1;
  597.         p += 1 + strlen(PARAM_START);
  598.         continue;
  599.         }
  600.       else if( EQUAL == strnicmp(p+1,PARAM_END,strlen(PARAM_END)) )
  601.         {
  602.         param -= 1;
  603.         p += 1 + strlen(PARAM_END);
  604.         continue;
  605.         }
  606.  
  607.       else if( EQUAL == strnicmp(p+1,UNDERLINE_START,strlen(UNDERLINE_START)) )
  608.         {
  609.         underline += 1;
  610.         p += 1 + strlen(UNDERLINE_START);
  611.         continue;
  612.         }
  613.       else if( EQUAL == strnicmp(p+1,UNDERLINE_END,strlen(UNDERLINE_END)) )
  614.         {
  615.         underline -= 1;
  616.         p += 1 + strlen(UNDERLINE_END);
  617.         continue;
  618.         }
  619.  
  620.       /* Ignore other commands */
  621.       else
  622.         {
  623.         while( '>' != *p )
  624.           p += 1;
  625.         continue;
  626.         }
  627.  
  628.       }   /* end if */
  629.  
  630.     /* Ignore param sections */
  631.     if( param > 0 )
  632.       continue;
  633.  
  634.     /* Convert italic, bold, or underlined text to uppercase */
  635.     if( (YES != simple) && ((italic > 0) || (bold > 0) || (underline > 0)) )
  636.       fputc( toupper(*p), file );
  637.     else
  638.       fputc( *p, file );
  639.  
  640.     }   /* end while */
  641.  
  642.   return;
  643.  
  644.   }
  645.  
  646.  
  647. /************************************************************************* 
  648.  *                                                                       * 
  649.  * html()                                                                * 
  650.  * Write text/html part of multipart/alternative email                   * 
  651.  *                                                                       * 
  652.  *************************************************************************/
  653. void html ( FILE* file, char* start, char* end )
  654.   {
  655.  
  656.   char* p = NULL;                 /* Pointer to text/enriched email in memory */
  657.   char* s = NULL;                 /* Auxiliary variable to set subjectend */
  658.   char* subjectstart = NULL;      /* Pointer to first character of Subject string */
  659.   char* subjectend = NULL;        /* Pointer to last character of Subject string */ 
  660.   int nofill = 0;                 /* Character *p is inside of <nofill>...</nofill> */
  661.   int param = 0;                  /* Character *p is inside of <param>...</param> */
  662.   int strobe = ON;                
  663.   int fontsize = 3;               /* Value for <FONT SIZE="..."> */
  664.   char fontcolor[7] = "000000";   /* Value for <FONT COLOR="#...">, format: rrggbb */
  665.   char richcolor[15] = "";        /* Text color in text/enriched format: color name or rrrr,gggg,bbbb */
  666.   int bigger = 0;                 /* Level of <bigger>...</bigger> */
  667.   int smaller = 0;                /* Level of <smaller>...</smaller> */
  668.   int pre = 0;                    /* Level of <PRE>...</PRE> */ 
  669.   int prefont = NO;               /* YES, if font change inside of <PRE>...</PRE> */
  670.   int i;                          /* All purpose index variable */
  671.   int bold = 0;                   /* Level of <bold>...</bold> */ 
  672.   int italic = 0;                 /* Level of <italic>...</italic> */ 
  673.   int underline = 0;              /* Level of <underline>...</underline> */ 
  674.   int teletype = 0;               /* Level of <TT>..</TT> */
  675.   int linebreak = 0;              /* Minimum number of linebreaks */
  676.  
  677.   /* Header */
  678.  
  679.   p = start;
  680.  
  681.   while( ('\n' != *p) || ('\n' != *(p+1)) ) 
  682.     {
  683.  
  684.     /* Ignore subject line, but store subject for <TITLE> */
  685.     if( (ON == strobe) && ('s' == tolower(*p)) && (EQUAL == strnicmp(SUBJECT,p,strlen(SUBJECT))) )
  686.       {
  687.  
  688.       /* Go to start of subject */
  689.       subjectstart = p + strlen(SUBJECT);
  690.  
  691.       /* Strip spaces from start of subject */
  692.       while( (' ' == *subjectstart) && ('\n' != *subjectstart) )
  693.         subjectstart += 1;
  694.  
  695.       /* Go to end of subject */
  696.       s = subjectstart;
  697.       while( '\n' != *s ) 
  698.         s += 1;
  699.  
  700.       /* Strip spaces from end of subject */
  701.       while( ' ' == *(s-1) ) 
  702.         s -= 1;
  703.       subjectend = s - 1;   
  704.  
  705.       /* If empty subject, now subjectend < subjectstart */
  706.  
  707.       strobe = OFF;
  708.  
  709.       }
  710.  
  711.     if( (OFF == strobe) && (p == subjectend) )
  712.       strobe = ON;
  713.  
  714.     /* Change content type */
  715.     if( (ON == strobe) && ('c' == tolower(*p)) && (EQUAL == strnicmp(CONTENT_TYPE,p,strlen(CONTENT_TYPE))) )
  716.       {
  717.       fputs( CONTENT_TYPE" text/html", file );
  718.       while( (';' != *p) && ('\n' != *p) )
  719.         p += 1;
  720.       continue;
  721.       }
  722.     else
  723.       fputc( *p, file );
  724.  
  725.     p += 1;
  726.  
  727.     }
  728.  
  729.   fputs( "\n\n", file );
  730.   p += 1;
  731.  
  732.   /* Body */
  733.  
  734.   fputs( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/PR-html40/strict.dtd\">\n", file );
  735.   fputs( "<!-- Converted from text/enriched to text/html by "PROGRAM" ("VERSION", "AUTHOR_HTML", "EMAIL") -->\n", file );
  736.   fputs( "<HTML>\n<HEAD>\n<TITLE>", file );
  737.  
  738.   for( s = subjectstart; s <= subjectend; s += 1 )
  739.     fputc( *s, file );
  740.  
  741.   fputs( "</TITLE>\n</HEAD>\n<BODY>\n<FONT SIZE=\"3\" COLOR=\"#000000\">\n<P>", file );
  742.  
  743.   while( ++p <= end )
  744.     {
  745.  
  746.     /* Line breaks */
  747.  
  748.     if( nofill < 1 )
  749.       {
  750.  
  751.       if( '\n' == *p ) 
  752.         {
  753.  
  754.         /* Last character in email body is '\n' */
  755.         if( p == end )
  756.           {
  757.           fputs( "</P>\n", file );
  758.           continue;
  759.           }
  760.  
  761.         /* Several '\n's in a row */
  762.         else if( ((p+1) <= end) && ('\n' == *(p+1)) )
  763.           {
  764.  
  765.           /* Two '\n's in a row */
  766.           if( (((p+2) <= end) && ('\n' != *(p+2))) || ((p+1) == end) )
  767.             {
  768.             /* Two '\n's in a row */
  769.             fputs( "<BR>\n", file );
  770.             p += 1;
  771.             continue;
  772.             }
  773.  
  774.           /* More than two '\n's in a row */
  775.           else
  776.             {
  777.             fputs( "</P>\n<P>", file );
  778.             while( (p < end) && ('\n' == *(p+1)) )
  779.               p += 1;
  780.             continue;
  781.             }
  782.  
  783.           }
  784.  
  785.         /* Single '\n' and no formatting command that forces a linebreak */
  786.         else if( 0 == linebreak )
  787.           {
  788.           fputc( ' ', file );
  789.           continue;
  790.           }
  791.  
  792.         /* Single '\n' before or after a formatting command that forces a linebreak */
  793.         else
  794.           {
  795.           fputs( "<BR>", file );
  796.           linebreak = 0;
  797.           continue;
  798.           }
  799.  
  800.         }   /* end if */
  801.  
  802.       /* No '\n' but a formatting command that forces a linebreak */
  803.       else if( linebreak > 0 )
  804.         {
  805.         fputs( "<BR>", file );
  806.         linebreak = 0;
  807.         /* No 'continue' here, since *p != '\n' */
  808.         }
  809.  
  810.       }   /* end if */
  811.  
  812.     /* Formatting commands */
  813.  
  814.     if( '<' == *p ) 
  815.       {
  816.  
  817.       if( '<' == *(p+1) )
  818.         {
  819.         fputs( "<", file );
  820.         p += 1;
  821.         continue;
  822.         }
  823.  
  824.       else if( EQUAL == strnicmp(p+1,BIGGER_START,strlen(BIGGER_START)) )
  825.         {
  826.         prefont = (pre > 0);
  827.         /* Ignore font changes inside of <PRE>...</PRE> */
  828.         if( NO == prefont )
  829.           {
  830.           bigger += 1;
  831.           fontsize = min( FONTSIZE_MAX, FONTSIZE_DEFAULT + bigger - smaller );
  832.           changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  833.           }
  834.         p += 1 + strlen(BIGGER_START);
  835.         continue;
  836.         }
  837.       else if( EQUAL == strnicmp(p+1,BIGGER_END,strlen(BIGGER_END)) )
  838.         {
  839.         prefont = (pre > 0);
  840.         /* Ignore font changes inside of <PRE>...</PRE> */
  841.         if( NO == prefont )
  842.           {
  843.           bigger -= 1;
  844.           fontsize = FONTSIZE_DEFAULT + max( 0, bigger - smaller );
  845.           changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  846.           }
  847.         p += 1 + strlen(BIGGER_END);
  848.         continue;
  849.         }
  850.  
  851.       else if( EQUAL == strnicmp(p+1,BOLD_START,strlen(BOLD_START)) )
  852.         {
  853.         prefont = (pre > 0);
  854.         /* Ignore font changes inside of <PRE>...</PRE> */
  855.         if( NO == prefont )
  856.           {
  857.           bold += 1;
  858.           fputs( "<B>", file );
  859.           }
  860.         p += 1 + strlen(BOLD_START);
  861.         continue;
  862.         }
  863.       else if( EQUAL == strnicmp(p+1,BOLD_END,strlen(BOLD_END)) )
  864.         {
  865.         prefont = (pre > 0);
  866.         /* Ignore font changes inside of <PRE>...</PRE> */
  867.         if( NO == prefont )
  868.           {
  869.           bold -= 1;
  870.           fputs( "</B>", file );
  871.           }
  872.         p += 1 + strlen(BOLD_END);
  873.         continue;
  874.         }
  875.  
  876.       else if( EQUAL == strnicmp(p+1,CENTER_START,strlen(CENTER_START)) )
  877.         {
  878.         /* <CENTER> will cause a line break in text/html automatically */
  879.         fputs( "<CENTER>", file );
  880.         p += 1 + strlen(CENTER_START);
  881.         continue;
  882.         }
  883.       else if( EQUAL == strnicmp(p+1,CENTER_END,strlen(CENTER_END)) )
  884.         {
  885.         /* </CENTER> will cause a line break in text/html automatically */
  886.         fputs( "</CENTER>", file );
  887.         p += 1 + strlen(CENTER_END);
  888.         continue;
  889.         }
  890.  
  891.       else if( EQUAL == strnicmp(p+1,COLOR_START,strlen(COLOR_START)) )
  892.         {
  893.  
  894.         /* Skip <color> */
  895.         p += 1 + strlen(COLOR_START);
  896.  
  897.         /* Skip <param> */
  898.         while( '<' != *p )
  899.           p += 1;
  900.         p += strlen(PARAM_START) + 2;
  901.         i = 0;
  902.  
  903.         /* Read color code and convert to text/html format */
  904.         while( '<' != *p )
  905.           {
  906.           /* Ignore spaces */
  907.           if( ' ' == *p )
  908.             {
  909.             p += 1;
  910.             continue;
  911.             }
  912.           /* Read digits and commas */
  913.           richcolor[i] = *p;
  914.           i += 1;
  915.           p += 1;
  916.           }
  917.         richcolor[i] = '\0';
  918.  
  919.         /* Ignore font changes inside of <PRE>...</PRE> */
  920.         prefont = (pre > 0);
  921.         if( NO == prefont )
  922.           convcolor( richcolor, fontcolor );
  923.  
  924.         /* Skip </param> */
  925.         p += 1 + strlen(PARAM_END);
  926.  
  927.         /* Change font settings, but ignore font changes inside of <PRE>...</PRE> */
  928.         if( NO == prefont )
  929.           changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  930.         
  931.         continue;
  932.  
  933.         }
  934.       else if( EQUAL == strnicmp(p+1,COLOR_END,strlen(COLOR_END)) )
  935.         {
  936.  
  937.         strcpy( fontcolor, "000000" );   /* To be done: Should be reset to previous color, not to default */
  938.  
  939.         prefont = (pre > 0);
  940.         /* Change font settings, if not inside of <PRE>...</PRE> */
  941.         if( NO == prefont )
  942.           changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  943.  
  944.         p += 1 + strlen(COLOR_END);
  945.  
  946.         continue;
  947.  
  948.         }
  949.  
  950.       else if( EQUAL == strnicmp(p+1,EXCERPT_START,strlen(EXCERPT_START)) )
  951.         {
  952.         fputs( "<BLOCKQUOTE>", file );
  953.         p += 1 + strlen(EXCERPT_START);
  954.         continue;
  955.         }
  956.       else if( EQUAL == strnicmp(p+1,EXCERPT_END,strlen(EXCERPT_END)) )
  957.         {
  958.         fputs( "</BLOCKQUOTE>", file );
  959.         p += 1 + strlen(EXCERPT_END);
  960.         continue;
  961.         }
  962.  
  963.       else if( EQUAL == strnicmp(p+1,FIXED_START,strlen(FIXED_START)) )
  964.         {
  965.         prefont = (pre > 0);
  966.         /* Ignore font changes inside of <PRE>...</PRE> */
  967.         if( NO == prefont )
  968.           {
  969.           teletype += 1;
  970.           fputs( "<TT>", file );
  971.           }
  972.         p += 1 + strlen(FIXED_START);
  973.         continue;
  974.         }
  975.       else if( EQUAL == strnicmp(p+1,FIXED_END,strlen(FIXED_END)) )
  976.         {
  977.         prefont = (pre > 0);
  978.         /* Ignore font changes inside of <PRE>...</PRE> */
  979.         if( NO == prefont )
  980.           {
  981.           teletype -= 1;
  982.           fputs( "</TT>", file );
  983.           }
  984.         p += 1 + strlen(FIXED_END);
  985.         continue;
  986.         }
  987.  
  988.       else if( EQUAL == strnicmp(p+1,FLUSHBOTH_START,strlen(FLUSHBOTH_START)) )
  989.         {
  990.         p += 1 + strlen(FLUSHBOTH_START);
  991.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHBOTH_START))) )
  992.           linebreak += 1;
  993.         continue;
  994.         }
  995.       else if( EQUAL == strnicmp(p+1,FLUSHBOTH_END,strlen(FLUSHBOTH_END)) )
  996.         {
  997.         p += 1 + strlen(FLUSHBOTH_END);
  998.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHBOTH_END))) )
  999.           linebreak += 1;
  1000.         continue;
  1001.         }
  1002.  
  1003.       else if( EQUAL == strnicmp(p+1,FLUSHLEFT_START,strlen(FLUSHLEFT_START)) )
  1004.         {
  1005.         p += 1 + strlen(FLUSHLEFT_START);
  1006.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHLEFT_START))) )
  1007.           linebreak += 1;
  1008.         continue;
  1009.         }
  1010.       else if( EQUAL == strnicmp(p+1,FLUSHLEFT_END,strlen(FLUSHLEFT_END)) )
  1011.         {
  1012.         p += 1 + strlen(FLUSHLEFT_END);
  1013.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHLEFT_END))) )
  1014.           linebreak += 1;
  1015.         continue;
  1016.         }
  1017.  
  1018.       else if( EQUAL == strnicmp(p+1,FLUSHRIGHT_START,strlen(FLUSHRIGHT_START)) )
  1019.         {
  1020.         p += 1 + strlen(FLUSHRIGHT_START);
  1021.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHRIGHT_START))) )
  1022.           linebreak += 1;
  1023.         continue;
  1024.         }
  1025.       else if( EQUAL == strnicmp(p+1,FLUSHRIGHT_END,strlen(FLUSHRIGHT_END)) )
  1026.         {
  1027.         p += 1 + strlen(FLUSHRIGHT_END);
  1028.         if( ('\n' != *(p-1)) && ('\n' != *(p+2+strlen(FLUSHRIGHT_END))) )
  1029.           linebreak += 1;
  1030.         continue;
  1031.         }
  1032.  
  1033.       else if( EQUAL == strnicmp(p+1,ITALIC_START,strlen(ITALIC_START)) )
  1034.         {
  1035.         prefont = (pre > 0);
  1036.         /* Ignore font changes inside of <PRE>...</PRE> */
  1037.         if( NO == prefont )
  1038.           {
  1039.           italic += 1;
  1040.           fputs( "<I>", file );
  1041.           }
  1042.         p += 1 + strlen(ITALIC_START);
  1043.         continue;
  1044.         }
  1045.       else if( EQUAL == strnicmp(p+1,ITALIC_END,strlen(ITALIC_END)) )
  1046.         {
  1047.         prefont = (pre > 0);
  1048.         /* Ignore font changes inside of <PRE>...</PRE> */
  1049.         if( NO == prefont )
  1050.           {
  1051.           italic -= 1;
  1052.           fputs( "</I>", file );
  1053.           }
  1054.         p += 1 + strlen(ITALIC_END);
  1055.         continue;
  1056.         }
  1057.  
  1058.       else if( EQUAL == strnicmp(p+1,NOFILL_START,strlen(NOFILL_START)) )
  1059.         {
  1060.         nofill += 1;
  1061.         /* Write a <PRE> only for the first <nofill> */
  1062.         if( 1 == nofill )
  1063.           {
  1064.           pre += 1;
  1065.           fputs( "\n<PRE>", file );  
  1066.           }
  1067.         p += 1 + strlen(NOFILL_START);
  1068.         continue;
  1069.         }
  1070.       else if( EQUAL == strnicmp(p+1,NOFILL_END,strlen(NOFILL_END)) )
  1071.         {
  1072.         nofill -= 1;
  1073.         /* Write a </PRE> only for the last <nofill> */
  1074.         if( 0 == nofill )
  1075.           {
  1076.           pre -= 1;
  1077.           fputs( "</PRE>\n", file );
  1078.           }
  1079.         else if( 0 < nofill )
  1080.           fputs( "<BR>\n", file );
  1081.         p += 1 + strlen(NOFILL_END);
  1082.         continue;
  1083.         }
  1084.  
  1085.       else if( EQUAL == strnicmp(p+1,SMALLER_START,strlen(SMALLER_START)) )
  1086.         {
  1087.         prefont = (pre > 0);
  1088.         /* Ignore font changes inside of <PRE>...</PRE> */
  1089.         if( NO == prefont )
  1090.           {
  1091.           smaller += 1;
  1092.           fontsize = max( FONTSIZE_MIN, FONTSIZE_DEFAULT - smaller + bigger );
  1093.             changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  1094.           }
  1095.         p += 1 + strlen(SMALLER_START);
  1096.         continue;
  1097.         }
  1098.       else if( EQUAL == strnicmp(p+1,SMALLER_END,strlen(SMALLER_END)) )
  1099.         {
  1100.         prefont = (pre > 0);
  1101.         /* Ignore font changes inside of <PRE>...</PRE> */
  1102.         if( NO == prefont )
  1103.           {
  1104.           smaller -= 1;
  1105.           fontsize = FONTSIZE_DEFAULT - min( 0, smaller - bigger );
  1106.             changefont( file, fontsize, fontcolor, bold, italic, underline, teletype );
  1107.           }
  1108.         p += 1 + strlen(SMALLER_END);
  1109.         continue;
  1110.         }
  1111.  
  1112.       else if( EQUAL == strnicmp(p+1,UNDERLINE_START,strlen(UNDERLINE_START)) )
  1113.         {
  1114.         prefont = (pre > 0);
  1115.         /* Ignore font changes inside of <PRE>...</PRE> */
  1116.         if( NO == prefont )
  1117.           {
  1118.           underline += 1;
  1119.           fputs( "<U>", file );
  1120.           }
  1121.         p += 1 + strlen(UNDERLINE_START);
  1122.         continue;
  1123.         }
  1124.       else if( EQUAL == strnicmp(p+1,UNDERLINE_END,strlen(UNDERLINE_END)) )
  1125.         {
  1126.         prefont = (pre > 0);
  1127.         /* Ignore font changes inside of <PRE>...</PRE> */
  1128.         if( NO == prefont )
  1129.           {
  1130.           underline -= 1;
  1131.           fputs( "</U>", file );
  1132.           }
  1133.         p += 1 + strlen(UNDERLINE_END);
  1134.         continue;
  1135.         }
  1136.  
  1137.       /* Ignore other <param> sections */
  1138.       else if( EQUAL == strnicmp(p+1,PARAM_START,strlen(PARAM_START)) )
  1139.         {
  1140.         param += 1;
  1141.         p += 1 + strlen(PARAM_START);
  1142.         continue;
  1143.         }
  1144.       else if( EQUAL == strnicmp(p+1,PARAM_END,strlen(PARAM_END)) )
  1145.         {
  1146.         param -= 1;
  1147.         p += 1 + strlen(PARAM_END);
  1148.         continue;
  1149.         }
  1150.  
  1151.       /* Ignore unknown commands */
  1152.       else
  1153.         {
  1154.         while( '>' != *p )
  1155.           p += 1;
  1156.         continue;
  1157.         }
  1158.  
  1159.       }   /* end if */
  1160.  
  1161.     if( param > 0 )
  1162.       continue;
  1163.     else if( '>' == *p )
  1164.       fputs( ">", file );
  1165.     else
  1166.       fputc( *p, file );
  1167.  
  1168.     }   /* end while */
  1169.  
  1170.   if( '\n' != *end )
  1171.     fputs( "</P>\n", file );
  1172.  
  1173.   fputs( "\n</FONT>\n</BODY>\n</HTML>\n", file );
  1174.  
  1175.   return;
  1176.  
  1177.   }
  1178.  
  1179.  
  1180. /************************************************************************* 
  1181.  *                                                                       * 
  1182.  * convcolor()                                                           * 
  1183.  * Convert color from text/enriched format (rrrr,gggg,bbbb or            * 
  1184.  * text/enriched color name) to text/html (rrggbb or text/html color     * 
  1185.  * name)                                                                 * 
  1186.  *                                                                       * 
  1187.  *************************************************************************/
  1188. char* convcolor ( char* richcolor, char* htmlcolor )
  1189.   {
  1190.  
  1191.   char red[5];
  1192.   int r;
  1193.   char blue[5];
  1194.   int b;
  1195.   char green[5];
  1196.   int g;
  1197.   char s[20];
  1198.  
  1199.   if( EQUAL == stricmp("black",richcolor) ) 
  1200.     {
  1201.     strcpy( htmlcolor, "000000" );
  1202.     return htmlcolor;
  1203.     }
  1204.  
  1205.   if( EQUAL == stricmp("blue",richcolor) ) 
  1206.     {
  1207.     strcpy( htmlcolor, "0000FF" );
  1208.     return htmlcolor;
  1209.     }
  1210.  
  1211.   if( EQUAL == stricmp("cyan",richcolor) ) 
  1212.     {
  1213.     strcpy( htmlcolor, "00FFFF" );
  1214.     return htmlcolor;
  1215.     }
  1216.  
  1217.   if( EQUAL == stricmp("green",richcolor) ) 
  1218.     {
  1219.     strcpy( htmlcolor, "00FF00" );
  1220.     return htmlcolor;
  1221.     }
  1222.  
  1223.   if( EQUAL == stricmp("magenta",richcolor) ) 
  1224.     {
  1225.     strcpy( htmlcolor, "FF00FF" );
  1226.     return htmlcolor;
  1227.     }
  1228.  
  1229.   if( EQUAL == stricmp("red",richcolor) ) 
  1230.     {
  1231.     strcpy( htmlcolor, "FF0000" );
  1232.     return htmlcolor;
  1233.     }
  1234.  
  1235.   if( EQUAL == stricmp("white",richcolor) ) 
  1236.     {
  1237.     strcpy( htmlcolor, "FFFFFF" );
  1238.     return htmlcolor;
  1239.     }
  1240.  
  1241.   if( EQUAL == stricmp("yellow",richcolor) ) 
  1242.     {
  1243.     strcpy( htmlcolor, "FFFF00" );
  1244.     return htmlcolor;
  1245.     }
  1246.  
  1247.   /* 
  1248.   At this point the text/enriched color is assumed to be of format rrrr,gggg,bbbb 
  1249.   (This is some probably not very fault tolerant code...)
  1250.   */
  1251.  
  1252.   strcpy( red, strtok(richcolor,",") );
  1253.   strcpy( green, strtok(NULL,",") );
  1254.   strcpy( blue, strtok(NULL,",") );
  1255.  
  1256.   /* Color experts may know of a better color mapping... */
  1257.   r = floor( xtoi(red) / 65536.0 * 256.0 + 0.5 );
  1258.   g = floor( xtoi(green) / 65536.0 * 256.0 + 0.5 );
  1259.   b = floor( xtoi(blue) / 65536.0 * 256.0 + 0.5 );
  1260.  
  1261.   strcpy( htmlcolor, itox(r,s) );
  1262.   strcat( htmlcolor, itox(g,s) );
  1263.   strcat( htmlcolor, itox(b,s) );
  1264.  
  1265.   return htmlcolor;
  1266.  
  1267.   }
  1268.  
  1269.  
  1270. /************************************************************************* 
  1271.  *                                                                       * 
  1272.  * xtoi()                                                                * 
  1273.  * Convert 4-digit hexadecimal string to integer                         * 
  1274.  *                                                                       * 
  1275.  *************************************************************************/
  1276. int xtoi ( char* hex )
  1277.   {
  1278.  
  1279.   int i;
  1280.   int n = 0;
  1281.  
  1282.   for( i = 0; i < strlen(hex); i += 1 )
  1283.     {
  1284.  
  1285.     n *= 16;
  1286.  
  1287.     switch( hex[i] )
  1288.       {
  1289.       case '0': break;
  1290.       case '1': n += 1;  break;
  1291.       case '2': n += 2;  break;
  1292.       case '3': n += 3;  break;
  1293.       case '4': n += 4;  break;
  1294.       case '5': n += 5;  break;
  1295.       case '6': n += 6;  break;
  1296.       case '7': n += 7;  break;
  1297.       case '8': n += 8;  break;
  1298.       case '9': n += 9;  break;
  1299.       case 'a': ;
  1300.       case 'A': n += 10; break;
  1301.       case 'b': ;
  1302.       case 'B': n += 11; break;
  1303.       case 'c': ;
  1304.       case 'C': n += 12; break;
  1305.       case 'd': ;
  1306.       case 'D': n += 13; break;
  1307.       case 'e': ;
  1308.       case 'E': n += 14; break;
  1309.       case 'f': ;
  1310.       case 'F': n += 15; break;
  1311.       default:  
  1312.         return 0;
  1313.       }
  1314.  
  1315.     }   /* end for */
  1316.  
  1317.   return n;
  1318.  
  1319.   }
  1320.  
  1321.  
  1322. /************************************************************************* 
  1323.  *                                                                       * 
  1324.  * itox()                                                                * 
  1325.  * Convert integer (0..255) to 2 character hex string                    * 
  1326.  *                                                                       * 
  1327.  *************************************************************************/
  1328. char* itox ( int n, char* hex )
  1329.   {
  1330.  
  1331.   if( n < 0 ) 
  1332.     { 
  1333.     strcpy( hex, "00" ); 
  1334.     return hex;
  1335.     }
  1336.  
  1337.   if( n > 255 ) 
  1338.     { 
  1339.     strcpy( hex, "FF" ); 
  1340.     return hex; 
  1341.     }
  1342.  
  1343.   switch( n / 16 )
  1344.     {
  1345.     case 0:  hex[0] = '0'; break;
  1346.     case 1:  hex[0] = '1'; break;
  1347.     case 2:  hex[0] = '2'; break;
  1348.     case 3:  hex[0] = '3'; break;
  1349.     case 4:  hex[0] = '4'; break;
  1350.     case 5:  hex[0] = '5'; break;
  1351.     case 6:  hex[0] = '6'; break;
  1352.     case 7:  hex[0] = '7'; break;
  1353.     case 8:  hex[0] = '8'; break;
  1354.     case 9:  hex[0] = '9'; break;
  1355.     case 10: hex[0] = 'A'; break;
  1356.     case 11: hex[0] = 'B'; break;
  1357.     case 12: hex[0] = 'C'; break;
  1358.     case 13: hex[0] = 'D'; break;
  1359.     case 14: hex[0] = 'E'; break;
  1360.     case 15: hex[0] = 'F'; break;
  1361.     }
  1362.  
  1363.   switch( n % 16 )
  1364.     {
  1365.     case 0:  hex[1] = '0'; break;
  1366.     case 1:  hex[1] = '1'; break;
  1367.     case 2:  hex[1] = '2'; break;
  1368.     case 3:  hex[1] = '3'; break;
  1369.     case 4:  hex[1] = '4'; break;
  1370.     case 5:  hex[1] = '5'; break;
  1371.     case 6:  hex[1] = '6'; break;
  1372.     case 7:  hex[1] = '7'; break;
  1373.     case 8:  hex[1] = '8'; break;
  1374.     case 9:  hex[1] = '9'; break;
  1375.     case 10: hex[1] = 'A'; break;
  1376.     case 11: hex[1] = 'B'; break;
  1377.     case 12: hex[1] = 'C'; break;
  1378.     case 13: hex[1] = 'D'; break;
  1379.     case 14: hex[1] = 'E'; break;
  1380.     case 15: hex[1] = 'F'; break;
  1381.     }
  1382.  
  1383.   hex[2] = '\0';
  1384.   return hex;
  1385.  
  1386.   }
  1387.  
  1388.  
  1389. /************************************************************************* 
  1390.  *                                                                       * 
  1391.  * changefont()                                                          * 
  1392.  * Write </FONT><FONT SIZE="..." COLOR="#...">                           * 
  1393.  *                                                                       * 
  1394.  *************************************************************************/
  1395. void changefont ( FILE* file, int size, char* color, int bold, int italic, int underline, int teletype )
  1396.   {
  1397.  
  1398.   char dummy[2];
  1399.  
  1400.   if( bold > 0 )
  1401.     fputs( "</B>", file );
  1402.   if( italic > 0 )
  1403.     fputs( "</I>", file );
  1404.   if( underline > 0 )
  1405.     fputs( "</U>", file );
  1406.   if( teletype > 0 )
  1407.     fputs( "</TT>", file );
  1408.  
  1409.   fputs( "</FONT><FONT SIZE=\"", file );
  1410.   fputs( (char*)_itoa(size,dummy,10), file );
  1411.   fputs( "\" COLOR=\"#", file );
  1412.   fputs( color, file );
  1413.   fputs( "\">", file );
  1414.  
  1415.   if( teletype > 0 )
  1416.     fputs( "<TT>", file );
  1417.   if( underline > 0 )
  1418.     fputs( "<U>", file );
  1419.   if( italic > 0 )
  1420.     fputs( "<I>", file );
  1421.   if( bold > 0 )
  1422.     fputs( "<B>", file );
  1423.  
  1424.   return;
  1425.  
  1426.   }
  1427.  
  1428.  
  1429.