Kamis, Februari 02, 2006

Kunci Motor Macet

Pernahkah Anda mengalami kunci kontak kendaraan anda tidak bisa digerakkan karena macet ? Saya mengalaminya akhir minggu lalu.
Ketika itu, saya bersama kakak saya sedang belanja kebutuhan rumah tangga di supermarket. Seperti biasa, motor saya parkir di tempat parkir ( ya iya lah, masak di tempat sampah :P ). Kami waktu itu berbelanja cukup cepat, mungkin sekitar 30 menit saja, karena waktu itu tidak ada acara untuk cuci mata atau lirik - lirik SPG :D Lagipula, saya waktu itu memang sudah ada rencana untuk melakukan kegiatan lain secepatnya (tepatnya coding :P)
Setelah selesai berbelanja, kami pun berjalan ke tempat parkir, untuk pulang. Dan bencana pun dimulai. Karena kakak saya yang mengemudikan motor, maka dia pun segera mencoba menyalakan kunci kontak, dan jreng jreng... kunci tetap tidak bisa bergerak, karena waktu itu kunci stang sedang dipasang. Alhasil, kami berdua mencoba berbagai macam cara, supaya kunci bisa dibuka, mulai dari putar putar, agak dipaksa, dll, namun kunci belum dapat dibuka. Setelah kira kira 30 menit, dan kunci belum bisa dibuka, kemudian ada niat untuk keluar dari supermarket tersebut, dengan motor yang terkunci stang :D
Karena setelah dicoba, sepertinya motor susah sekali dijalankan, meskipun cuma dituntun, akhirnya dicari jalan lain. Saya segera kembali ke supermarket tersebut, dan membeli peralatan pembuka kunci. Saya ambil tang dan obeng. Belanja kilat ini perlu waktu kira kira 10 - 15 menit (atau mungkin kurang). Setelah sampai di tempat parkir, kami coba lagi membuka kunci kontak, dan tetap tidak berhasil juga #-o
Akhirnya, 'jalan pencuri' pun terpaksa ditempuh. Ini adalah skenario terakhir. Kami buka body motor, dibuka bautnya satu per satu, kemudian, setelah sekian lama, kunci kontak pun berhasil dibuka (disini maksudnya adalah, kunci kontak dirusak), dan untuk bisa menyalakan motor, kami tinggal menghubungkan 2 kabel kontak saja, tidak perlu kunci kontak lagi :)) Benar benar terasa seperti pencuri waktu itu, bedanya, saya 'mencuri' motor milik saya sendiri :P
Akhirnya,.. kamipun pulang sampai ke rumah, dan keesokan harinya, kunci kontak saya ganti dengan yang baru :)
Saya masih sangat bersyukur, karena waktu kunci macet, saya masih berada di supermarket, jadi ada jalan untuk membeli alat pembuka kunci, dan waktu itu, saya tidak sendiri.
Bayangkan kalau waktu itu saya sedang sendiri, atau sehabis pulang kantor... I think I dont know what i will do if i met that situation :D

Selasa, Januari 24, 2006

A Little Silly Mistake

Today i got some phone call from someone who order me to make a small program on handling incoming sms. He told me that my program didn't work as expected. Damn, after doing some checking on my code, I have found that I only did a small mistake ( yes, i just misplace the argument of a function). I code using PHP, and use 1 function for 3 different case. The problem is, the argument passed to the function does really matter.
Consider the following code :
function updateFoo($foo, $bar=1, $bar2=""){}
when i gave 1 argument to the function, i will do A, when the arguments is 2, i will do B, etc
The problem happened, because i wrongly misplaced second argument, it should be placed in when condition is X, not when condition is Y.
The result, because the function is trying to update database based on the argument, the updating process is then failed, while other program expect it to be updated, otherwise the record will be processed again #-o (really silly huh.. )
Thank God that I noticed this during debugging.. :P
~a careless coder

Senin, Januari 23, 2006

Macet Day

Hari ini gw pergi ke kantor seperti biasa, sekitar jam 8 pagi, tapi... tidak seperti hari biasa, gw baru sampai di kantor jam 10 :(( Hampir di setiap jalan yg gw lewati, macet. Gw sih masih seneng, karena naik motor, masih bisa nyelip ke sela sela mobil. Kasihan banget yang naik mobil, biarpun kasihan jg gw.. soalnya hujan hujanan di jalan :P
Dari belokan tanjung barat, kemacetan langsung terasa. hampir tidak bisa bergerak, padahal biasanya disitu masih bisa ngebut :D Sampai belokan Ragunan ke arah mampang, bisa jalan sedikit lancar, sekitar 100 - 200 M, tetapi setelah itu macet lagi :( Setelah itu, keadaan tidak banyak berubah, paling banter bisa ngebut 100 M, terus macet lagi. Alhasil, sampai kantor molor 1 jam dari biasanya. Untung kantor gw baik, jd gak ada hukuman / potong potongan aneh aneh biarpun telat *jatis gitu lho >:)* Untungnya hari ini ada hiburan.. selain bisa cuci mata di kantor, seperti biasa :D, bisa juga dapat makan siang gratis. Kebetulan tadi teman lama di kantor yang lama dulu, ngajak makan siang, dan ternyata akhirnya dia yang bayarin. *thanks ya Ipot, kapan kapan makan bareng lagi :D*
Moga aja malem ini pas pulang gak hujan dan macet lagi di jalan..
Dear God, can you send the rain when i've already came to my home and I already slept at night? Thank You
*a selfish prayer*

Kamis, Januari 19, 2006

ODBC Module for gnokii-smsd

I tried to do some modification on gnokii smsd database module.
Firstly it began when I tried to build a sms handler for incoming message.
Then i want to do it in Linux / other unix based server. but then later I was told that the server will be used is MS Windows.
because i've little experience in doing programming using M$ language, then i think i must find some way to make the sms handler work in Windows environment.
After searching for many references about gnokii for windows, it seems that the smsd part cant be compiled under windows.
Actually I able to compile it under cygwin, but still... dunno why i cant use it.
Then i tried to look at the smsd source code. it seems that the program is designed to work mainly for unix based computer.
Then i looked at the database module part of gnokii smsd. It came to my mind that maybe it will be very helpful if i can write a database module which can be used for many database types. Because currently gnokii smsd support mysql and postgresql, then i think maybe ODBC will be a good choice.
Who knows that someone want to save their smses on other machine, maybe even in windows machine and using database type which hasn't been supported by smsd module (MS SQL Server maybe..)
Actually this code is just a modification from existing modules , i.e mysql and postgresql and I also looked at ODBC specification and sample code.
Because this is my early attempt to code in C, I believe that there will be many thing ugly.
I even actually cant code in C, but just did it with modification of available sample code :D
I've tested the code, it seems to work.
I can compile it under cygwin on windows and try to connect to ODBC (mysql and postgresql server on local machine) and it can connect to DB and (maybe) did the query.
Can someone capable on C coding comment on the code below.. maybe there is something wrong / harmful? Just in case you dont know what gnokii is, just check their homepage at here

/*
S M S D

A Linux/Unix tool for the mobile phones.

This file is part of gnokii.

Gnokii is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Gnokii is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with gnokii; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Copyright (C) 1999 Pavel Janík ml., Hugh Blemings
Copyright (C) 1999-2005 Jan Derfinak

This file is a module to smsd for db connection through ODBC Protocol.

*/

/* Needed for MS quasi-types */
#ifdef HAVE_WINDOWS_H
#include <windows.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <string.h>
#include <glib.h>
#include "smsd.h"
#include "gnokii.h"
#include "compat.h"

static SQLHDBC connIn;
static SQLHDBC connOut;
static SQLHENV inEnv;
static SQLHENV outEnv;

void DB_Bye (void)
{
SQLDisconnect(connIn);
SQLDisconnect(connOut);
SQLFreeHandle(SQL_HANDLE_DBC, connIn);
SQLFreeHandle(SQL_HANDLE_DBC, connOut);
SQLFreeHandle(SQL_HANDLE_ENV, inEnv);
SQLFreeHandle(SQL_HANDLE_ENV, outEnv);
}


gint DB_ConnectInbox (DBConfig connect)
{
gchar *uid = (connect.user[0] != '\0' ? connect.user : NULL);
gchar *pwd = (connect.password[0] != '\0' ? connect.password : NULL);
gchar *dsn = (connect.db != '\0' ? connect.db : NULL);
SQLRETURN retcode;
gchar stat[10];
SQLINTEGER err;
SQLSMALLINT mlen;
gchar msg[200];

if (dsn == NULL) return 1;

/*Allocate environment handle */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &inEnv);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
return 1;
}

/* Set the ODBC version environment attribute */
retcode = SQLSetEnvAttr(inEnv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLFreeHandle(SQL_HANDLE_ENV, inEnv);
return 1;
}
retcode = SQLAllocHandle(SQL_HANDLE_DBC, inEnv, &connIn);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLFreeHandle(SQL_HANDLE_ENV, inEnv);
return 1;
}
/* Set login timeout to 5 seconds. */
SQLSetConnectAttr(connIn, (void*)SQL_LOGIN_TIMEOUT, 5, 0);
retcode = SQLConnect(connIn, (SQLCHAR *) dsn, SQL_NTS, (SQLCHAR *)uid, SQL_NTS, (SQLCHAR *)pwd, SQL_NTS);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLGetDiagRec(SQL_HANDLE_DBC, connIn, 1,stat, &err, msg, 100,&amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_ENV, inEnv);
g_print (_("Connection to DSN '%s' failed.\n"), connect.db);
g_print (_("Error: %s\n"), msg);
return 1;
}
return (0);
}


gint DB_ConnectOutbox (DBConfig connect)
{
gchar *uid = connect.user[0] != '\0' ? connect.user : NULL;
gchar *pwd = connect.password[0] != '\0' ? connect.password : NULL;
gchar *dsn = connect.db != '\0' ? connect.db : NULL;
SQLRETURN retcode;
gchar stat[10];
SQLINTEGER err;
SQLSMALLINT mlen;
gchar msg[200];

if (dsn == NULL) return 1;

/*Allocate environment handle */
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &outEnv);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
return 1;
}

/* Set the ODBC version environment attribute */
retcode = SQLSetEnvAttr(outEnv, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLFreeHandle(SQL_HANDLE_ENV, outEnv);
return 1;
}
retcode = SQLAllocHandle(SQL_HANDLE_DBC, outEnv, &connOut);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLFreeHandle(SQL_HANDLE_ENV, outEnv);
return 1;
}
/* Set login timeout to 5 seconds. */
SQLSetConnectAttr(connOut, (void*)SQL_LOGIN_TIMEOUT, 5, 0);
retcode = SQLConnect(connOut, (SQLCHAR *) dsn, SQL_NTS, (SQLCHAR *)uid, SQL_NTS, (SQLCHAR *)pwd, SQL_NTS);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLGetDiagRec(SQL_HANDLE_DBC, connOut, 1,stat, &err, msg, 100,&amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_ENV, outEnv);
g_print (_("Connection to DSN '%s' failed.\n"), connect.db);
g_print (_("Error: %s\n"), msg);
return 1;
}
return (0);
}


gint DB_InsertSMS (const gn_sms * const data, const gchar * const phone)
{
GString *buf, *phnStr, *maxStr;
SQLRETURN *res;
gchar *text;
SQLHSTMT hstmt;
SQLRETURN retcode;
gchar stat[10];
SQLINTEGER err, msgId, szMsgId;
SQLSMALLINT mlen;
gchar msg[200];

if (phone[0] == '\0')
phnStr = g_string_new ("");
else
{
phnStr = g_string_sized_new (32);
g_string_sprintf (phnStr, "'%s',", phone);
}

text = strEscape (data->user_data[0].u.text);
maxStr = g_string_sized_new (32);
g_string_sprintf (maxStr, "SELECT MAX(id) from inbox");

retcode = SQLAllocHandle(SQL_HANDLE_STMT, connIn, &hstmt);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLGetDiagRec(SQL_HANDLE_DBC, connIn, 1, stat,&err, msg, 100, &amp;amp;amp;mlen);
g_print (_("Error: %s\n"), msg);
return 1;
}

retcode = SQLExecDirect(hstmt, (SQLCHAR *) maxStr->str, SQL_NTS);
g_string_free(buf, TRUE);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1,stat, &err, msg, 100, &amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
g_print (_("%d: SELECT MAX(id) from inbox failed.\n"), __LINE__);
g_print (_("Error: %s\n"), msg);
return 1;
}

if ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
SQLGetData(hstmt, 1, SQL_C_ULONG, &szMsgId, 0, &msgId);
++szMsgId;
buf = g_string_sized_new (256);
g_string_sprintf (buf, "INSERT INTO inbox (\"id\", \"number\", \"smsdate\", \"insertdate\", \"text\", %s \"processed\") VALUES ('%s', '%s', '%02d-%02d-%02d %02d:%02d:%02d+01', 'now', '%s', %s 'f')",
phone[0] != '\0' ? "\"phone\"," : "", szMsgId, data->remote.number,
data->smsc_time.year, data->smsc_time.month,
data->smsc_time.day, data->smsc_time.hour,
data->smsc_time.minute, data->smsc_time.second, text, phnStr->str);
g_free (text);
g_string_free(phnStr, TRUE);
retcode = SQLExecDirect(hstmt, (SQLCHAR *) buf->str, SQL_NTS);
g_string_free(buf, TRUE);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1,stat, &err, msg, 100, &amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
g_print (_("%d: INSERT INTO inbox failed.\n"), __LINE__);
g_print (_("Error: %s\n"), msg);
return 1;
}

return (0);
}

void DB_Look (const gchar * const phone)
{
#define DREPORT_LEN 10
#define PHONE_LEN 50
GString *buf, *phnStr;
SQLHSTMT hstmt , hstmt1;
SQLRETURN retcode;
gchar stat[10];
SQLINTEGER err, msgId, szMsgId;
SQLSMALLINT mlen;
gint numError,error;
gchar msg[200];
SQLCHAR szMsg[GN_SMS_MAX_LENGTH], szDReport[DREPORT_LEN], szPhone[PHONE_LEN];
SQLINTEGER destNumber,textMsg, dReport;
if (phone[0] == '\0')
phnStr = g_string_new ("");
else
{
phnStr = g_string_sized_new (32);
g_string_sprintf (phnStr, "AND phone = '%s'", phone);
}

buf = g_string_sized_new (128);

g_string_sprintf (buf, "SELECT id, number, text, dreport FROM outbox WHERE processed='0' AND {fn CURTIME()} >= not_before AND {fn CURTIME()} <= not_after %s", phnStr->str);
g_string_free (phnStr, TRUE);

retcode = SQLAllocHandle(SQL_HANDLE_STMT, connOut, &hstmt);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO))
{
SQLGetDiagRec(SQL_HANDLE_DBC, connOut, 1, stat,&err, msg, 100, &amp;amp;amp;mlen);
g_print (_("Error: %s\n"), msg);
return;
}

retcode = SQLExecDirect(hstmt, (SQLCHAR *) buf->str, SQL_NTS);
g_string_free(buf, TRUE);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1,stat, &err, msg, 100, &amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
g_print (_("%d: SELECT FROM outbox command failed.\n"), __LINE__);
g_print (_("Error: %s\n"), msg);
return;
}

while ((retcode = SQLFetch(hstmt)) == SQL_SUCCESS)
{
gn_sms sms;

gn_sms_default_submit (&sms);
memset (&sms.remote.number, 0, sizeof (sms.remote.number));

SQLGetData(hstmt, 1, SQL_C_ULONG, &szMsgId, 0, &msgId);
SQLGetData(hstmt, 2, SQL_C_CHAR, szPhone, PHONE_LEN, &destNumber);
SQLGetData(hstmt, 3, SQL_C_CHAR, szMsg, GN_SMS_MAX_LENGTH, &textMsg);
SQLGetData(hstmt, 4, SQL_C_CHAR, szDReport, DREPORT_LEN, &dReport);
sms.delivery_report = atoi (szDReport);

if (szPhone != NULL)
strncpy (sms.remote.number, szPhone, sizeof (sms.remote.number) - 1);
else
*sms.remote.number = '\0';
sms.remote.number[sizeof (sms.remote.number) - 1] = '\0';
if (sms.remote.number[0] == '+')
sms.remote.type = GN_GSM_NUMBER_International;
else
sms.remote.type = GN_GSM_NUMBER_Unknown;

if (szMsg != NULL)
strncpy (sms.user_data[0].u.text, szMsg, GN_SMS_MAX_LENGTH + 1);
else
*sms.user_data[0].u.text = '\0';
sms.user_data[0].u.text[GN_SMS_MAX_LENGTH] = '\0';
sms.user_data[0].length = strlen (sms.user_data[0].u.text);
sms.user_data[0].type = GN_SMS_DATA_Text;
sms.user_data[1].type = GN_SMS_DATA_None;
if (!gn_char_def_alphabet (sms.user_data[0].u.text))
sms.dcs.u.general.alphabet = GN_SMS_DCS_UCS2;

gn_log_xdebug ("Sending SMS: %s, %s\n", sms.remote.number, sms.user_data[0].u.text);

numError = 0;
do
{
error = WriteSMS (&sms);
sleep (1);
}
while ((error == GN_ERR_TIMEOUT || error == GN_ERR_FAILED) && numError++ < processed="'1'," error="'%d'," processed_date="NULL" id="'%s'" retcode =" SQLAllocHandle(SQL_HANDLE_STMT," retcode =" SQLExecDirect(hstmt1,">str, SQL_NTS);
g_string_free(buf, TRUE);
if ((retcode != SQL_SUCCESS) && (retcode != SQL_SUCCESS_WITH_INFO)) {
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt1, 1,stat, &err, msg, 100, &amp;amp;amp;mlen);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt1);
g_print (_("%d: UPDATE command failed.\n"), __LINE__);
g_print (_("Error: %s\n"), msg);
return;
}

}
g_string_free (buf, TRUE);

}

Hopefully this code will be usable :D


Senin, Januari 09, 2006

Harpitnas

Hari senin, besoknya libur pula... duh malesnya di kantor. Wish today is a holiday too 8->
Oh iya, hari ini hari kedua ke kantor naik motor. Setidaknya sekarang sudah terbebas dr bayang bayang "pejal" sewaktu naik kereta.
Bagi yg belom tahu rasanya naik kereta KRL Jabotabek, ada baiknya mencoba. Selain bagus untuk meningkatkan kewaspadaan (copetnya banyak sih :P), juga bagus untuk menjaga kelangsingan tubuh. (you can do a fee sauna at there :D)
Selama 2 hari naik motor, rasanya lebih cepat sampai ke kantor.
Tapi berhubung nggak ingin sampai ke kantor cepet cepet, mungkin besok hari bakal berangkat lebih siang dr biasanya ;))
Waktu hari pertama naik motor ke kantor, duh.. pas balik gw kesasar :))
Karena sok tahu ambil jalan, duh.. malah keterusan deh kesasarnya.. Padahal penginnya cari jalan yang baru, tapi apa daya justru kesasar. Hari ini dan seterusnya, misi harus terlaksana dengan baik :D