Now About Social Code
aboutsummaryrefslogtreecommitdiff
path: root/src/main.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.py')
-rw-r--r--src/main.py338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/main.py b/src/main.py
new file mode 100644
index 0000000..8997ab5
--- /dev/null
+++ b/src/main.py
@@ -0,0 +1,338 @@
+# main.py
+#
+# Copyright 2024 Lucas Fryzek
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+import sys
+import os
+import gi
+
+gi.require_version('Gtk', '4.0')
+gi.require_version('Adw', '1')
+
+from gi.repository import Gtk, Gio, Adw
+from .window import WeegtkWindow
+
+from .network import Network
+from weegtk import protocol
+from weegtk import config
+from .chat import WeegtkChat
+from .preferences import WeegtkPreferences
+
+class WeegtkApplication(Adw.Application):
+ """The main application singleton class."""
+
+ def __init__(self):
+ super().__init__(application_id='com.fryzekconcepts.weegtk',
+ flags=Gio.ApplicationFlags.DEFAULT_FLAGS)
+ self.create_action('quit', lambda *_: self.quit(), ['<primary>q'])
+ self.create_action('about', self.on_about_action)
+ self.create_action('preferences', self.on_preferences_action)
+
+ self.network = Network()
+ self.network.connect("status_changed", self._network_status_changed)
+ self.network.connect("message_from_weechat", self._network_weechat_msg)
+
+ conf = config.read()
+ #self.network.connect_weechat("localhost", "9001", False, relay_pw, None, "")
+ self.network.connect_weechat_ssh(conf["ssh"]["host"],
+ conf["ssh"]["port"],
+ conf["ssh"]["username"],
+ conf["ssh"]["key"],
+ conf["relay"]["hostname"],
+ conf["relay"]["port"],
+ conf["relay"]["password"])
+
+ self.buffers = []
+
+ def _network_status_changed(self, source_object, status, extra):
+ """Called when the network status has changed."""
+ # TODO handle this
+ #if self.config.getboolean('look', 'statusbar'):
+ # self.statusBar().showMessage(status)
+ #self.network.debug_print(0, '', status, forcecolor='#0000AA')
+ #self.network_status_set(status)
+ print(f"Status is {status}")
+
+ def _network_weechat_msg(self, source_object, message):
+ """Called when a message is received from WeeChat."""
+ #print(f"Message {message}")
+ try:
+ proto = protocol.Protocol()
+ message = proto.decode(message.get_data())
+ # TODO figure this out
+ #if message.uncompressed:
+ # self.network.debug_print(
+ # 0, '==>',
+ # 'message uncompressed (%d bytes):\n%s'
+ # % (message.size_uncompressed,
+ # protocol.hex_and_ascii(message.uncompressed, 20)),
+ # forcecolor='#008800')
+ #self.network.debug_print(0, '', 'Message: %s' % message)
+ #print(f"parsed message is f{message}")
+ self.parse_message(message)
+ except:
+ print('Error while decoding message from WeeChat:\n%s'
+ % traceback.format_exc())
+ self.net.disconnect_weechat()
+
+ def do_activate(self):
+ """Called when the application is activated.
+
+ We raise the application's main window, creating it if
+ necessary.
+ """
+ win = self.props.active_window
+ if not win:
+ win = WeegtkWindow(application=self)
+ win.present()
+
+ def on_about_action(self, *args):
+ """Callback for the app.about action."""
+ about = Adw.AboutDialog(application_name='weegtk',
+ application_icon='com.fryzekconcepts.weegtk',
+ developer_name='Lucas Fryzek',
+ version='0.1.0',
+ developers=['Lucas Fryzek <lucas.fryzek@fryzekconcepts.com>'],
+ copyright='© 2024 Lucas Fryzek')
+ # Translators: Replace "translator-credits" with your name/username, and optionally an email or URL.
+ about.set_translator_credits(_('translator-credits'))
+ about.add_credit_section("QWeechat", ["Sébastien Helleu <flashcode@flashtux.org>"])
+ about.present(self.props.active_window)
+
+ def on_preferences_action(self, widget, _):
+ """Callback for the app.preferences action."""
+ pref = WeegtkPreferences()
+ pref.present(self.props.active_window)
+
+ def create_action(self, name, callback, shortcuts=None):
+ """Add an application action.
+
+ Args:
+ name: the name of the action
+ callback: the function to be called when the action is
+ activated
+ shortcuts: an optional list of accelerators
+ """
+ action = Gio.SimpleAction.new(name, None)
+ action.connect("activate", callback)
+ self.add_action(action)
+ if shortcuts:
+ self.set_accels_for_action(f"app.{name}", shortcuts)
+
+ def _parse_handshake(self, message):
+ """Parse a WeeChat message with handshake response."""
+ for obj in message.objects:
+ if obj.objtype != 'htb':
+ continue
+ self.network.init_with_handshake(obj.value)
+ break
+
+ def _parse_listbuffers(self, message):
+ """Parse a WeeChat message with list of buffers."""
+ # TODO handle gui for this
+ for obj in message.objects:
+ if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer':
+ continue
+ #self.list_buffers.clear()
+ #while self.stacked_buffers.count() > 0:
+ # buf = self.stacked_buffers.widget(0)
+ # self.stacked_buffers.removeWidget(buf)
+ self.buffers = []
+ for item in obj.value['items']:
+ buf = self.create_buffer(item)
+ self.insert_buffer(len(self.buffers), buf)
+ #self.list_buffers.setCurrentRow(0)
+ #self.buffers[0].widget.input.setFocus()
+
+ def _parse_line(self, message):
+ """Parse a WeeChat message with a buffer line."""
+ # TODO implement text for chats
+ for obj in message.objects:
+ lines = []
+ if obj.objtype != 'hda' or obj.value['path'][-1] != 'line_data':
+ continue
+ for item in obj.value['items']:
+ if message.msgid == 'listlines':
+ ptrbuf = item['__path'][0]
+ else:
+ ptrbuf = item['buffer']
+ index = [i for i, b in enumerate(self.buffers)
+ if b.pointer() == ptrbuf]
+ if index:
+ lines.append(
+ (index[0],
+ (item['date'], item['prefix'],
+ item['message']))
+ )
+ if message.msgid == 'listlines':
+ lines.reverse()
+ for line in lines:
+ #print(line)
+ self.buffers[line[0]].display(*line[1])
+
+ def _parse_nicklist(self, message):
+ """Parse a WeeChat message with a buffer nicklist."""
+ # TODO implement nicklist for chat
+ # buffer_refresh = {}
+ # for obj in message.objects:
+ # if obj.objtype != 'hda' or \
+ # obj.value['path'][-1] != 'nicklist_item':
+ # continue
+ # group = '__root'
+ # for item in obj.value['items']:
+ # index = [i for i, b in enumerate(self.buffers)
+ # if b.pointer() == item['__path'][0]]
+ # if index:
+ # if not index[0] in buffer_refresh:
+ # self.buffers[index[0]].nicklist = {}
+ # buffer_refresh[index[0]] = True
+ # if item['group']:
+ # group = item['name']
+ # self.buffers[index[0]].nicklist_add_item(
+ # group, item['group'], item['prefix'], item['name'],
+ # item['visible'])
+ # for index in buffer_refresh:
+ # self.buffers[index].nicklist_refresh()
+
+ def _parse_nicklist_diff(self, message):
+ """Parse a WeeChat message with a buffer nicklist diff."""
+ buffer_refresh = {}
+ for obj in message.objects:
+ if obj.objtype != 'hda' or \
+ obj.value['path'][-1] != 'nicklist_item':
+ continue
+ group = '__root'
+ for item in obj.value['items']:
+ index = [i for i, b in enumerate(self.buffers)
+ if b.pointer() == item['__path'][0]]
+ if not index:
+ continue
+ buffer_refresh[index[0]] = True
+ if item['_diff'] == ord('^'):
+ group = item['name']
+ elif item['_diff'] == ord('+'):
+ self.buffers[index[0]].nicklist_add_item(
+ group, item['group'], item['prefix'], item['name'],
+ item['visible'])
+ elif item['_diff'] == ord('-'):
+ self.buffers[index[0]].nicklist_remove_item(
+ group, item['group'], item['name'])
+ elif item['_diff'] == ord('*'):
+ self.buffers[index[0]].nicklist_update_item(
+ group, item['group'], item['prefix'], item['name'],
+ item['visible'])
+ for index in buffer_refresh:
+ self.buffers[index].nicklist_refresh()
+
+ def _parse_buffer_opened(self, message):
+ """Parse a WeeChat message with a new buffer (opened)."""
+ for obj in message.objects:
+ if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer':
+ continue
+ for item in obj.value['items']:
+ buf = self.create_buffer(item)
+ index = self.find_buffer_index_for_insert(item['next_buffer'])
+ self.insert_buffer(index, buf)
+
+ def _parse_buffer(self, message):
+ """Parse a WeeChat message with a buffer event
+ (anything except a new buffer).
+ """
+ for obj in message.objects:
+ if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer':
+ continue
+ for item in obj.value['items']:
+ index = [i for i, b in enumerate(self.buffers)
+ if b.pointer() == item['__path'][0]]
+ if not index:
+ continue
+ index = index[0]
+ if message.msgid == '_buffer_type_changed':
+ self.buffers[index].data['type'] = item['type']
+ elif message.msgid in ('_buffer_moved', '_buffer_merged',
+ '_buffer_unmerged'):
+ buf = self.buffers[index]
+ buf.data['number'] = item['number']
+ self.remove_buffer(index)
+ index2 = self.find_buffer_index_for_insert(
+ item['next_buffer'])
+ self.insert_buffer(index2, buf)
+ elif message.msgid == '_buffer_renamed':
+ self.buffers[index].data['full_name'] = item['full_name']
+ self.buffers[index].data['short_name'] = item['short_name']
+ elif message.msgid == '_buffer_title_changed':
+ self.buffers[index].data['title'] = item['title']
+ self.buffers[index].update_title()
+ elif message.msgid == '_buffer_cleared':
+ self.buffers[index].widget.chat.clear()
+ elif message.msgid.startswith('_buffer_localvar_'):
+ self.buffers[index].data['local_variables'] = \
+ item['local_variables']
+ self.buffers[index].update_prompt()
+ elif message.msgid == '_buffer_closing':
+ self.remove_buffer(index)
+
+ def parse_message(self, message):
+ """Parse a WeeChat message."""
+ if message.msgid.startswith('debug'):
+ self.network.debug_print(0, '', '(debug message, ignored)')
+ elif message.msgid == 'handshake':
+ self._parse_handshake(message)
+ elif message.msgid == 'listbuffers':
+ self._parse_listbuffers(message)
+ elif message.msgid in ('listlines', '_buffer_line_added'):
+ self._parse_line(message)
+ elif message.msgid in ('_nicklist', 'nicklist'):
+ self._parse_nicklist(message)
+ elif message.msgid == '_nicklist_diff':
+ self._parse_nicklist_diff(message)
+ elif message.msgid == '_buffer_opened':
+ self._parse_buffer_opened(message)
+ elif message.msgid.startswith('_buffer_'):
+ self._parse_buffer(message)
+ elif message.msgid == '_upgrade':
+ self.network.desync_weechat()
+ elif message.msgid == '_upgrade_ended':
+ self.network.sync_weechat()
+ else:
+ print(f"Unknown message with id {message.msgid}")
+
+ def create_buffer(self, item):
+ """Create a new buffer."""
+ buf = WeegtkChat(data=item)
+ buf.connect("buffer_input", self.buffer_input)
+ return buf
+
+ def insert_buffer(self, index, buf):
+ """Insert a buffer in list."""
+ self.buffers.insert(index, buf)
+ buf_name = buf.data['short_name']
+
+ # Only make chats visible on main screen
+ if buf.is_chat():
+ self.props.active_window.stack.add_titled(buf, name=buf_name, title=buf_name)
+
+ def buffer_input(self, source_object, full_name, text):
+ if self.network.is_connected():
+ message = f"input {full_name} {text}\n"
+ self.network.send_to_weechat(message)
+
+def main(version):
+ """The application's entry point."""
+ app = WeegtkApplication()
+ return app.run(sys.argv)