chiark / gitweb /
Adding a user from Disobedience now works.
[disorder] / disobedience / users.c
index 80b6f421d49c53fce1a1b850787e5d704d324cb4..d345c4ce34d633061230f25891950ebb6439af44 100644 (file)
@@ -57,6 +57,13 @@ static int users_mode;
 #define MODE_ADD 1
 #define MODE_EDIT 2
 
+#define mode(X) do {                                    \
+  users_mode = MODE_##X;                                \
+  if(0) fprintf(stderr, "%s:%d: %s(): mode -> %s\n",    \
+          __FILE__, __LINE__, __FUNCTION__, #X);        \
+  users_details_sensitize_all();                        \
+} while(0)
+
 static const char *users_email, *users_rights, *users_password;
 
 /** @brief qsort() callback for username comparison */
@@ -66,9 +73,10 @@ static int usercmp(const void *a, const void *b) {
 
 /** @brief Called with the list of users
  *
- * Currently this is called when the window is created, and is responsible for
- * showing it.  There's currently no facility for refreshing the list, which
- * hopefuly would preserve the select user (if any).
+ * Called:
+ * - at startup to populate the initial list
+ * - when we add a user
+ * - maybe in the future when we delete a user
  */
 static void users_got_list(void attribute((unused)) *v, int nvec, char **vec) {
   int n;
@@ -159,36 +167,28 @@ static void users_add_right(const char *title,
 static void users_details_sensitize(rights_type r) {
   const int bit = leftmost_bit(r);
   const GtkWidget *all = users_details_rights[bit];
-  const int sensitive = !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(all));
-  
+  const int sensitive = (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(all))
+                         && users_mode != MODE_NONE);
+
   gtk_widget_set_sensitive(users_details_rights[bit + 1], sensitive);
   gtk_widget_set_sensitive(users_details_rights[bit + 2], sensitive);
 }
 
 /** @brief Set sensitivity of everything in sight */
 static void users_details_sensitize_all(void) {
-  int apply_sensitive;
+  int n;
 
-  /* Three-right groups */
+  for(n = 0; n < 32; ++n)
+    if(users_details_rights[n])
+      gtk_widget_set_sensitive(users_details_rights[n], users_mode != MODE_NONE);
+  gtk_widget_set_sensitive(users_details_name, users_mode != MODE_NONE);
+  gtk_widget_set_sensitive(users_details_email, users_mode != MODE_NONE);
+  gtk_widget_set_sensitive(users_details_password, users_mode != MODE_NONE);
+  gtk_widget_set_sensitive(users_details_password2, users_mode != MODE_NONE);
   users_details_sensitize(RIGHT_MOVE_ANY);
   users_details_sensitize(RIGHT_REMOVE_ANY);
   users_details_sensitize(RIGHT_SCRATCH_ANY);
-  /* Apply button */
-  switch(users_mode) {
-  case MODE_NONE:
-    apply_sensitive = 0;
-    break;
-  case MODE_EDIT:
-    apply_sensitive = 1;
-    break;
-  case MODE_ADD:
-    apply_sensitive = !!*gtk_entry_get_text(GTK_ENTRY(users_details_name));
-    break;
-  default:
-    assert(!"reached");
-  }
-  gtk_widget_set_sensitive(users_apply_button, apply_sensitive);
-  /* Delete button */
+  gtk_widget_set_sensitive(users_apply_button, users_mode != MODE_NONE);
   gtk_widget_set_sensitive(users_delete_button, !!users_selected);
 }
 
@@ -295,29 +295,103 @@ static void users_add(GtkButton attribute((unused)) *button,
   /* Unselect whatever is selected */
   gtk_tree_selection_unselect_all(users_selection);
   /* Reset the form */
+  /* TODO it would be better to use the server default_rights if there's no
+   * client setting. */
   users_makedetails("",
                     "",
-                    "",                 /* TODO default_rights */
+                    config->default_rights,
                     "",
                     DETAIL_EDITABLE|DETAIL_VISIBLE,
                     DETAIL_EDITABLE|DETAIL_VISIBLE);
   /* Remember we're adding a user */
-  users_mode = MODE_ADD;
+  mode(ADD);
+}
+
+static rights_type users_get_rights(void) {
+  rights_type r = 0;
+  int n;
+
+  /* Extract the rights value */
+  for(n = 0; n < 32; ++n) {
+    if(users_details_rights[n])
+      if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(users_details_rights[n])))
+         r |= 1 << n;
+  }
+  /* Throw out redundant bits */
+  if(r & RIGHT_REMOVE_ANY)
+    r &= ~(rights_type)(RIGHT_REMOVE_MINE|RIGHT_REMOVE_RANDOM);
+  if(r & RIGHT_MOVE_ANY)
+    r &= ~(rights_type)(RIGHT_MOVE_MINE|RIGHT_MOVE_RANDOM);
+  if(r & RIGHT_SCRATCH_ANY)
+    r &= ~(rights_type)(RIGHT_SCRATCH_MINE|RIGHT_SCRATCH_RANDOM);
+  return r;
+}
+
+static void users_adduser_completed(void *v) {
+  struct callbackdata *cbd = v;
+
+  /* Now the user is created we can go ahead and set the email address */
+  if(*cbd->u.edituser.email)
+    disorder_eclient_edituser(client, NULL, cbd->u.edituser.user,
+                              "email", cbd->u.edituser.email, cbd);
+  /* Refresh the list of users */
+  disorder_eclient_users(client, users_got_list, 0);
+}
+
+static void users_adduser_failed(struct callbackdata attribute((unused)) *cbd,
+                                 int attribute((unused)) code,
+                                 const char *msg) {
+  popup_submsg(users_window, GTK_MESSAGE_ERROR, msg);
 }
 
 /** @brief Called when the 'Apply' button is pressed */
 static void users_apply(GtkButton attribute((unused)) *button,
                         gpointer attribute((unused)) userdata) {
+  struct callbackdata *cbd;
+
   switch(users_mode) {
   case MODE_NONE:
     return;
   case MODE_ADD:
-    if(!*gtk_entry_get_text(GTK_ENTRY(users_details_name)))
+    if(!*gtk_entry_get_text(GTK_ENTRY(users_details_name))) {
+      /* No username.  Really we wanted to desensitize the Apply button when
+       * there's no userame but there doesn't seem to be a signal to detect
+       * changes to the entry text.  Consequently we have error messages
+       * instead.  */
+      popup_submsg(users_window, GTK_MESSAGE_ERROR, "Must enter a username");
+      return;
+    }
+    if(strcmp(gtk_entry_get_text(GTK_ENTRY(users_details_password)),
+              gtk_entry_get_text(GTK_ENTRY(users_details_password2)))) {
+      popup_submsg(users_window, GTK_MESSAGE_ERROR, "Passwords do not match");
+      return;
+    }
+    cbd = xmalloc(sizeof *cbd);
+    cbd->onerror = users_adduser_failed;
+    cbd->u.edituser.user = xstrdup(gtk_entry_get_text(GTK_ENTRY(users_details_name)));
+    cbd->u.edituser.email = xstrdup(gtk_entry_get_text(GTK_ENTRY(users_details_email)));
+    if(*cbd->u.edituser.email && !strchr(cbd->u.edituser.email, '@')) {
+      /* The server will complain about this but we can give a better error
+       * message this way */
+      popup_submsg(users_window, GTK_MESSAGE_ERROR, "Invalid email address");
       return;
-    /* TODO create user */
+    }
+    disorder_eclient_adduser(client, users_adduser_completed,
+                             cbd->u.edituser.user,
+                             xstrdup(gtk_entry_get_text(GTK_ENTRY(users_details_password))),
+                             rights_string(users_get_rights()),
+                             cbd);
+    mode(NONE);
     break;
   case MODE_EDIT:
+    if(strcmp(gtk_entry_get_text(GTK_ENTRY(users_details_password)),
+              gtk_entry_get_text(GTK_ENTRY(users_details_password2)))) {
+      popup_submsg(users_window, GTK_MESSAGE_ERROR, "Passwords do not match");
+      return;
+    }
     /* TODO */
+    mode(NONE);
+    popup_submsg(users_window, GTK_MESSAGE_INFO, "Would edit user");
     break;
   }
 }
@@ -326,7 +400,7 @@ static void users_apply(GtkButton attribute((unused)) *button,
 static void users_deleted_error(struct callbackdata attribute((unused)) *cbd,
                                int attribute((unused)) code,
                                const char *msg) {
-  popup_msg(GTK_MESSAGE_ERROR, msg);
+  popup_submsg(users_window, GTK_MESSAGE_ERROR, msg);
 }
 
 /** @brief Called when a user has been deleted */
@@ -393,7 +467,7 @@ static void users_got_password(void attribute((unused)) *v, const char *value) {
                     users_password,
                     DETAIL_VISIBLE,
                     DETAIL_EDITABLE|DETAIL_VISIBLE);
-  users_mode = MODE_EDIT;
+  mode(EDIT);
 }
 
 /** @brief Called when the selection MIGHT have changed */
@@ -421,13 +495,15 @@ static void users_selection_changed(GtkTreeSelection attribute((unused)) *treese
   users_makedetails("", "", "", "",
                     DETAIL_VISIBLE,
                     DETAIL_VISIBLE);
-  disorder_eclient_userinfo(client, users_got_email, users_selected,
-                            "email", 0);
-  disorder_eclient_userinfo(client, users_got_rights, users_selected,
-                            "rights", 0);
-  disorder_eclient_userinfo(client, users_got_password, users_selected,
-                            "password", 0);
-  users_mode = MODE_NONE;               /* not editing *yet* */
+  if(users_selected) {
+    disorder_eclient_userinfo(client, users_got_email, users_selected,
+                              "email", 0);
+    disorder_eclient_userinfo(client, users_got_rights, users_selected,
+                              "rights", 0);
+    disorder_eclient_userinfo(client, users_got_password, users_selected,
+                              "password", 0);
+  }
+  mode(NONE);                           /* not editing *yet* */
 }
 
 /** @brief Table of buttons below the user list */
@@ -498,10 +574,11 @@ void manage_users(void) {
   gtk_box_pack_start(GTK_BOX(vbox), buttons, FALSE/*expand*/, FALSE, 0);
 
   /* Create an empty user details table, and put an apply button below it */
+  users_apply_button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
   users_makedetails("", "", "", "",
                     DETAIL_VISIBLE,
                     DETAIL_VISIBLE);
-  users_apply_button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
+  /* TODO apply button is much too wide right now... */
   g_signal_connect(users_apply_button, "clicked",
                    G_CALLBACK(users_apply), NULL);
   vbox2 = gtk_vbox_new(FALSE, 2);
@@ -510,7 +587,7 @@ void manage_users(void) {
   gtk_box_pack_start(GTK_BOX(vbox2), users_apply_button,
                      FALSE/*expand*/, FALSE, 0);
   
-    /* User details are to the right of the list */
+  /* User details are to the right of the list */
   hbox = gtk_hbox_new(FALSE, 2);
   gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE/*expand*/, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(hbox), vbox2, TRUE/*expand*/, TRUE/*fill*/, 0);