Click here to Skip to main content
15,912,977 members
Articles / Programming Languages / C#

How To Send and Receive SMS using GSM Modem

Rate me:
Please Sign up or sign in to vote.
4.89/5 (146 votes)
2 Mar 2016CPOL6 min read 3.9M   100.8K   495   1.1K
SMS Client - Server Software is used for sending, reading, deleting messages. It uses GSM modem for sending SMS. It listens for incoming messages to arrive, processes the read message and takes action accordingly. This SMS software requires GSMComm Library which you can also download.

Screenshot - MainScreen.jpg

Note - As of today (03/15/2015), I am deprecating this article in favor of a reliable way of managing SMS without the need for thirdparty libraries like GSMComm. Please feel free to have a look into the below article.

Introduction

SMS client and server is an application software which is used for sending and receiving messages(SMS). It listens for incoming messages to arrive, processes the message if it's in a valid format. Note the processing of arrived messages depends on the application which will be discussed later. I am going to explain the following things:

  1. Communication Port Settings
  2. Receive Incoming Message
  3. Send Messages
  4. Read All Messages (Sent by the users)
  5. Delete Messages (One or All)

I have used the GSMComm Library for Sending and Receiving SMS. You require a GSM modem or phone for sending an SMS.

Using the code

1) Communication Port Settings

Screenshot - CommSettings.jpg

CommSetting class is used for storing comm port settings:

C#
public class CommSetting
{
    public static int Comm_Port=0;
    public static Int64 Comm_BaudRate=0;
    public static Int64 Comm_TimeOut=0;
    public static GsmCommMain comm;

    public CommSetting()
    {
        //
        // TODO: Add constructor logic here
        //
    }
}

Comm is an object of type GsmCommMain which is required for sending and receiving messages. We have to set the Comm port, Baud rate and time out for our comm object of type GsmCommMain. Then try to open with the above settings. We can test the Comm port settings by clicking on the Test button after selecting the Comm port, baud rate and Time out. Sometimes if the comm port is unable to open, you will get a message "No phone connected". This is mainly due to Baud rate settings. Change the baud rate and check again by clicking the Test button until you get a message "Successfully connected to the phone."

Before creating a GSMComm object with settings, we need to validate the port number, baud rate and Timeout.

The EnterNewSettings() does validation, returns true if valid, and will invoke SetData(port,baud,timeout) for comm setting.

The following block of code will try to connect. If any problem occurs "Phone not connected" message appears and you can either retry by clicking on the Retry button or else Cancel.

C#
GsmCommMain comm = new GsmCommMain(port, baudRate, timeout);
try
{
        comm.Open();
        while (!comm.IsConnected())
        {
            Cursor.Current = Cursors.Default;
            if (MessageBox.Show(this, "No phone connected.",
               "Connection setup", MessageBoxButtons.RetryCancel,
                 MessageBoxIcon.Exclamation) == DialogResult.Cancel)
            {
                comm.Close();
                return;
            }
            Cursor.Current = Cursors.WaitCursor;
        }

        // Close Comm port connection (Since it's just for testing
        // connection)
        comm.Close();
}
catch(Exception ex)
{
    MessageBox.Show(this, "Connection error: " + ex.Message,
    "Connection setup", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    return;
}

// display message if connection is a success.
MessageBox.Show(this, "Successfully connected to the phone.",
"Connection setup", MessageBoxButtons.OK, MessageBoxIcon.Information);

Screenshot - SucessfullyConnected.jpg

2) Receive Incoming Message

We are going to register the following events for GSMComm object comm.

  1. PhoneConnected
    This event is invoked when you try to open the Comm port. The event handler for Phone connected is comm_PhoneConnected which will invoke OnPhoneConnectionChange(bool connected) with the help of Delegate ConnectedHandler.
  2. MessageReceived
    This event is invoked when a message arrives at the GSM phone. We will register with MessageReceivedEventHandler. When the incoming message arrives, the comm_MessageReceived method will be invoked which in turn calls the MessageReceived() method in order to process the unread message. GSMComm object comm has a method ReadMessages which will be used for reading messages. It accepts the following parameters phone status (All, ReceivedRead, ReceivedUnread, StoredSent, and StoredUnsent) and storage type: SIM memory or Phone memory.
C#
private void MessageReceived()
{
    Cursor.Current = Cursors.WaitCursor;
    string storage = GetMessageStorage();
    DecodedShortMessage[] messages = CommSetting.comm.ReadMessages
                   (PhoneMessageStatus.ReceivedUnread, storage);
    foreach(DecodedShortMessage message in messages)
    {
         Output(string.Format("Message status = {0},
     Location =  {1}/{2}",
         StatusToString(message.Status),
         message.Storage, message.Index));
         ShowMessage(message.Data);
         Output("");
    }

    Output(string.Format("{0,9} messages read.",
                messages.Length.ToString()));
    Output("");
}   

The above code will read all unread messages from SIM memory. The method ShowMessage is used for displaying the read message. The message may be a status report, stored message sent/un sent, or a received message.

3) Send Message

Screenshot - SendSMS.jpg

You can send an SMS by keying in the destination phone number and text message.

If you want to send a message in your native language (Unicode), you need to check in Send as Unicode(UCS2). GSMComm object comm has a SendMessage method which will be used for sending SMS to any phone. Create a PDU for sending messages. We can create a PDU in straight forward version as:

C#
SmsSubmitPdu pdu = new SmsSubmitPdu
        (txt_message.Text,txt_destination_numbers.Text,"");

An extended version of PDU is used when you are sending a message in Unicode.

C#
 try
{
    // Send an SMS message
    SmsSubmitPdu pdu;
    bool alert = chkAlert.Checked;
    bool unicode = chkUnicode.Checked;

    if (!alert && !unicode)
    {
        // The straightforward version
        pdu = new SmsSubmitPdu
        (txt_message.Text, txt_destination_numbers.Text,"");
    }
    else
    {
        // The extended version with dcs
        byte dcs;
        if (!alert && unicode)
            dcs = DataCodingScheme.NoClass_16Bit;
        else
        if (alert && !unicode)
            dcs = DataCodingScheme.Class0_7Bit;
        else
        if (alert && unicode)
            dcs = DataCodingScheme.Class0_16Bit;
        else
            dcs = DataCodingScheme.NoClass_7Bit;

        pdu = new SmsSubmitPdu
        (txt_message.Text, txt_destination_numbers.Text, "", dcs);
    }

    // Send the same message multiple times if this is set
        int times = chkMultipleTimes.Checked ?
                int.Parse(txtSendTimes.Text) : 1;

    // Send the message the specified number of times
    for (int i=0;i<times;i++)
    {
        CommSetting.comm.SendMessage(pdu);
        Output("Message {0} of {1} sent.", i+1, times);
        Output("");
    }
}
catch(Exception ex)
{
    MessageBox.Show(ex.Message);
}

Cursor.Current = Cursors.Default;

4) Read All Messages

Screenshot - ReadAllMessages.jpg

You can read all messages from the phone memory of SIM memory. Just click on "Read All Messages" button. The message details such as sender, date-time, text message will be displayed on the Data Grid. Create a new row for each read message, add to Data table and assign the Data table to datagrid's source

C#
private void BindGrid(SmsPdu pdu)
{
    DataRow dr=dt.NewRow();
    SmsDeliverPdu data = (SmsDeliverPdu)pdu;

    dr[0]=data.OriginatingAddress.ToString();
    dr[1]=data.SCTimestamp.ToString();
    dr[2]=data.UserDataText;
    dt.Rows.Add(dr);

    dataGrid1.DataSource=dt;
}

The above code will read all unread messages from SIM memory. The method ShowMessage is used for displaying the read message. The message may be a status report, stored message sent/un sent, or a received message. The only change in processing Received message and Read message is the first parameter.

For received message

C#
DecodedShortMessage[] messages =
  CommSetting.comm.ReadMessages(PhoneMessageStatus.ReceivedUnread, storage);

For read all messages

C#
DecodedShortMessage[] messages =
   CommSetting.comm.ReadMessages(PhoneMessageStatus.All, storage);

5) Delete Messages (One or All)

Screenshot - DeleteMessage.jpg

All messages which are sent by the users will be stored in SIM memory and we are going to display them in the Data grid. We can delete a single message by specifying the message index number. We can delete all messages from SIM memory by clicking on "Delete All" button. Messages are deleted based on the index. Every message will be stored in memory with a unique index.

The following code will delete a message based on index:

C#
// Delete the message with the specified index from storage
CommSetting.comm.DeleteMessage(index, storage);

To delete all messages from memory( SIM/Phone)

C#
// Delete all messages from phone memory
CommSetting.comm.DeleteMessages(DeleteScope.All, storage); 

The DeleteScope is an Enum which contains:

  1. All
  2. Read
  3. ReadAndSent
  4. ReadSentAndUnsent

Applications

Here are some interesting applications where you can use and modify this software.

1) Pre paid Electricity

Scenario (Customer)

The customer has agreed for pre paid electricity recharges with the help of recharge coupons. The coupon is made available at shops. The customer will first buy the coupons from shops; every coupon consists of Coupon PIN which will be masked, the customer needs to scratch to view the PIN number. The customer will send an SMS to the SMS Server with a specified message format for recharging.

Message Format for Recharging:
RECHARGE <Coupon No> <Customer ID>

Scenario (Server Database)

On the Server, the Database consists of Customer information along with his telephone number, there will a field named Amount which will be used and updated when the customer recharged with some amount. This application becomes somewhat complex, an automatic meter reading software along with hardware needs to be integrated with this. Automatic meter reading systems will read all meter readings and calculate the amount to be deducted for the customer.

2) Astrology

You can implement as astrology software. The user will send an SMS with his zodiac sign. The SMS server will maintain an Astrology Database with zodiac sign and a text description which contains a message for the day. The Database is required to be updated daily for all zodiac signs.

Message Format which will be used by the user to get message of the day:
Zodiac Sign

3) Remote Controlling System

We can implement a remote controlling system, for example you need to:

  1. Shutdown
  2. Restart
  3. Log off system

You can send an SMS. The SMS server will listen and then process the message. Based on the message format sent by the user we can take action.
Example if message format is:
SHUTDOWN
Send to SMS phone number.

Conclusion

This project wouldn't be completed unless I thank the GSMComm Lib developer "Stefan Mayr". I customized my application using this Library. You can download the sample project, library from the web link which I provided under the Reference section.

Reference

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Profile

Around 10 years of professional software development experience in analysis, design, development, testing and implementation of enterprise web applications for healthcare domain with good exposure to object-oriented design, software architectures, design patterns, test-driven development and agile practices.

In Brief

Analyse and create High Level , Detailed Design documents.
Use UML Modelling and create Use Cases , Class Diagram , Component Model , Deployment Diagram, Sequence Diagram in HLD.

Area of Working : Dedicated to Microsoft .NET Technologies
Experience with : C# , J2EE , J2ME, Windows Phone 8, Windows Store App
Proficient in: C# , XML , XHTML, XML, HTML5, Javascript, Jquery, CSS, SQL, LINQ, EF

Software Development

Database: Microsoft SQL Server, FoxPro
Development Frameworks: Microsoft .NET 1.1, 2.0, 3.5, 4.5
UI: Windows Forms, Windows Presentation Foundation, ASP.NET Web Forms and ASP.NET MVC3, MVC4
Coding: WinForm , Web Development, Windows Phone, WinRT Programming, WCF, WebAPI

Healthcare Domain Experience

CCD, CCR, QRDA, HIE, HL7 V3, Healthcare Interoperability

Education

B.E (Computer Science)

CodeProject Contest So Far:

1. Windows Azure Developer Contest - HealthReunion - A Windows Azure based healthcare product , link - http://www.codeproject.com/Articles/582535/HealthReunion-A-Windows-Azure-based-healthcare-pro

2. DnB Developer Contest - DNB Business Lookup and Analytics , link - http://www.codeproject.com/Articles/618344/DNB-Business-Lookup-and-Analytics

3. Intel Ultrabook Contest - Journey from development, code signing to publishing my App to Intel AppUp , link - http://www.codeproject.com/Articles/517482/Journey-from-development-code-signing-to-publishin

4. Intel App Innovation Contest 2013 - eHealthCare

5. Grand Prize Winner of CodeProject HTML5 &CSS3 Article Contest 2014

6. Grand Prize Winner of CodeProject Android Article Contest 2014

7. Grand Prize Winner of IOT on Azure Contest 2015

Comments and Discussions

 
GeneralRe: 2 simple but most asked questions Pin
phuong oanh23-Jul-08 4:41
phuong oanh23-Jul-08 4:41 
GeneralRe: 2 simple but most asked questions Pin
Member 1207984(klsheng)23-Jul-08 5:02
Member 1207984(klsheng)23-Jul-08 5:02 
GeneralRe: 2 simple but most asked questions Pin
phuong oanh23-Jul-08 18:30
phuong oanh23-Jul-08 18:30 
GeneralRe: 2 simple but most asked questions Pin
Member 1207984(klsheng)24-Jul-08 5:48
Member 1207984(klsheng)24-Jul-08 5:48 
GeneralRe: 2 simple but most asked questions Pin
phuong oanh24-Jul-08 7:33
phuong oanh24-Jul-08 7:33 
GeneralRe: 2 simple but most asked questions Pin
phuong oanh24-Jul-08 21:21
phuong oanh24-Jul-08 21:21 
QuestionWhat about Flow Control Settings Pin
itsnomihere16-Jul-08 8:49
itsnomihere16-Jul-08 8:49 
AnswerRe: What about Flow Control Settings Pin
phuong oanh16-Jul-08 17:56
phuong oanh16-Jul-08 17:56 
Hi,

I send to you a sample code control RS232 with flow control. You have to use DLL function. Block code i control UPS from RS232, which is a part of my project as: send and receive SMS then control UPS if power off.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Collections;
using System.Windows;
using System.Data;
using MySql.Data;


namespace SMS_AGU.Controller
{
    /// <summary>
    /// Control UPS with Win32 API
    /// </summary>
    public class SerialPort
    {
        public int PortNum;
        int m_port;
        public int BaudRate = 9600;
        public byte ByteSize = 8;
        public byte Parity = 0; // 0-4=no,odd,even,mark,space
        public byte StopBits = 0; // 0,1,2 = 1, 1.5, 2
        public int ReadTimeout = 1500;

        //comm port win32 file handle
        public int hComm = -1;

        public bool Opened = false;

        //win32 api constants
        private const uint GENERIC_READ = 0x80000000;
        private const uint GENERIC_WRITE = 0x40000000;
        private const int OPEN_EXISTING = 3;
        private const int INVALID_HANDLE_VALUE = -1;
        
        /// <summary>
        /// Get port connect with UPS
        /// </summary>
        /// <returns></returns>
        public int PortUPS()
        {
            Port p=new Port();
            DataTable dt_port = p.Get_Port();
            DataRow dr_port = dt_port.NewRow();
            for (int i = 0; i < dt_port.Rows.Count; i++)
            {
                m_port = int.Parse(dt_port.Rows[i][0].ToString());
                string connectPhone = dt_port.Rows[i][2].ToString();
                if (connectPhone == "UPS")
                {
                    PortNum = m_port;
                   
                   
     
                }
                break;
            }
            return PortNum;
         }
        /// <summary>
        /// struct for Win32 API
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct DCB
        {
            public int DCBlength; // sizeof(DCB)
            public int BaudRate; // current baud rate
            public int fBinary; // binary mode, no EOF check
            public int fParity; // enable parity checking
            public int fOutxCtsFlow; // CTS output flow control
            public int fOutxDsrFlow; // DSR output flow control
            public int fDtrControl; // DTR flow control type
            public int fDsrSensitivity; // DSR sensitivity
            public int fTXContinueOnXoff; // XOFF continues Tx
            public int fOutX; // XON/XOFF out flow control
            public int fInX; // XON/XOFF in flow control
            public int fErrorChar; // enable error replacement
            public int fNull; // enable null stripping
            public int fRtsControl; // RTS flow control
            public int fAbortOnError; // abort on error
            public int fDummy2; // reserved

            public uint flags;
            public ushort wReserved; // not currently used
            public ushort XonLim; // transmit XON threshold
            public ushort XoffLim; // transmit XOFF threshold
            public byte ByteSize; // number of bits/byte, 4-8
            public byte Parity; // 0-4=no,odd,even,mark,space
            public byte StopBits; // 0,1,2 = 1, 1.5, 2
            public char XonChar; // Tx and Rx XON character
            public char XoffChar; // Tx and Rx XOFF character
            public char ErrorChar; // error replacement character
            public char EofChar; // end of input character
            public char EvtChar; // received event character
            public ushort wReserved1; // reserved; do not use
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;
            public int ReadTotalTimeoutMultiplier;
            public int ReadTotalTimeoutConstant;
            public int WriteTotalTimeoutMultiplier;
            public int WriteTotalTimeoutConstant;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }

        [DllImport("kernel32.dll")]
        private static extern int CreateFile(
        string lpFileName, // file name
        uint dwDesiredAccess, // access mode
        int dwShareMode, // share mode
        int lpSecurityAttributes, // SD
        int dwCreationDisposition, // how to create
        int dwFlagsAndAttributes, // file attributes
        int hTemplateFile // handle to template file
        );
        [DllImport("kernel32.dll")]
        private static extern bool GetCommState(
        int hFile, // handle to communications device
        ref DCB lpDCB // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool GetCommModemStatus(
        int hFile, // handle to communications device
        ref int d // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool BuildCommDCB(
        string lpDef, // device-control string
        ref DCB lpDCB // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool SetCommState(
        int hFile, // handle to communications device
        ref DCB lpDCB // device-control block
        );
        [DllImport("kernel32.dll")]
        private static extern bool GetCommTimeouts(
        int hFile, // handle to comm device
        ref COMMTIMEOUTS lpCommTimeouts // time-out values
        );
        [DllImport("kernel32.dll")]
        private static extern bool SetCommTimeouts(
        int hFile, // handle to comm device
        ref COMMTIMEOUTS lpCommTimeouts // time-out values
        );
       
        [DllImport("kernel32.dll")]
        
        private static extern bool ReadFile(
        int hFile, // handle to file
        byte[] lpBuffer, // data buffer
        int nNumberOfBytesToRead, // number of bytes to read
        ref int lpNumberOfBytesRead, // number of bytes read
        ref OVERLAPPED lpOverlapped // overlapped buffer
        
            );
        
        [DllImport("kernel32.dll")]
        
        private static extern bool WriteFile(
        int hFile, // handle to file
        byte[] lpBuffer, // data buffer
        int nNumberOfBytesToWrite, // number of bytes to write
        ref int lpNumberOfBytesWritten, // number of bytes written
        ref OVERLAPPED lpOverlapped // overlapped buffer
        );
        
        [DllImport("kernel32.dll")]
        private static extern bool CloseHandle(
        int hObject // handle to object
        );
        
        [DllImport("kernel32.dll")]
        
        private static extern uint GetLastError();

        public void Open()
        {

            DCB dcbCommPort = new DCB();
            COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
            // OPEN THE COMM PORT.
            hComm = CreateFile("COM" + this.PortUPS(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);

            // IF THE PORT CANNOT BE OPENED, BAIL OUT.
            if (hComm == INVALID_HANDLE_VALUE)
            {
                throw (new ApplicationException("Comm Port Can Not Be Opened"));
            }
            // SET THE COMM TIMEOUTS.

            GetCommTimeouts(hComm, ref ctoCommPort);
            ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            SetCommTimeouts(hComm, ref ctoCommPort);

            // SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
            GetCommState(hComm, ref dcbCommPort);


            dcbCommPort.BaudRate = BaudRate;
            dcbCommPort.flags = 0;
            //dcb.fBinary=1;
            dcbCommPort.flags |= 1;
            if (Parity > 0)
            {
                //dcb.fParity=1
                dcbCommPort.flags |= 2;
            }
            dcbCommPort.Parity = Parity;
            dcbCommPort.ByteSize = ByteSize;
            dcbCommPort.StopBits = StopBits;
            if (!SetCommState(hComm, ref dcbCommPort))
            {
                //uint ErrorNum=GetLastError();
                throw (new ApplicationException("Comm Port Can Not Be Opened"));
            }

            Opened = true;

        }

        public void SetRTS(int v)
        {
            DCB d = new DCB();
            GetCommState(hComm, ref d);
            d.fRtsControl = v;
            SetCommState(hComm, ref d);
        }

        public int GetDSR()
        {
            int dp = 0;
            GetCommModemStatus(hComm, ref dp);
            return dp;
        }


        public void Close()
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hComm);
            }
        }

        public byte[] Read(int NumBytes)
        {
            byte[] BufBytes;
            byte[] OutBytes;
            BufBytes = new byte[NumBytes];
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesRead = 0;
                ReadFile(hComm, BufBytes, NumBytes, ref BytesRead, ref ovlCommPort);
                OutBytes = new byte[BytesRead];
                Array.Copy(BufBytes, OutBytes, BytesRead);
            }
            else
            {
                throw (new ApplicationException("Comm Port Not Open"));
            }
            return OutBytes;
        }


        public void Write(byte[] WriteBytes)
        {
            if (hComm != INVALID_HANDLE_VALUE)
            {
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                int BytesWritten = 0;
                WriteFile(hComm, WriteBytes, WriteBytes.Length, ref BytesWritten, ref ovlCommPort);
            }
            else
            {
                throw (new ApplicationException("Comm Port Not Open"));
            }
        }
    }
}


Thanks
GeneralRe: What about Flow Control Settings Pin
itsnomihere17-Jul-08 9:15
itsnomihere17-Jul-08 9:15 
GeneralRe: What about Flow Control Settings Pin
itsnomihere17-Jul-08 9:15
itsnomihere17-Jul-08 9:15 
GeneralRe: What about Flow Control Settings Pin
phuong oanh17-Jul-08 16:44
phuong oanh17-Jul-08 16:44 
GeneralRe: What about Flow Control Settings_Include Port class Pin
phuong oanh18-Jul-08 7:00
phuong oanh18-Jul-08 7:00 
GeneralHelp how to add new AT command using GSMComm [modified] Pin
nteng1412-Jul-08 5:07
nteng1412-Jul-08 5:07 
GeneralRe: How to add new AT command using GSMComm Pin
nteng1413-Jul-08 21:26
nteng1413-Jul-08 21:26 
GeneralRe: Help how to add new AT command using GSMComm Pin
nteng1410-Aug-08 17:52
nteng1410-Aug-08 17:52 
GeneralRe: Help how to add new AT command using GSMComm Pin
Tom Saddul1-Aug-09 9:43
Tom Saddul1-Aug-09 9:43 
GeneralSending long smses Pin
samMaster11-Jul-08 20:23
samMaster11-Jul-08 20:23 
GeneralRe: Sending long smses Pin
phuong oanh11-Jul-08 21:55
phuong oanh11-Jul-08 21:55 
GeneralRe: Sending long smses Pin
samMaster12-Jul-08 3:10
samMaster12-Jul-08 3:10 
GeneralRe: Sending long smses Pin
samMaster12-Jul-08 18:22
samMaster12-Jul-08 18:22 
GeneralRe: Sending long smses Pin
phuong oanh14-Jul-08 3:50
phuong oanh14-Jul-08 3:50 
GeneralRe: Sending long smses Pin
samMaster14-Jul-08 22:17
samMaster14-Jul-08 22:17 
GeneralRe: Sending long smses Pin
phuong oanh16-Jul-08 6:16
phuong oanh16-Jul-08 6:16 
GeneralRe: Sending long smses Pin
Orestis Spanos14-Oct-08 12:44
Orestis Spanos14-Oct-08 12:44 
GeneralRe: Sending long smses Pin
samMaster15-Jul-08 21:03
samMaster15-Jul-08 21:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.