Archive | Uncategorized RSS for this section

How to send MMS using SOAP MM7

Here’s an article describing how to implement MM7 connection to your service provider’s MMS center.

Perhaps for the start, I would like to tell the history of MM7 implementation. At first most vendors implement MM7 connection to send MMS content using their own proprietary library. E.g. One of biggest vendor uses PAP (Push Application Protocol) to send standard MMS content from VAS App to the subscriber. Basically it’s built on standard MIME Message class.

Good news, nowadays many vendor has dealt to implement their MM7 connection from VAS App using standard SOAP connection. Moreover, under this SOAP implementation, they can support SMIL class message. It’s a standard Markup Language to implement layouting in MMS content delivery. Also, using this SMIL implementation, we can present multi pages MMS that showed one after another with predefined duration.

Here’s the example of SMIL tag:

<smil xmlns=”http://www.w3.org/2001/SMIL20/Language”>

<head>

<layout>      <root-layout width=”160″ height=”120″/>

<region id=”upper” top=”0″ left=”0″ />      <region id=”lower” top=”100″ left=”0″ />

</layout>

</head>

<body>

<par dur=”3s”>      <text region=”lower” src=”text0.txt” />      <img region=”upper” src=”zzz.JPG” />      <audio src=”01000000478.mid” />    </par>

<par dur=”5s”>      <text region=”lower” src=”text3.txt” />      <img region=”upper” src=”zzz.JPG” />      <audio src=”01000000478.mid” />    </par>

</body></smil>

For the art of software programming, I will put my example code here in Java from scratch. Actually you can code SOAP Message in Java using SAAJ standard library.

At first you need to make sure that you have variables that define the connection to the MMSC. They are MMSC IP, Port, VASID, VASPID, and Password. It can be defined from file configuration.

String mmsc_ip = Utility.getConfiguration(“MmscSoap.ip”); int mmsc_port = Integer.parseInt(Utility.getConfiguration(“MmscSoap.port”)); String mmsc_pwd = Utility.getConfiguration(“MmscSoap.pwd”); String mmsc_vaspid = Utility.getConfiguration(“MmscSoap.vaspid”); String mmsc_vasid = Utility.getConfiguration(“MmscSoap.vasid”);

Basically, SOAP connection is a like a HTTP socket connection using POST method. So, we need to define the HTTP header:

String header = “POST /vas_soap HTTP/1.1\n” +

“Host: “+mmsc_ip+”:”+mmsc_port+”\n” +

“Authorization: Basic “+toBASE64(mmsc_pwd,0)+”\n” +

“User-Agent: mm7submit/0.1\n” +   “Content-Type: multipart/related; boundary=\”–_=_NextPart_21B2_1EE0_E97.2593\”; type=\”text/xml\”; start=\”<mm7submit@localhost>\”\n” +

“Content-Length: “+data.length()+”\n” +

“Accept: */*\n” +

“SOAPAction: \”\”\n\n”;

You can specify either the connection is using HTTP/1.1 or HTTP/1.0. Also you can add more HTTP header there, depends on the server’s need.

MMS contents are simply the texts, multimedia contents (audio, video, and picture), and SMIL tags that defined how the contents presented. Multimedia contents are supposed to be sent as format Base64 Encoding. So, we’re going to put

import sun.misc.BASE64Encoder;

in top of the file.

For the contents’ location, this tutorial will search the contents based on the URL specified in the SMIL tags. Normally, SMIL tag should not be filled with URL. But, to simplify the solution, this code will accept SMIL with URL. Then it will string-process the SMIL to extracts the URL of the contents. Then, will put the content name based on the hashcode of the URL specified.

<img region=”upper” src=”http://www.google.com/images/logos/ps_logo2.png” />

will be replaced with:

<img region=”upper” src=”c63893e3754e335896165ed94d6ce67e” />

The code will differs multimedia into three different types (audio, video, and image). Then it will assume the Content-Type based on the suffix of the URL path.

The code will string-process the smil to get contents’ URL:

smil = URLDecoder.decode(smil);

Vector<String> gambars = new Vector<String>();

Pattern p = Pattern.compile( “<img[ *]region=.[^<>'\"]*.[ *]src=['\"]([^'\"<>]*)['\"][ *]/>”,  Pattern.DOTALL);
Matcher matcher = p.matcher(smil);

while (matcher.find()) {

String temp = matcher.group(1);

if(!gambars.contains(temp))

gambars.add(temp);

}

Vector<String> suaras = new Vector<String>();

p = Pattern.compile(“<audio[ *]src=['\"]([^'\"<>]*)['\"][ *]/>”, Pattern.DOTALL);
matcher = p.matcher(smil);

while (matcher.find()) {

String temp = matcher.group(1);

if(!suaras.contains(temp))

suaras.add(temp);

}

Vector<String> videos = new Vector<String>();

p = Pattern.compile(“<video[ *]src=['\"]([^'\"<>]*)['\"][ *]/>”, Pattern.DOTALL);
matcher = p.matcher(smil);

while (matcher.find()) {

String temp = matcher.group(1);

if(!videos.contains(temp))

videos.add(temp);

}

And here’s how we build the main HTTP body:

String data = “”+ “—-_=_NextPart_21B2_1EE0_E97.2593\n” +

“Content-Type: application/xml\n” +

“Content-ID: <mm7submit@localhost>\n” + “\n” +

“<?xml version=\”1.0\” encoding=\”UTF-8\”?>\n” +

“<SOAP-ENV:Envelope xmlns:SOAP-ENV=\”http://schemas.xmlsoap.org/soap/envelope/\” xmlns=\”http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-5-MM7-1-2\”>\n” +

“<SOAP-ENV:Header>\n” +

” <TransactionID SOAP-ENV:mustUnderstand=\”1\”>vas00001</TransactionID>\n” +

“</SOAP-ENV:Header>\n” +

“<SOAP-ENV:Body>\n” +

“<SubmitReq>\n” +

“<MM7Version>5.3.0</MM7Version>\n” +

“<SenderIdentification>\n” +

” <VASPID>”+mmsc_vaspid+”</VASPID>\n” +

” <VASID>”+mmsc_vasid+”</VASID>\n” +

” <SenderAddress><Number>”+ sender +”</Number></SenderAddress>\n” +

” </SenderIdentification>\n” +

” <Recipients>\n” +

” <To><Number>”+to+”</Number></To>\n” +

” </Recipients>\n” + ” <MessageClass>Informational</MessageClass>\n” +

” <DeliveryReport>false</DeliveryReport>\n” +

” <ReadReply>false</ReadReply>\n” +

” <Priority>Normal</Priority>\n” +

” <Subject>”+subject+”</Subject>\n” +

” <ChargedParty>Sender</ChargedParty>\n” +

” <Content href=\”cid:content@localhost\” allowAdaptations=\”true\”/>\n” +

“</SubmitReq>\n” + “</SOAP-ENV:Body>\n” +

“</SOAP-ENV:Envelope>\n\n” + “—-_=_NextPart_21B2_1EE0_E97.2593\n” +

“Content-Type: multipart/mixed; boundary=\”—-_=_NextPart_220A_232_2517.E38\”\n” +

“Content-ID: <content@localhost>\n” + “\n”;

String texts[] = text.split(“<next/>”);

for(int g = 0; g < texts.length; g++){

data+=”——_=_NextPart_220A_232_2517.E38\n” +

“Content-Type: text/plain; charset=\”us-ascii\”; Name=text”+g+”.txt\n” +

“Content-ID: <text”+g+”.txt>\n” +

“Content-Location: text”+g+”.txt\n\n” +

texts[g]+”\n” + “\n”;

}
String gambar_name[] = null;

int max_depth = 0;

if(gambars != null){

Log.getLogger().debug(“Parse image…”);

gambar_name = new String[gambars.size()];

for(int g = 0; g < gambars.size(); g++){

if(max_depth == g) max_depth++;

URL sourceURL1 = null;

try {

String url = gambars.get(g).replaceAll(” ” , “+”);

sourceURL1 = new URL(url);

byte[] byteArray = null;

HttpClient http = new HttpClient();

http.getParams().setSoTimeout(timeout);

if (proxyHost != null && proxyPort != null) {

Log.getLogger().info(“Using proxy = ” + proxyHost + “:” + proxyPort);

http.getHostConfiguration().setProxy(proxyHost, Integer.parseInt(proxyPort));

}

HttpMethod method = new GetMethod(url);

http.getParams().setParameter(“http.socket.timeout”, timeout);

http.getParams().setParameter(“http.connection.timeout”, timeout);

method.getParams().setParameter(“http.socket.timeout”, timeout);

method.getParams().setParameter(“http.connection.timeout”, timeout);

try {

int statusCode = http.executeMethod(method);

if (statusCode != HttpStatus.SC_OK && statusCode != 202) {

byteArray = null; Log.getLogger().debug(“Status HTTP:”+ statusCode);

} else { byteArray = method.getResponseBody(); }

} catch (Exception e) { Log.getLogger().error(“Error in httpGet”, e); byteArray = null; }

finally { method.releaseConnection(); }

String filename = sourceURL1.getFile();

BASE64Encoder encoder = new BASE64Encoder();

if(filename.contains(“/”)) filename = filename.substring(filename.lastIndexOf(“/”)+1);

gambar_name[g] = Integer.toString(filename.hashCode());

smil = replace(smil, url, gambar_name[g]);

String format = filename.substring(filename.lastIndexOf(“.”)).toLowerCase();

String type = “image/png”;

if(format.equals(“.gif”)) type = “image/gif”;

else if(format.equals(“.jpg”) || format.equals(“.jpeg”)) type = “image/jpeg”;

else if(format.equals(“.png”)) type = “image/png”;

else if(format.equals(“.tiff”)) type = “image/tiff”;

data+=”——_=_NextPart_220A_232_2517.E38\n” +

“Content-Type: “+type+”;

Name=”+gambar_name[g]+”\n” +

“Content-Transfer-Encoding: base64\n” +

“Content-ID: <”+gambar_name[g]+”>\n” +

“Content-Location: “+gambar_name[g]+”\n\n” +

encoder.encode(byteArray)+”\n” + “\n”;

} catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace(); }

}

}

String suara_name[] = null;

if(suaras != null){

suara_name = new String[suaras.size()];

for(int g = 0; g < suaras.size(); g++){

if(max_depth == g) max_depth++;

URL sourceURL1 = null;

try {

String url = suaras.get(g).replaceAll(” ” , “+”);

sourceURL1 = new URL(url);

byte[] byteArray = null;

HttpClient http = new HttpClient();

http.getParams().setSoTimeout(timeout);

if (proxyHost != null && proxyPort != null) {

Log.getLogger().info(“Using proxy = ” + proxyHost + “:” + proxyPort);

http.getHostConfiguration().setProxy(proxyHost, Integer.parseInt(proxyPort));

}

HttpMethod method = new GetMethod(url);

http.getParams().setParameter(“http.socket.timeout”, timeout);

http.getParams().setParameter(“http.connection.timeout”, timeout);

method.getParams().setParameter(“http.socket.timeout”, timeout);

method.getParams().setParameter(“http.connection.timeout”, timeout);

try {

int statusCode = http.executeMethod(method);

if (statusCode != HttpStatus.SC_OK && statusCode != 202) {

byteArray = null;

Log.getLogger().debug(“Status HTTP:”+ statusCode);

} else { byteArray = method.getResponseBody(); }

} catch (Exception e) { Log.getLogger().error(“Error in httpGet”, e); byteArray = null; }

finally { method.releaseConnection(); }

String filename = sourceURL1.getFile();

BASE64Encoder encoder = new BASE64Encoder();

if(filename.contains(“/”)) filename = filename.substring(filename.lastIndexOf(“/”)+1);

suara_name[g] = Integer.toString(filename.hashCode());

smil = replace(smil, suaras.get(g), suara_name[g]);

String format = filename.substring(filename.lastIndexOf(“.”)).toLowerCase();

String type = “audio/wav”;

if(format.equals(“.wav”)) type = “audio/wav”;

else if(format.equals(“.mid”) || format.equals(“.midi”)) type = “audio/midi”;

else if(format.equals(“.mp3″)) type = “audio/mp3″;

else if(format.equals(“.3gp”)) type = “audio/3gpp”;

else if(format.equals(“.aac”)) type = “audio/aac”;

else if(format.equals(“.amr”)) type = “audio/amr”;

else if(format.equals(“.amr-wb”)) type = “audio/amr-wb”;

else if(format.equals(“.mpeg”) || format.equals(“.mpg”)) type = “audio/mpeg”;

else if(format.equals(“.mp4″)) type = “audio/mp4″;

else if(format.equals(“.rmv”) || format.equals(“.rmvb”)) type = “audio/rmv”;

else continue;

data+=”——_=_NextPart_220A_232_2517.E38\n” +

“Content-Type: “+type+”; Name=”+filename+”\n” +

“Content-Transfer-Encoding: base64\n” +

“Content-ID: <”+filename+”>\n” +

“Content-Location: “+filename+”\n\n” +

encoder.encode(byteArray)+”\n” + “\n”;

} catch (MalformedURLException e) {// TODO Auto-generated catch block e.printStackTrace(); }

catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }

String video_name[] = null;

if(videos != null) {

video_name = new String[videos.size()];

for(int g = 0; g < videos.size(); g++) {

if(max_depth == g) max_depth++;

URL sourceURL1 = null;

try {

String url = videos.get(g).replaceAll(” ” , “+”);

sourceURL1 = new URL(url);

byte[] byteArray = null;

HttpClient http = new HttpClient();

http.getParams().setSoTimeout(timeout);

if (proxyHost != null && proxyPort != null) {

Log.getLogger().info(“Using proxy = ” + proxyHost + “:” + proxyPort);

http.getHostConfiguration().setProxy(proxyHost, Integer.parseInt(proxyPort));

}

HttpMethod method = new GetMethod(url);

http.getParams().setParameter(“http.socket.timeout”, timeout);

http.getParams().setParameter(“http.connection.timeout”, timeout);

method.getParams().setParameter(“http.socket.timeout”, timeout);

method.getParams().setParameter(“http.connection.timeout”, timeout);

try {

int statusCode = http.executeMethod(method);

if (statusCode != HttpStatus.SC_OK && statusCode != 202) {

byteArray = null;

Log.getLogger().debug(“Status HTTP:”+ statusCode);

} else { byteArray = method.getResponseBody(); }

}

catch (Exception e) { Log.getLogger().error(“Error in httpGet”, e); byteArray = null; }

finally { method.releaseConnection(); }

String filename = sourceURL1.getFile();

BASE64Encoder encoder = new BASE64Encoder();

if(filename.contains(“/”)) filename = filename.substring(filename.lastIndexOf(“/”)+1);

video_name[g] = Integer.toString(filename.hashCode());

smil = replace(smil, videos.get(g), video_name[g]);

String format = filename.substring(filename.lastIndexOf(“.”)).toLowerCase();

String type = “video/mpeg”;

if(format.equals(“mpeg”) || format.equals(“mpg”)) type = “video/mpeg”;

else if(format.equals(“.3gp”) || format.equals(“.3gpp”)) type = “video/3gpp”;

else if(format.equals(“.mp4″)) type = “video/mp4″;

else if(format.equals(“.rmv”) || format.equals(“.rmvb”)) type = “video/rmv”;

else continue;

data+=”——_=_NextPart_220A_232_2517.E38\n” +

“Content-Type: “+type+”; Name=”+filename+”\n” +

“Content-Transfer-Encoding: base64\n” +

“Content-ID: <”+filename+”>\n” +

“Content-Location: “+filename+”\n\n” +

encoder.encode(byteArray)+”\n” + “\n”;

} catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); }

catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }

}

}

if(use_smil != null && !use_smil.equals(“”) && !use_smil.equals(“false”)) {

if(use_smil.toLowerCase().equals(“default”)){

smil = “<smil><head><layout><root-layout/><region id=\”upper\” top=\”0\” left=\”0\” /><region id=\”lower\” top=\”100\” left=\”0\” /><region id=\”lowest\” top=\”200\” left=\”0\” /></layout></head><body>”;

for(int g = 0; g < max_depth; g++) {

smil += “<par dur=\”3s\”>”;

if(g < texts.length) smil += “<text region=\”lower\” src=\”text”+g+”.txt\” />”;

if(gambar_name != null && g < gambar_name.length) smil += “<img region=\”upper\” src=\”"+gambar_name[g]+”\” />”;

if(video_name != null && g < video_name.length) smil += “<video region=\”lowest\” src=”+video_name[g]+” />”;

if(suara_name != null && g < suara_name.length) smil += “<audio src=”+suara_name[g]+” />”;

smil += “</par>”;

}

smil += “</body></smil>”;

}

data += “——_=_NextPart_220A_232_2517.E38\n” +

“Content-Type: application/smil; charset=\”us-ascii\”; Name=smil4.smil\n” +

“Content-ID: <smil4.smil>\n” +

“Content-Location: smil4.smil\n” + “\n” +

“<?xml version=\”1.0\” encoding=\”utf-8\”?>” +

“<!DOCTYPE smil PUBLIC \”-//3GPP//DTD SMIL rel5//EN\” \”http://www.3gpp.org/SMIL20/PSS5\”>” + smil + “\n”;

}

data += “——_=_NextPart_220A_232_2517.E38–\n” + “—-_=_NextPart_21B2_1EE0_E97.2593–\n\n”;

Finally, here’s the code to submit the header + contents (data) to the MMSC using HTTP Socket SOAP:

String dat;

try {

Socket so = new Socket(mmsc_ip, mmsc_port);

BufferedOutputStream bos = new BufferedOutputStream(so.getOutputStream());

String msg = header + data;

BufferedReader br2 = new BufferedReader(new InputStreamReader(so.getInputStream()));

bos.write(msg.getBytes());

bos.flush();

dat = “”;

Log.getLogger().debug(“MmsSOAP request :”+msg);

String temp;

while((temp = br2.readLine()) != null){

dat += temp;

}

so.close();

try {

String a = dat.substring(dat.indexOf(“<StatusCode>”) + 12, dat.indexOf(“</StatusCode>”));

Log.getLogger().info(“MmsSOAP response :”+a);

ret = Integer.parseInt(a);

} catch (Exception e) {  // TODO Auto-generated catch block  ret = -9;  e.printStackTrace();  } }

catch (UnknownHostException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }

catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); }

For the response, normally MMSC will reply response String 1000 as Success.

Stand Up for the Champion !!

I was built to be the best
Number one and nothing less
Leave me to my destiny
I have waited patiently
I have vision’ oh I believe
I know I can count on me

(chorus)
So stand up for the champions
For the champions stand up
Stand up stand up
For the champions for the champions
Stand up for the champions
For the champions stand up
Stand up stand up
For the champions for the champions
Stand up

Here we go it’s getting close
Now it’s just who wants it most
It’s just like that’s how it is
Cause we have our strengths and weaknesses

Oh I have vision’ oh can’t you see
I’m on the move make way for me

(chorus)
So stand up for the champions
For the champions stand up
Stand up stand up
For the champions for the champions
Stand up for the champions
For the champions stand up
Stand up stand up
For the champions for the champions
Stand up

4x
And when I fall down
I have to pick myself back up

So stand up stand up for the champions
For the champions stand up
Stand up stand up
For the champions for the champions
Stand up

4x
Stand up stand up
For the champions for the champions

Stand up

Yahoo Hack Day submit

In the era of globalization, people tends to meet another people from different country, culture, and most probably (and usually most annoyingly) different language. Here I propose the idea to have a single framework for social media platform that can translate everything to our language preference. And by everything here, I mean the platform should be able to translate every posting from our friends and followee (people that we follow).

In the mean time, from last night work, I’m just able to develop the application for twitter user. Next I’ll try to collaborate with another source of social media platform (like Yahoo MeMe, Google Wave, Facebook, and another (perhaps it will be open for dynamic service addition, just like the concept of Pidgin Messenger)).

The basic idea of this application is mostly supported by YQL (Yahoo Query Language). Here I’m using Open Data Table (ODT) to translate with google translate. Why Google? Because, nowadays, I think they have supported most language in the earth ( I’ll try BabelFish soon as they translate Indonesian language ;P ).

To access twitter, I directly access twitter API in their site. And last but not the least, I use YQL IP geolocator to retrieve information about the user (language preference advise). But of course they can alse change their preference manually. Thanks for giving us chance to hacking this day. Good day,

 

try at : http://antonrifco.000space.com/x/index.php

Seminggu yang manis sekaligus melelahkan

Seminggu terakhir ini merupakan waktu yang sangat “sakit” buat gua.

Banyak UTS ama kerjaan laen, di saat mood sedang ingin bermain dan bermain games PC, terutama Warcraft dotA . Memang sih ujiannya (UTS) yang gua hadapi gak terlalu sulit dan ribet, hanya saja tekanan yang dikandung dalam esensi ujian itu sendiri yang membuat gua pusing dan kadang-kadang sampe sulit untuk tidur.

Kok bisa manis?

Nah, kalo yang belum sempet gua ceritain.

Ceritanya begini, sepulang dari mudik Cirebon kemaren2, gua dibawain oleh-oleh ama orangtua di sana banyak sekali, diantaranya ialah satu plastik besar mangga gincu (mungkin sekilo lebih deh).

Dan semuanya udah mateng. Masalahnya, di kosan ini, anak-anak yang laen gak ada yang doyan makan mangga, udah gw tawarin tetep aja pada gak mau. Mungkin mereka males untuk “ngoncek” kulitnya sih.

Nah, karena gw gak mau kalo mangga2 ini sampe jadi bosok, akhirnya gw buat suatu kebijakan internal (cieee…). Di tiap malem-malem ganjil, gw makan 2 buah mangga sekaligus. Hahahahaha……

Tujuannya, ya gak lain dan gak bukan, supaya mereka cepat habis dan gak jadi busuk.

Akhirnya setelah beberap malam belajar UTS ditemani makan mangga, akhirnya mereka mulai perlahan-lahan menghilang dari kamar gw dan masuk ke kamar mandi (menjadi produk limbah perut gw, haha..)

Mangga

mangga2

MAU?

Puteri Kerajaan Sunda

Hehehehehe, ada – ada saja kisah yang satu ini.

Mungkin berminat menunjukan sikap separatisme – nya terhadap bangsa Indonesia

Pengadilan Malaysia Minta Dua Puteri “Kerajaan Sunda” Hubungi Keluarga

Kuala Lumpur (ANTARA News) – Pengadilan Miri, Kuching, Malaysia, meminta dua wanita yang mengaku sebagai Puteri “Kerajaan Sunda”, yakni Lamia Rato Wiranata, (21) dan Fathia Reza, ( 23), agar menghubungi saudara atau “kedutaan” mereka secepat mungkin.

Hakim pengadilan Miri, Timothy Finlayson Joel, mengizinkan kedua terdakwa menulis surat kepada saudara atau “kedutaan “yang mengakui mereka sebagai warga negaranya atau menunjukkan bukti-bukti bahwa mereka Puteri “Kerajaan Sunda” yang tidak diketahui lokasinya.

Hakim mengancam jika mereka gagal menunjukan barang bukti sebagai Puteri “kerajaan Sunda”, maka sidang akan dilanjutkan.

Kepada pengadilan, kedua wanita mengaku bukan warga Indonesia dan tetap ngotot sebagai keturunan “Kerajaan Sunda”.

Sebelum ditahan imigrasi Malaysia, kedua wanita itu mengaku kepada hakim, telah melakukan perjalanan liburan ke Singapura dan Brunei.

Kedua wanita itu semula dipermasalahkan oleh pemerintahan Brunei, karena memegang paspor “kerajaan Sunda”.

Oleh pemerintah Brunei, kedua wanita itu dideportasi di perbatasan Malaysia, tepatnya di Miri, Kuching. Mereka tinggal di sebuah rumah di Miri dan kemudian ditangkap imigrasi Malaysia pada 23 Juli 2007. (*)

http://www.antara.co.id/arc/2007/8/9/pengadilan-malaysia-minta-dua-puteri-kerajaan-sunda-hubungi-keluarga/

Follow

Get every new post delivered to your Inbox.