# include <wctype.h>
#endif
-#include "xml.h"
+#include "addressbook.h"
#include "addr_compl.h"
#include "utils.h"
-#include "addressbook.h"
-#include "main.h"
/* How it works:
*
g_completion = NULL;
}
+static void add_address1(const char *str, address_entry *ae)
+{
+ completion_entry *ce1;
+ ce1 = g_new0(completion_entry, 1),
+ ce1->string = g_strdup(str);
+ /* GCompletion list is case sensitive */
+ g_strdown(ce1->string);
+ ce1->ref = ae;
+
+ g_completion_list = g_list_prepend(g_completion_list, ce1);
+}
+
/* add_address() - adds address to the completion list. this function looks
* complicated, but it's only allocation checks.
*/
-static gint add_address(const gchar *name, const gchar *address)
+static gint add_address(const gchar *name, const gchar *address, const gchar *alias)
{
address_entry *ae;
- completion_entry *ce1;
- completion_entry *ce2;
if (!name || !address) return -1;
- debug_print( "completion: add_address: %s - %s\n", name, address );
-
ae = g_new0(address_entry, 1);
- ce1 = g_new0(completion_entry, 1),
- ce2 = g_new0(completion_entry, 1);
g_return_val_if_fail(ae != NULL, -1);
- g_return_val_if_fail(ce1 != NULL && ce2 != NULL, -1);
ae->name = g_strdup(name);
ae->address = g_strdup(address);
- ce1->string = g_strdup(name);
- ce2->string = g_strdup(address);
- /* GCompletion list is case sensitive */
- g_strdown(ce2->string);
- g_strdown(ce1->string);
- ce1->ref = ce2->ref = ae;
+ g_address_list = g_list_prepend(g_address_list, ae);
- g_completion_list = g_list_append(g_completion_list, ce1);
- g_completion_list = g_list_append(g_completion_list, ce2);
- g_address_list = g_list_append(g_address_list, ae);
+ add_address1(name, ae);
+ add_address1(address, ae);
+ add_address1(alias, ae);
return 0;
}
*/
static void read_address_book(void) {
addressbook_load_completion( add_address );
+ g_address_list = g_list_reverse(g_address_list);
+ g_completion_list = g_list_reverse(g_completion_list);
}
/* start_address_completion() - returns the number of addresses
wchar_t *wtext;
wchar_t *wp;
wchar_t rfc_mail_sep;
+ wchar_t quote;
+ wchar_t lt;
+ wchar_t gt;
+ gboolean in_quote = FALSE;
+ gboolean in_bracket = FALSE;
gchar *str;
+ if (mbtowc(&rfc_mail_sep, ",", 1) < 0) return NULL;
+ if (mbtowc("e, "\"", 1) < 0) return NULL;
+ if (mbtowc(<, "<", 1) < 0) return NULL;
+ if (mbtowc(>, ">", 1) < 0) return NULL;
+
edit_text = gtk_entry_get_text(entry);
if (edit_text == NULL) return NULL;
cur_pos = gtk_editable_get_position(GTK_EDITABLE(entry));
- if (mbtowc(&rfc_mail_sep, ",", 1) < 0) {
- g_free(wtext);
- return NULL;
- }
-
/* scan for a separator. doesn't matter if walk points at null byte. */
- for (wp = wtext + cur_pos; wp > wtext && *wp != rfc_mail_sep; wp--)
- ;
+ for (wp = wtext + cur_pos; wp > wtext; wp--) {
+ if (*wp == quote)
+ in_quote ^= TRUE;
+ else if (!in_quote) {
+ if (!in_bracket && *wp == rfc_mail_sep)
+ break;
+ else if (*wp == gt)
+ in_bracket = TRUE;
+ else if (*wp == lt)
+ in_bracket = FALSE;
+ }
+ }
/* have something valid */
if (wcslen(wp) == 0) {
return NULL;
}
-#define IS_VALID_CHAR(x) (iswalnum(x) || ((x) > 0x7f))
+#define IS_VALID_CHAR(x) \
+ (iswalnum(x) || (x) == quote || (x) == lt || ((x) > 0x7f))
/* now scan back until we hit a valid character */
for (; *wp && !IS_VALID_CHAR(*wp); wp++)
void replace_address_in_edit(GtkEntry *entry, const gchar *newtext,
gint start_pos)
{
+ if (!newtext) return;
gtk_editable_delete_text(GTK_EDITABLE(entry), start_pos, -1);
gtk_editable_insert_text(GTK_EDITABLE(entry), newtext, strlen(newtext),
&start_pos);
gchar *get_complete_address(gint index)
{
const address_entry *p;
-
+ gchar *address = NULL;
+
if (index < g_completion_count) {
if (index == 0)
- return g_strdup(g_completion_prefix);
+ address = g_strdup(g_completion_prefix);
else {
/* get something from the unique addresses */
p = (address_entry *)g_slist_nth_data
(g_completion_addresses, index - 1);
- if (p == NULL)
- return NULL;
- else
- return g_strdup_printf
- ("%s <%s>", p->name, p->address);
+ if (p != NULL) {
+ if (!p->name || p->name[0] == '\0')
+ address = g_strdup_printf(p->address);
+ else if (strchr_with_skip_quote(p->name, '"', ','))
+ address = g_strdup_printf
+ ("\"%s\" <%s>", p->name, p->address);
+ else
+ address = g_strdup_printf
+ ("%s <%s>", p->name, p->address);
+ }
}
- } else
- return NULL;
+ }
+
+ return address;
}
gchar *get_next_complete_address(void)
gtk_clist_thaw(clist);
}
+#if 0
/* completion_window_accept_selection() - accepts the current selection in the
* clist, and destroys the window */
static void completion_window_accept_selection(GtkWidget **window,
GtkEntry *entry)
{
gchar *address = NULL, *text = NULL;
- gint cursor_pos, row, col;
+ gint cursor_pos, row;
g_return_if_fail(window != NULL);
g_return_if_fail(*window != NULL);
g_return_if_fail(entry != NULL);
g_return_if_fail(clist->selection != NULL);
- col = 0;
-
/* FIXME: I believe it's acceptable to access the selection member directly */
row = GPOINTER_TO_INT(clist->selection->data);
/* we just need the cursor position */
address = get_address_from_edit(entry, &cursor_pos);
- gtk_clist_get_text(clist, row, col, &text);
+ g_free(address);
+ gtk_clist_get_text(clist, row, 0, &text);
replace_address_in_edit(entry, text, cursor_pos);
- g_free(address);
clear_completion_cache();
gtk_widget_destroy(*window);
*window = NULL;
}
+#endif
+
+/* completion_window_apply_selection() - apply the current selection in the
+ * clist */
+static void completion_window_apply_selection(GtkCList *clist, GtkEntry *entry)
+{
+ gchar *address = NULL, *text = NULL;
+ gint cursor_pos, row;
+
+ g_return_if_fail(clist != NULL);
+ g_return_if_fail(entry != NULL);
+ g_return_if_fail(clist->selection != NULL);
+
+ row = GPOINTER_TO_INT(clist->selection->data);
+
+ address = get_address_from_edit(entry, &cursor_pos);
+ g_free(address);
+ gtk_clist_get_text(clist, row, 0, &text);
+ replace_address_in_edit(entry, text, cursor_pos);
+}
/* should be called when creating the main window containing address
* completion entries */
if (!GTK_WIDGET_HAS_FOCUS(entry)) return FALSE;
/* get an address component from the cursor */
- if (0 != (address = get_address_from_edit(entry, &cursor_pos))) {
- /* still something in the cache */
- if (is_completion_pending()) {
- new = next ? get_next_complete_address() :
- get_prev_complete_address();
- } else {
- if (0 < (ncount = complete_address(address)))
- new = get_next_complete_address();
- }
+ address = get_address_from_edit(entry, &cursor_pos);
+ if (!address) return FALSE;
- if (new) {
- /* prevent "change" signal */
- replace_address_in_edit(entry, new, cursor_pos);
- g_free(new);
- completed = TRUE;
- }
+ /* still something in the cache */
+ if (is_completion_pending()) {
+ new = next ? get_next_complete_address() :
+ get_prev_complete_address();
+ } else {
+ if (0 < (ncount = complete_address(address)))
+ new = get_next_complete_address();
+ }
- g_free(address);
- }
+ if (new) {
+ /* prevent "change" signal */
+ /* replace_address_in_edit(entry, new, cursor_pos); */
+ g_free(new);
+ completed = TRUE;
+ }
+
+ g_free(address);
return completed;
}
{
GtkEntry *entry;
- /* first check if it's anything but a mouse event. Mouse events
- * accept the completion. Anything else is accepted by the
- * completion_window_key_press() */
- if (!event) {
- /* event == NULL if key press did the selection or just
- * event emitted with signal_emit_XXX(). This seems to
- * be the case for the gtk versions I have seen */
- return;
- }
-
- /* however, a future version of GTK might pass the event type
- * that triggered the select_row. since this event handler
- * only wants mouse clicks, we check for that. */
- if (event->type != GDK_BUTTON_RELEASE) {
- return;
- }
-
g_return_if_fail(completion_window != NULL);
g_return_if_fail(*completion_window != NULL);
WINDOW_DATA_COMPL_ENTRY));
g_return_if_fail(entry != NULL);
- completion_window_accept_selection(completion_window, clist, entry);
+ completion_window_apply_selection(clist, entry);
+
+ if (!event || event->type != GDK_BUTTON_RELEASE)
+ return;
+
+ clear_completion_cache();
+ gtk_widget_destroy(*completion_window);
+ *completion_window = NULL;
}
/* completion_window_button_press() - check is mouse click is anywhere
prefix = get_complete_address(0);
g_free(get_address_from_edit(GTK_ENTRY(entry), &cursor_pos));
replace_address_in_edit(GTK_ENTRY(entry), prefix, cursor_pos);
+ g_free(prefix);
}
+ clear_completion_cache();
gtk_widget_destroy(*completion_window);
*completion_window = NULL;
- clear_completion_cache();
return TRUE;
}
/* look for presses that accept the selection */
if (event->keyval == GDK_Return || event->keyval == GDK_space) {
- completion_window_accept_selection(completion_window,
- GTK_CLIST(clist),
- GTK_ENTRY(entry));
+ clear_completion_cache();
+ gtk_widget_destroy(*completion_window);
+ *completion_window = NULL;
return FALSE;
}