diff --git a/geniuspaste/README b/geniuspaste/README index 4a8cf0491..436d264b5 100644 --- a/geniuspaste/README +++ b/geniuspaste/README @@ -15,7 +15,6 @@ services, but more can be added: * pastebin.geany.org * paste.debian.net * sprunge.us - * tinypaste.com GeniusPaste detects automatically the syntax of the code and pastes it with syntax highlighting enabled. @@ -67,7 +66,7 @@ Placeholders Values from the `[format] section`_ and the *replace* key in the `[parse] section`_ can contain references to placeholders with the syntax ``%name%`` -(i.e. ``%contents%``). +(e.g. ``%contents%``). Custom placeholders can be defined in the `[defaults] section`_. The builtin placeholders are: @@ -95,6 +94,10 @@ The *pastebin* section is required, and must contain at least the *name* and The URL to which submit the data. This key is required. *method* The HTTP method to use to submit the data. Defaults to ``POST``. +*content-type* + The Content-Type the request body should be sent in. Currently supported + types include ``application/x-www-form-urlencoded`` and ``application/json``. + Defaults to ``application/x-www-form-urlencoded``. *[format]* section ++++++++++++++++++ @@ -121,7 +124,7 @@ enable response body parsing, and it will use the default *search* and *search* A regular expression (PCRE) pattern to match against the pastebin service's raw response data. - Defaults to ``^[[:space:]]*(.+?)[[:space:]]*$``, e.g. capture everything + Defaults to ``^[[:space:]]*(.+?)[[:space:]]*$``, i.e. capture everything but the leading and trailing whitespaces. *replace* The final URL, with regular expression capture groups from *search* diff --git a/geniuspaste/data/Makefile.am b/geniuspaste/data/Makefile.am index 61086ebae..4469ea85a 100644 --- a/geniuspaste/data/Makefile.am +++ b/geniuspaste/data/Makefile.am @@ -8,5 +8,4 @@ dist_pastebins_DATA = \ fpaste.org.conf \ pastebin.geany.org.conf \ paste.debian.net.conf \ - sprunge.us.conf \ - tinypaste.com.conf + sprunge.us.conf diff --git a/geniuspaste/data/dpaste.de.conf b/geniuspaste/data/dpaste.de.conf index 0f64d2142..d17ea70b5 100644 --- a/geniuspaste/data/dpaste.de.conf +++ b/geniuspaste/data/dpaste.de.conf @@ -1,9 +1,9 @@ [pastebin] name=dpaste.de -url=http://dpaste.de/api/ +url=https://dpaste.de/api/ [format] -title=%title% +filename=%title% content=%contents% lexer=%language% #expires=%expire% diff --git a/geniuspaste/data/fpaste.org.conf b/geniuspaste/data/fpaste.org.conf index 68b966ced..4c74a248b 100644 --- a/geniuspaste/data/fpaste.org.conf +++ b/geniuspaste/data/fpaste.org.conf @@ -1,67 +1,55 @@ [pastebin] name=fpaste.org -url=http://fpaste.org/ +url=https://paste.fedoraproject.org/api/paste/submit +content-type=application/json [format] -paste_data=%contents% -paste_lang=%language% -api_submit=true -mode=xml +contents=%contents% +language=%language% +title=%title% # Optional stuff -paste_user=%user% -# expiration in seconds -#paste_expire=0 +# expiration date in UNIX timestamp +#expiry_time=1453355837 +# Password for accessing the paste +#password=password123 [parse] -search=(.+?) -replace=http://fpaste.org/\1 +search="url" *: *"([^"]+)" +replace=\1 # map GeanyFileType=PastebinFileType [languages] -# map for GeSHi 2015-01-14 -ActionScript=Actionscript -Ada=ADA -ASM=ASM -C=C -C#=C# -C++=C++ -COBOL=COBOL -Conf=INI -CSS=CSS -CUDA=C -Cython=Python -D=D -Diff=Diff -Docbook=XML -F77=Fortran -Fortran=Fortran -FreeBasic=FreeBasic -GLSL=C -Haskell=Haskell -HTML=HTML -Java=Java -Javascript=Javascript -JSON=Javascript -LaTeX=LaTeX -Lisp=Lisp -Lua=Lua -Make=Make -NSIS=NSIS -Objective-C=Objective-C -Pascal=Pascal -Perl=Perl -PHP=PHP -Po=GetText -PowerShell=PowerShell -Prolog=Prolog -Python=Python -Ruby=Ruby -Scala=Scala -Sh=Bash -SQL=SQL -Tcl=TCL -Verilog=Verilog -VHDL=VHDL -XML=XML +# based off the list on the pastebin's web frontend +CMake=cmake +CoffeeScript=coffeescript +CSS=css +D=d +Diff=diff +Elm=elm +Erlang=erlang +Factor=factor +F77=fortran +Fortran=fortran +Go=go +Haskell=haskell +HTML=htmlmixed +Javascript=javascript +Jinja2=jinja2 +Markdown=markdown +Matlab/Octave=octave +PHP=php +Python=python +RPM=rpm +Ruby=ruby +Rust=rust +SASS=sass +Sh=shell +Smalltalk=smalltalk +SQL=sql +Swift=swift +Verilog=verilog +VHDL=vhdl +XML=xml +YAML=yaml diff --git a/geniuspaste/data/tinypaste.com.conf b/geniuspaste/data/tinypaste.com.conf deleted file mode 100644 index ed709ff98..000000000 --- a/geniuspaste/data/tinypaste.com.conf +++ /dev/null @@ -1,20 +0,0 @@ -# FIXME: outdated, this leads to a 404 on http://pasted.co/ -[pastebin] -name=tinypaste.com -url=http://tinypaste.com/api/create.xml - -[format] -paste=%contents% -title=%title% -is_code=%language% - -[parse] -search=(.*) -replace=\1 - -[defaults] -language=1 - -# map GeanyFileType=PastebinFileType -[languages] -None=0 diff --git a/geniuspaste/src/geniuspaste.c b/geniuspaste/src/geniuspaste.c index 998cf947f..5cd29a53f 100644 --- a/geniuspaste/src/geniuspaste.c +++ b/geniuspaste/src/geniuspaste.c @@ -50,16 +50,17 @@ #define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX #endif -#define PASTEBIN_GROUP_DEFAULTS "defaults" -#define PASTEBIN_GROUP_FORMAT "format" -#define PASTEBIN_GROUP_LANGUAGES "languages" -#define PASTEBIN_GROUP_PARSE "parse" -#define PASTEBIN_GROUP_PARSE_KEY_SEARCH "search" -#define PASTEBIN_GROUP_PARSE_KEY_REPLACE "replace" -#define PASTEBIN_GROUP_PASTEBIN "pastebin" -#define PASTEBIN_GROUP_PASTEBIN_KEY_NAME "name" -#define PASTEBIN_GROUP_PASTEBIN_KEY_URL "url" -#define PASTEBIN_GROUP_PASTEBIN_KEY_METHOD "method" +#define PASTEBIN_GROUP_DEFAULTS "defaults" +#define PASTEBIN_GROUP_FORMAT "format" +#define PASTEBIN_GROUP_LANGUAGES "languages" +#define PASTEBIN_GROUP_PARSE "parse" +#define PASTEBIN_GROUP_PARSE_KEY_SEARCH "search" +#define PASTEBIN_GROUP_PARSE_KEY_REPLACE "replace" +#define PASTEBIN_GROUP_PASTEBIN "pastebin" +#define PASTEBIN_GROUP_PASTEBIN_KEY_NAME "name" +#define PASTEBIN_GROUP_PASTEBIN_KEY_URL "url" +#define PASTEBIN_GROUP_PASTEBIN_KEY_METHOD "method" +#define PASTEBIN_GROUP_PASTEBIN_KEY_CONTENT_TYPE "content-type" GeanyPlugin *geany_plugin; GeanyData *geany_data; @@ -73,6 +74,13 @@ typedef struct } Pastebin; +typedef enum +{ + FORMAT_HTML_FORM_URLENCODED, + FORMAT_JSON +} +Format; + GSList *pastebins = NULL; static struct @@ -503,9 +511,93 @@ static gchar *regex_replace(const gchar *pattern, return result; } -static void free_data_item(GQuark id, gpointer data, gpointer user_data) +static Format pastebin_get_format(const Pastebin *pastebin) { - g_free(data); + static const struct + { + const gchar *name; + Format format; + } formats[] = { + { "application/x-www-form-urlencoded", FORMAT_HTML_FORM_URLENCODED }, + { "application/json", FORMAT_JSON } + }; + Format result = FORMAT_HTML_FORM_URLENCODED; + gchar *format = utils_get_setting_string(pastebin->config, PASTEBIN_GROUP_PASTEBIN, + PASTEBIN_GROUP_PASTEBIN_KEY_CONTENT_TYPE, NULL); + + if (format) + { + for (guint i = 0; i < G_N_ELEMENTS(formats); i++) + { + if (strcmp(formats[i].name, format) == 0) + { + result = formats[i].format; + break; + } + } + + g_free(format); + } + + return result; +} + +/* Appends a JSON string. See: + * http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf */ +static void append_json_string(GString *str, const gchar *value) +{ + g_string_append_c(str, '"'); + for (; *value; value++) + { + if (*value == '"' || *value == '\\') + { + g_string_append_c(str, '\\'); + g_string_append_c(str, *value); + } + else if (*value == '\b') + g_string_append(str, "\\b"); + else if (*value == '\f') + g_string_append(str, "\\f"); + else if (*value == '\n') + g_string_append(str, "\\n"); + else if (*value == '\r') + g_string_append(str, "\\r"); + else if (*value == '\t') + g_string_append(str, "\\t"); + else if (*value >= 0x00 && *value <= 0x1F) + g_string_append_printf(str, "\\u%04d", *value); + else + g_string_append_c(str, *value); + } + g_string_append_c(str, '"'); +} + +static void append_json_data_item(GQuark id, gpointer data, gpointer user_data) +{ + GString *str = user_data; + + if (str->len > 1) /* if there's more than the first "{" */ + g_string_append_c(str, ','); + append_json_string(str, g_quark_to_string(id)); + g_string_append_c(str, ':'); + append_json_string(str, data); +} + +static SoupMessage *json_request_new(const gchar *method, + const gchar *url, + GData **fields) +{ + SoupMessage *msg = soup_message_new(method, url); + GString *str = g_string_new(NULL); + + g_string_append_c(str, '{'); + g_datalist_foreach(fields, append_json_data_item, str); + g_string_append_c(str, '}'); + soup_message_set_request(msg, "application/json", SOUP_MEMORY_TAKE, + str->str, str->len); + g_string_free(str, FALSE); + + return msg; } /* sends data to @pastebin and returns the raw response */ @@ -516,6 +608,7 @@ static SoupMessage *pastebin_soup_message_new(const Pastebin *pastebin, SoupMessage *msg; gchar *url; gchar *method; + Format format; gsize n_fields; gchar **fields; GData *data; @@ -527,6 +620,7 @@ static SoupMessage *pastebin_soup_message_new(const Pastebin *pastebin, PASTEBIN_GROUP_PASTEBIN_KEY_URL, NULL); method = utils_get_setting_string(pastebin->config, PASTEBIN_GROUP_PASTEBIN, PASTEBIN_GROUP_PASTEBIN_KEY_METHOD, "POST"); + format = pastebin_get_format(pastebin); /* prepare the form data */ fields = g_key_file_get_keys(pastebin->config, PASTEBIN_GROUP_FORMAT, &n_fields, NULL); g_datalist_init(&data); @@ -536,11 +630,20 @@ static SoupMessage *pastebin_soup_message_new(const Pastebin *pastebin, fields[i], NULL); SETPTR(value, expand_placeholders(value, pastebin, doc, contents)); - g_datalist_set_data(&data, fields[i], value); + g_datalist_set_data_full(&data, fields[i], value, g_free); } g_strfreev(fields); - msg = soup_form_request_new_from_datalist(method, url, &data); - g_datalist_foreach(&data, free_data_item, NULL); + switch (format) + { + case FORMAT_JSON: + msg = json_request_new(method, url, &data); + break; + + default: + case FORMAT_HTML_FORM_URLENCODED: + msg = soup_form_request_new_from_datalist(method, url, &data); + break; + } g_datalist_clear(&data); return msg;