1 /*
2 * DATE.C
3 *
4 * Written on 30-Jul-90 by jim nutt. Changes on 10-Jul-94 by John Dennis.
5 * Released to the public domain.
6 *
7 * Parse various string date formats into a UNIX style timestamp.
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <time.h>
15 #include "addr.h"
16 #include "nedit.h"
17 #include "msged.h"
18 #include "memextra.h"
19 #include "strextra.h"
20 #include "date.h"
21 #include "mctype.h"
22
23 static char *month[] =
24 {
25 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
26 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
27 };
28
29 static char *day[] =
30 {
31 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
32 };
33
34 static char *attr_tokens[] =
35 {
36 "yms", /* year of message creation */
37 "yno", /* current year */
38 "mms", /* month of message creation */
39 "mno", /* current month */
40 "dms", /* day of message creation */
41 "dno", /* current day */
42 "wms", /* weekday of message creation */
43 "wno", /* current weekday */
44 "tnm", /* (normal) time of message creation */
45 "tnn", /* (normal) current time */
46 "tam", /* (atime) time of message creation */
47 "tan", /* (atime) current time */
48
49 "ofn", /* orginal from name */
50 "off", /* original from first name */
51 "otn", /* original to name */
52 "otf", /* original to first name */
53 "osu", /* original subject */
54 "ooa", /* original originination address */
55 "oda", /* orginal destination address */
56
57 "fna", /* from name */
58 "ffn", /* from first name */
59 "fad", /* from address */
60 "tna", /* to name */
61 "tfn", /* to first name */
62 "tad", /* to address */
63 "sub", /* subject */
64
65 "una", /* user name */
66 "ufn", /* user first name */
67 "uad", /* user address */
68 "ceh", /* current conference name */
69 "oeh", /* original conference name */
70
71 "ims", /* (iso) date of message creation */
72 "ino", /* (iso) current date */
73 "cms", /* four-digit year of message creation */
74 "cno", /* current four-digit year */
75
76 NULL
77 };
78
79 #define ATTR_TOK_YMS 0
80 #define ATTR_TOK_YMO 1
81 #define ATTR_TOK_MMS 2
82 #define ATTR_TOK_MNO 3
83 #define ATTR_TOK_DMS 4
84 #define ATTR_TOK_DNO 5
85 #define ATTR_TOK_WMS 6
86 #define ATTR_TOK_WNO 7
87 #define ATTR_TOK_TNM 8
88 #define ATTR_TOK_TNN 9
89 #define ATTR_TOK_TAM 10
90 #define ATTR_TOK_TAN 11
91 #define ATTR_TOK_OFN 12
92 #define ATTR_TOK_OFF 13
93 #define ATTR_TOK_OTN 14
94 #define ATTR_TOK_OTF 15
95 #define ATTR_TOK_OSU 16
96 #define ATTR_TOK_OOA 17
97 #define ATTR_TOK_ODA 18
98 #define ATTR_TOK_FNA 19
99 #define ATTR_TOK_FFN 20
100 #define ATTR_TOK_FAD 21
101 #define ATTR_TOK_TNA 22
102 #define ATTR_TOK_TFN 23
103 #define ATTR_TOK_TAD 24
104 #define ATTR_TOK_SUB 25
105 #define ATTR_TOK_UNA 26
106 #define ATTR_TOK_UFN 27
107 #define ATTR_TOK_UAD 28
108 #define ATTR_TOK_CEH 29
109 #define ATTR_TOK_OEH 30
110 #define ATTR_TOK_IMS 31
111 #define ATTR_TOK_INO 32
112 #define ATTR_TOK_CMS 33
113 #define ATTR_TOK_CNO 34
114
valid_date(struct tm * tms)115 static int valid_date(struct tm *tms)
116 {
117 return !(tms->tm_wday > 6 || tms->tm_wday < 0 || tms->tm_mon > 11 ||
118 tms->tm_mon < 0 || tms->tm_mday > 31 || tms->tm_mday < 0 ||
119 tms->tm_hour > 23 || tms->tm_hour < 0 || tms->tm_min > 59 ||
120 tms->tm_min < 0 || tms->tm_sec > 59 || tms->tm_sec < 0);
121 }
122
parsedate(char * ds)123 time_t parsedate(char *ds)
124 {
125 int t, absnow, absyear;
126 struct tm tm, *now;
127 char work[80], *s;
128 time_t n;
129
130 if (ds == NULL || *ds == '\0')
131 {
132 return 0;
133 }
134
135 memset(&tm, 0, sizeof tm);
136 strcpy(work, ds);
137
138 if (strchr(ds, '-') != NULL)
139 {
140 /* quickbbs style date */
141
142 s = strtok(work, "-");
143 if (s != NULL)
144 {
145 tm.tm_mon = atoi(s) - 1;
146 }
147 s = strtok(NULL, "-");
148 if (s != NULL)
149 {
150 tm.tm_mday = atoi(s);
151 }
152 s = strtok(NULL, " ");
153 if (s != NULL)
154 {
155 tm.tm_year = atoi(s);
156 }
157 s = strtok(NULL, ":");
158 if (s != NULL)
159 {
160 while (m_isspace(*s))
161 {
162 s++;
163 }
164 tm.tm_hour = atoi(s);
165 }
166 s = strtok(NULL, " ");
167 if (s != NULL)
168 {
169 tm.tm_min = atoi(s);
170 }
171 tm.tm_sec = 0;
172 }
173 else
174 {
175 /* fido style date */
176
177 s = strtok(work, " ");
178
179 if (s == NULL)
180 {
181 return 0;
182 }
183
184 t = atoi(s);
185 if (t == 0)
186 {
187 /* a usenet date */
188 s = strtok(NULL, " ");
189 if (s == NULL)
190 {
191 return 0;
192 }
193 t = atoi(s);
194 }
195 tm.tm_mday = t;
196 s = strtok(NULL, " ");
197 if (s == NULL)
198 {
199 return 0;
200 }
201 for (t = 0; t < 12; t++)
202 {
203 if (stricmp(s, month[t]) == 0)
204 {
205 break;
206 }
207 }
208 if (t == 12)
209 {
210 t = 1;
211 }
212 tm.tm_mon = t;
213 s = strtok(NULL, " ");
214 if (s == NULL)
215 {
216 return 0;
217 }
218 tm.tm_year = atoi(s);
219 s = strtok(NULL, ":");
220 if (s == NULL)
221 {
222 return 0;
223 }
224 while (m_isspace(*s))
225 {
226 s++;
227 }
228 tm.tm_hour = atoi(s);
229 s = strtok(NULL, ": \0");
230 if (s == NULL)
231 {
232 return 0;
233 }
234 tm.tm_min = atoi(s);
235 s = strtok(NULL, " ");
236 if (s != NULL)
237 {
238 tm.tm_sec = atoi(s);
239 }
240 tm.tm_isdst = -1;
241 }
242
243 /* Now try to find out which century we're in and fix the year */
244
245 n = time(NULL);
246 now = localtime(&n);
247
248 absnow = 1900 + now->tm_year;
249 absyear = 1900 + tm.tm_year;
250 while (absyear <= absnow-50)
251 absyear += 100;
252 while (absyear > absnow+50)
253 absyear -= 100;
254
255 tm.tm_year = absyear - 1900;
256
257 return mktime(&tm);
258 }
259
itime(time_t now)260 char *itime(time_t now)
261 {
262 struct tm *tm;
263 static char tmp[40];
264
265 tm = localtime(&now);
266
267 if (!tm || !valid_date(tm))
268 {
269 sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", 1970, 1, 1, 0, 0, 0);
270 }
271 else
272 {
273 sprintf(tmp, "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900,
274 tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
275 }
276
277 return tmp;
278 }
279
atime(time_t now)280 char *atime(time_t now)
281 {
282 struct tm *tm;
283 static char tmp[40];
284
285 tm = localtime(&now);
286
287 if (!tm || !valid_date(tm))
288 {
289 sprintf(tmp, "%s %s %02d %04d %02d:%02d:%02d", day[4], month[0],
290 1, 1970, 0, 0, 0);
291 }
292 else
293 {
294 sprintf(tmp, "%s %s %02d %04d %02d:%02d:%02d", day[tm->tm_wday],
295 month[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900, tm->tm_hour,
296 tm->tm_min, tm->tm_sec);
297 }
298
299 return tmp;
300 }
301
mtime(time_t now)302 char *mtime(time_t now)
303 {
304 struct tm *tm;
305 static char tmp[21];
306
307 tm = localtime(&now);
308
309 if (!tm || !valid_date(tm))
310 {
311 sprintf(tmp, "%02d %s %02d %02d:%02d:%02d", 1, month[0], 70, 0, 0, 0);
312 }
313 else
314 {
315 sprintf(tmp, "%02d %s %02d %02d:%02d:%02d", tm->tm_mday,
316 month[tm->tm_mon], tm->tm_year % 100, tm->tm_hour, tm->tm_min,
317 tm->tm_sec);
318 }
319
320 return tmp;
321 }
322
qtime(time_t now)323 char *qtime(time_t now)
324 {
325 struct tm *tm;
326 static char tmp[20];
327
328 tm = localtime(&now);
329
330 if (!tm || !valid_date(tm))
331 {
332 sprintf(tmp, "%s %02d %02d:%02d", month[0], 1, 0, 0);
333 }
334 else
335 {
336 sprintf(tmp, "%s %02d %02d:%02d", month[tm->tm_mon], tm->tm_mday,
337 tm->tm_hour, tm->tm_min);
338 }
339
340 return tmp;
341 }
342
343 /* find_token - returns the token number or -1 if not found */
344
find_token(char * token)345 static int find_token(char *token)
346 {
347 int i;
348 i = 0;
349 while (attr_tokens[i] != NULL)
350 {
351 if (stricmp(attr_tokens[i], token) == 0)
352 {
353 return i;
354 }
355 i++;
356 }
357 return -1;
358 }
359
360 /* Returns a pointer to the first name. Note: uses static memory. */
361
firstname(char * name)362 char *firstname(char *name)
363 {
364 char *s;
365 static char work[40];
366
367 memset(work, 0, sizeof work);
368 if (name == NULL)
369 {
370 return work;
371 }
372 s = strchr(name, ' ');
373 if (s == NULL)
374 {
375 sprintf(work, "%-.39s", name);
376 }
377 else
378 {
379 *s = '\0';
380 sprintf(work, "%-.39s", name);
381 *s = ' ';
382 }
383 return work;
384 }
385
386 /* Returns a pointer to the last name. Note: uses static memory. */
387
lastname(char * name)388 char *lastname(char *name)
389 {
390 char *s;
391 static char work[40];
392
393 memset(work, 0, sizeof work);
394 if (name == NULL)
395 {
396 return work;
397 }
398
399 s = strchr(name, ' ');
400 if (s == NULL)
401 {
402 sprintf(work, "%-.39s", name);
403 }
404 else
405 {
406 sprintf(work, "%-.39s", s + 1);
407 }
408 return work;
409 }
410
411
412 /* attrib_line - builds an attribution line */
413
attrib_line(msg * m,msg * old,int olda,char * format,char ** days,char ** months)414 char *attrib_line(msg * m, msg * old, int olda, char *format,
415 char **days, char **months)
416 {
417 struct tm now, *tm;
418 char work[256], token[5], *t;
419 time_t n;
420 int num;
421
422 if (days == NULL) days = day;
423 if (months == NULL) months = month;
424
425 if (format == NULL)
426 {
427 return NULL;
428 }
429
430 memset(work, 0, sizeof work);
431 t = work;
432 n = time(NULL);
433 tm = localtime(&n);
434 now = *tm;
435
436 if (old)
437 {
438 tm = localtime(&(old->timestamp));
439 }
440
441 while (*format)
442 {
443 if (*format == '%')
444 {
445 format++;
446 switch (*format)
447 {
448 case '%':
449 *t = *format;
450 break;
451
452 case '_':
453 *t = ' ';
454 break;
455
456 default:
457 memset(token, 0, sizeof token);
458 strncpy(token, format, 3);
459 num = find_token(token);
460
461 switch (num)
462 {
463 case ATTR_TOK_YMS:
464 if (old)
465 {
466 sprintf(t, "%02d", tm->tm_year % 100);
467 }
468 break;
469
470 case ATTR_TOK_YMO:
471 sprintf(t, "%02d", now.tm_year % 100);
472 break;
473
474 case ATTR_TOK_MMS:
475 if (old)
476 {
477 strcpy(t, months[tm->tm_mon]);
478 }
479 break;
480
481 case ATTR_TOK_MNO:
482 strcpy(t, months[now.tm_mon]);
483 break;
484
485 case ATTR_TOK_DMS:
486 if (old)
487 {
488 sprintf(t, "%02d", tm->tm_mday);
489 }
490 break;
491
492 case ATTR_TOK_DNO:
493 sprintf(t, "%02d", now.tm_mday);
494 break;
495
496 case ATTR_TOK_WMS:
497 if (old)
498 {
499 strcpy(t, days[tm->tm_wday]);
500 }
501 break;
502
503 case ATTR_TOK_WNO:
504 strcpy(t, days[now.tm_wday]);
505 break;
506
507 case ATTR_TOK_TNM:
508 if (old)
509 {
510 sprintf(t, "%02d:%02d", tm->tm_hour, tm->tm_min);
511 }
512 break;
513
514 case ATTR_TOK_TNN:
515 sprintf(t, "%02d:%02d", now.tm_hour, now.tm_min);
516 break;
517
518 case ATTR_TOK_TAM:
519 if (old)
520 {
521 strcpy(t, atime(old->timestamp));
522 }
523 break;
524
525 case ATTR_TOK_TAN:
526 strcpy(t, atime(n));
527 break;
528
529 case ATTR_TOK_OFN:
530 if (old && old->isfrom)
531 {
532 strcpy(t, old->isfrom);
533 }
534 break;
535
536 case ATTR_TOK_OFF:
537 if (old && old->isfrom)
538 {
539 strcpy(t, firstname(old->isfrom));
540 }
541 break;
542
543 case ATTR_TOK_OTN:
544 if (old && old->isto)
545 {
546 strcpy(t, old->isto);
547 }
548 break;
549
550 case ATTR_TOK_OTF:
551 if (old && old->isto)
552 {
553 strcpy(t, firstname(old->isto));
554 }
555 break;
556
557 case ATTR_TOK_OSU:
558 if (old && old->subj)
559 {
560 strcpy(t, old->subj);
561 }
562 break;
563
564 case ATTR_TOK_OOA:
565 if (old)
566 {
567 strcpy(t, show_address(&old->from));
568 }
569 break;
570
571 case ATTR_TOK_ODA:
572 if (old)
573 {
574 strcpy(t, show_address(&old->to));
575 }
576 break;
577
578 case ATTR_TOK_FNA:
579 if (m->isfrom)
580 {
581 strcpy(t, m->isfrom);
582 }
583 break;
584
585 case ATTR_TOK_FFN:
586 if (m->isfrom)
587 {
588 strcpy(t, firstname(m->isfrom));
589 }
590 break;
591
592 case ATTR_TOK_FAD:
593 strcpy(t, show_address(&m->from));
594 break;
595
596 case ATTR_TOK_TNA:
597 if (m->isto)
598 {
599 strcpy(t, m->isto);
600 }
601 break;
602
603 case ATTR_TOK_TFN:
604 if (m->isto)
605 {
606 strcpy(t, firstname(m->isto));
607 }
608 break;
609
610 case ATTR_TOK_TAD:
611 strcpy(t, show_address(&m->to));
612 break;
613
614 case ATTR_TOK_SUB:
615 strcpy(t, m->subj);
616 break;
617
618 case ATTR_TOK_UNA:
619 if (ST->username)
620 {
621 strcpy(t, ST->username);
622 }
623 break;
624
625 case ATTR_TOK_UFN:
626 if (ST->username)
627 {
628 strcpy(t, firstname(ST->username));
629 }
630 break;
631
632 case ATTR_TOK_UAD:
633 strcpy(t, show_address(&CurArea.addr));
634 break;
635
636 case ATTR_TOK_CEH:
637 strcpy(t, CurArea.tag);
638 break;
639
640 case ATTR_TOK_OEH:
641 if (olda != -1)
642 {
643 strcpy(t, arealist[olda].tag);
644 }
645 break;
646
647 case ATTR_TOK_IMS:
648 if (old != NULL)
649 {
650 sprintf(t, "%04d-%02d-%02d", tm->tm_year + 1900,
651 tm->tm_mon + 1, tm->tm_mday);
652 }
653 break;
654
655 case ATTR_TOK_INO:
656 sprintf(t, "%04d-%02d-%02d", now.tm_year + 1900,
657 now.tm_mon + 1, now.tm_mday);
658 break;
659
660 case ATTR_TOK_CMS:
661 if (old != NULL)
662 {
663 sprintf(t, "%04d", tm->tm_year + 1900);
664 }
665 break;
666
667 case ATTR_TOK_CNO:
668 sprintf(t, "%04d", now.tm_year + 1900);
669 break;
670
671 default:
672 break;
673 }
674 break;
675 }
676 t = work + strlen(work);
677 format += 3;
678 }
679 else
680 {
681 *t++ = *format++;
682 }
683 }
684 return xstrdup(work);
685 }
686