Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions resources/main-window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,26 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="user_send_msg_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Send message</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">2</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
Expand Down
23 changes: 23 additions & 0 deletions resources/op-item.ui
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
<property name="halign">center</property>
<property name="icon_name">list-remove-symbolic</property>
</object>
<object class="GtkImage" id="image11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="icon_name">edit-copy-symbolic</property>
</object>
<object class="GtkBox" id="op_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
Expand Down Expand Up @@ -139,8 +145,10 @@
<property name="can_focus">False</property>
<property name="label" translatable="yes">Awaiting approval</property>
<property name="wrap">True</property>
<property name="ellipsize">end</property>
<property name="width_chars">30</property>
<property name="max_width_chars">30</property>
<property name="lines">4</property>
<property name="xalign">0</property>
</object>
<packing>
Expand Down Expand Up @@ -386,6 +394,21 @@
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkButton" id="transfer_copy_message">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Copy message</property>
<property name="valign">center</property>
<property name="image">image11</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">9</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
Expand Down
31 changes: 31 additions & 0 deletions src/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,34 @@ def _notification_response(self, action, variant, op):

app = Gio.Application.get_default()
app.lookup_action("notification-response").disconnect_by_func(self._notification_response)

class TextMessageNotification():
def __init__(self, op):
self.op = op
self.send_notification()

@misc._idle
def send_notification(self):
if prefs.get_show_notifications():
notification = Gio.Notification.new(_("New message from %s") % self.op.sender_name)
notification.set_body(self.op.message)
notification.set_icon(Gio.ThemedIcon(name="org.x.Warpinator-symbolic"))
notification.set_priority(Gio.NotificationPriority.URGENT)

notification.add_button(_("Copy"), "app.notification-response::copy")
notification.set_default_action("app.notification-response::focus")

app = Gio.Application.get_default()
app.lookup_action("notification-response").connect("activate", self._notification_response, self.op)
app.send_notification(self.op.sender, notification)

def _notification_response(self, action, variant, op):
response = variant.unpack()

if response == "copy":
op.copy_message()
else:
op.focus()

app = Gio.Application.get_default()
app.lookup_action("notification-response").disconnect_by_func(self._notification_response)
22 changes: 21 additions & 1 deletion src/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
from pathlib import Path

from gi.repository import GObject, GLib, Gio
from gi.repository import GObject, GLib, Gio, Gtk, Gdk

import grpc

Expand Down Expand Up @@ -283,3 +283,23 @@ def stop_transfer(self):
def remove_transfer(self):
self.emit("op-command", OpCommand.REMOVE_TRANSFER)

class TextMessageOp(CommonOp):
message = None

def __init__(self, direction, sender):
super(TextMessageOp, self).__init__(direction, sender)
self.gicon = Gio.ThemedIcon.new("mail-message-new-symbolic")
self.description = _("Text message")

def copy_message(self):
cb = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
cb.set_text(self.message, -1)

def send_notification(self):
notifications.TextMessageNotification(self)

def remove_transfer(self):
self.emit("op-command", OpCommand.REMOVE_TRANSFER)

def retry_transfer(self):
self.emit("op-command", OpCommand.RETRY_TRANSFER)
26 changes: 23 additions & 3 deletions src/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import misc
import transfers
import auth
from ops import SendOp, ReceiveOp
from ops import SendOp, ReceiveOp, TextMessageOp
from util import TransferDirection, OpStatus, OpCommand, RemoteStatus, ReceiveError

_ = gettext.gettext
Expand Down Expand Up @@ -585,6 +585,21 @@ def _send_files(uri_list):
util.add_to_recents_if_single_selection(uri_list)
self.rpc_call(_send_files, uri_list)

def send_text_message(self, message):
op = TextMessageOp(TransferDirection.TO_REMOTE_MACHINE, self.local_ident)
op.message = message
op.status = OpStatus.FINISHED
self.add_op(op)
self.rpc_call(self.do_send_text_message, op)

def do_send_text_message(self, op):
try:
self.stub.SendTextMessage(warp_pb2.TextMessage(ident=self.local_ident, timestamp=op.start_time, message=op.message))
except Exception as e:
logging.error("Sending message failed: %s" % e)
op.status = OpStatus.FAILED
op.emit_status_changed()

@misc._idle
def add_op(self, op):
if op not in self.transfer_ops:
Expand Down Expand Up @@ -657,8 +672,13 @@ def op_command_issued(self, op, command):
elif command == OpCommand.STOP_TRANSFER_BY_SENDER:
self.rpc_call(self.stop_transfer_op, op, by_sender=True)
elif command == OpCommand.RETRY_TRANSFER:
op.set_status(OpStatus.WAITING_PERMISSION)
self.rpc_call(self.send_transfer_op_request, op)
if isinstance(op, TextMessageOp):
op.status = OpStatus.FINISHED
op.emit_status_changed()
self.rpc_call(self.do_send_text_message, op)
else:
op.set_status(OpStatus.WAITING_PERMISSION)
self.rpc_call(self.send_transfer_op_request, op)
elif command == OpCommand.REMOVE_TRANSFER:
self.remove_op(op)
# receive
Expand Down
19 changes: 18 additions & 1 deletion src/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import util
import misc
import transfers
from ops import ReceiveOp
from ops import ReceiveOp, TextMessageOp
from util import TransferDirection, OpStatus, RemoteStatus

import zeroconf
Expand Down Expand Up @@ -669,3 +669,20 @@ def StopTransfer(self, request, context):
op.set_status(OpStatus.FAILED)

return void

def SendTextMessage(self, request, context):
logging.debug("Server RPC: SendTextMessage from '%s'" % request.ident)
try:
remote_machine:remote.RemoteMachine = self.remote_machines[request.ident]
except KeyError as e:
logging.warning("Received text message from unknown remote: %s" % e)
return

op = TextMessageOp(TransferDirection.FROM_REMOTE_MACHINE, request.ident)
op.sender_name = remote_machine.display_name
op.message = request.message
op.status = OpStatus.FINISHED
remote_machine.add_op(op)
op.send_notification()

return void
6 changes: 6 additions & 0 deletions src/warp.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ service Warp {
rpc GetRemoteMachineAvatar(LookupName) returns (stream RemoteMachineAvatar) {}
rpc ProcessTransferOpRequest(TransferOpRequest) returns (VoidType) {}
rpc PauseTransferOp(OpInfo) returns (VoidType) {}
rpc SendTextMessage(TextMessage) returns (VoidType) {}

// Receiver methods
rpc StartTransfer(OpInfo) returns (stream FileChunk) {}
Expand Down Expand Up @@ -112,3 +113,8 @@ message ServiceRegistration {
uint32 auth_port = 6;
}

message TextMessage {
string ident = 1;
uint64 timestamp = 2;
string message = 3;
}
12 changes: 7 additions & 5 deletions src/warp_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions src/warp_pb2_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def __init__(self, channel):
request_serializer=warp__pb2.OpInfo.SerializeToString,
response_deserializer=warp__pb2.VoidType.FromString,
)
self.SendTextMessage = channel.unary_unary(
'/Warp/SendTextMessage',
request_serializer=warp__pb2.TextMessage.SerializeToString,
response_deserializer=warp__pb2.VoidType.FromString,
)
self.StartTransfer = channel.unary_stream(
'/Warp/StartTransfer',
request_serializer=warp__pb2.OpInfo.SerializeToString,
Expand Down Expand Up @@ -122,6 +127,12 @@ def PauseTransferOp(self, request, context):
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')

def SendTextMessage(self, request, context):
"""Missing associated documentation comment in .proto file."""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')

def StartTransfer(self, request, context):
"""Receiver methods
"""
Expand Down Expand Up @@ -181,6 +192,11 @@ def add_WarpServicer_to_server(servicer, server):
request_deserializer=warp__pb2.OpInfo.FromString,
response_serializer=warp__pb2.VoidType.SerializeToString,
),
'SendTextMessage': grpc.unary_unary_rpc_method_handler(
servicer.SendTextMessage,
request_deserializer=warp__pb2.TextMessage.FromString,
response_serializer=warp__pb2.VoidType.SerializeToString,
),
'StartTransfer': grpc.unary_stream_rpc_method_handler(
servicer.StartTransfer,
request_deserializer=warp__pb2.OpInfo.FromString,
Expand Down Expand Up @@ -320,6 +336,23 @@ def PauseTransferOp(request,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

@staticmethod
def SendTextMessage(request,
target,
options=(),
channel_credentials=None,
call_credentials=None,
insecure=False,
compression=None,
wait_for_ready=None,
timeout=None,
metadata=None):
return grpc.experimental.unary_unary(request, target, '/Warp/SendTextMessage',
warp__pb2.TextMessage.SerializeToString,
warp__pb2.VoidType.FromString,
options, channel_credentials,
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)

@staticmethod
def StartTransfer(request,
target,
Expand Down
Loading
Loading