changeset 211:e13103257b33

implemented filtering functionality.
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 25 Aug 2008 21:17:02 +0900
parents 00e26402de03
children 8670e1572be8
files pidgin-twitter.c pidgin-twitter.h prefs.ui
diffstat 3 files changed, 511 insertions(+), 117 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin-twitter.c	Sat Aug 23 04:17:49 2008 +0900
+++ b/pidgin-twitter.c	Mon Aug 25 21:17:02 2008 +0900
@@ -518,13 +518,25 @@
 
          if(st->id > lastid && !is_posted_message(st, lastid)) {
              gchar *msg = NULL;
+             gchar *sender = NULL;
+
+             sender = g_strdup("twitter@twitter.com");
+
+             PurpleMessageFlags flag = PURPLE_MESSAGE_RECV;
 
              msg = g_strdup_printf("%s: %s", st->screen_name, st->text);
-             purple_conv_im_write(conv->u.im,
-                                  "twitter@twitter.com",
-                                  msg,
-                                  PURPLE_MESSAGE_RECV,
-                                  st->time);
+
+             /* apply filter*/
+             if(purple_prefs_get_bool(OPT_FILTER)) {
+                 apply_filter(&sender, &msg, &flag, twitter_service);
+             }
+             if(sender && msg) {
+                 purple_conv_im_write(conv->u.im,
+                                      sender,
+                                      msg,
+                                      flag,
+                                      st->time);
+             }
              lastid = st->id;
 
              g_free(msg);
@@ -951,13 +963,13 @@
 playsound(gchar **str, gint which)
 {
     GMatchInfo *match_info;
-    const gchar *list;
+    const gchar *list = NULL;
     gchar **candidates = NULL, **candidate = NULL;
 
     list = purple_prefs_get_string(which ? OPT_USERLIST_SENDER :
                                    OPT_USERLIST_RECIPIENT);
     g_return_if_fail(list != NULL);
-    if(!strcmp(list, DEFAULT_LIST))
+    if(strstr(list, DEFAULT_LIST))
         return;
 
     candidates = g_strsplit_set(list, " ,:;", 0);
@@ -1003,7 +1015,7 @@
     if(service == unknown_service)
         return FALSE;
 
-    /* Add screen_name if the current message is posted by owner */
+    /* add screen_name if the current message is posted by myself */
     if (flags & PURPLE_MESSAGE_SEND) {
         gchar *m = NULL;
         const char *screen_name = NULL;
@@ -1054,7 +1066,7 @@
         translate(buffer, TAG_IDENTICA, service);
     }
 
-    /* escape pseudo command (to show same result to sending message) */
+    /* escape pseudo command (to show the same result as sending message) */
     if(service == twitter_service &&
        purple_prefs_get_bool(OPT_ESCAPE_PSEUDO)) {
         escape(buffer);
@@ -1497,6 +1509,63 @@
         delete_requested_icon_marks(gtkconv, hash);
 }
 
+static void
+apply_filter(gchar **sender, gchar **buffer, PurpleMessageFlags *flags, int service)
+{
+    GMatchInfo *match_info;
+    const gchar *list = NULL;
+    gchar **candidates = NULL, **candidate = NULL;
+
+    gchar *plain = strip_html_markup(*buffer);
+
+    switch(service) {
+    case twitter_service:
+        list = purple_prefs_get_string(OPT_FILTER_TWITTER);
+        break;
+    case wassr_service:
+        list = purple_prefs_get_string(OPT_FILTER_WASSR);
+        break;
+    case identica_service:
+        list = purple_prefs_get_string(OPT_FILTER_IDENTICA);
+        break;
+    }
+    g_return_if_fail(list != NULL);
+    if(strstr(list, DEFAULT_LIST))
+        return;
+
+    candidates = g_strsplit_set(list, " ,:;", 0);
+    g_return_if_fail(candidates != NULL);
+
+    g_regex_match(regp[SENDER], plain, 0, &match_info);
+    while(g_match_info_matches(match_info)) {
+        gchar *user = NULL;
+        user = g_match_info_fetch(match_info, 2);
+        twitter_debug("user = %s\n", user);
+
+        for(candidate = candidates; *candidate; candidate++) {
+            if(!strcmp(*candidate, ""))
+                continue;
+            twitter_debug("candidate = %s\n", *candidate);
+            if(!strcmp(user, *candidate)) {
+                twitter_debug("match. filter %s\n", user);
+                *flags |= PURPLE_MESSAGE_INVISIBLE; /* pidgin should handle this flag properly --yaz */
+#if 1
+                /* temporal workaround */
+                g_free(*sender); *sender = NULL;
+                g_free(*buffer); *buffer = NULL;
+#endif
+                break;
+            }
+        }
+        g_free(user);
+        g_match_info_next(match_info, NULL);
+    }
+    g_free(plain);
+    g_strfreev(candidates);
+    g_match_info_free(match_info);
+}
+
+
 static gboolean
 receiving_im_cb(PurpleAccount *account, char **sender, char **buffer,
                 PurpleConversation *conv, PurpleMessageFlags *flags, void *data)
@@ -1506,21 +1575,20 @@
 
     gint service = get_service_type(conv);
 
-    if(service != unknown_service) {
-        /* suppress notification of incoming messages. */
-        if(purple_prefs_get_bool(OPT_PREVENT_NOTIFICATION))
-            *flags |= PURPLE_MESSAGE_SYSTEM;
-    }
-
-    /* quick hack to suppress annoying completion message from wassr */
+    /* suppress notification of incoming messages. */
+    if(service != unknown_service &&
+       purple_prefs_get_bool(OPT_PREVENT_NOTIFICATION))
+        *flags |= PURPLE_MESSAGE_SYSTEM;
+
     if(service == wassr_service) {
+        /* suppress annoying completion message from wassr */
         if(strstr(*buffer, "<body>投稿完了:") ||
            strstr(*buffer, "<body>チャンネル投稿完了:")) {
             twitter_debug("clearing sender and buffer\n");
             g_free(*sender); *sender = NULL;
             g_free(*buffer); *buffer = NULL;
         }
-        /* fix for parrot problem during post to a channel */
+        /* discard parrot message */
         else if(wassr_post &&
                 strlen(wassr_post) &&
                 strstr(*buffer, wassr_post)) {
@@ -1531,6 +1599,7 @@
     }
 
     if(service == identica_service) {
+        /* discard parrot message */
         gchar *stripped = strip_html_markup(*buffer);
         if(identica_post &&
            strlen(identica_post) &&
@@ -1543,6 +1612,12 @@
         g_free(stripped);
     }
 
+    /* filtering */
+    if(purple_prefs_get_bool(OPT_FILTER)) {
+        apply_filter(sender, buffer, flags, service);
+    }
+
+    /* return here if it is not twitter */
     if(service != twitter_service) {
         return FALSE;
     }
@@ -2764,6 +2839,39 @@
 
 
 
+    /***************/
+    /* filter page */
+    /***************/
+    e = GTK_WIDGET(gtk_builder_get_object (builder, "filter_check"));
+    g_object_set_data(G_OBJECT(e), "pref", OPT_FILTER);
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(e),
+                                 purple_prefs_get_bool(OPT_FILTER));
+    g_signal_connect(e, "toggled",
+                     G_CALLBACK(bool_toggled_cb), &e);
+
+    e = GTK_WIDGET(gtk_builder_get_object (builder, "filter_twitter"));
+    g_object_set_data(G_OBJECT(e), "pref", OPT_FILTER_TWITTER);
+    text = purple_prefs_get_string(OPT_FILTER_TWITTER);
+    gtk_entry_set_text(GTK_ENTRY(e), text);
+    g_signal_connect(e, "changed",
+                     G_CALLBACK(text_changed_cb), &e);
+
+    e = GTK_WIDGET(gtk_builder_get_object (builder, "filter_wassr"));
+    g_object_set_data(G_OBJECT(e), "pref", OPT_FILTER_WASSR);
+    text = purple_prefs_get_string(OPT_FILTER_WASSR);
+    gtk_entry_set_text(GTK_ENTRY(e), text);
+    g_signal_connect(e, "changed",
+                     G_CALLBACK(text_changed_cb), &e);
+
+    e = GTK_WIDGET(gtk_builder_get_object (builder, "filter_identica"));
+    g_object_set_data(G_OBJECT(e), "pref", OPT_FILTER_IDENTICA);
+    text = purple_prefs_get_string(OPT_FILTER_IDENTICA);
+    gtk_entry_set_text(GTK_ENTRY(e), text);
+    g_signal_connect(e, "changed",
+                     G_CALLBACK(text_changed_cb), &e);
+
+
+
     /*************/
     /* icon page */
     /*************/
@@ -2968,7 +3076,7 @@
     PURPLE_PRIORITY_DEFAULT,    /**< priority	*/
     PLUGIN_ID,                  /**< id		*/
     "Pidgin-Twitter",           /**< name	*/
-    "0.7.0",                    /**< version	*/
+    "0.8.0d1",                  /**< version	*/
     "provides useful features for twitter", /**  summary	*/
     "provides useful features for twitter", /**  desc	*/
     "Yoshiki Yazawa, mikanbako, \nKonosuke Watanabe, IWATA Ray, \nmojin, umq, \nthe pidging-twitter team",     /**< author	*/
@@ -3024,6 +3132,11 @@
     purple_prefs_add_int(OPT_ICON_MAX_COUNT, DEFAULT_ICON_MAX_COUNT);
     purple_prefs_add_int(OPT_ICON_MAX_DAYS, DEFAULT_ICON_MAX_DAYS);
     purple_prefs_add_bool(OPT_LOG_OUTPUT, FALSE);
+
+    purple_prefs_add_bool(OPT_FILTER, TRUE);
+    purple_prefs_add_string(OPT_FILTER_TWITTER, DEFAULT_LIST);
+    purple_prefs_add_string(OPT_FILTER_WASSR, DEFAULT_LIST);
+    purple_prefs_add_string(OPT_FILTER_IDENTICA, DEFAULT_LIST);
 }
 
 PURPLE_INIT_PLUGIN(pidgin_twitter, init_plugin, info)
--- a/pidgin-twitter.h	Sat Aug 23 04:17:49 2008 +0900
+++ b/pidgin-twitter.h	Mon Aug 25 21:17:02 2008 +0900
@@ -121,6 +121,10 @@
 #define OPT_ICON_MAX_DAYS       OPT_PIDGINTWITTER "/icon_max_days"
 #define OPT_API_BASE_GET_INTERVAL OPT_PIDGINTWITTER "/api_base_get_interval"
 #define OPT_LOG_OUTPUT          OPT_PIDGINTWITTER "/log_output"
+#define OPT_FILTER              OPT_PIDGINTWITTER "/filter"
+#define OPT_FILTER_TWITTER      OPT_PIDGINTWITTER "/filter_twitter"
+#define OPT_FILTER_WASSR        OPT_PIDGINTWITTER "/filter_wassr"
+#define OPT_FILTER_IDENTICA     OPT_PIDGINTWITTER "/filter_identica"
 
 /* formats and templates */
 #define RECIPIENT_FORMAT_TWITTER "@<a href='http://twitter.com/%s'>%s</a>"
@@ -247,5 +251,6 @@
 static void combo_changed_cb(gpointer *data);
 static void disconnect_prefs_cb(GtkObject *object, gpointer data);
 static GtkWidget *prefs_get_frame(PurplePlugin *plugin);
+static void apply_filter(gchar **sender, gchar **buffer, PurpleMessageFlags *flags, int service);
 
 #endif
--- a/prefs.ui	Sat Aug 23 04:17:49 2008 +0900
+++ b/prefs.ui	Mon Aug 25 21:17:02 2008 +0900
@@ -453,6 +453,222 @@
           </packing>
         </child>
         <child>
+          <object class="GtkVBox" id="vbox6">
+            <property name="visible">True</property>
+            <child>
+              <object class="GtkAlignment" id="alignment61">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="top_padding">4</property>
+                <property name="bottom_padding">4</property>
+                <property name="left_padding">4</property>
+                <child>
+                  <object class="GtkLabel" id="label35">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;Filter&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment60">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="left_padding">20</property>
+                <child>
+                  <object class="GtkCheckButton" id="filter_check">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Apply filters</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">2</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment43">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="top_padding">4</property>
+                <property name="bottom_padding">4</property>
+                <property name="left_padding">4</property>
+                <child>
+                  <object class="GtkLabel" id="label31">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">&lt;b&gt;User list for filtering&lt;/b&gt;</property>
+                    <property name="use_markup">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox10">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment44">
+                    <property name="visible">True</property>
+                    <property name="left_padding">20</property>
+                    <child>
+                      <object class="GtkLabel" id="label32">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">twitter</property>
+                        <property name="max_width_chars">10</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment55">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="right_padding">4</property>
+                    <child>
+                      <object class="GtkEntry" id="filter_twitter">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="width_chars">35</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">2</property>
+                <property name="position">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox11">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment56">
+                    <property name="visible">True</property>
+                    <property name="left_padding">20</property>
+                    <child>
+                      <object class="GtkLabel" id="label33">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">wassr</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment57">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="right_padding">4</property>
+                    <child>
+                      <object class="GtkEntry" id="filter_wassr">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="width_chars">35</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">2</property>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox12">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkAlignment" id="alignment58">
+                    <property name="visible">True</property>
+                    <property name="left_padding">20</property>
+                    <child>
+                      <object class="GtkLabel" id="label34">
+                        <property name="visible">True</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">identi.ca</property>
+                        <property name="max_width_chars">10</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment59">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="right_padding">4</property>
+                    <child>
+                      <object class="GtkEntry" id="filter_identica">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="width_chars">35</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="padding">2</property>
+                <property name="position">5</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="label30">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">&lt;b&gt;Filter&lt;/b&gt;</property>
+            <property name="use_markup">True</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
           <object class="GtkVBox" id="vbox1">
             <property name="visible">True</property>
             <child>
@@ -498,46 +714,41 @@
                 <property name="visible">True</property>
                 <property name="n_columns">4</property>
                 <child>
-                  <object class="GtkAlignment" id="alignment18">
-                    <property name="visible">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">2</property>
-                    <property name="right_attach">3</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment16">
-                    <property name="visible">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="y_options"></property>
-                  </packing>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment45">
+                  <placeholder/>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment40">
                     <property name="visible">True</property>
-                    <property name="right_padding">20</property>
+                    <property name="left_padding">40</property>
                     <child>
-                      <object class="GtkLabel" id="label27">
+                      <object class="GtkLabel" id="label24">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">pixel</property>
+                        <property name="label" translatable="yes">Icon size</property>
                       </object>
                     </child>
                   </object>
                   <packing>
-                    <property name="left_attach">3</property>
-                    <property name="right_attach">4</property>
                     <property name="x_options"></property>
                     <property name="y_options"></property>
                   </packing>
@@ -564,17 +775,46 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment40">
+                  <object class="GtkAlignment" id="alignment45">
                     <property name="visible">True</property>
-                    <property name="left_padding">40</property>
+                    <property name="right_padding">20</property>
                     <child>
-                      <object class="GtkLabel" id="label24">
+                      <object class="GtkLabel" id="label27">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">Icon size</property>
+                        <property name="label" translatable="yes">pixel</property>
                       </object>
                     </child>
                   </object>
                   <packing>
+                    <property name="left_attach">3</property>
+                    <property name="right_attach">4</property>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment16">
+                    <property name="visible">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment18">
+                    <property name="visible">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="right_attach">3</property>
                     <property name="x_options"></property>
                     <property name="y_options"></property>
                   </packing>
@@ -629,72 +869,60 @@
                 <property name="visible">True</property>
                 <property name="n_columns">6</property>
                 <child>
-                  <object class="GtkAlignment" id="alignment19">
-                    <property name="visible">True</property>
-                    <child>
-                      <placeholder/>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">1</property>
-                    <property name="right_attach">2</property>
-                    <property name="y_options"></property>
-                  </packing>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment50">
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment52">
                     <property name="visible">True</property>
-                    <property name="left_padding">40</property>
+                    <property name="right_padding">20</property>
                     <child>
-                      <object class="GtkLabel" id="label25">
+                      <object class="GtkLabel" id="label18">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">Update every</property>
+                        <property name="label" translatable="yes">days</property>
                       </object>
                     </child>
                   </object>
                   <packing>
+                    <property name="left_attach">5</property>
+                    <property name="right_attach">6</property>
                     <property name="x_options"></property>
                     <property name="y_options"></property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment51">
-                    <property name="visible">True</property>
-                    <property name="left_padding">4</property>
-                    <child>
-                      <object class="GtkSpinButton" id="icon_max_count_spin">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="climb_rate">1</property>
-                        <property name="snap_to_ticks">True</property>
-                        <property name="numeric">True</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">2</property>
-                    <property name="right_attach">3</property>
-                    <property name="x_options"></property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkAlignment" id="alignment53">
-                    <property name="visible">True</property>
-                    <child>
-                      <object class="GtkLabel" id="label3">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">times  or</property>
-                      </object>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="left_attach">3</property>
-                    <property name="right_attach">4</property>
-                    <property name="y_options"></property>
-                  </packing>
-                </child>
-                <child>
                   <object class="GtkAlignment" id="alignment54">
                     <property name="visible">True</property>
                     <property name="left_padding">4</property>
@@ -717,23 +945,71 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkAlignment" id="alignment52">
+                  <object class="GtkAlignment" id="alignment53">
                     <property name="visible">True</property>
-                    <property name="right_padding">20</property>
                     <child>
-                      <object class="GtkLabel" id="label18">
+                      <object class="GtkLabel" id="label3">
                         <property name="visible">True</property>
-                        <property name="label" translatable="yes">days</property>
+                        <property name="label" translatable="yes">times  or</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">3</property>
+                    <property name="right_attach">4</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment51">
+                    <property name="visible">True</property>
+                    <property name="left_padding">4</property>
+                    <child>
+                      <object class="GtkSpinButton" id="icon_max_count_spin">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="climb_rate">1</property>
+                        <property name="snap_to_ticks">True</property>
+                        <property name="numeric">True</property>
                       </object>
                     </child>
                   </object>
                   <packing>
-                    <property name="left_attach">5</property>
-                    <property name="right_attach">6</property>
+                    <property name="left_attach">2</property>
+                    <property name="right_attach">3</property>
                     <property name="x_options"></property>
                     <property name="y_options"></property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment50">
+                    <property name="visible">True</property>
+                    <property name="left_padding">40</property>
+                    <child>
+                      <object class="GtkLabel" id="label25">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Update every</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkAlignment" id="alignment19">
+                    <property name="visible">True</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="expand">False</property>
@@ -743,7 +1019,7 @@
             </child>
           </object>
           <packing>
-            <property name="position">2</property>
+            <property name="position">3</property>
           </packing>
         </child>
         <child type="tab">
@@ -753,7 +1029,7 @@
             <property name="use_markup">True</property>
           </object>
           <packing>
-            <property name="position">4</property>
+            <property name="position">3</property>
             <property name="tab_fill">False</property>
           </packing>
         </child>
@@ -822,7 +1098,7 @@
                       <object class="GtkEntry" id="sound_recip_list">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="width_chars">30</property>
+                        <property name="width_chars">35</property>
                       </object>
                     </child>
                   </object>
@@ -954,7 +1230,7 @@
                       <object class="GtkEntry" id="sound_send_list">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="width_chars">30</property>
+                        <property name="width_chars">35</property>
                       </object>
                     </child>
                   </object>
@@ -1025,7 +1301,7 @@
             </child>
           </object>
           <packing>
-            <property name="position">3</property>
+            <property name="position">4</property>
           </packing>
         </child>
         <child type="tab">
@@ -1035,7 +1311,7 @@
             <property name="use_markup">True</property>
           </object>
           <packing>
-            <property name="position">3</property>
+            <property name="position">4</property>
             <property name="tab_fill">False</property>
           </packing>
         </child>
@@ -1170,7 +1446,7 @@
             </child>
           </object>
           <packing>
-            <property name="position">4</property>
+            <property name="position">5</property>
           </packing>
         </child>
         <child type="tab">
@@ -1180,7 +1456,7 @@
             <property name="use_markup">True</property>
           </object>
           <packing>
-            <property name="position">4</property>
+            <property name="position">5</property>
             <property name="tab_fill">False</property>
           </packing>
         </child>