コード例 #1
0
/*
 * This method is used to parse Allow header.
 *
 * params: msg : sip msg
 * returns 0 on success,
 *        -1 on failure.
 */
int parse_allow_header(struct hdr_field* _hf)
{
	unsigned int* methods;
	
	if (!_hf) {
		LOG(L_ERR, "parse_allow_header: Invalid parameter value\n");
		return -1;
	}
	
	     /* maybe the header is already parsed! */
 	if (_hf->parsed) {
 		return 0;
	}

	     /* bad luck! :-( - we have to parse it */
	methods = pkg_malloc(sizeof(unsigned int));
 	if (methods == 0) {
 		LOG(L_ERR, "ERROR:parse_allow_header: Out of pkg_memory\n");
 		return -1;
 	}

	if (!parse_methods(&(_hf->body), methods)) {
 		LOG(L_ERR, "ERROR:parse_allow_header: Bad allow header\n"); 
 		pkg_free(methods);
		return -1;
 	}

 	_hf->parsed = methods;
 	return 0;
}
コード例 #2
0
ファイル: parse_allow.c プロジェクト: Distrotech/opensips
/*
 * This method is used to parse all Allow HF body.
 *
 * params: msg : sip msg
 * returns 0 on success,
 *        -1 on failure.
 */
int parse_allow(struct sip_msg *msg)
{
	unsigned int allow;
	struct hdr_field  *hdr;
	struct allow_body *ab = 0;

	/* maybe the header is already parsed! */
	if (msg->allow && msg->allow->parsed)
		return 0;

	/* parse to the end in order to get all ALLOW headers */
	if (parse_headers(msg,HDR_EOH_F,0)==-1 || !msg->allow)
		return -1;

	/* bad luck! :-( - we have to parse them */
	allow = 0;
	for( hdr=msg->allow ; hdr ; hdr=hdr->sibling) {
		if (hdr->parsed) {
			allow |= ((struct allow_body*)hdr->parsed)->allow;
			continue;
		}

		ab = (struct allow_body*)pkg_malloc(sizeof(struct allow_body));
		if (ab == 0) {
			LM_ERR("out of pkg_memory\n");
			return -1;
		}

		if (parse_methods(&(hdr->body), &(ab->allow))!=0) {
			LM_ERR("bad allow body header\n");
			set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
				"error parsing ALLOW header");
			set_err_reply(400, "bad headers");
			goto error;
		}
		ab->allow_all = 0;
		hdr->parsed = (void*)ab;
		allow |= ab->allow;
	}

	((struct allow_body*)msg->allow->parsed)->allow_all = allow;
	return 0;

error:
	if(ab!=0)
		pkg_free(ab);
	return -1;
}
コード例 #3
0
/*! \brief
 * Fills the common part (for all contacts) of the info structure
 */
static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
						unsigned int _e, unsigned int _f, unsigned int _flags)
{
	static ucontact_info_t ci;
	static str no_ua = str_init("n/a");
	static str callid;
	static str path_received = {0,0};
	static str path;
	static str received = {0,0};
	static int received_found;
	static unsigned int allowed, allow_parsed;
	static struct sip_msg *m = 0;
	int_str val;

	if (_m!=0) {
		memset( &ci, 0, sizeof(ucontact_info_t));

		/* Get callid of the message */
		callid = _m->callid->body;
		trim_trailing(&callid);
		if (callid.len > CALLID_MAX_SIZE) {
			rerrno = R_CALLID_LEN;
			LM_ERR("callid too long\n");
			goto error;
		}
		ci.callid = &callid;

		/* Get CSeq number of the message */
		if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) {
			rerrno = R_INV_CSEQ;
			LM_ERR("failed to convert cseq number\n");
			goto error;
		}

		/* set received socket */
		if ( _flags&REG_SAVE_SOCKET_FLAG) {
			ci.sock = get_sock_hdr(_m);
			if (ci.sock==0)
				ci.sock = _m->rcv.bind_address;
		} else {
			ci.sock = _m->rcv.bind_address;
		}

		/* additional info from message */
		if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
		_m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) {
			ci.user_agent = &_m->user_agent->body;
		} else {
			ci.user_agent = &no_ua;
		}

		/* extract Path headers */
		if ( _flags&REG_SAVE_PATH_FLAG ) {
			if (build_path_vector(_m, &path, &path_received, _flags) < 0) {
				rerrno = R_PARSE_PATH;
				goto error;
			}
			if (path.len && path.s) {
				ci.path = &path;
				/* save in msg too for reply */
				if (set_path_vector(_m, &path) < 0) {
					rerrno = R_PARSE_PATH;
					goto error;
				}
			}
		}

		ci.last_modified = act_time;

		/* set flags */
		ci.flags  = _f;
		ci.cflags =  getb0flags();

		/* get received */
		if (path_received.len && path_received.s) {
			ci.cflags |= ul.nat_flag;
			ci.received = path_received;
		}

		allow_parsed = 0; /* not parsed yet */
		received_found = 0; /* not found yet */
		m = _m; /* remember the message */
	}

	if(_c!=0) {
		/* Calculate q value of the contact */
		if (calc_contact_q(_c->q, &ci.q) < 0) {
			rerrno = R_INV_Q;
			LM_ERR("failed to calculate q\n");
			goto error;
		}

		/* set expire time */
		ci.expires = _e;

		/* Get methods of contact */
		if (_c->methods) {
			if (parse_methods(&(_c->methods->body), &ci.methods) < 0) {
				rerrno = R_PARSE;
				LM_ERR("failed to parse contact methods\n");
				goto error;
			}
		} else {
			/* check on Allow hdr */
			if (allow_parsed == 0) {
				if (m && parse_allow( m ) != -1) {
					allowed = get_allow_methods(m);
				} else {
					allowed = ALL_METHODS;
				}
				allow_parsed = 1;
			}
			ci.methods = allowed;
		}

		/* get received */
		if (ci.received.len==0) {
			if (_c->received) {
				ci.received = _c->received->body;
			} else {
				if (received_found==0) {
					memset(&val, 0, sizeof(int_str));
					if (rcv_avp_name>=0
								&& search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
								&& val.s.len > 0) {
						if (val.s.len>RECEIVED_MAX_SIZE) {
							rerrno = R_CONTACT_LEN;
							LM_ERR("received too long\n");
							goto error;
						}
						received = val.s;
					} else {
						received.s = 0;
						received.len = 0;
					}
					received_found = 1;
				}
				ci.received = received;
			}
		}

	}

	return &ci;
error:
	return 0;
}
コード例 #4
0
ファイル: ltest.c プロジェクト: santolucito/CCache
static int do_option(int optc)
{
	switch (optc)
	{
	case 'A':
		opt_use_asm_decompressor = 1;
		break;
	case 'b':
		opt_block_size = MAX_BLOCK_SIZE;
		if (mfx_optarg)
		{
			if (!mfx_optarg || !is_digit(mfx_optarg[0]))
				return optc;
			opt_block_size = atoi(mfx_optarg);
		}
		break;
	case 'c':
	case 'C':
		if (!mfx_optarg || !is_digit(mfx_optarg[0]))
			return optc;
		opt_c_loops = atoi(mfx_optarg);
		break;
	case 'd':
	case 'D':
		if (!mfx_optarg || !is_digit(mfx_optarg[0]))
			return optc;
		opt_d_loops = atoi(mfx_optarg);
		break;
	case 'F':
		opt_use_asm_fast_decompressor = 1;
		break;
	case 'h':
	case 'H':
	case '?':
	case 'h'+256:
		usage(argv0,EXIT_OK,0);
		break;
	case 'L':
		license();
		break;
	case 'm':
		parse_methods(mfx_optarg);
		break;
	case 'n':
		if (!mfx_optarg || !is_digit(mfx_optarg[0]))
			return optc;
		opt_c_loops = opt_d_loops = atoi(mfx_optarg);
		break;
	case 'O':
		opt_optimize_compressed_data = 1;
		break;
	case 'q':
		opt_verbose = (opt_verbose > 1) ? opt_verbose - 1 : 1;
		break;
	case 'Q':
		opt_verbose = 0;
		break;
#ifdef USE_CORPUS
	case 's':
	case OPT_CALGARY_CORPUS:
		if (!mfx_optarg || !mfx_optarg[0])
			return optc;
		opt_calgary_corpus_path = mfx_optarg;
		break;
#endif
	case 'S':
		opt_use_safe_decompressor = 1;
		break;
	case 'T':
		opt_totals = 1;
		break;
	case 'v':
		opt_verbose = (opt_verbose < 2) ? 2 : opt_verbose + 1;
		break;
	case 'V':
	case 'V'+256:
		exit(EXIT_OK);
		break;
	case '@':
		opt_read_from_stdin = 1;
		break;

	case '1': case '2': case '3': case '4': case '5':
	case '6': case '7': case '8': case '9':
		/* this is a dirty hack... */
		parse_methods(nextchar-1);
		if (nextchar[0])
		{
			nextchar = NULL;
			mfx_optind++;
		}
		break;

	case OPT_ADLER32:
		opt_compute_adler32 = 1;
		break;
	case OPT_CRC32:
		opt_compute_crc32 = 1;
		break;
#ifdef USE_DICT
	case OPT_DICT:
		opt_dict = 1;
		opt_dictionary_file = mfx_optarg;
		break;
#endif
	case OPT_EXECUTION_TIME:
		opt_execution_time = 1;
		break;
#ifdef USE_DUMP
	case OPT_DUMP:
		opt_dump_compressed_data = mfx_optarg;
		break;
#endif
	case OPT_MAX_DATA_LEN:
		if (!mfx_optarg || !is_digit(mfx_optarg[0]))
			return optc;
		opt_max_data_len = atoi(mfx_optarg);
		break;
#ifdef USE_DICT
	case OPT_MAX_DICT_LEN:
		if (!mfx_optarg || !(is_digit(mfx_optarg[0]) || mfx_optarg[0] == '-'))
			return optc;
		opt_max_dict_len = atoi(mfx_optarg);
		break;
#endif
	case OPT_QUERY:
		opt_query = 1;
		break;

	case '\0':
		return -1;
	case ':':
		return -2;
	default:
		fprintf(stderr,"%s: internal error in getopt (%d)\n",argv0,optc);
		return -3;
	}
	return 0;
}
コード例 #5
0
ファイル: save.c プロジェクト: Jared-Prime/kamailio
/*! \brief
 * Fills the common part (for all contacts) of the info structure
 */
static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c, unsigned int _e, unsigned int _f, int _use_regid)
{
	static ucontact_info_t ci;
	static str no_ua = str_init("n/a");
	static str callid;
	static str path_received = {0,0};
	static str path;
	static str received = {0,0};
	static int received_found;
	static unsigned int allowed, allow_parsed;
	static struct sip_msg *m = 0;
	int_str val;

	if (_m!=0) {
		memset( &ci, 0, sizeof(ucontact_info_t));

		/* Get callid of the message */
		callid = _m->callid->body;
		trim_trailing(&callid);
		if (callid.len > CALLID_MAX_SIZE) {
			rerrno = R_CALLID_LEN;
			LM_ERR("callid too long\n");
			goto error;
		}
		ci.callid = &callid;

		/* Get CSeq number of the message */
		if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) {
			rerrno = R_INV_CSEQ;
			LM_ERR("failed to convert cseq number\n");
			goto error;
		}

		/* set received socket */
		if (_m->flags&sock_flag) {
			ci.sock = get_sock_val(_m);
			if (ci.sock==0)
				ci.sock = _m->rcv.bind_address;
		} else {
			ci.sock = _m->rcv.bind_address;
		}

		/* set tcp connection id */
		if (_m->rcv.proto==PROTO_TCP || _m->rcv.proto==PROTO_TLS
				|| _m->rcv.proto==PROTO_WS  || _m->rcv.proto==PROTO_WSS) {
			ci.tcpconn_id = _m->rcv.proto_reserved1;
		} else {
			ci.tcpconn_id = -1;
		}

		/* additional info from message */
		if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
				_m->user_agent->body.len>0 && _m->user_agent->body.len<MAX_UA_SIZE) {
			ci.user_agent = &_m->user_agent->body;
		} else {
			ci.user_agent = &no_ua;
		}

		/* extract Path headers */
		if (path_enabled) {
			if (build_path_vector(_m, &path, &path_received) < 0) {
				rerrno = R_PARSE_PATH;
				goto error;
			}
			if (path.len && path.s) {
				ci.path = &path;
				if (path_mode != PATH_MODE_OFF) {
					/* save in msg too for reply */
					if (set_path_vector(_m, &path) < 0) {
						rerrno = R_PARSE_PATH;
						goto error;
					}
				}
			}
		}

		ci.last_modified = act_time;

		/* set flags */
		ci.flags  = _f;
		getbflagsval(0, &ci.cflags);

		/* get received */
		if (path_received.len && path_received.s) {
			ci.cflags |= ul.nat_flag;
			ci.received = path_received;
		}

		allow_parsed = 0; /* not parsed yet */
		received_found = 0; /* not found yet */
		m = _m; /* remember the message */
	}
	else {
		memset( &ci.instance, 0, sizeof(str));
	}

	if(_c!=0) {
		/* hook uri address - should be more than 'sip:' chars */
		if(_c->uri.s!=NULL && _c->uri.len>4)
			ci.c = &_c->uri;

		/* Calculate q value of the contact */
		if (m && m->id == q_override_msg_id)
		{
			ci.q = q_override_value;
		}
		else if (calc_contact_q(_c->q, &ci.q) < 0) {
			rerrno = R_INV_Q;
			LM_ERR("failed to calculate q\n");
			goto error;
		}

		/* set expire time */
		ci.expires = _e;

		/* Get methods of contact */
		if (_c->methods) {
			if (parse_methods(&(_c->methods->body), &ci.methods) < 0) {
				rerrno = R_PARSE;
				LM_ERR("failed to parse contact methods\n");
				goto error;
			}
		} else {
			/* check on Allow hdr */
			if (allow_parsed == 0) {
				if (m && parse_allow( m ) != -1) {
					allowed = get_allow_methods(m);
				} else {
					allowed = ALL_METHODS;
				}
				allow_parsed = 1;
			}
			ci.methods = allowed;
		}

		/* get received */
		if (ci.received.len==0) {
			if (_c->received) {
				ci.received = _c->received->body;
			} else {
				if (received_found==0) {
					memset(&val, 0, sizeof(int_str));
					if (rcv_avp_name.n!=0
							&& search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
							&& val.s.len > 0) {
						if (val.s.len>RECEIVED_MAX_SIZE) {
							rerrno = R_CONTACT_LEN;
							LM_ERR("received too long\n");
							goto error;
						}
						received = val.s;
					} else {
						received.s = 0;
						received.len = 0;
					}
					received_found = 1;
				}
				ci.received = received;
			}
		}
		if(_c->instance!=NULL && _c->instance->body.len>0)
			ci.instance = _c->instance->body;
		if(_use_regid && _c->instance!=NULL && _c->reg_id!=NULL && _c->reg_id->body.len>0) {
			if(str2int(&_c->reg_id->body, &ci.reg_id)<0 || ci.reg_id==0)
			{
				LM_ERR("invalid reg-id value\n");
				goto error;
			}
		}
		if(sruid_next(&_reg_sruid)<0)
			goto error;
		ci.ruid = _reg_sruid.uid;
		LM_DBG("generated ruid is: %.*s\n", ci.ruid.len, ci.ruid.s);
	}

	return &ci;
error:
	return 0;
}
コード例 #6
0
ファイル: encode_header.c プロジェクト: ryzhov/ATS0
/*
 * This function encodes an arbitrary header into a chunk of bytes,
 * ready to be sent to the Application Server.
 *
 * The header codes start with this encoded-bytes:
 * 2: SIP-MSG-START based pointer to the header (including header name)
 * 2: length of the header
 * 1: length of the header name
 */
int encode_header(struct sip_msg *sipmsg,struct hdr_field *hdr,unsigned char *payload,int paylen)
{
   int len=0;
   unsigned int integer,*methods=0;
   char *hdrstart,*tmp;
   unsigned short int ptr;
   struct to_body *tobody=0;
   struct via_body *viabody=0;
   struct cseq_body *cseqbody=0;
   char *msg,*myerror;
   int mlen;

   msg=sipmsg->buf;
   mlen=sipmsg->len;
   hdrstart = hdr->name.s;
   if(hdrstart-msg<0){
      LM_ERR("header(%.*s) does not belong to sip_msg(hdrstart<msg)\n",
			  hdr->name.len,hdr->name.s);
      return -1;
   }
   ptr=htons((short int)(hdrstart-msg));
   if((hdrstart-msg)>mlen){
      LM_ERR("out of the sip_msg bounds (%d>%d)\n",ntohs(ptr),mlen);
      return -1;
   }
   if(hdr->len>(1<<16)){
      LM_ERR("length of header too long\n");
      return -1;
   }
   memcpy(payload,&ptr,2);
   ptr=htons((short int)(hdr->len));
   memcpy(payload+HEADER_LEN_IDX,&ptr,2);
   payload[HEADER_NAME_LEN_IDX]=(unsigned char)hdr->name.len;
   switch(hdr->type){
      case HDR_FROM_T:
      case HDR_TO_T:
      case HDR_REFER_TO_T:
      case HDR_RPID_T:
	 if(!hdr->parsed){
	    if((tobody=pkg_malloc(sizeof(struct to_body)))==0){
	       myerror="Out of memory !!\n";
	       goto error;
	    }
	    parse_to(hdr->body.s,hdr->body.s+hdr->body.len+1,tobody);
	    if (tobody->error == PARSE_ERROR) {
	       myerror="bad (REFER,TO,FROM,RPID) header\n";
	       pkg_free(tobody);
	       return 5;
	       goto error;
	    }
	    hdr->parsed=(struct to_body*)tobody;
	 }else
	    tobody=(struct to_body*)hdr->parsed;
	 if((len=encode_to_body(hdr->name.s,hdr->len,tobody,payload+5))<0){
	    myerror="parsing from or to header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_CONTACT_T:
	 if(!hdr->parsed)
	    if(parse_contact(hdr)<0){
	       myerror="parsing contact\n";
	       goto error;
	    }
	 if((len=encode_contact_body(hdr->name.s,hdr->len,(contact_body_t*)hdr->parsed,payload+5))<0){
	    myerror="encoding contact header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_ROUTE_T:
      case HDR_RECORDROUTE_T:
	 if(!hdr->parsed)
	    if(parse_rr(hdr)<0){
	       myerror="encoding route or recordroute\n";
	       goto error;
	    }
	 if((len=encode_route_body(hdr->name.s,hdr->len,(rr_t*)hdr->parsed,payload+5))<0){
	    myerror="encoding route or recordroute header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_CONTENTLENGTH_T:
	 if(!hdr->parsed){
	    tmp=parse_content_length(hdr->body.s,hdr->body.s+hdr->body.len+1,(int*)&integer);
	    if (tmp==0){
	       myerror="bad content_length header\n";
	       goto error;
	    }
	    hdr->parsed=(void*)(long)integer;
	 }
	 if((len=encode_contentlength(hdr->name.s,hdr->len,(long int)hdr->parsed,(char*)(payload+5)))<0){
	    myerror="encoding content-length header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_VIA_T:
	 if(!hdr->parsed){
	    if((viabody=pkg_malloc(sizeof(struct via_body)))==0){
	       myerror="out of memory\n";
	       goto error;
	    }
	    memset(viabody,0,sizeof(struct via_body));
	    if(parse_via(hdr->body.s,hdr->body.s+hdr->body.len+1,viabody)==0){
	       myerror="encoding via \n";
	       goto error;
	    }
	    hdr->parsed=viabody;
	 }
	 if((len=encode_via_body(hdr->name.s,hdr->len,(struct via_body*)hdr->parsed,payload+5))<0){
	    myerror="encoding via header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_ACCEPT_T:
	 if(!hdr->parsed){
	    if(parse_accept_hdr(sipmsg)<0){
	       return 5;
	    }
	 }
	 if((len=encode_accept(hdr->name.s,hdr->len,(unsigned int*)hdr->parsed,(char*)(payload+5)))<0){
	    myerror="encoding via header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_CONTENTTYPE_T:
	 if(!hdr->parsed){
	    if(parse_content_type_hdr(sipmsg)<0){
	       myerror="encoding content-type header\n";
	       goto error;
	    }
	 }
	 if((len=encode_content_type(hdr->name.s,hdr->len,(unsigned int)get_content_type(sipmsg),(char*)(payload+5)))<0){
	    myerror="encoding via header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_CSEQ_T:
	 if(!hdr->parsed){
	    if((cseqbody=pkg_malloc(sizeof(struct cseq_body)))==0){
	       myerror="out of memory\n";
	       goto error;
	    }
	    memset(cseqbody,0,sizeof(struct cseq_body));
	    if(parse_cseq(hdr->name.s,hdr->body.s+hdr->body.len+1,cseqbody)==0){
	       myerror="encoding cseq header\n";
	       goto error;
	    }
	    hdr->parsed=cseqbody;
	 }
	 if((len=encode_cseq(hdr->name.s,hdr->len,(struct cseq_body*)hdr->parsed,payload+5))<0){
	    myerror="encoding via header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_EXPIRES_T:
	 if(!hdr->parsed){
	    if(parse_expires(hdr)<0){
	       myerror="encoding expires header\n";
	       goto error;
	    }
	 }
	 if((len=encode_expires(hdr->name.s,hdr->len,(exp_body_t *)hdr->parsed,payload+5))<0){
	    myerror="encoding expires header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_ALLOW_T:
	 if(!hdr->parsed){
	    if((methods=pkg_malloc(sizeof(unsigned int)))==0){
	       myerror="out of memory\n";
	       goto error;
	    }
	    *methods=0;
	    if(parse_methods(&hdr->body,methods)!=0){
	       myerror="encoding allow header\n";
	       pkg_free(methods);
	       return 5;
	       /*goto error;*/
	    }
	    hdr->parsed=methods;
	 }
	 if((len=encode_allow(hdr->name.s,hdr->len,(unsigned int*)hdr->parsed,(char*)(payload+5)))<0){
	    myerror="encoding allow header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      case HDR_AUTHORIZATION_T:
      case HDR_PROXYAUTH_T:
	 if(!hdr->parsed){
	    if(parse_credentials(hdr)<0){
	       myerror="encoding a digest header\n";
	       goto error;
	    }
	 }
	 if((len=encode_digest(hdr->name.s,hdr->len,(dig_cred_t*)(&(((auth_body_t*)hdr->parsed)->digest)),payload+5))<0){
	    myerror="encoding allow header\n";
	    goto error;
	 }else{
	    return 5+len;
	 }
	 break;
      default:
	 return 5;
   }
   return 1;
error:
   if(tobody)
      pkg_free(tobody);
   if(cseqbody)
      pkg_free(cseqbody);
   if(viabody)
      free_via_list(viabody);
   if(methods)
      pkg_free(methods);
   LM_ERR("%s",myerror);
   return -1;
}
コード例 #7
0
/*
 * Convert char* method to str* parameter
 */
static int fixup_method(void** param, int param_no)
{
	str* s;
	char *p;
	int m;
	unsigned int method;
	
	s = (str*)pkg_malloc(sizeof(str));
	if (!s) {
		LOG(L_ERR, "textops:fixup_method: No memory left\n");
		return E_UNSPEC;
	}

	s->s = (char*)*param;
	s->len = strlen(s->s);
	if(s->len==0)
	{
		LOG(L_ERR,"textops:fixup_method: empty method name\n");
		pkg_free(s);
		return E_UNSPEC;
	}
	m=0;
	p=s->s;
	while(*p)
	{
		if(*p=='|')
		{
			*p = ',';
			m=1;
		}
		p++;
	}
	if(parse_methods(s, &method)!=0)
	{
		LOG(L_ERR,"textops:fixup_method: bad method names\n");
		pkg_free(s);
		return E_UNSPEC;
	}

	if(m==1)
	{
		if(method==METHOD_UNDEF || method&METHOD_OTHER)
		{
			LOG(L_ERR,
				"textops:fixup_method: unknown method in list [%.*s/%d]"
				" - must be only defined methods\n",
				s->len, s->s, method);
			return E_UNSPEC;
		}
		DBG("textops:fixup_method: using id for methods [%.*s/%d]\n",
				s->len, s->s, method);
		s->s = 0;
		s->len = method;
	} else {
		if(method!=METHOD_UNDEF && method!=METHOD_OTHER)
		{
			DBG("textops:fixup_method: using id for method [%.*s/%d]\n",
				s->len, s->s, method);
			s->s = 0;
			s->len = method;
		} else
			DBG("textops:fixup_method: name for method [%.*s/%d]\n",
				s->len, s->s, method);
	}

	*param = (void*)s;
	return 0;
}