home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / admin / tnef_decoder.inc < prev    next >
Encoding:
Text File  |  2003-03-23  |  9.0 KB  |  352 lines

  1. <?php
  2. /*
  3.  * tnef_decoder.php
  4.  *  Graham Norbury <gnorbury@bondcar.com>
  5.  *  (c) 2002 (GNU GPL - see ../../COPYING)
  6.  *
  7.  *  Functions for decoding TNEF attachments in native PHP
  8.  *
  9.  *  Adapted from original designs by:
  10.  *    Thomas Boll <tb@boll.ch>             [tnef.c]
  11.  *    Mark Simpson <damned@world.std.com>  [tnef-1.1.1]
  12.  *
  13.  */
  14.  
  15. define("TNEF_SIGNATURE",      0x223e9f78);
  16. define("TNEF_LVL_MESSAGE",    0x01);
  17. define("TNEF_LVL_ATTACHMENT", 0x02);
  18.  
  19. define("TNEF_STRING", 0x00010000);
  20. define("TNEF_TEXT",   0x00020000);
  21. define("TNEF_BYTE",   0x00060000);
  22. define("TNEF_WORD",   0x00070000);
  23. define("TNEF_DWORD",  0x00080000);
  24.  
  25. define("TNEF_ASUBJECT",   TNEF_DWORD  | 0x8004);
  26. define("TNEF_AMCLASS",    TNEF_WORD   | 0x8008);
  27. define("TNEF_BODYTEXT",   TNEF_TEXT   | 0x800c);
  28. define("TNEF_ATTACHDATA", TNEF_BYTE   | 0x800f);
  29. define("TNEF_AFILENAME",  TNEF_STRING | 0x8010);
  30. define("TNEF_ARENDDATA",  TNEF_BYTE   | 0x9002);
  31. define("TNEF_AMAPIATTRS", TNEF_BYTE   | 0x9005);
  32. define("TNEF_AVERSION",   TNEF_DWORD  | 0x9006);
  33.  
  34. define("TNEF_MAPI_NULL",           0x0001);
  35. define("TNEF_MAPI_SHORT",          0x0002);
  36. define("TNEF_MAPI_INT",            0x0003);
  37. define("TNEF_MAPI_FLOAT",          0x0004);
  38. define("TNEF_MAPI_DOUBLE",         0x0005);
  39. define("TNEF_MAPI_CURRENCY",       0x0006);
  40. define("TNEF_MAPI_APPTIME",        0x0007);
  41. define("TNEF_MAPI_ERROR",          0x000a);
  42. define("TNEF_MAPI_BOOLEAN",        0x000b);
  43. define("TNEF_MAPI_OBJECT",         0x000d);
  44. define("TNEF_MAPI_INT8BYTE",       0x0014);
  45. define("TNEF_MAPI_STRING",         0x001e);
  46. define("TNEF_MAPI_UNICODE_STRING", 0x001f);
  47. define("TNEF_MAPI_SYSTIME",        0x0040);
  48. define("TNEF_MAPI_CLSID",          0x0048);
  49. define("TNEF_MAPI_BINARY",         0x0102);
  50.  
  51. define("TNEF_MAPI_ATTACH_MIME_TAG",      0x370E);
  52. define("TNEF_MAPI_ATTACH_LONG_FILENAME", 0x3707);
  53. define("TNEF_MAPI_ATTACH_DATA",          0x3701);
  54.  
  55. function tnef_getx($size, &$buf)
  56. {
  57.    $value = null;
  58.    if (strlen($buf) >= $size)
  59.    {
  60.       $value = substr($buf, 0, $size);
  61.       $buf = substr_replace($buf, '', 0, $size);
  62.    }
  63.    return $value;
  64. }
  65.  
  66. function tnef_geti8(&$buf)
  67. {
  68.    $value = null;
  69.    if (strlen($buf) >= 1)
  70.    {
  71.       $value = ord($buf{0});
  72.       $buf = substr_replace($buf, '', 0, 1);
  73.    }
  74.    return $value;
  75. }
  76.  
  77. function tnef_geti16(&$buf)
  78. {
  79.    $value = null;
  80.    if (strlen($buf) >= 2)
  81.    {
  82.       $value = ord($buf{0}) +
  83.                (ord($buf{1}) << 8);
  84.       $buf = substr_replace($buf, '', 0, 2);
  85.    }
  86.    return $value;
  87. }
  88.  
  89. function tnef_geti32(&$buf)
  90. {
  91.    $value = null;
  92.    if (strlen($buf) >= 4)
  93.    {
  94.       $value = ord($buf{0}) +
  95.                (ord($buf{1}) << 8) +
  96.                (ord($buf{2}) << 16) +
  97.                (ord($buf{3}) << 24);
  98.       $buf = substr_replace($buf, '', 0, 4);
  99.    }
  100.    return $value;
  101. }
  102.  
  103. function tnef_decode_attribute($attribute, &$buf)
  104. {
  105.    global $debug, $download;
  106.  
  107.    $length = tnef_geti32($buf);
  108.    $value = tnef_getx($length, $buf); //data
  109.    tnef_geti16($buf); //checksum
  110.  
  111.    if ($debug)
  112.    {
  113.       printf("ATTRIBUTE[%08x] %d bytes\n", $attribute, $length);
  114.    }
  115.  
  116.    switch($attribute)
  117.    {
  118.       case TNEF_BODYTEXT:
  119.          if (!$download)
  120.          {
  121.             printf("<b>Embedded message:</b><pre>%s</pre>",$value);
  122.          }
  123.          break;
  124.  
  125.       default:
  126.    }
  127. }
  128.  
  129. function extract_mapi_attrs($buf, &$attachment_data)
  130. {
  131.    global $debug;
  132.  
  133.    tnef_geti32($buf); // number of attributes
  134.    while(strlen($buf) > 0)
  135.    {
  136.       $value = null;
  137.       $length = 0;
  138.       $attr_type = tnef_geti16($buf);
  139.       $attr_name = tnef_geti16($buf);
  140.       if ($debug)
  141.       {
  142.          printf("mapi attribute: %04x:%04x\n", $attr_type, $attr_name);
  143.       }
  144.       switch($attr_type)
  145.       {
  146.          case TNEF_MAPI_SHORT:
  147.             $value = tnef_geti16($buf);
  148.             break;
  149.  
  150.          case TNEF_MAPI_INT:
  151.          case TNEF_MAPI_BOOLEAN:
  152.             $value = tnef_geti32($buf);
  153.             break;
  154.  
  155.          case TNEF_MAPI_FLOAT:
  156.             $value = tnef_getx(4, $buf);
  157.             break;
  158.  
  159.          case TNEF_MAPI_DOUBLE:
  160.          case TNEF_MAPI_SYSTIME:
  161.             $value = tnef_getx(8, $buf);
  162.             break;
  163.  
  164.          case TNEF_MAPI_STRING:
  165.          case TNEF_MAPI_UNICODE_STRING:
  166.          case TNEF_MAPI_BINARY:
  167.          case TNEF_MAPI_OBJECT:
  168.             $num_vals = tnef_geti32($buf);
  169.             for ($i = 0; $i < $num_vals; $i++) // usually just 1
  170.             {
  171.                $length = tnef_geti32($buf);
  172.                $buflen = $length + ((4 - ($length % 4)) % 4); // pad to next 4 byte boundary
  173.                $value = substr(tnef_getx($buflen, $buf), 0, $length); // read and truncate to length
  174.             }
  175.             break;
  176.  
  177.          default:
  178.             if ($debug)
  179.             {
  180.                echo("Unknown mapi attribute!\n");
  181.             }
  182.       }
  183.  
  184.       // store any interesting attributes
  185.       switch($attr_name)
  186.       {
  187.          case TNEF_MAPI_ATTACH_LONG_FILENAME: // used in preference to AFILENAME value
  188.             $attachment_data[0]['name'] = ereg_replace('.*[\/](.*)$', '\1', $value); // strip path
  189.             break;
  190.  
  191.          case TNEF_MAPI_ATTACH_MIME_TAG: // Is this ever set, and what is format?
  192.             $attachment_data[0]['type0'] = ereg_replace('^(.*)/.*', '\1', $value);
  193.             $attachment_data[0]['type1'] = ereg_replace('.*/(.*)$', '\1', $value);
  194.             break;
  195.  
  196.          case TNEF_MAPI_ATTACH_DATA:
  197.             tnef_getx(16, $value); // skip the next 16 bytes (unknown data)
  198.             array_shift($attachment_data); // eliminate the current (bogus) attachment
  199.             do_tnef_decode($value, $attachment_data); // recursively process the attached message
  200.             break;
  201.  
  202.          default:
  203.       }
  204.    }
  205. }
  206.  
  207. function tnef_decode_message(&$buf)
  208. {
  209.    global $debug;
  210.  
  211.    if ($debug)
  212.    {
  213.       echo("MESSAGE ");
  214.    }
  215.  
  216.    $attribute = tnef_geti32($buf);
  217.    tnef_decode_attribute($attribute, $buf);
  218. }
  219.  
  220. function tnef_decode_attachment(&$buf, &$attachment_data)
  221. {
  222.    global $debug;
  223.  
  224.    if ($debug)
  225.    {
  226.       echo("ATTACHMENT ");
  227.    }
  228.  
  229.    $attribute = tnef_geti32($buf);
  230.    switch($attribute)
  231.    {    
  232.       case TNEF_ARENDDATA: // marks start of new attachment
  233.          $length = tnef_geti32($buf);
  234.          tnef_getx($length, $buf);
  235.          tnef_geti16($buf); //checksum
  236.          if ($debug)
  237.          {
  238.             printf("ARENDDATA[%08x]: %d bytes\n", $attribute, $length);
  239.          }
  240.          // add a new default data block to hold details of this attachment
  241.          // reverse order is easier to handle later!
  242.          array_unshift($attachment_data, array('type0'  => 'application',
  243.                                                'type1'  => 'octet-stream',
  244.                                                'name'   => 'unknown',
  245.                                                'stream' => ''));
  246.          break;
  247.  
  248.       case TNEF_AFILENAME: // filename
  249.          $length = tnef_geti32($buf);
  250.          $attachment_data[0]['name'] = ereg_replace('.*[\/](.*)$',
  251.                                                     '\1',
  252.                                                     tnef_getx($length, $buf)); // strip path
  253.          tnef_geti16($buf); //checksum
  254.          if ($debug)
  255.          {
  256.             printf("AFILENAME[%08x]: %s\n", $attribute, $attachment_data[0]['name']);
  257.          }
  258.          break;
  259.  
  260.       case TNEF_ATTACHDATA: // the attachment itself
  261.          $length = tnef_geti32($buf);
  262.          $attachment_data[0]['size'] = $length;
  263.          $attachment_data[0]['stream'] = tnef_getx($length, $buf);
  264.          tnef_geti16($buf); //checksum
  265.          if ($debug)
  266.          {
  267.             printf("ATTACHDATA[%08x]: %d bytes\n", $attribute, $length);
  268.          }
  269.          break;
  270.  
  271.       case TNEF_AMAPIATTRS:
  272.          $length = tnef_geti32($buf);
  273.          $value = tnef_getx($length, $buf);
  274.          tnef_geti16($buf); //checksum
  275.          if ($debug)
  276.          {
  277.             printf("AMAPIATTRS[%08x]: %d bytes\n", $attribute, $length);
  278.          }
  279.          extract_mapi_attrs($value, $attachment_data);
  280.          break;
  281.  
  282.       default:
  283.          tnef_decode_attribute($attribute, $buf);
  284.    }
  285. }
  286.  
  287. function do_tnef_decode(&$buf, &$attachment_data)
  288. {
  289.    global $debug;
  290.  
  291.    $tnef_signature = tnef_geti32($buf);
  292.    if ($tnef_signature == TNEF_SIGNATURE)
  293.    {
  294.       $tnef_key = tnef_geti16($buf);
  295.       if ($debug)
  296.       {
  297.          printf("Signature: 0x%08x\nKey: 0x%04x\n", $tnef_signature, $tnef_key);
  298.       }
  299.  
  300.       while (strlen($buf) > 0)
  301.       {
  302.          $lvl_type = tnef_geti8($buf);
  303.          switch($lvl_type)
  304.          {
  305.             case TNEF_LVL_MESSAGE:
  306.                tnef_decode_message($buf);
  307.                break;
  308.  
  309.             case TNEF_LVL_ATTACHMENT:
  310.                tnef_decode_attachment($buf, $attachment_data);
  311.                break;
  312.  
  313.             default:
  314.                if ($debug)
  315.                {
  316.                   echo("Invalid file format!");
  317.                }
  318.                break 2;
  319.          }
  320.       }
  321.    }
  322.    else
  323.    {
  324.       if ($debug)
  325.       {
  326.          echo("Invalid file format!");
  327.       }
  328.    }
  329. }
  330.  
  331. function tnef_decode($buf)
  332. {
  333.    global $debug;
  334.  
  335.    $attachment_data = array();
  336.  
  337.    if ($debug)
  338.    {
  339.       echo("<pre>");
  340.    }
  341.  
  342.    do_tnef_decode($buf, $attachment_data);
  343.  
  344.    if ($debug)
  345.    {
  346.       echo("</pre>");
  347.    }
  348.    return array_reverse($attachment_data);
  349.  
  350. }
  351.  
  352. ?>