📄 smsc_at.c
字号:
long at2_queued_cb(SMSCConn *conn){ long ret; PrivAT2data *privdata = conn->data; if (conn->status == SMSCCONN_DEAD) /* I'm dead, why would you care ? */ return -1; ret = list_len(privdata->outgoing_queue); /* use internal queue as load, maybe something else later */ conn->load = ret; return ret;}void at2_start_cb(SMSCConn *conn){ PrivAT2data *privdata = conn->data; if (conn->status == SMSCCONN_DISCONNECTED) conn->status = SMSCCONN_ACTIVE; /* in case there are messages in the buffer already */ gwthread_wakeup(privdata->device_thread); debug("smsc.at2", 0, "AT2[%s]: start called", octstr_get_cstr(privdata->name));}int at2_add_msg_cb(SMSCConn *conn, Msg *sms){ PrivAT2data *privdata = conn->data; Msg *copy; copy = msg_duplicate(sms); list_produce(privdata->outgoing_queue, copy); gwthread_wakeup(privdata->device_thread); return 0;}int smsc_at2_create(SMSCConn *conn, CfgGroup *cfg){ PrivAT2data *privdata; Octstr *modem_type_string; privdata = gw_malloc(sizeof(PrivAT2data)); privdata->outgoing_queue = list_create(); privdata->pending_incoming_messages = list_create(); privdata->configfile = cfg_get_configfile(cfg); privdata->device = cfg_get(cfg, octstr_imm("device")); if (privdata->device == NULL) { error(0, "AT2[-]: 'device' missing in at2 configuration."); goto error; } privdata->name = cfg_get(cfg, octstr_imm("smsc-id")); if (privdata->name == NULL) { privdata->name = octstr_duplicate(privdata->device); } privdata->speed = 0; cfg_get_integer(&privdata->speed, cfg, octstr_imm("speed")); privdata->keepalive = 0; cfg_get_integer(&privdata->keepalive, cfg, octstr_imm("keepalive")); cfg_get_bool(&privdata->sms_memory_poll_interval, cfg, octstr_imm("sim-buffering")); if (privdata->sms_memory_poll_interval) { if (privdata->keepalive) privdata->sms_memory_poll_interval = privdata->keepalive; else privdata->sms_memory_poll_interval = AT2_DEFAULT_SMS_POLL_INTERVAL; } privdata->my_number = cfg_get(cfg, octstr_imm("my-number")); privdata->sms_center = cfg_get(cfg, octstr_imm("sms-center")); modem_type_string = cfg_get(cfg, octstr_imm("modemtype")); privdata->modem = NULL; if (modem_type_string != NULL) { if (octstr_compare(modem_type_string, octstr_imm("auto")) == 0 || octstr_compare(modem_type_string, octstr_imm("autodetect")) == 0) O_DESTROY(modem_type_string); } if (octstr_len(modem_type_string) == 0) { info(0, "AT2[%s]: configuration doesn't show modemtype. will autodetect", octstr_get_cstr(privdata->name)); } else { info(0, "AT2[%s]: configuration shows modemtype <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem_type_string)); privdata->modem = at2_read_modems(privdata, privdata->configfile, modem_type_string, 0); if (privdata->modem == NULL) { info(0, "AT2[%s]: modemtype not found, revert to autodetect", octstr_get_cstr(privdata->name)); } else { info(0, "AT2[%s]: read modem definition for <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(privdata->modem->name)); } O_DESTROY(modem_type_string); } privdata->ilb = octstr_create(""); privdata->fd = -1; privdata->lines = NULL; privdata->pin = cfg_get(cfg, octstr_imm("pin")); privdata->pin_ready = 0; privdata->conn = conn; privdata->phase2plus = 0; privdata->validityperiod = cfg_get(cfg, octstr_imm("validityperiod")); if (cfg_get_integer((long*)&privdata->max_error_count, cfg, octstr_imm("max-error-count")) == -1) privdata->max_error_count = -1; conn->data = privdata; conn->name = octstr_format("AT2[%s]", octstr_get_cstr(privdata->name)); conn->status = SMSCCONN_CONNECTING; privdata->shutdown = 0; conn->status = SMSCCONN_CONNECTING; conn->connect_time = time(NULL); if ((privdata->device_thread = gwthread_create(at2_device_thread, conn)) == -1) { privdata->shutdown = 1; goto error; } conn->shutdown = at2_shutdown_cb; conn->queued = at2_queued_cb; conn->start_conn = at2_start_cb; conn->send_msg = at2_add_msg_cb; return 0;error: error(0, "AT2[%s]: Failed to create at2 smsc connection", octstr_len(privdata->name) ? octstr_get_cstr(privdata->name) : ""); if (privdata != NULL) { list_destroy(privdata->outgoing_queue, NULL); } gw_free(privdata); conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT; conn->status = SMSCCONN_DEAD; info(0, "AT2[%s]: exiting", octstr_get_cstr(privdata->name)); return -1;}int at2_pdu_extract(PrivAT2data *privdata, Octstr **pdu, Octstr *line){ Octstr *buffer; long len = 0; int pos = 0; int tmp; buffer = octstr_duplicate(line); /* find the beginning of a message from the modem*/ if ((pos = octstr_search(buffer, octstr_imm("+CDS:"), 0)) != -1) pos += 5; else { if ((pos = octstr_search(buffer, octstr_imm("+CMT:"), 0)) != -1) pos += 5; else if ((pos = octstr_search(buffer, octstr_imm("+CMGR:"), 0)) != -1) { /* skip status field in +CMGR response */ if ((pos = octstr_search(buffer, octstr_imm(","), pos + 6)) != -1) pos++; else goto nomsg; } else goto nomsg; /* skip the next comma in CMGR and CMT responses */ tmp = octstr_search(buffer, octstr_imm(","), pos); if (! privdata->modem->broken && tmp == -1) goto nomsg; if (tmp != -1) pos = tmp + 1; } /* read the message length */ pos = octstr_parse_long(&len, buffer, pos, 10); if (pos == -1) goto nomsg; /* skip the spaces and line return */ while (isspace(octstr_get_char(buffer, pos))) pos++; /* skip the SMSC address on some modem types */ if (!privdata->modem->no_smsc) { tmp = at2_hexchar(octstr_get_char(buffer, pos)) * 16 + at2_hexchar(octstr_get_char(buffer, pos + 1)); if (tmp < 0) goto nomsg; pos += 2 + tmp * 2; } /* check if the buffer is long enough to contain the full message */ if (!privdata->modem->broken && octstr_len(buffer) < len * 2 + pos) goto nomsg; if (privdata->modem->broken && octstr_len(buffer) < len * 2) goto nomsg; /* copy the PDU then remove it from the input buffer*/ *pdu = octstr_copy(buffer, pos, len * 2); octstr_destroy(buffer); return 1;nomsg: octstr_destroy(buffer); return 0;}int at2_hexchar(int hexc){ hexc = toupper(hexc) - 48; return (hexc > 9) ? hexc - 7 : hexc;}Msg *at2_pdu_decode(Octstr *data, PrivAT2data *privdata){ int type; Msg *msg = NULL; /* Get the PDU type */ type = octstr_get_char(data, 1) & 3; switch (type) { case AT_DELIVER_SM: msg = at2_pdu_decode_deliver_sm(data, privdata); break; case AT_STATUS_REPORT_SM: msg = at2_pdu_decode_report_sm(data, privdata); break; /* Add other message types here: */ } return msg;}Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata){ int len, pos, i, ntype; int udhi, dcs, udhlen, pid; Octstr *origin = NULL; Octstr *udh = NULL; Octstr *text = NULL, *tmpstr; Octstr *pdu = NULL; Msg *message = NULL; struct universaltime mtime; /* time structure */ long stime; /* time in seconds */ int timezone; /* timezone in 15 minutes jumps from GMT */ /* * Note: some parts of the PDU are not decoded because they are * not needed for the Msg type. */ /* convert the pdu to binary format for ease of processing */ pdu = at2_convertpdu(data); /* UDH Indicator */ udhi = (octstr_get_char(pdu, 0) & 64) >> 6; /* originating address */ len = octstr_get_char(pdu, 1); if (len > 20) /* maximum valid number of semi-octets in Address-Value field */ goto msg_error; ntype = octstr_get_char(pdu, 2); pos = 3; if ((ntype & 0xD0) == 0xD0) { /* Alphanumeric sender */ origin = octstr_create(""); tmpstr = octstr_copy(pdu, 3, len); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0); octstr_destroy(tmpstr); debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(origin)); pos += (len + 1) / 2; } else { origin = octstr_create(""); if ((ntype & 0x90) == 0x90) { /* International number */ octstr_append_char(origin, '+'); } for (i = 0; i < len; i += 2, pos++) { octstr_append_char(origin, (octstr_get_char(pdu, pos) & 15) + 48); if (i + 1 < len) octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48); } debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(origin)); } if (pos > octstr_len(pdu)) goto msg_error; /* PID */ pid = octstr_get_char(pdu, pos); pos++; /* DCS */ dcs = octstr_get_char(pdu, pos); pos++; /* get the timestamp */ mtime.year = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.year += (mtime.year < 70 ? 2000 : 1900); mtime.month = swap_nibbles(octstr_get_char(pdu, pos)); mtime.month--; pos++; mtime.day = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.hour = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.minute = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.second = swap_nibbles(octstr_get_char(pdu, pos)); pos++; /* * time zone: * * time zone is "swapped nibble", with the MSB as the sign (1 is negative). */ timezone = swap_nibbles(octstr_get_char(pdu, pos)); pos++; timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127); /* * Ok, that was the time zone as read from the PDU. Now how to interpert it? * All the handsets I tested send the timestamp of their local time and the * timezone as GMT+0. I assume that the timestamp is the handset's local time, * so we need to apply the timezone in reverse to get GM time: */ /* * time in PDU is handset's local time and timezone is handset's time zone * difference from GMT */ mtime.hour -= timezone / 4; mtime.minute -= 15 * (timezone % 4); stime = date_convert_universal(&mtime); /* get data length * XXX: Is it allowed to have length = 0 ??? (alex) */ len = octstr_get_char(pdu, pos); pos++; debug("bb.smsc.at2", 0, "AT2[%s]: User data length read as (%d)", octstr_get_cstr(privdata->name), len); /* if there is a UDH */ udhlen = 0; if (udhi && len > 0) { udhlen = octstr_get_char(pdu, pos); pos++; if (udhlen + 1 > len) goto msg_error; udh = octstr_copy(pdu, pos, udhlen); pos += udhlen; len -= udhlen + 1; } else if (len <= 0) /* len < 0 is impossible, but sure is sure */ udhi = 0; debug("bb.smsc.at2", 0, "AT2[%s]: Udh decoding done len=%d udhi=%d udhlen=%d udh='%s'", octstr_get_cstr(privdata->name), len, udhi, udhlen, (udh?octstr_get_cstr(udh):"")); if (pos > octstr_len(pdu) || len < 0) goto msg_error; /* build the message */ message = msg_create(sms); if (!dcs_to_fields(&message, dcs)) { /* XXX Should reject this message? */ debug("bb.smsc.at2", 0, "AT2[%s]: Invalid DCS", octstr_get_cstr(privdata->name)); dcs_to_fields(&message, 0); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -