home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / ftp.vapor.com / microdot-1 / md1_src_02.lzx / mail.c < prev    next >
C/C++ Source or Header  |  2014-05-19  |  15KB  |  725 lines

  1. /* MicroDot-MsgBase-System */
  2.  
  3. #define RBSIZE MAILBFSIZE
  4.  
  5. #include "microdot.h"
  6. #include "asyncio.h"
  7.  
  8. struct ixcache
  9. {
  10.     struct MinNode    n;
  11.     ULONG             puffID;
  12.     BPTR              ixfile;
  13.     struct AsyncFile *datafile;
  14. };
  15.  
  16. static struct MinList ixlist;
  17. static void *ixcachepool; 
  18.  
  19. void ixc_flush( void )
  20. {
  21.     struct ixcache *ixc;
  22.  
  23.     while( ( ixc = ( struct ixcache * ) RemHead( ( struct List * ) &ixlist ) ) )
  24.     {
  25.         if( ixc->ixfile )
  26.             Close( ixc->ixfile );
  27.         if( ixc->datafile )
  28.             CloseAsync( ixc->datafile );
  29.         LibFreePooled( ixcachepool, ixc, sizeof( *ixc ) );
  30.     }
  31. }
  32.  
  33. void ixc_init( void )
  34. {
  35.     ixcachepool = LibCreatePool( MEMF_CLEAR, sizeof( struct ixcache ) * 10, sizeof( struct ixcache ) * 5 );
  36.     NewList( ( struct List * ) &ixlist );
  37. }
  38.  
  39. void ixc_exit( void )
  40. {
  41.     ixc_flush();
  42.     LibDeletePool( ixcachepool );
  43. }
  44.  
  45. static struct ixcache *getixc( ULONG pID )
  46. {
  47.     struct ixcache *ixc = ( struct ixcache * ) ixlist.mlh_Head;
  48.  
  49. //    Printf( "getixc %ld\n", pID );
  50.  
  51.     while( ixc->n.mln_Succ )
  52.     {
  53.         if( ixc->puffID == pID )
  54.         {
  55. //            Printf("getixc: found\n" );
  56.             return( ixc );
  57.         }
  58.         ixc = ( struct ixcache * ) ixc->n.mln_Succ;
  59.     }
  60.  
  61. //    Printf("getixc: numentries %ld\n",GetNumEntries( ( struct List * ) &ixlist ) );
  62.  
  63.     if( GetNumEntries( ( struct List * ) &ixlist ) > 10 || AvailMem( MEMF_LARGEST | MEMF_FAST ) < (256*1024) )
  64.         ixc_flush();
  65.  
  66.     ixc = LibAllocPooled( ixcachepool, sizeof( *ixc ) );
  67.     ixc->puffID = pID;
  68.     AddTail( ( struct List * ) &ixlist, ( struct Node * ) ixc );
  69.     return( ixc );
  70. }
  71.  
  72. static BPTR ixc_getix( ULONG pID )
  73. {
  74.     struct ixcache *ixc = getixc( pID );
  75.     char buf[á128 ];
  76.  
  77.     if( !ixc->ixfile )
  78.     {
  79.         sprintf( buf, "%sMD_%lx.Index", prefs.datadir, pID );
  80.         ixc->ixfile = Open( buf, MODE_OLDFILE );
  81.     }
  82.     return( ixc->ixfile );
  83. }
  84.  
  85. static struct AsyncFile *ixc_getdata( ULONG pID )
  86. {
  87.     struct ixcache *ixc = getixc( pID );
  88.     char buf[á128 ];
  89.  
  90.     if( !ixc->datafile )
  91.     {
  92.         sprintf( buf, "%sMD_%lx.Data", prefs.datadir, pID );
  93.         ixc->datafile = OpenAsync( buf, MODE_READ, 8192 );
  94.     }
  95.     return( ixc->datafile );
  96. }
  97.  
  98. struct msghandle *msg_open( ULONG pufID, ULONG mID )
  99. {
  100.     BPTR ixfile;
  101.     struct msghandle *new;
  102.     char buf[á256 ];
  103.     int rc;
  104.  
  105.     ixfile = ixc_getix( pufID );
  106.     if( !ixfile )
  107.     {
  108.         sprintf( buf, "%sMD_%lx.Data", prefs.datadir, pufID );
  109.         askreq( "Fehler beim Datenbankzugriff auf Nachricht %ld:%ld\nDatei %s lΣ▀t sich nicht ÷ffnen!", "Abbruch",
  110.             pufID, mID, buf
  111.         );
  112.         return( NULL );
  113.     }
  114.  
  115.     rc = Seek( ixfile, mID * sizeof( struct pindex ), OFFSET_BEGINNING );
  116.  
  117.     if( rc < 0 )
  118.     {
  119.         askreq( "Fehler (%ld) beim Datenbankzugriff auf Nachricht %ld:%ld\nIndexeintrag fehlend oder fehlerhaft.", "Abbruch",
  120.             IoErr(), pufID, mID
  121.         );
  122.         return( NULL );
  123.     }
  124.  
  125.     new = LibAllocPooled( miscmempool, sizeof( *new ) );
  126.     if( !new )
  127.     {
  128.         return( NULL );
  129.     }
  130.  
  131.     Read( ixfile, &new->pix, sizeof( struct pindex ) );
  132.  
  133.     new->file = ixc_getdata( pufID );
  134.  
  135. //    Printf( "pix.offset %ld, realoffset %ld\n", new->pix.offset, FtellAsync( new->file ) );
  136.  
  137.     if( !new->file )
  138.     {
  139.         askreq( "Fehler beim Datenbankzugriff auf Nachricht %ld:%ld\nDatei %s lΣ▀t sich nicht ÷ffnen!", "Abbruch",
  140.             pufID, mID, buf
  141.         );
  142.         return( NULL );
  143.     }
  144.  
  145.     return( new );
  146.  
  147. }
  148.  
  149. void msg_close( struct msghandle *msg )
  150. {
  151.     if( msg )
  152.     {
  153.         LibFreePooled( miscmempool, msg, sizeof( *msg ) );
  154.         /*if( msg->file )
  155.             CloseAsync( msg->file );*/
  156.     }
  157. }
  158.  
  159. static int copyfh( struct AsyncFile *from, BPTR to, int bytes, int packed )
  160. {
  161.     void *bufmem;
  162.     int rc;
  163.     struct pfhandle *pfh;
  164.     int bs;
  165.  
  166.     if( bytes < 1 )
  167.         return( 0 );
  168.  
  169.     pfh = pf_open( from, FALSE, packed, &bytes );
  170.  
  171.     bufmem = allocbuffmem( bytes, &bs );
  172.  
  173.     while( bytes )
  174.     {
  175.         rc = pf_read( pfh, bufmem, min( bs, bytes ) );
  176.         if( rc )
  177.             Write( to, bufmem, rc );
  178.         bytes -= rc;
  179.     }
  180.  
  181.     pf_close( pfh );
  182.  
  183.     freebuffmem();
  184.  
  185.     return( 0 );
  186. }
  187.  
  188. int copyfh2p( struct AsyncFile *from, FILE *to, int bytes, int packed )
  189. {
  190.     void *bufmem;
  191.     int rc;
  192.     struct pfhandle *pfh;
  193.     int bs;
  194.  
  195.     if( bytes < 1 )
  196.         return( 0 );
  197.  
  198.     pfh = pf_open( from, FALSE, packed, &bytes );
  199.  
  200.     bufmem = allocbuffmem( bytes, &bs );
  201.  
  202.     while( bytes )
  203.     {
  204.         rc = pf_read( pfh, bufmem, min( bs, bytes ) );
  205.         if( rc )
  206.             fwrite( bufmem, rc, 1, to );
  207.         bytes -= rc;
  208.     }
  209.  
  210.     pf_close( pfh );
  211.  
  212.     freebuffmem();
  213.  
  214.     return( 0 );
  215. }
  216.  
  217.  
  218. /* Nachricht rauskopieren */
  219. int msg_copyfh( struct msghandle *msg, BPTR tofile, ULONG flags )
  220. {
  221.     if( !msg || !msg->file )
  222.         return( -1 );
  223.  
  224.     if( flags & MC_HEADER )
  225.     {
  226.         SeekAsync( msg->file, msg->pix.offset, OFFSET_BEGINNING );
  227.         copyfh( msg->file, tofile, msg->pix.headersize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  228.     }
  229.  
  230.     if( msg->pix.commentsize )
  231.     {
  232.         if( flags & MC_COMMENT )
  233.         {
  234.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize, OFFSET_BEGINNING );
  235.             copyfh( msg->file, tofile, msg->pix.commentsize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  236.         }
  237.     }
  238.  
  239.     if( msg->pix.datasize )
  240.     {
  241.         if( flags & MC_DATA )
  242.         {
  243.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize + msg->pix.commentsize, OFFSET_BEGINNING );
  244.             copyfh( msg->file, tofile, msg->pix.datasize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  245.         }
  246.     }
  247.  
  248.     return( 0 );
  249. }
  250.  
  251. int msg_copyfp( struct msghandle *msg, FILE *tofile, ULONG flags )
  252. {
  253.     if( !msg || !msg->file )
  254.         return( -1 );
  255.  
  256.     if( flags & MC_HEADER )
  257.     {
  258.         SeekAsync( msg->file, msg->pix.offset, OFFSET_BEGINNING );
  259.         copyfh2p( msg->file, tofile, msg->pix.headersize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  260.     }
  261.  
  262.     if( msg->pix.commentsize )
  263.     {
  264.         if( flags & MC_COMMENT )
  265.         {
  266.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize, OFFSET_BEGINNING );
  267.             copyfh2p( msg->file, tofile, msg->pix.commentsize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  268.         }
  269.     }
  270.  
  271.     if( msg->pix.datasize )
  272.     {
  273.         if( flags & MC_DATA )
  274.         {
  275.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize + msg->pix.commentsize, OFFSET_BEGINNING );
  276.             copyfh2p( msg->file, tofile, msg->pix.datasize, msg->pix.flags & ( PIF_PACKED | PIF_XPK ) );
  277.         }
  278.     }
  279.  
  280.     return( 0 );
  281. }
  282.  
  283. int msg_copy( struct msghandle *msg, char *to, ULONG flags )
  284. {
  285.     BPTR tofile;
  286.     int rc;
  287.  
  288.     tofile = Open( to, MODE_NEWFILE );
  289.     if( !tofile )
  290.         return( -1 );
  291.     rc = msg_copyfh( msg, tofile, flags );
  292.     Close( tofile );
  293.     return( rc );
  294.  
  295. }
  296.  
  297.  
  298. /* Header einer Nachricht laden */
  299. struct hlist *msg_loadheader( struct msghandle *msg )
  300. {
  301.     char *buffer, *bp;
  302.     struct hlist *hlist;
  303.     struct pfhandle *pfh;
  304.     int len = msg->pix.headersize;
  305.     char *p, *p2;
  306.  
  307.     if( SeekAsync( msg->file, msg->pix.offset, MODE_START ) < 0 )
  308.     {
  309.         return( NULL );
  310.     }
  311.     pfh = pf_open( msg->file, FALSE, msg->pix.flags & ( PIF_PACKED | PIF_XPK ), &len );
  312.  
  313.     bp = buffer = myAllocVec( len + 1, MEMF_CLEAR );
  314.     if( !buffer )
  315.     {
  316.         pf_close( pfh );
  317.         return( NULL );
  318.     }
  319.  
  320.     pf_read( pfh, buffer, len );
  321.     pf_close( pfh );
  322.  
  323.     hlist = hl_initheader();
  324.  
  325.     while( ( p = strchr( buffer, '\n'á) ) )
  326.     {
  327.         *p++ = 0;
  328.         p2 = strchr( buffer, ':' );
  329.         if( !p2 )
  330.             break;
  331.         else
  332.             *p2++ = 0;
  333.         hl_addheader( hlist, buffer, stpblk( p2 ) );
  334.         buffer = p;
  335.     }
  336.  
  337.     myFreeVec( bp );
  338.  
  339.     return( hlist );
  340.  
  341. }
  342.  
  343. int msg_initread( struct msghandle *msg, int readwhat )
  344. {
  345.     switch( readwhat )
  346.     {
  347.         case MC_HEADER:
  348.             msg->readmode = 1;
  349.             msg->readremain = msg->pix.headersize;
  350.             if( !msg->readremain )
  351.                 return( 0 );
  352.             SeekAsync( msg->file, msg->pix.offset, MODE_START );
  353.             break;
  354.  
  355.         case MC_COMMENT:
  356.             msg->readmode = 1;
  357.             msg->readremain = msg->pix.commentsize;
  358.             if( !msg->readremain )
  359.                 return( 0 );
  360.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize, MODE_START );
  361.             break;
  362.  
  363.         case MC_DATA:
  364.             msg->readmode = 1;
  365.             msg->readremain = msg->pix.datasize;
  366.             if( !msg->readremain )
  367.                 return( 0 );
  368.             SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize + msg->pix.commentsize, MODE_START );
  369.             break;
  370.  
  371.         default:    /* tja... */
  372.             return( -1 );
  373.     }
  374.  
  375.     msg->pfh = pf_open( msg->file, FALSE, msg->pix.flags & ( PIF_PACKED | PIF_XPK ), ( int * ) &msg->readremain );
  376.     return( 0 );
  377. }
  378.  
  379. void msg_endread( struct msghandle *msg )
  380. {
  381.     msg->readmode = msg->readremain = 0;
  382.  
  383.     if( msg->pfh )
  384.     {
  385.         pf_close( msg->pfh );
  386.         msg->pfh = NULL;
  387.     }
  388. }
  389.  
  390.  
  391. /* Nachricht zeilenweise lesen; null bei ende/fehler */
  392. int msg_read( struct msghandle *msg, UBYTE *buffer, int size )
  393. {
  394.     int count = 0;
  395.     int ch;
  396.  
  397.     if( !msg->readmode || !msg->readremain )
  398.         return( 0 );
  399.  
  400.     while( size-- )
  401.     {
  402.         ch = pf_readch( msg->pfh );
  403.         if( ch < 0 )
  404.             break;
  405.         if( ch == 13 )
  406.             continue;
  407.         if( ch == 10  )
  408.             break;
  409.         buffer[ácount++ ]á= ch;
  410.     }
  411.     buffer[ count ] = 0;
  412.  
  413.     return( ( ch == 10 ) ? 1 : ( count ? 2 : 0 ) );
  414. }
  415.  
  416. /* Nummer des Userpuffers zurⁿckgeben */
  417.  
  418. static ULONG getmypuffer( void )
  419. {
  420.     ULONG c = ~0;
  421.     char buff[á64 ];
  422.     int pl;
  423.  
  424.     pushdir( prefs.datadir );
  425.  
  426.     while( c )
  427.     {
  428.         sprintf( buff, "MD_%lx.Data", c );
  429.         pl = getfilelen( buff );
  430.         if( pl < 256000 )
  431.             break;
  432.         c--;
  433.     }
  434.     popdir();
  435.     return( c );
  436. }
  437.  
  438. static int copypack( BPTR fromfile, struct AsyncFile *tofile, int size )
  439. {
  440.     struct pfhandle *pfh = pf_open( tofile, TRUE, prefs.do_packmsg, 0 );
  441.     char buffer[á2048 ];
  442.     int rc;
  443.  
  444.     while( size )
  445.     {
  446.         rc = Read( fromfile, buffer, min( size, 2048 ) );
  447.         if( rc )
  448.             pf_write( pfh, buffer, rc );
  449.         size -= rc;
  450.     }
  451.     return( pf_close( pfh ) );
  452. }
  453.  
  454. static int copymempack( struct AsyncFile *tofile, UBYTE *data, int size )
  455. {
  456.     struct pfhandle *pfh = pf_open( tofile, TRUE, prefs.do_packmsg, 0 );
  457.  
  458.     pf_write( pfh, data, size );
  459.     return( pf_close( pfh ) );
  460. }
  461.  
  462.  
  463. ULONG msg_getsize( struct msghandle *msg, int what )
  464. {
  465.     ULONG size = 0;
  466.  
  467.     if( ! ( msg->pix.flags & ( PIF_PACKED ) ) )
  468.     {
  469.         switch( what )
  470.         {
  471.             case MC_HEADER:
  472.                 return( msg->pix.headersize );
  473.  
  474.             case MC_COMMENT:
  475.                 return( msg->pix.commentsize );
  476.  
  477.             case MC_DATA:
  478.                 return( msg->pix.datasize );
  479.  
  480.         }
  481.     }
  482.     else switch( what )
  483.     {
  484.         case MC_HEADER:
  485.             if( msg->pix.headersize )
  486.             {
  487.                 SeekAsync( msg->file, msg->pix.offset, MODE_START );
  488.                 ReadAsync( msg->file, &size, 4 );
  489.             }
  490.             break;
  491.  
  492.         case MC_COMMENT:
  493.             if( msg->pix.commentsize )
  494.             {
  495.                 SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize, MODE_START );
  496.                 ReadAsync( msg->file, &size, 4 );
  497.             }
  498.             break;
  499.  
  500.         case MC_DATA:
  501.             if( msg->pix.datasize )
  502.             {
  503.                 SeekAsync( msg->file, msg->pix.offset + msg->pix.headersize + msg->pix.commentsize, MODE_START );
  504.                 ReadAsync( msg->file, &size, 4 );
  505.             }
  506.             break;
  507.  
  508.     }
  509.  
  510.     return( size );
  511. }
  512.  
  513.  
  514. /* Nachricht speichern; header in header... */
  515.  
  516. struct pindex *msg_store( char *comment, LONG commentsize,
  517.                              char *data, LONG datasize,
  518.                           ULONG *pID, ULONG *mID, struct hlist *hlist )
  519. {
  520.     BPTR commentfile = NULL, datafile = NULL;
  521.     BPTR ixfile;
  522.     struct AsyncFile *outfile;
  523.     static struct pindex pix;
  524.     ULONG p;
  525.     int c;
  526.     char buff[á128 ];
  527.  
  528.     ixc_flush();
  529.  
  530.     memset( &pix, 0, sizeof( pix ) );
  531.  
  532.     if( prefs.do_packmsg )
  533.         pix.flags |= PIF_PACKED;
  534.  
  535.     if( prefs.do_packmsg >= PACKMODE_XPK )
  536.         pix.flags |= PIF_XPK;
  537.  
  538.     /* Comment ist Datei */
  539.     if( commentsize < 0 )
  540.     {
  541.         commentsize = getfilelen( comment );
  542.         commentfile = Open( comment, MODE_OLDFILE );
  543.         if( !commentfile )
  544.         {
  545.             if( commentsize > 0 )
  546.                 return( NULL );
  547.             commentsize = 0;
  548.         }
  549.     }
  550.  
  551.     /* Data ist Datei */
  552.     if( datasize < 0 )
  553.     {
  554.         datasize = getfilelen( data );
  555.         datafile = Open( data, MODE_OLDFILE );
  556.         if( !datafile )
  557.         {
  558.             if( datasize > 0 )
  559.                 return( NULL );
  560.             datasize = 0;
  561.         }
  562.     }
  563.  
  564.     /* Gut... */
  565.     p = getmypuffer();
  566.     sprintf( buff, "%sMD_%lx.Data", prefs.datadir, p );
  567.     c = getfilelen( buff );
  568.     if( c < 0 )
  569.         c = 0;
  570.     outfile = OpenAsync( buff, MODE_APPEND, 32768 );
  571.     if( !outfile )
  572.         return( NULL );
  573. //    WriteAsync( outfile, "Test0\n", 6 );
  574.     *pID = p;
  575.     pix.offset = c;
  576.     pix.headersize = hl_dumpheaderpf( hlist, outfile );
  577.  
  578. //    WriteAsync( outfile, "Test1\n", 6 );
  579.  
  580.     if( commentsize )
  581.     {
  582.         if( commentfile )
  583.             pix.commentsize = copypack( commentfile, outfile, commentsize );
  584.         else
  585.             pix.commentsize = copymempack( outfile, comment, commentsize );
  586.     }
  587.  
  588. //    WriteAsync( outfile, "Test2\n", 6 );
  589.  
  590.     if( datasize )
  591.     {
  592.         if( datafile )
  593.             pix.datasize = copypack( datafile, outfile, datasize );
  594.         else
  595.             pix.datasize = copymempack( outfile, data, datasize );
  596.     }
  597. //    WriteAsync( outfile, "Test3\n", 6 );
  598.  
  599.     CloseAsync( outfile );
  600.     if( datafile )
  601.         Close( datafile );
  602.     if( commentfile )
  603.         Close( commentfile );
  604.  
  605.     /* Index schreiben */
  606.     sprintf( buff, "%sMD_%lx.Index", prefs.datadir, p );
  607.     ixfile = OpenAppend( buff );
  608.     if( !ixfile )
  609.         return( NULL );
  610.     *mID = Seek( ixfile, 0, OFFSET_CURRENT ) / sizeof( pix );
  611.     Write( ixfile, &pix, sizeof( pix ) );
  612.     Close( ixfile );
  613.  
  614.     /* Alles k.o. */
  615.     return( &pix );
  616.  
  617. }
  618.  
  619. /* Nachricht ersetzen (!) */
  620.  
  621. struct pindex *msg_replace( char *comment, LONG commentsize,
  622.                              char *data, LONG datasize,
  623.                           ULONG pID, ULONG mID, struct hlist *hlist )
  624. {
  625.     BPTR commentfile = NULL, datafile = NULL;
  626.     BPTR ixfile;
  627.     struct AsyncFile *outfile;
  628.     static struct pindex pix;
  629.     char buff[á128 ];
  630.  
  631.     ixc_flush();
  632.  
  633.     memset( &pix, 0, sizeof( pix ) );
  634.  
  635.     if( prefs.do_packmsg )
  636.         pix.flags |= PIF_PACKED;
  637.  
  638.     if( prefs.do_packmsg >= PACKMODE_XPK )
  639.         pix.flags |= PIF_XPK;
  640.  
  641.     /* Comment ist Datei */
  642.     if( commentsize < 0 )
  643.     {
  644.         commentsize = getfilelen( comment );
  645.         commentfile = Open( comment, MODE_OLDFILE );
  646.         if( !commentfile )
  647.         {
  648.             if( commentsize > 0 )
  649.                 return( NULL );
  650.             commentsize = 0;
  651.         }
  652.     }
  653.  
  654.     /* Data ist Datei */
  655.     if( datasize < 0 )
  656.     {
  657.         datasize = getfilelen( data );
  658.         datafile = Open( data, MODE_OLDFILE );
  659.         if( !datafile )
  660.         {
  661.             if( datasize > 0 )
  662.                 return( NULL );
  663.             datasize = 0;
  664.         }
  665.     }
  666.  
  667.     /* Gut... */
  668.     sprintf( buff, "%sMD_%lx.Data", prefs.datadir, pID );
  669.     outfile = OpenAsync( buff, MODE_APPEND, 32768 );
  670.     if( !outfile )
  671.         return( NULL );
  672.     pix.offset = FtellAsync( outfile );
  673.     pix.headersize = hl_dumpheaderpf( hlist, outfile );
  674.  
  675.     if( commentsize )
  676.     {
  677.         if( commentfile )
  678.             pix.commentsize = copypack( commentfile, outfile, commentsize );
  679.         else
  680.             pix.commentsize = copymempack( outfile, comment, commentsize );
  681.     }
  682.  
  683.     if( datasize )
  684.     {
  685.         if( datafile )
  686.             pix.datasize = copypack( datafile, outfile, datasize );
  687.         else
  688.             pix.datasize = copymempack( outfile, data, datasize );
  689.     }
  690.  
  691.     CloseAsync( outfile );
  692.     if( datafile )
  693.         Close( datafile );
  694.     if( commentfile )
  695.         Close( commentfile );
  696.  
  697.     /* Index schreiben */
  698.     sprintf( buff, "%sMD_%lx.Index", prefs.datadir, pID );
  699.     ixfile = OpenAppend( buff );
  700.     if( !outfile )
  701.         return( NULL );
  702.     Seek( ixfile, sizeof( pix ) * mID, OFFSET_BEGINNING );
  703.     Write( ixfile, &pix, sizeof( pix ) );
  704.     Close( ixfile );
  705.  
  706.     /* Alles k.o. */
  707.     return( &pix );
  708.  
  709. }
  710.  
  711.  
  712. /*
  713.  
  714.   Format gecrunchter Daten: 
  715.  
  716.   ULONG decrunchlen        Entpackte LΣnge des gesammten Parts
  717.  
  718.   dann ein oder mehrere
  719.  
  720.   UWORD chunksize       Gepackte Gr÷▀e dieses Chunks; 0 = Ende
  721.   UWORD chunkreal       Entpackte Gr÷▀e dieses Chunks; 0 = ungepackt
  722.   UBYTE data[ xxx ]     Gepackte Daten
  723.  
  724. */
  725.