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 }