/ src / tools / eibwrite-cgi.c
eibwrite-cgi.c
  1  /*
  2      cgi for webserver to write from comet/ajax client
  3  
  4      Parameters:
  5      url= (ip:host:port or local:/run/knx - local is default)
  6      t=timeout (10000)
  7      g=GA - groupadress as x/y/z or integer
  8      v=cleartext value
  9      d=DPT (number)
 10  
 11      Copyright (C) 2010 Michael Markstaller <mm@elabnet.de>
 12      Copyright (C) 2005-2010 Martin Koegler <mkoegler@auto.tuwien.ac.at>
 13  
 14      This program is free software; you can redistribute it and/or modify
 15      it under the terms of the GNU General Public License as published by
 16      the Free Software Foundation; either version 2 of the License, or
 17      (at your option) any later version.
 18  
 19      This program is distributed in the hope that it will be useful,
 20      but WITHOUT ANY WARRANTY; without even the implied warranty of
 21      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 22      GNU General Public License for more details.
 23  
 24      You should have received a copy of the GNU General Public License
 25      along with this program; if not, write to the Free Software
 26      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 27  */
 28  
 29  #include "common.h"
 30  #include <ctype.h>
 31  
 32  #include <string.h>
 33  #define MAX_POSTSIZE 4096 /* max post-size */
 34  #define MAX_GA 1024 /* max number of GAs */
 35  
 36  char *eiburl[256];
 37  char data[50];
 38  int gadest,dpt=0;
 39  
 40  void
 41  cgidie (const char *msg)
 42  {
 43    printf ("{\"error\": \"%s\"}\n", msg);
 44    exit (1);
 45  }
 46  
 47  char *parseRequest ()
 48  {
 49    unsigned long size;
 50    char *buffer = NULL;
 51    char *request = getenv("REQUEST_METHOD");
 52    char *contentlen;
 53    char *cgi_str;
 54  
 55    /* check METHOD */
 56    if(  NULL == request )
 57      return NULL;
 58    else if( strcmp(request, "GET") == 0 )
 59      {
 60        cgi_str = getenv("QUERY_STRING");
 61        if( NULL == cgi_str )
 62          return NULL;
 63        else
 64          {
 65            buffer =(char *) strdup(cgi_str);
 66            return buffer;
 67          }
 68      }
 69    else if( strcmp(request, "POST") == 0 )
 70      {
 71        contentlen = getenv("CONTENT_LENGTH");
 72        if( NULL == contentlen )
 73          return NULL;
 74        else
 75          {
 76            size = (unsigned long) atoi(contentlen);
 77            if(size <= 0 && size > MAX_POSTSIZE) /* avoid insane */
 78              return NULL;
 79          }
 80        buffer =(char *) malloc(size+1);
 81        if( NULL == buffer )
 82          return NULL;
 83        else
 84          {
 85            if( NULL == fgets(buffer, size+1, stdin) )
 86              {
 87                free(buffer);
 88                return NULL;
 89              }
 90            else
 91              return buffer;
 92          }
 93      }
 94    else /* no GET or POST */
 95      return NULL;
 96  }
 97  
 98  /* convert 2xHex to char */
 99  char convHtoA(char *hex)
100  {
101    char ascii;
102    ascii =
103      (hex[0] >= 'A' ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
104    ascii <<= 4;
105    ascii +=
106      (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
107    return ascii;
108  }
109  /* FIXME: better handling non-hex chars ? */
110  
111  /* conv urlized Hex (%xx) to ASCII */
112  void hex2ascii(char *str)
113  {
114    int x,y;
115    for(x=0,y=0; str[y] != '\0'; ++x,++y)
116      {
117        str[x] = str[y];
118        if(str[x] == '%')
119          {
120            str[x] = convHtoA(&str[y+1]);
121            y+=2;
122            /* FIXME: Buffer overflow */
123          }
124        else if( str[x] == '+')
125          str[x]=' ';
126      }
127    str[x] = '\0';
128  }
129  
130  int isNumeric(char *str)
131  {
132    while(*str)
133      {
134        if(!isdigit(*str))
135          return 0;
136        str++;
137      }
138    return 1;
139  }
140  
141  /* read parameters */
142  void readParseCGI()
143  {
144    char* params;
145    char* value;
146    char *valuepairs[MAX_GA];
147    char *cgistr;
148    int i=0,j=0;
149    cgistr = parseRequest();
150    if(cgistr == NULL)
151      cgidie ("No data");
152    hex2ascii(cgistr);
153    params=strtok(cgistr,"&");
154    while( params != NULL && i < MAX_GA)
155      {
156        valuepairs[i] = (char *)malloc(strlen(params)+1);
157        if(valuepairs[i] == NULL)
158          return;
159        valuepairs[i] = params;
160        params=strtok(NULL,"&");
161        i++;
162      }
163    while (i > j)
164      {
165        value=strtok(valuepairs[j],"=");
166        if ( value != NULL )
167          {
168            if (strcmp (value,"url") == 0)
169              {
170                value=strtok(NULL,"=");
171  #ifdef BETA
172                if ( value != NULL )
173                  *eiburl = (char *) strdup(value);
174                /* FIXME: Security - define url from ENV - Parameter only for devel */
175  #endif
176              }
177            else if (strcmp (value,"a") == 0)
178              {
179                value=strtok(NULL,"=");
180                if (value==NULL)
181                  break;
182                if (isNumeric(value))
183                  gadest=atoi(value);
184                else
185                  gadest=readgaddr(value);
186              }
187            else if (strcmp (value,"d") == 0)
188              {
189                value=strtok(NULL,"=");
190                if (isNumeric(value))
191                  {
192                    dpt=atoi(value);
193                  }
194              }
195            else if (strcmp (value,"v") == 0)
196              {
197                value=strtok(NULL,"=");
198                if ( value != NULL && strlen(value)<50 )
199                  strcpy(data,value);
200              }
201            else
202              {
203                /* printf ("Unknown param %s\n",value); // debug */
204              }
205  
206          }
207        j++;
208      }
209  }
210  
211  
212  int
213  main ()
214  {
215    int len=0;
216    EIBConnection *con;
217    unsigned int i,j;
218    double fval;
219    int sign=0,exp=0,mant=0;
220    eibaddr_t dest;
221    uint8_t buf[255] = { 0, 0x80 };
222    char tmpbuf[255];
223    printf("Content-Type: text/plain\r\n\r\n");
224  
225    readParseCGI();
226    if (*eiburl == NULL)
227      *eiburl = "local:/run/knx";
228  
229    con = EIBSocketURL (*eiburl);
230    if (!con)
231      cgidie ("Open failed");
232  
233    dest=gadest;
234    if (EIBOpenT_Group (con, dest, 1) == -1)
235      cgidie ("Connect failed");
236  
237    if (!gadest || !(strlen(data)>0))
238      cgidie ("Need ga(g),value(v)");
239    switch (dpt)
240      {
241      case 0:
242        len=1;
243        for(i = 0; i < strlen(data)/2; i++)
244          {
245            tmpbuf[0] = data[i*2];
246            tmpbuf[1] = data[(i*2)+1];
247            sscanf(tmpbuf, "%x", &j);
248            buf[i+1] = j;
249            len++;
250          }
251        /* only allow A_GroupValue_Write */
252        if ((buf[1] &0x80) != 0x80)
253          cgidie ("Only A_GroupValue_Write allowed");
254        break;
255      case 1:
256        buf[1] |= atoi(data) & 0x3f;
257        len=2;
258        break;
259      case 3:
260        /* EIS2/DPT3 4bit dim */
261        buf[1] |= atoi(data) & 0x3f;
262        len=2;
263        break;
264      case 5:
265        buf[2] = atoi(data)*255/100;
266        len=3;
267        break;
268      case 51:
269      case 5001:
270        buf[2] = atoi(data);
271        len=3;
272        break;
273      case 9:
274        fval=atof(data);
275        if (fval<0)
276          sign = 0x8000;
277        mant = (int)(fval * 100.0);
278        while (abs(mant) > 2047)
279          {
280            mant = mant >> 1;
281            exp++;
282          }
283        i = sign | (exp << 11) | (mant & 0x07ff);
284        buf[2] = i >> 8;
285        buf[3] = i & 0xff;
286        /* return $data >> 8, $data & 0xff; */
287        len=4;
288        break;
289      case 16:
290        len=2;
291        for (i=0; i<strlen(data); i++)
292          {
293            buf[i+2] = (int)(data[i]);
294            len++;
295          }
296      }
297  
298    len = EIBSendAPDU (con, len, buf);
299    if (len == -1)
300      cgidie ("Request failed");
301    printf ("{\"success\":%d}\n",len-1); /*don't confuse client with leading 0x00 */
302  
303  #if 0
304    printf("size %d %d\n",sizeof(buf),strlen(buf));
305    printf("buf 0x%02X 0x%02X 0x%02X 0x%02X v:%s l:%d\n" ,buf[1],buf[2],buf[3],buf[4],data,strlen(data));
306  #endif
307    EIBClose (con);
308    return 0;
309  }