Mercurial > pidgin
view plugins/spellchk.c @ 4829:e7e45cee4265
[gaim-migrate @ 5154]
This does 3 things:
1) Removes the "Get Capabilities" option which I re-added a few hours
ago. We decided that it's pointless, since caps are in the tooltips.
It also needlessly complicates things.
2) Adds an "unable to add this buddy because you are over the limit"
message that is currently commented out. We have some sort of a
message like this right now, but it's less good. If you really want
to know why, ask me.
3) Adds a workaround for the bug where some users tooltips do not
show capabilities sometimes. This is really an AIM bug, honest.
Gaim is getting status updates for people that don't contain their
capabilities. I guess it's probably intentional. I imagine it
saves a bit o' bandwidth, since each capability is 16 bytes.
[Insert humorous phrase or catch song lyric here]
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Wed, 19 Mar 2003 02:52:42 +0000 |
parents | 03ea71acade3 |
children | fefad67de2c7 |
line wrap: on
line source
/* * A lot of this code (especially the config code) was taken directly * or nearly directly from xchat, version 1.4.2 by Peter Zelezny and others. * * TODO: * ? I think i did everything i want to with it. * * BUGS: * ? I think i fixed them all. */ #include "config.h" #ifndef GAIM_PLUGINS #define GAIM_PLUGINS #endif #include "gaim.h" #include <string.h> #include <ctype.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #ifdef _WIN32 #include "win32dep.h" #endif enum { BAD_COLUMN, GOOD_COLUMN, N_COLUMNS }; static int num_words(const char *); static int get_word(char *, int); static char *have_word(char *, int); static void substitute(char **, int, int, const char *); static GtkListStore *model; static void substitute_words(struct gaim_connection *gc, char *who, char **message, void *m) { int i, l; int word; char *tmp; if (message == NULL || *message == NULL) return; l = num_words(*message); for (i = 0; i < l; i++) { GtkTreeIter iter; word = get_word(*message, i); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { do { GValue val0, val1; const char *bad, *good; memset(&val0, 0, sizeof(val0)); memset(&val1, 0, sizeof(val1)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 0, &val0); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 1, &val1); tmp = have_word(*message, word); bad = g_value_get_string(&val0); good = g_value_get_string(&val1); if (!strcmp(tmp, bad)) { substitute(message, word, strlen(bad), good); l += num_words(good) - num_words(bad); i += num_words(good) - num_words(bad); } free(tmp); g_value_unset(&val0); g_value_unset(&val1); } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); } } } static int buf_get_line(char *ibuf, char **buf, int *position, int len) { int pos = *position, spos = pos; if (pos == len) return 0; while (ibuf[pos++] != '\n') { if (pos == len) return 0; } pos--; ibuf[pos] = 0; *buf = &ibuf[spos]; pos++; *position = pos; return 1; } static void load_conf() { const char * const defaultconf = "BAD r\nGOOD are\n\n" "BAD u\nGOOD you\n\n" "BAD teh\nGOOD the\n\n"; char *buf, *ibuf; char name[82]; char cmd[256]; int pnt = 0; gsize size; model = gtk_list_store_new((gint)N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING); buf = g_build_filename(gaim_home_dir(), ".gaim", "dict", NULL); g_file_get_contents(buf, &ibuf, &size, NULL); free(buf); if(!ibuf) { ibuf = g_strdup(defaultconf); size = strlen(defaultconf); } cmd[0] = 0; name[0] = 0; while(buf_get_line(ibuf, &buf, &pnt, size)) { if (*buf != '#') { if (!strncasecmp(buf, "BAD ", 4)) strncpy(name, buf + 4, 81); if (!strncasecmp(buf, "GOOD ", 5)) { strncpy(cmd, buf + 5, 255); if (*name) { GtkTreeIter iter; gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, g_strdup(name), 1, g_strdup(cmd), -1); } } } } free(ibuf); } static int num_words(const char *m) { int count = 0; int pos; int state = 0; for (pos = 0; pos < strlen(m); pos++) { switch (state) { case 0: /* expecting word */ if (!isspace(m[pos]) && !ispunct(m[pos])) { count++; state = 1; } else if (m[pos] == '<') state = 2; break; case 1: /* inside word */ if (m[pos] == '<') state = 2; else if (isspace(m[pos]) || ispunct(m[pos])) state = 0; break; case 2: /* inside HTML tag */ if (m[pos] == '>') state = 0; break; } } return count; } static int get_word(char *m, int word) { int count = 0; int pos = 0; int state = 0; for (pos = 0; pos < strlen(m) && count <= word; pos++) { switch (state) { case 0: if (!isspace(m[pos]) && !ispunct(m[pos])) { count++; state = 1; } else if (m[pos] == '<') state = 2; break; case 1: if (m[pos] == '<') state = 2; else if (isspace(m[pos]) || ispunct(m[pos])) state = 0; break; case 2: if (m[pos] == '>') state = 0; break; } } return pos - 1; } static char *have_word(char *m, int pos) { char *tmp = strpbrk(&m[pos], "' \t\f\r\n\"><.?!-,/"); int len = (int)(tmp - &m[pos]); if (tmp == NULL) { tmp = strdup(&m[pos]); return tmp; } tmp = malloc(len + 1); tmp[0] = 0; strncat(tmp, &m[pos], len); return tmp; } static void substitute(char **mes, int pos, int m, const char *text) { char *new = g_malloc(strlen(*mes) + strlen(text) + 1); char *tmp; new[0] = 0; strncat(new, *mes, pos); strcat(new, text); strcat(new, &(*mes)[pos + m]); tmp = *mes; *mes = new; g_free(tmp); } static GtkWidget *tree; static GtkWidget *bad_entry; static GtkWidget *good_entry; static void save_list(); static void on_edited(GtkCellRendererText *cellrenderertext, gchar *path, gchar *arg2, gpointer data) { GtkTreeIter iter; GValue val; if(arg2[0] == '\0') { gdk_beep(); return; } memset(&val, 0, sizeof(val)); g_return_if_fail(gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(model), &iter, path)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, GPOINTER_TO_INT(data), &val); if(strcmp(arg2, g_value_get_string(&val))) { gtk_list_store_set(model, &iter, GPOINTER_TO_INT(data), arg2, -1); save_list(); printf("Editado! %s, %s\n", path, arg2); } g_value_unset(&val); } static void list_add_new() { GtkTreeIter iter; gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, gtk_entry_get_text(GTK_ENTRY(bad_entry)), 1, gtk_entry_get_text(GTK_ENTRY(good_entry)), -1); gtk_editable_select_region(GTK_EDITABLE(bad_entry), 0, -1); gtk_widget_grab_focus(bad_entry); save_list(); } static void add_selected_row_to_list(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { GSList **list = (GSList **)data; *list = g_slist_append(*list, gtk_tree_path_copy(path) ); } static void remove_row(void *data1, gpointer data2) { GtkTreePath *path = (GtkTreePath*)data1; GtkTreeIter iter; gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path); gtk_list_store_remove(model, &iter); gtk_tree_path_free(path); } static void list_delete() { GtkTreeSelection *sel; GSList *list = NULL; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)); gtk_tree_selection_selected_foreach(sel, add_selected_row_to_list, &list); g_slist_foreach(list, remove_row, NULL); g_slist_free(list); save_list(); } static void save_list() { FILE *f; char *name; GtkTreeIter iter; char tempfilename[BUF_LONG]; int fd; name = g_build_filename(gaim_home_dir(), ".gaim", "dict", NULL); strcpy(tempfilename, name); strcat(tempfilename,".XXXXXX"); fd = g_mkstemp(tempfilename); if(fd<0) { perror(tempfilename); g_free(name); return; } if (!(f = fdopen(fd, "w"))) { perror("fdopen"); close(fd); g_free(name); return; } fchmod(fd, S_IRUSR | S_IWUSR); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) { do { GValue val0, val1; memset(&val0, 0, sizeof(val0)); memset(&val1, 0, sizeof(val1)); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 0, &val0); gtk_tree_model_get_value(GTK_TREE_MODEL(model), &iter, 1, &val1); fprintf(f, "BAD %s\nGOOD %s\n\n", g_value_get_string(&val0), g_value_get_string(&val1)); g_value_unset(&val0); g_value_unset(&val1); } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter)); } if(fclose(f)) { debug_printf("Error writing to %s: %m\n", tempfilename); unlink(tempfilename); g_free(name); return; } rename(tempfilename, name); g_free(name); } static void check_if_something_is_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) { *((gboolean*)data) = TRUE; } static void on_selection_changed(GtkTreeSelection *sel, gpointer data) { gboolean is = FALSE; gtk_tree_selection_selected_foreach(sel, check_if_something_is_selected, &is); gtk_widget_set_sensitive((GtkWidget*)data, is); } static gboolean non_empty(const char *s) { while(*s && isspace(*s)) s++; return *s; } static void on_entry_changed(GtkEditable *editable, gpointer data) { gtk_widget_set_sensitive((GtkWidget*)data, non_empty(gtk_entry_get_text(GTK_ENTRY(bad_entry))) && non_empty(gtk_entry_get_text(GTK_ENTRY(good_entry)))); } /* * EXPORTED FUNCTIONS */ G_MODULE_EXPORT char *gaim_plugin_init(GModule *handle) { load_conf(); gaim_signal_connect(handle, event_im_send, substitute_words, NULL); gaim_signal_connect(handle, event_chat_send, substitute_words, NULL); return NULL; } G_MODULE_EXPORT void gaim_plugin_remove() { } struct gaim_plugin_description desc; G_MODULE_EXPORT struct gaim_plugin_description *gaim_plugin_desc() { desc.api_version = PLUGIN_API_VERSION; desc.name = g_strdup(_("Text replacement")); desc.version = g_strdup(VERSION); desc.description = g_strdup(_("Replaces text in outgoing messages according to user-defined rules.")); desc.authors = g_strdup("Eric Warmehoven <eric@warmenhoven.org>"); desc.url = g_strdup(WEBSITE); return &desc; } G_MODULE_EXPORT char *name() { return _("Text replacement"); } G_MODULE_EXPORT char *description() { return _("Replaces text in outgoing messages according to user-defined rules."); } G_MODULE_EXPORT GtkWidget *gaim_plugin_config_gtk() { GtkWidget *ret, *vbox, *win; GtkWidget *hbox, *label; GtkWidget *button; GtkSizeGroup *sg; GtkCellRenderer *renderer; GtkTreeViewColumn *column; sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width (GTK_CONTAINER (ret), 12); vbox = make_frame(ret, _("Text Replacements")); gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); gtk_widget_set_size_request(vbox, 300, -1); gtk_widget_show (vbox); win = gtk_scrolled_window_new(0, 0); gtk_container_add(GTK_CONTAINER(vbox), win); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(win), GTK_SHADOW_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (win), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show(win); tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); /* gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE); */ gtk_widget_set_size_request(tree, 260,200); renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(on_edited), GINT_TO_POINTER(0)); column = gtk_tree_view_column_new_with_attributes (_("You type"), renderer, "text", BAD_COLUMN, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(column, 130); /* gtk_tree_view_column_set_resizable(column, TRUE); */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); renderer = gtk_cell_renderer_text_new (); g_object_set (G_OBJECT (renderer), "editable", TRUE, NULL); g_signal_connect(G_OBJECT(renderer), "edited", G_CALLBACK(on_edited), GINT_TO_POINTER(1)); column = gtk_tree_view_column_new_with_attributes (_("You send"), renderer, "text", GOOD_COLUMN, NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED); gtk_tree_view_column_set_fixed_width(column, 130); /* gtk_tree_view_column_set_resizable(column, TRUE); */ gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)), GTK_SELECTION_MULTIPLE); gtk_container_add(GTK_CONTAINER(win), tree); gtk_widget_show(tree); hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); button = gtk_button_new_from_stock(GTK_STOCK_DELETE); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(list_delete), NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); gtk_widget_set_sensitive(button, FALSE); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree))), "changed", G_CALLBACK(on_selection_changed), button); gtk_widget_show(button); vbox = make_frame(ret, _("Add a new text replacement")); gtk_widget_set_size_request(vbox, 300, -1); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); label = gtk_label_new_with_mnemonic(_("You _type:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); bad_entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(bad_entry), 40); gtk_box_pack_start(GTK_BOX(hbox), bad_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg, bad_entry); gtk_label_set_mnemonic_widget(GTK_LABEL(label), bad_entry); gtk_widget_show(bad_entry); hbox = gtk_hbox_new(FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); label = gtk_label_new_with_mnemonic(_("You _send:")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); good_entry = gtk_entry_new(); gtk_entry_set_max_length(GTK_ENTRY(good_entry), 255); gtk_box_pack_start(GTK_BOX(hbox), good_entry, TRUE, TRUE, 0); gtk_size_group_add_widget(sg, good_entry); gtk_label_set_mnemonic_widget(GTK_LABEL(label), good_entry); gtk_widget_show(good_entry); hbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); button = gtk_button_new_from_stock(GTK_STOCK_ADD); g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(list_add_new), NULL); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(bad_entry), "changed", G_CALLBACK(on_entry_changed), button); g_signal_connect(G_OBJECT(good_entry), "changed", G_CALLBACK(on_entry_changed), button); gtk_widget_set_sensitive(button, FALSE); gtk_widget_show(button); gtk_widget_show_all(ret); return ret; }