2009-02-24 Alejandro G. Castro <alex@igalia.com>
[hildon] / src / hildon-get-password-dialog.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-get-password-dialog
27  * @short_description: A widget used to get a password.
28  * @see_also: #HildonSetPasswordDialog
29  * 
30  * HildonGetPasswordDialog prompts the user for a password.  It allows
31  * inputting password, with an optional configurable label eg. for
32  * showing a custom message. The maximum length of the password can be set.
33  *
34  * <example>
35  * <title>HildonGetPassword example</title>
36  * <programlisting>
37  * get_dialog =  HILDON_GET_PASSWORD_DIALOG (hildon_get_password_dialog_new (parent, FALSE));
38  * <!-- -->
39  * gtk_widget_show (GTK_WIDGET (get_dialog));
40  * <!-- -->
41  * i = gtk_dialog_run (GTK_DIALOG (get_dialog));
42  * <!-- -->
43  * pass = hildon_get_password_dialog_get_password (get_dialog);
44  * <!-- -->
45  * if (i == GTK_RESPONSE_OK &amp;&amp; (strcmp (pass, dialog.current_password) != 0))
46  * {
47  *      gtk_infoprint (GTK_WINDOW (parent), STR_PASSWORD_INCORRECT);
48  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button2), FALSE);
49  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button3), FALSE);
50  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button4), FALSE);
51  * }
52  * <!-- -->
53  * else if (i == GTK_RESPONSE_OK)
54  * {   
55  *      gtk_widget_set_sensitive( GTK_WIDGET( dialog.button2 ), TRUE);
56  * }
57  * <!-- -->
58  * else
59  * {
60  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button2), FALSE);
61  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button3), FALSE);
62  *      gtk_widget_set_sensitive (GTK_WIDGET (dialog.button4), FALSE);
63  * }
64  * gtk_widget_destroy (GTK_WIDGET (get_dialog));
65  * }
66  * </programlisting>
67  * </example>
68  */
69
70 #undef                                          HILDON_DISABLE_DEPRECATED
71
72 #ifdef                                          HAVE_CONFIG_H
73 #include                                        <config.h>
74 #endif
75
76 #include                                        <errno.h>
77 #include                                        <string.h>
78 #include                                        <strings.h>
79 #include                                        <unistd.h>
80 #include                                        <stdio.h>
81 #include                                        <libintl.h>
82
83 #include                                        "hildon-get-password-dialog.h"
84 #include                                        "hildon-caption.h"
85 #include                                        "hildon-banner.h"
86 #include                                        "hildon-get-password-dialog-private.h"
87
88 #define                                         _(String) dgettext("hildon-libs", String)
89
90 #define                                         HILDON_GET_PASSWORD_DIALOG_TITLE "ecdg_ti_get_old_password"
91
92 #define                                         HILDON_GET_PASSWORD_DIALOG_PASSWORD "ecdg_fi_get_old_pwd_enter_pwd"
93
94 #define                                         HILDON_GET_PASSWORD_DIALOG_OK "wdgt_bd_done"
95
96 #define                                         HILDON_GET_PASSWORD_DIALOG_CANCEL "ecdg_bd_get_old_password_dialog_cancel"
97
98 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_TITLE "ecdg_ti_verify_password"
99
100 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_PASSWORD "ecdg_fi_verify_pwd_enter_pwd"
101
102 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_OK "wdgt_bd_done"
103
104 #define                                         HILDON_GET_PASSWORD_VERIFY_DIALOG_CANCEL "ecdg_bd_verify_password_dialog_cancel"
105
106 #define                                         HILDON_GET_PASSWORD_DIALOG_MAX_CHARS "ckdg_ib_maximum_characters_reached"
107
108 static GtkDialogClass*                          parent_class;
109
110 static void
111 hildon_get_password_dialog_class_init           (HildonGetPasswordDialogClass *class);
112
113 static void
114 hildon_get_password_dialog_init                 (HildonGetPasswordDialog *widget);
115
116 static void
117 hildon_get_password_set_property                (GObject *object,
118                                                  guint prop_id,
119                                                  const GValue *value,
120                                                  GParamSpec *pspec);
121
122 static void
123 hildon_get_password_get_property                (GObject *object,
124                                                  guint prop_id, 
125                                                  GValue *value,
126                                                  GParamSpec *pspec);
127
128 static void 
129 create_contents                                 (HildonGetPasswordDialog *dialog);
130
131 #ifdef MAEMO_GTK 
132 static void 
133 invalid_input                                   (GtkWidget *widget, 
134                                                  GtkInvalidInputType reason, 
135                                                  gpointer unused);
136 #endif
137
138 enum
139 {
140     PROP_0,
141     PROP_MESSAGE,
142     PROP_PASSWORD,
143     PROP_NUMBERS_ONLY,
144     PROP_CAPTION_LABEL,
145     PROP_MAX_CHARS,
146     PROP_GET_OLD
147 };
148
149 /* Private functions */
150 static void
151 hildon_get_password_set_property                (GObject *object,
152                                                  guint prop_id,
153                                                  const GValue *value, 
154                                                  GParamSpec *pspec)
155 {
156     HildonGetPasswordDialog *dialog = HILDON_GET_PASSWORD_DIALOG (object);
157     HildonGetPasswordDialogPrivate *priv;
158
159     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (object);
160     g_assert (priv);
161
162     switch (prop_id) {
163
164         case PROP_MESSAGE:
165             /* Set label text representing password domain */
166             gtk_label_set_text (priv->message_label, g_value_get_string (value));
167             break;
168
169         case PROP_PASSWORD:
170             gtk_entry_set_text(GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))), 
171                     g_value_get_string(value));
172             break;
173
174         case PROP_NUMBERS_ONLY:
175 #ifdef MAEMO_GTK 
176             /* Set input mode for the password entry */
177             g_object_set(G_OBJECT (gtk_bin_get_child GTK_BIN ((priv->password_entry))),
178                     "hildon-input-mode",
179                     (g_value_get_boolean (value)
180                      ? HILDON_GTK_INPUT_MODE_NUMERIC
181                      : HILDON_GTK_INPUT_MODE_FULL),
182                     NULL);
183 #endif
184             break;
185
186         case PROP_CAPTION_LABEL:
187             hildon_get_password_dialog_set_caption (dialog, g_value_get_string (value));
188             break;
189
190         case PROP_MAX_CHARS:
191             hildon_get_password_dialog_set_max_characters (dialog, g_value_get_int (value));
192             break;
193
194         case PROP_GET_OLD:
195             priv->get_old = g_value_get_boolean (value);
196             create_contents (dialog);
197             break;
198
199         default:
200             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201             break;
202     }
203 }
204
205 static void
206 hildon_get_password_get_property                (GObject *object,
207                                                  guint prop_id,
208                                                  GValue *value, 
209                                                  GParamSpec *pspec)
210 {
211     HildonGetPasswordDialog *dialog = HILDON_GET_PASSWORD_DIALOG (object);
212     HildonGetPasswordDialogPrivate *priv;
213     const gchar *string;
214     gint max_length;
215 #ifdef MAEMO_GTK 
216     gint input_mode;
217 #endif
218
219     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
220     g_assert (priv);
221
222     switch (prop_id) {
223
224         case PROP_MESSAGE:
225             string = gtk_label_get_text (priv->message_label);
226             g_value_set_string (value, string);
227             break;
228
229         case PROP_PASSWORD:
230             string = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))));
231             g_value_set_string (value, string);
232             break;
233
234         case PROP_NUMBERS_ONLY:
235 #ifdef MAEMO_GTK 
236             /* This property is set if and only if the input mode
237                of the password entry has been set to numeric only */
238             g_object_get (G_OBJECT (gtk_bin_get_child (GTK_BIN (priv->password_entry))),
239                     "hildon-input-mode", &input_mode, NULL);
240             g_value_set_boolean (value,
241                     (input_mode == HILDON_GTK_INPUT_MODE_NUMERIC));
242 #else
243             g_value_set_boolean (value, FALSE);
244 #endif
245             break;
246
247         case PROP_CAPTION_LABEL:
248             string = hildon_caption_get_label (priv->password_entry);
249             g_value_set_string (value, string);
250             break;
251
252         case PROP_MAX_CHARS:
253             max_length = gtk_entry_get_max_length 
254                     (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry))));
255             g_value_set_int (value, max_length);
256             break;
257
258         case PROP_GET_OLD:
259             g_value_set_boolean (value, priv->get_old);
260             break;
261
262         default:
263             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
264             break;
265     }
266 }
267
268 static void
269 hildon_get_password_dialog_class_init           (HildonGetPasswordDialogClass *class)
270 {
271     GObjectClass *object_class = G_OBJECT_CLASS (class);
272
273     parent_class = g_type_class_peek_parent (class);
274
275     /* Override virtual functions */
276     object_class->set_property = hildon_get_password_set_property;
277     object_class->get_property = hildon_get_password_get_property;
278
279     /* Install new properties */
280     
281     /**
282      * HildonGetPasswordDialog:message:
283      *
284      * Optional message displayed to the user.
285      */
286     g_object_class_install_property 
287         (object_class, 
288          PROP_MESSAGE, 
289          g_param_spec_string ("message",
290              "Message",
291              "Set optional message",
292              NULL,
293              G_PARAM_READWRITE));
294
295     /**
296      * HildonGetPasswordDialog:password:
297      *
298      * Password field contents.
299      */
300     g_object_class_install_property
301         (object_class, 
302          PROP_PASSWORD,
303          g_param_spec_string ("password",
304              "Password",
305              "Password field",
306              "DEFAULT",
307              G_PARAM_READWRITE));
308
309     /**
310      * HildonGetPasswordDialog:numbers-only:
311      *
312      * If the password entry field is operating in numbers-only mode.
313      */
314     g_object_class_install_property
315         (object_class, 
316          PROP_NUMBERS_ONLY,
317          g_param_spec_boolean ("numbers-only",
318              "NumbersOnly",
319              "Set entry to accept only numeric values",
320              FALSE,
321              G_PARAM_READWRITE));
322
323     /**
324      * HildonGetPasswordDialog:caption-label:
325      *
326      * Caption label.
327      */
328     g_object_class_install_property
329         (object_class, 
330          PROP_CAPTION_LABEL,
331          g_param_spec_string ("caption-label",
332              "Caption Label",
333              "The text to be set as the caption label",
334              NULL,
335              G_PARAM_READWRITE));
336     
337     /**
338      * HildonGetPasswordDialog:max-characters:
339      *
340      * Maximum characters than can be entered.
341      */
342     g_object_class_install_property
343         (object_class, 
344          PROP_MAX_CHARS,
345          g_param_spec_int ("max-characters",
346              "Maximum Characters",
347              "The maximum number of characters the password"
348              " dialog accepts",
349              G_MININT,
350              G_MAXINT,
351              0,
352              G_PARAM_READWRITE));
353
354     /**
355      * HildonGetPasswordDialog:get-old:
356      *
357      * If the dialog is used to retrieve an old password or set a new one.
358      */
359     g_object_class_install_property
360         (object_class,
361          PROP_GET_OLD,
362          g_param_spec_boolean ("get-old",
363              "Get Old Password",
364              "TRUE if dialog is a get old password dialog, "
365              "FALSE if dialog is a get password dialog",
366              FALSE,
367              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
368
369     /* Install private structure */
370     g_type_class_add_private (class, sizeof (HildonGetPasswordDialogPrivate));
371 }
372
373 static void
374 hildon_get_password_dialog_init                 (HildonGetPasswordDialog *dialog)
375 {
376     /* Set initial properties for the dialog; the actual contents are
377        created once the 'get-old' property is set with g_object_new */
378
379     gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
380     gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
381     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
382 }
383
384 static void
385 create_contents                                 (HildonGetPasswordDialog *dialog)
386 {
387     HildonGetPasswordDialogPrivate *priv;
388     GtkSizeGroup * group;
389     GtkWidget *control;
390     AtkObject *atk_aux = NULL;
391
392     /* Cache private pointer for faster member access */
393     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
394     g_assert (priv);
395
396     /* Sizegroup for captions */
397     group = GTK_SIZE_GROUP (gtk_size_group_new
398             (GTK_SIZE_GROUP_HORIZONTAL));
399
400     /* Dialog title */
401     gtk_window_set_title (GTK_WINDOW (dialog),
402             priv->get_old
403             ? _(HILDON_GET_PASSWORD_DIALOG_TITLE)
404             : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_TITLE));
405
406     /* Optional password domain label */
407     priv->message_label = GTK_LABEL (gtk_label_new (NULL));
408
409     /* Create buttons */
410     gtk_dialog_add_button (GTK_DIALOG (dialog),
411                     (priv->get_old
412                      ? _(HILDON_GET_PASSWORD_DIALOG_OK)
413                      : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_OK)),
414                     GTK_RESPONSE_OK);
415
416     gtk_dialog_add_button (GTK_DIALOG (dialog),
417                     (priv->get_old
418                      ? _(HILDON_GET_PASSWORD_DIALOG_CANCEL)
419                      : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_CANCEL)),
420                     GTK_RESPONSE_CANCEL);
421
422     /* Create password text entry */
423     control = gtk_entry_new ();
424     if ((atk_aux = gtk_widget_get_accessible(control)))
425       {
426         atk_object_set_name(atk_aux, _("Passwd"));
427       }
428
429     gtk_entry_set_width_chars (GTK_ENTRY (control), 20);
430
431 #ifdef MAEMO_GTK 
432     g_object_set (control, "hildon-input-mode", HILDON_GTK_INPUT_MODE_FULL, NULL);
433 #endif
434
435     gtk_entry_set_visibility (GTK_ENTRY(control), FALSE);
436     priv->password_entry = HILDON_CAPTION
437         (hildon_caption_new(group,
438                             (priv->get_old
439                              ? _(HILDON_GET_PASSWORD_DIALOG_PASSWORD)
440                              : _(HILDON_GET_PASSWORD_VERIFY_DIALOG_PASSWORD)),
441                             control, NULL,
442                             HILDON_CAPTION_OPTIONAL));
443     hildon_caption_set_separator (HILDON_CAPTION (priv->password_entry), "");
444
445     /* Do the basic layout */
446     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
447             GTK_WIDGET (priv->message_label), FALSE, FALSE, 0);
448     gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
449             GTK_WIDGET (priv->password_entry), FALSE, FALSE, 0);
450     gtk_widget_show_all (GTK_DIALOG (dialog)->vbox);
451
452     /* Ensure group is freed when all its contents have been removed */
453     g_object_unref (group);
454 }
455
456 /**
457  * hildon_get_password_dialog_get_type:
458  *
459  * Returns GType for HildonGetPasswordDialog as produced by
460  * g_type_register_static().
461  *
462  * Returns: HildonGetPasswordDialog type
463  */
464 GType G_GNUC_CONST
465 hildon_get_password_dialog_get_type             (void)
466 {
467     static GType dialog_type = 0;
468
469     if (! dialog_type) {
470         static const GTypeInfo dialog_info = {
471             sizeof (HildonGetPasswordDialogClass),
472             NULL,       /* base_init */
473             NULL,       /* base_finalize */
474             (GClassInitFunc) hildon_get_password_dialog_class_init,
475             NULL,       /* class_finalize */
476             NULL,       /* class_data */
477             sizeof (HildonGetPasswordDialog),
478             0,  /* n_preallocs */
479             (GInstanceInitFunc) hildon_get_password_dialog_init
480         };
481
482         dialog_type = g_type_register_static (GTK_TYPE_DIALOG,
483                 "HildonGetPasswordDialog",
484                 &dialog_info, 0);
485     }
486     return dialog_type;
487 }
488
489 /**
490  * hildon_get_password_dialog_new:
491  * @parent: parent window; can be NULL
492  * @get_old: FALSE creates a new get password dialog and
493  *           TRUE creates a new get old password dialog. That is,
494  *           if the password to be obtained is the old password, 
495  *           this parameter is specified TRUE.  
496  * 
497  * Construct a new HildonGetPasswordDialog.
498  *
499  * Returns: a new #GtkWidget of type HildonGetPasswordDialog
500  */
501 GtkWidget*
502 hildon_get_password_dialog_new                  (GtkWindow *parent,
503                                                  gboolean get_old)
504 {
505     HildonGetPasswordDialog *dialog = g_object_new
506         (HILDON_TYPE_GET_PASSWORD_DIALOG,
507          "get-old", get_old, NULL);
508
509     if (parent != NULL) {
510         gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
511     }
512
513     return (GtkWidget *) dialog;
514 }
515
516 /**
517  * hildon_get_password_dialog_new_with_default:
518  * @parent: parent window; can be NULL
519  * @password: a default password to be shown in password field
520  * @get_old: FALSE creates a new get password dialog and
521  *           TRUE creates a new get old password dialog. That is,
522  *           if the password to be obtained is the old password,
523  *           this parameter is specified TRUE.
524  *                        
525  * 
526  * Same as #hildon_get_password_dialog_new but with a default password
527  * in password field.
528  *
529  * Returns: a new #GtkWidget of type HildonGetPasswordDialog
530  */
531 GtkWidget*
532 hildon_get_password_dialog_new_with_default     (GtkWindow *parent,
533                                                  const gchar *password,
534                                                  gboolean get_old)
535 {
536     GtkWidget *dialog;
537
538     dialog = hildon_get_password_dialog_new (parent, get_old);
539
540     if (password != NULL)
541         g_object_set (G_OBJECT (dialog), "password", password, NULL);
542
543     return GTK_WIDGET (dialog);
544 }
545
546 /**
547  * hildon_get_password_dialog_get_password:
548  * @dialog: pointer to HildonSetPasswordDialog
549  * 
550  * Gets the currently entered password. The string should not be freed.
551  *
552  * Returns: current password entered by the user.
553  */
554 const gchar*
555 hildon_get_password_dialog_get_password         (HildonGetPasswordDialog *dialog)
556 {
557     GtkEntry *entry1;
558     gchar *text1;
559
560     HildonGetPasswordDialogPrivate *priv;
561
562     g_return_val_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog), NULL);
563     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
564     g_assert (priv);
565
566     /* Retrieve the password entry widget */
567     entry1 = GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->password_entry)));
568     text1 = GTK_ENTRY (entry1)->text;
569
570     return text1;
571 }
572
573 /**
574  * hildon_get_password_dialog_set_message
575  * @dialog: the dialog
576  * @message: a custom message or some other descriptive text to be set
577  * 
578  * Sets the optional descriptive text displayed at the top of the dialog.
579  */
580 void 
581 hildon_get_password_dialog_set_message          (HildonGetPasswordDialog *dialog, 
582                                                  const gchar *message)
583 {
584     HildonGetPasswordDialogPrivate *priv;
585
586     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
587
588     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
589     g_assert (priv);
590
591     gtk_label_set_text (priv->message_label, message);
592
593 }
594
595 /**
596  * hildon_get_password_dialog_set_caption:
597  * @dialog: the dialog
598  * @new_caption: the text to be set as the caption label
599  * 
600  * Sets the password entry field's neigbouring label.
601  */
602 void 
603 hildon_get_password_dialog_set_caption          (HildonGetPasswordDialog *dialog,
604                                                  const gchar *new_caption)
605 {
606     HildonGetPasswordDialogPrivate *priv;
607
608     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
609     g_return_if_fail (new_caption != NULL);
610
611     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
612     g_assert (priv);
613
614     hildon_caption_set_label (priv->password_entry, new_caption);
615 }
616
617 /**
618  * hildon_get_password_dialog_set_max_characters:
619  * @dialog: the dialog
620  * @max_characters: the maximum number of characters the password dialog
621  * accepts
622  * 
623  * sets the maximum number of characters allowed as the password
624  */
625 void 
626 hildon_get_password_dialog_set_max_characters   (HildonGetPasswordDialog *dialog, 
627                                                  gint max_characters)
628 {
629     HildonGetPasswordDialogPrivate *priv;
630
631     g_return_if_fail (max_characters > 0);
632     g_return_if_fail (HILDON_IS_GET_PASSWORD_DIALOG (dialog));
633
634     priv = HILDON_GET_PASSWORD_DIALOG_GET_PRIVATE (dialog);
635     g_assert (priv);
636
637     /* Apply the given length to password entry */
638     gtk_entry_set_max_length (GTK_ENTRY
639             (gtk_bin_get_child
640              GTK_BIN ((priv->password_entry))),
641              max_characters);
642
643     /* FIXME There is a bug here -- the prev. signal needs to be
644      * disconnected before connecting the new signal. Besides, this 
645      * should go into the constructor */
646
647 #ifdef MAEMO_GTK 
648     /* Connect callback to show error banner if the limit is exceeded */
649     g_signal_connect (GTK_ENTRY
650             (gtk_bin_get_child
651              GTK_BIN ((priv->password_entry))),
652             "invalid_input",
653             G_CALLBACK (invalid_input),
654             NULL
655             );
656 #endif
657 }
658
659 #ifdef MAEMO_GTK 
660 /* Callback that gets called when maximum chars is reached in the entry */
661 static void 
662 invalid_input                                   (GtkWidget *widget, 
663                                                  GtkInvalidInputType reason, 
664                                                  gpointer unused) 
665 {
666     if (reason == GTK_INVALID_INPUT_MAX_CHARS_REACHED) 
667     {
668         hildon_banner_show_information (widget, NULL, _(HILDON_GET_PASSWORD_DIALOG_MAX_CHARS));
669     }
670 }
671 #endif