I suppose I should've written this with the last post, but I completely forgot. The solution is quite simple, in the end, and quite obvious if you think about it.

Firstly, I really needed to be monitoring the incoming buffer from another thread, so that I wasn't blocking the data recevied thread. That was a simple matter of throwing the CheckForIncomingMessage() function into a ThreadStart and launching it. Lastly, the PeekResponseLine() method, I needed to allow for a special case for when the new message notification turned up.

Once I'd changed these two methods, I had myself a working SMS modem driver that can send and receive messages. One of the more complex things I've done of recent.

In case you are interested, here's the modified methods:

private void CheckForIncomingMessage()
{
    while (true)
    {
        if (terminateThread.WaitOne(50, false))
            break;
        string response = PeekResponseLine();
        if (response.Contains(GsmResponses.MessageReceived))
        {
            EraseFromBuffer(response);
            int commaIndex = response.IndexOf(',');
            string messageIndexText = response.Substring(++commaIndex, response.Length - commaIndex);
            int messageIndex;
            if (int.TryParse(messageIndexText.Trim(), out messageIndex))
            {
                OnMessageReceived(messageIndex);
            }
        }
    }
}
private string PeekResponseLine()
{
    while (true)
    {
        string bufferCopy = string.Empty;
        lock (incomingBuffer)
        {
            bufferCopy = incomingBuffer;
        }
        int length = bufferCopy.IndexOf("\r\n");
        if (length > -1)
        {
            if (bufferCopy.Contains(GsmResponses.MessageTextWanted))
            {
                length = GsmResponses.MessageTextWanted.Length;
            }
            else if (bufferCopy.Contains(GsmResponses.MessageReceived))
            {
                length = bufferCopy.IndexOf("\r\n", GsmResponses.MessageReceived.Length);
                if (length > -1)
                    length += 2;
            }
            else
                length += 2;
            if (length > -1)
            {
                string response = bufferCopy.Substring(0, length);
                return response;
            }
        }
    }
}


The code fragment:

if (terminateThread.WaitOne(50, false))
    break;


is responsible for cleaning up the worker thread when the driver class is disposed. By breaking out of the infinite loop, the thread method ends and so does the thread. That's all nice and dandy. On the chance that the unpredictable happens and the thread is off with the fairies, there's this little bit of code in the Dispose() method call:

if (incomingSmsThread != null)
{
    terminateThread.Set();
    if (!incomingSmsThread.Join(500))
        incomingSmsThread.Abort();
}


I've just taken a stab at the timeout value. It's a bit too hard to predict what is reasonable, as these desktop machines are nowhere near the power of the servers that this code will ultimately run on. If the thread doesn't play nice, I smack it down.