home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / contrib / mms / mmsviewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-05  |  15.1 KB  |  703 lines

  1. /*////////////////////////////////////////////////////////////////////////
  2. Copyright (c) 1992 Electrotechnical Laboratry (ETL)
  3.  
  4. Permission to use, copy, modify, and distribute this material 
  5. for any purpose and without fee is hereby granted, provided 
  6. that the above copyright notice and this permission notice 
  7. appear in all copies, and that the name of ETL not be 
  8. used in advertising or publicity pertaining to this 
  9. material without the specific, prior written permission 
  10. of an authorized representative of ETL.
  11. ETL MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
  12. OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
  13. WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
  14. /////////////////////////////////////////////////////////////////////////
  15. Content-Type: program/C; charset=US-ASCII
  16. Program:      mmsviewer.c (MIME message viewer)
  17. Author:       Yutaka Sato <ysato@etl.go.jp>
  18. Description:
  19.  
  20. History:
  21.         920503    created a small prototype
  22.         920513    added HOLOPHRASTING function
  23.     920621    added automatic assembling of partial messages
  24. ///////////////////////////////////////////////////////////////////////*/
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. char *getenv();
  29.  
  30. typedef int MimePartP;
  31. char *MMS_partContentType();
  32. char *MMS_partContentParam();
  33. char *MMS_partContentDescription();
  34. char *MMS_partInheritHeader();
  35. FILE *MMS_partTmpfile();
  36. FILE *MMS_partMakeTmpfile();
  37.  
  38. /*//////////////////////////////////////////////////////////////////////*/
  39.  
  40. MMS_E_viewer(ac,av,in,out)
  41.     char *av[];
  42.     FILE *in,*out;
  43. {    FILE *in1;
  44.  
  45.     if( 1 < ac ){
  46.         in1 = fopen(av[1],"r");
  47.         if( in1 == NULL ){
  48.             fprintf(stderr,"mmsviewer: unknown file '%s'\n",av[1]);
  49.             exit(-1);
  50.         }
  51.         in = in1;
  52.     }
  53.     MMS_viewer(in,out);
  54. }
  55. int (*MMS_E_VIEWER)() = MMS_E_viewer;
  56.  
  57. /*//////////////////////////////////////////////////////////////////////*/
  58.  
  59. int MMS_V_HEAD        = 1;
  60. int MMS_V_BODY        = 2;
  61. int MMS_V_ARTICLE    = 3;
  62.  
  63. /*////////////////////////////////////////////////////////////////////////
  64.  *    SIMPLE VIEWER
  65.  */
  66. static winclear(mp){
  67.     char *cd;
  68.  
  69.     if( cd = getenv("MMS_CLEARDISPLAY") ){
  70.         printf("%s",cd);
  71.         fflush(stdout);
  72.     }else    system("clear");
  73. }
  74. int (*MMS_BEFORE_viewZoom1)();
  75.  
  76. MMS_viewer(in,out)
  77.     FILE *in,*out;
  78. {    MimePartP root;
  79.     FILE *tty;
  80.  
  81.     if( !MMS_seekable(in) )
  82.         in = (FILE*)MMS_saveTempfile(in,0);
  83.     root = MMS_parser(in,out);
  84.  
  85.     tty = fopen("/dev/tty","r");
  86.     if( tty == NULL )
  87.         return;
  88.  
  89.     if( in == stdin ){
  90.         in = fdopen(dup(fileno(stdin)),"r");
  91.         close(fileno(stdin));
  92.         dup(fileno(tty));
  93.     }
  94.  
  95.     MMS_BEFORE_viewZoom1 = winclear;
  96.     MMS_Viewer(in,out,root,0,tty);
  97.     fclose(tty);
  98. }
  99.  
  100. MMS_viewNthPart(in,out,root,nth)
  101.     FILE *in,*out;
  102.     MimePartP root;
  103. {    MimePartP mp;
  104.  
  105.     if( root )
  106.     if( mp = MMS_partNthPart(root,nth) )
  107.         MMS_viewCocked(in,out,mp);
  108. }
  109.  
  110. static char *
  111. MMS_std_comget(msg,command,size,comin)
  112.     char *msg,*command;
  113.     FILE *comin;
  114. {
  115.     fprintf(stdout,"[ %s ] ",msg);
  116.     fflush(stdout);
  117.     return fgets(command,size,comin);
  118. }
  119. #define STRTAIL(s)    (s+strlen(s))
  120. MMS_Viewer(in,out,rootmp,comfunc,comin)
  121.     FILE *in,*out,*comin;
  122.     MimePartP rootmp;
  123.     char *(*comfunc)();
  124. {    char command[128],msg[256],*comp;
  125.     MimePartP mp,pmp;
  126.     int numarg = 0;
  127.  
  128.     if( comfunc == 0 )
  129.         comfunc = MMS_std_comget;
  130.  
  131.     mp = rootmp;
  132.     MMS_viewZoom1(in,out,rootmp,mp);
  133.     for(;;){
  134.         printf(">>>> "); MIME_dumpStat(out,mp);
  135.         sprintf(msg,"q:uit w:rite s:keleton ");
  136.         if(!MMS_partIsMultipart(mp))sprintf(STRTAIL(msg),"v:iew ");
  137.         if( MMS_partNextPeer(mp)   )sprintf(STRTAIL(msg),"n:ext ");
  138.         if( MMS_partPrevPeer(mp)   )sprintf(STRTAIL(msg),"p:rev ");
  139.         if( MMS_part1stChild(mp)   )sprintf(STRTAIL(msg),"d:own ");
  140.         if( MMS_partParent(mp)     )sprintf(STRTAIL(msg),"u:p ");
  141.         sprintf(STRTAIL(msg),"Ng:goto-Nth ");
  142.         if( MMS_partNext(mp) )
  143.             sprintf(STRTAIL(msg),"RETURN:print-next");
  144.         else    sprintf(STRTAIL(msg),"RETURN:quit");
  145.  
  146.         (*comfunc)(msg,command,sizeof(command),comin);
  147.         if( *command == '\n' ){
  148.             if( MMS_partNext(mp) == 0 )
  149.                 break;
  150.             else    strcpy(command,"+a");
  151.         }
  152.  
  153.         for(comp = command; *comp; comp++ ){
  154.             pmp = mp;
  155.             numarg = 0;
  156.             if( isdigit(*comp) ){
  157.             do {
  158.                 numarg = numarg * 10 + (*comp - '0');
  159.                 comp++;
  160.             } while( isdigit(*comp) );
  161.             if( *comp == '\n' )
  162.                 strcpy(comp,"g");
  163.             }
  164.             switch( *comp ){
  165.             case '+': mp = MMS_partNext(mp); break;
  166.             case '-': mp = MMS_partPrev(mp); break;
  167.  
  168.             case 'j': case 'n':
  169.                 if( mp = MMS_partNextPeer(mp) )
  170.                     MMS_viewZoom1(in,out,rootmp,mp);break;
  171.             case 'k': case 'p':
  172.                 if( mp = MMS_partPrevPeer(mp) )
  173.                     MMS_viewZoom1(in,out,rootmp,mp);break;
  174.             case 'i': case 'd':
  175.                 if( mp = MMS_part1stChild(mp) )
  176.                     MMS_viewZoom1(in,out,rootmp,mp);break;
  177.             case 'o': case 'u':
  178.                 if( mp = MMS_partParent(mp) )
  179.                     MMS_viewZoom1(in,out,rootmp,mp);break;
  180.             case 'g':
  181.                 if( mp = MMS_partNthSection(rootmp,numarg) )
  182.                   MMS_viewZoom1(in,out,rootmp,mp);    break;
  183.  
  184.             case 'h': MMS_viewAsis(in,out,mp,MMS_V_HEAD);    break;
  185.             case 'b': MMS_viewAsis(in,out,mp,MMS_V_BODY);    break;
  186.             case 'a': MMS_viewZoom1(in,out,rootmp,mp);    break;
  187.             case 'v': MMS_viewCocked(in,out,mp);        break;
  188.             case 'w': MMS_writetotmp(in,mp);        break;
  189.  
  190.             case 's': MMS_viewSkeleton(in,out,mp); break;
  191.  
  192.             case 'q': goto EXIT;
  193.             }
  194.             if( mp == 0 )
  195.             mp = pmp;
  196.         }
  197.     }
  198.     EXIT:;
  199. }
  200.  
  201. extern char MMS_ERR_BADPARAM[];
  202. MMS_BuildCommand(command,tmpfile,comspec,in,mp)
  203.     char *command,*tmpfile,*comspec;
  204.     FILE *in;
  205.     MimePartP mp;
  206. {    char *sp,*cp,*tp;
  207.     int usetemp = 0;
  208.     char *tmpfn;
  209.     FILE *tmpfp;
  210.  
  211.     command[0] = 0; 
  212.     sp = comspec;
  213.     cp = command;
  214.     while( *sp ){
  215.         if( *sp == '%' ){
  216.         sp++;
  217.         switch(*sp){
  218.             case 's': /* FILENAME */
  219.             if( usetemp == 0 ){
  220.                 if( *tmpfile == 0 ){
  221.                 strcpy(tmpfile,tmpname());
  222.                 tmpfp = fopen(tmpfile,"w+");
  223.                 MMS_partWriteBody(in,tmpfp,mp,0,1);
  224.                 }
  225.                 usetemp = 1;
  226.             }
  227.             strcpy(cp,tmpfile);
  228.             cp += strlen(cp);
  229.             sp++;
  230.             break;
  231.  
  232.     /* PARAMETER */
  233.             case '{':
  234.             {    char *fp,param[256];
  235.  
  236.             tp = (char*)index(sp,'}');
  237.             if( tp == 0 )
  238.                 break;
  239.             sscanf(sp+1,"%[^}]",param);
  240.             MMS_tolowers(param);
  241.  
  242.             fp = MMS_partContentParam(mp,param);
  243.             if( fp == MMS_ERR_BADPARAM)
  244.                 sprintf(cp,"?{%s}?",param);
  245.             else if( fp == 0 )
  246.                 strcpy(cp,"\"\"");
  247.             else    strcpy(cp,fp);
  248.             cp += strlen(cp);
  249.             sp = tp + 1;
  250.             break;
  251.             }
  252.  
  253.             case 't':
  254.             strcpy(cp,MMS_partContentType(mp));
  255.             cp += strlen(cp);
  256.             sp++;
  257.             break;
  258.  
  259.             default:
  260.             break;
  261.         }
  262.         }else{
  263.         *cp++ = *sp++;
  264.         }
  265.     }
  266.     *cp = 0;
  267.     return usetemp;
  268. }
  269.  
  270. MMS_BuildViewer(in,mp,command,tmpfile)
  271.     MimePartP mp;
  272.     char *command,*tmpfile;
  273. {    char *ctype,*viewer;
  274.  
  275.     ctype = MMS_partContentType(mp);
  276.     if( ctype == 0 ){
  277.         printf("cannot get content-type\n");
  278.         return -1;
  279.     }
  280.     viewer = (char*)MMS_mailtoGetCommand(ctype,0);
  281.     if( viewer == 0 ){
  282.         printf("cannot get viewer for %s\n",ctype);
  283.         return -1;
  284.     }
  285.     return MMS_BuildCommand(command,tmpfile,viewer,in,mp);
  286. }
  287. MMS_BuildComposer(in,mp,command,tmpfile)
  288.     char *command,*tmpfile;
  289. {    char *ctype,*composer;
  290.  
  291.     ctype = MMS_partContentType(mp);
  292.     composer = (char*)MMS_mailtoGetCommand(ctype,"compose");
  293.     return MMS_BuildCommand(command,tmpfile,composer,in,mp);
  294. }
  295.  
  296. #include <signal.h>
  297. MMS_viewCocked(in,out,mp)
  298.     FILE *in,*out;
  299.     MimePartP mp;
  300. {    FILE *pfp;
  301.     char command[1024],tmpfile[1024];
  302.     int usetemp;
  303.  
  304.     *tmpfile = 0;
  305.     if( (usetemp = MMS_BuildViewer(in,mp,command,tmpfile)) < 0 )
  306.         return -1;
  307.  
  308.     if( isatty(fileno(stdout)) ){
  309.         printf(">>>> command: %s\n",command);
  310.         printf(">>>> input size: %dbytes Wait ...\n",MMS_partSize(mp));
  311.     }
  312.  
  313.     if( out != stdout ){
  314.         fflush(out);
  315.         if( fork() ){
  316.             wait(0);
  317.             return 0;
  318.         }
  319.         close(fileno(stdout));
  320.         dup(fileno(out));
  321.     }
  322.     if( usetemp ){
  323.         system(command);
  324.         unlink(tmpfile);
  325.     }else{
  326.         typedef void (*VOIDFUNC)();
  327.         VOIDFUNC osig;
  328.  
  329.         osig = (VOIDFUNC)signal(SIGPIPE,SIG_IGN);
  330.         pfp = popen(command,"w");
  331.         MMS_partWriteBody(in,pfp,mp,0,1);
  332.         pclose(pfp);
  333.         signal(SIGPIPE,osig);
  334.     }
  335.     if( out != stdout ){
  336.         fflush(stdout);
  337.         _exit(0);
  338.     }
  339.     return 0;
  340. }
  341.  
  342.  
  343. int MMS_WINCOLS = 76;
  344. MMS_viewAsis(in,out,mp,headbody)
  345.     FILE *in,*out;
  346.     MimePartP mp;
  347. {    int maxlines,col;
  348.  
  349.     for(col = 0; col < MMS_WINCOLS; col++) printf("="); printf("\n");
  350.  
  351.     if( MMS_partIsMultipart(mp) ){
  352.         MMS_viewSkeleton(in,out,mp);
  353.     }else{
  354.         maxlines = 10;
  355.         MMS_partWrite(in,out,mp,headbody,maxlines);
  356.     }
  357.     for(col = 0; col < MMS_WINCOLS; col++) printf("-"); printf("\n");
  358. }
  359.  
  360. MMS_holophrast(holo,mp)
  361.     char *holo;
  362.     MimePartP mp;
  363. {    char sec[32],*ctype,*desc;
  364.  
  365.     MMS_partSectionNO(sec,mp);
  366.     ctype = MMS_partContentType(mp);
  367.     sprintf(holo,"%s    %s ",sec,ctype);
  368.     if( MMS_partIsExternalBody(mp) )
  369.         sprintf(holo+strlen(holo),"(%s)",MMS_partAccessType(mp));
  370. /*
  371.     else    sprintf(holo+strlen(holo),"(%dbytes)",MMS_partSize(mp));
  372. */
  373.     else    sprintf(holo+strlen(holo),"(%d)",MMS_partLines(mp));
  374. }
  375. MMS_viewZoom1(in,out,rootmp,cmp)
  376.     MimePartP rootmp,cmp;
  377. {
  378.     if( MMS_BEFORE_viewZoom1 )
  379.         (*MMS_BEFORE_viewZoom1)(cmp);
  380.     MMS_viewHolophrast(in,out,rootmp,cmp,"",10);
  381.     fflush(out);
  382. }
  383.  
  384. MMS_viewHolophrast(in,out,rootmp,cmp,form,lines)
  385.     MimePartP rootmp,cmp;
  386.     FILE *in,*out;
  387.     char *form;
  388. {    MimePartP mp;
  389.     char holo[256],sec[32],*desc;
  390.     int col,len;
  391.  
  392.     for(mp = rootmp; mp; mp = MMS_partNext(mp) ){
  393.         if( mp != rootmp && !MMS_partIsAncestorOf(rootmp,mp) )
  394.             break;
  395.         MMS_holophrast(holo,mp);
  396.  
  397.         col = fprintf(out,"%s(%2d) %s",form,MMS_partSerialNO(mp),holo);
  398.         desc = MMS_partContentDescription(mp);
  399.         if( desc ){
  400.             len = MMS_decodeStrColumns(desc);
  401.             if( MMS_WINCOLS < col+len )
  402.                 fprintf(out,"\\\n %*s\n",MMS_WINCOLS,desc);
  403.             else    fprintf(out," %s\n",desc);
  404.         }else    fprintf(out,"\n");
  405.  
  406.         if( mp == cmp ){
  407.             MMS_partSectionNO(sec,mp);
  408.             fprintf(out,
  409.                 "======== content of section %s ========\n",
  410.                 sec);
  411.  
  412.             MMS_partWrite(in,out,mp,MMS_V_ARTICLE,lines);
  413.  
  414.             for(col = 0; col < MMS_WINCOLS; col++)
  415.                 fprintf(out,"-");
  416.             fprintf(out,"\n");
  417.         }
  418.     }
  419. }
  420.  
  421. /*////////////////////////////////////////////////////////////////////////
  422.  *
  423.  */
  424.  
  425. MMS_writetotmp(in,mp)
  426.     FILE *in;
  427.     MimePartP mp;
  428. {    FILE *out;
  429.  
  430.     out = fopen("mms.out","w+");
  431. /*
  432.     MMS_partWrite(in,out,mp,MMS_V_BODY,0);
  433. */
  434.     MMS_partWriteBody(in,out,mp,0,1);
  435.     fflush(out);
  436.     fprintf(stderr,"**** Written to mms.out ***\n");
  437. }
  438.  
  439. MMS_partWrite(in,out,mp,headbody,maxlines)
  440.     FILE *in,*out;
  441.     MimePartP mp;
  442. {    char line[1024];
  443.     int lines;
  444.     int tail;
  445.  
  446.     MMS_seekpart(in,mp,headbody);
  447.     if( headbody == MMS_V_HEAD )
  448.         tail = MMS_partBodyOffset(mp);
  449.     else    tail = MMS_partTailOffset(mp);
  450.  
  451.     for(lines = 1; ;lines++){
  452.         if( fgets(line,sizeof(line),in) == NULL )
  453.             break;
  454.         if( tail <= MMS_ftell(in) )
  455.             break;
  456.         if( maxlines && maxlines <= lines )
  457.             break;
  458.         fprintf(out,"%s",line);
  459.     }
  460.     fflush(out);
  461. }
  462.  
  463. MMS_partWriteHead(in,out,mp,maxlines)
  464.     FILE *in,*out; MimePartP mp;
  465. {    return MMS_partWrite(in,out,mp,MMS_V_HEAD,maxlines); }
  466.  
  467. MMS_partWriteBody(in,out,mp,maxlines,do_decode)
  468.     FILE *in,*out; MimePartP mp;
  469. {    char *encode;
  470.  
  471.     if( do_decode )
  472.     if( encode = (char*)MMS_partContentEncode(mp) ){
  473.         FILE *tmp = tmpfile();
  474.  
  475.         MMS_partWrite(in,tmp,mp,MMS_V_BODY,maxlines);
  476.         MMS_fseek(tmp,0,0);
  477.         MIME_Decode(tmp,out,encode);
  478.         fclose(tmp);
  479.         return;
  480.     }
  481.     return MMS_partWrite(in,out,mp,MMS_V_BODY,maxlines);
  482. }
  483.  
  484. MMS_partWriteArticle(in,out,mp,maxlines)
  485.     FILE *in,*out; MimePartP mp;
  486. {    return MMS_partWrite(in,out,mp,MMS_V_ARTICLE,maxlines); }
  487.  
  488. MMS_seekpart(in,mp,headbody)
  489.     FILE *in;
  490.     MimePartP mp;
  491. {    int off;
  492.  
  493.     if( headbody == MMS_V_BODY )
  494.         off = MMS_partBodyOffset(mp);
  495.     else    off = MMS_partHeadOffset(mp);
  496.     clearerr(in);
  497.     MMS_fseek(in,off,0);
  498.     return off;
  499. }
  500.  
  501. /*////////////////////////////////////////////////////////////////////////
  502.  *
  503.  */
  504. MMS_viewSkeleton(in,out,mp)
  505.     FILE *in,*out;
  506.     MimePartP mp;
  507. {
  508.     while( mp ){
  509.         MIME_dumpStat(out,mp);
  510.         MIME_dumpValues(out,mp,"    ");
  511.         mp = MMS_partNext(mp);
  512.     }
  513. }
  514.  
  515. MMS_getCockedText(in,out,mp,maxlines)
  516.     FILE *in,*out;
  517.     MimePartP mp;
  518. {    char *ctype;
  519.     FILE *tfp;
  520.  
  521.     ctype = MMS_partContentType(mp);
  522.     if( !MMS_partIsText(mp) )
  523.         return 0;
  524.  
  525.     if( MMS_partIsPlainText(mp) )
  526.         MMS_partWriteBody(in,out,mp,maxlines,1);
  527.     else{
  528.         fflush(out);
  529.         tfp = tmpfile();
  530.         MMS_partWriteBody(in,tfp,mp,maxlines,1);
  531.         fflush(tfp);
  532.         MMS_fseek(tfp,0,0);
  533.         MMS_richtextFork(tfp,out);
  534.         fclose(tfp);
  535.     }
  536.     return 1;
  537. }
  538.  
  539. static char *richtext_av[] = {"richtext","-f",0};
  540. MMS_richtextFork(in,out)
  541.     FILE *in,*out;
  542. {
  543.     if( fork() == 0 ){
  544.         close(0); dup(fileno(in));
  545.         close(1); dup(fileno(out));
  546.         close(2); dup(fileno(out));
  547.         richtext_main(2,richtext_av);
  548.         _exit(0);
  549.     }
  550.     wait(0);
  551. }
  552. extern int (*RichtextGetc)();
  553. extern int (*RichtextPutc)();
  554.  
  555. static FILE *richtextGetFp;
  556. static FILE *richtextPutFp;
  557.  
  558. static richtextGetc()  { return fgetc(   richtextGetFp); }
  559. static richtextPutc(ch){ return fputc(ch,richtextPutFp); }
  560.  
  561. MMS_richtextCall(in,out)
  562.     FILE *in,*out;
  563. {
  564.     richtextGetFp = in;  RichtextGetc = richtextGetc;
  565.     richtextPutFp = out; RichtextPutc = richtextPutc;
  566.     richtext_main(2,richtext_av);
  567. }
  568.  
  569. MMS_partPrintf(in,out,mp)
  570. {
  571. }
  572.  
  573.  
  574. /*
  575. --========================================================
  576. Content-Description: assembling partial messages
  577. */
  578.  
  579. FILE *(*MMS_X_OpenMessage)();
  580. MimePartP Mime_saved[100];
  581. extern char *HC_ID;
  582. extern char *HC_NUMBER;
  583. extern char *HC_TOTAL;
  584. extern char *H_MESSAGE_ID;
  585.  
  586. MMS_savePartial(in,current)
  587.     FILE *in;
  588.     MimePartP current;
  589. {    int px;
  590.     MimePartP mp;
  591.     char *cmsgid,*msgid;
  592.     char *cnumber,*number;
  593.     FILE *tmp;
  594.  
  595.     cmsgid = MMS_partContentParam(current,HC_ID);
  596.     cnumber = MMS_partContentParam(current,HC_NUMBER);
  597.  
  598.     for(px = 1; mp = Mime_saved[px]; px++){
  599.         msgid = MMS_partContentParam(mp,HC_ID);
  600.         number = MMS_partContentParam(mp,HC_NUMBER);
  601.         if( strcmp(cmsgid,msgid) == 0 ){
  602.             if( strcmp(cnumber,number) == 0 )
  603.                 break;
  604.         }
  605.     }
  606.     Mime_saved[px] = current;
  607.  
  608.     if( MMS_X_OpenMessage == 0 ){
  609.         if( (tmp = MMS_partTmpfile(current)) == 0 )
  610.             tmp = MMS_partMakeTmpfile(current);
  611.         MMS_partWriteArticle(in,tmp,current,0
  612.                 /*MUST BE LINE or BYTES*/);
  613.     }
  614. }
  615.  
  616. FILE *
  617. MMS_partCatenatePartial(path,part,search)
  618.     char *path;
  619.     MimePartP part;
  620. {    MimePartP mp;
  621.     int px;
  622.     char *pid,*stotal;
  623.     int total;
  624.     MimePartP parts[100];
  625.     int pi;
  626.     FILE *out,*pfp;
  627.     char *mid,tmid[1024],xmid[1024];
  628.  
  629.     for(pi = 1; pi < 100; pi++)
  630.         parts[pi] = 0;
  631.  
  632.     total = 0;
  633.     pid = MMS_partContentParam(part,HC_ID);
  634.  
  635.     for(px = 1; mp = Mime_saved[px]; px++)
  636.     if( strcmp(pid,MMS_partContentParam(mp,HC_ID)) == 0 ){
  637.         parts[atoi(MMS_partContentParam(mp,HC_NUMBER))] = mp;
  638.         if( stotal = MMS_partContentParam(mp,HC_TOTAL) )
  639.             total = atoi(stotal);
  640.     }
  641.  
  642.     if( mid = MMS_partInheritHeader(part,H_MESSAGE_ID) )
  643.         sscanf(mid,"<%*d%[^>]",tmid);
  644.     else    strcpy(tmid,"");
  645.  
  646.     for( pi = 1; total == 0 || pi <= total; pi++){
  647.         if( parts[pi] == 0 )
  648.         if( MMS_X_OpenMessage ){
  649.             sprintf(xmid,"<%d%s>",pi,tmid);
  650.             if( pfp = (*MMS_X_OpenMessage)(xmid,pid,pi) ){
  651.                 parts[pi] = MMS_parser(pfp,stderr);
  652.                 fclose(pfp);
  653.             }
  654.         }
  655.         if( parts[pi] == 0 )
  656.             goto incomplete;
  657.  
  658.         if( total == 0 )
  659.         if( stotal = MMS_partContentParam(parts[pi],HC_TOTAL) ){
  660.             fprintf(stderr,"**** %s/%s ***\n",stotal,stotal);
  661.             total = atoi(stotal);
  662.             goto complete;
  663.         }
  664.     }
  665.  
  666. incomplete:
  667.     if( total == 0 )
  668.         return 0;
  669. complete:
  670.     if( strcmp(path,"-") == 0 )
  671.         out = stdin;
  672.     else    out = fopen(path,"w+");
  673.  
  674.     for(pi = 1; pi <= total; pi++){
  675.         mp = parts[pi];
  676.  
  677.         if(MMS_X_OpenMessage)
  678.             pfp = (*MMS_X_OpenMessage)(
  679.                 MMS_partInheritHeader(mp,H_MESSAGE_ID),pid,pi);
  680.         else    pfp = MMS_partTmpfile(mp);
  681.  
  682.         if( pfp == NULL ){
  683.             if(out != stdin)
  684.                 unlink(path);
  685.             fclose(out);
  686.             out = 0;
  687.             goto exit;
  688.         }
  689.  
  690.         if( pi == 1 ){
  691.             MMS_fseek(pfp,MMS_partHeadOffset(mp),0);
  692.             MMS_filterHead(pfp,out);
  693.         }
  694.         MMS_partWriteBody(pfp,out,mp,0,0);
  695.         if(MMS_X_OpenMessage)
  696.             fclose(pfp);
  697.     }
  698.     fflush(out);
  699.     MMS_fseek(out,0,0);
  700. exit:
  701.     return out;
  702. }
  703.