Crossfire Client, Trunk  R20996
account.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
19 #include "client.h"
20 
21 #include <ctype.h>
22 #include <gtk/gtk.h>
23 
24 #include "image.h"
25 #include "main.h"
26 #include "metaserver.h"
27 #include "gtk2proto.h"
28 
29 #ifdef WIN32
30 # include "script.h"
31 #endif
32 
33 /* These are in the login_window */
36 
37 /* These are in the create_account_window */
42 
43 /* These are in the choose_character window */
47 
48 /* These are in the new_character window */
52 
53 /* These are in the account_password window */
57 
58 GtkListStore *character_store;
59 
60 /* create_char.c also uses this */
61 char account_password[256];
62 
63 /* This enum just maps the columns in the list store to their position.
64  */
67  };
68 #define CHAR_NUM_COLUMNS 8
69 
70 /* These are in the add_character window */
71 static GtkWidget *button_do_add_character,
74 
77 
78 /* These are used as offsets for num_text_views - we share the drawing code in
79  * info.c if more textviews are added, note that NUM_TEXT_VIEWS in info.c
80  * needs to be increased.
81  */
82 #define TEXTVIEW_MOTD 0
83 #define TEXTVIEW_NEWS 1
84 #define TEXTVIEW_RULES_ACCOUNT 2
85 #define TEXTVIEW_RULES_CHAR 3
86 
88 
89 extern int num_text_views;
90 
91 static int has_init = 0;
92 
100  extern GtkWidget *treeview_look;
101  gtk_widget_hide(connect_window);
102 
103  if (has_init) {
104  /* If we have not initialized, nothing to hide */
105  gtk_widget_hide(new_character_window);
106  create_character_window_hide(); /* create_char.c */
107 
108  /* If the player has started playing (this function being called from
109  * AddMeSuccess), we want to make sure that the extended command entry
110  * widget is not activated - we want normal command entry. Where this
111  * shows up is if the player was playing before and uses a savebed -
112  * now the last thing activated is that entry widget.
113  */
114  gtk_widget_grab_focus(GTK_WIDGET(treeview_look));
115  }
116 }
117 
126 gboolean on_window_delete_event(GtkWidget *window, gpointer *user_data) {
127  return TRUE;
128 }
129 
130 /*****************************************************************************
131  * New character window functions
132  *****************************************************************************/
133 
145 void create_new_character_failure(char *message) {
146  GtkWidget *dialog;
147 
148  dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
149  GTK_MESSAGE_QUESTION, GTK_BUTTONS_OK,
150  "Error: %s", message);
151  gtk_dialog_run(GTK_DIALOG(dialog));
152  gtk_widget_destroy(dialog);
153 }
154 
155 static void create_new_character() {
156  const char *name;
157  guint8 buf[MAX_BUF];
158  SockList sl;
159 
160  SockList_Init(&sl, buf);
161 
162  name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
163 
164  if (!name || *name == 0) {
165  gtk_label_set_text(GTK_LABEL(label_new_char_status),
166  "You must enter a character name.");
167  return;
168  } else {
169  gtk_label_set_text(GTK_LABEL(label_new_char_status), "");
170 
171  SockList_AddString(&sl, "createplayer ");
172  SockList_AddChar(&sl, strlen(name));
173  SockList_AddString(&sl, name);
174  SockList_AddChar(&sl, strlen(account_password));
176  SockList_Send(&sl, csocket.fd);
177  }
178 }
179 
185 void
186 on_button_create_new_char_clicked(GtkButton *button, gpointer user_data) {
188 }
189 
196 void on_entry_new_character_name(GtkEntry *entry, gpointer user_data) {
198 }
199 
206 void
207 on_button_new_char_cancel_clicked(GtkButton *button, gpointer user_data) {
208  gtk_widget_hide(new_character_window);
210 }
211 
217  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "create_character_window"));
218 
219  gtk_window_set_transient_for(
220  GTK_WINDOW(new_character_window), GTK_WINDOW(window_root));
221 
223  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_create_character"));
225  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_cc_cancel"));
227  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "cc_entry_new_character_name"));
229  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "label_cc_status_update"));
230 
231  g_signal_connect((gpointer) new_character_window, "delete_event",
232  G_CALLBACK(on_window_delete_event), NULL);
233  g_signal_connect((gpointer) button_create_new_char, "clicked",
234  G_CALLBACK(on_button_create_new_char_clicked), NULL);
235  g_signal_connect((gpointer) button_new_char_cancel, "clicked",
236  G_CALLBACK(on_button_new_char_cancel_clicked), NULL);
237  g_signal_connect((gpointer) entry_new_character_name, "activate",
238  G_CALLBACK(on_entry_new_character_name), NULL);
239 }
240 
241 /******************************************************************************
242  * add_character_window functions
243  *****************************************************************************/
244 
251 static void add_character_to_account(const char *name, const char *password,
252  int force) {
253  SockList sl;
254  guint8 buf[MAX_BUF];
255 
256  if (!name || !password || *name == 0 || *password == 0) {
257  gtk_label_set_text(GTK_LABEL(label_add_status),
258  "You must enter both a name and password!");
259  } else {
260  gtk_label_set_text(GTK_LABEL(label_add_status), "");
261 
262  SockList_Init(&sl, buf);
263  SockList_AddString(&sl, "accountaddplayer ");
264  SockList_AddChar(&sl, force);
265  SockList_AddChar(&sl, strlen(name));
266  SockList_AddString(&sl, name);
267  SockList_AddChar(&sl, strlen(password));
268  SockList_AddString(&sl, password);
269  SockList_Send(&sl, csocket.fd);
270  }
271 }
272 
284 void account_add_character_failure(char *message) {
285  char *cp;
286  int retry;
287 
288  retry = atoi(message);
289  cp = strchr(message, ' ');
290  if (cp) {
291  cp++;
292  } else {
293  cp = message;
294  }
295 
296  if (!retry) {
297  gtk_label_set_text(GTK_LABEL(label_add_status), cp);
298  } else {
299  /* In this case, we can retry it and it should work if we set force.
300  * So bring up a dialog, as the user what to do - if they enter yes,
301  * we use force. If not, we clear the entry fields and just continue
302  * onward.
303  */
304  GtkWidget *dialog;
305  int result;
306  const char *name, *password;
307 
308  /* Bring up a dialog window */
309  dialog =
310  gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT,
311  GTK_MESSAGE_QUESTION,
312  GTK_BUTTONS_YES_NO, "%s\n%s", cp, "Apply anyways?");
313  result = gtk_dialog_run(GTK_DIALOG(dialog));
314  gtk_widget_destroy(dialog);
315 
316  if (result == GTK_RESPONSE_YES) {
317  name = gtk_entry_get_text(GTK_ENTRY(entry_character_name));
318  password = gtk_entry_get_text(GTK_ENTRY(entry_character_password));
319  add_character_to_account(name, password, 1);
320  } else {
321  gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
322  gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
323  gtk_widget_grab_focus(entry_character_name);
324  }
325  }
326 }
327 
335 void
336 on_button_do_add_character_clicked(GtkButton *button, gpointer user_data) {
338  gtk_entry_get_text(GTK_ENTRY(entry_character_name)),
339  gtk_entry_get_text(GTK_ENTRY(entry_character_password)), 0);
340 }
341 
349 void
351  gpointer user_data) {
352  gtk_notebook_set_current_page(main_notebook, 3);
353 }
354 
363 void on_entry_character(GtkEntry *entry, gpointer user_data) {
364  const char *name, *password;
365 
366  name = gtk_entry_get_text(GTK_ENTRY(entry_character_name));
367  password = gtk_entry_get_text(GTK_ENTRY(entry_character_password));
368 
369  if (name && name[0] && password && password[0]) {
370  add_character_to_account(name, password, 0);
371  } else {
372  const char *cp;
373 
374  /* First case - this widget is empty - do nothing */
375  cp = gtk_entry_get_text(entry);
376  if (!cp || !cp[0]) {
377  return;
378  }
379 
380  /* In this case, this widget is not empty - means the other one is.
381  */
382  if (entry == GTK_ENTRY(entry_character_name)) {
383  gtk_widget_grab_focus(entry_character_password);
384  } else {
385  gtk_widget_grab_focus(entry_character_name);
386  }
387  }
388 }
389 
392  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_do_add_character"));
394  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
395  "button_return_character_select"));
397  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_character_name"));
399  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_character_password"));
401  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "label_add_status"));
402 
403  g_signal_connect((gpointer) button_do_add_character, "clicked",
404  G_CALLBACK(on_button_do_add_character_clicked), NULL);
405  g_signal_connect((gpointer) button_return_character_select, "clicked",
407  g_signal_connect((gpointer) entry_character_name, "activate",
408  G_CALLBACK(on_entry_character), NULL);
409  g_signal_connect((gpointer) entry_character_password, "activate",
410  G_CALLBACK(on_entry_character), NULL);
411 }
412 
413 /*****************************************************************************
414  * choose_char_window
415  ****************************************************************************/
416 
426 
427  /* Store any old/stale entries */
428  gtk_list_store_clear(character_store);
429 }
430 
439  gtk_notebook_set_current_page(main_notebook, 3);
440 }
441 
442 
447 static void play_character(const char *name) {
448  SockList sl;
449  guint8 buf[MAX_BUF];
450 
451  SockList_Init(&sl, buf);
452  SockList_AddString(&sl, "accountplay ");
453  SockList_AddString(&sl, name);
454  SockList_Send(&sl, csocket.fd);
455 }
456 
463 void
464 on_button_play_character_clicked(GtkButton *button, gpointer user_data) {
465  GtkTreeSelection *selected;
466  GtkTreeModel *model;
467  GtkTreeIter iter;
468  char *name;
469 
470  selected = gtk_tree_view_get_selection(GTK_TREE_VIEW(
472 
473  if (gtk_tree_selection_get_selected(selected, &model, &iter)) {
474  gtk_tree_model_get(model, &iter, CHAR_NAME, &name, -1);
476  play_character(name);
477  }
478 }
479 
485 void
486 on_button_create_character_clicked(GtkButton *button, gpointer user_data) {
487  if (serverloginmethod >= 2) {
489  } else {
490  gtk_widget_show(new_character_window);
491  gtk_entry_set_text(GTK_ENTRY(entry_new_character_name), "");
492  }
493 }
494 
501 void
502 on_button_add_character_clicked(GtkButton *button, gpointer user_data) {
503  gtk_notebook_set_current_page(main_notebook, 5);
504  gtk_entry_set_text(GTK_ENTRY(entry_character_name), "");
505  gtk_entry_set_text(GTK_ENTRY(entry_character_password), "");
506  gtk_widget_grab_focus(entry_character_name);
507 }
508 
515 void
516 on_button_return_login_clicked(GtkButton *button, gpointer user_data) {
517  gtk_notebook_set_current_page(main_notebook, 1);
518 }
519 
526 void
527 on_button_account_password_clicked(GtkButton *button, gpointer user_data) {
528  gtk_notebook_set_current_page(main_notebook, 4);
529  /* reset previous values */
530  gtk_entry_set_text(GTK_ENTRY(entry_account_password_current), "");
531  gtk_entry_set_text(GTK_ENTRY(entry_account_password_new), "");
532  gtk_entry_set_text(GTK_ENTRY(entry_account_password_confirm), "");
533 }
534 
549 void update_character_choose(const char *name, const char *class,
550  const char *race, const char *face,
551  const char *party, const char *map,
552  int level, int faceno) {
553  GtkTreeIter iter;
554 
555  gtk_list_store_append(character_store, &iter);
556 
557  /* If this pixmap matches pixmap[0], it means we are caching images and
558  * this image hasn't been set up. It looks better in this case to just
559  * leave that area of the window blank vs drawing a question mark there.
560  */
561  if (pixmaps[faceno] == pixmaps[0]) {
562  gtk_list_store_set(character_store, &iter,
563  CHAR_NAME, name,
564  CHAR_CLASS, class,
565  CHAR_RACE, race,
566  CHAR_IMAGE, face,
567  CHAR_PARTY, party,
568  CHAR_MAP, map,
569  CHAR_LEVEL, level,
570  -1);
571  } else {
572  gtk_list_store_set(character_store, &iter,
573  CHAR_ICON, pixmaps[faceno]->icon_image,
574  CHAR_NAME, name,
575  CHAR_CLASS, class,
576  CHAR_RACE, race,
577  CHAR_IMAGE, face,
578  CHAR_PARTY, party,
579  CHAR_MAP, map,
580  CHAR_LEVEL, level,
581  -1);
582  }
583 }
584 
585 static void init_choose_char_window() {
586  GtkTextIter end;
587  GtkCellRenderer *renderer;
588  GtkTreeViewColumn *column;
589 
591  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_play_character"));
593  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_create_character"));
595  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_add_character"));
597  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_return_login"));
599  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_account_password"));
600  login_pane[TEXTVIEW_RULES_CHAR].textview =
601  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "textview_rules_char"));
602 
604  gtk_text_view_get_buffer(
605  GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_CHAR].textview));
606 
608  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "treeview_choose_character"));
609 
612  add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_CHAR], NULL);
613  gtk_text_buffer_get_end_iter(
614  login_pane[TEXTVIEW_RULES_CHAR].textbuffer, &end);
615  login_pane[TEXTVIEW_RULES_CHAR].textmark =
616  gtk_text_buffer_create_mark(
617  login_pane[TEXTVIEW_RULES_CHAR].textbuffer, NULL, &end, FALSE);
618 
619  g_signal_connect((gpointer) button_play_character, "clicked",
620  G_CALLBACK(on_button_play_character_clicked), NULL);
621  g_signal_connect((gpointer) button_create_character, "clicked",
622  G_CALLBACK(on_button_create_character_clicked), NULL);
623  g_signal_connect((gpointer) button_add_character, "clicked",
624  G_CALLBACK(on_button_add_character_clicked), NULL);
625  g_signal_connect((gpointer) button_return_login, "clicked",
626  G_CALLBACK(on_button_return_login_clicked), NULL);
627  g_signal_connect((gpointer) button_account_password, "clicked",
628  G_CALLBACK(on_button_account_password_clicked), NULL);
629  g_signal_connect((gpointer) treeview_choose_character, "row_activated",
630  G_CALLBACK(on_button_play_character_clicked), NULL);
631 
632  character_store = gtk_list_store_new(CHAR_NUM_COLUMNS,
633  G_TYPE_STRING, G_TYPE_STRING,
634  G_TYPE_STRING, G_TYPE_STRING,
635  G_TYPE_INT, G_TYPE_STRING,
636  G_TYPE_STRING, G_TYPE_OBJECT);
637  gtk_tree_view_set_model(GTK_TREE_VIEW(treeview_choose_character),
638  GTK_TREE_MODEL(character_store));
639 
640  renderer = gtk_cell_renderer_pixbuf_new();
641  column = gtk_tree_view_column_new_with_attributes("?", renderer,
642  "pixbuf", CHAR_ICON,
643  NULL);
644 
645  gtk_tree_view_column_set_min_width(column, image_size);
646  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
647 
648  renderer = gtk_cell_renderer_text_new();
649  column = gtk_tree_view_column_new_with_attributes("Character Name", renderer,
650  "text", CHAR_NAME, NULL);
651  gtk_tree_view_column_set_sort_column_id(column, CHAR_NAME);
652  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
653 
654  renderer = gtk_cell_renderer_text_new();
655  column = gtk_tree_view_column_new_with_attributes("Class", renderer,
656  "text", CHAR_CLASS, NULL);
657  gtk_tree_view_column_set_sort_column_id(column, CHAR_CLASS);
658  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
659 
660  renderer = gtk_cell_renderer_text_new();
661  column = gtk_tree_view_column_new_with_attributes("Race", renderer,
662  "text", CHAR_RACE, NULL);
663  gtk_tree_view_column_set_sort_column_id(column, CHAR_RACE);
664  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
665 
666  renderer = gtk_cell_renderer_text_new();
667  column = gtk_tree_view_column_new_with_attributes("Level", renderer,
668  "text", CHAR_LEVEL, NULL);
669  gtk_tree_view_column_set_sort_column_id(column, CHAR_LEVEL);
670  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
671 
672  renderer = gtk_cell_renderer_text_new();
673  column = gtk_tree_view_column_new_with_attributes("Party", renderer,
674  "text", CHAR_PARTY, NULL);
675  gtk_tree_view_column_set_sort_column_id(column, CHAR_PARTY);
676  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
677 
678  renderer = gtk_cell_renderer_text_new();
679  column = gtk_tree_view_column_new_with_attributes("Map", renderer,
680  "text", CHAR_MAP, NULL);
681  gtk_tree_view_column_set_sort_column_id(column, CHAR_MAP);
682  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview_choose_character), column);
683 }
684 
685 /******************************************************************************
686  * create_account_window
687  ******************************************************************************/
688 
694 void account_creation_failure(char *message) {
695  gtk_label_set_text(GTK_LABEL(label_create_account_status), message);
696 }
697 
710 static void do_account_create(const char *name, const char *p1,
711  const char *p2) {
712  SockList sl;
713  guint8 buf[MAX_BUF];
714 
715  if (strcmp(p1, p2)) {
716  gtk_label_set_text(GTK_LABEL(label_create_account_status),
717  "The passwords you entered do not match!");
718  return;
719  } else {
720  gtk_label_set_text(GTK_LABEL(label_create_account_status), "");
721  SockList_Init(&sl, buf);
722  SockList_AddString(&sl, "accountnew ");
723  SockList_AddChar(&sl, strlen(name));
724  SockList_AddString(&sl, name);
725  SockList_AddChar(&sl, strlen(p1));
726  SockList_AddString(&sl, p1);
727  SockList_Send(&sl, csocket.fd);
728  /* Store password away for new character creation */
729  snprintf(account_password, sizeof(account_password), "%s", p1);
730  }
731 }
732 
739 void
740 on_button_new_create_account_clicked(GtkButton *button, gpointer user_data) {
741  const char *password1, *password2, *name;
742 
743  password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
744  password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
745  name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
746 
747  if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
748  do_account_create(name, password1, password2);
749  } else {
750  gtk_label_set_text(GTK_LABEL(label_create_account_status),
751  "You must fill in all three entries!");
752  }
753 }
754 
760 void
761 on_button_new_cancel_clicked(GtkButton *button, gpointer user_data) {
762  gtk_notebook_set_current_page(main_notebook, 1);
763 }
764 
774 void
775 on_entry_new_account(GtkEntry *entry, gpointer user_data) {
776 
777  const char *password1, *password2, *name, *cp;
778 
779  password1 = gtk_entry_get_text(GTK_ENTRY(entry_new_account_password));
780  password2 = gtk_entry_get_text(GTK_ENTRY(entry_new_confirm_password));
781  name = gtk_entry_get_text(GTK_ENTRY(entry_new_account_name));
782  if (name && name[0] && password1 && password1[0] && password2 && password2[0]) {
783  do_account_create(name, password1, password2);
784  } else {
785  /* In this case, one, or more, of the fields is blank. If there were
786  * more than 3 widgets, I might but them into an array to make cycling
787  * easier
788  */
789 
790  /* First case - if the currently active one is blank, no reason to
791  * move onward.
792  */
793  cp = gtk_entry_get_text(entry);
794  if (!cp || !cp[0]) {
795  return;
796  }
797 
798  /* I'm not sure if it would make more sense to advance to the first
799  * NULL entry - but in that case, the pointer may hop in non intuitive
800  * ways - in this case, the user may just need to hit return a few
801  * times - MSW 2010/03/29
802  */
803  if (entry == GTK_ENTRY(entry_new_account_name)) {
804  gtk_widget_grab_focus(entry_new_account_password);
805  } else if (entry == GTK_ENTRY(entry_new_account_password)) {
806  gtk_widget_grab_focus(entry_new_confirm_password);
807  } else if (entry == GTK_ENTRY(entry_new_confirm_password)) {
808  gtk_widget_grab_focus(entry_new_account_name);
809  }
810  }
811 }
812 
818  GtkTextIter end;
819 
821  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_new_create_account"));
823  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_new_cancel"));
824  login_pane[TEXTVIEW_RULES_ACCOUNT].textview =
825  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "textview_rules_account"));
826 
828  gtk_text_view_get_buffer(
829  GTK_TEXT_VIEW(login_pane[TEXTVIEW_RULES_ACCOUNT].textview));
830 
832  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_new_account_name"));
834  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_new_account_password"));
836  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_new_confirm_password"));
838  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "label_create_account_status"));
839 
842  add_style_to_textbuffer(&login_pane[TEXTVIEW_RULES_ACCOUNT], NULL);
843  gtk_text_buffer_get_end_iter(
844  login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, &end);
845  login_pane[TEXTVIEW_RULES_ACCOUNT].textmark =
846  gtk_text_buffer_create_mark(
847  login_pane[TEXTVIEW_RULES_ACCOUNT].textbuffer, NULL, &end, FALSE);
848 
849  g_signal_connect((gpointer) button_new_create_account, "clicked",
850  G_CALLBACK(on_button_new_create_account_clicked), NULL);
851  g_signal_connect((gpointer) button_new_cancel, "clicked",
852  G_CALLBACK(on_button_new_cancel_clicked), NULL);
853  g_signal_connect((gpointer) entry_new_account_name, "activate",
854  G_CALLBACK(on_entry_new_account), NULL);
855  g_signal_connect((gpointer) entry_new_account_password, "activate",
856  G_CALLBACK(on_entry_new_account), NULL);
857  g_signal_connect((gpointer) entry_new_confirm_password, "activate",
858  G_CALLBACK(on_entry_new_account), NULL);
859 }
860 
861 /*****************************************************************************
862  * login_window
863  *****************************************************************************/
864 
870 void account_login_failure(char *message) {
871  gtk_label_set_text(GTK_LABEL(label_account_login_status), message);
872 }
873 
880 void
881 on_button_create_account_clicked(GtkButton *button, gpointer user_data) {
882  gtk_label_set_text(GTK_LABEL(label_create_account_status), "");
883  gtk_entry_set_text(GTK_ENTRY(entry_new_account_name), "");
884  gtk_entry_set_text(GTK_ENTRY(entry_new_account_password), "");
885  gtk_entry_set_text(GTK_ENTRY(entry_new_confirm_password), "");
886  gtk_notebook_set_current_page(main_notebook, 2);
887 }
888 
896 void
897 on_button_go_metaserver_clicked(GtkButton *button, gpointer user_data) {
899 }
900 
906 void on_button_exit_client_clicked(GtkButton *button, gpointer user_data) {
907 #ifdef WIN32
908  script_killall();
909 #endif
910  exit(0);
911 }
912 
920 static void do_account_login(const char *name, const char *password) {
921  SockList sl;
922  guint8 buf[MAX_BUF];
923 
924  if (!name || !password || *name == 0 || *password == 0) {
925  gtk_label_set_text(GTK_LABEL(label_account_login_status),
926  "You must enter both a name and password!");
927  } else {
928  gtk_label_set_text(GTK_LABEL(label_account_login_status), "");
929 
930  SockList_Init(&sl, buf);
931  SockList_AddString(&sl, "accountlogin ");
932  SockList_AddChar(&sl, strlen(name));
933  SockList_AddString(&sl, name);
934  SockList_AddChar(&sl, strlen(password));
935  SockList_AddString(&sl, password);
936  SockList_Send(&sl, csocket.fd);
937  /* Store password away for new character creation */
938  snprintf(account_password, sizeof(account_password), "%s", password);
939  }
940 }
941 
947 void
948 on_button_login_clicked(GtkButton *button, gpointer user_data) {
949  do_account_login(gtk_entry_get_text(GTK_ENTRY(entry_account_name)),
950  gtk_entry_get_text(GTK_ENTRY(entry_account_password)));
951 }
952 
958 void on_entry_account_name_activate(GtkEntry* entry, gpointer user_data) {
959  gtk_widget_grab_focus(entry_account_password);
960 }
961 
966 static void init_login_window() {
967  GtkTextIter end;
968 
969  button_login =
970  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_login"));
972  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_create_account"));
974  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "button_go_metaserver"));
976  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "label_account_login_status"));
977  login_pane[TEXTVIEW_MOTD].textview =
978  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "textview_motd"));
979 
980  textbuf_motd =
981  gtk_text_view_get_buffer(
982  GTK_TEXT_VIEW(login_pane[TEXTVIEW_MOTD].textview));
983 
985  add_style_to_textbuffer(&login_pane[TEXTVIEW_MOTD], NULL);
986  gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_MOTD].textbuffer, &end);
987  login_pane[TEXTVIEW_MOTD].textmark =
988  gtk_text_buffer_create_mark(
989  login_pane[TEXTVIEW_MOTD].textbuffer, NULL, &end, FALSE);
990 
991  login_pane[TEXTVIEW_NEWS].textview =
992  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "textview_news"));
993 
994  textbuf_news =
995  gtk_text_view_get_buffer(
996  GTK_TEXT_VIEW(login_pane[TEXTVIEW_NEWS].textview));
997 
999  add_style_to_textbuffer(&login_pane[TEXTVIEW_NEWS], NULL);
1000  gtk_text_buffer_get_end_iter(login_pane[TEXTVIEW_NEWS].textbuffer, &end);
1001  login_pane[TEXTVIEW_NEWS].textmark =
1002  gtk_text_buffer_create_mark(
1003  login_pane[TEXTVIEW_NEWS].textbuffer, NULL, &end, FALSE);
1004 
1006  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_account_name"));
1008  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_account_password"));
1009 
1010  g_signal_connect((gpointer) entry_account_name, "activate",
1011  G_CALLBACK(on_entry_account_name_activate), NULL);
1012  // entry_account_password is the default action in GtkBuilder
1013  g_signal_connect((gpointer) button_login, "clicked",
1014  G_CALLBACK(on_button_login_clicked), NULL);
1015  g_signal_connect((gpointer) button_create_account, "clicked",
1016  G_CALLBACK(on_button_create_account_clicked), NULL);
1017  g_signal_connect((gpointer) button_go_metaserver, "clicked",
1018  G_CALLBACK(on_button_go_metaserver_clicked), NULL);
1019 }
1020 
1021 /*****************************************************************************
1022  * Account password change
1023  ****************************************************************************/
1024 
1037 static void do_account_change(const char *old, const char *p1, const char *p2) {
1038  SockList sl;
1039  guint8 buf[MAX_BUF];
1040 
1041  if (strcmp(p1, p2)) {
1042  gtk_label_set_text(GTK_LABEL(label_account_password_status),
1043  "The passwords you entered do not match!");
1044  return;
1045  } else {
1046  gtk_label_set_text(GTK_LABEL(label_account_password_status), "");
1047  SockList_Init(&sl, buf);
1048  SockList_AddString(&sl, "accountpw ");
1049  SockList_AddChar(&sl, strlen(old));
1050  SockList_AddString(&sl, old);
1051  SockList_AddChar(&sl, strlen(p1));
1052  SockList_AddString(&sl, p1);
1053  SockList_Send(&sl, csocket.fd);
1054  /* Store password away for new character creation */
1055  snprintf(account_password, sizeof(account_password), "%s", p1);
1056  }
1057 }
1058 
1065 void
1067  gpointer user_data) {
1068  gtk_notebook_set_current_page(main_notebook, 3);
1069 }
1070 
1076 void
1078  gpointer user_data) {
1079  do_account_change(gtk_entry_get_text(GTK_ENTRY(entry_account_password_current)),
1080  gtk_entry_get_text(GTK_ENTRY(entry_account_password_new)),
1081  gtk_entry_get_text(GTK_ENTRY(entry_account_password_confirm)));
1082 }
1083 
1093 void
1094 on_entry_account_password(GtkEntry *entry, gpointer user_data) {
1095 
1096  const char *old, *password1, *password2, *cp;
1097 
1098  old = gtk_entry_get_text(GTK_ENTRY(entry_account_password_current));
1099  password1 = gtk_entry_get_text(GTK_ENTRY(entry_account_password_new));
1100  password2 = gtk_entry_get_text(GTK_ENTRY(entry_account_password_confirm));
1101  if (old && old[0] && password1 && password1[0] && password2 && password2[0]) {
1102  do_account_change(old, password1, password2);
1103  } else {
1104  /* In this case, one, or more, of the fields is blank. If there were
1105  * more than 3 widgets, I might but them into an array to make cycling
1106  * easier
1107  */
1108 
1109  /* First case - if the currently active one is blank, no reason to
1110  * move onward.
1111  */
1112  cp = gtk_entry_get_text(entry);
1113  if (!cp || !cp[0]) {
1114  return;
1115  }
1116 
1117  if (entry == GTK_ENTRY(entry_account_password_current)) {
1118  gtk_widget_grab_focus(entry_account_password_new);
1119  } else if (entry == GTK_ENTRY(entry_account_password_new)) {
1120  gtk_widget_grab_focus(entry_account_password_confirm);
1121  } else if (entry == GTK_ENTRY(entry_account_password_confirm)) {
1122  gtk_widget_grab_focus(entry_account_password_current);
1123  }
1124  }
1125 }
1126 
1127 void account_change_password_failure(char *message) {
1128  gtk_label_set_text(GTK_LABEL(label_account_password_status), message);
1129 }
1130 
1137  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
1138  "button_account_password_confirm"));
1140  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
1141  "button_account_password_cancel"));
1142 
1144  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
1145  "entry_account_password_current"));
1147  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "entry_account_password_new"));
1149  GTK_WIDGET(gtk_builder_get_object(dialog_xml,
1150  "entry_account_password_confirm"));
1152  GTK_WIDGET(gtk_builder_get_object(dialog_xml, "label_account_password_status"));
1153 
1154  g_signal_connect((gpointer) button_account_password_confirm, "clicked",
1155  G_CALLBACK(on_button_account_password_confirm_clicked), NULL);
1156  g_signal_connect((gpointer) button_account_password_cancel, "clicked",
1157  G_CALLBACK(on_button_account_password_cancel_clicked), NULL);
1158  g_signal_connect((gpointer) entry_account_password_current, "activate",
1159  G_CALLBACK(on_entry_account_password), NULL);
1160  g_signal_connect((gpointer) entry_account_password_new, "activate",
1161  G_CALLBACK(on_entry_account_password), NULL);
1162  g_signal_connect((gpointer) entry_account_password_confirm, "activate",
1163  G_CALLBACK(on_entry_account_password), NULL);
1164 }
1165 
1166 
1167 /*****************************************************************************
1168  * Common/generic functions
1169  ****************************************************************************/
1170 
1178 void update_login_info(int type) {
1179  if (!has_init) {
1180  return;
1181  }
1182 
1183  /* In all cases, we clear the buffer, and if we have data, then set it to
1184  * that data. This routine could be smarter an
1185  */
1186  if (type == INFO_NEWS) {
1187  gtk_text_buffer_set_text(textbuf_news, "", 0);
1188  if (news) {
1189  /* the format of the news entry is special - there are a series of
1190  * %entries, and they are in reverse older (newest last) we want
1191  * to get rid of the %, make them more visible (convert them to
1192  * bold) and reverse the order.
1193  */
1194  char *mynews, *cp, *el, big_buf[BIG_BUF], *cp1;
1195 
1196  mynews = g_strdup(news);
1197  /* We basically work from the end of the string going towards the
1198  * start looking for % characters. If we find one, we have to
1199  * make sure it is at the start of the line or start of the buffer
1200  */
1201  for (cp = mynews + strlen(mynews); cp > mynews; cp--) {
1202  if (*cp == '%' && (*(cp - 1) == '\n' || cp == mynews)) {
1203  /* Find the end of the line */
1204  el = strchr(cp, '\n');
1205  /* null out the newline, put el one char beyond it */
1206  if (el) {
1207  *el = 0;
1208  el++;
1209  }
1210  /* There isn't a clear standard - % news may be valid, as
1211  * might be %news. If % news is used, it looks better to
1212  * get rid of that leading space.
1213  */
1214  cp1 = cp + 1;
1215  while (isspace(*cp1)) {
1216  cp1++;
1217  }
1218 
1219  /* since we've null out the newline, this snprintf will
1220  * only get the % line and that is it. Mark it up
1221  */
1222  snprintf(big_buf, BIG_BUF, "[b]%s[/b]", cp1);
1223  add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], big_buf, 0, 0, 0);
1224  /* Now we draw the text that goes with it, if it exists */
1225  if (el) {
1226  add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], el, 0, 0, 0);
1227  }
1228 
1229  /* Now we wipe the % out. In this way, the news buffer is
1230  * shorter, so when it draws the ext, there will just be
1231  * that between the % and the one we just wiped out.
1232  */
1233  *cp = 0;
1234  }
1235  }
1236  /* If there are remnants left over, or perhaps the news file isn't
1237  * formatted with % headers, display what we have got.
1238  */
1239  if (*mynews != 0) {
1240  add_marked_text_to_pane(&login_pane[TEXTVIEW_NEWS], mynews, 0, 0, 0);
1241  }
1242  }
1243  } else if (type == INFO_MOTD) {
1244  gtk_text_buffer_set_text(textbuf_motd, "", 0);
1245  if (motd) {
1246  add_marked_text_to_pane(&login_pane[TEXTVIEW_MOTD], motd, 0, 0, 0);
1247  }
1248  } else if (type == INFO_RULES) {
1249  gtk_text_buffer_set_text(textbuf_rules_account, "", 0);
1250  gtk_text_buffer_set_text(textbuf_rules_char, "", 0);
1251 
1252  if (rules) {
1253  add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_ACCOUNT], rules, 0, 0, 0);
1254  add_marked_text_to_pane(&login_pane[TEXTVIEW_RULES_CHAR], rules, 0, 0, 0);
1255  }
1256  }
1257 }
1258 
1267 void start_login(int method) {
1268  /* Store this away - if method is only 1, we can not do smart character
1269  * creation.
1270  */
1271  serverloginmethod = method;
1272 
1273  if (!has_init) {
1274  /* Since there are 4 windows associated with account and character
1275  * login, to make life a little easier, each section here does all the
1276  * work for one window, so it is easier to see that everything for a
1277  * window is done - don't need to hunt through what would otherwise be
1278  * a long routine looking for entries.
1279  */
1281 
1283 
1285 
1287 
1289 
1291 
1292  has_init = 1;
1293 
1294  /* In case we have gotten news/motd/rules before getting here, update
1295  * it now.
1296  */
1300  }
1301 
1302  gtk_entry_set_text(GTK_ENTRY(entry_account_name), "");
1303  gtk_entry_set_text(GTK_ENTRY(entry_account_password), "");
1304 }
1305 
1307  gtk_notebook_set_current_page(main_notebook, 1);
1308  /* We set focus to account name - this makes the most sense if user is
1309  * logging in again - it is possible that the password is active, but both
1310  * fields are blank, which is not what is expected.
1311  */
1312  gtk_widget_grab_focus(entry_account_name);
1313  gtk_widget_grab_default(button_login);
1314 }
static void init_new_character_window()
Definition: account.c:215
static GtkWidget * entry_account_password_current
Definition: account.c:54
char * news
Definition: client.h:554
GtkWidget * textview
Definition: info.h:57
static GtkWidget * button_account_password
Definition: account.c:44
static GtkWidget * button_new_create_account
Definition: account.c:38
GtkTextBuffer * textbuf_rules_char
Definition: account.c:75
#define TEXTVIEW_NEWS
Definition: account.c:83
int image_size
Definition: image.c:35
GSocketConnection * fd
Definition: client.h:120
static GtkWidget * button_go_metaserver
Definition: account.c:34
void on_button_account_password_cancel_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:1066
void choose_char_window_show()
Definition: account.c:438
Info_Pane login_pane[4]
Definition: account.c:87
static GtkWidget * entry_new_account_password
Definition: account.c:38
void on_button_return_character_select_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:350
static GtkWidget * button_create_new_char
Definition: account.c:49
void on_button_new_char_cancel_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:207
void on_button_account_password_confirm_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:1077
void on_button_create_character_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:486
void add_marked_text_to_pane(Info_Pane *pane, const char *message, int type, int subtype, int orig_color)
Definition: info.c:819
char * rules
Definition: client.h:554
void on_button_add_character_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:502
static void init_login_window()
Definition: account.c:966
static GtkWidget * entry_new_character_name
Definition: account.c:49
static GtkWidget * button_create_character
Definition: account.c:44
int num_text_views
static void init_create_account_window()
Definition: account.c:817
void add_tags_to_textbuffer(Info_Pane *pane, GtkTextBuffer *textbuf)
Definition: info.c:372
static GtkWidget * label_account_login_status
Definition: account.c:34
ClientSocket csocket
Definition: client.c:67
void update_character_choose(const char *name, const char *class, const char *race, const char *face, const char *party, const char *map, int level, int faceno)
Definition: account.c:549
#define CHAR_NUM_COLUMNS
Definition: account.c:68
static GtkWidget * entry_character_name
Definition: account.c:71
void on_button_create_new_char_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:186
static GtkWidget * button_play_character
Definition: account.c:44
void on_button_new_create_account_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:740
#define TEXTVIEW_MOTD
Definition: account.c:82
static GtkWidget * label_create_account_status
Definition: account.c:38
GtkWidget * treeview_look
Definition: inventory.c:38
char account_password[256]
Definition: account.c:61
void on_entry_account_password(GtkEntry *entry, gpointer user_data)
Definition: account.c:1094
int serverloginmethod
Definition: client.c:59
static GtkWidget * treeview_choose_character
Definition: account.c:44
static void add_character_to_account(const char *name, const char *password, int force)
Definition: account.c:251
static void do_account_login(const char *name, const char *password)
Definition: account.c:920
void start_login(int method)
Definition: account.c:1267
void account_login_failure(char *message)
Definition: account.c:870
void account_change_password_failure(char *message)
Definition: account.c:1127
void client_disconnect()
Definition: client.c:178
void hide_main_client()
Definition: main.c:423
#define INFO_NEWS
Definition: client.h:632
GtkWidget * window_root
Definition: main.c:97
static void create_new_character()
Definition: account.c:155
static GtkWidget * button_new_cancel
Definition: account.c:38
static GtkWidget * label_add_status
Definition: account.c:71
GtkTextBuffer * textbuf_news
Definition: account.c:75
int SockList_Send(SockList *sl, GSocketConnection *c)
Definition: newsocket.c:112
static GtkWidget * label_account_password_status
Definition: account.c:54
void on_button_create_account_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:881
static void play_character(const char *name)
Definition: account.c:447
gboolean on_window_delete_event(GtkWidget *window, gpointer *user_data)
Definition: account.c:126
#define TEXTVIEW_RULES_ACCOUNT
Definition: account.c:84
GtkTextBuffer * textbuf_rules_account
Definition: account.c:75
void on_entry_new_character_name(GtkEntry *entry, gpointer user_data)
Definition: account.c:196
static GtkWidget * new_character_window
Definition: account.c:49
void on_button_do_add_character_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:336
void on_button_play_character_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:464
void on_button_login_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:948
static GtkWidget * button_create_account
Definition: account.c:34
void add_style_to_textbuffer(Info_Pane *pane, GtkStyle *base_style)
Definition: info.c:426
void on_button_go_metaserver_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:897
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:98
#define MAX_BUF
Definition: client.h:40
GtkTextMark * textmark
Definition: info.h:60
#define INFO_MOTD
Definition: client.h:633
static GtkWidget * button_login
Definition: account.c:34
static GtkWidget * entry_account_password_confirm
Definition: account.c:54
static GtkWidget * button_return_login
Definition: account.c:44
void account_add_character_failure(char *message)
Definition: account.c:284
static void init_account_password_window()
Definition: account.c:1135
static GtkWidget * button_new_char_cancel
Definition: account.c:49
void create_new_character_failure(char *message)
Definition: account.c:145
static void do_account_create(const char *name, const char *p1, const char *p2)
Definition: account.c:710
void hide_all_login_windows()
Definition: account.c:99
void create_character_window_show()
Definition: create_char.c:152
static void do_account_change(const char *old, const char *p1, const char *p2)
Definition: account.c:1037
static GtkWidget * button_account_password_confirm
Definition: account.c:54
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:43
static GtkWidget * entry_account_password_new
Definition: account.c:54
Definition: info.h:55
#define INFO_RULES
Definition: client.h:634
static int has_init
Definition: account.c:91
GtkListStore * character_store
Definition: account.c:58
void on_button_exit_client_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:906
void choose_character_init()
Definition: account.c:423
#define BIG_BUF
Definition: client.h:41
void create_character_window_hide()
Definition: create_char.c:195
static GtkWidget * button_return_character_select
Definition: account.c:71
GtkTextBuffer * textbuf_motd
Definition: account.c:75
static GtkWidget * entry_new_confirm_password
Definition: account.c:38
static GtkWidget * button_add_character
Definition: account.c:44
void on_entry_character(GtkEntry *entry, gpointer user_data)
Definition: account.c:363
void on_entry_new_account(GtkEntry *entry, gpointer user_data)
Definition: account.c:775
static void init_add_character_window()
Definition: account.c:390
void account_creation_failure(char *message)
Definition: account.c:694
void account_show_login()
Definition: account.c:1306
static GtkWidget * entry_new_account_name
Definition: account.c:38
static GtkWidget * entry_account_password
Definition: account.c:34
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:32
static GtkWidget * button_account_password_cancel
Definition: account.c:54
PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: image.c:39
static void init_choose_char_window()
Definition: account.c:585
void on_button_return_login_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:516
#define TEXTVIEW_RULES_CHAR
Definition: account.c:85
void on_button_new_cancel_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:761
void on_button_account_password_clicked(GtkButton *button, gpointer user_data)
Definition: account.c:527
static GtkWidget * button_do_add_character
Definition: account.c:71
GtkWidget * connect_window
Definition: main.c:97
GtkNotebook * main_notebook
Definition: main.c:98
static GtkWidget * entry_account_name
Definition: account.c:34
GtkBuilder * dialog_xml
Definition: main.c:96
static GtkWidget * entry_character_password
Definition: account.c:71
void on_entry_account_name_activate(GtkEntry *entry, gpointer user_data)
Definition: account.c:958
char * motd
Definition: client.h:554
void show_main_client(void)
Definition: main.c:412
void update_login_info(int type)
Definition: account.c:1178
static GtkWidget * label_new_char_status
Definition: account.c:49
static item * map
Definition: item.c:28