/* Parser for DIR sub mode of SMS interactive mode. */ void gn_atem_dir_parse(char *buff) { switch (toupper(*buff)) { case 'P': SMSNumber--; gn_atem_sms_handle(); return; case 'N': SMSNumber++; gn_atem_sms_handle(); return; case 'D': data.sms->memory_type = SMSType; data.sms->number = SMSNumber; if (gn_sm_functions(GN_OP_DeleteSMS, &data, sm) == GN_ERR_NONE) { gn_atem_modem_result(MR_OK); } else { gn_atem_modem_result(MR_ERROR); } return; case 'Q': Parser= gn_atem_sms_parse; gn_atem_modem_result(MR_OK); return; } gn_atem_modem_result(MR_ERROR); }
/* Parser for entering message content (+CMGS) */ void gn_atem_sms_parseText(char *buff) { static int index = 0; int i, length; char buffer[MAX_LINE_LENGTH]; gn_error error; length = strlen(buff); sms.user_data[0].type = GN_SMS_DATA_Text; for (i = 0; i < length; i++) { if (buff[i] == ModemRegisters[REG_CTRLZ]) { /* Exit SMS text mode with sending */ sms.user_data[0].u.text[index] = 0; sms.user_data[0].length = index; index = 0; Parser = gn_atem_at_parse; dprintf("Sending SMS to %s (text: %s)\n", data.sms->remote.number, data.sms->user_data[0].u.text); /* FIXME: set more SMS fields before sending */ error = gn_sms_send(&data, sm); if (error == GN_ERR_NONE) { gsprintf(buffer, MAX_LINE_LENGTH, "+CMGS: %d\r\n", data.sms->number); gn_atem_string_out(buffer); gn_atem_modem_result(MR_OK); } else { gn_atem_string_out(gn_atem_cme(0)); gn_atem_string_out("\r\n"); } return; } else if (buff[i] == ModemRegisters[REG_ESCAPE]) { /* Exit SMS text mode without sending */ sms.user_data[0].u.text[index] = 0; sms.user_data[0].length = index; index = 0; Parser = gn_atem_at_parse; gn_atem_modem_result(MR_OK); return; } else { /* Appent next char to message text */ sms.user_data[0].u.text[index++] = buff[i]; } } /* reached the end of line so insert \n and wait for more */ sms.user_data[0].u.text[index++] = '\n'; gn_atem_string_out("\r\n> "); }
/* This gets called to output caller id info of incoming call */ void gn_atem_cid_out(gn_call_info *CallInfo) { struct tm *now; time_t nowh; char buf[14]; /* 7 for "DATE = " + 4 digits + \n + \r + \0 */ nowh = time(NULL); now = localtime(&nowh); switch (CallerIDMode) { case 0: /* no output */ break; case 1: /* formatted CID */ snprintf(buf, sizeof(buf), "DATE = %02d%02d\r\n", now->tm_mon + 1, now->tm_mday); gn_atem_string_out(buf); snprintf(buf, sizeof(buf), "TIME = %02d%02d\r\n", now->tm_hour, now->tm_min); gn_atem_string_out(buf); /* TO DO: handle P and O numbers */ gn_atem_string_out("NMBR = "); gn_atem_string_out(1 + CallInfo->number); /* skip leading "+" */ gn_atem_string_out("\r\nNAME = "); gn_atem_string_out(CallInfo->name); gn_atem_string_out("\r\n"); /* FIX ME: do a real emulation of rings after the first one (at a lower level than this) */ gn_atem_modem_result(MR_RING); break; } }
/* This gets called to indicate an incoming call */ void gn_atem_call_passup(gn_call_status CallStatus, gn_call_info *CallInfo, struct gn_statemachine *state) { dprintf("gn_atem_call_passup called with %d\n", CallStatus); switch (CallStatus) { case GN_CALL_Incoming: IncomingCallNo = CallInfo->call_id; gn_atem_modem_result(MR_RING); ModemRegisters[REG_RINGCNT]++; gn_atem_cid_out(CallInfo); if (ModemRegisters[REG_RINGATA] != 0) gn_atem_answer_phone(); break; case GN_CALL_LocalHangup: case GN_CALL_RemoteHangup: if (IncomingCallNo > 0) { gn_atem_cpi(GSMD_CALLPROG_DISCONNECT, GSMD_CALL_DIR_MT, 0); gn_atem_cpi(GSMD_CALLPROG_RELEASE, GSMD_CALL_DIR_MT, 0); } IncomingCallNo = -1; break; default: break; } }
/* Parser for SMS interactive mode */ void gn_atem_sms_parse(char *buff) { if (!strcasecmp(buff, "HELP")) { gn_atem_string_out(_("\r\nThe following commands work...\r\n")); gn_atem_string_out("DIR\r\n"); gn_atem_string_out("EXIT\r\n"); gn_atem_string_out("HELP\r\n"); return; } if (!strcasecmp(buff, "DIR")) { SMSNumber = 1; gn_atem_sms_handle(); Parser = gn_atem_dir_parse; return; } if (!strcasecmp(buff, "EXIT")) { Parser = gn_atem_at_parse; gn_atem_modem_result(MR_OK); return; } gn_atem_modem_result(MR_ERROR); }
/* This gets called to indicate an incoming call */ void gn_atem_call_passup(gn_call_status CallStatus, gn_call_info *CallInfo, struct gn_statemachine *state, void *callback_data) { dprintf("gn_atem_call_passup called with %d\n", CallStatus); switch (CallStatus) { case GN_CALL_Incoming: gn_atem_modem_result(MR_RING); IncomingCallNo = CallInfo->call_id; ModemRegisters[REG_RINGCNT]++; gn_atem_cid_out(CallInfo); if (ModemRegisters[REG_RINGATA] != 0) gn_atem_answer_phone(); break; case GN_CALL_LocalHangup: case GN_CALL_RemoteHangup: IncomingCallNo = -1; break; default: break; } }
/* Parser for standard AT commands. cmd_buffer must be null terminated. */ void gn_atem_at_parse(char *cmd_buffer) { char *buf; int regno, val; char str[256]; if (!cmd_buffer[0]) return; if (strncasecmp (cmd_buffer, "AT", 2) != 0) { gn_atem_modem_result(MR_ERROR); return; } for (buf = &cmd_buffer[2]; *buf;) { switch (toupper(*buf)) { case 'Z': /* Reset modem */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* reset and load stored profile 0 */ case 1: /* reset and load stored profile 1 */ gn_atem_hangup_phone(); gn_atem_registers_init(); break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'A': /* Answer call */ buf++; gn_atem_answer_phone(); return; break; case 'D': /* Dial Data :-) */ /* FIXME - should parse this better */ /* For now we'll also initialise the datapump + rlp code again */ dp_Initialise(PtyRDFD, PtyWRFD); buf++; if (toupper(*buf) == 'T' || toupper(*buf) == 'P') buf++; while (*buf == ' ') buf++; data.call_notification = dp_CallPassup; gn_sm_functions(GN_OP_SetCallNotification, &data, sm); snprintf(data.call_info->number, sizeof(data.call_info->number), "%s", buf); if (ModemRegisters[S35] == 0) data.call_info->type = GN_CALL_DigitalData; else data.call_info->type = GN_CALL_NonDigitalData; data.call_info->send_number = GN_CALL_Default; CommandMode = false; if (gn_sm_functions(GN_OP_MakeCall, &data, sm) != GN_ERR_NONE) { CommandMode = true; dp_CallPassup(GN_CALL_RemoteHangup, NULL, NULL, NULL); } else { IncomingCallNo = data.call_info->call_id; gn_sm_loop(10, sm); } return; break; case 'H': /* Hang Up */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* hook off the phone */ gn_atem_hangup_phone(); break; case 1: /* hook on the phone */ break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'S': /* Change registers */ buf++; regno = gn_atem_num_get(&buf); if (regno < 0 || regno >= MAX_MODEM_REGISTERS) { gn_atem_modem_result(MR_ERROR); return; } if (*buf == '=') { buf++; val = gn_atem_num_get(&buf); if (val < 0 || val > 255) { gn_atem_modem_result(MR_ERROR); return; } ModemRegisters[regno] = val; } else if (*buf == '?') { buf++; snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[regno]); gn_atem_string_out(str); } else { gn_atem_modem_result(MR_ERROR); return; } break; case 'E': /* E - Turn Echo on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_ECHO] &= ~BIT_ECHO; break; case 1: ModemRegisters[REG_ECHO] |= BIT_ECHO; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'Q': /* Q - Turn Quiet on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_QUIET] &= ~BIT_QUIET; break; case 1: ModemRegisters[REG_QUIET] |= BIT_QUIET; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'V': /* V - Turn Verbose on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_VERBOSE] &= ~BIT_VERBOSE; break; case 1: ModemRegisters[REG_VERBOSE] |= BIT_VERBOSE; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'X': /* X - Set verbosity of the result messages */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: val = 0x00; break; case 1: val = 0x40; break; case 2: val = 0x50; break; case 3: val = 0x60; break; case 4: val = 0x70; break; case 5: val = 0x10; break; default: gn_atem_modem_result(MR_ERROR); return; } ModemRegisters[S22] = (ModemRegisters[S22] & 0x8f) | val; break; case 'I': /* I - info */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* terminal id */ snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[39]); gn_atem_string_out(str); break; case 1: /* serial number (IMEI) */ snprintf(str, sizeof(str), "%s\r\n", imei); gn_atem_string_out(str); break; case 2: /* phone revision */ snprintf(str, sizeof(str), "%s\r\n", revision); gn_atem_string_out(str); break; case 3: /* modem revision */ gn_atem_string_out("gnokiid " VERSION "\r\n"); break; case 4: /* OEM string */ snprintf(str, sizeof(str), "%s %s\r\n", manufacturer, model); gn_atem_string_out(str); break; default: gn_atem_modem_result(MR_ERROR); return; } break; /* Handle AT* commands (Nokia proprietary I think) */ case '*': buf++; if (!strcasecmp(buf, "NOKIATEST")) { gn_atem_modem_result(MR_OK); /* FIXME? */ return; } else { if (!strcasecmp(buf, "C")) { gn_atem_modem_result(MR_OK); Parser = gn_atem_sms_parse; return; } } break; /* + is the precursor to another set of commands */ case '+': buf++; switch (toupper(*buf)) { case 'C': buf++; /* Returns true if error occured */ if (gn_atem_command_plusc(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; case 'G': buf++; /* Returns true if error occured */ if (gn_atem_command_plusg(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; default: gn_atem_modem_result(MR_ERROR); return; } break; /* # is the precursor to another set of commands */ case '#': buf++; /* Returns true if error occured */ if (gn_atem_command_diesis(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; default: gn_atem_modem_result(MR_ERROR); return; } } gn_atem_modem_result(MR_OK); }