This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/gnoemoe/mcp/gm-mcp.c

264 lines
4.3 KiB
C

#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "gm-mcp.h"
#include "../gm-support.h"
gdouble
gm_mcp_get_version(gdouble client_min, gdouble client_max, gdouble server_min,
gdouble server_max) {
if (client_max >= server_min && server_max >= client_min) {
if (client_max < server_max) {
return server_max;
} else {
return client_max;
}
} else {
return 0.0;
}
}
gchar const *
gm_mcp_find_value(GList const *fields, gchar const *key) {
GmKeyValuePair *tmp;
while (fields) {
tmp = (GmKeyValuePair *)(fields->data);
if (strcasecmp(key, tmp->key) == 0) {
return tmp->value;
}
fields = fields->next;
}
return NULL;
}
gchar *
gm_mcp_escape_if_needed(gchar const *line) {
GString *new_line;
gchar const *ptr = line;
gchar *result;
if (*line == '\0') {
return g_strdup("\"\"");
}
if (g_utf8_strchr(line, -1, ' ') || g_utf8_strchr(line, -1, '"') ||
g_utf8_strchr(line, -1, '\\')) {
new_line = g_string_new("\"");
while (*ptr != '\0') {
if (*ptr == '"' || *ptr == '\\') {
new_line = g_string_append_c(new_line, '\\');
}
new_line = g_string_append_c(new_line, *ptr);
++ptr;
}
new_line = g_string_append_c(new_line, '"');
result = new_line->str;
g_string_free(new_line, FALSE);
return result;
} else {
return g_strdup(line);
}
}
gchar *
gm_mcp_un_escape(gchar *line) {
gchar *ptri = line, *ptrj = line;
gboolean shifted = FALSE;
while (*ptri != '\0') {
if (*ptri == '\\') {
shifted = TRUE;
++ptri;
}
if (shifted) {
*ptrj = *ptri;
}
++ptrj;
++ptri;
}
*ptrj = '\0';
return line;
}
gchar *
gm_mcp_process_keyval(GList **info, gchar *line) {
gchar *keystart;
gchar *valuestart;
int keylen, valuelen;
GmKeyValuePair *newKeyValue;
if (*line != ' ' || line[1] == '\0' || line[1] == ' ') {
return NULL;
}
keystart = ++line;
gm_string_skip_till(&line, ": ");
if (*line != ':') {
return NULL;
}
keylen = line - keystart;
line = g_utf8_next_char(line);
if (line[1] == '\0' || *line != ' ') {
return NULL;
}
line = g_utf8_next_char(line);
if (*line == ' ') {
return NULL;
}
valuestart = line;
if (*line == '"') {
++valuestart;
++line;
while (*line != '\0' && *line != '"') {
if (*line == '\\') {
++line;
}
++line;
}
valuelen = line - valuestart;
if (*line != '"') {
--valuelen;
} else {
++line;
}
} else {
gm_string_skip_nonspace(&line);
valuelen = line - valuestart;
}
newKeyValue = g_new(GmKeyValuePair, 1);
newKeyValue->key = g_strndup(keystart, keylen);
newKeyValue->value = gm_mcp_un_escape(g_strndup(valuestart, valuelen));
*info = g_list_append(*info, newKeyValue);
return line;
}
GList *
gm_mcp_process_key_values(gchar *line) {
GList *result = NULL;
while (line && *line != '\0') {
line = gm_mcp_process_keyval(&result, line);
}
return result;
}
gboolean
gm_mcp_parse_line(gchar *line, McpMessageInfo *info) {
gchar *p = g_utf8_strchr(line, -1, ' ');
if (!p || p == line) {
return FALSE;
}
info->name = g_strndup(line, (p - line));
line = p + 1;
// Now there should be a authentication key!
p = g_utf8_strchr(line, -1, ' ');
if (!p) {
p = line + strlen(line);
}
info->authkey = g_strndup(line, (p - line));
// Now process the keyvals
info->fields = gm_mcp_process_key_values(p);
return TRUE;
}
gchar *
gm_mcp_generate_key(gint len) {
gchar *s = g_malloc(len + 1);
gchar ref[] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
gint n = strlen(ref);
gint i;
srand((int) time(NULL));
for (i = 0; i < len; i++) {
s[i] = ref[rand() % n];
}
s[i] = 0;
return s;
}
gchar *
gm_mcp_generate_data_tag() {
return gm_mcp_generate_key(10);
}
gchar *
gm_mcp_generate_auth_key() {
return gm_mcp_generate_key(6);
}
gchar const *
gm_mcp_find_multiline_tag(GList const *fields) {
GmKeyValuePair *data;
gunichar last;
while (fields) {
data = (GmKeyValuePair *)(fields->data);
last = g_utf8_get_char(g_utf8_prev_char(data->key + strlen(data->key)));
if (last == '*') {
return data->key;
}
fields = fields->next;
}
return NULL;
}
void
gm_mcp_destroy_fields(GList *fields) {
GmKeyValuePair *tmp;
GList *elem = fields;
while (elem) {
tmp = (GmKeyValuePair *) (elem->data);
g_free(tmp->key);
g_free(tmp->value);
g_free(elem->data);
elem->data = NULL;
elem = elem->next;
}
g_list_free(fields);
}