core, lib, modules: restructured source code tree
[sip-router] / src / core / parser / parse_date.c
1 /*
2  * Copyright (c) 2007 iptelorg GmbH
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio 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 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 /*! \file
22  * \brief Parser :: Date header
23  *
24  * \ingroup parser
25  */
26
27
28
29 #include <string.h>
30 #include "parse_date.h"
31 #include "parse_def.h"
32 #include "parser_f.h"  /* eat_space_end and so on */
33 #include "../mem/mem.h"
34
35 /*
36  * Parse Date header field
37  */
38
39 #define READ(val) \
40 (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
41
42 inline static int char2int (char *p, int *t)
43 {
44         if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9')
45                 return -1;
46         *t = (*p - '0')*10 + *(p + 1) - '0';
47
48         return 0;
49 }
50
51 /*! \brief
52  * Converts a RFC 1123 formatted date string to stuct tm
53  */
54 static int rfc1123totm (char *stime, struct tm *ttm ) {
55         char *ptime = stime;
56         unsigned int uval;
57         int ires;
58
59         uval = READ(ptime);
60         ptime+=4;
61         switch (uval) {
62                 /* Sun, */
63                 case 0x2c6e7553: ttm->tm_wday = 0; break;
64                 /* Mon, */
65                 case 0x2c6e6f4d: ttm->tm_wday = 1; break;
66                 /* Tue, */
67                 case 0x2c657554: ttm->tm_wday = 2; break;
68                 /* Wed, */
69                 case 0x2c646557: ttm->tm_wday = 3; break;
70                 /* Thu, */
71                 case 0x2c756854: ttm->tm_wday = 4; break;
72                 /* Fri, */
73                 case 0x2c697246: ttm->tm_wday = 5; break;
74                 /* Sat, */
75                 case 0x2c746153: ttm->tm_wday = 6; break;
76                 default: return -2;
77         }
78
79         if (*(ptime++)!=' ') return -3;
80
81
82         if (char2int(ptime,&ttm->tm_mday) || ttm->tm_mday > 31) return -4;
83         ptime+=2;
84
85         if (*(ptime++) != ' ') return -5;
86
87         uval = READ(ptime);
88         ptime+=4;
89         switch (uval) {
90                 /* Jan, */
91                 case 0x206e614a: ttm->tm_mon = 0; break;
92                 /* Feb, */
93                 case 0x20626546: ttm->tm_mon = 1; break;
94                 /* Mar, */
95                 case 0x2072614d: ttm->tm_mon = 2; break;
96                 /* Apr, */
97                 case 0x20727041: ttm->tm_mon = 3; break;
98                 /* May, */
99                 case 0x2079614d: ttm->tm_mon = 4; break;
100                 /* Jun, */
101                 case 0x206e754a: ttm->tm_mon = 5; break;
102                 /* Jul, */
103                 case 0x206c754a: ttm->tm_mon = 6; break;
104                 /* Aug, */
105                 case 0x20677541: ttm->tm_mon = 7; break;
106                 /* Sep, */
107                 case 0x20706553: ttm->tm_mon = 8; break;
108                 /* Oct, */
109                 case 0x2074634f: ttm->tm_mon = 9; break;
110                 /* Nov, */
111                 case 0x20766f4e: ttm->tm_mon = 10; break;
112                 /* Dec, */
113                 case 0x20636544: ttm->tm_mon = 11; break;
114                 default: return -6;
115         }
116
117         if (char2int(ptime,&ires)) return -7;
118         ptime+=2;
119         if (char2int(ptime,&ttm->tm_year)) return -8;
120         ptime+=2;
121         ttm->tm_year+=(ires-19)*100;
122
123         if (*(ptime++) != ' ') return -9;
124
125         if (char2int(ptime,&ttm->tm_hour) || ttm->tm_hour > 23) return -10;
126         ptime+=2;
127         if (*(ptime++) != ':') return -11;
128
129         if (char2int(ptime,&ttm->tm_min) || ttm->tm_min > 59) return -12;
130         ptime+=2;
131         if (*(ptime++) != ':') return -13;
132
133         if (char2int(ptime,&ttm->tm_sec) || ttm->tm_sec > 59) return -14;
134         ptime+=2;
135
136         /* " GMT" */
137         uval = READ(ptime);
138         if ((uval | 0x20202020) != 0x746d6720) return -15;
139
140         return 0;
141 }
142
143 void parse_date(char *buffer, char *end, struct date_body *db)
144 {
145         db->error=PARSE_ERROR;
146
147         /* check whether enough characters are available */
148         if (end - buffer < RFC1123DATELENGTH)
149                 goto error;
150
151         if (rfc1123totm(buffer,&db->date))
152                 goto error;
153
154         db->error=PARSE_OK;
155         return ;
156 error:
157         LOG(L_ERR,"ERROR: parse_date: parse error\n");
158         return ;
159 }
160
161 int parse_date_header(struct sip_msg *msg)
162 {
163         struct date_body* date_b;
164
165
166         if ( !msg->date && (parse_headers(msg,HDR_DATE_F,0)==-1 || !msg->date) ) {
167                 LOG(L_ERR,"ERROR:parse_date_header: bad msg or missing DATE header\n");
168                 goto error;
169         }
170
171         /* maybe the header is already parsed! */
172         if (msg->date->parsed)
173                 return 0;
174
175         date_b=pkg_malloc(sizeof(*date_b));
176         if (date_b==0){
177                 LOG(L_ERR, "ERROR:parse_date_header: out of memory\n");
178                 goto error;
179         }
180         memset(date_b, 0, sizeof(*date_b));
181
182         parse_date(msg->date->body.s,
183                            msg->date->body.s + msg->date->body.len+1,
184                            date_b);
185         if (date_b->error==PARSE_ERROR){
186                 free_date(date_b);
187                 goto error;
188         }
189         msg->date->parsed=(void*)date_b;
190
191         return 0;
192 error:
193         return -1;
194 }
195
196 void free_date(struct date_body *db)
197 {
198         pkg_free(db);
199 }