Daniel Brötzmann pushed to branch newcontrol at gajim / gajim

Commits:

7 changed files:

Changes:

  • gajim/common/helpers.py
    ... ... @@ -68,6 +68,7 @@
    68 68
     from nbxmpp.const import ConnectionType
    
    69 69
     from nbxmpp.const import Affiliation
    
    70 70
     from nbxmpp.errors import StanzaError
    
    71
    +from nbxmpp.structs import CommonError
    
    71 72
     from nbxmpp.structs import ProxyData
    
    72 73
     from nbxmpp.protocol import JID
    
    73 74
     from nbxmpp.protocol import InvalidJid
    
    ... ... @@ -1145,7 +1146,7 @@ def validate_jid(jid: Union[str, JID], type_: Optional[str] = None) -> JID:
    1145 1146
         raise ValueError(f'Not a {type_} JID')
    
    1146 1147
     
    
    1147 1148
     
    
    1148
    -def to_user_string(error: StanzaError) -> str:
    
    1149
    +def to_user_string(error: Union[CommonError, StanzaError]) -> str:
    
    1149 1150
         text = error.get_text(get_rfc5646_lang())
    
    1150 1151
         if text:
    
    1151 1152
             return text
    

  • gajim/common/modules/muc.py
    ... ... @@ -34,6 +34,7 @@
    34 34
     from nbxmpp.protocol import JID
    
    35 35
     from nbxmpp.protocol import Message
    
    36 36
     from nbxmpp.protocol import Presence
    
    37
    +from nbxmpp.structs import CommonError
    
    37 38
     from nbxmpp.structs import DiscoInfo
    
    38 39
     from nbxmpp.structs import MessageProperties
    
    39 40
     from nbxmpp.structs import PresenceProperties
    
    ... ... @@ -511,6 +512,9 @@ def _on_error_presence(self,
    511 512
             elif muc_data.state == MUCJoinedState.CAPTCHA_REQUEST:
    
    512 513
                 self._set_muc_state(room_jid, MUCJoinedState.CAPTCHA_FAILED)
    
    513 514
                 self._set_muc_state(room_jid, MUCJoinedState.NOT_JOINED)
    
    515
    +            muc_data.error = 'captcha-failed'
    
    516
    +            assert isinstance(properties.error, CommonError)
    
    517
    +            muc_data.error_text = helpers.to_user_string(properties.error)
    
    514 518
                 room.notify('room-captcha-error', properties.error)
    
    515 519
     
    
    516 520
             elif muc_data.state == MUCJoinedState.CAPTCHA_FAILED:
    

  • gajim/common/structs.py
    ... ... @@ -70,6 +70,8 @@ def __init__(self,
    70 70
             # Message id of the captcha challenge
    
    71 71
             self.captcha_id: Optional[str] = None
    
    72 72
             self.captcha_form: Optional[SimpleDataForm] = None
    
    73
    +        self.error: Optional[str] = None
    
    74
    +        self.error_text: Optional[str] = None
    
    73 75
             self.subject: Optional[MucSubject] = None
    
    74 76
     
    
    75 77
         @property
    

  • gajim/data/gui/groupchat_control.ui
    ... ... @@ -221,96 +221,7 @@
    221 221
                   </packing>
    
    222 222
                 </child>
    
    223 223
                 <child>
    
    224
    -              <object class="GtkBox">
    
    225
    -                <property name="visible">True</property>
    
    226
    -                <property name="can-focus">False</property>
    
    227
    -                <property name="orientation">vertical</property>
    
    228
    -                <child>
    
    229
    -                  <!-- n-columns=1 n-rows=2 -->
    
    230
    -                  <object class="GtkGrid">
    
    231
    -                    <property name="visible">True</property>
    
    232
    -                    <property name="can-focus">False</property>
    
    233
    -                    <property name="halign">center</property>
    
    234
    -                    <property name="valign">center</property>
    
    235
    -                    <property name="hexpand">True</property>
    
    236
    -                    <property name="vexpand">True</property>
    
    237
    -                    <property name="row-spacing">12</property>
    
    238
    -                    <child>
    
    239
    -                      <object class="GtkBox">
    
    240
    -                        <property name="visible">True</property>
    
    241
    -                        <property name="can-focus">False</property>
    
    242
    -                        <property name="homogeneous">True</property>
    
    243
    -                        <child>
    
    244
    -                          <object class="GtkButton">
    
    245
    -                            <property name="label" translatable="yes">_Cancel</property>
    
    246
    -                            <property name="visible">True</property>
    
    247
    -                            <property name="can-focus">True</property>
    
    248
    -                            <property name="receives-default">True</property>
    
    249
    -                            <property name="halign">start</property>
    
    250
    -                            <property name="valign">start</property>
    
    251
    -                            <property name="use-underline">True</property>
    
    252
    -                            <signal name="clicked" handler="_on_captcha_cancel_clicked" swapped="no"/>
    
    253
    -                          </object>
    
    254
    -                          <packing>
    
    255
    -                            <property name="expand">False</property>
    
    256
    -                            <property name="fill">True</property>
    
    257
    -                            <property name="position">0</property>
    
    258
    -                          </packing>
    
    259
    -                        </child>
    
    260
    -                        <child>
    
    261
    -                          <object class="GtkButton" id="captcha_set_button">
    
    262
    -                            <property name="label" translatable="yes">_Join</property>
    
    263
    -                            <property name="visible">True</property>
    
    264
    -                            <property name="sensitive">False</property>
    
    265
    -                            <property name="can-focus">True</property>
    
    266
    -                            <property name="can-default">True</property>
    
    267
    -                            <property name="receives-default">True</property>
    
    268
    -                            <property name="halign">end</property>
    
    269
    -                            <property name="valign">start</property>
    
    270
    -                            <property name="use-underline">True</property>
    
    271
    -                            <signal name="clicked" handler="_on_captcha_set_clicked" swapped="no"/>
    
    272
    -                            <style>
    
    273
    -                              <class name="suggested-action"/>
    
    274
    -                            </style>
    
    275
    -                          </object>
    
    276
    -                          <packing>
    
    277
    -                            <property name="expand">False</property>
    
    278
    -                            <property name="fill">True</property>
    
    279
    -                            <property name="position">1</property>
    
    280
    -                          </packing>
    
    281
    -                        </child>
    
    282
    -                      </object>
    
    283
    -                      <packing>
    
    284
    -                        <property name="left-attach">0</property>
    
    285
    -                        <property name="top-attach">1</property>
    
    286
    -                      </packing>
    
    287
    -                    </child>
    
    288
    -                    <child>
    
    289
    -                      <object class="GtkBox" id="captcha_box">
    
    290
    -                        <property name="visible">True</property>
    
    291
    -                        <property name="can-focus">False</property>
    
    292
    -                        <property name="orientation">vertical</property>
    
    293
    -                        <child>
    
    294
    -                          <placeholder/>
    
    295
    -                        </child>
    
    296
    -                      </object>
    
    297
    -                      <packing>
    
    298
    -                        <property name="left-attach">0</property>
    
    299
    -                        <property name="top-attach">0</property>
    
    300
    -                      </packing>
    
    301
    -                    </child>
    
    302
    -                  </object>
    
    303
    -                  <packing>
    
    304
    -                    <property name="expand">False</property>
    
    305
    -                    <property name="fill">True</property>
    
    306
    -                    <property name="position">0</property>
    
    307
    -                  </packing>
    
    308
    -                </child>
    
    309
    -              </object>
    
    310
    -              <packing>
    
    311
    -                <property name="name">captcha</property>
    
    312
    -                <property name="position">2</property>
    
    313
    -              </packing>
    
    224
    +              <placeholder/>
    
    314 225
                 </child>
    
    315 226
                 <child>
    
    316 227
                   <object class="GtkBox">
    
    ... ... @@ -451,116 +362,6 @@
    451 362
                     <property name="position">3</property>
    
    452 363
                   </packing>
    
    453 364
                 </child>
    
    454
    -            <child>
    
    455
    -              <object class="GtkBox">
    
    456
    -                <property name="visible">True</property>
    
    457
    -                <property name="can-focus">False</property>
    
    458
    -                <property name="orientation">vertical</property>
    
    459
    -                <child>
    
    460
    -                  <!-- n-columns=1 n-rows=3 -->
    
    461
    -                  <object class="GtkGrid">
    
    462
    -                    <property name="visible">True</property>
    
    463
    -                    <property name="can-focus">False</property>
    
    464
    -                    <property name="halign">center</property>
    
    465
    -                    <property name="valign">center</property>
    
    466
    -                    <property name="hexpand">True</property>
    
    467
    -                    <property name="vexpand">True</property>
    
    468
    -                    <property name="row-spacing">12</property>
    
    469
    -                    <child>
    
    470
    -                      <object class="GtkBox">
    
    471
    -                        <property name="visible">True</property>
    
    472
    -                        <property name="can-focus">False</property>
    
    473
    -                        <property name="homogeneous">True</property>
    
    474
    -                        <child>
    
    475
    -                          <object class="GtkButton" id="captcha_close_button">
    
    476
    -                            <property name="label" translatable="yes">_Close</property>
    
    477
    -                            <property name="visible">True</property>
    
    478
    -                            <property name="can-focus">True</property>
    
    479
    -                            <property name="can-default">True</property>
    
    480
    -                            <property name="receives-default">True</property>
    
    481
    -                            <property name="halign">center</property>
    
    482
    -                            <property name="valign">start</property>
    
    483
    -                            <property name="use-underline">True</property>
    
    484
    -                            <signal name="clicked" handler="_on_page_close_clicked" swapped="no"/>
    
    485
    -                          </object>
    
    486
    -                          <packing>
    
    487
    -                            <property name="expand">False</property>
    
    488
    -                            <property name="fill">True</property>
    
    489
    -                            <property name="position">0</property>
    
    490
    -                          </packing>
    
    491
    -                        </child>
    
    492
    -                        <child>
    
    493
    -                          <object class="GtkButton" id="captcha_try_again_button">
    
    494
    -                            <property name="label" translatable="yes">_Try Again</property>
    
    495
    -                            <property name="visible">True</property>
    
    496
    -                            <property name="can-focus">True</property>
    
    497
    -                            <property name="can-default">True</property>
    
    498
    -                            <property name="receives-default">True</property>
    
    499
    -                            <property name="use-underline">True</property>
    
    500
    -                            <signal name="clicked" handler="_on_captcha_try_again_clicked" swapped="no"/>
    
    501
    -                            <style>
    
    502
    -                              <class name="suggested-action"/>
    
    503
    -                            </style>
    
    504
    -                          </object>
    
    505
    -                          <packing>
    
    506
    -                            <property name="expand">False</property>
    
    507
    -                            <property name="fill">True</property>
    
    508
    -                            <property name="position">1</property>
    
    509
    -                          </packing>
    
    510
    -                        </child>
    
    511
    -                      </object>
    
    512
    -                      <packing>
    
    513
    -                        <property name="left-attach">0</property>
    
    514
    -                        <property name="top-attach">2</property>
    
    515
    -                      </packing>
    
    516
    -                    </child>
    
    517
    -                    <child>
    
    518
    -                      <object class="GtkImage">
    
    519
    -                        <property name="visible">True</property>
    
    520
    -                        <property name="can-focus">False</property>
    
    521
    -                        <property name="icon-name">dialog-error-symbolic</property>
    
    522
    -                        <property name="icon_size">6</property>
    
    523
    -                        <style>
    
    524
    -                          <class name="error-color"/>
    
    525
    -                        </style>
    
    526
    -                      </object>
    
    527
    -                      <packing>
    
    528
    -                        <property name="left-attach">0</property>
    
    529
    -                        <property name="top-attach">0</property>
    
    530
    -                      </packing>
    
    531
    -                    </child>
    
    532
    -                    <child>
    
    533
    -                      <object class="GtkLabel" id="captcha_error_label">
    
    534
    -                        <property name="visible">True</property>
    
    535
    -                        <property name="can-focus">False</property>
    
    536
    -                        <property name="justify">center</property>
    
    537
    -                        <property name="wrap">True</property>
    
    538
    -                        <property name="max-width-chars">40</property>
    
    539
    -                        <style>
    
    540
    -                          <class name="bold16"/>
    
    541
    -                        </style>
    
    542
    -                      </object>
    
    543
    -                      <packing>
    
    544
    -                        <property name="left-attach">0</property>
    
    545
    -                        <property name="top-attach">1</property>
    
    546
    -                      </packing>
    
    547
    -                    </child>
    
    548
    -                  </object>
    
    549
    -                  <packing>
    
    550
    -                    <property name="expand">False</property>
    
    551
    -                    <property name="fill">True</property>
    
    552
    -                    <property name="position">0</property>
    
    553
    -                  </packing>
    
    554
    -                </child>
    
    555
    -              </object>
    
    556
    -              <packing>
    
    557
    -                <property name="name">captcha-error</property>
    
    558
    -                <property name="position">4</property>
    
    559
    -              </packing>
    
    560
    -            </child>
    
    561
    -            <child>
    
    562
    -              <placeholder/>
    
    563
    -            </child>
    
    564 365
                 <child>
    
    565 366
                   <placeholder/>
    
    566 367
                 </child>
    

  • gajim/gtk/chat_function_page.py
    ... ... @@ -38,7 +38,7 @@
    38 38
     class ChatFunctionPage(Gtk.Box):
    
    39 39
     
    
    40 40
         __gsignals__ = {
    
    41
    -        'finish': (GObject.SignalFlags.RUN_LAST, None, ()),
    
    41
    +        'finish': (GObject.SignalFlags.RUN_LAST, None, (bool,)),
    
    42 42
             'message': (GObject.SignalFlags.RUN_LAST, None, (str,)),
    
    43 43
         }
    
    44 44
     
    
    ... ... @@ -63,6 +63,7 @@ def __init__(self) -> None:
    63 63
             self.add(self._heading)
    
    64 64
     
    
    65 65
             self._content_box = Gtk.Box()
    
    66
    +        self._content_box.set_halign(Gtk.Align.CENTER)
    
    66 67
             self.add(self._content_box)
    
    67 68
     
    
    68 69
             cancel_button = Gtk.Button(label=_('Cancel'))
    
    ... ... @@ -72,7 +73,7 @@ def __init__(self) -> None:
    72 73
             self._confirm_button.set_can_default(True)
    
    73 74
             self._confirm_button.connect('clicked', self._on_confirm_clicked)
    
    74 75
     
    
    75
    -        button_box = Gtk.Box()
    
    76
    +        button_box = Gtk.Box(spacing=18)
    
    76 77
             button_box.pack_start(cancel_button, False, True, 0)
    
    77 78
             button_box.pack_end(self._confirm_button, False, True, 0)
    
    78 79
     
    
    ... ... @@ -81,7 +82,7 @@ def __init__(self) -> None:
    81 82
     
    
    82 83
         def _on_key_press(self, _widget: Gtk.Widget, event: Gdk.EventKey) -> None:
    
    83 84
             if event.keyval == Gdk.KEY_Escape:
    
    84
    -            self.emit('finish')
    
    85
    +            self.emit('finish', self._mode in ('error', 'captcha-error'))
    
    85 86
     
    
    86 87
         def _clear(self) -> None:
    
    87 88
             for child in self._content_box.get_children():
    
    ... ... @@ -159,6 +160,14 @@ def set_mode(self,
    159 160
                 self._widget.show_all()
    
    160 161
                 self._widget.connect('is-valid', self._on_ready)
    
    161 162
     
    
    163
    +        elif mode == 'captcha-error':
    
    164
    +            self._confirm_button.set_label(_('Try Again'))
    
    165
    +            self._confirm_button.set_sensitive(True)
    
    166
    +            self._confirm_button.get_style_context().add_class(
    
    167
    +                'suggested-action')
    
    168
    +            assert data is not None
    
    169
    +            self._widget = ErrorWidget(data)
    
    170
    +
    
    162 171
             assert self._widget is not None
    
    163 172
             self._content_box.add(self._widget)
    
    164 173
             if isinstance(self._widget, InputWidget):
    
    ... ... @@ -221,7 +230,12 @@ def _on_confirm_clicked(self, _button: Gtk.Button) -> None:
    221 230
                 self._client.get_module('MUC').send_captcha(
    
    222 231
                     self._contact.jid, form_node)
    
    223 232
     
    
    224
    -        self.emit('finish')
    
    233
    +        elif self._mode == 'captcha-error':
    
    234
    +            assert self._client is not None
    
    235
    +            assert self._contact is not None
    
    236
    +            self._client.get_module('MUC').join(self._contact.jid)
    
    237
    +
    
    238
    +        self.emit('finish', False)
    
    225 239
     
    
    226 240
         def _on_cancel_clicked(self, _button: Gtk.Button) -> None:
    
    227 241
             if self._mode == 'captcha-request':
    
    ... ... @@ -229,8 +243,14 @@ def _on_cancel_clicked(self, _button: Gtk.Button) -> None:
    229 243
                 assert self._contact is not None
    
    230 244
                 self._client.get_module('MUC').cancel_captcha(
    
    231 245
                     self._contact.jid)
    
    246
    +            self.emit('finish', True)
    
    247
    +            return
    
    232 248
     
    
    233
    -        self.emit('finish')
    
    249
    +        if self._mode in ('error', 'captcha-error'):
    
    250
    +            self.emit('finish', True)
    
    251
    +            return
    
    252
    +
    
    253
    +        self.emit('finish', False)
    
    234 254
     
    
    235 255
         def _invite(self, invited_jid: JID) -> None:
    
    236 256
             assert self._contact is not None
    
    ... ... @@ -323,3 +343,22 @@ def focus(self) -> None:
    323 343
     
    
    324 344
         def get_text(self) -> str:
    
    325 345
             return self._entry.get_text()
    
    346
    +
    
    347
    +
    
    348
    +class ErrorWidget(Gtk.Box):
    
    349
    +    def __init__(self, error_text: str) -> None:
    
    350
    +        Gtk.Box.__init__(self,
    
    351
    +                         orientation=Gtk.Orientation.VERTICAL,
    
    352
    +                         spacing=12)
    
    353
    +        image = Gtk.Image.new_from_icon_name(
    
    354
    +            'dialog-error-symbolic', Gtk.IconSize.DIALOG)
    
    355
    +        image.get_style_context().add_class('error-color')
    
    356
    +        heading = Gtk.Label(label=_('Error'))
    
    357
    +        heading.get_style_context().add_class('bold16')
    
    358
    +        label = Gtk.Label(label=error_text)
    
    359
    +        label.set_max_width_chars(40)
    
    360
    +
    
    361
    +        self.add(image)
    
    362
    +        self.add(heading)
    
    363
    +        self.add(label)
    
    364
    +        self.show_all()

  • gajim/gtk/chat_stack.py
    ... ... @@ -24,7 +24,9 @@
    24 24
     from gi.repository import Gio
    
    25 25
     from gi.repository import Gtk
    
    26 26
     
    
    27
    +from nbxmpp.errors import StanzaError
    
    27 28
     from nbxmpp.protocol import JID
    
    29
    +from nbxmpp.structs import MessageProperties
    
    28 30
     from nbxmpp.structs import PresenceProperties
    
    29 31
     
    
    30 32
     from gajim.common import app
    
    ... ... @@ -106,6 +108,8 @@ def show_chat(self, account: str, jid: JID) -> None:
    106 108
                     'user-role-changed': self._on_user_role_changed,
    
    107 109
                     'user-affiliation-changed': self._on_user_affiliation_changed,
    
    108 110
                     'state-changed': self._on_muc_state_changed,
    
    111
    +                'room-captcha-challenge': self._on_muc_captcha_challenge,
    
    112
    +                'room-captcha-error': self._on_muc_captcha_error,
    
    109 113
                 })
    
    110 114
                 self._update_group_chat_actions(self._current_contact)
    
    111 115
             elif isinstance(self._current_contact, GroupchatParticipant):
    
    ... ... @@ -118,17 +122,36 @@ def show_chat(self, account: str, jid: JID) -> None:
    118 122
                     str(self._current_contact.jid))
    
    119 123
                 if muc_data is not None:
    
    120 124
                     if muc_data.state.is_captcha_request:
    
    121
    -                    self._chat_function_page.set_mode(
    
    122
    -                        self._current_contact, 'captcha-request')
    
    125
    +                    self._show_chat_function_page('captcha-request')
    
    123 126
                         return
    
    127
    +
    
    128
    +                if muc_data.error == 'captcha-failed':
    
    129
    +                    self._show_chat_function_page(
    
    130
    +                        'captcha-error', muc_data.error_text)
    
    131
    +                    return
    
    132
    +
    
    124 133
                     if muc_data.state.is_password_request:
    
    125
    -                    self._chat_function_page.set_mode(
    
    126
    -                        self._current_contact, 'password-request')
    
    134
    +                    self._show_chat_function_page('password-request')
    
    127 135
                         return
    
    128 136
     
    
    129 137
             self.set_transition_type(Gtk.StackTransitionType.NONE)
    
    130 138
             self.set_visible_child_name('controls')
    
    131 139
     
    
    140
    +    def _on_muc_captcha_challenge(self,
    
    141
    +                                  contact: GroupchatContact,
    
    142
    +                                  _signal_name: str,
    
    143
    +                                  properties: MessageProperties
    
    144
    +                                  ) -> None:
    
    145
    +        self._show_chat_function_page('captcha-request')
    
    146
    +
    
    147
    +    def _on_muc_captcha_error(self,
    
    148
    +                              _contact: GroupchatContact,
    
    149
    +                              _signal_name: str,
    
    150
    +                              error: StanzaError
    
    151
    +                              ) -> None:
    
    152
    +        error_text = helpers.to_user_string(error)
    
    153
    +        self._show_chat_function_page('captcha-error', error_text)
    
    154
    +
    
    132 155
         def _on_muc_state_changed(self,
    
    133 156
                                   contact: GroupchatContact,
    
    134 157
                                   _signal_name: str
    
    ... ... @@ -412,8 +435,16 @@ def _show_chat_function_page(self,
    412 435
             self.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN)
    
    413 436
             self.set_visible_child_name('function')
    
    414 437
     
    
    415
    -    def _on_function_finished(self, _function_page: ChatFunctionPage) -> None:
    
    416
    -        # TODO: close control on password/captcha cancel
    
    438
    +    def _on_function_finished(self,
    
    439
    +                              _function_page: ChatFunctionPage,
    
    440
    +                              close_control: bool
    
    441
    +                              ) -> None:
    
    442
    +        if close_control:
    
    443
    +            self._close_control()
    
    444
    +            self.set_visible_child_name('empty')
    
    445
    +            self.set_transition_type(Gtk.StackTransitionType.NONE)
    
    446
    +            return
    
    447
    +
    
    417 448
             self.set_visible_child_name('controls')
    
    418 449
             self.set_transition_type(Gtk.StackTransitionType.NONE)
    
    419 450
     
    
    ... ... @@ -485,6 +516,14 @@ def _on_send_message(self) -> None:
    485 516
     
    
    486 517
             self._message_action_box.msg_textview.clear()
    
    487 518
     
    
    519
    +    def _close_control(self) -> None:
    
    520
    +        assert self._current_contact is not None
    
    521
    +        app.window.activate_action(
    
    522
    +            'remove-chat',
    
    523
    +            GLib.Variant('as',
    
    524
    +                         [self._current_contact.account,
    
    525
    +                          str(self._current_contact.jid)]))
    
    526
    +
    
    488 527
         def clear(self) -> None:
    
    489 528
             self.set_visible_child_name('empty')
    
    490 529
             self._control_stack.clear()
    

  • gajim/gtk/controls/groupchat.py
    ... ... @@ -60,7 +60,6 @@
    60 60
     from gajim.gui.const import TARGET_TYPE_URI_LIST
    
    61 61
     from gajim.gui.dialogs import DialogButton
    
    62 62
     from gajim.gui.dialogs import ConfirmationDialog
    
    63
    -from gajim.gui.dataform import DataFormWidget
    
    64 63
     from gajim.gui.groupchat_roster import GroupchatRoster
    
    65 64
     from gajim.gui.groupchat_state import GroupchatState
    
    66 65
     from gajim.gui.util import open_window
    
    ... ... @@ -112,9 +111,6 @@ def __init__(self, account: str, jid: JID) -> None:
    112 111
                 'hide_groupchat_occupants_list', self._show_roster)
    
    113 112
             self.roster.connect('row-activated', self._on_roster_row_activated)
    
    114 113
     
    
    115
    -        # Holds CaptchaRequest widget
    
    116
    -        self._captcha_request: Optional[DataFormWidget] = None
    
    117
    -
    
    118 114
             self._subject_text = ''
    
    119 115
     
    
    120 116
             self._set_control_inactive()
    
    ... ... @@ -147,8 +143,6 @@ def _connect_contact_signals(self) -> None:
    147 143
                 'room-creation-failed': self._on_room_creation_failed,
    
    148 144
                 'room-presence-error': self._on_room_presence_error,
    
    149 145
                 'room-voice-request': self._on_room_voice_request,
    
    150
    -            'room-captcha-challenge': self._on_room_captcha_challenge,
    
    151
    -            'room-captcha-error': self._on_room_captcha_error,
    
    152 146
                 'room-subject': self._on_room_subject,
    
    153 147
                 'room-joined': self._on_room_joined,
    
    154 148
                 'room-join-failed': self._on_room_join_failed,
    
    ... ... @@ -792,9 +786,7 @@ def delegate_action(self, action: str) -> int:
    792 786
     
    
    793 787
                 if self._get_current_page() == 'password':
    
    794 788
                     self._on_password_cancel_clicked()
    
    795
    -            elif self._get_current_page() == 'captcha':
    
    796
    -                self._on_captcha_cancel_clicked()
    
    797
    -            elif self._get_current_page() in ('error', 'captcha-error'):
    
    789
    +            elif self._get_current_page() == 'error':
    
    798 790
                     self._on_page_close_clicked()
    
    799 791
                 else:
    
    800 792
                     self._show_page('groupchat')
    
    ... ... @@ -816,8 +808,6 @@ def focus(self) -> None:
    816 808
                 pass
    
    817 809
             elif page_name == 'password':
    
    818 810
                 self.xml.password_entry.grab_focus_without_selecting()
    
    819
    -        elif page_name == 'captcha':
    
    820
    -            self._captcha_request.focus_first_entry()
    
    821 811
     
    
    822 812
         def _on_page_change(self, stack: Gtk.Stack, _param: Any) -> None:
    
    823 813
             page_name = stack.get_visible_child_name()
    
    ... ... @@ -827,10 +817,6 @@ def _on_page_change(self, stack: Gtk.Stack, _param: Any) -> None:
    827 817
                 self.xml.password_entry.set_text('')
    
    828 818
                 self.xml.password_entry.grab_focus()
    
    829 819
                 self.xml.password_set_button.grab_default()
    
    830
    -        elif page_name == 'captcha':
    
    831
    -            self.xml.captcha_set_button.grab_default()
    
    832
    -        elif page_name == 'captcha-error':
    
    833
    -            self.xml.captcha_try_again_button.grab_default()
    
    834 820
             elif page_name == 'error':
    
    835 821
                 self.xml.close_button.grab_default()
    
    836 822
     
    
    ... ... @@ -846,63 +832,6 @@ def _on_password_changed(self, entry: Gtk.Entry, *args: Any) -> None:
    846 832
         def _on_password_cancel_clicked(self, *args: Any) -> None:
    
    847 833
             self._close_control()
    
    848 834
     
    
    849
    -    def _on_room_captcha_challenge(self,
    
    850
    -                                   _contact: GroupchatContact,
    
    851
    -                                   _signal_name: str,
    
    852
    -                                   properties: MessageProperties
    
    853
    -                                   ) -> None:
    
    854
    -        self._remove_captcha_request()
    
    855
    -        form = properties.captcha.form
    
    856
    -
    
    857
    -        options = {'no-scrolling': True,
    
    858
    -                   'entry-activates-default': True}
    
    859
    -        self._captcha_request = DataFormWidget(form, options=options)
    
    860
    -        self._captcha_request.connect('is-valid', self._on_captcha_changed)
    
    861
    -        self._captcha_request.set_valign(Gtk.Align.START)
    
    862
    -        self._captcha_request.show_all()
    
    863
    -        self.xml.captcha_box.add(self._captcha_request)
    
    864
    -
    
    865
    -        self._show_page('captcha')
    
    866
    -        self._captcha_request.focus_first_entry()
    
    867
    -
    
    868
    -    def _on_room_captcha_error(self,
    
    869
    -                               _contact: GroupchatContact,
    
    870
    -                               _signal_name: str,
    
    871
    -                               error: StanzaError
    
    872
    -                               ) -> None:
    
    873
    -        error_text = to_user_string(error)
    
    874
    -        self.xml.captcha_error_label.set_text(error_text)
    
    875
    -        self._show_page('captcha-error')
    
    876
    -
    
    877
    -    def _remove_captcha_request(self) -> None:
    
    878
    -        if self._captcha_request is None:
    
    879
    -            return
    
    880
    -        if self._captcha_request in self.xml.captcha_box.get_children():
    
    881
    -            self.xml.captcha_box.remove(self._captcha_request)
    
    882
    -        self._captcha_request.destroy()
    
    883
    -        self._captcha_request = None
    
    884
    -
    
    885
    -    def _on_captcha_changed(self,
    
    886
    -                            _widget: DataFormWidget,
    
    887
    -                            is_valid: bool
    
    888
    -                            ) -> None:
    
    889
    -        self.xml.captcha_set_button.set_sensitive(is_valid)
    
    890
    -
    
    891
    -    def _on_captcha_set_clicked(self, _button: Gtk.Button) -> None:
    
    892
    -        form_node = self._captcha_request.get_submit_form()
    
    893
    -        self._client.get_module('MUC').send_captcha(self.room_jid, form_node)
    
    894
    -        self._remove_captcha_request()
    
    895
    -        self._show_page('groupchat')
    
    896
    -
    
    897
    -    def _on_captcha_cancel_clicked(self, *args: Any) -> None:
    
    898
    -        self._client.get_module('MUC').cancel_captcha(self.room_jid)
    
    899
    -        self._remove_captcha_request()
    
    900
    -        self._close_control()
    
    901
    -
    
    902
    -    def _on_captcha_try_again_clicked(self, _button: Gtk.Button) -> None:
    
    903
    -        self._client.get_module('MUC').join(self.room_jid)
    
    904
    -        self._show_page('groupchat')
    
    905
    -
    
    906 835
         def _on_remove_bookmark_button_clicked(self, _button: Gtk.Button) -> None:
    
    907 836
             self._client.get_module('Bookmarks').remove(self.room_jid)
    
    908 837
             self._close_control()