<?php
/*
sms2csv.php for Treo 650 (php version)
written by Livy - Nobody's Life
Copyright @ 2005 mylivy.net
2005 May 25

Background:
modified code from C++ version by Viacheslav Kaloshin multik@multik.org

Copyright:
You can copy, modify, and distribute the source code.

Comments:
This is not bug free.
for questions, comments, and suggestions, email me at livy@mylivy.net

function:
    extract sms only, with date, name, phone number, message body.
    
Installation guide:
    copy the source code, with no extra space infront of the beginning <?php , and save as a .php file.
    upload to your server

Requirements:
    PHP 4

Functions used:
    dirname
    move_uploaded_file
    header
    filesize
    fopen
    fread
    fclose
    unlink
    highlight_file
    substr
    ord
    str_pad
    dechex
    strtoupper
    localtime
    date
    

*/

$title="SMS2CSV - Nobody's Life";

$mode="\x0"/* R - receive, S - sent */
$phonenumber[256]="\x0";
$name[256]="\x0";
$date[40]="\x0"/*date field */
$textbody[4096]="\x0";

$messagetotal=0;
$outputoptions=Array( "csv" => "CSV File""screen" => "Screen");
$timezones=Array("-12" => "GMT-12:00 (International Date Line West)",
            
"-11" => "GMT-11:00 (Midway Island, Samoa), ",
            
"-10" => "GMT-10:00 (US Hawaiian Time)"
            
"-9" => "GMT-9:00 (US Alaska Time)"
            
"-8" => "GMT-8:00 (US Pacific Time, Los Angeles)"
            
"-7" => "GMT-7:00 (US Mountain Time, Denver)"
            
"-6" => "GMT-6:00 (US Central Time, Chicago)"
            
"-5" => "GMT-5:00 (US Eastern Time, New York)"
            
"-4" => "GMT-4:00 (Atlantic Time, Quebec)"
            
"-3" => "GMT-3:00 (Greenland)"
            
"-2" => "GMT-2:00 (Mid-Atlantic)"
            
"-1" => "GMT-1:00 (Azores, Cape Verdi Is.)"
            
"0" => "GMT (London, Dublin, Edinburgh, Lisbon, Casablanca, Monrovia)"
            
"1" => "GMT+1:00 (Paris, Amsterdam, Berlin, Rome, Vienna, Madrid, Warsaw, Brussels)"
            
"2" => "GMT+2:00 (Israel, Cairo, Athens, Helsinki, Istanbul, Buchrest)"
            
"3" => "GMT+3:00 (Moscow, Kuwait, Baghdad, Tehran, Nairobi)"
            
"4" => "GMT+4:00 (Abu Dhabi, Baku)"
            
"5" => "GMT+5:00 (Islamabad, Ekaterinburg, Karachi, Tashkent)"
            
"5.5" => "GMT+5:30 (Chennai, New Delhi, Mumbai)"
            
"5.75" => "GMT+5:45 (Kathmandu)"
            
"6" => "GMT+6:00 (Almaty, Astana, Dhaka, Novosibirsk)"
            
"7" => "GMT+7:00 (Bankok, Jakarta, Hanoi, Krasnoyarsk)"
            
"8" => "GMT+8:00 (Beijing, Singapore, Taipei, Kuala Lumpur, Irkutsk, Perth)"
            
"9" => "GMT+9:00 (Japan, Korea, Yakutsk)"
            
"9.5" => "GMT+9:30 (Adelaide, Darwin)"
            
"10" => "GMT+10:00 (Brisbane, Sydney, Melbourne, Canberra, Guam, Hobart)"
            
"11" => "GMT+11:00 (Magadan, Solomon Is., New Caledonia)"
            
"12" => "GMT+12:00 (Auckland, Wellington, Fiji)"
        
            
);


?>
<?php
if($_POST['upload']){
    
$pdbDir=dirname($_SERVER["SCRIPT_FILENAME"]);
    
$pdbFile=$pdbDir."/".$HTTP_POST_FILES['smspdb']['name'];
    
$csvFile="message.csv";
    
$GMT=$HTTP_POST_VARS['GMT']*60*60;
    
$opt=$HTTP_POST_VARS['OUTPUT']; //output to screen or csv file?
    
if($HTTP_POST_VARS['NOGMT'])
        
$GMT=0;
        
    
//set cookie for GMT setting
    
setcookie("GMT"$HTTP_POST_VARS['GMT'], time()+2592000);  //remeber GMT setting for 1 month    
    
setcookie("NOGMT"$HTTP_POST_VARS['NOGMT'], time()+2592000);
    
setcookie("OUTPUT"$HTTP_POST_VARS['OUTPUT'], time()+2592000);

    if (
move_uploaded_file($_FILES['smspdb']['tmp_name'], $pdbFile)) {
        if (
file_exists($pdbFile)){
            
//check if Message PDB file exists

            
if($opt=="csv"){
                
header('Content-Description: File Transfer');
                
header('Content-Type: application/octet-stream');
                
header('Content-Disposition: attachment; filename='.basename($csvFile));
            }
            else{
                
//direct print to screen
            
}

            
//read contents
            
$filesize=filesize($pdbFile);
            
$fp=fopen($pdbFile"rb");
            
$buf=fread($fp$filesize);
            
fclose($fp);

            
//delete file from server
            
unlink($pdbFile);

            
//analyse contents
            
analyse($buf);

        }else{
            print 
"No Message file found.";
        }
    } else {
        echo 
"File was not uploaded!\n";
    }
}
elseif(
$HTTP_GET_VARS['source']){
    print 
"<html><head><title>$title</title></head><body>";
    
highlight_file(basename($_SERVER['PHP_SELF']));
    print 
"</body></html>";
}
else{
?>
<html>
<head>
<title><?php echo $title?></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>

<body>
    <p>
        <b>sms2csv.php</b>: convert sms from .pdb to .csv format for Treo 650
    </p>
    
<form enctype="multipart/form-data" method="post" action="<?php echo $_SERVER['PHP_SELF'?>">
  <p>Upload the <b>Messages Database.pdb</b> file from your computer. </p>
  <p>
    File: <input type="hidden" name="MAX_FILE_SIZE" value="3000000" />
    <input name="smspdb" type="file" />
  </p>
  <p>
      Timezone
      <select name="GMT">
        <?php
            
foreach($timezones as $t => $z){
                
$t==$_COOKIE["GMT"]? $select="selected" $select="";                
                print 
"<option $select value=$t>$z</option>\n";
            }
        
?>

    </select>
    
    <input type="checkbox" name="NOGMT" <?php echo $_COOKIE["NOGMT"]? "checked" ""?>>No GMT Offset
    <p>Output to 
        <select name="OUTPUT">
            <?php
                
foreach($outputoptions as $o => $p){
            
?>
                    
                    <option value=<?php echo $o?> <?php echo $o==$_COOKIE["OUTPUT"]? "selected"""?>><?php echo $p?></option>
            <?php
                
}
            
?>    
        </select>
    </p>
    <p>
        <small><b>Disclaimer: Your uploaded .pdb file will be deleted immediately after processing.  The .csv file is not saved on our server.</b></small>
    <p>
    <p>
    <input type="submit" name="upload" value="Submit" />
  </p>
</form>
<p>To download this script? Please
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?source=s">View Source</a>
</p>
<p>
    To fix (some known bugs, a lot more...): 
    <ol>        
        <li>sms sent not properly fetched</li>
        <li>specify messag start/end date</li>
        <li>MMS not extracted</li>
    </ol>
    
</p>

<p>Post your comments <a href="http://mylivy.net/blog/?page_id=31">here</a>. </p>
    <p><hr>Copyright &copy; 2005 <a href="http://mylivy.net">mylivy.net</a>    &nbsp &nbsp
    Last modified on <?php echo date("d.m.Y H:i:s T"filemtime(basename($_SERVER['PHP_SELF']))); ?> </p>
</body>
</html>


<?php
}
?>

<?php
function analyse($buf){
    global 
$filesize$messagetotal;

    
$messageflag=0;
    
$messagestart=0;
    
$messageend=0;

    for(
$i=0;$i<($filesize-6);$i++){
        if(
$buf[$i]=="\x1B" && $buf[$i+1]=="\x54" && $buf[$i+2]=="\x72" && $buf[$i+3]=="\x53" && $buf[$i+4]=="\x4D"){
            
$messageend=$i;
            if(
$messagestart){ /* in additional we need to skip 'garbage' at begin of the file */
                
$tmpmsg=substr($buf$messagestart$messageend-$messagestart);
                
$messagetotal++;
                
processmessage($messagestart,$messageend);
            }
            
$messagestart=$i;
        }
    }
    
processmessage($messageend,$filesize); /* and dont forget the last one */
}

function 
processmessage($begin$end){
    global 
$buf$GMT$messagetotal$opt;

    
$start=$begin;
    
$start=$start+5/* skip TrSM header*/

    //print "process message: begin=$begin, end=$end\n";
    
while($start<$end){ /* message parsing */
        
$bufc=str_pad(dechex(ord($buf[$start])),2,'0'STR_PAD_LEFT);  //convert current buffer to HEX
        
$bufn=str_pad(dechex(ord($buf[$start+1])),2,'0'STR_PAD_LEFT);  //convert next buffer to HEX
        
$type=strtoupper(str_pad($bufc,4,$bufn,STR_PAD_RIGHT)); //now it is 4 bits

        
switch($type){
            case 
"0001"/* unknow */
            
case "0002":
            case 
"000f":
                
$start=$start+2+4;
                break;

            case 
"0003"/* unknow */
                
$start=$start+2+5;
                break;

            case 
"0004"/* unknow */
                
$start=$start+2+8;
                break;

            case 
"0008"/* unknow */
                
$start=$start+2+3;
                break;

            
/* SMS&MMS  */
            
case "8000"/* date/time */
            
case "0007":
            case 
"0006":
                
                
$start=$start+2;
                
$rawtime=(ord($buf[$start])*256+ord($buf[$start+1]))*65536+ord($buf[$start+2])*256+ord($buf[$start+3]);
                
$diff=2082853800+5400-8*60*60//64 years (1970-1904) +1,5 hour 
                
$rawtime=$rawtime-$diff+$GMT;

                
$ti=localtime($rawtime);
                
$date=date("d.m.Y H:i:s"$rawtime);
                
$start=$start+4/* skip date/time record */
                
break;

            case 
"4009":
            case 
"400C":
                
$start=$start+2+20+2/* skip zeros */
                
if($type=="4009"$mode='S'; else $mode='R';
                
$start=getmsg($start,$phonenumber);
                
$start=getmsg($start+1,$name);
                break;

            
/* SMS */
            
case "2002"/* SMS text filed */
                
$start=getmsg($start+2+2,$textbody);
                
$textbody=str_replace("\n"" "$textbody);  //replace new line with a space
                
$textbody=str_replace("\"""\"\" "$textbody); //replace double quote
                
$textbody=str_replace(","". "$textbody);  //replace , with . hehe... not a good idea
                
break;

            default:
                
/* printf("Unknow  %4X at %4X. step one byte\n",type,start);*/
                
$start++;
                break;
        }

    } 
// end while of message parsing

    
if($opt=="csv")
        print 
"$mode, $date, $phonenumber, $name, $textbody\n";
    else
            print 
"<br>$messagetotal, $mode, $date, $phonenumber, $name, $textbody";
    return 
0;
}

function 
getmsg($start, &$msgstr){
    global 
$buf;

    
$b=$start;
    while(
$buf[$b]!="\x0"){
        
$msgstr.=$buf[$b];
        
$b++;
    }
    return 
$b;
}

?>