chiark / gitweb /
Better visual feedback in users window: the apply button is
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 14 Jun 2008 12:52:34 +0000 (13:52 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sat, 14 Jun 2008 12:52:34 +0000 (13:52 +0100)
desensitized if it will not work an an error message is constantly
displayed.  If there are multiple errors you only get one, but they go
in vertical order of text entry fields.

cgi/actions.c
disobedience/users.c
lib/Makefile.am
lib/email.c [new file with mode: 0644]
lib/sendmail.h
server/server.c

index 449c5dcafa4028ff9ed59e810689c4b272297a6a..8bbce8787a97642a087c2900f73f5843917a2863 100644 (file)
@@ -434,7 +434,8 @@ static void act_register(void) {
     return;
   }
   /* We could well do better address validation but for now we'll just do the
-   * minimum */
+   * minimum
+   /* TODO use email_valid() */
   if(!strchr(email, '@')) {
     login_error("bademail");
     return;
@@ -524,6 +525,7 @@ static void act_edituser(void) {
     }
   } else
     password = password2 = 0;
+  /* TODO use email_valid() */
   if(email && !strchr(email, '@')) {
     login_error("bademail");
     return;
index af42858a1ec2010f91d6649e63de3a206f3d5297..bb099f2d7ac27ab39ea7e57f2941a282809f5bc4 100644 (file)
 
 #include "disobedience.h"
 #include "bits.h"
+#include "sendmail.h"
+
+static void users_details_sensitize_all(void);
+static void users_set_report(const char *msg);
 
 static GtkWidget *users_window;
 static GtkListStore *users_list;
@@ -54,6 +58,7 @@ static GtkWidget *users_details_email;
 static GtkWidget *users_details_password;
 static GtkWidget *users_details_password2;
 static GtkWidget *users_details_rights[32];
+static GtkWidget *users_reporter;
 static int users_details_row;
 static const char *users_selected;
 static const char *users_deferred_select;
@@ -165,6 +170,11 @@ static void users_detail_generic(const char *title,
                    1, 1);               /* x/ypadding */
 }
 
+static void users_entry_changed(GtkEditable attribute((unused)) *editable,
+                                gpointer attribute((unused)) user_data) {
+  users_details_sensitize_all();
+}
+
 /** @brief Add a row to the user details table
  * @param entryp Where to put GtkEntry
  * @param title Label for this row
@@ -179,6 +189,8 @@ static void users_add_detail(GtkWidget **entryp,
 
   if(!(entry = *entryp)) {
     *entryp = entry = gtk_entry_new();
+    g_signal_connect(entry, "changed",
+                     G_CALLBACK(users_entry_changed), 0);
     users_detail_generic(title, entry);
   }
   gtk_entry_set_visibility(GTK_ENTRY(entry),
@@ -220,6 +232,7 @@ static void users_details_sensitize(rights_type r) {
 /** @brief Set sensitivity of everything in sight */
 static void users_details_sensitize_all(void) {
   int n;
+  const char *report = 0;
 
   for(n = 0; n < 32; ++n)
     if(users_details_rights[n])
@@ -231,8 +244,42 @@ static void users_details_sensitize_all(void) {
   users_details_sensitize(RIGHT_MOVE_ANY);
   users_details_sensitize(RIGHT_REMOVE_ANY);
   users_details_sensitize(RIGHT_SCRATCH_ANY);
-  gtk_widget_set_sensitive(users_apply_button, users_mode != MODE_NONE);
+  int apply_sensitive = 1;
+  if(users_mode == MODE_NONE)
+    apply_sensitive = 0;
+  else {
+    const char *name = gtk_entry_get_text(GTK_ENTRY(users_details_name));
+    const char *email = gtk_entry_get_text(GTK_ENTRY(users_details_email));
+    const char *pw = gtk_entry_get_text(GTK_ENTRY(users_details_password));
+    const char *pw2 = gtk_entry_get_text(GTK_ENTRY(users_details_password2));
+    /* Username must be filled in */
+    if(!*name) {
+      apply_sensitive = 0;
+      if(!report)
+        report = "Must fill in username";
+    }
+    /* Passwords must be nontrivial and match */
+    if(!*pw) {
+      apply_sensitive = 0;
+      if(!report)
+        report = "Must fill in password";
+    }
+    if(strcmp(pw, pw2)) {
+      apply_sensitive = 0;
+      if(!report)
+        report = "Passwords must match";
+    }
+    /* Email address must be somewhat valid */
+    if(*email) {
+      if(!email_valid(email)) {
+        apply_sensitive = 0;
+        report = "Invalid email address";
+      }
+    }
+  }
+  gtk_widget_set_sensitive(users_apply_button, apply_sensitive);
   gtk_widget_set_sensitive(users_delete_button, !!users_selected);
+  users_set_report(report);
 }
 
 /** @brief Called when an _ALL widget is toggled
@@ -593,6 +640,19 @@ static void users_selection_changed(GtkTreeSelection attribute((unused)) *treese
   mode(NONE);                           /* not editing *yet* */
 }
 
+static GtkWidget *users_make_reporter() {
+  if(!users_reporter) {
+    users_reporter = gtk_label_new("");
+    gtk_label_set_ellipsize(GTK_LABEL(users_reporter), PANGO_ELLIPSIZE_END);
+    gtk_misc_set_alignment(GTK_MISC(users_reporter), 0.99, 0);
+  }
+  return users_reporter;
+}
+
+static void users_set_report(const char *msg) {
+  gtk_label_set_text(GTK_LABEL(users_make_reporter()), msg ? msg : "");
+}
+
 /** @brief Table of buttons below the user list */
 static struct button users_buttons[] = {
   {
@@ -674,6 +734,10 @@ void manage_users(void) {
   vbox2 = gtk_vbox_new(FALSE, 0);
   gtk_box_pack_start(GTK_BOX(vbox2), users_details_table,
                      TRUE/*expand*/, TRUE/*fill*/, 0);
+  gtk_box_pack_start(GTK_BOX(vbox2), gtk_hseparator_new(),
+                     FALSE/*expand*/, FALSE, 0);
+  gtk_box_pack_start(GTK_BOX(vbox2), users_make_reporter(),
+                     FALSE/*expand*/, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(vbox2), hbox2,
                      FALSE/*expand*/, FALSE, 0);
   
index 86886eb66981842eeea83ce48ffd2350137b4c4d..f2943cc62b76aab98cd3737e3ae298d0195e08ba 100644 (file)
@@ -44,6 +44,7 @@ libdisorder_a_SOURCES=charset.c charset.h             \
        dateparse.c dateparse.h xgetdate.c              \
        defs.c defs.h                                   \
        eclient.c eclient.h                             \
+       email.c                                         \
        eventdist.c eventdist.h                         \
        event.c event.h                                 \
        eventlog.c eventlog.h                           \
diff --git a/lib/email.c b/lib/email.c
new file mode 100644 (file)
index 0000000..fb2f744
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * This file is part of DisOrder
+ * Copyright (C) 2008 Richard Kettlewell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/** @file lib/email.c
+ * @brief Email addresses
+ */
+
+#include "common.h"
+
+#include "sendmail.h"
+
+/** @brief Test email address validity
+ * @param address to verify
+ * @return 1 if it might be valid, 0 if it is definitely not
+ *
+ * This function doesn't promise to tell you whether an address is deliverable,
+ * it just does basic syntax checks.
+ */
+int email_valid(const char *address) {
+  /* There must be an '@' sign */
+  const char *at = strchr(address, '@');
+  if(!at)
+    return 0;
+  /* There must be only one of them */
+  if(strchr(at + 1, '@'))
+    return 0;
+  /* It mustn't be the first or last character */
+  if(at == address || !at[1])
+    return 0;
+  /* Local part must be valid */
+  /* TODO */
+  /* Domain part must be valid */
+  /* TODO */
+  return 1;
+}
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
index e8d87a0805e8205ef235260bd71dd492c42f09da..958cd79cea1f02ff8de1adafaade0edde7bf1279 100644 (file)
@@ -35,6 +35,7 @@ pid_t sendmail_subprocess(const char *sender,
                           const char *encoding,
                           const char *content_type,
                           const char *body);
+int email_valid(const char *address);
 
 #endif /* SENDMAIL_H */
 
index 09f5098a81c06b3060a692ff255f51a0a24cb4ff..6cfed04f2c30b37e5716cbf2dfe37dc8924e12bb 100644 (file)
@@ -1404,6 +1404,7 @@ static int c_reminder(struct conn *c,
     sink_writes(ev_writer_sink(c->w), "550 Cannot send a reminder email\n");
     return 1;
   }
+  /* TODO use email_valid() */
   if(!(email = kvp_get(k, "email"))
      || !strchr(email, '@')) {
     error(0, "user '%s' has no valid email address", vec[0]);