date.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <bio.h>
  12. #include <auth.h>
  13. #include "imap4d.h"
  14. char *
  15. wdayname[7] =
  16. {
  17. "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  18. };
  19. char *
  20. monname[12] =
  21. {
  22. "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  23. };
  24. static void time2tm(Tm *tm, char *s);
  25. static void zone2tm(Tm *tm, char *s);
  26. static int dateindex(char *d, char **tab, int n);
  27. int
  28. rfc822date(char *s, int n, Tm *tm)
  29. {
  30. char *plus;
  31. int m;
  32. plus = "+";
  33. if(tm->tzoff < 0)
  34. plus = "";
  35. m = 0;
  36. if(0 <= tm->wday && tm->wday < 7){
  37. m = snprint(s, n, "%s, ", wdayname[tm->wday]);
  38. if(m < 0)
  39. return m;
  40. }
  41. return snprint(s+m, n-m, "%.2d %s %.4d %.2d:%.2d:%.2d %s%.4d",
  42. tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec,
  43. plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
  44. }
  45. int
  46. imap4date(char *s, int n, Tm *tm)
  47. {
  48. char *plus;
  49. plus = "+";
  50. if(tm->tzoff < 0)
  51. plus = "";
  52. return snprint(s, n, "%2d-%s-%.4d %2.2d:%2.2d:%2.2d %s%4.4d",
  53. tm->mday, monname[tm->mon], tm->year+1900, tm->hour, tm->min, tm->sec, plus, (tm->tzoff/3600)*100 + (tm->tzoff/60)%60);
  54. }
  55. int
  56. imap4Date(Tm *tm, char *date)
  57. {
  58. char *flds[4];
  59. if(getfields(date, flds, 3, 0, "-") != 3)
  60. return 0;
  61. tm->mday = strtol(flds[0], nil, 10);
  62. tm->mon = dateindex(flds[1], monname, 12);
  63. tm->year = strtol(flds[2], nil, 10) - 1900;
  64. return 1;
  65. }
  66. /*
  67. * parse imap4 dates
  68. */
  69. uint32_t
  70. imap4DateTime(char *date)
  71. {
  72. Tm tm;
  73. char *flds[4], *sflds[4];
  74. uint32_t t;
  75. if(getfields(date, flds, 4, 0, " ") != 3)
  76. return ~0;
  77. if(!imap4Date(&tm, flds[0]))
  78. return ~0;
  79. if(getfields(flds[1], sflds, 3, 0, ":") != 3)
  80. return ~0;
  81. tm.hour = strtol(sflds[0], nil, 10);
  82. tm.min = strtol(sflds[1], nil, 10);
  83. tm.sec = strtol(sflds[2], nil, 10);
  84. strcpy(tm.zone, "GMT");
  85. tm.yday = 0;
  86. t = tm2sec(&tm);
  87. zone2tm(&tm, flds[2]);
  88. t -= tm.tzoff;
  89. return t;
  90. }
  91. /*
  92. * parse dates of formats
  93. * [Wkd[,]] DD Mon YYYY HH:MM:SS zone
  94. * [Wkd] Mon ( D|DD) HH:MM:SS zone YYYY
  95. * plus anything similar
  96. * return nil for a failure
  97. */
  98. Tm*
  99. date2tm(Tm *tm, char *date)
  100. {
  101. Tm gmt, *atm;
  102. char *flds[7], *s, dstr[64];
  103. int n;
  104. /*
  105. * default date is Thu Jan 1 00:00:00 GMT 1970
  106. */
  107. tm->wday = 4;
  108. tm->mday = 1;
  109. tm->mon = 1;
  110. tm->hour = 0;
  111. tm->min = 0;
  112. tm->sec = 0;
  113. tm->year = 70;
  114. strcpy(tm->zone, "GMT");
  115. tm->tzoff = 0;
  116. strncpy(dstr, date, sizeof(dstr));
  117. dstr[sizeof(dstr)-1] = '\0';
  118. n = tokenize(dstr, flds, 7);
  119. if(n != 6 && n != 5)
  120. return nil;
  121. if(n == 5){
  122. for(n = 5; n >= 1; n--)
  123. flds[n] = flds[n - 1];
  124. n = 5;
  125. }else{
  126. /*
  127. * Wday[,]
  128. */
  129. s = strchr(flds[0], ',');
  130. if(s != nil)
  131. *s = '\0';
  132. tm->wday = dateindex(flds[0], wdayname, 7);
  133. if(tm->wday < 0)
  134. return nil;
  135. }
  136. /*
  137. * check for the two major formats:
  138. * Month first or day first
  139. */
  140. tm->mon = dateindex(flds[1], monname, 12);
  141. if(tm->mon >= 0){
  142. tm->mday = strtoul(flds[2], nil, 10);
  143. time2tm(tm, flds[3]);
  144. zone2tm(tm, flds[4]);
  145. tm->year = strtoul(flds[5], nil, 10);
  146. if(strlen(flds[5]) > 2)
  147. tm->year -= 1900;
  148. }else{
  149. tm->mday = strtoul(flds[1], nil, 10);
  150. tm->mon = dateindex(flds[2], monname, 12);
  151. tm->year = strtoul(flds[3], nil, 10);
  152. if(strlen(flds[3]) > 2)
  153. tm->year -= 1900;
  154. time2tm(tm, flds[4]);
  155. zone2tm(tm, flds[5]);
  156. }
  157. if(n == 5){
  158. gmt = *tm;
  159. strncpy(gmt.zone, "", 4);
  160. gmt.tzoff = 0;
  161. atm = gmtime(tm2sec(&gmt));
  162. tm->wday = atm->wday;
  163. }else{
  164. /*
  165. * Wday[,]
  166. */
  167. s = strchr(flds[0], ',');
  168. if(s != nil)
  169. *s = '\0';
  170. tm->wday = dateindex(flds[0], wdayname, 7);
  171. if(tm->wday < 0)
  172. return nil;
  173. }
  174. return tm;
  175. }
  176. /*
  177. * zone : [A-Za-z][A-Za-z][A-Za-z] some time zone names
  178. * | [A-IK-Z] military time; rfc1123 says the rfc822 spec is wrong.
  179. * | "UT" universal time
  180. * | [+-][0-9][0-9][0-9][0-9]
  181. * zones is the rfc-822 list of time zone names
  182. */
  183. static NamedInt zones[] =
  184. {
  185. {"A", -1 * 3600},
  186. {"B", -2 * 3600},
  187. {"C", -3 * 3600},
  188. {"CDT", -5 * 3600},
  189. {"CST", -6 * 3600},
  190. {"D", -4 * 3600},
  191. {"E", -5 * 3600},
  192. {"EDT", -4 * 3600},
  193. {"EST", -5 * 3600},
  194. {"F", -6 * 3600},
  195. {"G", -7 * 3600},
  196. {"GMT", 0},
  197. {"H", -8 * 3600},
  198. {"I", -9 * 3600},
  199. {"K", -10 * 3600},
  200. {"L", -11 * 3600},
  201. {"M", -12 * 3600},
  202. {"MDT", -6 * 3600},
  203. {"MST", -7 * 3600},
  204. {"N", +1 * 3600},
  205. {"O", +2 * 3600},
  206. {"P", +3 * 3600},
  207. {"PDT", -7 * 3600},
  208. {"PST", -8 * 3600},
  209. {"Q", +4 * 3600},
  210. {"R", +5 * 3600},
  211. {"S", +6 * 3600},
  212. {"T", +7 * 3600},
  213. {"U", +8 * 3600},
  214. {"UT", 0},
  215. {"V", +9 * 3600},
  216. {"W", +10 * 3600},
  217. {"X", +11 * 3600},
  218. {"Y", +12 * 3600},
  219. {"Z", 0},
  220. {nil, 0}
  221. };
  222. static void
  223. zone2tm(Tm *tm, char *s)
  224. {
  225. Tm aux, *atm;
  226. int i;
  227. if(*s == '+' || *s == '-'){
  228. i = strtol(s, &s, 10);
  229. tm->tzoff = (i / 100) * 3600 + i % 100;
  230. strncpy(tm->zone, "", 4);
  231. return;
  232. }
  233. /*
  234. * look it up in the standard rfc822 table
  235. */
  236. strncpy(tm->zone, s, 3);
  237. tm->zone[3] = '\0';
  238. tm->tzoff = 0;
  239. for(i = 0; zones[i].name != nil; i++){
  240. if(cistrcmp(zones[i].name, s) == 0){
  241. tm->tzoff = zones[i].v;
  242. return;
  243. }
  244. }
  245. /*
  246. * one last try: look it up in the current local timezone
  247. * probe a couple of times to get daylight/standard time change.
  248. */
  249. aux = *tm;
  250. memset(aux.zone, 0, 4);
  251. aux.hour--;
  252. for(i = 0; i < 2; i++){
  253. atm = localtime(tm2sec(&aux));
  254. if(cistrcmp(tm->zone, atm->zone) == 0){
  255. tm->tzoff = atm->tzoff;
  256. return;
  257. }
  258. aux.hour++;
  259. }
  260. strncpy(tm->zone, "GMT", 4);
  261. tm->tzoff = 0;
  262. }
  263. /*
  264. * hh[:mm[:ss]]
  265. */
  266. static void
  267. time2tm(Tm *tm, char *s)
  268. {
  269. tm->hour = strtoul(s, &s, 10);
  270. if(*s++ != ':')
  271. return;
  272. tm->min = strtoul(s, &s, 10);
  273. if(*s++ != ':')
  274. return;
  275. tm->sec = strtoul(s, &s, 10);
  276. }
  277. static int
  278. dateindex(char *d, char **tab, int n)
  279. {
  280. int i;
  281. for(i = 0; i < n; i++)
  282. if(cistrcmp(d, tab[i]) == 0)
  283. return i;
  284. return -1;
  285. }