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

📄 mms_uaprof.c

📁 手机端彩信的编解码、以及接收和发送。非常有用。
💻 C
📖 第 1 页 / 共 3 页
字号:
		    } else 
			 error(0, "mms_uaprof: Failed to save profile data to cache file %s->%s\n",
			       octstr_get_cstr(fname), strerror(errno));
		    octstr_destroy(fname);
	       }
	  } else 
	       error(0, "mms_uaprof: Failed to parse UA prof url=%s\n", 
		     octstr_get_cstr(profile_url));	  
     }  else 
	  prof = NULL;     

     if (body) octstr_destroy(body);

     if (h) http_destroy_headers(h);
     if (rh) http_destroy_headers(rh);
     
     return prof;
}

static void init_format_table(void);
#define UACOUNT_PROFILE 1023
int mms_start_profile_engine(char *cache_dir)
{
     if (profile_dict)
	  return 0;

     profile_dir = octstr_create(cache_dir);
     
    if (!profile_dict)
	  profile_dict = dict_create(UACOUNT_PROFILE, 
				     (void (*)(void *))destroy_uaprof);     
     init_format_table();
     mms_load_ua_profile_cache(cache_dir); 

     
     return 0;
}

int mms_stop_profile_engine(void)
{     
     /* This will cause thread to stop and also destroy dict. */
     if (profile_dir)
	  octstr_destroy(profile_dir);
     dict_destroy(profile_dict);
     profile_dict = NULL;
     return 0;
}

MmsUaProfile *mms_get_ua_profile(char *url)
{
     Octstr *s = octstr_create(url);
     MmsUaProfile *prof = NULL;

     gw_assert(profile_dict);
     prof = profile_fetch(s);
     octstr_destroy(s);
     return prof;
}

/* Content convertors. 
 * content types are listed in order of preference. 
 * Notes: We have a concept of an intermediate format. For audio it is WAV 
 * (of indeterminate frequency or sample size). Each type of command should expect input on stdin
 * and write output to standard out.
 * New 25-01-04: For images we now use Imagemagick to convert, hence no intermediate format. 
 */

#define NELEMS(a) (sizeof a/sizeof a[0])
struct {
     char *content_type; /* Content type. */
     unsigned long chash; /* hash value. */
     
     char *tostandard_cmd; /* Command to convert to standard format. */
     char *fromstandard_cmd; /* Command to convert from standard format. */
     
     char *file_ext; /* Standard file extension. */
     int multi_image; /* whether this format allows for multiple images in one file. */
     enum {TIMAGE=1,TAUDIO,TTEXT,TPRES,TOTHER} t;
} cformats[] = { 
  /* Note: Order of listing matters: 
   * For images, we prefer jpeg (smaller, better support),
   * For audio we prefer MP3 (smaller, well supported).
   */
     {"image/jpeg", 0, "jpegtopnm", "pnmtojpeg", "jpg", 0, TIMAGE},
     {"image/png", 0, "pngtopnm  ", "pnmtopng  ", "png", 0, TIMAGE},
     {"image/jpg", 0, "jpegtopnm", "pnmtojpeg", "jpg", 0, TIMAGE},
     {"image/tiff", 0, "tifftopnm", "pnmtotiff", "tiff", 1, TIMAGE},

     {"image/gif", 0, "giftopnm", "pnmquant 256 | ppmtogif", "gif", 1, TIMAGE},
     {"image/bmp", 0, "bmptopnm", "pnmquant 256 | ppmtobmp", "bmp", 1, TIMAGE},
     {"image/vnd.wap.wbmp", 0, "wbmptopbm", "ppmtopgm | pgmtopbm | pbmtowbmp", "wbmp", 0, TIMAGE},
#if 0
     {"image/x-bmp", 0, "bmptopnm", "pnmtobmp", "bmp", 0, TIMAGE},
     {"image/x-wmf", 0, "bmptopnm", "pnmtobmp", "bmp", 0, TIMAGE},
     {"image/vnd.wap.wpng", 0, "pngtopnm", "pngtobmp", "png", 0, TIMAGE},
     {"image/x-up-wpng", 0, "pngtopnm", "pnmtopng", "png", 0, TIMAGE},
#endif
     {"audio/mpeg", 0, "mpg123 -w - -", "lame - -", "mp3",0, TAUDIO},
     {"audio/wav", 0, "cat", "cat", "wav",0, TAUDIO},
     {"audio/x-wav", 0, "cat", "cat", "wav",0, TAUDIO},
     {"audio/basic", 0, "sox -t au -r 8000 -b -c 1 - -t wav -", 
      "sox -t wav - -t au -b -c 1 -r 8000 - lowpass 3700", "au",0, TAUDIO},
     {"audio/amr", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -", 
      "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
     {"audio/x-amr", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -", 
      "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
     {"audio/amr-wb", 0, "amrdecoder - - | sox -t raw -s -w -c 1 -r 8000 - -t wav -", 
      "sox -t wav - -t raw -s -w -c 1 -r 8000 - lowpass 3700 | amrencoder MR122 - -", "amr",0, TAUDIO},
#if 0
     {"audio/midi", 0, "cat", "cat", "mid",0, TAUDIO},
     {"audio/sp-midi", 0, "cat", "cat", "mid",0, TAUDIO},
#endif
};

/* Image commands for finding resolution, scaling and conversion. */
#define IMGRESCMD "identify -format '%%w %%h' %s:%s"
#define IMGSCALECMD "convert -scale '%ldx%ld>' %s:%s %s:-"
#define IMGCONVERTCMD "convert '%s:%s' '%s:%s'"

static void init_format_table(void)
{
     int i;
     
     for (i = 0; i < NELEMS(cformats); i++)
	  cformats[i].chash = hash_key(octstr_imm(cformats[i].content_type));
     
}

/* Removes an object by making it text/plain. For now not configurable. */
static void remove_object(MIMEEntity *m, Octstr *ctype)
{
     List *h = mime_entity_headers(m);
     Octstr *s = octstr_format("Unsupported object (content type %S) removed", ctype);

     http_header_remove_all(h, "Content-Type");     
     http_header_add(h, "Content-Type", "text/plain");

     mime_replace_headers(m, h);
     http_destroy_headers(h);

     while (mime_entity_num_parts(m) > 0) /* Delete all parts, if any. */
	  mime_entity_remove_part(m, 0);
     mime_entity_set_body(m, s);
     octstr_destroy(s);
}

static void mktmpfname(char fname[])
{
     sprintf(fname, "%s/t%ld.%ld.%ld", 
#ifdef P_tmpdir
	     P_tmpdir,
#else
	     "/tmp"
#endif
	     random(), (long)getpid(), (long)time(NULL));     
}

static Octstr *mknewname(Octstr *oldname, char *ext)
{
     Octstr *s;

     int i = octstr_search_char(oldname, '.', 0);

     if (i<0)
	  return octstr_format("%S.%s", oldname, ext);

     s = octstr_copy(oldname, 0, i+1);
     octstr_append_cstr(s,ext);
     return s;
}

static void replace_ctype(List *headers, char *newcontent_type, List *params_h)
{
     Octstr *ct;
     if (gwlist_len(params_h) > 0) {
	  Octstr *tmp = make_value_parameters(params_h);
	  ct  = octstr_format("%s; %S", newcontent_type, tmp);
	  octstr_destroy(tmp);
     } else 
	  ct  = octstr_format("%s", newcontent_type);
     
     http_header_remove_all(headers, "Content-Type");	  
     http_header_add(headers, "Content-Type", octstr_get_cstr(ct));
     octstr_destroy(ct);
}

static void replace_body(MIMEEntity *msg, Octstr *newbody, List *params_h, 
			 char *newcontent_type, char *file_ext, 
			 int add_disposition_header)
{
     Octstr *part_name;
     Octstr *new_partname = NULL;
     List *h = mime_entity_headers(msg);

     mime_entity_set_body(msg, newbody); /* Replace the body. */
     octstr_destroy(newbody);

     if ((part_name = http_header_value(params_h, octstr_imm("name"))) != NULL) {
	  Octstr *tmp = mknewname(part_name, file_ext);
	  http_header_remove_all(params_h, "name");
	  http_header_add(params_h, "name", octstr_get_cstr(tmp));
	
	  octstr_destroy(part_name);
	  new_partname = tmp;
     }
     
     replace_ctype(h, newcontent_type, params_h);

     if (add_disposition_header) {
	  Octstr *tmp = octstr_format("inline; filename=\"%S\"",
				      new_partname ? new_partname : octstr_imm("any"));
	  http_header_add(h, "Content-Disposition", octstr_get_cstr(tmp));
	  octstr_destroy(tmp);
     }
     mime_replace_headers(msg,h);
     http_destroy_headers(h);
     if (new_partname) octstr_destroy(new_partname);
}

/* Modify the message based on the user agent profile data. Return 1 if was supported, 0
 * otherwise 
 */
static int modify_msg(MIMEEntity *msg, MmsUaProfile *prof)
{
     int i, n, type, send_data;
     int j,m;
     Octstr *content_type = NULL, *params = NULL, *s;
     List *params_h;
     
     unsigned long chash;
     unsigned char supported = 0;
     
     int iindex, oindex;
     
     FILE *pf;
     char tmpf[40], tmpf2[40];
     Octstr *cmd = NULL;
     List *h = NULL;

     if (!msg) return 0;

     tmpf[0] = tmpf2[0] = 0; /* Clear .*/
     
     /* Get the content type, hash it. */  
     h = mime_entity_headers(msg);
     get_content_type(h, &content_type, &params);	       
     params_h = get_value_parameters(params);
     
#if 0
     debug("MMS uaprof:", 0, " content_type = ### %s & %s: Header dump follows:",  
	   octstr_get_cstr(content_type), params ? octstr_get_cstr(params) : "NULL");	  
     http_header_dump(params_h);
#endif
     
     if ((n = mime_entity_num_parts(msg)) > 0) {
	  Octstr *startp = http_header_value(params_h, octstr_imm("start"));
	  int sflag = 0;
	  
	  for (i = 0; i<n; i++) {
	       MIMEEntity *x = mime_entity_get_part(msg,i);
	       List *hx = mime_entity_headers(x);
 	       Octstr *cid = _x_get_content_id(hx);
	       int sup;
	       	       
	       debug("MMS uaprof: cid =###", 0, "%s", cid ? octstr_get_cstr(cid) : "NULL");
	       
	       sup = modify_msg(x, prof);
	       
	       if (!sup && /* not supported and is the presentation part, set flag */
		   cid && octstr_compare(cid, startp) == 0) 
		    sflag = 1;		   
	       if (cid) octstr_destroy(cid);

	       mime_entity_replace_part(msg, i, x); /* Put back changed one */
	       http_destroy_headers(hx);
	       mime_entity_destroy(x);
	  }
	  
	  /* If no start param but content type is other than multipart/mixed OR 
	   *   There is a start param but presentation type is not supported, 
	   * Or presentations are not supported.
	   */
	  if (sflag || 
	      (!startp && 
	       octstr_case_compare(content_type, octstr_imm("multipart/related")) == 0) || 
	      !(prof->ccppaccept.presentation || prof->ccppaccept.all)) {
	       /* MMS conformance guide says: If presentation part is removed or unsupported, 
		*  then change content type to multipart/mixed
		*/
	       
	       http_header_remove_all(params_h, "start"); 
	       http_header_remove_all(params_h, "type");
	       
	       replace_ctype(h, "multipart/mixed", params_h);
	  }
	  
	  if (startp) octstr_destroy(startp);
	  
	  supported = 1;
	  goto done;
     }

     
     if (octstr_case_search(content_type, octstr_imm("image/"), 0) == 0)
	  type = TIMAGE;
     else if (octstr_case_search(content_type, octstr_imm("audio/"), 0) == 0)
	  type = TAUDIO;
     else if (octstr_case_search(content_type, octstr_imm("text/"), 0) == 0)
	  type = TTEXT;
     else
	  type = TOTHER;


     if (type == TTEXT) { /* Deal with charset issues. */
	  Octstr *charset = http_header_value(params_h, octstr_imm("charset")); 
	  char csupport = 0;
	  int i,n;
	  
	  if (charset == NULL || 
	      octstr_str_compare(charset, "unknown") == 0) {
	       if (charset) octstr_destroy(charset);
	       charset = octstr_imm(DEFAULT_CHARSET);
	  }
	  
	  n = prof->ccppaccept.charset ? gwlist_len(prof->ccppaccept.charset) : 0;
	  
	  /* Is this character set supported? If so do nothing. */
	  for (i = 0; i<n; i++) 
	       if (octstr_case_compare(gwlist_get(prof->ccppaccept.charset,i), charset) == 0) {
		    csupport = 1;
		    break;
	       }

	  if (!csupport) 
	       for (i = 0; i<n; i++) {
		    Octstr *ncharset = gwlist_get(prof->ccppaccept.charset,i); /* Don't free this! */
		    Octstr *ct;
		    Octstr *s = mime_entity_body(msg);
		    if (charset_convert(s, octstr_get_cstr(charset), 
					octstr_get_cstr(ncharset)) != -1) { /* using libiconv...*/
			 Octstr *tmp;
			 
			 http_header_remove_all(params_h, "charset");
			 http_header_add(params_h, "charset", octstr_get_cstr(ncharset));
			 tmp = make_value_parameters(params_h);
			 
			 ct  = octstr_format("%S; %S", content_type, tmp);
			 octstr_destroy(tmp);
			 http_header_remove_all(h, "Content-Type");
			 http_header_add(h, "Content-Type", octstr_get_cstr(ct));
			 octstr_destroy(ct);
			 
			 mime_entity_set_body(msg,s); /* replace with new body. */
			 break;  /* We succeeded in converting it so we shd go away. */
		    } else 
			 octstr_destroy(s);
	       }
	  
	  octstr_destroy(charset);
	  supported = 1;
	  goto done; /* No further processing for text/plain. */
     }

    /* find out if it is supported by the user agent. */
     chash = hash_key(content_type);
     if (prof->ccppaccept.all) /* Check if it accepts all content types. */
	  supported = 1;
     else 
	  for (i = 0, n = prof->ccppaccept.content ? gwlist_len(prof->ccppaccept.content) : 0;
	       i<n; i++)
	       if ((unsigned long)gwlist_get(prof->ccppaccept._hash,i) == chash &&
		   octstr_case_compare(gwlist_get(prof->ccppaccept.content,i),content_type) == 0) {
		    supported = 1;
		    break;
	       }
     
     if (supported && type != TIMAGE)
	  goto done; /* If it is supported, go away now. 
		      * But for images we defer since we might have to  scale the image.
		      */
     else if (type == TOTHER) 
	  goto done; /* Not supported and not audio or image, will be removed at done. */

     
     /* At this point we have type = IMAGE (supported or not) OR type = AUDIO (unsuppported). */

     
     /* Find out if we have a means of converting this format to our internal format,
      * and if we have means of converting from internal to a format the UA supports.
      * For images this means: Can we read it? Can we write out a supported format?
      */

     iindex = -1;
     for (i = 0; i < NELEMS(cformats); i++)
	  if (cformats[i].chash == chash && 
	      octstr_case_compare(content_type, octstr_imm(cformats[i].content_type)) == 0) {
	       if (cformats[i].tostandard_cmd) 
		    iindex = i; /* Only if the cmd exists actually. */
	       break;
	  }

     oindex = -1;
     for (i = 0; i < NELEMS(cformats); i++)
	  if (cformats[i].fromstandard_cmd) /* Check only ones we can convert from. */
	       for (j = 0, m = gwlist_len(prof->ccppaccept.content); j<m; j++) 
		    if ((unsigned long)gwlist_get(prof->ccppaccept._hash,j) == cformats[i].chash &&
			cformats[i].t == type && /* Convert to like type ! */
			octstr_case_compare(gwlist_get(prof->ccppaccept.content,j),
					    octstr_imm(cformats[i].content_type)) == 0){
			 oindex = i;
			 i = NELEMS(cformats); /* So the other loop breaks too. */
			 break;
		    }
     
     
     if (iindex < 0 || oindex < 0)  /* We don't know how to convert this one fully, so... */
	  goto done2; /* go away, don't even replace headers. */
     
     
     /* Whatever we have (audio or image) we know how to convert it fully, so ... */
     mktmpfname(tmpf);          
     if (type == TIMAGE) {
	  FILE *pf;
	  long x = 640, y = 480;
	  Octstr *icmd, *s;
	  char *selector;
	  
	  mktmpfname(tmpf2);	  
	  pf = fopen(tmpf2, "w");
	  if (!pf) 
	       goto done;
	  
	  s = mime_entity_body(msg);
	  n = octstr_print(pf, s);
	  m = fclose(pf);

	  octstr_destroy(s);
	  if (n < 0 || m != 0)
	       goto done; /* error .*/
	  
	  /* Get the image dimensions, see if we need to modify it. */
	  icmd = octstr_format(IMGRESCMD, 
				 cformats[iindex].file_ext, tmpf2);
	  
	  pf = popen(octstr_get_cstr(icmd), "r");
	  octstr_destroy(icmd);
	  
	  if (!pf)
	       goto done;
	  fscanf(pf, "%ld %ld", &x, &y);
	  pclose(pf);

	  icmd = NULL; /* Reset to NULL. */
	  if (x > prof->maxres.x ||
	      y > prof->maxres.y)
	       icmd = octstr_format(IMGSCALECMD, prof->maxres.x, prof->maxres.y, 
		       cformats[iindex].file_ext,
		       tmpf2,
		       cformats[iindex].file_ext);
	  else if (supported) /* A supported image format and no need to scale, so go away. */
	       goto done;

⌨️ 快捷键说明

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