+struct FCGIContext {
+ /**The time of last valid logged-in user access*/
+ time_t login_timestamp;
+ char login_key[41];
+ char login_ip[16];
+ /**The name of the current module**/
+ const char *current_module;
+ /**For debugging purposes?**/
+ int response_number;
+};
+
+/**
+ * Handles user logins.
+ * @param context The context to work in
+ * @param params User specified parameters
+ */
+static void LoginHandler(FCGIContext *context, char *params) {
+ const char *key, *value;
+ bool force = 0, end = 0;
+
+ while ((params = FCGI_KeyPair(params, &key, &value))) {
+ if (!strcmp(key, "force"))
+ force = !force;
+ else if (!strcmp(key, "end"))
+ end = !end;
+ }
+
+ if (end) {
+ *(context->login_key) = 0;
+ FCGI_BeginJSON(context, STATUS_OK);
+ FCGI_EndJSON();
+ return;
+ }
+
+ time_t now = time(NULL);
+ if (force || !*(context->login_key) ||
+ (now - context->login_timestamp > LOGIN_TIMEOUT))
+ {
+ SHA_CTX sha1ctx;
+ unsigned char sha1[20];
+ int i = rand();
+
+ SHA1_Init(&sha1ctx);
+ SHA1_Update(&sha1ctx, &now, sizeof(now));
+ SHA1_Update(&sha1ctx, &i, sizeof(i));
+ SHA1_Final(sha1, &sha1ctx);
+
+ context->login_timestamp = now;
+ for (i = 0; i < 20; i++)
+ sprintf(context->login_key + i * 2, "%02x", sha1[i]);
+ snprintf(context->login_ip, 16, "%s", getenv("REMOTE_ADDR"));
+ FCGI_BeginJSON(context, STATUS_OK);
+ FCGI_JSONPair("key", context->login_key);
+ FCGI_EndJSON();
+ } else {
+ char buf[128];
+ strftime(buf, 128, "%H:%M:%S %d-%m-%Y",
+ localtime(&(context->login_timestamp)));
+ FCGI_BeginJSON(context, STATUS_UNAUTHORIZED);
+ FCGI_JSONPair("description", "Already logged in");
+ FCGI_JSONPair("user", context->login_ip);
+ FCGI_JSONPair("time", buf);
+ FCGI_EndJSON();
+ }
+}
+
+/**
+ * Given an FCGIContext, determines if the current user (as specified by
+ * the key) is authorized or not. If validated, the context login_timestamp is
+ * updated.
+ * @param context The context to work in
+ * @param key The login key to be validated.
+ * @return TRUE if authorized, FALSE if not.
+ */
+int FCGI_Authorized(FCGIContext *context, const char *key) {
+ time_t now = time(NULL);
+ int result = (now - context->login_timestamp) <= LOGIN_TIMEOUT &&
+ !strcmp(context->login_key, key);
+ if (result) {
+ context->login_timestamp = now; //Update the login_timestamp
+ }
+ return result;
+}