Tuesday, June 23, 2009

Plugin for Python

To develop software that extensible and maintainable, we have to separate the concern in our programs. Plugin system is one way to do it. So, I made a Plugin class, for my own programs, that will load python script dynamically.

Here is the code:

class Plugin:
def __init__(self,base,dir):
"""docstring for __"""
self.plugins={}
self.plugin_dir=base+'/'+dir
sys.path.append(self.plugin_dir)
def load(self,fname):
"""docstring for load"""
p=''
if fname.find('.pyc')>0:
p=fname.replace('.pyc','').strip()
#print 'importing:',p
try:
self.plugins[p] = __import__(p)
except:
pass
def load_all(self):
"""docstring for load"""
try:
dir_list=os.listdir(self.plugin_dir)
for fname in dir_list:
self.load(fname)
except Exception, e:
raise e

Sunday, June 21, 2009

Encoding & Decoding SMS Format for Nokia 6235 CDMA device

There is little informations about how to send SMS on CDMA device. Finally, I found AT Command document on Nokiad 6325 CDMA mobile phone. So I made small python scripts for encoding and decoding sms format based on the AT Document. Here is the scripts:

import sys
import os


def intToHex(i):
"""docstring for intToHex"""
return hex(i).replace('x','').upper()
def strToHex(s):
lst = []
for ch in s:
hv = hex(ord(ch)).replace('0x', '')
if len(hv) == 1:
hv = '0'+hv
lst.append(hv)

return reduce(lambda x,y:x+y, lst)

#convert hex repr to string
def hexToStr(s):
return s and chr(atoi(s[:2], base=16)) + toStr(s[2:]) or ''


def hexStrToInt(s1,s2):
"""docstring for hextToInt"""
return int('0x%s%s' % (s1,s2),16)

#encode into sms format for nokia 6235
#Use this function with sending sms (AT+CMGS)
#input:
# - msisdn = destination mobile #
# - sms = message
def sms_encode_nokia_cdma(msisdn,sms):

len_msisdn=len(msisdn)
len_sms=len(sms)

hex_len_msisdn=intToHex(len_msisdn)
hex_len_sms=intToHex(len_sms)
format_hex = []
print 'len',hex_len_msisdn,hex_len_sms
format_hex.append(hex_len_msisdn)
for i in msisdn:
format_hex.append(strToHex(i))
format_hex.append('02')
format_hex.append(hex_len_sms)
for i in sms:
format_hex.append(strToHex(i))
print format_hex

return ''.join(format_hex)

#decode into sms format for nokia 6235
#Use this function with reading sms (AT+CMGL)
# output: dictionary
# - msisdn = source mobile phone #
# - timestamp = timestamp format: yymmddhhiiss
# - msg = message
def sms_decode_nokia_cdma(s):
"""docstring for decode_sms"""
s=s.replace('\t','').replace('\n','').strip()
print 'start decoding:%s' % s
if not s:
return None
sms={}
j=0
send_num_len=hexStrToInt(s[j],s[j+1])
#print 'sender_num_len',send_num_len
j=j+2
i=0
msisdn_a=[]
while i
#print 'i:',i,j,'=',s[j]
msisdn_a.append(s[j])
j=j+1
i=i+1
#print 'msisdn',''.join(msisdn_a)
sms['msisdn']=''.join(msisdn_a)
i=0
timestamp_a=[]
while i<6:
#print 't:',i,j,'=',s[j],s[j+1]
timestamp_a.append(s[j])
timestamp_a.append(s[j+1])
j=j+2
i=i+1
#print 'timestamp:',''.join(timestamp_a)
sms['timestamp']=''.join(timestamp_a)
print 'encoding:',s[j],s[j+1]
j=j+2
#print 'data len1:',s[j],s[j+1],'=',hexStrToInt(s[j],s[j+1])
len_data1=hexStrToInt(s[j],s[j+1])
j=j+2
#print 'data len2:',s[j],s[j+1],'=',hexStrToInt(s[j],s[j+1])
len_data2=hexStrToInt(s[j],s[j+1])
j=j+2
len_data=int('%s%s' % (len_data1,len_data2))
print 'len data:',len_data
d=s[j:len(s)]
# i=0
# print 'start parsing data:',j,s[j]
# while i
# print 'adding:',s[j]
# d.append(s[j])
# j=j+1
# i=i+1
#print 'data:',''.join(d)
sms['msg']=''.join(d)
#print sms
return sms



Friday, June 12, 2009

Using CURL as HTTP Client for XmlRPC in PHP

From my previous post, about modification of IXR XmlRPC client to add HTTPS capability, I used function fopen as a HTTP/S client. This technique can only be applied for PHP ver 5.0 or above. So, in this post, I will try to use CURL as a more attractive alternative for all PHP version that support CURL extention. CURL itself is known as stable and powerful multi protocol (including HTTP/S) client for command line in linux world. Thanks to the extension capability of PHP, we can utilize the power of CURL inside PHP directly. So here is the code for SendHttpPost method using CURL:

function SendHttpPost($url,$content){

$ch = curl_init(); // initialize curl handle

curl_setopt($ch, CURLOPT_VERBOSE, 0); // set url to post to
curl_setopt($ch, CURLOPT_URL, $url); // set url to post to
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // return into a variable
curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 40); // times out after 4s
curl_setopt($ch, CURLOPT_POSTFIELDS, $content); // add POST fields
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST ,0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

$result = curl_exec($ch); // run the whole process

if (empty($result)) {
// some kind of an error happened
//die(curl_error($ch));
//curl_close($ch); // close cURL handler

} else {
$info = curl_getinfo($ch);
//curl_close($ch); // close cURL handler

if (empty($info['http_code'])) {
//die("No HTTP code was returned");
} else {
// load the HTTP codes
// $http_codes = parse_ini_file("response.inc");
// echo results
//echo "The server responded: \n";
//echo $info['http_code'] . " " . $http_codes[$info['http_code']];
}
}

curl_close($ch);
return $result; //contains response from server

}



Thursday, June 11, 2009

Secure HTTP/HTTPS capable XmlRpc library for PHP

IXR - The Inutio XML-RPC Library is one of my favorite Xmlrpc library for PHP. I found it very straight forward,simple and powerful xmlrpc client. Unfortunately, it doesn't have capability to connect using secure HTTP protocol / HTTPS. So, I decided to give more "security" juice to it. The trick is to use fopen instead of fsockopen function to send HTTP POST method to the server. For your notice, this trick is for PHP ver 5 or above only. Replace the function query() in file IXR_Library.inc, with this modification:

/*
* Sends a form-encoded HTTP(S) POST to a given URL.
* Returns a string containing the response.
*
* If response code is not 200, throws an error msg.
*/
function SendHttpPost($url,$content)
{


$context_options = array(
'http'=>array(
'method'=>"POST",
'header'=> "User-Agent: {$this->useragent}\r\n".
"Content-type: text/xml\r\n".
"Content-length: " . strlen($content) . "\r\n"
,
'content'=> $content
)
);
// Make sure the HTTPS options are the same as HTTP
$context_options['https'] = $context_options['http'];
$context = stream_context_create($context_options);
echo 'context:'.var_export($context_options,true);
$fp = fopen($url, 'r', false, $context);
// Get the response...
$response = '';
/* For HTTPS, IIS closes the SSL socket improperly hence
* generating a warning. We want to suppress this, as some
* servers will be doing this.
*
* see http://uk.php.net/manual/en/wrappers.http.php
*/
$old_error_reporting = error_reporting();
error_reporting($old_error_reporting & ~E_WARNING);
// Get the headers
$metadata = stream_get_meta_data($fp);
foreach($metadata['wrapper_data'] as $responseheader) {
// Look for the status header...
if (substr($responseheader,0,5) == 'HTTP/') {
$bits = split(' ', $responseheader);
$httpstatus = (int) $bits[1];
$httpstatusmessage = $responseheader;
}
}
// There is no need to check the HTTP status, as fopen wrapper
// that for us anyway.
// Read the the response data
while (!feof($fp)) {
$response .= fread($fp, 8192);
}
fclose($fp);
error_reporting($old_error_reporting);
return $response;
}


function query() {
$args = func_get_args();
$method = array_shift($args);
$request = new IXR_Request($method, $args);
$length = $request->getLength();
$xml = $request->getXml();
// Modification from Original ------------------
// $r = "\r\n";
// $request = "POST {$this->path} HTTP/1.0$r";
// $request .= "Host: {$this->server}$r";
// $request .= "Content-Type: text/xml$r";
// $request .= "User-Agent: {$this->useragent}$r";
// $request .= "Content-length: {$length}$r$r";
// $request .= $xml;
// // Now send the request
// if ($this->debug) {
// echo '
'.htmlspecialchars($request)."\n
\n\n";
// }
// $fp = @fsockopen($this->server, $this->port);
// if (!$fp) {
// $this->error = new IXR_Error(-32300, 'transport error - could not open socket');
// return false;
// }
// fputs($fp, $request);
// $contents = '';
// $gotFirstLine = false;
// $gettingHeaders = true;
// while (!feof($fp)) {
// $line = fgets($fp, 4096);
// if (!$gotFirstLine) {
// // Check line for '200'
// if (strstr($line, '200') === false) {
// $this->error = new IXR_Error(-32300, 'transport error - HTTP status code was not 200');
// return false;
// }
// $gotFirstLine = true;
// }
// if (trim($line) == '') {
// $gettingHeaders = false;
// }
// if (!$gettingHeaders) {
// $contents .= trim($line)."\n";
// }
// }


// end of Modification from Original ------------------

if ($this->debug) {
echo 'server:'.$this->server.'
'.htmlspecialchars( $xml)."\n
\n\n";
}
// Add new function to send HTTP Post
$contents=$this->SendHttpPost($this->server,$xml);
if ($this->debug) {
echo '
'.htmlspecialchars($contents)."\n
\n\n";
}
// Now parse what we've got back
$this->message = new IXR_Message($contents);
if (!$this->message->parse()) {
// XML error
$this->error = new IXR_Error(-32700, 'parse error. not well formed');
return false;
}
// Is the message a fault?
if ($this->message->messageType == 'fault') {
$this->error = new IXR_Error($this->message->faultCode, $this->message->faultString);
return false;
}
// Message must be OK
return true;
}