mirror of
https://github.com/profanity-im/profanity.git
synced 2025-01-03 14:57:42 -05:00
Merge pull request #1341 from profanity-im/feature/urlopen
Add urlopen command
This commit is contained in:
commit
7862542c58
@ -54,6 +54,7 @@
|
||||
#include "xmpp/muc.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
#include "xmpp/roster_list.h"
|
||||
#include "ui/buffer.h"
|
||||
|
||||
#ifdef HAVE_LIBGPGME
|
||||
#include "pgp/gpg.h"
|
||||
@ -122,6 +123,8 @@ static char* _avatar_autocomplete(ProfWin *window, const char *const input, gboo
|
||||
static char* _correction_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
static char* _correct_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
static char* _software_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
static char* _urlopen_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
static char* _executable_autocomplete(ProfWin *window, const char *const input, gboolean previous);
|
||||
|
||||
static char* _script_autocomplete_func(const char *const prefix, gboolean previous, void *context);
|
||||
|
||||
@ -254,6 +257,7 @@ static Autocomplete logging_group_ac;
|
||||
static Autocomplete color_ac;
|
||||
static Autocomplete correction_ac;
|
||||
static Autocomplete avatar_ac;
|
||||
static Autocomplete executable_ac;
|
||||
|
||||
void
|
||||
cmd_ac_init(void)
|
||||
@ -986,8 +990,11 @@ cmd_ac_init(void)
|
||||
|
||||
avatar_ac = autocomplete_new();
|
||||
autocomplete_add(avatar_ac, "get");
|
||||
autocomplete_add(avatar_ac, "cmd");
|
||||
autocomplete_add(avatar_ac, "open");
|
||||
|
||||
executable_ac = autocomplete_new();
|
||||
autocomplete_add(executable_ac, "avatar");
|
||||
autocomplete_add(executable_ac, "urlopen");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1304,6 +1311,7 @@ cmd_ac_reset(ProfWin *window)
|
||||
autocomplete_reset(color_ac);
|
||||
autocomplete_reset(correction_ac);
|
||||
autocomplete_reset(avatar_ac);
|
||||
autocomplete_reset(executable_ac);
|
||||
|
||||
autocomplete_reset(script_ac);
|
||||
if (script_show_ac) {
|
||||
@ -1462,6 +1470,7 @@ cmd_ac_uninit(void)
|
||||
autocomplete_free(color_ac);
|
||||
autocomplete_free(correction_ac);
|
||||
autocomplete_free(avatar_ac);
|
||||
autocomplete_free(executable_ac);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1721,6 +1730,8 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ
|
||||
g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/software", _software_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/urlopen", _urlopen_autocomplete);
|
||||
g_hash_table_insert(ac_funcs, "/executable", _executable_autocomplete);
|
||||
|
||||
int len = strlen(input);
|
||||
char parsed[len+1];
|
||||
@ -3912,3 +3923,30 @@ _software_autocomplete(ProfWin *window, const char *const input, gboolean previo
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char*
|
||||
_urlopen_autocomplete(ProfWin *window, const char *const input, gboolean previous)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
if (window->type == WIN_CHAT ||
|
||||
window->type == WIN_MUC ||
|
||||
window->type == WIN_PRIVATE) {
|
||||
result = autocomplete_param_with_func(input, "/urlopen", wins_get_url, previous, window);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char*
|
||||
_executable_autocomplete(ProfWin *window, const char *const input, gboolean previous)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
result = autocomplete_param_with_ac(input, "/executable", executable_ac, TRUE, previous);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2340,26 +2340,23 @@ static struct cmd_t command_defs[] =
|
||||
},
|
||||
|
||||
{ "/avatar",
|
||||
parse_args, 2, 2, &cons_avatar_setting,
|
||||
parse_args, 2, 2, NULL,
|
||||
CMD_NOSUBFUNCS
|
||||
CMD_MAINFUNC(cmd_avatar)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_CHAT)
|
||||
CMD_SYN(
|
||||
"/avatar get <barejid>",
|
||||
"/avatar open <barejid>",
|
||||
"/avatar cmd <command>")
|
||||
"/avatar open <barejid>")
|
||||
CMD_DESC(
|
||||
"Download avatar (XEP-0084) for a certain contact. "
|
||||
"If nothing happens after using this command the user either doesn't have an avatar set at all "
|
||||
"or doesn't use XEP-0084 to publish it.")
|
||||
CMD_ARGS(
|
||||
{ "get <barejid>", "Download the avatar. barejid is the JID to download avatar from."},
|
||||
{ "cmd <command>", "Set a command to execute with 'avatar open'. Use your favourite image viewer here."},
|
||||
{ "open <barejid>", "Download avatar and open it with command."})
|
||||
CMD_EXAMPLES(
|
||||
"/avatar get thor@valhalla.edda",
|
||||
"/avatar cmd xdg-open",
|
||||
"/avatar open freyja@vanaheimr.edda")
|
||||
},
|
||||
|
||||
@ -2449,7 +2446,43 @@ static struct cmd_t command_defs[] =
|
||||
CMD_EXAMPLES(
|
||||
"/software valhalla.edda",
|
||||
"/software xmpp.vanaheimr.edda")
|
||||
}
|
||||
},
|
||||
|
||||
{ "/urlopen",
|
||||
parse_args, 1, -1, NULL,
|
||||
CMD_NOSUBFUNCS
|
||||
CMD_MAINFUNC(cmd_urlopen)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_CHAT,
|
||||
CMD_TAG_GROUPCHAT)
|
||||
CMD_SYN(
|
||||
"/urlopen <url>")
|
||||
CMD_DESC(
|
||||
"Open the URL")
|
||||
CMD_ARGS(
|
||||
{ "<url>", "URL to open."})
|
||||
CMD_NOEXAMPLES
|
||||
},
|
||||
|
||||
{ "/executable",
|
||||
parse_args, 2, 2, &cons_executable_setting,
|
||||
CMD_NOSUBFUNCS
|
||||
CMD_MAINFUNC(cmd_executable)
|
||||
CMD_TAGS(
|
||||
CMD_TAG_DISCOVERY)
|
||||
CMD_SYN(
|
||||
"/executable avatar <cmd>",
|
||||
"/executable urlopen <cmd>")
|
||||
CMD_DESC(
|
||||
"Configure executable that should be called upon a certain command."
|
||||
"Default is xdg-open.")
|
||||
CMD_ARGS(
|
||||
{ "avatar", "Set executable that is run in /avatar open. Use your favourite image viewer." },
|
||||
{ "urlopen", "Set executable that is run in /urlopen. Use your favourite browser." })
|
||||
CMD_EXAMPLES(
|
||||
"/executable avatar xdg-open",
|
||||
"/executable urlopen firefox")
|
||||
},
|
||||
};
|
||||
|
||||
static GHashTable *search_index;
|
||||
|
@ -8858,3 +8858,39 @@ cmd_slashguard(ProfWin *window, const char *const command, gchar **args)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cmd_urlopen(ProfWin *window, const char *const command, gchar **args)
|
||||
{
|
||||
if (window->type == WIN_CHAT ||
|
||||
window->type == WIN_MUC ||
|
||||
window->type == WIN_PRIVATE) {
|
||||
|
||||
if (args[0] == NULL) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
call_external(prefs_get_string(PREF_URL_OPEN_CMD), args[0]);
|
||||
} else {
|
||||
cons_show("urlopen not supported in this window");
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
cmd_executable(ProfWin *window, const char *const command, gchar **args)
|
||||
{
|
||||
if (g_strcmp0(args[0], "avatar") == 0) {
|
||||
prefs_set_string(PREF_AVATAR_CMD, args[1]);
|
||||
cons_show("Avatar command set to: %s", args[1]);
|
||||
} else if (g_strcmp0(args[0], "urlopen") == 0) {
|
||||
prefs_set_string(PREF_URL_OPEN_CMD, args[1]);
|
||||
cons_show("urlopen command set to: %s", args[1]);
|
||||
} else {
|
||||
cons_bad_cmd_usage(command);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -232,4 +232,7 @@ gboolean cmd_correction(ProfWin *window, const char *const command, gchar **args
|
||||
gboolean cmd_correct(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_slashguard(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_serversoftware(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_urlopen(ProfWin *window, const char *const command, gchar **args);
|
||||
gboolean cmd_executable(ProfWin *window, const char *const command, gchar **args);
|
||||
|
||||
#endif
|
||||
|
13
src/common.c
13
src/common.c
@ -483,3 +483,16 @@ get_mentions(gboolean whole_word, gboolean case_sensitive, const char *const mes
|
||||
|
||||
return mentions;
|
||||
}
|
||||
|
||||
void
|
||||
call_external(const char *const exe, const char *const param)
|
||||
{
|
||||
GString *cmd = g_string_new("");
|
||||
|
||||
g_string_append_printf(cmd, "%s %s > /dev/null 2>&1", exe, param);
|
||||
log_debug("Calling external: %s", cmd->str);
|
||||
FILE *stream = popen(cmd->str, "r");
|
||||
|
||||
pclose(stream);
|
||||
g_string_free(cmd, TRUE);
|
||||
}
|
||||
|
@ -106,4 +106,6 @@ void get_file_paths_recursive(const char *directory, GSList **contents);
|
||||
|
||||
char* get_random_string(int length);
|
||||
|
||||
void call_external(const char *const exe, const char *const param);
|
||||
|
||||
#endif
|
||||
|
@ -1783,6 +1783,7 @@ _get_group(preference_t pref)
|
||||
case PREF_LOG_ROTATE:
|
||||
case PREF_LOG_SHARED:
|
||||
case PREF_AVATAR_CMD:
|
||||
case PREF_URL_OPEN_CMD:
|
||||
return PREF_GROUP_LOGGING;
|
||||
case PREF_AUTOAWAY_CHECK:
|
||||
case PREF_AUTOAWAY_MODE:
|
||||
@ -2070,6 +2071,8 @@ _get_key(preference_t pref)
|
||||
return "slashguard";
|
||||
case PREF_MAM:
|
||||
return "mam";
|
||||
case PREF_URL_OPEN_CMD:
|
||||
return "urlopen.cmd";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -2205,6 +2208,7 @@ _get_default_string(preference_t pref)
|
||||
case PREF_COLOR_NICK:
|
||||
return "false";
|
||||
case PREF_AVATAR_CMD:
|
||||
case PREF_URL_OPEN_CMD:
|
||||
return "xdg-open";
|
||||
default:
|
||||
return NULL;
|
||||
|
@ -170,6 +170,7 @@ typedef enum {
|
||||
PREF_AVATAR_CMD,
|
||||
PREF_SLASH_GUARD,
|
||||
PREF_MAM,
|
||||
PREF_URL_OPEN_CMD,
|
||||
} preference_t;
|
||||
|
||||
typedef struct prof_alias_t {
|
||||
|
@ -385,6 +385,18 @@ autocomplete_param_no_with_func(const char *const input, char *command, int arg_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* remove the first message if we have more than max */
|
||||
void
|
||||
autocomplete_remove_older_than_max(Autocomplete ac, int maxsize)
|
||||
{
|
||||
if (autocomplete_length(ac) > maxsize) {
|
||||
GList *first = g_list_nth(ac->items, 0);
|
||||
if (first) {
|
||||
ac->items = g_list_delete_link(ac->items, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gchar*
|
||||
_search_next(Autocomplete ac, GList *curr, gboolean quote)
|
||||
{
|
||||
|
@ -74,4 +74,6 @@ char* autocomplete_param_no_with_func(const char *const input, char *command,
|
||||
void autocomplete_reset(Autocomplete ac);
|
||||
|
||||
gboolean autocomplete_contains(Autocomplete ac, const char *value);
|
||||
|
||||
void autocomplete_remove_older_than_max(Autocomplete ac, int maxsize);
|
||||
#endif
|
||||
|
@ -292,7 +292,7 @@ chatwin_incoming_msg(ProfChatWin *chatwin, ProfMessage *message, gboolean win_cr
|
||||
//1) only send IQ once
|
||||
//2) sort incoming messages on timestamp
|
||||
//for now if experimental MAM is enabled we dont show no history from sql either
|
||||
|
||||
|
||||
// MUCPMs also get printed here. In their case we don't save any logs (because nick owners can change) and thus we shouldn't read logs
|
||||
// (and if we do we need to check the resourcepart)
|
||||
if (!prefs_get_boolean(PREF_MAM) && prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY) && message->type == PROF_MSG_TYPE_CHAT) {
|
||||
@ -311,6 +311,8 @@ chatwin_incoming_msg(ProfChatWin *chatwin, ProfMessage *message, gboolean win_cr
|
||||
win_print_incoming(window, display_name, message);
|
||||
}
|
||||
|
||||
wins_add_urls_ac(window, message);
|
||||
|
||||
if (prefs_get_boolean(PREF_BEEP)) {
|
||||
beep();
|
||||
}
|
||||
|
@ -2051,13 +2051,15 @@ cons_correction_setting(void)
|
||||
}
|
||||
|
||||
void
|
||||
cons_avatar_setting(void)
|
||||
cons_executable_setting(void)
|
||||
{
|
||||
char *pref = prefs_get_string(PREF_AVATAR_CMD);
|
||||
char *avatar = prefs_get_string(PREF_AVATAR_CMD);
|
||||
cons_show("Avatar command (/executable avatar) : %s", avatar);
|
||||
prefs_free_string(avatar);
|
||||
|
||||
cons_show("Avatar command (/avatar cmd) : %s", pref);
|
||||
|
||||
prefs_free_string(pref);
|
||||
char *exec = prefs_get_string(PREF_URL_OPEN_CMD);
|
||||
cons_show("urlopen command (/executable urlopen) : %s", exec);
|
||||
prefs_free_string(exec);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -557,6 +557,7 @@ mucwin_incoming_msg(ProfMucWin *mucwin, const ProfMessage *const message, GSList
|
||||
}
|
||||
|
||||
win_insert_last_read_position_marker((ProfWin*)mucwin, mucwin->roomjid);
|
||||
wins_add_urls_ac(window, message);
|
||||
|
||||
if (g_slist_length(mentions) > 0) {
|
||||
_mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags);
|
||||
|
@ -79,6 +79,8 @@ privwin_incoming_msg(ProfPrivateWin *privatewin, ProfMessage *message)
|
||||
}
|
||||
}
|
||||
|
||||
wins_add_urls_ac(window, message);
|
||||
|
||||
if (prefs_get_boolean(PREF_BEEP)) {
|
||||
beep();
|
||||
}
|
||||
|
@ -319,7 +319,7 @@ void cons_winpos_setting(void);
|
||||
void cons_color_setting(void);
|
||||
void cons_os_setting(void);
|
||||
void cons_correction_setting(void);
|
||||
void cons_avatar_setting(void);
|
||||
void cons_executable_setting(void);
|
||||
void cons_slashguard_setting(void);
|
||||
void cons_show_contact_online(PContact contact, Resource *resource, GDateTime *last_activity);
|
||||
void cons_show_contact_offline(PContact contact, char *resource, char *status);
|
||||
|
@ -138,6 +138,7 @@ typedef enum {
|
||||
typedef struct prof_win_t {
|
||||
win_type_t type;
|
||||
ProfLayout *layout;
|
||||
Autocomplete urls_ac;
|
||||
} ProfWin;
|
||||
|
||||
typedef struct prof_console_win_t {
|
||||
|
@ -534,7 +534,7 @@ wins_close_by_num(int i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
autocomplete_free(window->urls_ac);
|
||||
break;
|
||||
}
|
||||
case WIN_MUC:
|
||||
@ -546,6 +546,7 @@ wins_close_by_num(int i)
|
||||
if (mucwin->last_msg_timestamp) {
|
||||
g_date_time_unref(mucwin->last_msg_timestamp);
|
||||
}
|
||||
autocomplete_free(window->urls_ac);
|
||||
break;
|
||||
}
|
||||
case WIN_PRIVATE:
|
||||
@ -553,6 +554,7 @@ wins_close_by_num(int i)
|
||||
ProfPrivateWin *privwin = (ProfPrivateWin*)window;
|
||||
autocomplete_remove(wins_ac, privwin->fulljid);
|
||||
autocomplete_remove(wins_close_ac, privwin->fulljid);
|
||||
autocomplete_free(window->urls_ac);
|
||||
break;
|
||||
}
|
||||
case WIN_XML:
|
||||
@ -624,6 +626,7 @@ wins_new_chat(const char *const barejid)
|
||||
autocomplete_add(wins_close_ac, nick);
|
||||
}
|
||||
}
|
||||
newwin->urls_ac = autocomplete_new();
|
||||
|
||||
return newwin;
|
||||
}
|
||||
@ -638,6 +641,8 @@ wins_new_muc(const char *const roomjid)
|
||||
g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin);
|
||||
autocomplete_add(wins_ac, roomjid);
|
||||
autocomplete_add(wins_close_ac, roomjid);
|
||||
newwin->urls_ac = autocomplete_new();
|
||||
|
||||
return newwin;
|
||||
}
|
||||
|
||||
@ -649,6 +654,7 @@ wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback s
|
||||
g_list_free(keys);
|
||||
ProfWin *newwin = win_create_config(roomjid, form, submit, cancel, userdata);
|
||||
g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin);
|
||||
|
||||
return newwin;
|
||||
}
|
||||
|
||||
@ -662,6 +668,8 @@ wins_new_private(const char *const fulljid)
|
||||
g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin);
|
||||
autocomplete_add(wins_ac, fulljid);
|
||||
autocomplete_add(wins_close_ac, fulljid);
|
||||
newwin->urls_ac = autocomplete_new();
|
||||
|
||||
return newwin;
|
||||
}
|
||||
|
||||
@ -1141,3 +1149,36 @@ wins_get_next_unread(void)
|
||||
g_list_free(values);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wins_add_urls_ac(const ProfWin *const win, const ProfMessage *const message)
|
||||
{
|
||||
GRegex *regex;
|
||||
GMatchInfo *match_info;
|
||||
|
||||
regex = g_regex_new("https?://\\S+", 0, 0, NULL);
|
||||
g_regex_match (regex, message->plain, 0, &match_info);
|
||||
|
||||
while (g_match_info_matches (match_info))
|
||||
{
|
||||
gchar *word = g_match_info_fetch (match_info, 0);
|
||||
|
||||
autocomplete_add(win->urls_ac, word);
|
||||
// for people who run profanity a long time, we don't want to waste a lot of memory
|
||||
autocomplete_remove_older_than_max(win->urls_ac, 20);
|
||||
|
||||
g_free (word);
|
||||
g_match_info_next (match_info, NULL);
|
||||
}
|
||||
|
||||
g_match_info_free (match_info);
|
||||
g_regex_unref (regex);
|
||||
}
|
||||
|
||||
char*
|
||||
wins_get_url(const char *const search_str, gboolean previous, void *context)
|
||||
{
|
||||
ProfWin *win = (ProfWin*)context;
|
||||
|
||||
return autocomplete_complete(win->urls_ac, search_str, FALSE, previous);
|
||||
}
|
||||
|
@ -98,4 +98,7 @@ void win_reset_search_attempts(void);
|
||||
char* win_close_autocomplete(const char *const search_str, gboolean previous, void *context);
|
||||
void win_close_reset_search_attempts(void);
|
||||
|
||||
void wins_add_urls_ac(const ProfWin *const win, const ProfMessage *const message);
|
||||
char* wins_get_url(const char *const search_str, gboolean previous, void *context);
|
||||
|
||||
#endif
|
||||
|
@ -266,15 +266,7 @@ _avatar_request_item_result_handler(xmpp_stanza_t *const stanza, void *const use
|
||||
|
||||
// if we shall open it
|
||||
if (g_hash_table_contains(shall_open, from_attr)) {
|
||||
GString *cmd = g_string_new("");
|
||||
|
||||
g_string_append_printf(cmd, "%s %s > /dev/null 2>&1", prefs_get_string(PREF_AVATAR_CMD), filename->str);
|
||||
cons_show("Calling: %s", cmd->str);
|
||||
FILE *stream = popen(cmd->str, "r");
|
||||
|
||||
pclose(stream);
|
||||
g_string_free(cmd, TRUE);
|
||||
|
||||
call_external(prefs_get_string(PREF_AVATAR_CMD), filename->str);
|
||||
g_hash_table_remove(shall_open, from_attr);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user