1/* 2 * b2m - a filter for Babyl -> Unix mail files 3 * The copyright on this file has been disclaimed. 4 * 5 * usage: b2m < babyl > mailbox 6 * 7 * I find this useful whenever I have to use a 8 * system which - shock horror! - doesn't run 9 * GNU Emacs. At least now I can read all my 10 * GNU Emacs Babyl format mail files! 11 * 12 * it's not much but it's free! 13 * 14 * Ed Wilkinson 15 * E.Wilkinson@massey.ac.nz 16 * Mon Nov 7 15:54:06 PDT 1988 17 */ 18 19/* Made conformant to the GNU coding standards January, 1995 20 by Francesco Potorti` <pot@cnuce.cnr.it>. */ 21 22#ifdef HAVE_CONFIG_H 23#include <config.h> 24/* On some systems, Emacs defines static as nothing for the sake 25 of unexec. We don't want that here since we don't use unexec. */ 26#undef static 27#endif 28 29#include <stdio.h> 30#include <time.h> 31#include <sys/types.h> 32#include <getopt.h> 33#ifdef MSDOS 34#include <fcntl.h> 35#endif 36 37#undef TRUE 38#define TRUE 1 39#undef FALSE 40#define FALSE 0 41 42#define streq(s,t) (strcmp (s, t) == 0) 43#define strneq(s,t,n) (strncmp (s, t, n) == 0) 44 45typedef int logical; 46 47#define TM_YEAR_BASE 1900 48 49/* Nonzero if TM_YEAR is a struct tm's tm_year value that causes 50 asctime to have well-defined behavior. */ 51#ifndef TM_YEAR_IN_ASCTIME_RANGE 52# define TM_YEAR_IN_ASCTIME_RANGE(tm_year) \ 53 (1000 - TM_YEAR_BASE <= (tm_year) && (tm_year) <= 9999 - TM_YEAR_BASE) 54#endif 55 56/* 57 * A `struct linebuffer' is a structure which holds a line of text. 58 * `readline' reads a line from a stream into a linebuffer and works 59 * regardless of the length of the line. 60 */ 61struct linebuffer 62{ 63 long size; 64 char *buffer; 65}; 66 67extern char *strtok(); 68 69long *xmalloc (), *xrealloc (); 70char *concat (); 71long readline (); 72void fatal (); 73 74/* 75 * xnew -- allocate storage. SYNOPSIS: Type *xnew (int n, Type); 76 */ 77#define xnew(n, Type) ((Type *) xmalloc ((n) * sizeof (Type))) 78 79 80 81char *progname; 82 83struct option longopts[] = 84{ 85 { "help", no_argument, NULL, 'h' }, 86 { "version", no_argument, NULL, 'V' }, 87 { 0 } 88}; 89 90extern int optind; 91 92int 93main (argc, argv) 94 int argc; 95 char **argv; 96{ 97 logical labels_saved, printing, header; 98 time_t ltoday; 99 struct tm *tm; 100 char *labels, *p, *today; 101 struct linebuffer data; 102 103#ifdef MSDOS 104 _fmode = O_BINARY; /* all of files are treated as binary files */ 105#if __DJGPP__ > 1 106 if (!isatty (fileno (stdout))) 107 setmode (fileno (stdout), O_BINARY); 108 if (!isatty (fileno (stdin))) 109 setmode (fileno (stdin), O_BINARY); 110#else /* not __DJGPP__ > 1 */ 111 (stdout)->_flag &= ~_IOTEXT; 112 (stdin)->_flag &= ~_IOTEXT; 113#endif /* not __DJGPP__ > 1 */ 114#endif 115 progname = argv[0]; 116 117 while (1) 118 { 119 int opt = getopt_long (argc, argv, "hV", longopts, 0); 120 if (opt == EOF) 121 break; 122 123 switch (opt) 124 { 125 case 'V': 126 printf ("%s (GNU Emacs %s)\n", "b2m", VERSION); 127 puts ("b2m is in the public domain."); 128 exit (EXIT_SUCCESS); 129 130 case 'h': 131 fprintf (stderr, "Usage: %s <babylmailbox >unixmailbox\n", progname); 132 exit (EXIT_SUCCESS); 133 } 134 } 135 136 if (optind != argc) 137 { 138 fprintf (stderr, "Usage: %s <babylmailbox >unixmailbox\n", progname); 139 exit (EXIT_SUCCESS); 140 } 141 142 labels_saved = printing = header = FALSE; 143 ltoday = time (0); 144 /* Convert to a string, checking for out-of-range time stamps. 145 Don't use 'ctime', as that might dump core if the hardware clock 146 is set to a bizarre value. */ 147 tm = localtime (<oday); 148 if (! (tm && TM_YEAR_IN_ASCTIME_RANGE (tm->tm_year) 149 && (today = asctime (tm)))) 150 fatal ("current time is out of range"); 151 data.size = 200; 152 data.buffer = xnew (200, char); 153 154 if (readline (&data, stdin) == 0 155 || !strneq (data.buffer, "BABYL OPTIONS:", 14)) 156 fatal ("standard input is not a Babyl mailfile."); 157 158 while (readline (&data, stdin) > 0) 159 { 160 if (streq (data.buffer, "*** EOOH ***") && !printing) 161 { 162 printing = header = TRUE; 163 printf ("From \"Babyl to mail by %s\" %s", progname, today); 164 continue; 165 } 166 167 if (data.buffer[0] == '\037') 168 { 169 if (data.buffer[1] == '\0') 170 continue; 171 else if (data.buffer[1] == '\f') 172 { 173 /* Save labels. */ 174 readline (&data, stdin); 175 p = strtok (data.buffer, " ,\r\n\t"); 176 labels = "X-Babyl-Labels: "; 177 178 while ((p = strtok (NULL, " ,\r\n\t"))) 179 labels = concat (labels, p, ", "); 180 181 p = &labels[strlen (labels) - 2]; 182 if (*p == ',') 183 *p = '\0'; 184 printing = header = FALSE; 185 labels_saved = TRUE; 186 continue; 187 } 188 } 189 190 if ((data.buffer[0] == '\0') && header) 191 { 192 header = FALSE; 193 if (labels_saved) 194 puts (labels); 195 } 196 197 if (printing) 198 puts (data.buffer); 199 } 200 201 return EXIT_SUCCESS; 202} 203 204 205 206/* 207 * Return a newly-allocated string whose contents 208 * concatenate those of s1, s2, s3. 209 */ 210char * 211concat (s1, s2, s3) 212 char *s1, *s2, *s3; 213{ 214 int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3); 215 char *result = xnew (len1 + len2 + len3 + 1, char); 216 217 strcpy (result, s1); 218 strcpy (result + len1, s2); 219 strcpy (result + len1 + len2, s3); 220 result[len1 + len2 + len3] = '\0'; 221 222 return result; 223} 224 225/* 226 * Read a line of text from `stream' into `linebuffer'. 227 * Return the number of characters read from `stream', 228 * which is the length of the line including the newline, if any. 229 */ 230long 231readline (linebuffer, stream) 232 struct linebuffer *linebuffer; 233 register FILE *stream; 234{ 235 char *buffer = linebuffer->buffer; 236 register char *p = linebuffer->buffer; 237 register char *pend; 238 int chars_deleted; 239 240 pend = p + linebuffer->size; /* Separate to avoid 386/IX compiler bug. */ 241 242 while (1) 243 { 244 register int c = getc (stream); 245 if (p == pend) 246 { 247 linebuffer->size *= 2; 248 buffer = (char *) xrealloc (buffer, linebuffer->size); 249 p += buffer - linebuffer->buffer; 250 pend = buffer + linebuffer->size; 251 linebuffer->buffer = buffer; 252 } 253 if (c == EOF) 254 { 255 *p = '\0'; 256 chars_deleted = 0; 257 break; 258 } 259 if (c == '\n') 260 { 261 if (p > buffer && p[-1] == '\r') 262 { 263 *--p = '\0'; 264 chars_deleted = 2; 265 } 266 else 267 { 268 *p = '\0'; 269 chars_deleted = 1; 270 } 271 break; 272 } 273 *p++ = c; 274 } 275 276 return (p - buffer + chars_deleted); 277} 278 279/* 280 * Like malloc but get fatal error if memory is exhausted. 281 */ 282long * 283xmalloc (size) 284 unsigned int size; 285{ 286 long *result = (long *) malloc (size); 287 if (result == NULL) 288 fatal ("virtual memory exhausted"); 289 return result; 290} 291 292long * 293xrealloc (ptr, size) 294 char *ptr; 295 unsigned int size; 296{ 297 long *result = (long *) realloc (ptr, size); 298 if (result == NULL) 299 fatal ("virtual memory exhausted"); 300 return result; 301} 302 303void 304fatal (message) 305 char *message; 306{ 307 fprintf (stderr, "%s: %s\n", progname, message); 308 exit (EXIT_FAILURE); 309} 310 311/* arch-tag: 5a3ad2af-a802-408f-83cc-e7cf5e98653e 312 (do not change this comment) */ 313 314/* b2m.c ends here */ 315