Update comments for Doxygen. Move old, unused files to the testing folder.
[matches/MCTX3420.git] / server / fastcgi.c
index e3d9873..6006322 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdarg.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <ctype.h>
 
 #include "common.h"
 #include "sensor.h"
@@ -46,8 +47,7 @@ static void IdentifyHandler(FCGIContext *context, char *params)
        FCGI_BeginJSON(context, STATUS_OK);
        FCGI_JSONPair("description", "MCTX3420 Server API (2013)");
        FCGI_JSONPair("build_date", __DATE__ " " __TIME__);
-       struct timespec t;
-       t.tv_sec = 0; t.tv_nsec = 0;
+       struct timespec t = {0};
        clock_getres(CLOCK_MONOTONIC, &t);
        FCGI_JSONDouble("clock_getres", TIMEVAL_TO_DOUBLE(t));
        FCGI_JSONLong("api_version", API_VERSION);
@@ -65,7 +65,9 @@ static void IdentifyHandler(FCGIContext *context, char *params)
                        if (i > 0) {
                                FCGI_JSONValue(",\n\t\t");
                        }
-                       FCGI_JSONValue("\"%d\" : \"%s\"", i, Sensor_GetName(i)); 
+                       DataPoint d = Sensor_LastData(i);
+                       FCGI_JSONValue("\"%d\" : {\"name\" : \"%s\", \"value\" : [%f,%f] }", 
+                               i, Sensor_GetName(i), d.time_stamp, d.value); 
                }
                FCGI_JSONValue("\n\t}");
        }
@@ -76,7 +78,9 @@ static void IdentifyHandler(FCGIContext *context, char *params)
                        if (i > 0) {
                                FCGI_JSONValue(",\n\t\t");
                        }
-                       FCGI_JSONValue("\"%d\" : \"%s\"", i, Actuator_GetName(i)); 
+
+                       DataPoint d = Actuator_LastData(i);
+                       FCGI_JSONValue("\"%d\" : {\"name\" : \"%s\", \"value\" : [%f, %f] }", i, Actuator_GetName(i), d.time_stamp, d.value); 
                }
                FCGI_JSONValue("\n\t}");
        }
@@ -160,7 +164,6 @@ bool FCGI_LockControl(FCGIContext *context, const char * user_name, UserType use
  * the key) has control or not. If validated, the context control_timestamp is
  * updated.
  * @param context The context to work in
- * @param key The control key to be validated.
  * @return TRUE if authorized, FALSE if not.
  */
 bool FCGI_HasControl(FCGIContext *context)
@@ -382,7 +385,6 @@ void FCGI_BeginJSON(FCGIContext *context, StatusCodes status_code)
  * Generic accept response in JSON format.
  * @param context The context to work in
  * @param description A short description.
- * @param cookie Optional. If given, the cookie field is set to that value.
  */
 void FCGI_AcceptJSON(FCGIContext *context, const char *description)
 {
@@ -506,7 +508,7 @@ void FCGI_WriteBinary(void * data, size_t size, size_t num_elem)
 /**
  * Escapes a string so it can be used safely.
  * Currently escapes to ensure the validity for use as a JSON string
- * Does not support unicode specifiers in the form of \uXXXX.
+ * Does not support unicode specifiers in the form of \\uXXXX.
  * @param buf The string to be escaped
  * @return The escaped string (return value == buf)
  */
@@ -534,6 +536,42 @@ char *FCGI_EscapeText(char *buf)
        return buf;
 }
 
+/**
+ * Unescapes a URL encoded string in-place. The string
+ * must be NULL terminated.
+ * (e.g this%2d+string --> this- string)
+ * @param buf The buffer to decode. Will be modified in-place.
+ * @return The same buffer.
+ */
+char *FCGI_URLDecode(char *buf)
+{
+       char *head = buf, *tail = buf;
+       char val, hex[3] = {0};
+
+       while (*tail) {
+               if (*tail == '%') { //%hh hex to char
+                       tail++;
+                       if (isxdigit(*tail) && isxdigit(*(tail+1))) {
+                               hex[0] = *tail++;
+                               hex[1] = *tail++;
+                               val = (char)strtol(hex, NULL, 16);
+                               //Control codes --> Space character
+                               *head++ = (val < 0x20) ? 0x20 : val;
+                       } else { //Not valid format; keep original
+                               head++;
+                       }
+               } else if (*tail == '+') { //Plus to space
+                       tail++;
+                       *head++ = ' ';
+               } else { //Anything else
+                       *head++ = *tail++;
+               }
+       }
+       *head = 0; //NULL-terminate at new end point
+
+       return buf;
+}
+
 /**
  * Main FCGI request loop that receives/responds to client requests.
  * @param data Reserved.
@@ -552,7 +590,11 @@ void * FCGI_RequestLoop (void *data)
                
                //strncpy doesn't zero-truncate properly
                snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL"));
+               
+               //Get the GET query string
                snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING"));
+               //URL decode the parameters
+               FCGI_URLDecode(params);
 
                FCGI_GetControlCookie(context.received_key);
                Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params);
@@ -589,26 +631,38 @@ void * FCGI_RequestLoop (void *data)
                context.current_module = module;
                context.response_number++;
                
-               if (module_handler) 
-               {
-                       if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler)
-                       //if (false) // Testing
-                       {
+               if (module_handler) {
+                       if (module_handler == IdentifyHandler) {
+                               FCGI_EscapeText(params);
+                       } else if (module_handler != Login_Handler) {
                                if (!FCGI_HasControl(&context))
                                {
-                                       FCGI_RejectJSON(&context, "Please login. Invalid control key.");
-                                       continue;       
+                                       if (g_options.auth_method == AUTH_NONE) {       //:(
+                                               Log(LOGWARN, "Locking control (no auth!)");
+                                               FCGI_LockControl(&context, NOAUTH_USERNAME, USER_ADMIN);
+                                               FCGI_SendControlCookie(&context, true);
+                                       }
+                                       else {
+                                               FCGI_RejectJSON(&context, "Please login. Invalid control key.");
+                                               continue;
+                                       }
                                }
-
+                               
                                //Escape all special characters.
                                //Don't escape for login (password may have special chars?)
                                FCGI_EscapeText(params);
+                       } else { //Only for Login handler.
+                               //If GET data is empty, use POST instead.
+                               if (*params == '\0') {
+                                       Log(LOGDEBUG, "Using POST!");
+                                       fgets(params, BUFSIZ, stdin); 
+                                       FCGI_URLDecode(params);
+                               }
                        }
 
                        module_handler(&context, params);
                } 
-               else 
-               {
+               else {
                        FCGI_RejectJSON(&context, "Unhandled module");
                }
        }

UCC git Repository :: git.ucc.asn.au