Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
sdk:scripts:sms-control [2022/08/26 10:52] – removed dodenhoeftsdk:scripts:sms-control [2022/08/26 11:04] (current) – created dodenhoeft
Line 1: Line 1:
 +====== SMS-Control ======
 +
 +<code c sms-control.are>
 +
 +/* DESC: This script will execute commands received by SMS.
 + * Copyright (C) 2012 NetModule AG, Switzerland
 + 
 + * sms-commands:
 + * <reboot>: reboot netmodule router
 + * <connect>: configure wanlink 0 permanent
 + * <disconnect>: configure wanlink 0 disable 
 + * <status>: get system status summary
 + * <output [1|2] [on|off]> set dio n on or off
 + */
 +
 +INTERVAL        = 10;                           /* only run every 10 seconds                    */
 +MAXMSG          = 5;                            /* process max. 5 msgs                          */
 +MAXAGE          = 300;                          /* message mustn't be older than 5 mins         */
 +MAXLINES        = 32;                           /* max. number of lines in msg (incl. header)   */
 +AUTH            = 1;                            /* perform authentication                       */
 +ADMPWD          = "";                           /* password used for authentication             */
 +IGNORECASE      = 1;                            /* ignore upper-/lower-case                     */
 +SENDERS         = mkarray(/* "+123456789" */);  /* allowed senders                              */
 +
 +/* check if we should perform authentication */
 +if (argc == 2 && argv[1] == "noauth") {
 +    AUTH = 0;
 +}
 +
 +/* retrieve password */
 +if (AUTH) {
 +    if (strlen(ADMPWD) == 0) {
 +        /* use configured admin password */
 +        ADMPWD = nb_config_get("admin.password");
 +        if (strlen(ADMPWD) > 0) {
 +            nb_syslog("using admin password for authentication");
 +        } else {
 +            /* not there -> use a default password instead */
 +            nb_syslog("using default password for authentication");
 +            ADMPWD = "admin01";
 +        }
 +    }
 +    if (IGNORECASE) ADMPWD = tolower(ADMPWD);
 +}
 +
 +/* split a message into an array */
 +array split(string msg) {
 +  args=mkarray();
 +  pos=strchr(msg, "\r");
 +  if(pos==0) msg="";
 +  if(pos>0) msg=left(msg, pos);
 +  pos=strchr(msg, "\n");
 +  if(pos==0) msg="";
 +  if(pos>0) msg=left(msg, pos);
 +  for(n=0;;) {
 +    pos=strchr(msg, " ");
 +    if(is_void(pos)) pos=strchr(msg, "\t");
 +    if(is_void(pos)) pos=strchr(msg, "\f");
 +    if(pos==0) {
 +      msg=trim(msg);
 +    } else if(pos>0) {
 +      args[n++]=trim(left(msg, pos));
 +      msg=trim(substr(msg, pos));
 +    } else {
 +      if(msg!="") args[n++]=trim(msg);
 +      break;
 +    }
 +  }
 +  return args;
 +}
 +
 +/* parse message */
 +array parse (string msg)
 +{
 +    /* read by line */
 +    lnr = 0;
 +    ishdr = 1;
 +    tlnr = 0;
 +    allowed = (length(SENDERS) == 0) ? 1 : 0;
 +    
 +    lp = msg;
 +    for (lnr = 0; lnr < MAXLINES && strlen(lp) > 0; lnr++) {
 +        pos = strchr(lp, "\n");
 +        if (is_void(pos)) pos = strlen(lp);
 +
 +        line = left(lp, pos);
 +        lp = substr(lp, pos + 1);
 +        
 +        if (strlen(line) == 0) {
 +            /* saw header separator */
 +            ishdr = 0;
 +            continue;
 +        }
 +        if (ishdr) {
 +            /* saw header line */
 +            if (left(line, 5) == "Sent:") {
 +                /* check age of message */
 +                sentdate = trim(substr(line, 5));
 +                sent = strptime(sentdate, "%Y-%m-%d %H:%M:%S");
 +                
 +                if (!is_void(sent)) {
 +                    /* got a valid sent date */
 +                    now = localtime(time());
 +                    age = mktime(now) - mktime(sent);
 +                    nb_syslog("message has been sent %ds ago", age);
 +                    if (age > MAXAGE) {
 +                        nb_syslog("rejecting too old message");
 +                        return mkarray();
 +                    }
 +                } else {
 +                    nb_syslog("time check has been omitted");
 +                }
 +            } else if (left(line, 5) == "From:") {
 +                from = substr(line, 6);
 +                if (length(SENDERS) > 0) {
 +                    for (s = 0; s < length(SENDERS); s++) {
 +                        sender = SENDERS[s]; 
 +                        if (left(from, strlen(sender)) == sender) {
 +                            allowed = 1;
 +                            break;
 +                        }
 +                    }
 +                }
 +                if (allowed == 0) {
 +                    nb_syslog("rejecting message from unknown sender %s", from);
 +                    return mkarray();
 +                } else {
 +                    nb_syslog("sender %s can pass", from);
 +                }
 +            }
 +        } else {
 +            /* saw text line */
 +            if (IGNORECASE) line = tolower(line);
 +
 +            if (AUTH && tlnr == 0) {
 +                /* first line of message must contain the password */
 +                if (left(line, strlen(ADMPWD)) != ADMPWD) {
 +                    nb_syslog("authentication failed");
 +                    return mkarray();
 +                } else {
 +                    nb_syslog("authentication succeeded");
 +                }
 +            } else if ((AUTH && tlnr == 1) || (!AUTH && tlnr == 0)) {
 +                /* this line must contain the command */
 +                return split(line);
 +            } else {
 +                break;
 +            }
 +            tlnr++;
 +        }
 +    }
 +    
 +    nb_syslog("no command detected");
 +
 +    return mkarray();
 +}
 +
 +int setdio (string port, string newstate) 
 +{
 +    if (port != "1" && port != "2") {
 +        nb_syslog("invalid DIO port %s\n", port);        
 +        return -1;
 +    }     
 +    if (newstate == "on") { 
 +        st = 1;
 +    } else if (newstate == "off") { 
 +        st = 0;
 +    } else  {         
 +        nb_syslog("invalid new DIO state %s\n", newstate);
 +        return -1;
 +    }        
 +    
 +    rc = nb_dio_set(sprintf("out%s", port), st);
 +    if (rc) {
 +        nb_syslog("Unable to set state %s for DIO output port %s\n", newstate, port);
 +        return -1;
 +    } else {            
 +        nb_syslog("Setting state %s for DIO output port %s\n", newstate, port);
 +        return 0; 
 +    }
 +}
 +
 +/* check if we got stressed */
 +LASTFILE = "/tmp/sms-control.last";
 +last = 0;
 +
 +fp = fopen(LASTFILE, "r");
 +if (fp) {
 +    /* we have been run at least one time */
 +    str = fread(fp, 32);
 +    if (str) last = (int) str;
 +    fclose(fp);
 +}
 +
 +now = mktime(localtime(time()));
 +elapsed = now - last;
 +if (elapsed > 0 && elapsed < INTERVAL) {
 +    nb_syslog("we have ben run %d seconds ago. skipping.", elapsed);
 +    exit(0);
 +}
 +
 +/* record timestamp */
 +fp = fopen(LASTFILE, "w+");
 +if (fp) {
 +    str = sprintf("%d", now);
 +    fwrite(fp, str);
 +    fclose(fp);
 +}
 +
 +/* read inbox */
 +msgs = nb_sms_list();
 +nr_msgs = length(msgs);
 +
 +if (nr_msgs == 0) {
 +    nb_syslog("there are no messages in your inbox");
 +    exit(0);
 +}
 +
 +nb_syslog("you have %d message(s) in your inbox", nr_msgs);
 +
 +/* track states */
 +reboot = 0;
 +
 +/* only process latest messages */
 +start = nr_msgs - MAXMSG;
 +if (start < 0) start = 0;
 +
 +for (i=start; i<nr_msgs; i++) {
 +    msg = nb_sms_retrieve(msgs[i]);
 +    if (!msg) continue;
 +
 +    nb_syslog("processing message %d of %d (ID %s)", 
 +               i, nr_msgs, msgs[i]);
 +
 +    args = parse(msg);
 +    if ((is_array(args)) && (length(args) > 0)) {
 +        if (args[0] == "") {
 +            nb_syslog("no command");
 +        } else if ((args[0] == "reboot") && (length(args) == 1)) {   
 +            nb_syslog("reboot command received");
 +            reboot = 1;
 +        } else if ((args[0] == "connect") && (length(args) == 1)) {
 +            nb_syslog("connect command received");
 +            if (nb_config_get("wanlink.0.mode") == "1") {
 +                nb_syslog("already connecting");
 +            } else {
 +                /* enable first wanlink */
 +                nb_config_set("wanlink.0.mode=1");
 +            }
 +        } else if ((args[0] == "disconnect") && (length(args) == 1)) {
 +            nb_syslog("disconnect command received");
 +            if (nb_config_get("wanlink.0.mode") == "0") {
 +                nb_syslog("already disconnecting");
 +            } else {
 +                /* disable first wanlink */
 +                nb_config_set("wanlink.0.mode=0");
 +            }
 +        } else if ((args[0] == "status") && (length(args) == 1)) {
 +            nb_syslog("status command received");
 +            rcpt = nb_sms_header(msgs[i], "From");
 +            if (rcpt) {
 +                id = nb_sms_send(rcpt, nb_status_summary());
 +                if (!id) {
 +                    nb_syslog("unable to send status message to %s", rcpt);
 +                } else {
 +                    nb_syslog("successfully queued status message to %s (ID %s)", rcpt, id);
 +                }
 +            }
 +        } else if ((args[0] == "output") && (length(args) == 3)) {
 +            nb_syslog("dio out command received");
 +            setdio(args[1], args[2]);
 +        } else {
 +            nb_syslog("command <%s> not supported", msg);
 +        }
 +    } else {
 +        nb_syslog("ignoring invalid message");
 +    }
 +
 +    /* delete message */
 +    ret = nb_sms_delete(msgs[i]);
 +    if (ret == 0) nb_syslog("deleted message %s", msgs[i]);
 +}
 +
 +if (reboot == 1) {
 +    /* trigger reboot */
 +    nb_syslog("rebooting system");
 +    nb_reboot();
 +}
 +
 +exit(0);
 +</code>