Index: common/links/atbus.c =================================================================== RCS file: /cvsroot/gnokii/gnokii/common/links/atbus.c,v retrieving revision 1.50 diff -u -r1.50 atbus.c --- common/links/atbus.c 6 Jul 2007 19:31:06 -0000 1.50 +++ common/links/atbus.c 8 Jul 2007 18:10:53 -0000 @@ -151,7 +151,8 @@ { int error; atbus_instance *bi = AT_BUSINST(sm); - int unsolicited, count; + int unsolicited, count, messagetype; + char *start; if (!bi) return; @@ -170,10 +171,10 @@ bi->rbuf_pos = 1; bi->rbuf[1] = '\0'; } + unsolicited = 0; if (bi->rbuf_pos > 4 && !strncmp(bi->rbuf + bi->rbuf_pos - 2, "\r\n", 2)) { /* try to find previous */ - char *start = findcrlfbw(bi->rbuf + bi->rbuf_pos - 2, bi->rbuf_pos - 1); - unsolicited = 0; + start = findcrlfbw(bi->rbuf + bi->rbuf_pos - 2, bi->rbuf_pos - 1); /* if not found, start at buffer beginning */ if (!start) start = bi->rbuf+1; @@ -191,23 +192,13 @@ bi->rbuf[0] = GN_AT_CME; bi->rbuf[1] = error / 256; bi->rbuf[2] = error % 256; - } else if (!strncmp(start, "RING", 4)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start, "CONNECT", 7)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start, "BUSY", 4)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start, "NO ANSWER", 9)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start, "NO CARRIER", 10)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start, "NO DIALTONE", 11)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); + } else if (!strncmp(start, "RING", 4) || + !strncmp(start, "CONNECT", 7) || + !strncmp(start, "BUSY", 4) || + !strncmp(start, "NO ANSWER", 9) || + !strncmp(start, "NO CARRIER", 10) || + !strncmp(start, "NO DIALTONE", 11)) { + bi->rbuf[0] = GN_OP_AT_Ring; unsolicited = 1; } else if (*start == '+') { /* check for possible unsolicited responses */ @@ -217,30 +208,29 @@ unsolicited = 1; } else if (!strncmp(start + 1, "CPIN:", 5)) bi->rbuf[0] = GN_AT_OK; - else if (!strncmp(start + 1, "CRING:", 6)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); - unsolicited = 1; - } else if (!strncmp(start + 1, "CLIP:", 5)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); + else if (!strncmp(start + 1, "CRING:", 6) || + !strncmp(start + 1, "CLIP:", 5) || + !strncmp(start + 1, "CLCC:", 5)) { + bi->rbuf[0] = GN_OP_AT_Ring; unsolicited = 1; - } else if (!strncmp(start + 1, "CLCC:", 5)) { - sm_incoming_function(GN_OP_AT_Ring, start, bi->rbuf_pos - 1 - (start - bi->rbuf), sm); + } else if (!strncmp(start + 1, "CMTI:", 5)) { + bi->rbuf[0] = GN_OP_AT_IncomingSMS; unsolicited = 1; } } - if (unsolicited) { - *start = '\0'; - bi->rbuf_pos = start - bi->rbuf; - } } /* check if SMS prompt is found */ if (bi->rbuf_pos > 4 && !strncmp(bi->rbuf + bi->rbuf_pos - 4, "\r\n> ", 4)) bi->rbuf[0] = GN_AT_PROMPT; if (bi->rbuf[0] != GN_AT_NONE) { + int rbuf_pos = bi->rbuf_pos; at_dprintf("read : ", bi->rbuf + 1, bi->rbuf_pos - 1); - sm_incoming_function(sm->last_msg_type, bi->rbuf, bi->rbuf_pos - 1, sm); bi->rbuf_pos = 1; bi->binlen = 1; + if (unsolicited) + sm_incoming_function(bi->rbuf[0], start, rbuf_pos - 1 - (start - bi->rbuf), sm); + else + sm_incoming_function(sm->last_msg_type, bi->rbuf, rbuf_pos - 1, sm); return; } #if 0 Index: common/phones/atgen.c =================================================================== RCS file: /cvsroot/gnokii/gnokii/common/phones/atgen.c,v retrieving revision 1.150 diff -u -r1.150 atgen.c --- common/phones/atgen.c 7 Jul 2007 12:01:19 -0000 1.150 +++ common/phones/atgen.c 8 Jul 2007 18:10:56 -0000 @@ -77,6 +77,8 @@ static gn_error ReplyRing(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); static gn_error ReplyGetDateTime(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); static gn_error ReplyGetActiveCalls(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); +static gn_error ReplyIncomingSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); +static gn_error ReplyGetSMSMemorySize(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state); static gn_error AT_Identify(gn_data *data, struct gn_statemachine *state); static gn_error AT_GetModel(gn_data *data, struct gn_statemachine *state); @@ -114,6 +116,8 @@ static gn_error AT_GetDateTime(gn_data *data, struct gn_statemachine *state); static gn_error AT_SendDTMF(gn_data *data, struct gn_statemachine *state); static gn_error AT_GetActiveCalls(gn_data *data, struct gn_statemachine *state); +static gn_error AT_OnSMS(gn_data *data, struct gn_statemachine *state); +static gn_error AT_GetSMSMemorySize(gn_data *data, struct gn_statemachine *state); typedef struct { int gop; @@ -163,6 +167,9 @@ { GN_OP_GetDateTime, AT_GetDateTime, ReplyGetDateTime }, { GN_OP_SendDTMF, AT_SendDTMF, Reply }, { GN_OP_GetActiveCalls, AT_GetActiveCalls, ReplyGetActiveCalls }, + { GN_OP_OnSMS, AT_OnSMS, Reply }, + { GN_OP_AT_IncomingSMS, NULL, ReplyIncomingSMS }, + { GN_OP_AT_GetSMSMemorySize, AT_GetSMSMemorySize, ReplyGetSMSMemorySize }, }; char *strip_quotes(char *s) @@ -1243,6 +1250,29 @@ return sm_block_no_retry(GN_OP_GetActiveCalls, data, state); } +static gn_error AT_OnSMS(gn_data *data, struct gn_statemachine *state) +{ + gn_error error; + + if (sm_message_send(12, GN_OP_OnSMS, "AT+CNMI=2,1\r", state)) + return GN_ERR_NOTREADY; + + error = sm_block_no_retry(GN_OP_OnSMS, data, state); + if (error == GN_ERR_NONE) { + AT_DRVINST(state)->on_sms = data->on_sms; + AT_DRVINST(state)->sms_callback_data = data->callback_data; + } + return error; +} + +static gn_error AT_GetSMSMemorySize(gn_data *data, struct gn_statemachine *state) +{ + if (sm_message_send(18, GN_OP_AT_GetSMSMemorySize, "AT+CPMS=\"ME\",\"SM\"\r", state)) + return GN_ERR_NOTREADY; + + return sm_block_no_retry(GN_OP_AT_GetSMSMemorySize, data, state); +} + static gn_error ReplyReadPhonebook(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state) { at_driver_instance *drvinst = AT_DRVINST(state); @@ -2002,6 +2032,93 @@ return GN_ERR_UNSOLICITED; } +static gn_error ReplyIncomingSMS(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state) +{ + at_driver_instance *drvinst = AT_DRVINST(state); + at_line_buffer buf; + char *memory, *pos; + int index, i; + gn_memory_type mem; + int freesms = 0; + gn_error error = GN_ERR_NONE; + + if (!drvinst->on_sms) + return GN_ERR_UNSOLICITED; + + buf.line1 = buffer; + buf.length= length; + splitlines(&buf); + + mem = GN_MT_XX; + + if (strncmp(buf.line1, "+CMTI: ", 7)) + return GN_ERR_UNSOLICITED; + + pos = strrchr(buf.line1, ','); + if (pos == NULL) + return GN_ERR_UNSOLICITED; + pos[0] = '\0'; + pos++; + index = atoi(pos); + + memory = strip_quotes(buf.line1 + 7); + if (memory == NULL) + return GN_ERR_UNSOLICITED; + for (i = 0; i < NR_MEMORIES; i++) { + if (!strcmp(memory, memorynames[i])) { + mem = i; + break; + } + } + + if (mem == GN_MT_XX) + return GN_ERR_UNSOLICITED; + + /* Ugly workaround for at least Nokia behaviour. Reply is of form: + * +CMTI: , + * is the memory where the message is stored and can be "ME" or "SM". + * is a place in "MT" memory which consists of "SM" and "ME". + * order is that "SM" memory goes first, "ME" memory goes second. + * So if the memory is "ME" we need to substract from size of "SM" + * memory to get the location (we cannot read from "MT" memory + */ + dprintf("A %d %d\n", mem, GN_MT_ME); + if (mem == GN_MT_ME) { + dprintf("B %d %d\n", drvinst->smmemorysize, index); + if (drvinst->smmemorysize < 0) + error = AT_GetSMSMemorySize(data, state); + dprintf("C %d %d\n", drvinst->smmemorysize, index); + /* ignore errors */ + if ((error == GN_ERR_NONE) && (index > drvinst->smmemorysize)) + index -= drvinst->smmemorysize; + dprintf("D %d %d\n", drvinst->smmemorysize, index); + } + + dprintf("Received message folder %s index %d\n", memorynames[mem], index); + + if (!data->sms) { + freesms = 1; + data->sms = calloc(1, sizeof(gn_sms)); + if (!data->sms) + return GN_ERR_INTERNALERROR; + } + + memset(data->sms, 0, sizeof(gn_sms)); + data->sms->memory_type = mem; + data->sms->number = index; + + error = gn_sms_get(data, state); + if (error == GN_ERR_NONE) { + error = GN_ERR_UNSOLICITED; + drvinst->on_sms(data->sms, state, drvinst->sms_callback_data); + } + + if (freesms) + free(data->sms); + + return error; +} + static gn_error ReplyGetNetworkInfo(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state) { at_driver_instance *drvinst = AT_DRVINST(state); @@ -2201,6 +2318,29 @@ return GN_ERR_NONE; } +static gn_error ReplyGetSMSMemorySize(int messagetype, unsigned char *buffer, int length, gn_data *data, struct gn_statemachine *state) +{ + at_driver_instance *drvinst = AT_DRVINST(state); + at_line_buffer buf; + gn_error error; + + if ((error = at_error_get(buffer, state)) != GN_ERR_NONE) + return error; + + buf.line1 = buffer + 1; + buf.length = length; + splitlines(&buf); + + dprintf("1: %s\n", buf.line1); + dprintf("2: %s\n", buf.line2); + if (sscanf(buf.line2, "+CPMS: %*d,%d,%*d,%d", &drvinst->mememorysize, &drvinst->smmemorysize) != 2) + return GN_ERR_FAILED; + dprintf("saved sizes: %d %d\n", drvinst->mememorysize, drvinst->smmemorysize); + drvinst->smsmemorytype = GN_MT_ME; + + return GN_ERR_NONE; +} + /* General reply function for phone responses. buffer[0] holds the compiled * success of the result (OK, ERROR, ... ). see links/atbus.h and links/atbus.c * for reference */ @@ -2250,6 +2390,8 @@ drvinst->last_call_type = GN_CALL_Voice; drvinst->last_call_status = GN_CALL_Idle; drvinst->prev_state = GN_CALL_Idle; + drvinst->mememorysize = -1; + drvinst->smmemorysize = -1; drvinst->if_pos = 0; for (i = 0; i < GN_OP_AT_Max; i++) { Index: include/phones/atgen.h =================================================================== RCS file: /cvsroot/gnokii/gnokii/include/phones/atgen.h,v retrieving revision 1.27 diff -u -r1.27 atgen.h --- include/phones/atgen.h 7 Jul 2007 12:21:21 -0000 1.27 +++ include/phones/atgen.h 8 Jul 2007 18:10:58 -0000 @@ -45,6 +45,8 @@ GN_OP_AT_Prompt, GN_OP_AT_GetMemoryRange, GN_OP_AT_Ring, + GN_OP_AT_IncomingSMS, + GN_OP_AT_GetSMSMemorySize, GN_OP_AT_Max /* don't append anything after this entry */ } at_operation; @@ -72,6 +74,7 @@ int if_pos; int no_smsc; + /* CBPS (phonebook related) */ gn_memory_type memorytype; int memoryoffset; int memorysize; @@ -80,6 +83,10 @@ at_charset defaultcharset; at_charset charset; + /* CPMS (sms related) */ + int smmemorysize; + int mememorysize; + /* For call notifications via AT+CLIP */ int clip_supported; gn_call_type last_call_type;