📄 cpl_parser.c
字号:
/* * $Id: cpl_parser.c,v 1.32 2004/08/24 08:58:26 janakj Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <unistd.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include "../../parser/parse_uri.h"#include "../../dprint.h"#include "../../str.h"#include "../../ut.h"#include "CPL_tree.h"#include "sub_list.h"#include "cpl_log.h"static struct node *list = 0;static xmlDtdPtr dtd; /* DTD file */static xmlValidCtxt cvp; /* validating context */typedef unsigned short length_type ;typedef length_type* length_type_ptr;enum {EMAIL_TO,EMAIL_HDR_NAME,EMAIL_KNOWN_HDR_BODY,EMAIL_UNKNOWN_HDR_BODY};#define ENCONDING_BUFFER_SIZE 65536#define FOR_ALL_ATTR(_node,_attr) \ for( (_attr)=(_node)->properties ; (_attr) ; (_attr)=(_attr)->next)/* right and left space trimming */#define trimlr(_s_) \ do{\ for(;(_s_).s[(_s_).len-1]==' ';(_s_).s[--(_s_).len]=0);\ for(;(_s_).s[0]==' ';(_s_).s=(_s_).s+1,(_s_).len--);\ }while(0);#define check_overflow(_p_,_offset_,_end_,_error_) \ do{\ if ((_p_)+(_offset_)>=(_end_)) { \ LOG(L_ERR,"ERROR:cpl-c:%s:%d: overflow -> buffer to small\n",\ __FILE__,__LINE__);\ goto _error_;\ }\ }while(0)\#define set_attr_type(_p_,_type_,_end_,_error_) \ do{\ check_overflow(_p_,sizeof(length_type),_end_,_error_);\ *((length_type_ptr)(_p_)) = htons((length_type)(_type_));\ (_p_) += sizeof(length_type);\ }while(0)\#define append_short_attr(_p_,_n_,_end_,_error_) \ do{\ check_overflow(_p_,sizeof(length_type),_end_,_error_);\ *((length_type_ptr)(_p_)) = htons((length_type)(_n_));\ (_p_) += sizeof(length_type);\ }while(0)#define append_str_attr(_p_,_s_,_end_,_error_) \ do{\ check_overflow(_p_,(_s_).len + 1*((((_s_).len)&0x0001)==1),\ _end_,_error_);\ *((length_type_ptr)(_p_)) = htons((length_type)(_s_).len);\ (_p_) += sizeof(length_type);\ memcpy( (_p_), (_s_).s, (_s_).len);\ (_p_) += (_s_).len + 1*((((_s_).len)&0x0001)==1);\ }while(0)#define append_double_str_attr(_p_,_s1_,_s2_,_end_,_error_) \ do{\ check_overflow(_p_,(_s1_).len + (_s2_).len +\ 1*((((_s2_).len+(_s2_).len)&0x0001)==1), _end_, _error_);\ *((length_type_ptr)(_p_))=htons((length_type)((_s1_).len)+(_s2_).len);\ (_p_) += sizeof(length_type);\ memcpy( (_p_), (_s1_).s, (_s1_).len);\ (_p_) += (_s1_).len;\ memcpy( (_p_), (_s2_).s, (_s2_).len);\ (_p_) += (_s2_).len + 1*((((_s1_).len+(_s2_).len)&0x0001)==1);\ }while(0)#define get_attr_val(_attr_name_,_val_,_error_) \ do { \ (_val_).s = (char*)xmlGetProp(node,(_attr_name_));\ (_val_).len = strlen((_val_).s);\ /* remove all spaces from begin and end */\ trimlr( (_val_) );\ if ((_val_).len==0) {\ LOG(L_ERR,"ERROR:cpl_c:%s:%d: attribute <%s> has an "\ "empty value\n",__FILE__,__LINE__,(_attr_name_));\ goto _error_;\ }\ }while(0)\#define MAX_EMAIL_HDR_SIZE 7 /*we are looking only for SUBJECT and BODY ;-)*/#define MAX_EMAIL_BODY_SIZE 512#define MAX_EMAIL_SUBJECT_SIZE 32static inline char *decode_mail_url(char *p, char *p_end, char *url, unsigned char *nr_attr){ static char buf[ MAX_EMAIL_HDR_SIZE ]; char c; char foo; unsigned short hdr_len; unsigned short *len; int max_len; int status; /* init */ hdr_len = 0; max_len = 0; status = EMAIL_TO; (*nr_attr) ++; set_attr_type(p, TO_ATTR, p_end, error); /* attr type */ len = ((unsigned short*)(p)); /* attr val's len */ *len = 0; /* init the len */ p += 2; /* parse the whole url */ do { /* extract a char from the encoded url */ if (*url=='+') { /* substitute a blank for a plus */ c=' '; url++; /* Look for a hex encoded character */ } else if ( (*url=='%') && *(url+1) && *(url+2) ) { /* hex encoded - convert to a char */ c = hex2int(url[1]); foo = hex2int(url[2]); if (c==-1 || foo==-1) { LOG(L_ERR, "ERROR:cpl_c:decode_mail_url: non-ASCII escaped " "character in mail url [%.*s]\n", 3, url); goto error; } c = c<<4 | foo; url += 3; } else { /* normal character - just copy it without changing */ c = *url; url++; } /* finally we got a character !! */ switch (c) { case '?': switch (status) { case EMAIL_TO: if (*len==0) { LOG(L_ERR,"ERROR:cpl_c:decode_mail_url: empty TO " "address found in MAIL node!\n"); goto error; } if (((*len)&0x0001)==1) p++; *len = htons(*len); hdr_len = 0; status = EMAIL_HDR_NAME; break; default: goto parse_error; } break; case '=': switch (status) { case EMAIL_HDR_NAME: DBG("DEBUG:cpl_c:decode_mail_url: hdr [%.*s] found\n", hdr_len,buf); if ( hdr_len==BODY_EMAILHDR_LEN && strncasecmp(buf,BODY_EMAILHDR_STR,hdr_len)==0 ) { /* BODY hdr found */ set_attr_type( p, BODY_ATTR, p_end, error); max_len = MAX_EMAIL_BODY_SIZE; } else if ( hdr_len==SUBJECT_EMAILHDR_LEN && strncasecmp(buf,SUBJECT_EMAILHDR_STR,hdr_len)==0 ) { /* SUBJECT hdr found */ set_attr_type( p, SUBJECT_ATTR, p_end, error); max_len = MAX_EMAIL_SUBJECT_SIZE; } else { DBG("DEBUG:cpl_c:decode_mail_url: unknown hdr ->" " ignoring\n"); status = EMAIL_UNKNOWN_HDR_BODY; break; } (*nr_attr) ++; len = ((unsigned short*)(p)); /* attr val's len */ *len = 0; /* init the len */ p += 2; status = EMAIL_KNOWN_HDR_BODY; break; default: goto parse_error; } break; case '&': switch (status) { case EMAIL_KNOWN_HDR_BODY: if (((*len)&0x0001)==1) p++; *len = htons(*len); case EMAIL_UNKNOWN_HDR_BODY: hdr_len = 0; status = EMAIL_HDR_NAME; break; default: goto parse_error; } break; case 0: switch (status) { case EMAIL_TO: if (*len==0) { LOG(L_ERR,"ERROR:cpl_c:decode_mail_url: empty TO " "address found in MAIL node!\n"); goto error; } case EMAIL_KNOWN_HDR_BODY: if (((*len)&0x0001)==1) p++; *len = htons(*len); case EMAIL_UNKNOWN_HDR_BODY: break; default: goto parse_error; } break; default: switch (status) { case EMAIL_TO: (*len)++; *(p++) = c; if (*len==URL_MAILTO_LEN && !strncasecmp(p-(*len),URL_MAILTO_STR,(*len))) { DBG("DEBUG:cpl_c:decode_mail_url: MAILTO: found at" " the beginning of TO -> removed\n"); p -= (*len); *len = 0; } break; case EMAIL_KNOWN_HDR_BODY: if ((*len)<max_len) (*len)++; *(p++) = c; break; case EMAIL_HDR_NAME: if (hdr_len<MAX_EMAIL_HDR_SIZE) hdr_len++; buf[hdr_len-1] = c; break; case EMAIL_UNKNOWN_HDR_BODY: /* do nothing */ break; default : goto parse_error; } } }while(c!=0); return p;parse_error: LOG(L_ERR,"ERROR:cpl_c:decode_mail_url: unexpected char [%c] in state %d" " in email url \n",*url,status);error: return 0;}/* Attr. encoding for ADDRESS node: * | attr_t(2) attr_len(2) attr_val(2*x) | IS/CONTAINS/SUBDOMAIN_OF attr (NT) */static inline int encode_address_attr(xmlNodePtr node, char *node_ptr, char *buf_end){ xmlAttrPtr attr; char *p, *p_orig; unsigned char *nr_attr; str val; nr_attr = &(NR_OF_ATTR(node_ptr)); *nr_attr = 0; p = p_orig = ATTR_PTR(node_ptr); FOR_ALL_ATTR(node,attr) { (*nr_attr)++; switch (attr->name[0]) { case 'i': case 'I': set_attr_type(p, IS_ATTR, buf_end, error); break; case 'c': case 'C': set_attr_type(p, CONTAINS_ATTR, buf_end, error); break; case 's': case 'S': set_attr_type(p, SUBDOMAIN_OF_ATTR, buf_end, error); break; default: LOG(L_ERR,"ERROR:cpl_c:encode_address_attr: unknown attribute " "<%s>\n",attr->name); goto error; } /* get the value of the attribute */ get_attr_val( attr->name , val, error); /* copy also the \0 from the end of string */ val.len++; append_str_attr(p, val, buf_end, error); } return p-p_orig;error: return -1;}/* Attr. encoding for ADDRESS_SWITCH node: * | attr1_t(2) attr1_val(2) | FIELD attr * [| attr2_t(2) attr2_val(2) |]? SUBFILED attr */static inline int encode_address_switch_attr(xmlNodePtr node, char *node_ptr, char *buf_end){ xmlAttrPtr attr; char *p, *p_orig; unsigned char *nr_attr; str val; nr_attr = &(NR_OF_ATTR(node_ptr)); *nr_attr = 0; p = p_orig = ATTR_PTR(node_ptr); FOR_ALL_ATTR(node,attr) { (*nr_attr)++; /* get the value of the attribute */ get_attr_val( attr->name , val, error); switch(attr->name[0]) { case 'F': case 'f': set_attr_type(p, FIELD_ATTR, buf_end, error); if (val.s[0]=='D' || val.s[0]=='d') append_short_attr(p, DESTINATION_VAL, buf_end, error); else if (val.s[6]=='A' || val.s[6]=='a') append_short_attr(p,ORIGINAL_DESTINATION_VAL,buf_end,error); else if (!val.s[6]) append_short_attr(p, ORIGIN_VAL, buf_end, error); else { LOG(L_ERR,"ERROR:cpl_c:encode_address_switch_attr: unknown" " value <%s> for FIELD attr\n",val.s); goto error; }; break; case 'S': case 's': set_attr_type(p, SUBFIELD_ATTR, buf_end, error); switch (val.s[0]) { case 'u': case 'U': append_short_attr(p, USER_VAL, buf_end, error); break; case 'h': case 'H': append_short_attr(p, HOST_VAL, buf_end, error); break; case 'p': case 'P': append_short_attr(p, PORT_VAL, buf_end, error); break; case 't': case 'T': append_short_attr(p, TEL_VAL, buf_end, error); break; case 'd': case 'D': /*append_short_attr(p, DISPLAY_VAL, buf_end, error); break;*/ /* NOT YET SUPPORTED BY INTERPRETER */ case 'a': case 'A': /*append_short_attr(p, ADDRESS_TYPE_VAL, buf_end,error); break;*/ /* NOT YET SUPPORTED BY INTERPRETER */ default: LOG(L_ERR,"ERROR:cpl_c:encode_address_switch_attr: " "unknown value <%s> for SUBFIELD attr\n",val.s); goto error; } break; default: LOG(L_ERR,"ERROR:cpl_c:encode_address_switch_attr: unknown" " attribute <%s>\n",attr->name); goto error; } } return p-p_orig;error: return -1;}/* Attr. encoding for LANGUAGE node: * | attr_t(2) attr_len(2) attr_val(2*x) | MATCHES attr (NNT) */static inline int encode_lang_attr(xmlNodePtr node, char *node_ptr, char *buf_end){ xmlAttrPtr attr; char *p, *p_orig; unsigned char *nr_attr; char *end; char *val_bk; str val; nr_attr = &(NR_OF_ATTR(node_ptr)); *nr_attr = 0; p = p_orig = ATTR_PTR(node_ptr); FOR_ALL_ATTR(node,attr) { /* there is only one attribute -> MATCHES */ if (attr->name[0]!='M' && attr->name[0]!='m') { LOG(L_ERR,"ERROR:cpl_c:encode_lang_attr: unknown attribute " "<%s>\n",attr->name); goto error; } val.s = val_bk = (char*)xmlGetProp(node,attr->name); /* parse the language-tag */ for(end=val.s,val.len=0;;end++) { /* trim all spaces from the beginning of the tag */ if (!val.len && (*end==' ' || *end=='\t')) continue; /* we cannot have more than 2 attrs - LANG_TAG and LANG_SUBTAG */ if ((*nr_attr)>=2) goto lang_error; if (((*end)|0x20)>='a' && ((*end)|0x20)<='z') { val.len++; continue; } else if (*end=='*' && val.len==0 && (*nr_attr)==0 && (*end==' '|| *end=='\t' || *end==0)) { val.len++; set_attr_type(p, MATCHES_TAG_ATTR, buf_end, error); } else if (val.len && (*nr_attr)==0 && *end=='-' ) { set_attr_type(p, MATCHES_TAG_ATTR, buf_end, error); } else if (val.len && ((*nr_attr)==0 || (*nr_attr)==1) && (*end==' '|| *end=='\t' || *end==0)) { set_attr_type(p, (!(*nr_attr))?MATCHES_TAG_ATTR:MATCHES_SUBTAG_ATTR, buf_end, error ); } else goto lang_error; (*nr_attr)++; /*DBG("----> language tag=%d; %d [%.*s]\n",*(p-1), val.len,val.len,end-val.len);*/ val.s = end-val.len; append_str_attr(p, val, buf_end, error); val.len = 0; if (*end==0) break; } } return p-p_orig;lang_error: LOG(L_ERR,"ERROR:cpl-c:encode_lang_attr: bad value for language_tag <%s>\n", val_bk);error: return -1;}/* Attr. encoding for PRIORITY node: * | attr1_t(2) attr1_val(2) | LESS/GREATER/EQUAL attr * [| attr2_t(2) attr2_len(2) attr_val(2*x) |]? PRIOSTR attr (NT) */static inline int encode_priority_attr(xmlNodePtr node, char *node_ptr, char *buf_end){ xmlAttrPtr attr; char *p, *p_orig; unsigned char *nr_attr; str val; nr_attr = &(NR_OF_ATTR(node_ptr)); *nr_attr = 0; p = p_orig = ATTR_PTR(node_ptr); FOR_ALL_ATTR(node,attr) { (*nr_attr)++; /* attribute's name */ switch(attr->name[0]) { case 'L': case 'l': set_attr_type(p, LESS_ATTR, buf_end, error); break; case 'G': case 'g': set_attr_type(p, GREATER_ATTR, buf_end, error); break; case 'E': case 'e': set_attr_type(p, EQUAL_ATTR, buf_end, error); break; default: LOG(L_ERR,"ERROR:cpl_c:encode_priority_attr: unknown attribute " "<%s>\n",attr->name); goto error; } /* attribute's encoded value */ get_attr_val( attr->name , val, error); if ( val.len==EMERGENCY_STR_LEN && !strncasecmp(val.s,EMERGENCY_STR,val.len) ) { append_short_attr(p, EMERGENCY_VAL, buf_end, error); } else if ( val.len==URGENT_STR_LEN && !strncasecmp(val.s,URGENT_STR,val.len) ) { append_short_attr(p, URGENT_VAL, buf_end, error); } else if ( val.len==NORMAL_STR_LEN && !strncasecmp(val.s,NORMAL_STR,val.len) ) { append_short_attr(p, NORMAL_VAL, buf_end, error); } else if ( val.len==NON_URGENT_STR_LEN && !strncasecmp(val.s,NON_URGENT_STR,val.len) ) { append_short_attr(p, NON_URGENT_VAL, buf_end, error); } else { append_short_attr(p, UNKNOWN_PRIO_VAL, buf_end, error); set_attr_type(p, PRIOSTR_ATTR, buf_end, error); val.len++; /* append \0 also */ append_str_attr(p, val, buf_end, error); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -