1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-09-29 19:56:07 -04:00

Merge branch 'master' into bookmarks

This commit is contained in:
Dmitry Podgorny 2013-07-14 13:50:57 +03:00
commit ccbbd16d5f
12 changed files with 248 additions and 130 deletions

View File

@ -163,7 +163,7 @@ static struct cmd_t command_defs[] =
"Example : /help presence",
"Example : /help who",
"",
"For more details help, see the user guide at http://www.profanity.im/userguide.html.",
"For more detailed help, see the user guide at http://www.profanity.im/userguide.html.",
NULL } } },
{ "/about",
@ -197,11 +197,11 @@ static struct cmd_t command_defs[] =
{ "/msg",
_cmd_msg, parse_args_with_freetext, 1, 2, NULL,
{ "/msg jid|nick [message]", "Start chat with user.",
{ "/msg jid|nick [message]",
"-----------------------",
"Open a chat window with for the user JID (Jabber ID) and send the message if one is supplied.",
"When in a chat room, supply the nickname to start private chat with the room member.",
{ "/msg contact|nick [message]", "Start chat with user.",
{ "/msg contact|nick [message]",
"---------------------------",
"Open a chat window for the contact and send the message if one is supplied.",
"When in a chat room, supply a nickname to start private chat with a room member.",
"Use quotes if the nickname includes spaces.",
"",
"Example : /msg myfriend@server.com Hey, here's a message!",
@ -232,32 +232,32 @@ static struct cmd_t command_defs[] =
{ "/group",
_cmd_group, parse_args_with_freetext, 0, 3, NULL,
{ "/group show|add|remove [group] [contact]", "Manage roster groups.",
{ "/group show|add|remove [group] [contact]",
"-------------------------------------",
{ "/group [show|add|remove] [group] [contact]", "Manage roster groups.",
{ "/group [show|add|remove] [group] [contact]",
"------------------------------------------",
"View, add to, and remove from roster groups.",
"Passing no argument will list all roster groups.",
"The 'show' command takes 'group' as an argument, and lists all roster items in that group.",
"The 'add' command takes 'group' and 'contact' arguments, and add the contact to the group.",
"The 'remove' command takes 'group' and 'contact' arguments and removed the contact from the group,",
"The 'add' command takes 'group' and 'contact' arguments, and adds the contact to the group.",
"The 'remove' command takes 'group' and 'contact' arguments and removes the contact from the group,",
"",
"Example : /group",
"Example : /group show friends",
"Example : /group add friends newfriend@server.org",
"Example : /group add family brother (using contacts nickname)",
"Example : /group add family Brother (using contacts nickname)",
"Example : /group remove colleagues boss@work.com",
NULL } } },
{ "/info",
_cmd_info, parse_args, 0, 1, NULL,
{ "/info [jid|nick]", "Show basic information about a contact, or room member.",
{ "/info [jid|nick]",
"----------------",
{ "/info [contact|nick]", "Show basic information about a contact, or room member.",
{ "/info [contact|nick]",
"--------------------",
"Show information including current subscription status and summary information for each connected resource.",
"If in a chat window the parameter is not required, the current recipient will be used.",
"",
"Example : /info mybuddy@chat.server.org (contact)",
"Example : /info kai (room member)",
"Example : /info mybuddy@chat.server.org",
"Example : /info kai",
NULL } } },
{ "/caps",
@ -284,7 +284,7 @@ static struct cmd_t command_defs[] =
"If in the console window or a regular chat window, a full JID is required.",
"If in a chat room, the nickname is required.",
"If in private chat, no parameter is required.",
"If the contacts software does not support software version requests, nothing will be displayed.",
"If the contact's software does not support software version requests, nothing will be displayed.",
"",
"Example : /software mybuddy@chat.server.org/laptop (contact's laptop resource)",
"Example : /software mybuddy@chat.server.org/phone (contact's phone resource)",
@ -293,14 +293,14 @@ static struct cmd_t command_defs[] =
{ "/status",
_cmd_status, parse_args, 0, 1, NULL,
{ "/status [jid|nick]", "Find out your contacts presence information.",
{ "/status [jid|nick]",
"------------------",
{ "/status [contact|nick]", "Find out a contacts presence information.",
{ "/status [contact|nick]",
"----------------------",
"Find out a contact, or room members presence information.",
"If in a chat window the parameter is not required, the current recipient will be used.",
"",
"Example : /status buddy@server.com (contact)",
"Example : /status jon (room member)",
"Example : /status buddy@server.com",
"Example : /status jon",
NULL } } },
{ "/join",
@ -311,7 +311,7 @@ static struct cmd_t command_defs[] =
"Join a chat room at the conference server.",
"If nick is specified you will join with this nickname.",
"Otherwise the 'localpart' of your JID (before the @) will be used.",
"If no server is supplied, it will default to 'conference.<domain-part>'",
"If no server is supplied, a default of 'conference.<domain-part>' will be used.",
"If the room doesn't exist, and the server allows it, a new one will be created.",
"",
"Example : /join jdev@conference.jabber.org",
@ -329,11 +329,10 @@ static struct cmd_t command_defs[] =
{ "/invite",
_cmd_invite, parse_args_with_freetext, 1, 2, NULL,
{ "/invite jid [message]", "Invite contact to chat room.",
{ "/invite jid [message]",
"--------------------------",
{ "/invite contact [message]", "Invite contact to chat room.",
{ "/invite contact [message]",
"-------------------------",
"Send a direct invite to the specified contact to the current chat room.",
"The jid must be a contact in your roster.",
"If a message is supplied it will be send as the reason for the invite.",
NULL } } },
@ -404,7 +403,7 @@ static struct cmd_t command_defs[] =
{ "/wins [tidy|prune]",
"------------------",
"Passing no argument will list all currently active windows and information about their usage.",
"tidy : Shuffle windows so there are no gaps between used windows.",
"tidy : Shuffle windows so there are no gaps.",
"prune : Close all windows with no unread messages, and then tidy as above.",
NULL } } },
@ -438,7 +437,7 @@ static struct cmd_t command_defs[] =
"---------",
"Send the url as a tiny url.",
"",
"Example : /tiny http://www.google.com",
"Example : /tiny http://www.profanity.im",
NULL } } },
{ "/duck",
@ -522,7 +521,6 @@ static struct cmd_t command_defs[] =
" : on|off",
"invite : Notifications for chat room invites.",
" : on|off",
"",
"sub : Notifications for subscription requests.",
" : on|off",
"",
@ -644,7 +642,7 @@ static struct cmd_t command_defs[] =
{ "/history on|off", "Chat history in message windows.",
{ "/history on|off",
"---------------",
"Switch chat history on or off, requires /chlog will automatically be enabled when this setting in on.",
"Switch chat history on or off, /chlog will automatically be enabled when this setting is on.",
"When history is enabled, previous messages are shown in chat windows.",
NULL } } },
@ -663,7 +661,7 @@ static struct cmd_t command_defs[] =
{ "/reconnect seconds",
"------------------",
"Set the reconnect attempt interval in seconds for when the connection is lost.",
"A value of 0 will switch of reconnect attempts.",
"A value of 0 will switch off reconnect attempts.",
NULL } } },
{ "/autoping",
@ -872,7 +870,7 @@ cmd_init(void)
autocomplete_add(help_ac, strdup("chatting"));
autocomplete_add(help_ac, strdup("groupchat"));
autocomplete_add(help_ac, strdup("presence"));
autocomplete_add(help_ac, strdup("roster"));
autocomplete_add(help_ac, strdup("contacts"));
autocomplete_add(help_ac, strdup("service"));
autocomplete_add(help_ac, strdup("settings"));
autocomplete_add(help_ac, strdup("other"));
@ -1463,7 +1461,7 @@ _cmd_account(gchar **args, struct cmd_help_t help)
cons_show("");
} else if (strcmp(property, "status") == 0) {
if (!valid_resource_presence_string(value) && (strcmp(value, "last") != 0)) {
cons_show("Invalud status: %s", value);
cons_show("Invalid status: %s", value);
} else {
accounts_set_login_presence(account_name, value);
cons_show("Updated login status for account %s: %s", account_name, value);
@ -1741,7 +1739,7 @@ _cmd_help(gchar **args, struct cmd_help_t help)
"/xa" };
_cmd_show_filtered_help("Presence commands", filter, ARRAY_SIZE(filter));
} else if (strcmp(args[0], "roster") == 0) {
} else if (strcmp(args[0], "contacts") == 0) {
gchar *filter[] = { "/group", "/roster", "/sub", "/who" };
_cmd_show_filtered_help("Roster commands", filter, ARRAY_SIZE(filter));
@ -2690,7 +2688,7 @@ _cmd_join(gchar **args, struct cmd_help_t help)
} else {
g_string_append(room_str, args[0]);
g_string_append(room_str, "@conference.");
g_string_append(room_str, strdup(my_jid->domainpart));
g_string_append(room_str, my_jid->domainpart);
room = room_str->str;
}
@ -2711,6 +2709,7 @@ _cmd_join(gchar **args, struct cmd_help_t help)
ui_room_join(room_jid);
muc_remove_invite(room);
jid_destroy(room_arg);
jid_destroy(room_jid);
jid_destroy(my_jid);
g_string_free(room_str, TRUE);
@ -2788,7 +2787,7 @@ _cmd_rooms(gchar **args, struct cmd_help_t help)
if (args[0] == NULL) {
Jid *jid = jid_create(jabber_get_fulljid());
GString *conference_node = g_string_new("conference.");
g_string_append(conference_node, strdup(jid->domainpart));
g_string_append(conference_node, jid->domainpart);
jid_destroy(jid);
iq_room_list_request(conference_node->str);
g_string_free(conference_node, TRUE);
@ -2814,7 +2813,7 @@ _cmd_disco(gchar **args, struct cmd_help_t help)
jid = g_string_append(jid, args[1]);
} else {
Jid *jidp = jid_create(jabber_get_fulljid());
jid = g_string_append(jid, strdup(jidp->domainpart));
jid = g_string_append(jid, jidp->domainpart);
jid_destroy(jidp);
}

View File

@ -201,8 +201,14 @@ parse_args_with_freetext(const char * const inp, int min, int max)
in_quotes = TRUE;
i++;
}
token_start = &copy[i];
token_size++;
if (copy[i] == '"') {
token_start = &copy[i+1];
} else {
token_start = &copy[i];
}
if (copy[i] != '"') {
token_size++;
}
}
} else {
if (in_quotes) {
@ -213,7 +219,9 @@ parse_args_with_freetext(const char * const inp, int min, int max)
in_token = FALSE;
in_quotes = FALSE;
} else {
token_size++;
if (copy[i] != '"') {
token_size++;
}
}
} else {
if ((!in_freetext && copy[i] == ' ') || copy[i] == '\0') {
@ -222,7 +230,9 @@ parse_args_with_freetext(const char * const inp, int min, int max)
token_size = 0;
in_token = FALSE;
} else {
token_size++;
if (copy[i] != '"') {
token_size++;
}
}
}
}

View File

@ -72,6 +72,8 @@ static struct colours_t {
NCURSES_COLOR_T inputtext;
NCURSES_COLOR_T timetext;
NCURSES_COLOR_T splashtext;
NCURSES_COLOR_T subscribed;
NCURSES_COLOR_T unsubscribed;
NCURSES_COLOR_T online;
NCURSES_COLOR_T away;
NCURSES_COLOR_T xa;
@ -220,6 +222,10 @@ theme_init_colours(void)
// states
init_pair(60, colour_prefs.typing, colour_prefs.bkgnd);
init_pair(61, colour_prefs.gone, colour_prefs.bkgnd);
// subscription status
init_pair(70, colour_prefs.subscribed, colour_prefs.bkgnd);
init_pair(71, colour_prefs.unsubscribed, colour_prefs.bkgnd);
}
static NCURSES_COLOR_T
@ -306,6 +312,14 @@ _load_colours(void)
_set_colour(timetext_val, &colour_prefs.timetext, COLOR_WHITE);
g_free(timetext_val);
gchar *subscribed_val = g_key_file_get_string(theme, "colours", "subscribed", NULL);
_set_colour(subscribed_val, &colour_prefs.subscribed, COLOR_GREEN);
g_free(subscribed_val);
gchar *unsubscribed_val = g_key_file_get_string(theme, "colours", "unsubscribed", NULL);
_set_colour(unsubscribed_val, &colour_prefs.unsubscribed, COLOR_RED);
g_free(unsubscribed_val);
gchar *online_val = g_key_file_get_string(theme, "colours", "online", NULL);
_set_colour(online_val, &colour_prefs.online, COLOR_GREEN);
g_free(online_val);

View File

@ -55,6 +55,8 @@
#define COLOUR_XA COLOR_PAIR(55)
#define COLOUR_TYPING COLOR_PAIR(60)
#define COLOUR_GONE COLOR_PAIR(61)
#define COLOUR_SUBSCRIBED COLOR_PAIR(70)
#define COLOUR_UNSUBSCRIBED COLOR_PAIR(71)
void theme_init(const char * const theme_name);
void theme_init_colours(void);

View File

@ -252,6 +252,20 @@ p_contact_subscription(const PContact contact)
return contact->subscription;
}
gboolean
p_contact_subscribed(const PContact contact)
{
if (contact->subscription == NULL) {
return FALSE;
} else if (strcmp(contact->subscription, "to") == 0) {
return TRUE;
} else if (strcmp(contact->subscription, "both") == 0) {
return TRUE;
} else {
return FALSE;
}
}
Resource *
p_contact_get_resource(const PContact contact, const char * const resource)
{

View File

@ -53,5 +53,6 @@ Resource * p_contact_get_resource(const PContact contact, const char * const res
void p_contact_set_groups(const PContact contact, GSList *groups);
GSList * p_contact_groups(const PContact contact);
gboolean p_contact_in_group(const PContact contact, const char * const group);
gboolean p_contact_subscribed(const PContact contact);
#endif

View File

@ -260,6 +260,80 @@ autocomplete_param_with_ac(char *input, int *size, char *command,
return auto_msg;
}
int
_count_tokens(char *string)
{
int num_tokens = 0;
// if no quotes, use glib
if (g_strrstr(string, "\"") == NULL) {
gchar **tokens = g_strsplit(string, " ", 0);
num_tokens = g_strv_length(tokens);
g_strfreev(tokens);
// else count tokens including quoted
} else {
int length = strlen(string);
int i = 0;
gboolean in_quotes = FALSE;
// include first token
num_tokens++;
for (i = 0; i < length; i++) {
if (string[i] == ' ') {
if (!in_quotes) {
num_tokens++;
}
} else if (string[i] == '"') {
if (in_quotes) {
in_quotes = FALSE;
} else {
in_quotes = TRUE;
}
}
}
}
return num_tokens;
}
char *
_get_start(char *string, int tokens)
{
char *result_str = NULL;
int num_tokens = 0;
int length = strlen(string);
int i = 0;
gboolean in_quotes = FALSE;
GString *result = g_string_new("");
// include first token
num_tokens++;
for (i = 0; i < length; i++) {
if (num_tokens < tokens) {
g_string_append_c(result, string[i]);
}
if (string[i] == ' ') {
if (!in_quotes) {
num_tokens++;
}
} else if (string[i] == '"') {
if (in_quotes) {
in_quotes = FALSE;
} else {
in_quotes = TRUE;
}
}
}
result_str = result->str;
g_string_free(result, FALSE);
return result_str;
}
char *
autocomplete_param_no_with_func(char *input, int *size, char *command,
int arg_number, autocomplete_func func)
@ -267,44 +341,31 @@ autocomplete_param_no_with_func(char *input, int *size, char *command,
char *result = NULL;
if (strncmp(input, command, strlen(command)) == 0 && (*size > strlen(command))) {
int i = 0;
int quote_count = 0;
char *found = NULL;
GString *result_str = NULL;
// copy and null terminate input, count quotes
// copy and null terminate input
gchar inp_cpy[*size];
for (i = 0; i < *size; i++) {
if (input[i] == '"') {
quote_count++;
}
inp_cpy[i] = input[i];
}
inp_cpy[i] = '\0';
g_strstrip(inp_cpy);
// count tokens
gchar **tokens = g_strsplit(inp_cpy, " ", 0);
int num_tokens = g_strv_length(tokens);
// count tokens properly
int num_tokens = _count_tokens(inp_cpy);
// if num tokens, or 2 quotes then candidate for autocompletion of last param
if (((num_tokens > arg_number - 1) && quote_count == 0) || quote_count == 2) {
gchar *comp_str = NULL;
// find start of autocompletion string
if (num_tokens > 3 && quote_count == 0) {
comp_str = g_strrstr(inp_cpy, tokens[arg_number - 1]);
} else {
comp_str = g_strrstr(inp_cpy, "\"");
comp_str = comp_str + 2;
}
// if correct number of tokens, then candidate for autocompletion of last param
if (num_tokens == arg_number) {
gchar *start_str = _get_start(inp_cpy, arg_number);
gchar *comp_str = g_strdup(&inp_cpy[strlen(start_str)]);
// autocomplete param
if (comp_str != NULL) {
found = func(comp_str);
if (found != NULL) {
result_str = g_string_new("");
g_string_append(result_str, g_strndup(inp_cpy, strlen(inp_cpy) - strlen(comp_str)));
g_string_append(result_str, start_str);
g_string_append(result_str, found);
result = result_str->str;
g_string_free(result_str, FALSE);

View File

@ -146,6 +146,10 @@ history_next(History history, char *item)
return NULL;
}
if (g_list_next(history->session.sess_curr) == NULL) {
return NULL;
}
char *copied = "";
if (item != NULL) {
copied = strdup(item);

View File

@ -43,6 +43,7 @@
static ProfWin* console;
static void _cons_splash_logo(void);
void _show_roster_contacts(GSList *list, gboolean show_groups);
ProfWin *
cons_create(void)
@ -1307,17 +1308,9 @@ cons_navigation_help(void)
}
void
cons_show_roster_group(const char * const group, GSList *list)
_show_roster_contacts(GSList *list, gboolean show_groups)
{
GSList *curr = list;
cons_show("");
if (curr != NULL) {
cons_show("%s:", group);
} else {
cons_show("No group named %s exists.", group);
}
while(curr) {
PContact contact = curr->data;
@ -1328,10 +1321,24 @@ cons_show_roster_group(const char * const group, GSList *list)
title = g_string_append(title, strdup(p_contact_name(contact)));
title = g_string_append(title, ")");
}
cons_show(title->str);
const char *presence = p_contact_presence(contact);
win_print_time(console, '-');
if (p_contact_subscribed(contact)) {
win_presence_colour_on(console, presence);
wprintw(console->win, "%s\n", title->str);
win_presence_colour_off(console, presence);
} else {
win_presence_colour_on(console, "offline");
wprintw(console->win, "%s\n", title->str);
win_presence_colour_off(console, "offline");
}
g_string_free(title, TRUE);
GString *sub = g_string_new(" Subscription : ");
win_print_time(console, '-');
wprintw(console->win, " Subscription : ");
GString *sub = g_string_new("");
sub = g_string_append(sub, p_contact_subscription(contact));
if (p_contact_pending_out(contact)) {
sub = g_string_append(sub, ", request sent");
@ -1339,12 +1346,54 @@ cons_show_roster_group(const char * const group, GSList *list)
if (presence_sub_request_exists(p_contact_barejid(contact))) {
sub = g_string_append(sub, ", request received");
}
cons_show(sub->str);
if (p_contact_subscribed(contact)) {
wattron(console->win, COLOUR_SUBSCRIBED);
} else {
wattron(console->win, COLOUR_UNSUBSCRIBED);
}
wprintw(console->win, "%s\n", sub->str);
if (p_contact_subscribed(contact)) {
wattroff(console->win, COLOUR_SUBSCRIBED);
} else {
wattroff(console->win, COLOUR_UNSUBSCRIBED);
}
g_string_free(sub, TRUE);
if (show_groups) {
GSList *groups = p_contact_groups(contact);
if (groups != NULL) {
GString *groups_str = g_string_new(" Groups : ");
while (groups != NULL) {
g_string_append(groups_str, strdup(groups->data));
if (g_slist_next(groups) != NULL) {
g_string_append(groups_str, ", ");
}
groups = g_slist_next(groups);
}
cons_show(groups_str->str);
g_string_free(groups_str, TRUE);
}
}
curr = g_slist_next(curr);
}
}
void
cons_show_roster_group(const char * const group, GSList *list)
{
cons_show("");
if (list != NULL) {
cons_show("%s:", group);
} else {
cons_show("No group named %s exists.", group);
}
_show_roster_contacts(list, FALSE);
ui_console_dirty();
cons_alert();
}
@ -1352,52 +1401,10 @@ cons_show_roster_group(const char * const group, GSList *list)
void
cons_show_roster(GSList *list)
{
GSList *curr = list;
cons_show("");
cons_show("Roster:");
while(curr) {
PContact contact = curr->data;
GString *title = g_string_new(" ");
title = g_string_append(title, p_contact_barejid(contact));
if (p_contact_name(contact) != NULL) {
title = g_string_append(title, " (");
title = g_string_append(title, strdup(p_contact_name(contact)));
title = g_string_append(title, ")");
}
cons_show(title->str);
g_string_free(title, TRUE);
GString *sub = g_string_new(" Subscription : ");
sub = g_string_append(sub, p_contact_subscription(contact));
if (p_contact_pending_out(contact)) {
sub = g_string_append(sub, ", request sent");
}
if (presence_sub_request_exists(p_contact_barejid(contact))) {
sub = g_string_append(sub, ", request received");
}
cons_show(sub->str);
g_string_free(sub, TRUE);
GSList *groups = p_contact_groups(contact);
if (groups != NULL) {
GString *groups_str = g_string_new(" Groups : ");
while (groups != NULL) {
g_string_append(groups_str, strdup(groups->data));
if (g_slist_next(groups) != NULL) {
g_string_append(groups_str, ", ");
}
groups = g_slist_next(groups);
}
cons_show(groups_str->str);
g_string_free(groups_str, TRUE);
}
curr = g_slist_next(curr);
}
_show_roster_contacts(list, TRUE);
ui_console_dirty();
cons_alert();
}

View File

@ -490,6 +490,10 @@ _handle_edit(int result, const wint_t ch, char *input, int *size)
next = cmd_history_next(input, size);
if (next) {
inp_replace_input(input, next, size);
} else if (*size != 0) {
input[*size] = '\0';
cmd_history_append(input);
inp_replace_input(input, "", size);
}
return 1;

View File

@ -562,14 +562,16 @@ _roster_handle_push(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
// remove each fulljid
PContact contact = roster_get_contact(barejid);
GList *resources = p_contact_get_available_resources(contact);
while (resources != NULL) {
GString *fulljid = g_string_new(strdup(barejid));
g_string_append(fulljid, "/");
g_string_append(fulljid, strdup(resources->data));
autocomplete_remove(fulljid_ac, fulljid->str);
g_string_free(fulljid, TRUE);
resources = g_list_next(resources);
if (contact != NULL) {
GList *resources = p_contact_get_available_resources(contact);
while (resources != NULL) {
GString *fulljid = g_string_new(strdup(barejid));
g_string_append(fulljid, "/");
g_string_append(fulljid, strdup(resources->data));
autocomplete_remove(fulljid_ac, fulljid->str);
g_string_free(fulljid, TRUE);
resources = g_list_next(resources);
}
}
// remove the contact

View File

@ -93,7 +93,7 @@ void prev_with_val_then_next_returns_val(void)
assert_string_equals("Oioi", item2);
}
void prev_with_val_then_next_twice_returns_val(void)
void prev_with_val_then_next_twice_returns_null(void)
{
History history = history_new(10);
history_append(history, "Hello");
@ -102,7 +102,7 @@ void prev_with_val_then_next_twice_returns_val(void)
char *item2 = history_next(history, item1);
char *item3 = history_next(history, item2);
assert_string_equals("Oioi", item3);
assert_is_null(item3);
}
void navigate_then_append_new(void)
@ -225,7 +225,7 @@ void register_history_tests(void)
TEST(previous_goes_to_correct_element);
TEST(prev_then_next_returns_empty);
TEST(prev_with_val_then_next_returns_val);
TEST(prev_with_val_then_next_twice_returns_val);
TEST(prev_with_val_then_next_twice_returns_null);
TEST(navigate_then_append_new);
TEST(edit_item_mid_history);
TEST(edit_previous_and_append);