parse_supported.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2006 Andreas Granig <agranig@linguin.org>
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00029 #include "../../mem/mem.h"
00030 #include "../../parser/keys.h"
00031 #include "parse_supported.h"
00032 
00033 #define _100r_ 0x72303031   /* "100r" for "100rel" */
00034 #define _time_ 0x656d6974   
00036 #define IS_DELIM(c) (*(c) == ' ' || *(c) == '\t' || *(c) == '\r' || *(c) == '\n' || *(c) == ',')
00037 
00038 /* from parser/parse_hname2.c: */
00039 #define LOWER_BYTE(b) ((b) | 0x20)
00040 #define LOWER_DWORD(d) ((d) | 0x20202020)
00041 #define READ(val) \
00042         (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
00043 
00044 
00048 static inline int parse_supported_body(str *body, unsigned int *sup)
00049 {
00050         register char* p;
00051         register unsigned int val;
00052         int len, pos = 0;
00053 
00054         *sup = 0;
00055 
00056         p = body->s;
00057         len = body->len;
00058 
00059         while (pos < len) {
00060                 /* skip spaces and commas */
00061                 for (; pos < len && IS_DELIM(p); ++pos, ++p);
00062 
00063                 val = LOWER_DWORD(READ(p));
00064                 switch (val) {
00065 
00066                         /* "path" */
00067                         case _path_:
00068                                 if(pos + 4 <= len && IS_DELIM(p+4)) {
00069                                         *sup |= F_SUPPORTED_PATH;
00070                                         pos += 5; p += 5;
00071                                 }
00072                                 break;
00073 
00074                         /* "100rel" */
00075                         case _100r_:
00076                                 if ( pos+6 <= len
00077                                          && LOWER_BYTE(*(p+4))=='e' && LOWER_BYTE(*(p+5))=='l'
00078                                          && IS_DELIM(p+6)) {
00079                                         *sup |= F_SUPPORTED_100REL;
00080                                         pos += SUPPORTED_100REL_LEN + 1;
00081                                         p   += SUPPORTED_100REL_LEN + 1;
00082                                 }
00083                                 break;
00084 
00085                         /* "timer" */
00086                         case _time_:
00087                                 if ( pos+5 <= len && LOWER_BYTE(*(p+4))=='r'
00088                                          && IS_DELIM(p+5) ) {
00089                                         *sup |= F_SUPPORTED_TIMER;
00090                                         pos += SUPPORTED_TIMER_LEN + 1;
00091                                         p   += SUPPORTED_TIMER_LEN + 1;
00092                                 }
00093                                 break;
00094 
00095                         /* extra supported or unknown */
00096                         default:
00097                                 if(pos+SUPPORTED_EVENTLIST_LEN<=len
00098                                                 && strncasecmp(p, SUPPORTED_EVENTLIST_STR,
00099                                                         SUPPORTED_EVENTLIST_LEN)==0
00100                                                 && IS_DELIM(p+SUPPORTED_EVENTLIST_LEN) ) {
00101                                         *sup |= F_SUPPORTED_EVENTLIST;
00102                                         pos += SUPPORTED_EVENTLIST_LEN + 1;
00103                                         p   += SUPPORTED_EVENTLIST_LEN + 1;
00104                                 } else if(pos+SUPPORTED_GRUU_LEN<=len
00105                                                 && strncasecmp(p, SUPPORTED_GRUU_STR,
00106                                                         SUPPORTED_GRUU_LEN)==0
00107                                                 && IS_DELIM(p+SUPPORTED_GRUU_LEN)) {
00108                                         *sup |= F_SUPPORTED_GRUU;
00109                                         pos += SUPPORTED_GRUU_LEN + 1;
00110                                         p   += SUPPORTED_GRUU_LEN + 1;
00111                                 } else if(pos+SUPPORTED_OUTBOUND_LEN<=len
00112                                                 && strncasecmp(p, SUPPORTED_OUTBOUND_STR,
00113                                                         SUPPORTED_OUTBOUND_LEN)==0
00114                                                 && IS_DELIM(p+SUPPORTED_OUTBOUND_LEN)) {
00115                                         *sup |= F_SUPPORTED_OUTBOUND;
00116                                         pos += SUPPORTED_OUTBOUND_LEN + 1;
00117                                         p   += SUPPORTED_OUTBOUND_LEN + 1;
00118                                 } else {
00119                                         /* skip element */
00120                                         for (; pos < len && !IS_DELIM(p); ++pos, ++p);
00121                                 }
00122                                 break;
00123                 }
00124         }
00125         
00126         return 0;
00127 }
00128 
00129 
00133 void hf_free_supported(void *parsed)
00134 {
00135         struct supported_body *sb;
00136         sb = (struct supported_body*)parsed;
00137         free_supported(&sb);
00138 }
00139 
00143 int parse_supported( struct sip_msg *msg)
00144 {
00145         unsigned int supported;
00146         struct hdr_field  *hdr;
00147         struct supported_body *sb;
00148 
00149         /* maybe the header is already parsed! */
00150         if (msg->supported && msg->supported->parsed)
00151                 return 0;
00152 
00153         /* parse to the end in order to get all SUPPORTED headers */
00154         if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->supported)
00155                 return -1;
00156 
00157         /* bad luck! :-( - we have to parse them */
00158         supported = 0;
00159         for( hdr=msg->supported ; hdr ; hdr=next_sibling_hdr(hdr)) {
00160                 if (hdr->parsed) {
00161                         supported |= ((struct supported_body*)hdr->parsed)->supported;
00162                         continue;
00163                 }
00164 
00165                 sb = (struct supported_body*)pkg_malloc(sizeof(struct supported_body));
00166                 if (sb == 0) {
00167                         LM_ERR("out of pkg_memory\n");
00168                         return -1;
00169                 }
00170 
00171                 parse_supported_body(&(hdr->body), &(sb->supported));
00172                 sb->hfree = hf_free_supported;
00173                 sb->supported_all = 0;
00174                 hdr->parsed = (void*)sb;
00175                 supported |= sb->supported;
00176         }
00177 
00178         ((struct supported_body*)msg->supported->parsed)->supported_all = 
00179                 supported;
00180         return 0;
00181 }
00182 
00183 /* free supported header structure */
00184 void free_supported(struct supported_body **sb)
00185 {
00186         if (sb && *sb) {
00187                 pkg_free(*sb);
00188                 *sb = 0;
00189         }
00190 }