manually merged changes in

This commit is contained in:
Jonathan Warren 2013-05-14 11:44:51 -04:00
commit 0842679314
16 changed files with 368 additions and 64 deletions

View File

@ -13,7 +13,6 @@ source:
install: install:
mkdir -m 755 -p $(DEST_APP) mkdir -m 755 -p $(DEST_APP)
mkdir -m 755 -p $(DEST_SHARE)/applications mkdir -m 755 -p $(DEST_SHARE)/applications
mkdir -m 755 -p $(DEST_SHARE)/applications/$(APP)
mkdir -m 755 -p $(DEST_APP)/images mkdir -m 755 -p $(DEST_APP)/images
mkdir -m 755 -p $(DEST_APP)/pyelliptic mkdir -m 755 -p $(DEST_APP)/pyelliptic
mkdir -m 755 -p $(DEST_APP)/socks mkdir -m 755 -p $(DEST_APP)/socks
@ -37,7 +36,7 @@ install:
install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt install -m 644 src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
install -m 755 debian/pybm /usr/bin/pybitmessage install -m 755 debian/pybm /usr/bin/pybitmessage
install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP)/$(APP).desktop install -m 644 desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop
install -m 644 src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png install -m 644 src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg install -m 644 desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
install -m 644 desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg install -m 644 desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
pybitmessage (0.3.0-1) unstable; urgency=low pybitmessage (0.3.0-1) raring; urgency=low
* Added new API function: getStatus * Added new API function: getStatus

4
debian/control vendored
View File

@ -2,7 +2,7 @@ Source: pybitmessage
Section: contrib/comm Section: contrib/comm
Priority: extra Priority: extra
Maintainer: Jonathan Warren <jonathan@bitmessage.org> Maintainer: Jonathan Warren <jonathan@bitmessage.org>
Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, libmessaging-menu-dev
Standards-Version: 3.9.2 Standards-Version: 3.9.2
Homepage: https://bitmessage.org/ Homepage: https://bitmessage.org/
Vcs-Browser: https://github.com/Bitmessage/PyBitmessage Vcs-Browser: https://github.com/Bitmessage/PyBitmessage
@ -10,7 +10,7 @@ Vcs-Git: https://github.com/Bitmessage/PyBitmessage.git
Package: pybitmessage Package: pybitmessage
Architecture: all Architecture: all
Depends: ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev Depends: ${misc:Depends}, python (>= 2.7.0), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, libmessaging-menu-dev
Description: Send encrypted messages to another person or to many subscribers Description: Send encrypted messages to another person or to many subscribers
Bitmessage is a P2P communications protocol used to send encrypted messages Bitmessage is a P2P communications protocol used to send encrypted messages
to another person or to many subscribers. It is decentralized and trustless, to another person or to many subscribers. It is decentralized and trustless,

1
debian/files vendored
View File

@ -1 +0,0 @@
pybitmessage_0.3.0-1_all.deb contrib/comm extra

4
debian/pybm vendored
View File

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
cd /usr/share/pybitmessage cd /usr/share/pybitmessage
python bitmessagemain.py exec python bitmessagemain.py

4
debian/rules vendored
View File

@ -20,11 +20,11 @@ install: build clean
dh_testroot dh_testroot
dh_prep dh_prep
dh_installdirs dh_installdirs
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr
mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr/bin mkdir -m 755 -p $(CURDIR)/debian/$(APP)/usr/bin
mkdir -m 755 -p $(DEST_APP) mkdir -m 755 -p $(DEST_APP)
mkdir -m 755 -p $(DEST_SHARE)/applications mkdir -m 755 -p $(DEST_SHARE)/applications
mkdir -m 755 -p $(DEST_SHARE)/applications/$(APP)
mkdir -m 755 -p $(DEST_APP)/images mkdir -m 755 -p $(DEST_APP)/images
mkdir -m 755 -p $(DEST_APP)/pyelliptic mkdir -m 755 -p $(DEST_APP)/pyelliptic
mkdir -m 755 -p $(DEST_APP)/socks mkdir -m 755 -p $(DEST_APP)/socks
@ -48,7 +48,7 @@ install: build clean
install -m 644 $(CURDIR)/src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt install -m 644 $(CURDIR)/src/bitmessageqt/*.py $(DEST_APP)/bitmessageqt
install -m 755 $(CURDIR)/debian/pybm $(DEST_MAIN)/pybitmessage install -m 755 $(CURDIR)/debian/pybm $(DEST_MAIN)/pybitmessage
install -m 644 $(CURDIR)/desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP)/$(APP).desktop install -m 644 $(CURDIR)/desktop/$(APP).desktop $(DEST_SHARE)/applications/$(APP).desktop
install -m 644 $(CURDIR)/src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png install -m 644 $(CURDIR)/src/images/can-icon-24px.png $(DEST_SHARE)/icons/hicolor/24x24/apps/$(APP).png
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/icons/hicolor/scalable/apps/$(APP).svg
install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg install -m 644 $(CURDIR)/desktop/can-icon.svg $(DEST_SHARE)/pixmaps/$(APP).svg

View File

@ -6,6 +6,9 @@ src/images/redicon.png
src/images/subscriptions.png src/images/subscriptions.png
src/images/blacklist.png src/images/blacklist.png
src/images/can-icon-24px.png src/images/can-icon-24px.png
src/images/can-icon-24px-red.png
src/images/can-icon-24px-yellow.png
src/images/can-icon-24px-green.png
src/images/identities.png src/images/identities.png
src/images/yellowicon.png src/images/yellowicon.png
src/images/inbox.png src/images/inbox.png

View File

@ -2,8 +2,29 @@
Type=Application Type=Application
Name=PyBitmessage Name=PyBitmessage
GenericName=PyBitmessage GenericName=PyBitmessage
X-GNOME-FullName=PyBitmessage Secure Messaging
Comment=Send encrypted messages to another person or to many subscribers Comment=Send encrypted messages to another person or to many subscribers
Exec=pybitmessage %U Exec=pybitmessage %U
Icon=pybitmessage Icon=pybitmessage
Terminal=false Terminal=false
Categories=Network Categories=Network;Email;Application
Keywords=Email;E-mail;Newsgroup;Messaging
X-MessagingMenu-UsesChatSection=true
X-Ubuntu-Gettext-Domain=pybitmessage
Actions=Send;Subscribe;AddressBook
[Desktop Action Send]
Name=Send
Exec=pybitmessage -s
OnlyShowIn=Unity;
[Desktop Action Subscribe]
Name=Subscribe
Exec=pybitmessage -b
OnlyShowIn=Unity;
[Desktop Action AddressBook]
Name=Address Book
Exec=pybitmessage -a
OnlyShowIn=Unity;

View File

@ -47,7 +47,7 @@ import signal #Used to capture a Ctrl-C keypress so that Bitmessage can shutdown
from SimpleXMLRPCServer import * from SimpleXMLRPCServer import *
import json import json
from subprocess import call #used when the API must execute an outside program from subprocess import call #used when the API must execute an outside program
import singleton
#For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers. #For each stream to which we connect, several outgoingSynSender threads will exist and will collectively create 8 connections with peers.
class outgoingSynSender(threading.Thread): class outgoingSynSender(threading.Thread):
@ -3810,6 +3810,9 @@ if useVeryEasyProofOfWorkForTesting:
shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000) shared.networkDefaultPayloadLengthExtraBytes = int(shared.networkDefaultPayloadLengthExtraBytes / 7000)
if __name__ == "__main__": if __name__ == "__main__":
# is the application already running? If yes then exit.
thisapp = singleton.singleinstance()
signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGINT, signal_handler)
#signal.signal(signal.SIGINT, signal.SIG_DFL) #signal.signal(signal.SIGINT, signal.SIG_DFL)
@ -3857,6 +3860,7 @@ if __name__ == "__main__":
shared.config.set('bitmessagesettings','messagesencrypted','false') shared.config.set('bitmessagesettings','messagesencrypted','false')
shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte',str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte',str(shared.networkDefaultProofOfWorkNonceTrialsPerByte))
shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes',str(shared.networkDefaultPayloadLengthExtraBytes)) shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes',str(shared.networkDefaultPayloadLengthExtraBytes))
shared.config.set('bitmessagesettings','minimizeonclose','true')
if storeConfigFilesInSameDirectoryAsProgramByDefault: if storeConfigFilesInSameDirectoryAsProgramByDefault:
#Just use the same directory as the program and forget about the appdata folder #Just use the same directory as the program and forget about the appdata folder

View File

@ -1,3 +1,4 @@
try: try:
from PyQt4.QtCore import * from PyQt4.QtCore import *
from PyQt4.QtGui import * from PyQt4.QtGui import *
@ -5,6 +6,15 @@ except Exception, err:
print 'PyBitmessage requires PyQt. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).' print 'PyBitmessage requires PyQt. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).'
print 'Error message:', err print 'Error message:', err
sys.exit() sys.exit()
withMessagingMenu = False
try:
from gi.repository import MessagingMenu
from gi.repository import Notify
withMessagingMenu = True
except ImportError:
MessagingMenu = None
from addresses import * from addresses import *
import shared import shared
from bitmessageui import * from bitmessageui import *
@ -22,8 +32,10 @@ import time
import os import os
from pyelliptic.openssl import OpenSSL from pyelliptic.openssl import OpenSSL
import pickle import pickle
import platform
class MyForm(QtGui.QMainWindow): class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent) QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow() self.ui = Ui_MainWindow()
@ -62,7 +74,7 @@ class MyForm(QtGui.QMainWindow):
traySignal = "activated(QSystemTrayIcon::ActivationReason)" traySignal = "activated(QSystemTrayIcon::ActivationReason)"
QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated) QtCore.QObject.connect(self.trayIcon, QtCore.SIGNAL(traySignal), self.__icon_activated)
menu = QtGui.QMenu() menu = QtGui.QMenu()
self.exitAction = menu.addAction("Exit", self.close) self.exitAction = menu.addAction("Quit", self.quit)
self.trayIcon.setContextMenu(menu) self.trayIcon.setContextMenu(menu)
#I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock. #I'm currently under the impression that Mac users have different expectations for the tray icon. They don't necessairly expect it to open the main window when clicked and they still expect a program showing a tray icon to also be in the dock.
if 'darwin' in sys.platform: if 'darwin' in sys.platform:
@ -71,7 +83,7 @@ class MyForm(QtGui.QMainWindow):
self.ui.labelSendBroadcastWarning.setVisible(False) self.ui.labelSendBroadcastWarning.setVisible(False)
#FILE MENU and other buttons #FILE MENU and other buttons
QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"), self.close) QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL("triggered()"), self.quit)
QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL("triggered()"), self.click_actionManageKeys) QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL("triggered()"), self.click_actionManageKeys)
QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses, QtCore.SIGNAL("triggered()"), self.click_actionRegenerateDeterministicAddresses) QtCore.QObject.connect(self.ui.actionRegenerateDeterministicAddresses, QtCore.SIGNAL("triggered()"), self.click_actionRegenerateDeterministicAddresses)
QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL("clicked()"), self.click_NewAddressDialog) QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL("clicked()"), self.click_NewAddressDialog)
@ -228,12 +240,13 @@ class MyForm(QtGui.QMainWindow):
shared.sqlSubmitQueue.put('') shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get() queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release() shared.sqlLock.release()
str_broadcast_subscribers = '[Broadcast subscribers]'
for row in queryreturn: for row in queryreturn:
msgid, toAddress, fromAddress, subject, received, message, read = row msgid, toAddress, fromAddress, subject, received, message, read = row
try: try:
if toAddress == '[Broadcast subscribers]': if toAddress == str_broadcast_subscribers:
toLabel = '[Broadcast subscribers]' toLabel = str_broadcast_subscribers
else: else:
toLabel = shared.config.get(toAddress, 'label') toLabel = shared.config.get(toAddress, 'label')
except: except:
@ -459,6 +472,27 @@ class MyForm(QtGui.QMainWindow):
#self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) #self.setWindowState(self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive)
#self.activateWindow() #self.activateWindow()
# pointer to the application
#app = None
# show the application window
def appIndicatorShow(self):
if self.actionShow == None:
return
if not self.actionShow.isChecked():
self.actionShow.setChecked(True)
self.appIndicatorShowOrHideWindow()
# unchecks the show item on the application indicator
def appIndicatorHide(self):
if self.actionShow == None:
return
if self.actionShow.isChecked():
self.actionShow.setChecked(False)
self.appIndicatorShowOrHideWindow()
# application indicator show or hide
"""# application indicator show or hide """# application indicator show or hide
def appIndicatorShowBitmessage(self): def appIndicatorShowBitmessage(self):
#if self.actionShow == None: #if self.actionShow == None:
@ -470,33 +504,53 @@ class MyForm(QtGui.QMainWindow):
else: else:
self.appIndicatorShowOrHideWindow()""" self.appIndicatorShowOrHideWindow()"""
# returns the index of the oldest unread message
def getUnreadMessageIndex(self):
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''SELECT msgid, received, read FROM inbox where folder='inbox' ORDER BY received DESC ''')
shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
i = 0
index = 0
for row in queryreturn:
msgid, received, read = row
if not read:
index = i
i = i + 1
return index
# Show the program window and select inbox tab
def appIndicatorInbox(self, mm_app, source_id):
self.appIndicatorShow()
# select inbox
self.ui.tabWidget.setCurrentIndex(0)
# select unread message
self.ui.tableWidgetInbox.selectRow(self.getUnreadMessageIndex())
self.tableWidgetInboxItemClicked()
# Show the program window and select send tab # Show the program window and select send tab
def appIndicatorSend(self): def appIndicatorSend(self):
if not self.actionShow.isChecked(): self.appIndicatorShow()
self.actionShow.setChecked(True)
self.appIndicatorShowOrHideWindow()
self.ui.tabWidget.setCurrentIndex(1) self.ui.tabWidget.setCurrentIndex(1)
# Show the program window and select subscriptions tab # Show the program window and select subscriptions tab
def appIndicatorSubscribe(self): def appIndicatorSubscribe(self):
if not self.actionShow.isChecked(): self.appIndicatorShow()
self.actionShow.setChecked(True)
self.appIndicatorShowOrHideWindow()
self.ui.tabWidget.setCurrentIndex(4) self.ui.tabWidget.setCurrentIndex(4)
# Show the program window and select the address book tab # Show the program window and select the address book tab
def appIndicatorAddressBook(self): def appIndicatorAddressBook(self):
if not self.actionShow.isChecked(): self.appIndicatorShow()
self.actionShow.setChecked(True)
self.appIndicatorShowOrHideWindow()
self.ui.tabWidget.setCurrentIndex(5) self.ui.tabWidget.setCurrentIndex(5)
# create application indicator # create application indicator
def createAppIndicator(self,app): def appIndicatorInit(self,app):
self.tray = QSystemTrayIcon(QtGui.QIcon("images/can-icon-24px.png"), app) self.tray = QSystemTrayIcon(QtGui.QIcon("images/can-icon-24px-red.png"), app)
if sys.platform[0:3] == 'win': if sys.platform[0:3] == 'win':
traySignal = "activated(QSystemTrayIcon::ActivationReason)" traySignal = "activated(QSystemTrayIcon::ActivationReason)"
QtCore.QObject.connect(self.tray, QtCore.SIGNAL(traySignal), self.__icon_activated) QtCore.QObject.connect(self.tray, QtCore.SIGNAL(traySignal), self.__icon_activated)
m = QMenu() m = QMenu()
self.actionStatus = QtGui.QAction('Not Connected',m,checkable=False) self.actionStatus = QtGui.QAction('Not Connected',m,checkable=False)
@ -509,7 +563,7 @@ class MyForm(QtGui.QMainWindow):
# show bitmessage # show bitmessage
self.actionShow = QtGui.QAction('Show Bitmessage',m,checkable=True) self.actionShow = QtGui.QAction('Show Bitmessage',m,checkable=True)
self.actionShow.setChecked(True) self.actionShow.setChecked(not shared.config.getboolean('bitmessagesettings', 'startintray'))
self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow) self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow)
if not sys.platform[0:3] == 'win': if not sys.platform[0:3] == 'win':
m.addAction(self.actionShow) m.addAction(self.actionShow)
@ -535,15 +589,133 @@ class MyForm(QtGui.QMainWindow):
m.addAction(actionSeparator) m.addAction(actionSeparator)
# Quit # Quit
m.addAction("Quit", self.close) m.addAction("Quit", self.quit)
self.tray.setContextMenu(m) self.tray.setContextMenu(m)
self.tray.show() self.tray.show()
if shared.config.getboolean('bitmessagesettings', 'startintray'):
#myapp.trayIcon.show()#This option seems to have been obsoleted by https://github.com/Bitmessage/PyBitmessage/pull/133/files # Ubuntu Messaging menu object
self.actionShow.setChecked(False) mmapp = None
self.appIndicatorShowOrHideWindow()
#if sys.platform[0:3] == 'win': # is the operating system Ubuntu?
# myapp.setWindowFlags(Qt.ToolTip) def isUbuntu(self):
for entry in platform.uname():
if "Ubuntu" in entry:
return True
return False
# returns the number of unread messages and subscriptions
def getUnread(self):
str_broadcast_subscribers = '[Broadcast subscribers]'
unreadMessages = 0
unreadSubscriptions = 0
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''SELECT msgid, toaddress, read FROM inbox where folder='inbox' ''')
shared.sqlSubmitQueue.put('')
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
for row in queryreturn:
msgid, toAddress, read = row
try:
if toAddress == str_broadcast_subscribers:
toLabel = str_broadcast_subscribers
else:
toLabel = shared.config.get(toAddress, 'label')
except:
toLabel = ''
if toLabel == '':
toLabel = toAddress
if not read:
if toLabel == str_broadcast_subscribers:
# increment the unread subscriptions
unreadSubscriptions = unreadSubscriptions + 1
else:
# increment the unread messages
unreadMessages = unreadMessages + 1
return unreadMessages, unreadSubscriptions
# show the number of unread messages and subscriptions on the messaging menu
def ubuntuMessagingMenuUnread(self, drawAttention):
unreadMessages, unreadSubscriptions = self.getUnread()
# unread messages
if unreadMessages > 0:
self.mmapp.append_source("Messages", None, "Messages (" + str(unreadMessages) + ")")
if drawAttention:
self.mmapp.draw_attention("Messages")
# unread subscriptions
if unreadSubscriptions > 0:
self.mmapp.append_source("Subscriptions", None, "Subscriptions (" + str(unreadSubscriptions) + ")")
if drawAttention:
self.mmapp.draw_attention("Subscriptions")
# initialise the Ubuntu messaging menu
def ubuntuMessagingMenuInit(self):
global withMessagingMenu
# if this isn't ubuntu then don't do anything
if not self.isUbuntu():
return
# has messageing menu been installed
if not withMessagingMenu:
print 'WARNING: MessagingMenu is not available. Is libmessaging-menu-dev installed?'
return
# create the menu server
if withMessagingMenu:
try:
self.mmapp = MessagingMenu.App(desktop_id='pybitmessage.desktop')
self.mmapp.register()
self.mmapp.connect('activate-source', self.appIndicatorInbox)
self.ubuntuMessagingMenuUnread(True)
except Exception:
withMessagingMenu = False
print 'WARNING: messaging menu disabled'
# update the Ubuntu messaging menu
def ubuntuMessagingMenuUpdate(self, drawAttention):
global withMessagingMenu
# if this isn't ubuntu then don't do anything
if not self.isUbuntu():
return
# has messageing menu been installed
if not withMessagingMenu:
print 'WARNING: messaging menu disabled or libmessaging-menu-dev not installed'
return
# Remove previous messages and subscriptions entries, then recreate them
# There might be a better way to do it than this
if self.mmapp.has_source("Messages"):
self.mmapp.remove_source("Messages")
if self.mmapp.has_source("Subscriptions"):
self.mmapp.remove_source("Subscriptions")
# update the menu entries
self.ubuntuMessagingMenuUnread(drawAttention)
# initialise the message notifier
def notifierInit(self):
global withMessagingMenu
if withMessagingMenu:
Notify.init('pybitmessage')
# shows a notification
def notifierShow(self, title, subtitle):
global withMessagingMenu
if withMessagingMenu:
n = Notify.Notification.new(title, subtitle,'notification-message-email')
n.show()
return
# Show with tray
self.trayIcon.showMessage(title, subtitle, 1, 2000)
def tableWidgetInboxKeyPressEvent(self,event): def tableWidgetInboxKeyPressEvent(self,event):
if event.key() == QtCore.Qt.Key_Delete: if event.key() == QtCore.Qt.Key_Delete:
@ -598,10 +770,7 @@ class MyForm(QtGui.QMainWindow):
if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform:
if event.type() == QtCore.QEvent.WindowStateChange: if event.type() == QtCore.QEvent.WindowStateChange:
if self.windowState() & QtCore.Qt.WindowMinimized: if self.windowState() & QtCore.Qt.WindowMinimized:
self.hide() self.appIndicatorHide()
#self.trayIcon.show() #This may have been obsoleted by https://github.com/Bitmessage/PyBitmessage/issues/135
#self.hidden = True
if 'win32' in sys.platform or 'win64' in sys.platform: if 'win32' in sys.platform or 'win64' in sys.platform:
self.setWindowFlags(Qt.ToolTip) self.setWindowFlags(Qt.ToolTip)
elif event.oldState() & QtCore.Qt.WindowMinimized: elif event.oldState() & QtCore.Qt.WindowMinimized:
@ -688,27 +857,47 @@ class MyForm(QtGui.QMainWindow):
elif len(shared.connectedHostsList) == 0: elif len(shared.connectedHostsList) == 0:
self.setStatusIcon('red') self.setStatusIcon('red')
# Indicates whether or not there is a connection to the Bitmessage network
connected = False
def setStatusIcon(self,color): def setStatusIcon(self,color):
global withMessagingMenu
#print 'setting status icon color' #print 'setting status icon color'
if color == 'red': if color == 'red':
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/redicon.png")) self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/redicon.png"))
shared.statusIconColor = 'red' shared.statusIconColor = 'red'
#if self.actionStatus != None: # if the connection is lost then show a notification
self.actionStatus.setText('Not Connected') if self.connected:
self.notifierShow('PyBitmessage','Connection lost')
self.connected = False
if self.actionStatus != None:
self.actionStatus.setText('Not Connected')
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-red.png"))
self.trayIcon.show()
if color == 'yellow': if color == 'yellow':
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
self.statusBar().showMessage('') self.statusBar().showMessage('')
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png"))
shared.statusIconColor = 'yellow' shared.statusIconColor = 'yellow'
#if self.actionStatus != None: # if a new connection has been established then show a notification
self.actionStatus.setText('Connected') if not self.connected:
self.notifierShow('PyBitmessage','Connected')
self.connected = True
if self.actionStatus != None:
self.actionStatus.setText('Connected')
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-yellow.png"))
if color == 'green': if color == 'green':
if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.':
self.statusBar().showMessage('') self.statusBar().showMessage('')
self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/greenicon.png")) self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/greenicon.png"))
shared.statusIconColor = 'green' shared.statusIconColor = 'green'
#if self.actionStatus != None: self.connected = True
self.actionStatus.setText('Connected')
if self.actionStatus != None:
self.actionStatus.setText('Connected')
self.tray.setIcon(QtGui.QIcon("images/can-icon-24px-green.png"))
def updateSentItemStatusByHash(self,toRipe,textToDisplay): def updateSentItemStatusByHash(self,toRipe,textToDisplay):
for i in range(self.ui.tableWidgetSent.rowCount()): for i in range(self.ui.tableWidgetSent.rowCount()):
@ -1072,11 +1261,11 @@ class MyForm(QtGui.QMainWindow):
if fromLabel == '': if fromLabel == '':
newItem = QtGui.QTableWidgetItem(unicode(fromAddress,'utf-8')) newItem = QtGui.QTableWidgetItem(unicode(fromAddress,'utf-8'))
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
self.trayIcon.showMessage('New Message', 'New message from '+ fromAddress, 1, 2000) self.notifierShow('New Message', 'From '+ fromAddress)
else: else:
newItem = QtGui.QTableWidgetItem(unicode(fromLabel,'utf-8')) newItem = QtGui.QTableWidgetItem(unicode(fromLabel,'utf-8'))
if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'):
self.trayIcon.showMessage('New Message', 'New message from '+fromLabel, 1, 2000) self.notifierShow('New Message', 'From ' + fromLabel)
newItem.setData(Qt.UserRole,str(fromAddress)) newItem.setData(Qt.UserRole,str(fromAddress))
newItem.setFont(font) newItem.setFont(font)
self.ui.tableWidgetInbox.setItem(0,1,newItem) self.ui.tableWidgetInbox.setItem(0,1,newItem)
@ -1084,7 +1273,7 @@ class MyForm(QtGui.QMainWindow):
newItem.setData(Qt.UserRole,unicode(message,'utf-8)')) newItem.setData(Qt.UserRole,unicode(message,'utf-8)'))
newItem.setFont(font) newItem.setFont(font)
self.ui.tableWidgetInbox.setItem(0,2,newItem) self.ui.tableWidgetInbox.setItem(0,2,newItem)
newItem = myTableWidgetItem(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8')) newItem = myTableWidgetItem(unicode(strftime(shared.config.get('bitmessagesettings', 'timeformat'),localtime(int(time.time()))),'utf-8'))
newItem.setData(Qt.UserRole,QByteArray(inventoryHash)) newItem.setData(Qt.UserRole,QByteArray(inventoryHash))
newItem.setData(33,int(time.time())) newItem.setData(33,int(time.time()))
newItem.setFont(font) newItem.setFont(font)
@ -1096,6 +1285,7 @@ class MyForm(QtGui.QMainWindow):
else: else:
self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(0,2).data(Qt.UserRole).toPyObject())""" self.ui.textEditInboxMessage.setPlainText(self.ui.tableWidgetInbox.item(0,2).data(Qt.UserRole).toPyObject())"""
self.ui.tableWidgetInbox.setSortingEnabled(True) self.ui.tableWidgetInbox.setSortingEnabled(True)
self.ubuntuMessagingMenuUpdate(True)
def click_pushButtonAddAddressBook(self): def click_pushButtonAddAddressBook(self):
self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self) self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self)
@ -1400,25 +1590,43 @@ class MyForm(QtGui.QMainWindow):
else: else:
print 'new address dialog box rejected' print 'new address dialog box rejected'
def closeEvent(self, event):
# Quit selected from menu or application indicator
def quit(self):
'''quit_msg = "Are you sure you want to exit Bitmessage?" '''quit_msg = "Are you sure you want to exit Bitmessage?"
reply = QtGui.QMessageBox.question(self, 'Message', reply = QtGui.QMessageBox.question(self, 'Message',
quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
if reply == QtGui.QMessageBox.Yes: if reply is QtGui.QMessageBox.No:
event.accept() return
else: '''
event.ignore()'''
shared.doCleanShutdown() shared.doCleanShutdown()
#self.trayIcon.hide()
self.tray.hide() self.tray.hide()
# unregister the messaging system
if self.mmapp is not None:
self.mmapp.unregister()
self.trayIcon.hide()
self.statusBar().showMessage('All done. Closing user interface...') self.statusBar().showMessage('All done. Closing user interface...')
event.accept()
shared.printLock.acquire()
print 'Done. (passed event.accept())'
shared.printLock.release()
os._exit(0) os._exit(0)
# window close event
def closeEvent(self, event):
self.appIndicatorHide()
minimizeonclose = False
try:
minimizeonclose = shared.config.getboolean('bitmessagesettings', 'minimizeonclose')
except Exception:
pass
if minimizeonclose:
# minimize the application
event.ignore()
else:
# quit the application
event.accept()
self.quit()
def on_action_InboxMessageForceHtml(self): def on_action_InboxMessageForceHtml(self):
currentInboxRow = self.ui.tableWidgetInbox.currentRow() currentInboxRow = self.ui.tableWidgetInbox.currentRow()
lines = self.ui.tableWidgetInbox.item(currentInboxRow,2).data(Qt.UserRole).toPyObject().split('\n') lines = self.ui.tableWidgetInbox.item(currentInboxRow,2).data(Qt.UserRole).toPyObject().split('\n')
@ -2045,12 +2253,21 @@ class UISignaler(QThread):
else: else:
sys.stderr.write('Command sent to UISignaler not recognized: %s\n' % command) sys.stderr.write('Command sent to UISignaler not recognized: %s\n' % command)
def run(): def run():
app = QtGui.QApplication(sys.argv) app = QtGui.QApplication(sys.argv)
app.setStyleSheet("QStatusBar::item { border: 0px solid black }") app.setStyleSheet("QStatusBar::item { border: 0px solid black }")
myapp = MyForm() myapp = MyForm()
if not shared.config.getboolean('bitmessagesettings', 'startintray'):
if shared.config.getboolean('bitmessagesettings', 'startintray'):
if not myapp.isUbuntu():
myapp.trayIcon.show()
if 'win32' in sys.platform or 'win64' in sys.platform:
myapp.setWindowFlags(Qt.ToolTip)
else:
myapp.show() myapp.show()
myapp.createAppIndicator(app)
myapp.appIndicatorInit(app)
myapp.ubuntuMessagingMenuInit()
myapp.notifierInit()
sys.exit(app.exec_()) sys.exit(app.exec_())

View File

@ -515,7 +515,7 @@ class Ui_MainWindow(object):
self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8)) self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
self.actionImport_keys.setText(QtGui.QApplication.translate("MainWindow", "Import keys", None, QtGui.QApplication.UnicodeUTF8)) self.actionImport_keys.setText(QtGui.QApplication.translate("MainWindow", "Import keys", None, QtGui.QApplication.UnicodeUTF8))
self.actionManageKeys.setText(QtGui.QApplication.translate("MainWindow", "Manage keys", None, QtGui.QApplication.UnicodeUTF8)) self.actionManageKeys.setText(QtGui.QApplication.translate("MainWindow", "Manage keys", None, QtGui.QApplication.UnicodeUTF8))
self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Exit", None, QtGui.QApplication.UnicodeUTF8)) self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Quit", None, QtGui.QApplication.UnicodeUTF8))
self.actionHelp.setText(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8)) self.actionHelp.setText(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8)) self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8))
self.actionSettings.setText(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8)) self.actionSettings.setText(QtGui.QApplication.translate("MainWindow", "Settings", None, QtGui.QApplication.UnicodeUTF8))

View File

@ -979,7 +979,7 @@ p, li { white-space: pre-wrap; }
</action> </action>
<action name="actionExit"> <action name="actionExit">
<property name="text"> <property name="text">
<string>Exit</string> <string>Quit</string>
</property> </property>
</action> </action>
<action name="actionHelp"> <action name="actionHelp">

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 872 B

61
src/singleton.py Normal file
View File

@ -0,0 +1,61 @@
#! /usr/bin/env python
import sys
import os
import errno
import tempfile
from multiprocessing import Process
class singleinstance:
"""
Implements a single instance application by creating a lock file based on the full path to the script file.
This is based upon the singleton class from tendo https://github.com/pycontribs/tendo
which is under the Python Software Foundation License version 2
"""
def __init__(self, flavor_id=""):
import sys
self.initialized = False
basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock'
self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename)
if sys.platform == 'win32':
try:
# file already exists, we try to remove (in case previous execution was interrupted)
if os.path.exists(self.lockfile):
os.unlink(self.lockfile)
self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR)
except OSError:
type, e, tb = sys.exc_info()
if e.errno == 13:
print 'Another instance of this application is already running'
sys.exit(-1)
print(e.errno)
raise
else: # non Windows
import fcntl
self.fp = open(self.lockfile, 'w')
try:
fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
print 'Another instance of this application is already running'
sys.exit(-1)
self.initialized = True
def __del__(self):
import sys
if not self.initialized:
return
try:
if sys.platform == 'win32':
if hasattr(self, 'fd'):
os.close(self.fd)
os.unlink(self.lockfile)
else:
import fcntl
fcntl.lockf(self.fp, fcntl.LOCK_UN)
if os.path.isfile(self.lockfile):
os.unlink(self.lockfile)
except Exception, e:
sys.exit(-1)