<?
// fincheck.php
// 
// Functions to access finarea websites functionality.
// Inspired by the fincheck shell script. http://www.voip-info.org/wiki/view/Finarea+SA 
// or http://www.simong.net/finarea/
//
// Simon G <junk@simong.net>
//

$sVersion "20091115";

// November 15th 2009
// More problem with BASEURL
// It appears that a new URL is now used for call setup.
// phone-to-phone.php

// November 11th 2009
// Fixed a change done where all betamax use the /myaccount/ URL 
//    instead of the old /clx/ URL

// August 31st 2008
// Fixed a bug with creditcents for balances over €1000.

// June 22nd 2008. (Uwe Gellhaus)
// New .com clone (intervoip) , but different url base.

// Version: 1.2
// Dated: 2007 July 18th.
// Just a warning that text send here should be utf-8 encoded. 
// I've adjusted the example to help things there.

//
// Added CallForwarding feature.

// Added Credit check and freeminutes to the functions instead of the example.

// Added Callerid to sent SMS messages. (They must be registered with your provider using their program first)
//
// Now we parse out the Telecom Service Providers GMT time ($iTSPtime) in Unix time. (Epoch)
// This is a help when sending immediate SMSes.

// A known problem with Summer / Winter time has appeared. Finarea/Betamax don't seem to understand time correctly.
// This version will work around that.

// Function tariffwizard added. Just like the webpage !! Although I can't see much use for it :)

// ***********************************************************************************************************
// * All functions return arrays with $iResult (An integer) and $sDebug (A text string).
// * In general $iResult should be 0 if the function worked sucessfully.
// ***********************************************************************************************************

//
// Creditcents, sms with caller-id(+ delayed sms) ,call and tariffwizard implemented so far.
//
// Feedback appreciated to junk at simong dot net or a comment at http://www.voip-info.org/wiki/view/Finarea+SA
//

// You need php with curl and ssl for curl.
// See http://www.php.net/curl

// *** See an example usage at http://www.simong.net/finarea/

// Don't forget to set (Done in the example.php script) ...

//    $BASEURL = "https://myaccount.".$SERVICE.".com/clx"; // Where $SERVICE is the service name eg. voipstunt
// OR   $BASEURL = "https://www.".$SERVICE.".com/myaccount"; // Where $SERVICE is intervoip 

//
// Then do a login followed by gomainpage BEFORE calling the other functions (call, sms etc.)


$sCookie_File "/tmp/".$_SERVER['REMOTE_ADDR'].":".$_SERVER['REMOTE_PORT'].".cookie"// This is where to store the cookie file. Any better suggestions ? 

// **************** Some functions *****************************************************************************

function http_arraytoxform ($aData){
    
$sDebug "";
    
$iResult 0;
        
reset ($aData);
        
$sData "";
        
$iCount 0;
        while (list (
$sKey$sVal) = each ($aData)) {
                
$sDebug .= "[$sKey] => [$sVal]<BR>\n";
                if ( 
$iCount == ) {
                        
$sData .= ($sKey "=" $sVal);
                        
$iCount += 1;
                } else {
                        
$sData .= ("&" $sKey "=" $sVal);
                }
        }

        return array(
$sData$iResult$sDebug);
}

function 
doRequest($sUrl$sMethod="GET"$sVars="",$bRemoveCookie=FALSE) {
   global 
$sCookie_File// A little unsafe maybe.

   
$iResult 0;
   
$sDebug "DEBUG: URL is [".$sUrl."] Method is [".$sMethod."]<br />\n";
   
$sResponse "";

   
$pCh curl_init();
   if (
$pCh) {
       
curl_setopt($pChCURLOPT_URL$sUrl);
       
curl_setopt($pChCURLOPT_HEADER1);
       
curl_setopt($pChCURLOPT_USERAGENT$_SERVER['HTTP_USER_AGENT']); // Uses the browsers user-agent. Smart !! :)
       
curl_setopt($pChCURLOPT_FOLLOWLOCATION1);
       
curl_setopt($pChCURLOPT_RETURNTRANSFER1);
       
curl_setopt($pChCURLOPT_COOKIEJAR$sCookie_File);
       
curl_setopt($pChCURLOPT_COOKIEFILE$sCookie_File);
       
curl_setopt($pChCURLOPT_SSL_VERIFYPEERfalse); // Verify the sites ssl cert, or not(false).
       // curl_setopt($AuthNetConn, CURLOPT_CAINFO, "path:/ca-bundle.crt"); // This points to your Certs authority bundle.
       // curl_setopt($pCh, CURLOPT_CONNECTTIMEOUT, 15); // Wait max 15 seconds for connection.
       // curl_setopt($pCh, CURLOPT_TIMEOUT, 30); // Wait max 30 for everything.
       
if ($sMethod == 'POST') {
           
curl_setopt($pChCURLOPT_POST1);
           
curl_setopt($pChCURLOPT_POSTFIELDS$sVars);
       }
       
$sData curl_exec($pCh);
   } else {
    
$sResponse "ERROR: Couldnt init curl";
    
$iResult ;
    
$sDebug .= $sResponse
   }
   if (
$sData) {
       
$sResponse $sData;
   } else {
       
$iResult ;
       
$sResponse "NO DATA \n";
       
$sResponse .= curl_error($ch);
       
$sDebug .= $sResponse;
   }
   
curl_close($pCh);

   if ( 
$bRemoveCookie === TRUE ){
    
// Remove cookie file
    
unlink($sCookie_File);
    
$sDebug .= "Cookie file [".$sCookie_File."] removed.<br />\n";
   }
   return array(
$sResponse$iResult$sDebug);

}

/**
*
* This function must be used before any other.
*
**/
function login($sUSER$sPASS){
    global 
$BASEURL;

    
$iResult 0;
        
$sDebug "";

    
$sDebug .= "DEBUG:BASEURL[".$BASEURL."]<br />\n"// u[".$sUSER."]p[".$sPASS."]<br />\n";

    
list($sXform$iThisResult$sThisDebug) = http_arraytoxform (array("username" => $sUSER"password" => $sPASS));

    list(
$sContent$iThisResult$sThisDebug) = 
        
doRequest($BASEURL."/""POST"$sXform);

    
// Look for "logout.gif" If it exists then we managed to log-in.
    
$bLOGGEDIN strpos(strtolower($sContent),"logout.gif"); // strtolower makes the search case-insensitive (Like grep -i)
    // Convert the Boolean result to 1 and 0 (true false)
    
if ( $bLOGGEDIN === FALSE ){
        
$bResult 0;
        
$iResult 1;
        
$sDebug .= "DEBUG: doRequest[".$sThisDebug."]<br />\n";
        
$sDebug .= "DEBUG: Content[".htmlentities ($sContent)."]<br />\n";
    } else {
        
$bResult 1;
        
$sDebug .= "DEBUG:[Login successfull]<br />\n";
    }
    return array(
$bResult$iResult$sDebug);
}

/**
*
* This appears to be required after logging in.
* And now this is where we get the Telecom Service Providers current time $iTSP (in Unix Epoch)
* It is needed to generate the now time for sending immediate SMSes.
*
**/
function gomainpage() {
    global 
$BASEURL;

    
$iResult 0;
    
$sDebug "";

    list(
$sContent$iThisResult$sThisDebug) = doRequest($BASEURL."/index.php?part=menu&justloggedin=true");


    
$iTSPtime 0// Initialise variable.
    // Parse eg. 200 OK\r\nDate: Sun, 25 Mar 2007 19:52:26 GMT
    //                Day         ,   01         May         2007         19:52:26            GMT
    
preg_match('/200 OK\r\nDate: ([a-z|A-Z]{3}), ([0-9]+) ([a-z|A-Z]{3}) ([0-9]{4}) ([0-9]+:[0-9]+:[0-9]+) (GMT)/'
        
htmlentities ($sContent), $aMatches);

    if ( 
count($aMatches) == 7){ // 0 - 6
        // Unix epoch. GMT
        
$iTSPtime strtotime($aMatches[2]." ".$aMatches[3]." ".$aMatches[4]." ".$aMatches[5]." "$aMatches[6]);
        
    } else {

        
$sDebug .= "Couldn't get Telecom Server Time.<br />\n";
        
$iResult 1;
    }

    
//$sDebug .=  "DEBUG:[".htmlentities ($sContent)."]<br />\n";
    
$sDebug .= "DEBUG : iTSPtime is [".$iTSPtime."]   [".date('r',$iTSPtime)."]<br />\n";

    return array(
$sContent$iTSPtime$iResult$sDebug);
}


function 
freedays ($sMainPage) {
    
$iResult 0;
    
$sDebug "";
    
// Freedays remaining:
    
$bResult preg_match('/.*Freedays remaining\:\<br\>\<b\>([0-9]*).*\<\/span/'$sMainPage$aMatches); //
    //print_r($aMatches); // DEBUG
    
if ($bResult){
        
$iFreeDays $aMatches[1];
    } else {
        
$iFreeDays 0;
    }

    return array(
$iFreeDays$iResult$sDebug);
}

function 
creditcents ($sMainPage) {
    
// Grep the remaining credit from the main page.
    // Almost the same as the fincheck shell script.
    
$iResult 0;
        
$sDebug "";
    
preg_match('/.*Remaining credit[^0-9]+([0-9.,]+).*/'$sMainPage$aMatches);
    
$iCreditCents str_replace(","""$aMatches[1]); // Get rid of thousand separator (,)
    
$iCreditCents = ($iCreditCents 100); // Convert to cents

    
return array($iCreditCents$iResult$sDebug);
}

function 
call($iSourceNum$iDestNum){
    global 
$BASEURL;

    
$sResult ""
    
$iResult 0;
        
$sDebug "";

    if (empty(
$iSourceNum)){
        
$sResult .= "No sourcenumber. "// No source number
        
$sDebug .= "$sResult";
        
$iResult 1;
    }
    if (empty(
$iDestNum)){
                
$sResult .= "No destination number. "// No dest number
        
$sDebug .= "No destination number. ";
        
$iResult 2;
        }


    if (
$iResult == 0){
        list(
$sXform$iThisResult$sThisDebug) = http_arraytoxform (array("action"=>"initcall",
                                
"panel"=>"true""anrphonenr"=>$iSourceNum"bnrphonenr"=>$iDestNum));

        
//$sThisURL = $BASEURL."/webcalls2.php";
        
$sThisURL $BASEURL."/phone-to-phone.php";
    
        list(
$sContent$iThisResult$sThisDebug) = 
            
doRequest($sThisURL"POST"$sXform);

        
$sDebug .= "RequestURL= [".$sThisURL."] CONTENT [".htmlentities ($sContent)."]<br />\n"// DEBUG
    
}

        

    return array(
$sResult$iResult$sDebug);
}



//    function sms($iDestNum,$sMsg,$iTime, $iGmtDiff=0,$iCallerId=0)
//     Where $iTime is the Unix time (Epoch) to send the SMS.
//    And You can use $iTSPtime from gomainpage function as $iTime to send NOW.
//    Otherwise it uses your servers time. And you better be in sync with Betamax servers.
//    And a fix here for the Finarea / Betamax Winter / Summer time problem.

function sms($iDestNum,$sMsg,$iTime=0$iGmtDiff=0,$iCallerId=0){

    
$bUSE_OLD_METHOD FALSE// Use the old websms page on immediate(NOW) SMSes.

    // NOTE: $iDestNum can be multiple numbers by comma separating them.

    
global $BASEURL;
    
$iResult 0;
        
$sDebug "";

     if (empty(
$iDestNum)){
                
$sThisMsg "No destination number. "// No dest number
        
$sResult .= $sThisMsg;
        
$sDebug .= $sThisMsg;
        
$iResult += 1;
        }

        if (empty(
$sMsg)){
                
$sThisMsg "No smstext. ";
        
$sResult .= $sThisMsg;
                
$sDebug .= $sThisMsg;
                
$iResult += 2;
    }    

    
$bSMSSent FALSE;

    if ( 
$iTime == 0) { // Immediate SMS
        
$bDelaySMS FALSE;

        if (
$bUSE_OLD_METHOD === TRUE){ // Use the old method
            
$sDebug .= "Sending immediate SMS the OLD way <br />\n";

            list(
$sXform$iThisResult$sThisDebug) = http_arraytoxform (array("action"=>"send",
                                        
"panel"=>"true""message" => $sMsg"bnrphonenumber"=>$iDestNum));

            list(
$sContent$iThisResult$sThisDebug) = 
                
doRequest($BASEURL."/websms.php""POST"$sXform);

            
$bSMSSent TRUE;
        } else {
            
$sThisMsg "Sending immediate SMS. <br />\n";
            
$iTime time(); // Using THIS servers time !! 
            
$sDebug .= $sThisMsg"WARNING: Using this servers time[".$iTime."] [".date('r',$iTime)."].<br />\n";
        }

    } else { 
// Timed SMS
        
$bDelaySMS TRUE;
        
$sThisMsg "Sending timed or immediate SMS using TSPtime.<br />\n";
        
$sDebug .= $sThisMsg;
    }

    if ( 
$bSMSSent == FALSE ){ // We didn't send an immediate SMS the OLD way. So lets send one now.

        // This script sends all messages using Betamax's version of GMT+1 
        // (Betamax has problems with GMT and Summertime breaks the GMT offset)

        // Get the Month, day, hour, minute and GMT offset, All converted to GMT+1 (As Betamax sees it. ie. wrongly !!)
        
$iGMTTime = ($iTime + ($iGmtDiff * -1)); // Convert $iTime to GMT.


        
if (date('I'$iTime)  == ){ // Summer time. TODO Check if a setlocale() or something is needed here.
            
$iBetamaxGMTTime = ($iGMTTime + (60 60)); // +1 hour. WORKAROUND to Betamax problem.
            
$sDebug .= "Summertime.<br />\n";
        } else { 
// Wintertime. Now Betamax understands the GMT offsets.
            
$iBetamaxGMTTime $iGMTTime;
            
$sDebug .= "Wintertime.<br />\n";
        }

        
// Now convert to GMT+1 (Or Betamax's GMT+1)  WORKAROUND to Betamax problem.
        
$iBetamaxTime = ($iBetamaxGMTTime + (60 60)); // 1 hour

        // Get the Month, day, hour, minute
        
$iMonthToSend gmstrftime ('%m',$iBetamaxTime);
        
$iDayToSend gmstrftime ('%d' ,$iBetamaxTime);
        
$iHourToSend gmstrftime ('%H' ,$iBetamaxTime);
        
$iMinuteToSend gmstrftime ('%M' ,$iBetamaxTime);
        
$iGmtDiff 1// GMT+1
        //

        // Send SMS
        
list($sXform$iThisResult$sThisDebug) = http_arraytoxform (array("action"=>"send",
                                
"panel"=>"true""message"=>$sMsg"bnrphonenumber"=>$iDestNum"day"=> $iDayToSend,
                                
"month"=>$iMonthToSend"hour"=>$iHourToSend"minute"=>$iMinuteToSend,
                                
"gmt"=>$iGmtDiff"callerid"=>$iCallerId));

        list(
$sContent$iThisResult$sThisDebug) = 
            
doRequest($BASEURL."/websms2.php""POST"$sXform);

        
//
    
// END  if ( $bSMSSent == FALSE

    // Parse $sContent for result, Cents left etc.
    // Attempt to check all went well ??
    // It appears that the balance is returned on a successful POST.
    // Grep for updateBalance("1860000"). Equals 1860 cents

    
$iThisResult preg_match('/.*updateBalance\("([0-9]+).*/'$sContent$aMatches);

    if ( 
$iThisResult == ){
        
$sResult .= "Failed to send sms<br />";

        
// Parse out some known faults.
        
$iThisFault preg_match('/The send date and time is in the past./'$sContent$aMatches);
        if ( 
$iThisFault ){
            
$iResult += 4;
            
$sResult .= "ERROR: Send date/time is in the past. MM/DD HH:MM[".$iMonthToSend ."/"$iDayToSend ." "
                
$iHourToSend .":"$iMinuteToSend." GMT ".$iGmtDiff."]<br />\n";
        } else {
            
$iResult += 32;  // Unknown SMS send fault.
            
$sResult .= "ERROR: Unknown SMS send fault<br />\n";
        }
        
//

        
$sResult .= "<h2>See DEBUG below.</h2>\n";
        
$sThisMsg "CONTENT [".htmlentities ($sContent)."]<br />\n"// DEBUG
        
$sDebug .= $sThisMsg$sThisDebug;
    } else {
        
$iCents = ($aMatches[1] / 1000);
        
$sDebug .= "Credit cents left is [".$iCents."]  or &euro;[".($iCents 100)."]<br />\n";
    }
    
//

    
return array($sResult$iCents$iResult$sDebug);
// END function sms

function tariffwizard ($iDestNum) {
    
// Check a telephone numbers cheapest Betamax service cost in cents per minute.

    // I wrote this by mistake, thinking that I could check this service providers call cost :)

    
global $BASEURL;
        
$sResult ""
        
$iResult 0;
        
$sDebug "";

    list(
$sXform$iThisResult$sThisDebug) = http_arraytoxform (array("action"=>"showoverview",
        
"telephonenr"=>$iDestNum));

    list(
$sContent$iThisResult$sThisDebug) =
                        
doRequest($BASEURL."/tariffwizard.php""POST"$sXform);

    
// Parse $sContent for Service, Provider type, Rate per minute, Callsetup and Additional info:
    //            wizardlog.php?url=http%3A%2F%2Fwww.justvoip.com%2F&bnr=
    
$iThisResult preg_match('/wizardlog.php\?url=http\%3A\%2F\%2F([a-z.]+)\%2F\&bnr=/'$sContent$aMatches);
    
$sUrl $aMatches[1];

    
//                 Provider type:</b></td>\n  <td>Voip</td>
    
$iThisResult preg_match('/Provider type:<\/b><\/td>\n.*<td>(.*)<\/td>/'$sContent$aMatches);
    
$sProviderType $aMatches[1];

    
//                Rate per minute:</b></td>\n  <td>5&nbsp;Ct/min</td>
    
$iThisResult preg_match('/Rate per minute:<\/b><\/td>\n.*<td>(.*)\&nbsp\;Ct\/min<\/td>/'$sContent$aMatches);
    
$iRatePerMinute $aMatches[1];


    
//                 Callsetup:</b></td>\n  <td>0&nbsp;Ct.</td>
    
$iThisResult preg_match('/Callsetup:<\/b><\/td>\n.*<td>(.*)\&nbsp\;Ct.<\/td>/'$sContent$aMatches);
    
$iCallSetup $aMatches[1];

    
//                 Additional info:</b></td>  <td>n/a </td>
    
$iThisResult preg_match('/Additional info:<\/b><\/td>\n.*<td>(.*)<\/td>/'$sContent$aMatches);
    
$sAdditionalInfo $aMatches[1];

    
$sDebug .= "CONTENT [".htmlentities ($sContent)."]<br />\n"// DEBUG


    
return array($sUrl$iRatePerMinute$iCallSetup$iResult$sDebug);
// End function tarriffwizard


// Callforward
function callforward($iType=-1$iDestNum=0){
        
// Where 
    // $iType = -1 "Check", 0 "Never", 1 "Always" , 2 "When offline", 
    //        3 "When offline or away" 

    
global $BASEURL;

        
$iResult 0;
        
$sDebug "";

    if ( 
$iType == -) {
        
$sDebug .= "Checking current forwarding details.<br />\n";
        list(
$sContent$iThisResult$sThisDebug) = doRequest($BASEURL."/callforwarding.php");
        
$iResult += $iThisResult;
        
$sDebug .= $sThisDebug;
    
        
// Match current details
        //$iThisResult = preg_match('/Forward calls:.*option value=\"([0-9])\"  selected.*forwardphone_0.*value=\"(\[0-9]*)\".*/s', $sContent, $aMatches);
        
$iThisResult preg_match('/Forward calls:.*option value=\"([0-9])\"  selected.*forwardphone_0.*value=\"([+0-9]*)\".*/s'$sContent$aMatches);

    } else {
        
// Remove + . Otherwise it causes problems. Dont know why ??
        
$iDestNum =  preg_replace('/^\+([0-9]*)/''${1}',$iDestNum);

        
$sDebug .= "Setting Forwarding type[".$iType."] Dest[".$iDestNum."] <br />\n";
        list(
$sXform$iThisResult$sThisDebug) = http_arraytoxform (array("fromsignup" => "",
            
"action" => "updatecallforwarding""nextpage" => """forwardingcondition" => $iType,
            
"forwardphone_0" => $iDestNum));

            list(
$sContent$iThisResult$sThisDebug) =
                            
doRequest($BASEURL."/callforwarding.php""POST"$sXform);
        
$iResult += $iThisResult;
        
$sDebug .= $sThisDebug;

        
// Match [Your callforwarding details have been changed.]
        
$iThisResult preg_match('/Your callforwarding details have been changed\./s'$sContent$aMatches);
    }


    if ( 
$iThisResult ) { 
        if ( 
$iType == -) {
            
$iCurrentType $aMatches[1];
            
$iCurrentNumber $aMatches[2];
        } else {
            
$iCurrentType $iType;
            
$iCurrentNumber $iDestNum;
        }
        
$sDebug .= "CONTENT [".htmlentities ($sContent)."]<br />\n"// DEBUG        
    
} else { 
        
$iResult += 127;
        if ( 
$iType == -) {
            
$sDebug .= "Coundnt find current forwarding details.<br />\n";
            
print_r($aMatches);
        } else {
            
$sDebug .= "Coundnt verify the new settings.<br />\n";
        }
        
$sDebug .= "CONTENT [".htmlentities ($sContent)."]<br />\n"// DEBUG        
        
$iCurrentType 0;
        
$iCurrentNumber "";
    }    
    
// echo "Matches <br />\n";
    // print_r($aMatches);
    // echo "<br />\n";

    
return array($iCurrentType$iCurrentNumber$iResult$sDebug);
}


function 
_maketime($iHour$iMinute$iMonth$iDay){
    
// Really just a shell for gmmktime.
    // Its a little help for those who don't understand Unix Epoch
    //    and want help converting to the new sms function.

    
return (gmmktime($iHour$iMinute,0,$iMonth$iDay));

}


function 
logoff(){
    global 
$BASEURL;
    list(
$sContent$iThisResult$sThisDebug) = doRequest($BASEURL."/index.php?part=logoff","",TRUE);
    return array(
$sContent,$iThisResult$sThisDebug);
}

// ********************************************* End of functions *******************************************************

?>