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