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