func GetMessage(messageIndex int) (*message, error) { log.Println("GetMessage...") status, err := SendCommand(fmt.Sprintf("AT+CMGR=%d\r", messageIndex), true) if err != nil { return nil, fmt.Errorf("GetMessage: Failed to send command.\n%s", err.Error()) } log.Printf("GetMessage: %#v\n", status) regex := regexp.MustCompile(`(?Us)CMGR: "([A-Z ]*)","([+\d]*)",,"([0-9/,:\+]*)"\r\n(.*)\r\n\r\nOK`) if regex.MatchString(status) { msg := regex.FindStringSubmatch(status) messageLabels := msg[1] messageSender := msg[2] messageDate, _ := time.Parse("06/01/02,15:04:05-07", msg[3]) var messageBody string if regexp.MustCompile(`^[0-9A-F]+$`).MatchString(msg[4]) { bytesWritten, _ := hex.DecodeString(msg[4]) log.Println("GetMessage: bytesWritten =", bytesWritten) regex := regexp.MustCompile(`[a-z ]{3}`) if regex.MatchString(string(bytesWritten)) { log.Printf("GetMessage: Decoding message #%d using plain text", messageIndex) messageBody = string(bytesWritten) } else { log.Printf("GetMessage: Decoding message #%d using Ucs2", messageIndex) messageBody, err = pdu.DecodeUcs2(bytesWritten) if err != nil { log.Printf("GetMessage: Failed to decode message #%d using Ucs2", messageIndex) } } } else { messageBody = msg[4] } log.Printf("GetMessage: %v %#v %#v %v %#v\n", messageIndex, messageLabels, messageSender, messageDate.Format(time.RFC3339), messageBody) return &message{ Labels: messageLabels, Date: messageDate, Sender: messageSender, Body: messageBody, Index: messageIndex, }, nil } else { return nil, fmt.Errorf("GetMessage: Failed to parse response: %v", status) } }
// handleReport detects and parses a report from the notification port represented // as a string. The parsed values may change the inner state or be sent over out channels. func (d *Device) handleReport(str string) (err error) { report := Reports.Resolve(str) str = strings.TrimSpace(strings.TrimPrefix(str, report.ID)) switch report { case Reports.Message: var report messageReport if err = report.Parse(str); err != nil { return } var octets []byte octets, err = d.Commands.CMGR(report.Index) if err != nil { return } if err = d.Commands.CMGD(report.Index, DeleteOptions.Index); err != nil { return } var msg sms.Message if _, err = msg.ReadFrom(octets); err != nil { return } d.messages <- &msg case Reports.Ussd: var ussd ussdReport if err = ussd.Parse(str); err != nil { return } var text string if ussd.Enc == Encodings.UCS2 { text, err = pdu.DecodeUcs2(ussd.Octets) if err != nil { return } } else if ussd.Enc == Encodings.Gsm7Bit { text, err = pdu.Decode7Bit(ussd.Octets) if err != nil { return } } else { return ErrUnknownEncoding } d.ussd <- Ussd(text) case Reports.SignalStrength: var rssi signalStrengthReport if err = rssi.Parse(str); err != nil { return } if d.State.SignalStrength != int(rssi) { d.State.SignalStrength = int(rssi) d.updated <- struct{}{} } case Reports.Mode: var report modeReport if err = report.Parse(str); err != nil { return } var updated bool if d.State.SystemMode != report.Mode { d.State.SystemMode = report.Mode updated = true } if d.State.SystemSubmode != report.Submode { d.State.SystemSubmode = report.Submode updated = true } if updated { d.updated <- struct{}{} } case Reports.ServiceState: var report serviceStateReport if err = report.Parse(str); err != nil { return } if d.State.ServiceState != Opt(report) { d.State.ServiceState = Opt(report) d.updated <- struct{}{} } case Reports.SimState: var report simStateReport if err = report.Parse(str); err != nil { return } if d.State.SimState != Opt(report) { d.State.SimState = Opt(report) d.updated <- struct{}{} } case Reports.BootHandshake: var token bootHandshakeReport if err = token.Parse(str); err != nil { return } if err = d.Commands.BOOT(uint64(token)); err != nil { return } case Reports.Stin: // ignore. what is this btw? default: switch FinalResults.Resolve(str) { case FinalResults.Noop, FinalResults.NotSupported, FinalResults.Timeout: // ignore default: return errors.New("at: unknown report: " + str) } } return }
// ReadFrom constructs a message from the supplied PDU octets. Returns the number of bytes read. // Complies with 3GPP TS 23.040. func (s *Message) ReadFrom(octets []byte) (n int, err error) { *s = Message{} buf := bytes.NewReader(octets) scLen, err := buf.ReadByte() n++ if err != nil { return } if scLen > 12 { return 0, ErrIncorrectSize } addr := make([]byte, scLen) off, err := io.ReadFull(buf, addr) n += off if err != nil { return } s.ServiceCenterAddress.ReadFrom(addr) msgType, err := buf.ReadByte() n++ if err != nil { return } n-- buf.UnreadByte() s.Type = MessageType(msgType & 0x03) switch s.Type { case MessageTypes.Deliver: var sms smsDeliver off, err2 := sms.FromBytes(octets[1+scLen:]) n += off if err2 != nil { return n, err2 } s.MoreMessagesToSend = sms.MoreMessagesToSend s.LoopPrevention = sms.LoopPrevention s.ReplyPathExists = sms.ReplyPath s.UserDataStartsWithHeader = sms.UserDataHeaderIndicator s.StatusReportIndication = sms.StatusReportIndication s.Address.ReadFrom(sms.OriginatingAddress[1:]) s.Encoding = Encoding(sms.DataCodingScheme) s.ServiceCenterTime.ReadFrom(sms.ServiceCentreTimestamp) switch s.Encoding { case Encodings.Gsm7Bit: s.Text, err = pdu.Decode7Bit(sms.UserData) if err != nil { return } s.Text = cutStr(s.Text, int(sms.UserDataLength)) case Encodings.UCS2: s.Text, err = pdu.DecodeUcs2(sms.UserData) if err != nil { return } default: return 0, ErrUnknownEncoding } case MessageTypes.Submit: var sms smsSubmit off, err2 := sms.FromBytes(octets[1+scLen:]) n += off if err2 != nil { return n, err2 } s.RejectDuplicates = sms.RejectDuplicates switch s.VPFormat { case ValidityPeriodFormats.Absolute, ValidityPeriodFormats.Enhanced: return n, ErrNonRelative default: s.VPFormat = ValidityPeriodFormat(sms.ValidityPeriodFormat) } s.ReplyPathExists = sms.ReplyPath s.UserDataStartsWithHeader = sms.UserDataHeaderIndicator s.StatusReportRequest = sms.StatusReportRequest s.Address.ReadFrom(sms.DestinationAddress[1:]) s.Encoding = Encoding(sms.DataCodingScheme) if s.VPFormat != ValidityPeriodFormats.FieldNotPresent { s.VP.ReadFrom(sms.ValidityPeriod) } switch s.Encoding { case Encodings.Gsm7Bit: s.Text, err = pdu.Decode7Bit(sms.UserData) if err != nil { return } s.Text = cutStr(s.Text, int(sms.UserDataLength)) case Encodings.UCS2: s.Text, err = pdu.DecodeUcs2(sms.UserData) if err != nil { return } default: return 0, ErrUnknownEncoding } default: return n, ErrUnknownMessageType } return }