⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mms_uaprof.c

📁 手机端彩信的编解码、以及接收和发送。非常有用。
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Mbuni - Open  Source MMS Gateway 
 * 
 * User-Agent profiles handling, content adaptation.
 * 
 * Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com
 *
 * Paul Bagyenda <bagyenda@dsmagic.com>
 * 
 * This program is free software, distributed under the terms of
 * the GNU General Public License, with a few exceptions granted (see LICENSE)
 */
#include <ctype.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>

#include "mms_uaprof.h"
#include "mms_util.h"

struct MmsUaProfile {
     List *versions;
     unsigned long maxmsgsize;
     struct {
	  long x, y;
     } maxres;
     struct {
	  unsigned char all;
	  unsigned char presentation;
	  List *content, *_hash; /* List of accepted content formats (+ hash keys for fast look-up). */
	  
	  List *charset, *_chash; /* List of accepted charsets. */
	  List *lang;    /* List of accepted languages. */
	  List *enc;     /* List of accepted encodings. */
     } ccppaccept;
};

static Dict *profile_dict; /* Of MmsUaProfile *. */
static Octstr *profile_dir;  /* Directory for storing data. */

/* Hash function -- case insensitive. */
static unsigned long hash_key(Octstr *s)
{
     unsigned long h = 0;
     int i, n;
     char *x;

     if (!s) return 0;
     for (x = octstr_get_cstr(s), i = 0, n = octstr_len(s); i<n; i++)
	  h  += (unsigned long)tolower(x[i]);
     return h;
}


static void destroy_uaprof(MmsUaProfile *prof)
{
     if (prof->versions)
	  gwlist_destroy(prof->versions, 
		       (gwlist_item_destructor_t *)octstr_destroy);
     
     if (prof->ccppaccept.content) {
	  gwlist_destroy(prof->ccppaccept.content, (gwlist_item_destructor_t *)octstr_destroy);
	  gwlist_destroy(prof->ccppaccept._hash, NULL);
     }
     
     if (prof->ccppaccept.charset) {
	  gwlist_destroy(prof->ccppaccept.charset, (gwlist_item_destructor_t *)octstr_destroy);
	  gwlist_destroy(prof->ccppaccept._chash, NULL);
     } if (prof->ccppaccept.lang)
	  gwlist_destroy(prof->ccppaccept.lang, (gwlist_item_destructor_t *)octstr_destroy);
     if (prof->ccppaccept.enc)
	  gwlist_destroy(prof->ccppaccept.enc, (gwlist_item_destructor_t *)octstr_destroy);

     gw_free(prof);
}

static void dump_profile(MmsUaProfile *prof, Octstr *name)
{
     int i;
     Octstr *s;
     
     debug("mms.uaprof", 0, "Dumping profile for %s", octstr_get_cstr(name));
     
     debug("mms.uaprof", 0, "MaxMsgSize: %ld", prof->maxmsgsize);
     debug("mms.uaprof", 0, "MaxRes: %ldx%ld", prof->maxres.x,prof->maxres.y);
     

     s = octstr_create("");
     if (prof->ccppaccept.content)
	  for (i=0; i<gwlist_len(prof->ccppaccept.content); i++)
	       octstr_format_append(s, "%S, ", gwlist_get(prof->ccppaccept.content,i));
     debug("mms.uaprof", 0, "Accept content: %s", octstr_get_cstr(s));     
     octstr_destroy(s);


     s = octstr_create("");
     if (prof->ccppaccept.enc)
	  for (i=0; i<gwlist_len(prof->ccppaccept.enc); i++)
	       octstr_format_append(s, "%S, ", gwlist_get(prof->ccppaccept.enc,i));
     debug("mms.uaprof", 0, "Accept encodings: %s", octstr_get_cstr(s));     
     octstr_destroy(s);

     s = octstr_create("");
     if (prof->ccppaccept.lang)
	  for (i=0; i<gwlist_len(prof->ccppaccept.lang); i++)
	       octstr_format_append(s, "%S, ", gwlist_get(prof->ccppaccept.lang,i));
     debug("mms.uaprof", 0, "Accept language: %s", octstr_get_cstr(s));     
     octstr_destroy(s);

     s = octstr_create("");
     if (prof->ccppaccept.charset)
	  for (i=0; i<gwlist_len(prof->ccppaccept.charset); i++)
	       octstr_format_append(s, "%S, ", gwlist_get(prof->ccppaccept.charset,i));
     debug("mms.uaprof", 0, "Accept charset: %s", octstr_get_cstr(s));     
     octstr_destroy(s);

     s = octstr_create("");
     if (prof->versions)
	  for (i=0; i<gwlist_len(prof->versions); i++)
	       octstr_format_append(s, "%S, ", gwlist_get(prof->versions,i));
     debug("mms.uaprof", 0, "Mms Version: %s", octstr_get_cstr(s));     
     octstr_destroy(s);
     
}

/* Helper function: find a node. Uses breadth first search */
static xmlNodePtr find_node(xmlNodePtr start, char *name, char *id, int level, int maxlevel)
{
     xmlNodePtr node, x, list;

     
     if (level >= maxlevel) return NULL;
     
     /* First search at top level. */
     for (list=start; list; list=list->next)
	  if (list->type == XML_COMMENT_NODE)
	       continue;
	  else if (xmlStrcasecmp(list->name, (const xmlChar *)name) == 0) {
	       if (!id)
		    return list;
	       else {
		    unsigned char *s;
		    if ((s= xmlGetProp(list,(unsigned char *)"ID")) != NULL && 
			xmlStrcasecmp(s,(unsigned char *)id) == 0) {
			 xmlFree(s);
			 return list;
		    }
		    if (s) xmlFree(s);
	       }
	  }
     /* Then recurse...*/
     for (list = start; list; list=list->next)     
	  for (node = list->xmlChildrenNode; node; node = node->next)
	       if (xmlStrcasecmp(node->name, (const xmlChar *)name) == 0) {
		    if (!id)
			 return node;
		    else {
			 unsigned char *s;
			 if ((s = xmlGetProp(node,(unsigned char *)"ID")) != NULL && 
			     xmlStrcasecmp(s,(unsigned char *)id) == 0) {
			      xmlFree(s);
			      return node; 
			 }
			 if (s) xmlFree(s);
		    }
	       } else if (node->type != XML_COMMENT_NODE && 
			  (x = find_node(node, name,id, level+1,maxlevel)) != NULL) 
		    return x;     
     return NULL;
}

MmsUaProfile *mms_make_ua_profile(List *req_headers)
{
     MmsUaProfile *prof = NULL;
     Octstr *s, *ua;
     List *l;
     int i, n;
     static int uacounter;
     
     /* Check cache first, if not, then construct. */
     if ((ua = http_header_value(req_headers, octstr_imm("User-Agent"))) == NULL)
	  ua = octstr_format("dummy-ua-%d", uacounter++);
     
     if ((prof = dict_get(profile_dict, ua)) != NULL) 
	  goto done;
          
     prof = gw_malloc(sizeof *prof);
     memset(prof, 0, sizeof *prof);
     
     /* Put in some defaults. then read then check accepts. */
     prof->maxres.x = 640;
     prof->maxres.y = 480;
     prof->maxmsgsize = 100*1024;
     prof->versions = gwlist_create();


     gwlist_append(prof->versions, octstr_imm("1.0")); /* Assume 1.0 for now. */
     
     /* Get accepted charsets. */
     s = http_header_value(req_headers, octstr_imm("Accept-Charset"));
     
     if (s && (l = http_header_split_value(s)) != NULL) {
	  prof->ccppaccept.charset = l;
	  prof->ccppaccept._chash = gwlist_create();
	  for (i = 0, n = gwlist_len(l); i<n; i++)
	       gwlist_append(prof->ccppaccept._chash, (void *)hash_key(gwlist_get(l, i)));	  
     }
     if (s) octstr_destroy(s);


     /* Get accepted encodings. */
     s = http_header_value(req_headers, octstr_imm("Accept-Encoding"));
     
     if (s && (l = http_header_split_value(s)) != NULL)
	  prof->ccppaccept.enc = l;     

     if (s) octstr_destroy(s);



     /* Get accepted language. */
     s = http_header_value(req_headers, octstr_imm("Accept-Language"));   
     if (s && (l = http_header_split_value(s)) != NULL)
	  prof->ccppaccept.lang = l;     

     if (s) octstr_destroy(s);
     
     s = http_header_value(req_headers, octstr_imm("Accept"));   
     if (s && (l = http_header_split_value(s)) != NULL) {
	  prof->ccppaccept.content = l;
	  prof->ccppaccept._hash = gwlist_create();
	  
	  for (i = 0, n = l ? gwlist_len(l) : 0; i<n; i++) {
	       Octstr *x = gwlist_get(l, i);
	       if (octstr_str_compare(x, "*/*") == 0)
		    prof->ccppaccept.all = 1;
	       else if (octstr_case_compare(x, octstr_imm(PRES_TYPE)) == 0)
		    prof->ccppaccept.presentation = 1;
	       
	       gwlist_append(prof->ccppaccept._hash, (void *)hash_key(x));
	  }
     }
     
     if (s) octstr_destroy(s);
 
     /* Put it in with the UA string as the key. */
     if (dict_put_once(profile_dict, ua, prof) != 1)
	  warning(0, "mms_uaprof: Duplicate cache entry(%s)?\n", 
		  octstr_get_cstr(ua));
     
     /* Done. Dump it while debugging. */
 done:

#if 1
     dump_profile(prof, ua ? ua : octstr_imm("<from http headers>"));
#endif
     
     if (ua)
	  octstr_destroy(ua);
     return prof;     
}

static MmsUaProfile *parse_uaprofile(Octstr *xml)
{
     char *s = octstr_get_cstr(xml);
     xmlDocPtr doc = xmlParseMemory(s, octstr_len(xml));
     xmlNodePtr node, xnode;
     MmsUaProfile *prof = NULL;
     
     if (!doc || !doc->xmlChildrenNode) 
	  goto done;

     node = find_node(doc->xmlChildrenNode, "Description", "MmsCharacteristics",0,3);
     
     prof = gw_malloc(sizeof *prof);
     memset(prof, 0, sizeof *prof);
     
     /* Put in some defaults. then read the file. */
     prof->versions = NULL;
     prof->maxres.x = 640;
     prof->maxres.y = 480;
     prof->maxmsgsize = 100*1024;
     prof->versions = NULL;


     if (!node) 
	  goto done;

     for (xnode = node->xmlChildrenNode; xnode; xnode = xnode->next) {
	  xmlNodePtr child = xnode->xmlChildrenNode, lnode, rdfnode;
	  const unsigned char *xname = xnode->name;
	  unsigned char *childtext = xmlNodeListGetString(doc, child, 1);
	  List *l;
	  
	  /* If there is a Bag, get the list. */
	  if ((rdfnode = find_node(xnode->xmlChildrenNode, "Bag", NULL,0,1)) != NULL) {
	       l = gwlist_create();	       
	       for (lnode = rdfnode->xmlChildrenNode; lnode; lnode = lnode->next)
		    if (xmlStrcasecmp(lnode->name, (const xmlChar *)"li") == 0) {
			 unsigned char *t = xmlNodeListGetString(doc, lnode->xmlChildrenNode,1);
			 if (t) {
			   gwlist_append(l, octstr_create((char *)t));
			   xmlFree(t);
			 }
		    }
	  } else
	       l = NULL;
	  
	  if (xmlStrcasecmp(xname, (const xmlChar *)"MmsMaxMessageSize") == 0) 
	    sscanf((char *)childtext, "%ld", &prof->maxmsgsize);
	  else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsMaxImageResolution") == 0) 
	    sscanf((char *)childtext, "%ldx%ld", &prof->maxres.x, &prof->maxres.y);
	  else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptCharSet") == 0 ||
		   xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAccept-CharSet") == 0) {/* Cranky old ones! */
	       int i, n;
	       prof->ccppaccept.charset = l;
	       prof->ccppaccept._chash = gwlist_create();
	       for (i = 0, n = gwlist_len(l); i<n; i++)
		    gwlist_append(prof->ccppaccept._chash, (void *)hash_key(gwlist_get(l, i)));
	  } else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptLanguage") == 0) 
	       prof->ccppaccept.lang = l;
	  else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAcceptEncoding") == 0) 
	       prof->ccppaccept.enc = l;
	  else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsVersion") == 0) {
	       if (!l && childtext) { /* SonyEriccson uses old format! */
		    l = gwlist_create();
		    gwlist_append(l, octstr_create((char *)childtext));
	       }
	       prof->versions = l;
	  } else if (xmlStrcasecmp(xname, (const xmlChar *)"MmsCcppAccept") == 0) {
	       int i, n;
	       prof->ccppaccept.content = l;
	       prof->ccppaccept._hash = gwlist_create();
	       
	       for (i = 0, n = l ? gwlist_len(l) : 0; i<n; i++) {
		    Octstr *x = gwlist_get(l, i);
		    if (octstr_str_compare(x, "*/*") == 0)
			 prof->ccppaccept.all = 1;
		    else if (octstr_case_compare(x, octstr_imm(PRES_TYPE)) == 0)
			 prof->ccppaccept.presentation = 1;

		    gwlist_append(prof->ccppaccept._hash, (void *)hash_key(x));
	       }
	  }	  
	  if (childtext) xmlFree(childtext);
     }

 done:
     if (doc) xmlFreeDoc(doc);
     return prof;
}


static int replace_slash(int ch)
{
     return (ch == '/') ? '$' : ch;
}

static int unreplace_slash(int ch)
{
     return (ch == '$') ? '/' : ch;
}

static int mms_load_ua_profile_cache(char *dir)
{

     DIR *dirp;
     struct dirent *dp;
     dirp = opendir(dir);
     
     if (!dirp) {
	  error(0, "mms_uaprof: Failed to open UA prof cache directory %s", 
		dir);
	  return -1;
     }

     while ((dp = readdir(dirp)) != NULL) {
	  Octstr *fname;
	  Octstr *xml = NULL;
	  MmsUaProfile *prof = NULL;
	  Octstr *key = NULL;
	  
	  
	  if (strcmp(dp->d_name, ".") == 0 || 
	      strcmp(dp->d_name, "..") == 0) /* A directory, skip. */
	       continue;
	  
	  fname = octstr_format("%.255s/%.254s", dir, dp->d_name);
	  
	  xml = octstr_read_file(octstr_get_cstr(fname));
	  octstr_destroy(fname);
	  if (!xml) {
	       error(0, "mms_uaprof: Failed to read UA prof doc %s in %s (%s)\n", 
		     dp->d_name, dir, strerror(errno));
	       continue;
	  }
	  
	  prof = parse_uaprofile(xml);
	  if (!prof) {
	       error(0, "mms_uaprof: Failed to parse UA prof doc %s in %s\n", dp->d_name, dir);
	       goto loop;
	  }

	  key = octstr_create(dp->d_name);
	  octstr_convert_range(key, 0, octstr_len(key), unreplace_slash);

	  if (dict_put_once(profile_dict, key, prof) != 1)
	       warning(0, "mms_uaprof: Duplicate cache entry(%s)?\n", 
		       octstr_get_cstr(key));
#if 1
	  dump_profile(prof, key);
#endif
     loop:
	  if (xml) octstr_destroy(xml);	  	  
	  if (key) octstr_destroy(key);
     }
     closedir(dirp);

     return 0;
}


static MmsUaProfile *profile_fetch(Octstr *profile_url)
{
     Octstr *body = NULL;
     List *h, *rh = NULL;
     int status;
     MmsUaProfile *prof;

     gw_assert(profile_dict);
     
     debug("mms.uaprof", 0, "Entered fetcher");  

     if ((prof = dict_get(profile_dict, profile_url)) != NULL) 
	  return prof;

     h = http_create_empty_headers();
     http_header_add(h, "User-Agent", MM_NAME "/" MMSC_VERSION);	       
     
     status = mms_url_fetch_content(HTTP_METHOD_GET, profile_url, h, octstr_imm(""), &rh, &body);   
     if (http_status_class(status) == HTTP_STATUS_SUCCESSFUL) {
	  prof = parse_uaprofile(body);
	  
	  debug("mms.uaprof", 0, "Fetcher got %s", octstr_get_cstr(profile_url));	  
	  if (prof) {
	       if (dict_put_once(profile_dict, profile_url, prof) != 1)
		    warning(0, "mms_uaprof: Duplicate ua profile fetched? (%s)?\n", 
			    octstr_get_cstr(profile_url));
	       else {
		    Octstr *fname;
		    FILE *f;
		    octstr_convert_range(profile_url, 0, octstr_len(profile_url), replace_slash);
		    fname = octstr_format("%.255s/%.254s", octstr_get_cstr(profile_dir), 
					  octstr_get_cstr(profile_url));
		    
		    f = fopen(octstr_get_cstr(fname), "w");
		    
		    if (f) {
			 octstr_print(f, body);
			 fclose(f);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -