static void init_plugin(PurplePlugin *plugin) { PurpleAccountUserSplit *split; PurpleAccountOption *option; GList *encryption_values = NULL; /* Translators: 'domain' is used here in the context of Internet domains, e.g. pidgin.im */ split = purple_account_user_split_new(_("Domain"), NULL, '@'); purple_account_user_split_set_reverse(split, FALSE); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); split = purple_account_user_split_new(_("Resource"), "", '/'); purple_account_user_split_set_reverse(split, FALSE); prpl_info.user_splits = g_list_append(prpl_info.user_splits, split); #define ADD_VALUE(list, desc, v) { \ PurpleKeyValuePair *kvp = g_new0(PurpleKeyValuePair, 1); \ kvp->key = g_strdup((desc)); \ kvp->value = g_strdup((v)); \ list = g_list_prepend(list, kvp); \ } ADD_VALUE(encryption_values, _("Require encryption"), "require_tls"); ADD_VALUE(encryption_values, _("Use encryption if available"), "opportunistic_tls"); ADD_VALUE(encryption_values, _("Use old-style SSL"), "old_ssl"); #if 0 ADD_VALUE(encryption_values, "None", "none"); #endif encryption_values = g_list_reverse(encryption_values); #undef ADD_VALUE option = purple_account_option_list_new(_("Connection security"), "connection_security", encryption_values); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_bool_new( _("Allow plaintext auth over unencrypted streams"), "auth_plain_in_clear", FALSE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Connect port"), "port", 5222); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new(_("Connect server"), "connect_server", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new(_("File transfer proxies"), "ft_proxies", /* TODO: Is this an acceptable default? * Also, keep this in sync as they add more servers */ JABBER_DEFAULT_FT_PROXIES); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_string_new(_("BOSH URL"), "bosh_url", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); /* this should probably be part of global smiley theme settings later on, shared with MSN */ option = purple_account_option_bool_new(_("Show Custom Smileys"), "custom_smileys", TRUE); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); my_protocol = plugin; purple_prefs_remove("/plugins/prpl/jabber"); purple_signal_connect(purple_get_core(), "uri-handler", plugin, PURPLE_CALLBACK(xmpp_uri_handler), NULL); }
ssize_t spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t num_values, void **end, uint32_t flags) { uint8_t *json_end = json + size; enum spdk_json_val_type containers[SPDK_JSON_MAX_NESTING_DEPTH]; size_t con_value[SPDK_JSON_MAX_NESTING_DEPTH]; enum spdk_json_val_type con_type = SPDK_JSON_VAL_INVALID; bool trailing_comma = false; size_t depth = 0; /* index into containers */ size_t cur_value = 0; /* index into values */ size_t con_start_value; uint8_t *data = json; uint8_t *new_data; int rc; const struct json_literal *lit; enum { STATE_VALUE, /* initial state */ STATE_VALUE_SEPARATOR, /* value separator (comma) */ STATE_NAME, /* "name": value */ STATE_NAME_SEPARATOR, /* colon */ STATE_END, /* parsed the complete value, so only whitespace is valid */ } state = STATE_VALUE; #define ADD_VALUE(t, val_start_ptr, val_end_ptr) \ if (values && cur_value < num_values) { \ values[cur_value].type = t; \ values[cur_value].start = val_start_ptr; \ values[cur_value].len = val_end_ptr - val_start_ptr; \ } \ cur_value++ while (data < json_end) { uint8_t c = *data; switch (c) { case ' ': case '\t': case '\r': case '\n': /* Whitespace is allowed between any tokens. */ data++; break; case 't': case 'f': case 'n': /* true, false, or null */ if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; lit = &g_json_literals[(c >> 3) & 3]; /* See comment above g_json_literals[] */ assert(lit->str[0] == c); rc = match_literal(data, json_end, lit->str, lit->len); if (rc < 0) return rc; ADD_VALUE(lit->type, data, data + rc); data += rc; state = depth ? STATE_VALUE_SEPARATOR : STATE_END; trailing_comma = false; break; case '"': if (state != STATE_VALUE && state != STATE_NAME) return SPDK_JSON_PARSE_INVALID; rc = json_decode_string(data, json_end, &new_data, flags); if (rc < 0) return rc; /* * Start is data + 1 to skip initial quote. * Length is data + rc - 1 to skip both quotes. */ ADD_VALUE(state == STATE_VALUE ? SPDK_JSON_VAL_STRING : SPDK_JSON_VAL_NAME, data + 1, data + rc - 1); data = new_data; if (state == STATE_NAME) { state = STATE_NAME_SEPARATOR; } else { state = depth ? STATE_VALUE_SEPARATOR : STATE_END; } trailing_comma = false; break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; rc = json_valid_number(data, json_end); if (rc < 0) return rc; ADD_VALUE(SPDK_JSON_VAL_NUMBER, data, data + rc); data += rc; state = depth ? STATE_VALUE_SEPARATOR : STATE_END; trailing_comma = false; break; case '{': case '[': if (state != STATE_VALUE) return SPDK_JSON_PARSE_INVALID; if (depth == SPDK_JSON_MAX_NESTING_DEPTH) { return SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED; } if (c == '{') { con_type = SPDK_JSON_VAL_OBJECT_BEGIN; state = STATE_NAME; } else { con_type = SPDK_JSON_VAL_ARRAY_BEGIN; state = STATE_VALUE; } con_value[depth] = cur_value; containers[depth++] = con_type; ADD_VALUE(con_type, data, data + 1); data++; trailing_comma = false; break; case '}': case ']': if (trailing_comma) return SPDK_JSON_PARSE_INVALID; if (depth == 0) return SPDK_JSON_PARSE_INVALID; con_type = containers[--depth]; con_start_value = con_value[depth]; if (values && con_start_value < num_values) { values[con_start_value].len = cur_value - con_start_value - 1; } if (c == '}') { if (state != STATE_NAME && state != STATE_VALUE_SEPARATOR) { return SPDK_JSON_PARSE_INVALID; } if (con_type != SPDK_JSON_VAL_OBJECT_BEGIN) { return SPDK_JSON_PARSE_INVALID; } ADD_VALUE(SPDK_JSON_VAL_OBJECT_END, data, data + 1); } else { if (state != STATE_VALUE && state != STATE_VALUE_SEPARATOR) { return SPDK_JSON_PARSE_INVALID; } if (con_type != SPDK_JSON_VAL_ARRAY_BEGIN) { return SPDK_JSON_PARSE_INVALID; } ADD_VALUE(SPDK_JSON_VAL_ARRAY_END, data, data + 1); } con_type = depth == 0 ? SPDK_JSON_VAL_INVALID : containers[depth - 1]; data++; state = depth ? STATE_VALUE_SEPARATOR : STATE_END; trailing_comma = false; break; case ',': if (state != STATE_VALUE_SEPARATOR) return SPDK_JSON_PARSE_INVALID; data++; assert(con_type == SPDK_JSON_VAL_ARRAY_BEGIN || con_type == SPDK_JSON_VAL_OBJECT_BEGIN); state = con_type == SPDK_JSON_VAL_ARRAY_BEGIN ? STATE_VALUE : STATE_NAME; trailing_comma = true; break; case ':': if (state != STATE_NAME_SEPARATOR) return SPDK_JSON_PARSE_INVALID; data++; state = STATE_VALUE; break; case '/': if (!(flags & SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS)) { return SPDK_JSON_PARSE_INVALID; } rc = json_valid_comment(data, json_end); if (rc < 0) return rc; /* Skip over comment */ data += rc; break; default: return SPDK_JSON_PARSE_INVALID; } if (state == STATE_END) { break; } } if (state == STATE_END) { /* Skip trailing whitespace */ while (data < json_end) { uint8_t c = *data; if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { data++; } else { break; } } /* * These asserts are just for sanity checking - they are guaranteed by the allowed * state transitions. */ assert(depth == 0); assert(trailing_comma == false); assert(data <= json_end); if (end) { *end = data; } return cur_value; } /* Invalid end state - ran out of data */ if (end) { *end = data; } return SPDK_JSON_PARSE_INCOMPLETE; }