├── .gitignore ├── COPYING ├── INSTALL.md ├── LICENSE ├── Makefile ├── README.md ├── arch.sh ├── archpackage └── PKGBUILD ├── compiletest.py ├── configure ├── debian.sh ├── debian ├── changelog ├── compat ├── control ├── copyright ├── docs ├── manpages ├── pybm ├── rules └── source │ ├── format │ └── include-binaries ├── desktop ├── can-icon.svg ├── icon14.xpm ├── icon24.png └── pybitmessage.desktop ├── ebuild.sh ├── generate.sh ├── man └── pybitmessage.1.gz ├── osx.sh ├── puppy.sh ├── puppypackage ├── icon14.xpm └── pybitmessage-0.3.5.pet.specs ├── pyinstaller └── bitmessagemain.spec ├── rpm.sh ├── rpmpackage └── pybitmessage.spec ├── slack.sh ├── slackpackage ├── doinst.sh └── slack-desc └── src ├── addresses.py ├── api.py ├── api_client.py ├── bitmessagecli.py ├── bitmessagecurses └── __init__.py ├── bitmessagemain.py ├── bitmessageqt ├── __init__.py ├── about.py ├── about.ui ├── account.py ├── addaddressdialog.py ├── addaddressdialog.ui ├── addpeer.ui ├── bitmessage_icons.qrc ├── bitmessage_icons_rc.py ├── bitmessageui.py ├── bitmessageui.ui ├── blacklist.py ├── blacklist.ui ├── connect.py ├── connect.ui ├── dialogs.py ├── emailgateway.py ├── emailgateway.ui ├── foldertree.py ├── help.py ├── help.ui ├── iconglossary.py ├── iconglossary.ui ├── languagebox.py ├── messagecompose.py ├── messageview.py ├── migrationwizard.py ├── networkstatus.py ├── networkstatus.ui ├── newaddressdialog.py ├── newaddressdialog.ui ├── newaddresswizard.py ├── newchandialog.py ├── newchandialog.ui ├── newsubscriptiondialog.py ├── newsubscriptiondialog.ui ├── regenerateaddresses.py ├── regenerateaddresses.ui ├── retranslateui.py ├── safehtmlparser.py ├── settings.py ├── settings.ui ├── settingsmixin.py ├── specialaddressbehavior.py ├── specialaddressbehavior.ui ├── support.py ├── uisignaler.py ├── utils.py ├── wanlan.ui └── widgets.py ├── bitmsghash ├── Makefile ├── bitmsghash.cl └── bitmsghash.cpp ├── build_osx.py ├── class_addressGenerator.py ├── class_objectHashHolder.py ├── class_objectProcessor.py ├── class_objectProcessorQueue.py ├── class_outgoingSynSender.py ├── class_receiveDataThread.py ├── class_sendDataThread.py ├── class_singleCleaner.py ├── class_singleListener.py ├── class_singleWorker.py ├── class_sqlThread.py ├── debug.py ├── defaultKnownNodes.py ├── depends.py ├── helper_bitcoin.py ├── helper_bootstrap.py ├── helper_generic.py ├── helper_inbox.py ├── helper_search.py ├── helper_sent.py ├── helper_sql.py ├── helper_startup.py ├── helper_threading.py ├── highlevelcrypto.py ├── images ├── addressbook.png ├── bitmessage.icns ├── blacklist.png ├── can-icon-16px.png ├── can-icon-24px-green.png ├── can-icon-24px-red.png ├── can-icon-24px-yellow.png ├── can-icon-24px.png ├── can-icon.ico ├── greenicon.png ├── identities.png ├── inbox.png ├── networkstatus.png ├── no_identicons.png ├── qidenticon.png ├── qidenticon_two.png ├── qidenticon_two_x.png ├── qidenticon_x.png ├── redicon.png ├── send.png ├── sent.png ├── subscriptions.png └── yellowicon.png ├── l10n.py ├── message_data_reader.py ├── namecoin.py ├── openclpow.py ├── proofofwork.py ├── protocol.py ├── pyelliptic ├── LICENSE ├── README.md ├── __init__.py ├── arithmetic.py ├── cipher.py ├── ecc.py ├── hash.py └── openssl.py ├── qidenticon.py ├── shared.py ├── singleton.py ├── socks ├── BUGS ├── LICENSE ├── README └── __init__.py ├── sslkeys ├── cert.pem └── key.pem ├── tr.py ├── translations ├── bitmessage.pro ├── bitmessage_ar.qm ├── bitmessage_ar.ts ├── bitmessage_cs.qm ├── bitmessage_cs.ts ├── bitmessage_da.qm ├── bitmessage_da.ts ├── bitmessage_de.qm ├── bitmessage_de.ts ├── bitmessage_en.qm ├── bitmessage_en.ts ├── bitmessage_en_pirate.qm ├── bitmessage_en_pirate.ts ├── bitmessage_eo.qm ├── bitmessage_eo.ts ├── bitmessage_fr.qm ├── bitmessage_fr.ts ├── bitmessage_it.qm ├── bitmessage_it.ts ├── bitmessage_ja.qm ├── bitmessage_ja.ts ├── bitmessage_nb.ts ├── bitmessage_nl.qm ├── bitmessage_nl.ts ├── bitmessage_no.qm ├── bitmessage_no.ts ├── bitmessage_pl.ts ├── bitmessage_pt.ts ├── bitmessage_ru.qm ├── bitmessage_ru.ts ├── bitmessage_sk.qm ├── bitmessage_sk.ts ├── bitmessage_sv.ts ├── bitmessage_zh_cn.qm └── bitmessage_zh_cn.ts └── upnp.py /.gitignore: -------------------------------------------------------------------------------- 1 | **pyc 2 | **dat 3 | **.DS_Store 4 | src/build 5 | src/dist 6 | src/.project 7 | src/.pydevproject 8 | src/.settings/ 9 | *.dll -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2016 Jonathan Warren 2 | Copyright (c) 2013-2016 The Bitmessage Developers 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | #PyBitmessage Installation Instructions 2 | 3 | For an up-to-date version of these instructions, please visit the 4 | [Bitmessage Wiki](https://bitmessage.org/wiki/Compiling_instructions). 5 | 6 | PyBitmessage can be run either straight from source or from an installed 7 | package. 8 | 9 | ##Dependencies 10 | Before running PyBitmessage, make sure you have all the necessary dependencies 11 | installed on your system. 12 | 13 | Here's a list of dependencies needed for PyBitmessage 14 | - python2.7 15 | - python2-qt4 (python-qt4 on Debian/Ubuntu) 16 | - openssl 17 | - (Fedora & Redhat only) openssl-compat-bitcoin-libs 18 | 19 | ##Running PyBitmessage 20 | PyBitmessage can be run two ways: straight from source or via a package which 21 | is installed on your system. Since PyBitmessage is Beta, it is best to run 22 | PyBitmessage from source, so that you may update as needed. 23 | 24 | ####Updating 25 | To update PyBitmessage from source (Linux/OS X), you can do these easy steps: 26 | ``` 27 | cd PyBitmessage/src/ 28 | git fetch --all 29 | git reset --hard origin/master 30 | python bitmessagemain.py 31 | ``` 32 | Voilà! Bitmessage is updated! 33 | 34 | ####Linux 35 | To run PyBitmessage from the command-line, you must download the source, then 36 | run `src/bitmessagemain.py`. 37 | ``` 38 | git clone git://github.com/Bitmessage/PyBitmessage.git 39 | cd PyBitmessage/ && python src/bitmessagemain.py 40 | ``` 41 | 42 | That's it! *Honestly*! 43 | 44 | ####Windows 45 | On Windows you can download an executable for Bitmessage 46 | [here](https://bitmessage.org/download/windows/Bitmessage.exe). 47 | 48 | However, if you would like to run PyBitmessage via Python in Windows, you can 49 | go [here](https://bitmessage.org/wiki/Compiling_instructions#Windows) for 50 | information on how to do so. 51 | 52 | ####OS X 53 | First off, install Homebrew. 54 | ``` 55 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 56 | ``` 57 | 58 | Now, install the required dependencies 59 | ``` 60 | brew install git python pyqt 61 | ``` 62 | 63 | Download and run PyBitmessage: 64 | ``` 65 | git clone git://github.com/Bitmessage/PyBitmessage.git 66 | cd PyBitmessage && python src/bitmessagemain.py 67 | ``` 68 | 69 | ##Creating a package for installation 70 | If you really want, you can make a package for PyBitmessage, which you may 71 | install yourself or distribute to friends. This isn't recommended, since 72 | PyBitmessage is in Beta, and subject to frequent change. 73 | 74 | ####Linux 75 | 76 | First off, since PyBitmessage uses something nifty called 77 | [packagemonkey](https://github.com/fuzzgun/packagemonkey), go ahead and get 78 | that installed. You may have to build it from source. 79 | 80 | Next, edit the generate.sh script to your liking. 81 | 82 | Now, run the appropriate script for the type of package you'd like to make 83 | ``` 84 | arch.sh - create a package for Arch Linux 85 | debian.sh - create a package for Debian/Ubuntu 86 | ebuild.sh - create a package for Gentoo 87 | osx.sh - create a package for OS X 88 | puppy.sh - create a package for Puppy Linux 89 | rpm.sh - create a RPM package 90 | slack.sh - create a package for Slackware 91 | ``` 92 | 93 | ####OS X 94 | Please refer to 95 | [this page](https://bitmessage.org/forum/index.php/topic,2761.0.html) on the 96 | forums for instructions on how to create a package on OS X. 97 | 98 | Please note that some versions of OS X don't work. 99 | ###Windows 100 | #TODO: Create Windows package creation instructions 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2012-2016 Jonathan Warren 3 | Copyright (c) 2013-2016 The Bitmessage Developers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APP=pybitmessage 2 | VERSION=0.4.4 3 | RELEASE=1 4 | ARCH_TYPE=`uname -m` 5 | PREFIX?=/usr/local 6 | LIBDIR=lib 7 | 8 | all: 9 | debug: 10 | source: 11 | tar -cvf ../${APP}_${VERSION}.orig.tar ../${APP}-${VERSION} --exclude-vcs 12 | gzip -f9n ../${APP}_${VERSION}.orig.tar 13 | install: 14 | mkdir -p ${DESTDIR}/usr 15 | mkdir -p ${DESTDIR}${PREFIX} 16 | mkdir -p ${DESTDIR}${PREFIX}/bin 17 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share 18 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/man 19 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/man/man1 20 | install -m 644 man/${APP}.1.gz ${DESTDIR}${PREFIX}/share/man/man1 21 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/${APP} 22 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/applications 23 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/pixmaps 24 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons 25 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons/hicolor 26 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons/hicolor/scalable 27 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons/hicolor/scalable/apps 28 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons/hicolor/24x24 29 | mkdir -m 755 -p ${DESTDIR}${PREFIX}/share/icons/hicolor/24x24/apps 30 | install -m 644 desktop/${APP}.desktop ${DESTDIR}${PREFIX}/share/applications/${APP}.desktop 31 | install -m 644 desktop/icon24.png ${DESTDIR}${PREFIX}/share/icons/hicolor/24x24/apps/${APP}.png 32 | cp -rf src/* ${DESTDIR}${PREFIX}/share/${APP} 33 | echo '#!/bin/sh' > ${DESTDIR}${PREFIX}/bin/${APP} 34 | echo "if [ -d ${PREFIX}/share/${APP} ]; then" >> ${DESTDIR}${PREFIX}/bin/${APP} 35 | echo " cd ${PREFIX}/share/${APP}" >> ${DESTDIR}${PREFIX}/bin/${APP} 36 | echo 'else' >> ${DESTDIR}${PREFIX}/bin/${APP} 37 | echo " cd /usr/share/pybitmessage" >> ${DESTDIR}${PREFIX}/bin/${APP} 38 | echo 'fi' >> ${DESTDIR}${PREFIX}/bin/${APP} 39 | echo 'if [ -d /opt/openssl-compat-bitcoin/lib ]; then' >> ${DESTDIR}${PREFIX}/bin/${APP} 40 | echo ' LD_LIBRARY_PATH="/opt/openssl-compat-bitcoin/lib/" exec python2 bitmessagemain.py' >> ${DESTDIR}${PREFIX}/bin/${APP} 41 | echo 'else' >> ${DESTDIR}${PREFIX}/bin/${APP} 42 | echo ' exec python2 bitmessagemain.py' >> ${DESTDIR}${PREFIX}/bin/${APP} 43 | echo 'fi' >> ${DESTDIR}${PREFIX}/bin/${APP} 44 | chmod +x ${DESTDIR}${PREFIX}/bin/${APP} 45 | uninstall: 46 | rm -f ${PREFIX}/share/man/man1/${APP}.1.gz 47 | rm -rf ${PREFIX}/share/${APP} 48 | rm -f ${PREFIX}/bin/${APP} 49 | rm -f ${PREFIX}/share/applications/${APP}.desktop 50 | rm -f ${PREFIX}/share/icons/hicolor/scalable/apps/${APP}.svg 51 | rm -f ${PREFIX}/share/pixmaps/${APP}.svg 52 | clean: 53 | rm -f ${APP} \#* \.#* gnuplot* *.png debian/*.substvars debian/*.log 54 | rm -fr deb.* debian/${APP} rpmpackage/${ARCH_TYPE} 55 | rm -f ../${APP}*.deb ../${APP}*.changes ../${APP}*.asc ../${APP}*.dsc 56 | rm -f rpmpackage/*.src.rpm archpackage/*.gz archpackage/*.xz 57 | rm -f puppypackage/*.gz puppypackage/*.pet slackpackage/*.txz 58 | 59 | sourcedeb: 60 | tar -cvf ../${APP}_${VERSION}.orig.tar ../${APP}-${VERSION} --exclude-vcs --exclude 'debian' 61 | gzip -f9n ../${APP}_${VERSION}.orig.tar 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PyBitmessage 2 | ============ 3 | 4 | Bitmessage is a P2P communications protocol used to send encrypted messages to 5 | another person or to many subscribers. It is decentralized and trustless, 6 | meaning that you need-not inherently trust any entities like root certificate 7 | authorities. It uses strong authentication, which means that the sender of a 8 | message cannot be spoofed, and it aims to hide "non-content" data, like the 9 | sender and receiver of messages, from passive eavesdroppers like those running 10 | warrantless wiretapping programs. 11 | 12 | 13 | Development 14 | ---------- 15 | Bitmessage is a collaborative project. You are welcome to submit pull requests 16 | although if you plan to put a non-trivial amount of work into coding new 17 | features, it is recommended that you first solicit feedback on the DevTalk 18 | pseudo-mailing list: 19 | BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh 20 | 21 | 22 | This fork 23 | --------- 24 | 25 | The purpose of this fork is to add features for server deployment for a 26 | bitmessage/email gateway. It contains merged support for OpenCL PoW and a 27 | couple of new/modified API calls. 28 | 29 | 30 | References 31 | ---------- 32 | * [Project Website](https://bitmessage.org) 33 | * [Protocol Specification](https://bitmessage.org/wiki/Protocol_specification) 34 | * [Whitepaper](https://bitmessage.org/bitmessage.pdf) 35 | * [Installation](https://bitmessage.org/wiki/Compiling_instructions) 36 | -------------------------------------------------------------------------------- /arch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.4 5 | VERSION=0.4.4 6 | RELEASE=1 7 | ARCH_TYPE=any 8 | CURRDIR=`pwd` 9 | SOURCE=archpackage/${APP}-${VERSION}.tar.gz 10 | 11 | # Update version numbers automatically - so you don't have to 12 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile debian.sh rpm.sh puppy.sh ebuild.sh slack.sh 13 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 14 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 15 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 16 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 17 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 18 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 19 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 20 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 21 | 22 | 23 | # Create the source code 24 | make clean 25 | rm -f archpackage/*.gz 26 | 27 | # having the root directory called name-version seems essential 28 | mv ../${APP} ../${APP}-${VERSION} 29 | tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs 30 | 31 | # rename the root directory without the version number 32 | mv ../${APP}-${VERSION} ../${APP} 33 | 34 | # calculate the MD5 checksum 35 | CHECKSM=$(md5sum ${SOURCE}) 36 | sed -i "s/md5sums[^)]*)/md5sums=(${CHECKSM%% *})/g" archpackage/PKGBUILD 37 | 38 | cd archpackage 39 | 40 | # Create the package 41 | tar -c -f ${APP}-${VERSION}.pkg.tar . 42 | sync 43 | xz ${APP}-${VERSION}.pkg.tar 44 | sync 45 | 46 | # Move back to the original directory 47 | cd ${CURRDIR} 48 | 49 | -------------------------------------------------------------------------------- /archpackage/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Bob Mottram (4096 bits) 2 | pkgname=pybitmessage 3 | pkgver=0.4.4 4 | pkgrel=1 5 | pkgdesc="Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide "non-content" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs." 6 | arch=('any') 7 | url="https://github.com/Bitmessage/PyBitmessage" 8 | license=('MIT') 9 | groups=() 10 | depends=('python2' 'qt4' 'python2-pyqt4' 'sqlite' 'openssl' 'mpg123') 11 | makedepends=() 12 | optdepends=('python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency') 13 | provides=() 14 | conflicts=() 15 | replaces=() 16 | backup=() 17 | options=() 18 | install= 19 | changelog= 20 | source=($pkgname-$pkgver.tar.gz) 21 | noextract=() 22 | md5sums=() 23 | build() { 24 | cd "$srcdir/$pkgname-$pkgver" 25 | ./configure --prefix=/usr 26 | make 27 | } 28 | package() { 29 | cd "$srcdir/$pkgname-$pkgver" 30 | make DESTDIR="$pkgdir/" PREFIX="/usr" install 31 | } 32 | -------------------------------------------------------------------------------- /compiletest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | import ctypes 4 | import fnmatch 5 | import os 6 | import sys 7 | import traceback 8 | 9 | matches = [] 10 | for root, dirnames, filenames in os.walk('src'): 11 | for filename in fnmatch.filter(filenames, '*.py'): 12 | matches.append(os.path.join(root, filename)) 13 | 14 | for filename in matches: 15 | source = open(filename, 'r').read() + '\n' 16 | try: 17 | compile(source, filename, 'exec') 18 | except Exception as e: 19 | ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) 20 | sys.exit(1) -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /debian.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.2 5 | VERSION=0.4.4 6 | RELEASE=1 7 | ARCH_TYPE=all 8 | DIR=${APP}-${VERSION} 9 | 10 | if [ $ARCH_TYPE == "x86_64" ]; then 11 | ARCH_TYPE="amd64" 12 | fi 13 | if [ $ARCH_TYPE == "i686" ]; then 14 | ARCH_TYPE="i386" 15 | fi 16 | 17 | 18 | # Update version numbers automatically - so you don't have to 19 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile rpm.sh arch.sh puppy.sh ebuild.sh slack.sh 20 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 21 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 22 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 23 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 24 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 25 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 26 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 27 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 28 | 29 | make clean 30 | make 31 | 32 | # Change the parent directory name to Debian format 33 | mv ../${APP} ../${DIR} 34 | 35 | # Create a source archive 36 | make sourcedeb 37 | 38 | # Build the package 39 | dpkg-buildpackage -F 40 | 41 | # Sign files 42 | gpg -ba ../${APP}_${VERSION}-1_${ARCH_TYPE}.deb 43 | gpg -ba ../${APP}_${VERSION}.orig.tar.gz 44 | 45 | # Restore the parent directory name 46 | mv ../${DIR} ../${APP} 47 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: pybitmessage 2 | Section: mail 3 | Priority: extra 4 | Maintainer: Bob Mottram (4096 bits) 5 | Build-Depends: debhelper (>= 9.0.0), libqt4-dev (>= 4.8.0), python-qt4-dev, libsqlite3-dev 6 | Standards-Version: 3.9.4 7 | Homepage: https://github.com/Bitmessage/PyBitmessage 8 | Vcs-Git: https://github.com/Bitmessage/PyBitmessage.git 9 | 10 | Package: pybitmessage 11 | Architecture: all 12 | Depends: ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}, python (>= 2.7), openssl, python-qt4, sqlite3, gst123 13 | Suggests: libmessaging-menu-dev 14 | Description: Send encrypted messages 15 | Bitmessage is a P2P communications protocol used to send encrypted 16 | messages to another person or to many subscribers. It is decentralized and 17 | trustless, meaning that you need-not inherently trust any entities like 18 | root certificate authorities. It uses strong authentication which means 19 | that the sender of a message cannot be spoofed, and it aims to hide 20 | "non-content" data, like the sender and receiver of messages, from passive 21 | eavesdroppers like those running warrantless wiretapping programs. 22 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: 3 | Source: 4 | 5 | Files: * 6 | Copyright: Copyright 2016 Bob Mottram (4096 bits) 7 | License: MIT 8 | 9 | Files: debian/* 10 | Copyright: Copyright 2016 Bob Mottram (4096 bits) 11 | License: MIT 12 | 13 | License: MIT 14 | Permission is hereby granted, free of charge, to any person obtaining a 15 | copy of this software and associated documentation files (the "Software"), 16 | to deal in the Software without restriction, including without limitation 17 | the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 | and/or sell copies of the Software, and to permit persons to whom the 19 | Software is furnished to do so, subject to the following conditions: 20 | . 21 | The above copyright notice and this permission notice shall be included 22 | in all copies or substantial portions of the Software. 23 | . 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 28 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 29 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 30 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /debian/manpages: -------------------------------------------------------------------------------- 1 | man/pybitmessage.1.gz 2 | -------------------------------------------------------------------------------- /debian/pybm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd /usr/share/pybitmessage 3 | exec python bitmessagemain.py 4 | 5 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | APP=pybitmessage 4 | PREFIX=/usr 5 | build: build-stamp 6 | make 7 | build-arch: build-stamp 8 | build-indep: build-stamp 9 | build-stamp: 10 | dh_testdir 11 | touch build-stamp 12 | 13 | clean: 14 | dh_testdir 15 | dh_testroot 16 | rm -f build-stamp 17 | dh_clean 18 | 19 | install: build clean 20 | dh_testdir 21 | dh_testroot 22 | dh_prep 23 | dh_installdirs 24 | ${MAKE} install -B DESTDIR=${CURDIR}/debian/${APP} PREFIX=/usr 25 | binary-indep: build install 26 | dh_testdir 27 | dh_testroot 28 | dh_installchangelogs 29 | dh_installdocs 30 | dh_installexamples 31 | dh_installman 32 | dh_link 33 | dh_compress 34 | dh_fixperms 35 | dh_installdeb 36 | dh_gencontrol 37 | dh_md5sums 38 | dh_builddeb 39 | 40 | binary-arch: build install 41 | 42 | binary: binary-indep binary-arch 43 | .PHONY: build clean binary-indep binary-arch binary install 44 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /debian/source/include-binaries: -------------------------------------------------------------------------------- 1 | src/images/sent.png 2 | src/images/can-icon-16px.png 3 | src/images/addressbook.png 4 | src/images/networkstatus.png 5 | src/images/redicon.png 6 | src/images/subscriptions.png 7 | src/images/blacklist.png 8 | src/images/can-icon-24px.png 9 | src/images/can-icon-24px-red.png 10 | src/images/can-icon-24px-yellow.png 11 | src/images/can-icon-24px-green.png 12 | src/images/identities.png 13 | src/images/yellowicon.png 14 | src/images/inbox.png 15 | src/images/greenicon.png 16 | src/images/can-icon.ico 17 | src/images/send.png 18 | desktop/can-icon.svg 19 | -------------------------------------------------------------------------------- /desktop/icon14.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char * icon14_xpm[] = { 3 | "14 14 94 2", 4 | " c None", 5 | ". c #B9BABC", 6 | "+ c #D2D3D4", 7 | "@ c #BEBFC1", 8 | "# c #CBCCCF", 9 | "$ c #E0E3E1", 10 | "% c #F6F8F8", 11 | "& c #F3F3F3", 12 | "* c #B9BABD", 13 | "= c #C8C9CB", 14 | "- c #DADCDB", 15 | "; c #E6E8E7", 16 | "> c #F7F7F7", 17 | ", c #FCFCFC", 18 | "' c #F5F5F5", 19 | ") c #BCBDBF", 20 | "! c #D3D5D5", 21 | "~ c #E3E5E4", 22 | "{ c #F1F2F2", 23 | "] c #FDFDFD", 24 | "^ c #F8F8F8", 25 | "/ c #CBCCCC", 26 | "( c #B2B3B6", 27 | "_ c #B0B1B3", 28 | ": c #D3D4D6", 29 | "< c #DFE0E0", 30 | "[ c #EAEDEB", 31 | "} c #FAF9F9", 32 | "| c #DFE0DF", 33 | "1 c #B9BBBD", 34 | "2 c #C2C3C5", 35 | "3 c #B7B8BC", 36 | "4 c #CDCED0", 37 | "5 c #DCDDDE", 38 | "6 c #E7E9E7", 39 | "7 c #F6F6F6", 40 | "8 c #C0C1C2", 41 | "9 c #DDDFDF", 42 | "0 c #BCBCBF", 43 | "a c #D7D9DA", 44 | "b c #E2E4E3", 45 | "c c #F0F2F1", 46 | "d c #FAFAFA", 47 | "e c #F9F9F9", 48 | "f c #CCCDCD", 49 | "g c #B6B7B9", 50 | "h c #C7C8CA", 51 | "i c #A6A7A9", 52 | "j c #D3D4D5", 53 | "k c #F2F5F3", 54 | "l c #F1F2F1", 55 | "m c #F6F8F7", 56 | "n c #FCFBFC", 57 | "o c #E8EAE9", 58 | "p c #B6B7B8", 59 | "q c #BFC0C2", 60 | "r c #323138", 61 | "s c #1D1D22", 62 | "t c #111117", 63 | "u c #4C4C51", 64 | "v c #ECECED", 65 | "w c #FFFFFF", 66 | "x c #BBBDBD", 67 | "y c #C9CACB", 68 | "z c #333238", 69 | "A c #313036", 70 | "B c #27272C", 71 | "C c #1E1F24", 72 | "D c #16171D", 73 | "E c #919193", 74 | "F c #F2F3F3", 75 | "G c #B4B5B7", 76 | "H c #CDCFCF", 77 | "I c #67666B", 78 | "J c #37363C", 79 | "K c #2C2B31", 80 | "L c #2A292F", 81 | "M c #16171C", 82 | "N c #68696B", 83 | "O c #C7C8C9", 84 | "P c #CBCDCC", 85 | "Q c #49474E", 86 | "R c #39383E", 87 | "S c #36353B", 88 | "T c #333138", 89 | "U c #28272D", 90 | "V c #CED0D0", 91 | "W c #67676C", 92 | "X c #414046", 93 | "Y c #424147", 94 | "Z c #39383F", 95 | "` c #8C8D8F", 96 | " . c #6B6C70", 97 | ".. c #75757A", 98 | " . + ", 99 | " @ # $ % & ", 100 | " * = - ; > , ' ", 101 | " ) ! ~ { ] ^ / ( ", 102 | " _ : < [ } , | 1 2 ", 103 | " 3 4 5 6 7 , { 8 . 9 ", 104 | " 2 0 a b c d e f g h ", 105 | " i j k l m n o p q h ", 106 | " r s t u v w ' x g y ", 107 | " z A B C D E F G H ", 108 | " I J A K L M N O P ", 109 | " Q R R S T U V ", 110 | " W X Y X Z ` ", 111 | " ... "}; 112 | -------------------------------------------------------------------------------- /desktop/icon24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/desktop/icon24.png -------------------------------------------------------------------------------- /desktop/pybitmessage.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=PyBitmessage 4 | GenericName=PyBitmessage 5 | Comment=Send encrypted messages 6 | Exec=pybitmessage %F 7 | Icon=pybitmessage 8 | Terminal=false 9 | Categories=Office;Email; 10 | -------------------------------------------------------------------------------- /ebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.4 5 | VERSION=0.4.4 6 | RELEASE=1 7 | SOURCEDIR=. 8 | ARCH_TYPE=`uname -m` 9 | CURRDIR=`pwd` 10 | SOURCE=~/ebuild/${APP}-${VERSION}.tar.gz 11 | 12 | 13 | # Update version numbers automatically - so you don't have to 14 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile debian.sh rpm.sh arch.sh puppy.sh slack.sh 15 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 16 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 17 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 18 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 19 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 20 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 21 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 22 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 23 | 24 | # create the source code in the SOURCES directory 25 | make clean 26 | mkdir -p ~/ebuild 27 | rm -f ${SOURCE} 28 | mv ../${APP} ../${APP}-${VERSION} 29 | tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs 30 | 31 | # rename the root directory without the version number 32 | mv ../${APP}-${VERSION} ../${APP} 33 | 34 | -------------------------------------------------------------------------------- /generate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generates packaging 4 | 5 | rm -f Makefile rpmpackage/*.spec 6 | 7 | packagemonkey -n "PyBitmessage" --version "0.4.4" --dir "." -l "mit" \ 8 | -e "Bob Mottram (4096 bits) " \ 9 | --brief "Send encrypted messages" \ 10 | --desc "Bitmessage is a P2P communications protocol used to send encrypted messages to another person or to many subscribers. It is decentralized and trustless, meaning that you need-not inherently trust any entities like root certificate authorities. It uses strong authentication which means that the sender of a message cannot be spoofed, and it aims to hide \"non-content\" data, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs." \ 11 | --homepage "https://github.com/Bitmessage/PyBitmessage" --section "mail" \ 12 | --categories "Office/Email" \ 13 | --dependsdeb "python (>= 2.7), openssl, python-qt4, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, gst123" \ 14 | --dependsrpm "python, PyQt4, openssl-compat-bitcoin-libs, gst123" \ 15 | --mainscript "bitmessagemain.py" \ 16 | --librarypath "/opt/openssl-compat-bitcoin/lib/" \ 17 | --suggestsdeb "libmessaging-menu-dev" \ 18 | --dependspuppy "openssl, python-qt4, sqlite3, sqlite3-dev, python-openssl, python-sip, gst123" \ 19 | --dependsarch "python2, qt4, python2-pyqt4, sqlite, openssl, mpg123" \ 20 | --suggestsarch "python2-gevent: Python network library that uses greenlet and libevent for easy and scalable concurrency" --pythonversion 2 \ 21 | --dependsebuild "dev-libs/openssl, dev-python/PyQt4[${PYTHON_USEDEP}]" \ 22 | --buildebuild "\${PYTHON_DEPS}" --pythonreq "sqlite" \ 23 | --repository "https://github.com/Bitmessage/PyBitmessage.git" 24 | -------------------------------------------------------------------------------- /man/pybitmessage.1.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/man/pybitmessage.1.gz -------------------------------------------------------------------------------- /osx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # OS X Build script wrapper around the py2app script. 4 | # This build can only be generated on OS X. 5 | # Requires all build dependencies for Bitmessage 6 | # Especially important is OpenSSL installed through brew 7 | 8 | export ARCHFLAGS="-arch i386 -arch x86_64" 9 | 10 | if [[ -z "$1" ]]; then 11 | echo "Please supply a version number for this release as the first argument." 12 | exit 13 | fi 14 | 15 | echo "Creating OS X packages for Bitmessage." 16 | 17 | export PYBITMESSAGEVERSION=$1 18 | 19 | cd src && python2.7 build_osx.py py2app 20 | 21 | if [[ $? = "0" ]]; then 22 | hdiutil create -fs HFS+ -volname "Bitmessage" -srcfolder dist/Bitmessage.app dist/bitmessage-v$1.dmg 23 | else 24 | echo "Problem creating Bitmessage.app, stopping." 25 | exit 26 | fi 27 | -------------------------------------------------------------------------------- /puppy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.4 5 | VERSION=0.4.4 6 | RELEASE=1 7 | BUILDDIR=~/petbuild 8 | CURRDIR=`pwd` 9 | PROJECTDIR=${BUILDDIR}/${APP}-${VERSION}-${RELEASE} 10 | 11 | # Update version numbers automatically - so you don't have to 12 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile debian.sh rpm.sh arch.sh ebuild.sh slack.sh 13 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 14 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 15 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 16 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 17 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 18 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 19 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 20 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 21 | 22 | 23 | # Make directories within which the project will be built 24 | mkdir -p ${BUILDDIR} 25 | mkdir -p ${PROJECTDIR} 26 | 27 | # Build the project 28 | make clean 29 | make 30 | make install -B DESTDIR=${PROJECTDIR} PREFIX=/usr 31 | 32 | # Alter the desktop file categories 33 | sed -i "s/Categories=Office;Email;/Categories=Internet;mailnews;/g" ${PROJECTDIR}/usr/share/applications/${APP}.desktop 34 | 35 | # Create directories specific to puppy 36 | mkdir ${PROJECTDIR}/usr 37 | mkdir ${PROJECTDIR}/usr/local 38 | mkdir ${PROJECTDIR}/usr/local/bin 39 | 40 | # Copy anything in /usr/bin into /usr/local/bin 41 | cp ${PROJECTDIR}/usr/bin/* ${PROJECTDIR}/usr/local/bin/ 42 | 43 | # Copy the spec file into the build directory 44 | cp ${CURRDIR}/puppypackage/${APP}-${VERSION}.pet.specs ${PROJECTDIR} 45 | 46 | # Copy the XPM mini icon into the build directory 47 | cp ${CURRDIR}/desktop/icon14.xpm ${PROJECTDIR}/${APP}.xpm 48 | 49 | # Compress the build directory 50 | cd ${BUILDDIR} 51 | tar -c -f ${APP}-${VERSION}-${RELEASE}.tar . 52 | sync 53 | gzip ${APP}-${VERSION}-${RELEASE}.tar 54 | mv ${APP}-${VERSION}-${RELEASE}.tar.gz ${CURRDIR}/puppypackage 55 | cd ${CURRDIR}/puppypackage 56 | 57 | # Create the PET package 58 | MD5SUM="`md5sum ${APP}-${VERSION}-${RELEASE}.tar.gz | cut -f 1 -d ' '`" 59 | echo -n "$MD5SUM" >> ${APP}-${VERSION}-${RELEASE}.tar.gz 60 | sync 61 | mv -f ${APP}-${VERSION}-${RELEASE}.tar.gz ${APP}-${VERSION}-${RELEASE}.pet 62 | sync 63 | cd ${CURRDIR} 64 | 65 | # Remove the temporary build directory 66 | rm -fr ${BUILDDIR} 67 | -------------------------------------------------------------------------------- /puppypackage/icon14.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char * icon14_xpm[] = { 3 | "14 14 94 2", 4 | " c None", 5 | ". c #B9BABC", 6 | "+ c #D2D3D4", 7 | "@ c #BEBFC1", 8 | "# c #CBCCCF", 9 | "$ c #E0E3E1", 10 | "% c #F6F8F8", 11 | "& c #F3F3F3", 12 | "* c #B9BABD", 13 | "= c #C8C9CB", 14 | "- c #DADCDB", 15 | "; c #E6E8E7", 16 | "> c #F7F7F7", 17 | ", c #FCFCFC", 18 | "' c #F5F5F5", 19 | ") c #BCBDBF", 20 | "! c #D3D5D5", 21 | "~ c #E3E5E4", 22 | "{ c #F1F2F2", 23 | "] c #FDFDFD", 24 | "^ c #F8F8F8", 25 | "/ c #CBCCCC", 26 | "( c #B2B3B6", 27 | "_ c #B0B1B3", 28 | ": c #D3D4D6", 29 | "< c #DFE0E0", 30 | "[ c #EAEDEB", 31 | "} c #FAF9F9", 32 | "| c #DFE0DF", 33 | "1 c #B9BBBD", 34 | "2 c #C2C3C5", 35 | "3 c #B7B8BC", 36 | "4 c #CDCED0", 37 | "5 c #DCDDDE", 38 | "6 c #E7E9E7", 39 | "7 c #F6F6F6", 40 | "8 c #C0C1C2", 41 | "9 c #DDDFDF", 42 | "0 c #BCBCBF", 43 | "a c #D7D9DA", 44 | "b c #E2E4E3", 45 | "c c #F0F2F1", 46 | "d c #FAFAFA", 47 | "e c #F9F9F9", 48 | "f c #CCCDCD", 49 | "g c #B6B7B9", 50 | "h c #C7C8CA", 51 | "i c #A6A7A9", 52 | "j c #D3D4D5", 53 | "k c #F2F5F3", 54 | "l c #F1F2F1", 55 | "m c #F6F8F7", 56 | "n c #FCFBFC", 57 | "o c #E8EAE9", 58 | "p c #B6B7B8", 59 | "q c #BFC0C2", 60 | "r c #323138", 61 | "s c #1D1D22", 62 | "t c #111117", 63 | "u c #4C4C51", 64 | "v c #ECECED", 65 | "w c #FFFFFF", 66 | "x c #BBBDBD", 67 | "y c #C9CACB", 68 | "z c #333238", 69 | "A c #313036", 70 | "B c #27272C", 71 | "C c #1E1F24", 72 | "D c #16171D", 73 | "E c #919193", 74 | "F c #F2F3F3", 75 | "G c #B4B5B7", 76 | "H c #CDCFCF", 77 | "I c #67666B", 78 | "J c #37363C", 79 | "K c #2C2B31", 80 | "L c #2A292F", 81 | "M c #16171C", 82 | "N c #68696B", 83 | "O c #C7C8C9", 84 | "P c #CBCDCC", 85 | "Q c #49474E", 86 | "R c #39383E", 87 | "S c #36353B", 88 | "T c #333138", 89 | "U c #28272D", 90 | "V c #CED0D0", 91 | "W c #67676C", 92 | "X c #414046", 93 | "Y c #424147", 94 | "Z c #39383F", 95 | "` c #8C8D8F", 96 | " . c #6B6C70", 97 | ".. c #75757A", 98 | " . + ", 99 | " @ # $ % & ", 100 | " * = - ; > , ' ", 101 | " ) ! ~ { ] ^ / ( ", 102 | " _ : < [ } , | 1 2 ", 103 | " 3 4 5 6 7 , { 8 . 9 ", 104 | " 2 0 a b c d e f g h ", 105 | " i j k l m n o p q h ", 106 | " r s t u v w ' x g y ", 107 | " z A B C D E F G H ", 108 | " I J A K L M N O P ", 109 | " Q R R S T U V ", 110 | " W X Y X Z ` ", 111 | " ... "}; 112 | -------------------------------------------------------------------------------- /puppypackage/pybitmessage-0.3.5.pet.specs: -------------------------------------------------------------------------------- 1 | pybitmessage-0.3.5-1|PyBitmessage|0.3.5|1|Internet;mailnews;|3.8M||pybitmessage-0.3.5-1.pet|+openssl,+python-qt4,+sqlite3,+sqlite3-dev,+python-openssl,+python-sip,+gst123|Send encrypted messages|ubuntu|precise|5| 2 | -------------------------------------------------------------------------------- /pyinstaller/bitmessagemain.spec: -------------------------------------------------------------------------------- 1 | srcPath = "C:\\src\\PyBitmessage\\src\\" 2 | qtPath = "C:\\Qt\\4.8.6\\" 3 | openSSLPath = "C:\\OpenSSL-1.0.2e\\" 4 | outPath = "C:\\src\\PyInstaller\\bitmessagemain" 5 | 6 | # -*- mode: python -*- 7 | a = Analysis([srcPath + 'bitmessagemain.py'], 8 | pathex=[outPath], 9 | hiddenimports=[], 10 | hookspath=None, 11 | runtime_hooks=None) 12 | 13 | # fix duplicates 14 | for d in a.datas: 15 | if 'pyconfig' in d[0]: 16 | a.datas.remove(d) 17 | break 18 | 19 | def addTranslations(): 20 | import os 21 | extraDatas = [] 22 | for file in os.listdir(srcPath + 'translations'): 23 | if file[-3:] != ".qm": 24 | continue 25 | extraDatas.append(('translations\\'+file, srcPath + 'translations\\' + file, 'DATA')) 26 | for file in os.listdir(qtPath + 'translations'): 27 | if file[0:3] != "qt_" or file[5:8] != ".qm": 28 | continue 29 | extraDatas.append(('translations\\'+file, qtPath + 'translations\\' + file, 'DATA')) 30 | return extraDatas 31 | 32 | def addUIs(): 33 | import os 34 | extraDatas = [] 35 | for file in os.listdir(srcPath + 'bitmessageqt'): 36 | if file[-3:] != ".ui": 37 | continue 38 | extraDatas.append(('ui\\'+file, srcPath + 'bitmessageqt\\' + file, 'DATA')) 39 | return extraDatas 40 | 41 | # append the translations directory 42 | a.datas += addTranslations() 43 | a.datas += addUIs() 44 | 45 | a.binaries.append(('msvcr120.dll', 'C:\\WINDOWS\\system32\\msvcr120.dll', 'BINARY')) 46 | 47 | pyz = PYZ(a.pure) 48 | exe = EXE(pyz, 49 | a.scripts, 50 | a.binaries, 51 | a.zipfiles, 52 | a.datas, 53 | a.binaries + [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), ('bitmsghash\\bitmsghash32.dll', srcPath + 'bitmsghash\\bitmsghash32.dll', 'BINARY'), ('bitmsghash\\bitmsghash.cl', srcPath + 'bitmsghash\\bitmsghash.cl', 'BINARY'), ('sslkeys\\cert.pem', srcPath + 'sslkeys\\cert.pem', 'BINARY'), ('sslkeys\\key.pem', srcPath + 'sslkeys\\key.pem', 'BINARY')], 54 | name='Bitmessage.exe', 55 | debug=False, 56 | strip=None, 57 | upx=False, 58 | console=False, icon= srcPath + 'images\\can-icon.ico') 59 | -------------------------------------------------------------------------------- /rpm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.4 5 | VERSION=0.4.4 6 | RELEASE=1 7 | SOURCEDIR=. 8 | ARCH_TYPE=`uname -m` 9 | CURRDIR=`pwd` 10 | SOURCE=~/rpmbuild/SOURCES/${APP}_${VERSION}.orig.tar.gz 11 | 12 | 13 | # Update version numbers automatically - so you don't have to 14 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile debian.sh arch.sh puppy.sh ebuild.sh slack.sh 15 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 16 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 17 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 18 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 19 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 20 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 21 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 22 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 23 | 24 | sudo yum groupinstall "Development Tools" 25 | sudo yum install rpmdevtools 26 | 27 | # setup the rpmbuild directory tree 28 | rpmdev-setuptree 29 | 30 | # create the source code in the SOURCES directory 31 | make clean 32 | mkdir -p ~/rpmbuild/SOURCES 33 | rm -f ${SOURCE} 34 | 35 | # having the root directory called name-version seems essential 36 | mv ../${APP} ../${APP}-${VERSION} 37 | tar -cvzf ${SOURCE} ../${APP}-${VERSION} --exclude-vcs 38 | 39 | # rename the root directory without the version number 40 | mv ../${APP}-${VERSION} ../${APP} 41 | 42 | # copy the spec file into the SPECS directory 43 | cp -f rpmpackage/${APP}.spec ~/rpmbuild/SPECS 44 | 45 | # build 46 | cd ~/rpmbuild/SPECS 47 | rpmbuild -ba ${APP}.spec 48 | cd ${CURRDIR} 49 | 50 | # Copy the results into the rpmpackage directory 51 | mkdir -p rpmpackage/${ARCH_TYPE} 52 | cp -r ~/rpmbuild/RPMS/${ARCH_TYPE}/${APP}* rpmpackage/${ARCH_TYPE} 53 | cp -r ~/rpmbuild/SRPMS/${APP}* rpmpackage 54 | -------------------------------------------------------------------------------- /slack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | APP=pybitmessage 4 | PREV_VERSION=0.4.4 5 | VERSION=0.4.4 6 | RELEASE=1 7 | ARCH_TYPE=`uname -m` 8 | BUILDDIR=~/slackbuild 9 | CURRDIR=`pwd` 10 | PROJECTDIR=${BUILDDIR}/${APP}-${VERSION}-${RELEASE} 11 | 12 | # Update version numbers automatically - so you don't have to 13 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' Makefile debian.sh rpm.sh arch.sh puppy.sh ebuild.sh 14 | sed -i 's/Version: '${PREV_VERSION}'/Version: '${VERSION}'/g' rpmpackage/${APP}.spec 15 | sed -i 's/Release: '${RELEASE}'/Release: '${RELEASE}'/g' rpmpackage/${APP}.spec 16 | sed -i 's/pkgrel='${RELEASE}'/pkgrel='${RELEASE}'/g' archpackage/PKGBUILD 17 | sed -i 's/pkgver='${PREV_VERSION}'/pkgver='${VERSION}'/g' archpackage/PKGBUILD 18 | sed -i "s/-${PREV_VERSION}-/-${VERSION}-/g" puppypackage/*.specs 19 | sed -i "s/|${PREV_VERSION}|/|${VERSION}|/g" puppypackage/*.specs 20 | sed -i 's/VERSION='${PREV_VERSION}'/VERSION='${VERSION}'/g' puppypackage/pinstall.sh puppypackage/puninstall.sh 21 | sed -i 's/-'${PREV_VERSION}'.so/-'${VERSION}'.so/g' debian/*.links 22 | 23 | 24 | # Make directories within which the project will be built 25 | mkdir -p ${BUILDDIR} 26 | mkdir -p ${PROJECTDIR} 27 | 28 | # Build the project 29 | make clean 30 | make 31 | make install -B DESTDIR=${PROJECTDIR} PREFIX=/usr 32 | 33 | # Copy the slack-desc and doinst.sh files into the build install directory 34 | mkdir ${PROJECTDIR}/install 35 | cp ${CURRDIR}/slackpackage/slack-desc ${PROJECTDIR}/install 36 | cp ${CURRDIR}/slackpackage/doinst.sh ${PROJECTDIR}/install 37 | 38 | # Compress the build directory 39 | cd ${BUILDDIR} 40 | tar -c -f ${APP}-${VERSION}-${RELEASE}.tar . 41 | sync 42 | xz ${APP}-${VERSION}-${RELEASE}.tar 43 | sync 44 | mv ${APP}-${VERSION}-${RELEASE}.tar.xz ${CURRDIR}/slackpackage/${APP}-${VERSION}-${ARCH_TYPE}-${RELEASE}.txz 45 | cd ${CURRDIR} 46 | 47 | # Remove the temporary build directory 48 | rm -fr ${BUILDDIR} 49 | -------------------------------------------------------------------------------- /slackpackage/doinst.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | # This script is run after installation. 4 | # Any additional configuration goes here. 5 | -------------------------------------------------------------------------------- /slackpackage/slack-desc: -------------------------------------------------------------------------------- 1 | # HOW TO EDIT THIS FILE: 2 | # The "handy ruler" below makes it easier to edit a package description. Line 3 | # up the first '|' above the ':' following the base package name, and the '|' on 4 | # the right side marks the last column you can put a character in. You must make 5 | # exactly 11 lines for the formatting to be correct. It's also customary to 6 | # leave one space after the ':'. 7 | 8 | |-----handy-ruler--------------------------------------------------| 9 | pybitmessage: pybitmessage (Send encrypted messages) 10 | pybitmessage: 11 | pybitmessage: Bitmessage is a P2P communications protocol used to send 12 | pybitmessage: encrypted messages to another person or to many subscribers. It 13 | pybitmessage: is decentralized and trustless, meaning that you need-not 14 | pybitmessage: inherently trust any entities like root certificate authorities. 15 | pybitmessage: It uses strong authentication which means that the sender of a 16 | pybitmessage: message cannot be spoofed, and it aims to hide "non-content" 17 | pybitmessage: data, like the sender and receiver of messages, from passive 18 | pybitmessage: eavesdroppers like those running warrantless wiretapping 19 | pybitmessage: programs. 20 | -------------------------------------------------------------------------------- /src/api_client.py: -------------------------------------------------------------------------------- 1 | # This is an example of how to connect to and use the Bitmessage API. 2 | # See https://bitmessage.org/wiki/API_Reference 3 | 4 | import xmlrpclib 5 | import json 6 | import time 7 | 8 | api = xmlrpclib.ServerProxy("http://bradley:password@localhost:8442/") 9 | 10 | print 'Let\'s test the API first.' 11 | inputstr1 = "hello" 12 | inputstr2 = "world" 13 | print api.helloWorld(inputstr1, inputstr2) 14 | print api.add(2,3) 15 | 16 | print 'Let\'s set the status bar message.' 17 | print api.statusBar("new status bar message") 18 | 19 | print 'Let\'s list our addresses:' 20 | print api.listAddresses() 21 | 22 | print 'Let\'s list our address again, but this time let\'s parse the json data into a Python data structure:' 23 | jsonAddresses = json.loads(api.listAddresses()) 24 | print jsonAddresses 25 | print 'Now that we have our address data in a nice Python data structure, let\'s look at the first address (index 0) and print its label:' 26 | print jsonAddresses['addresses'][0]['label'] 27 | 28 | print 'Uncomment the next two lines to create a new random address with a slightly higher difficulty setting than normal.' 29 | #addressLabel = 'new address label'.encode('base64') 30 | #print api.createRandomAddress(addressLabel,False,1.05,1.1111) 31 | 32 | print 'Uncomment these next four lines to create new deterministic addresses.' 33 | #passphrase = 'asdfasdfqwser'.encode('base64') 34 | #jsonDeterministicAddresses = api.createDeterministicAddresses(passphrase, 2, 4, 1, False) 35 | #print jsonDeterministicAddresses 36 | #print json.loads(jsonDeterministicAddresses) 37 | 38 | #print 'Uncomment this next line to print the first deterministic address that would be generated with the given passphrase. This will Not add it to the Bitmessage interface or the keys.dat file.' 39 | #print api.getDeterministicAddress('asdfasdfqwser'.encode('base64'),4,1) 40 | 41 | #print 'Uncomment this line to subscribe to an address. (You must use your own address, this one is invalid).' 42 | #print api.addSubscription('2D94G5d8yp237GGqAheoecBYpdehdT3dha','test sub'.encode('base64')) 43 | 44 | #print 'Uncomment this line to unsubscribe from an address.' 45 | #print api.deleteSubscription('2D94G5d8yp237GGqAheoecBYpdehdT3dha') 46 | 47 | print 'Let\'s now print all of our inbox messages:' 48 | print api.getAllInboxMessages() 49 | inboxMessages = json.loads(api.getAllInboxMessages()) 50 | print inboxMessages 51 | 52 | print 'Uncomment this next line to decode the actual message data in the first message:' 53 | #print inboxMessages['inboxMessages'][0]['message'].decode('base64') 54 | 55 | print 'Uncomment this next line in the code to delete a message' 56 | #print api.trashMessage('584e5826947242a82cb883c8b39ac4a14959f14c228c0fbe6399f73e2cba5b59') 57 | 58 | print 'Uncomment these lines to send a message. The example addresses are invalid; you will have to put your own in.' 59 | #subject = 'subject!'.encode('base64') 60 | #message = 'Hello, this is the message'.encode('base64') 61 | #ackData = api.sendMessage('BM-Gtsm7PUabZecs3qTeXbNPmqx3xtHCSXF', 'BM-2DCutnUZG16WiW3mdAm66jJUSCUv88xLgS', subject,message) 62 | #print 'The ackData is:', ackData 63 | #while True: 64 | # time.sleep(2) 65 | # print 'Current status:', api.getStatus(ackData) 66 | 67 | print 'Uncomment these lines to send a broadcast. The example address is invalid; you will have to put your own in.' 68 | #subject = 'subject within broadcast'.encode('base64') 69 | #message = 'Hello, this is the message within a broadcast.'.encode('base64') 70 | #print api.sendBroadcast('BM-onf6V1RELPgeNN6xw9yhpAiNiRexSRD4e', subject,message) 71 | -------------------------------------------------------------------------------- /src/bitmessageqt/about.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'about.ui' 4 | # 5 | # Created: Tue Jan 21 22:29:38 2014 6 | # by: PyQt4 UI code generator 4.10.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_aboutDialog(object): 27 | def setupUi(self, aboutDialog): 28 | aboutDialog.setObjectName(_fromUtf8("aboutDialog")) 29 | aboutDialog.resize(360, 315) 30 | self.buttonBox = QtGui.QDialogButtonBox(aboutDialog) 31 | self.buttonBox.setGeometry(QtCore.QRect(20, 280, 311, 32)) 32 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 33 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) 34 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 35 | self.label = QtGui.QLabel(aboutDialog) 36 | self.label.setGeometry(QtCore.QRect(70, 126, 111, 20)) 37 | font = QtGui.QFont() 38 | font.setBold(True) 39 | font.setWeight(75) 40 | self.label.setFont(font) 41 | self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) 42 | self.label.setObjectName(_fromUtf8("label")) 43 | self.labelVersion = QtGui.QLabel(aboutDialog) 44 | self.labelVersion.setGeometry(QtCore.QRect(190, 126, 161, 20)) 45 | self.labelVersion.setObjectName(_fromUtf8("labelVersion")) 46 | self.label_2 = QtGui.QLabel(aboutDialog) 47 | self.label_2.setGeometry(QtCore.QRect(10, 150, 341, 41)) 48 | self.label_2.setAlignment(QtCore.Qt.AlignCenter) 49 | self.label_2.setObjectName(_fromUtf8("label_2")) 50 | self.label_3 = QtGui.QLabel(aboutDialog) 51 | self.label_3.setGeometry(QtCore.QRect(20, 200, 331, 71)) 52 | self.label_3.setWordWrap(True) 53 | self.label_3.setOpenExternalLinks(True) 54 | self.label_3.setObjectName(_fromUtf8("label_3")) 55 | self.label_5 = QtGui.QLabel(aboutDialog) 56 | self.label_5.setGeometry(QtCore.QRect(10, 190, 341, 20)) 57 | self.label_5.setAlignment(QtCore.Qt.AlignCenter) 58 | self.label_5.setObjectName(_fromUtf8("label_5")) 59 | 60 | self.retranslateUi(aboutDialog) 61 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), aboutDialog.accept) 62 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), aboutDialog.reject) 63 | QtCore.QMetaObject.connectSlotsByName(aboutDialog) 64 | 65 | def retranslateUi(self, aboutDialog): 66 | aboutDialog.setWindowTitle(_translate("aboutDialog", "About", None)) 67 | self.label.setText(_translate("aboutDialog", "PyBitmessage", None)) 68 | self.labelVersion.setText(_translate("aboutDialog", "version ?", None)) 69 | self.label_2.setText(_translate("aboutDialog", "

Copyright © 2012-2016 Jonathan Warren
Copyright © 2013-2016 The Bitmessage Developers

", None)) 70 | self.label_3.setText(_translate("aboutDialog", "

Distributed under the MIT/X11 software license; see http://www.opensource.org/licenses/mit-license.php

", None)) 71 | self.label_5.setText(_translate("aboutDialog", "This is Beta software.", None)) 72 | 73 | -------------------------------------------------------------------------------- /src/bitmessageqt/about.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | aboutDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 360 10 | 315 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | 19 | 20 20 | 280 21 | 311 22 | 32 23 | 24 | 25 | 26 | Qt::Horizontal 27 | 28 | 29 | QDialogButtonBox::Ok 30 | 31 | 32 | 33 | 34 | 35 | 70 36 | 126 37 | 111 38 | 20 39 | 40 | 41 | 42 | 43 | 75 44 | true 45 | 46 | 47 | 48 | PyBitmessage 49 | 50 | 51 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 52 | 53 | 54 | 55 | 56 | 57 | 190 58 | 126 59 | 161 60 | 20 61 | 62 | 63 | 64 | version ? 65 | 66 | 67 | 68 | 69 | 70 | 10 71 | 150 72 | 341 73 | 41 74 | 75 | 76 | 77 | <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> 78 | 79 | 80 | Qt::AlignCenter 81 | 82 | 83 | 84 | 85 | 86 | 20 87 | 200 88 | 331 89 | 71 90 | 91 | 92 | 93 | <html><head/><body><p>Distributed under the MIT/X11 software license; see <a href="http://www.opensource.org/licenses/mit-license.php"><span style=" text-decoration: underline; color:#0000ff;">http://www.opensource.org/licenses/mit-license.php</span></a></p></body></html> 94 | 95 | 96 | true 97 | 98 | 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 10 106 | 190 107 | 341 108 | 20 109 | 110 | 111 | 112 | This is Beta software. 113 | 114 | 115 | Qt::AlignCenter 116 | 117 | 118 | 119 | 120 | 121 | 122 | buttonBox 123 | accepted() 124 | aboutDialog 125 | accept() 126 | 127 | 128 | 248 129 | 254 130 | 131 | 132 | 157 133 | 274 134 | 135 | 136 | 137 | 138 | buttonBox 139 | rejected() 140 | aboutDialog 141 | reject() 142 | 143 | 144 | 316 145 | 260 146 | 147 | 148 | 286 149 | 274 150 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /src/bitmessageqt/addaddressdialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'addaddressdialog.ui' 4 | # 5 | # Created: Sat Nov 30 20:35:38 2013 6 | # by: PyQt4 UI code generator 4.10.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_AddAddressDialog(object): 27 | def setupUi(self, AddAddressDialog): 28 | AddAddressDialog.setObjectName(_fromUtf8("AddAddressDialog")) 29 | AddAddressDialog.resize(368, 162) 30 | self.formLayout = QtGui.QFormLayout(AddAddressDialog) 31 | self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) 32 | self.formLayout.setObjectName(_fromUtf8("formLayout")) 33 | self.label_2 = QtGui.QLabel(AddAddressDialog) 34 | self.label_2.setObjectName(_fromUtf8("label_2")) 35 | self.formLayout.setWidget(0, QtGui.QFormLayout.SpanningRole, self.label_2) 36 | self.newAddressLabel = QtGui.QLineEdit(AddAddressDialog) 37 | self.newAddressLabel.setObjectName(_fromUtf8("newAddressLabel")) 38 | self.formLayout.setWidget(2, QtGui.QFormLayout.SpanningRole, self.newAddressLabel) 39 | self.label = QtGui.QLabel(AddAddressDialog) 40 | self.label.setObjectName(_fromUtf8("label")) 41 | self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label) 42 | self.lineEditAddress = QtGui.QLineEdit(AddAddressDialog) 43 | self.lineEditAddress.setObjectName(_fromUtf8("lineEditAddress")) 44 | self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.lineEditAddress) 45 | self.labelAddressCheck = QtGui.QLabel(AddAddressDialog) 46 | self.labelAddressCheck.setText(_fromUtf8("")) 47 | self.labelAddressCheck.setWordWrap(True) 48 | self.labelAddressCheck.setObjectName(_fromUtf8("labelAddressCheck")) 49 | self.formLayout.setWidget(6, QtGui.QFormLayout.SpanningRole, self.labelAddressCheck) 50 | self.buttonBox = QtGui.QDialogButtonBox(AddAddressDialog) 51 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 52 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) 53 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 54 | self.formLayout.setWidget(7, QtGui.QFormLayout.FieldRole, self.buttonBox) 55 | 56 | self.retranslateUi(AddAddressDialog) 57 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), AddAddressDialog.accept) 58 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), AddAddressDialog.reject) 59 | QtCore.QMetaObject.connectSlotsByName(AddAddressDialog) 60 | 61 | def retranslateUi(self, AddAddressDialog): 62 | AddAddressDialog.setWindowTitle(_translate("AddAddressDialog", "Add new entry", None)) 63 | self.label_2.setText(_translate("AddAddressDialog", "Label", None)) 64 | self.label.setText(_translate("AddAddressDialog", "Address", None)) 65 | 66 | -------------------------------------------------------------------------------- /src/bitmessageqt/addaddressdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AddAddressDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 368 10 | 162 11 | 12 | 13 | 14 | Add new entry 15 | 16 | 17 | 18 | QFormLayout::AllNonFixedFieldsGrow 19 | 20 | 21 | 22 | 23 | Label 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Address 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | 52 | 53 | Qt::Horizontal 54 | 55 | 56 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | buttonBox 66 | accepted() 67 | AddAddressDialog 68 | accept() 69 | 70 | 71 | 360 72 | 234 73 | 74 | 75 | 157 76 | 256 77 | 78 | 79 | 80 | 81 | buttonBox 82 | rejected() 83 | AddAddressDialog 84 | reject() 85 | 86 | 87 | 360 88 | 240 89 | 90 | 91 | 286 92 | 256 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/bitmessageqt/addpeer.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 362 10 | 136 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | When you opened this dialog box, you had X peers in your list of peers. 21 | 22 | 23 | 24 | 25 | 26 | 27 | You can manually add a peer here: 28 | 29 | 30 | 31 | 32 | 33 | 34 | IP 35 | 36 | 37 | 38 | 39 | 40 | 41 | Port 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Add 55 | 56 | 57 | 58 | 59 | 60 | 61 | Qt::Horizontal 62 | 63 | 64 | 65 | 47 66 | 20 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Qt::Horizontal 75 | 76 | 77 | QDialogButtonBox::Close 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | buttonBox 87 | accepted() 88 | Dialog 89 | accept() 90 | 91 | 92 | 248 93 | 254 94 | 95 | 96 | 157 97 | 274 98 | 99 | 100 | 101 | 102 | buttonBox 103 | rejected() 104 | Dialog 105 | reject() 106 | 107 | 108 | 316 109 | 260 110 | 111 | 112 | 286 113 | 274 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/bitmessageqt/bitmessage_icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ../images/no_identicons.png 4 | ../images/qidenticon_x.png 5 | ../images/qidenticon.png 6 | ../images/qidenticon_two.png 7 | ../images/qidenticon_two_x.png 8 | ../images/can-icon-24px-yellow.png 9 | ../images/can-icon-24px-red.png 10 | ../images/can-icon-24px-green.png 11 | ../images/can-icon-24px.png 12 | ../images/can-icon-16px.png 13 | ../images/greenicon.png 14 | ../images/redicon.png 15 | ../images/yellowicon.png 16 | ../images/addressbook.png 17 | ../images/blacklist.png 18 | ../images/identities.png 19 | ../images/networkstatus.png 20 | ../images/sent.png 21 | ../images/subscriptions.png 22 | ../images/send.png 23 | ../images/inbox.png 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/bitmessageqt/blacklist.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | blacklist 4 | 5 | 6 | 7 | 0 8 | 0 9 | 819 10 | 295 11 | 12 | 13 | 14 | 15 | 16 | 17 | Use a Blacklist (Allow all incoming messages except those on the Blacklist) 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | Use a Whitelist (Block all incoming messages except those on the Whitelist) 28 | 29 | 30 | 31 | 32 | 33 | 34 | Add new entry 35 | 36 | 37 | 38 | 39 | 40 | 41 | Qt::Horizontal 42 | 43 | 44 | 45 | 689 46 | 20 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | true 55 | 56 | 57 | QAbstractItemView::SingleSelection 58 | 59 | 60 | QAbstractItemView::SelectRows 61 | 62 | 63 | true 64 | 65 | 66 | true 67 | 68 | 69 | 400 70 | 71 | 72 | false 73 | 74 | 75 | false 76 | 77 | 78 | true 79 | 80 | 81 | false 82 | 83 | 84 | 85 | Name or Label 86 | 87 | 88 | 89 | 90 | Address 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | STableWidget 100 | QTableWidget 101 |
bitmessageqt/settingsmixin.h
102 |
103 |
104 | 105 | 106 | 107 | 108 |
109 | -------------------------------------------------------------------------------- /src/bitmessageqt/connect.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'connect.ui' 4 | # 5 | # Created: Wed Jul 24 12:42:01 2013 6 | # by: PyQt4 UI code generator 4.10 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_connectDialog(object): 27 | def setupUi(self, connectDialog): 28 | connectDialog.setObjectName(_fromUtf8("connectDialog")) 29 | connectDialog.resize(400, 124) 30 | self.gridLayout = QtGui.QGridLayout(connectDialog) 31 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 32 | self.label = QtGui.QLabel(connectDialog) 33 | self.label.setObjectName(_fromUtf8("label")) 34 | self.gridLayout.addWidget(self.label, 0, 0, 1, 2) 35 | self.radioButtonConnectNow = QtGui.QRadioButton(connectDialog) 36 | self.radioButtonConnectNow.setChecked(True) 37 | self.radioButtonConnectNow.setObjectName(_fromUtf8("radioButtonConnectNow")) 38 | self.gridLayout.addWidget(self.radioButtonConnectNow, 1, 0, 1, 2) 39 | self.radioButtonConfigureNetwork = QtGui.QRadioButton(connectDialog) 40 | self.radioButtonConfigureNetwork.setObjectName(_fromUtf8("radioButtonConfigureNetwork")) 41 | self.gridLayout.addWidget(self.radioButtonConfigureNetwork, 2, 0, 1, 2) 42 | spacerItem = QtGui.QSpacerItem(185, 24, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) 43 | self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) 44 | self.buttonBox = QtGui.QDialogButtonBox(connectDialog) 45 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 46 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) 47 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 48 | self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) 49 | 50 | self.retranslateUi(connectDialog) 51 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), connectDialog.accept) 52 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), connectDialog.reject) 53 | QtCore.QMetaObject.connectSlotsByName(connectDialog) 54 | 55 | def retranslateUi(self, connectDialog): 56 | connectDialog.setWindowTitle(_translate("connectDialog", "Bitmessage", None)) 57 | self.label.setText(_translate("connectDialog", "Bitmessage won\'t connect to anyone until you let it. ", None)) 58 | self.radioButtonConnectNow.setText(_translate("connectDialog", "Connect now", None)) 59 | self.radioButtonConfigureNetwork.setText(_translate("connectDialog", "Let me configure special network settings first", None)) 60 | 61 | -------------------------------------------------------------------------------- /src/bitmessageqt/connect.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | connectDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 124 11 | 12 | 13 | 14 | Bitmessage 15 | 16 | 17 | 18 | 19 | 20 | Bitmessage won't connect to anyone until you let it. 21 | 22 | 23 | 24 | 25 | 26 | 27 | Connect now 28 | 29 | 30 | true 31 | 32 | 33 | 34 | 35 | 36 | 37 | Let me configure special network settings first 38 | 39 | 40 | 41 | 42 | 43 | 44 | Qt::Horizontal 45 | 46 | 47 | 48 | 185 49 | 24 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | Qt::Horizontal 58 | 59 | 60 | QDialogButtonBox::Ok 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | buttonBox 70 | accepted() 71 | connectDialog 72 | accept() 73 | 74 | 75 | 248 76 | 254 77 | 78 | 79 | 157 80 | 274 81 | 82 | 83 | 84 | 85 | buttonBox 86 | rejected() 87 | connectDialog 88 | reject() 89 | 90 | 91 | 316 92 | 260 93 | 94 | 95 | 286 96 | 274 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /src/bitmessageqt/dialogs.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtCore, QtGui 2 | from addaddressdialog import Ui_AddAddressDialog 3 | from addresses import decodeAddress 4 | from tr import _translate 5 | 6 | 7 | class AddAddressDialog(QtGui.QDialog): 8 | 9 | def __init__(self, parent): 10 | QtGui.QWidget.__init__(self, parent) 11 | self.ui = Ui_AddAddressDialog() 12 | self.ui.setupUi(self) 13 | self.parent = parent 14 | QtCore.QObject.connect(self.ui.lineEditAddress, QtCore.SIGNAL( 15 | "textChanged(QString)"), self.addressChanged) 16 | 17 | def addressChanged(self, QString): 18 | status, a, b, c = decodeAddress(str(QString)) 19 | if status == 'missingbm': 20 | self.ui.labelAddressCheck.setText(_translate( 21 | "MainWindow", "The address should start with ''BM-''")) 22 | elif status == 'checksumfailed': 23 | self.ui.labelAddressCheck.setText(_translate( 24 | "MainWindow", "The address is not typed or copied correctly (the checksum failed).")) 25 | elif status == 'versiontoohigh': 26 | self.ui.labelAddressCheck.setText(_translate( 27 | "MainWindow", "The version number of this address is higher than this software can support. Please upgrade Bitmessage.")) 28 | elif status == 'invalidcharacters': 29 | self.ui.labelAddressCheck.setText(_translate( 30 | "MainWindow", "The address contains invalid characters.")) 31 | elif status == 'ripetooshort': 32 | self.ui.labelAddressCheck.setText(_translate( 33 | "MainWindow", "Some data encoded in the address is too short.")) 34 | elif status == 'ripetoolong': 35 | self.ui.labelAddressCheck.setText(_translate( 36 | "MainWindow", "Some data encoded in the address is too long.")) 37 | elif status == 'varintmalformed': 38 | self.ui.labelAddressCheck.setText(_translate( 39 | "MainWindow", "Some data encoded in the address is malformed.")) 40 | elif status == 'success': 41 | self.ui.labelAddressCheck.setText( 42 | _translate("MainWindow", "Address is valid.")) 43 | -------------------------------------------------------------------------------- /src/bitmessageqt/emailgateway.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | EmailGatewayDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 386 10 | 172 11 | 12 | 13 | 14 | Email gateway 15 | 16 | 17 | 18 | 19 | 20 | true 21 | 22 | 23 | Desired email address (including @mailchuck.com) 24 | 25 | 26 | 27 | 28 | 29 | 30 | Register on email gateway 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 368 42 | 0 43 | 44 | 45 | 46 | Qt::Horizontal 47 | 48 | 49 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 50 | 51 | 52 | 53 | 54 | 55 | 56 | true 57 | 58 | 59 | @mailchuck.com 60 | 61 | 62 | 63 | 64 | 65 | 66 | Email gateway alows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. 67 | 68 | 69 | true 70 | 71 | 72 | 73 | 74 | 75 | 76 | Unregister from email gateway 77 | 78 | 79 | false 80 | 81 | 82 | 83 | 84 | 85 | 86 | radioButtonRegister 87 | lineEditEmailAddress 88 | buttonBox 89 | 90 | 91 | 92 | 93 | buttonBox 94 | accepted() 95 | EmailGatewayDialog 96 | accept() 97 | 98 | 99 | 227 100 | 152 101 | 102 | 103 | 157 104 | 171 105 | 106 | 107 | 108 | 109 | buttonBox 110 | rejected() 111 | EmailGatewayDialog 112 | reject() 113 | 114 | 115 | 295 116 | 158 117 | 118 | 119 | 286 120 | 171 121 | 122 | 123 | 124 | 125 | radioButtonRegister 126 | clicked(bool) 127 | lineEditEmailAddress 128 | setEnabled(bool) 129 | 130 | 131 | 95 132 | 40 133 | 134 | 135 | 94 136 | 123 137 | 138 | 139 | 140 | 141 | radioButtonUnregister 142 | clicked(bool) 143 | lineEditEmailAddress 144 | setDisabled(bool) 145 | 146 | 147 | 139 148 | 19 149 | 150 | 151 | 187 152 | 123 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /src/bitmessageqt/help.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'help.ui' 4 | # 5 | # Created: Wed Jan 14 22:42:39 2015 6 | # by: PyQt4 UI code generator 4.9.4 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_helpDialog(object): 18 | def setupUi(self, helpDialog): 19 | helpDialog.setObjectName(_fromUtf8("helpDialog")) 20 | helpDialog.resize(335, 96) 21 | self.formLayout = QtGui.QFormLayout(helpDialog) 22 | self.formLayout.setObjectName(_fromUtf8("formLayout")) 23 | self.labelHelpURI = QtGui.QLabel(helpDialog) 24 | self.labelHelpURI.setOpenExternalLinks(True) 25 | self.labelHelpURI.setObjectName(_fromUtf8("labelHelpURI")) 26 | self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.labelHelpURI) 27 | self.label = QtGui.QLabel(helpDialog) 28 | self.label.setWordWrap(True) 29 | self.label.setObjectName(_fromUtf8("label")) 30 | self.formLayout.setWidget(0, QtGui.QFormLayout.SpanningRole, self.label) 31 | spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) 32 | self.formLayout.setItem(2, QtGui.QFormLayout.LabelRole, spacerItem) 33 | self.buttonBox = QtGui.QDialogButtonBox(helpDialog) 34 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 35 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) 36 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 37 | self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.buttonBox) 38 | 39 | self.retranslateUi(helpDialog) 40 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), helpDialog.accept) 41 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), helpDialog.reject) 42 | QtCore.QMetaObject.connectSlotsByName(helpDialog) 43 | 44 | def retranslateUi(self, helpDialog): 45 | helpDialog.setWindowTitle(QtGui.QApplication.translate("helpDialog", "Help", None, QtGui.QApplication.UnicodeUTF8)) 46 | self.labelHelpURI.setText(QtGui.QApplication.translate("helpDialog", "https://bitmessage.org/wiki/PyBitmessage_Help", None, QtGui.QApplication.UnicodeUTF8)) 47 | self.label.setText(QtGui.QApplication.translate("helpDialog", "As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki:", None, QtGui.QApplication.UnicodeUTF8)) 48 | 49 | -------------------------------------------------------------------------------- /src/bitmessageqt/help.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | helpDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 405 10 | 104 11 | 12 | 13 | 14 | Help 15 | 16 | 17 | 18 | 19 | 20 | <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | Qt::Horizontal 41 | 42 | 43 | 44 | 40 45 | 20 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Qt::Horizontal 54 | 55 | 56 | QDialogButtonBox::Ok 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | buttonBox 66 | accepted() 67 | helpDialog 68 | accept() 69 | 70 | 71 | 248 72 | 254 73 | 74 | 75 | 157 76 | 274 77 | 78 | 79 | 80 | 81 | buttonBox 82 | rejected() 83 | helpDialog 84 | reject() 85 | 86 | 87 | 316 88 | 260 89 | 90 | 91 | 286 92 | 274 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/bitmessageqt/iconglossary.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | iconGlossaryDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 424 10 | 282 11 | 12 | 13 | 14 | Icon Glossary 15 | 16 | 17 | 18 | 19 | 20 | Icon Glossary 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | :/newPrefix/images/redicon.png 30 | 31 | 32 | 33 | 34 | 35 | 36 | You have no connections with other peers. 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | :/newPrefix/images/yellowicon.png 47 | 48 | 49 | 50 | 51 | 52 | 53 | You have made at least one connection to a peer using an outgoing connection but you have not yet received any incoming connections. Your firewall or home router probably isn't configured to forward incoming TCP connections to your computer. Bitmessage will work just fine but it would help the Bitmessage network if you allowed for incoming connections and will help you be a better-connected node. 54 | 55 | 56 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 57 | 58 | 59 | true 60 | 61 | 62 | 63 | 64 | 65 | 66 | Qt::Vertical 67 | 68 | 69 | 70 | 20 71 | 73 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | You are using TCP port ?. (This can be changed in the settings). 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | :/newPrefix/images/greenicon.png 90 | 91 | 92 | 93 | 94 | 95 | 96 | You do have connections with other peers and your firewall is correctly configured. 97 | 98 | 99 | true 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Qt::Horizontal 110 | 111 | 112 | QDialogButtonBox::Ok 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | buttonBox 124 | accepted() 125 | iconGlossaryDialog 126 | accept() 127 | 128 | 129 | 248 130 | 254 131 | 132 | 133 | 157 134 | 274 135 | 136 | 137 | 138 | 139 | buttonBox 140 | rejected() 141 | iconGlossaryDialog 142 | reject() 143 | 144 | 145 | 316 146 | 260 147 | 148 | 149 | 286 150 | 274 151 | 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /src/bitmessageqt/languagebox.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | from PyQt4 import QtCore, QtGui 4 | 5 | from shared import codePath, config 6 | 7 | class LanguageBox(QtGui.QComboBox): 8 | languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} 9 | def __init__(self, parent = None): 10 | super(QtGui.QComboBox, self).__init__(parent) 11 | self.populate() 12 | 13 | def populate(self): 14 | self.languages = [] 15 | self.clear() 16 | localesPath = os.path.join (codePath(), 'translations') 17 | configuredLocale = "system" 18 | try: 19 | configuredLocale = config.get('bitmessagesettings', 'userlocale', "system") 20 | except: 21 | pass 22 | self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system") 23 | self.setCurrentIndex(0) 24 | self.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) 25 | for translationFile in sorted(glob.glob(os.path.join(localesPath, "bitmessage_*.qm"))): 26 | localeShort = os.path.split(translationFile)[1].split("_", 1)[1][:-3] 27 | locale = QtCore.QLocale(QtCore.QString(localeShort)) 28 | if localeShort in LanguageBox.languageName: 29 | self.addItem(LanguageBox.languageName[localeShort], localeShort) 30 | elif locale.nativeLanguageName() == "": 31 | self.addItem(localeShort, localeShort) 32 | else: 33 | self.addItem(locale.nativeLanguageName(), localeShort) 34 | for i in range(self.count()): 35 | if self.itemData(i) == configuredLocale: 36 | self.setCurrentIndex(i) 37 | break 38 | -------------------------------------------------------------------------------- /src/bitmessageqt/messagecompose.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtCore, QtGui 2 | 3 | class MessageCompose(QtGui.QTextEdit): 4 | 5 | def __init__(self, parent = 0): 6 | super(MessageCompose, self).__init__(parent) 7 | self.setAcceptRichText(False) # we'll deal with this later when we have a new message format 8 | self.defaultFontPointSize = self.currentFont().pointSize() 9 | 10 | def wheelEvent(self, event): 11 | if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: 12 | if event.delta() > 0: 13 | self.zoomIn(1) 14 | else: 15 | self.zoomOut(1) 16 | zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize 17 | QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(str(zoom))) 18 | else: 19 | # in QTextEdit, super does not zoom, only scroll 20 | super(MessageCompose, self).wheelEvent(event) 21 | 22 | def reset(self): 23 | self.setText('') 24 | -------------------------------------------------------------------------------- /src/bitmessageqt/migrationwizard.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | from PyQt4 import QtCore, QtGui 3 | 4 | class MigrationWizardIntroPage(QtGui.QWizardPage): 5 | def __init__(self): 6 | super(QtGui.QWizardPage, self).__init__() 7 | self.setTitle("Migrating configuration") 8 | 9 | label = QtGui.QLabel("This wizard will help you to migrate your configuration. " 10 | "You can still keep using PyBitMessage once you migrate, the changes are backwards compatible.") 11 | label.setWordWrap(True) 12 | 13 | layout = QtGui.QVBoxLayout() 14 | layout.addWidget(label) 15 | self.setLayout(layout) 16 | 17 | def nextId(self): 18 | return 1 19 | 20 | 21 | class MigrationWizardAddressesPage(QtGui.QWizardPage): 22 | def __init__(self, addresses): 23 | super(QtGui.QWizardPage, self).__init__() 24 | self.setTitle("Addresses") 25 | 26 | label = QtGui.QLabel("Please select addresses that you are already using with mailchuck. ") 27 | label.setWordWrap(True) 28 | 29 | layout = QtGui.QVBoxLayout() 30 | layout.addWidget(label) 31 | self.setLayout(layout) 32 | 33 | def nextId(self): 34 | return 10 35 | 36 | 37 | class MigrationWizardGPUPage(QtGui.QWizardPage): 38 | def __init__(self): 39 | super(QtGui.QWizardPage, self).__init__() 40 | self.setTitle("GPU") 41 | 42 | label = QtGui.QLabel("Are you using a GPU? ") 43 | label.setWordWrap(True) 44 | 45 | layout = QtGui.QVBoxLayout() 46 | layout.addWidget(label) 47 | self.setLayout(layout) 48 | 49 | def nextId(self): 50 | return 10 51 | 52 | 53 | class MigrationWizardConclusionPage(QtGui.QWizardPage): 54 | def __init__(self): 55 | super(QtGui.QWizardPage, self).__init__() 56 | self.setTitle("All done!") 57 | 58 | label = QtGui.QLabel("You successfully migrated.") 59 | label.setWordWrap(True) 60 | 61 | layout = QtGui.QVBoxLayout() 62 | layout.addWidget(label) 63 | self.setLayout(layout) 64 | 65 | 66 | class Ui_MigrationWizard(QtGui.QWizard): 67 | def __init__(self, addresses): 68 | super(QtGui.QWizard, self).__init__() 69 | 70 | self.pages = {} 71 | 72 | page = MigrationWizardIntroPage() 73 | self.setPage(0, page) 74 | self.setStartId(0) 75 | page = MigrationWizardAddressesPage(addresses) 76 | self.setPage(1, page) 77 | page = MigrationWizardGPUPage() 78 | self.setPage(2, page) 79 | page = MigrationWizardConclusionPage() 80 | self.setPage(10, page) 81 | 82 | self.setWindowTitle("Migration from PyBitMessage wizard") 83 | self.adjustSize() 84 | self.show() -------------------------------------------------------------------------------- /src/bitmessageqt/newsubscriptiondialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'newsubscriptiondialog.ui' 4 | # 5 | # Created: Sat Nov 30 21:53:38 2013 6 | # by: PyQt4 UI code generator 4.10.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_NewSubscriptionDialog(object): 27 | def setupUi(self, NewSubscriptionDialog): 28 | NewSubscriptionDialog.setObjectName(_fromUtf8("NewSubscriptionDialog")) 29 | NewSubscriptionDialog.resize(368, 173) 30 | self.formLayout = QtGui.QFormLayout(NewSubscriptionDialog) 31 | self.formLayout.setObjectName(_fromUtf8("formLayout")) 32 | self.label_2 = QtGui.QLabel(NewSubscriptionDialog) 33 | self.label_2.setObjectName(_fromUtf8("label_2")) 34 | self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_2) 35 | self.newsubscriptionlabel = QtGui.QLineEdit(NewSubscriptionDialog) 36 | self.newsubscriptionlabel.setObjectName(_fromUtf8("newsubscriptionlabel")) 37 | self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.newsubscriptionlabel) 38 | self.label = QtGui.QLabel(NewSubscriptionDialog) 39 | self.label.setObjectName(_fromUtf8("label")) 40 | self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label) 41 | self.lineEditSubscriptionAddress = QtGui.QLineEdit(NewSubscriptionDialog) 42 | self.lineEditSubscriptionAddress.setObjectName(_fromUtf8("lineEditSubscriptionAddress")) 43 | self.formLayout.setWidget(3, QtGui.QFormLayout.SpanningRole, self.lineEditSubscriptionAddress) 44 | self.labelAddressCheck = QtGui.QLabel(NewSubscriptionDialog) 45 | self.labelAddressCheck.setText(_fromUtf8("")) 46 | self.labelAddressCheck.setWordWrap(True) 47 | self.labelAddressCheck.setObjectName(_fromUtf8("labelAddressCheck")) 48 | self.formLayout.setWidget(4, QtGui.QFormLayout.SpanningRole, self.labelAddressCheck) 49 | self.checkBoxDisplayMessagesAlreadyInInventory = QtGui.QCheckBox(NewSubscriptionDialog) 50 | self.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(False) 51 | self.checkBoxDisplayMessagesAlreadyInInventory.setObjectName(_fromUtf8("checkBoxDisplayMessagesAlreadyInInventory")) 52 | self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.checkBoxDisplayMessagesAlreadyInInventory) 53 | self.buttonBox = QtGui.QDialogButtonBox(NewSubscriptionDialog) 54 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 55 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) 56 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 57 | self.formLayout.setWidget(6, QtGui.QFormLayout.FieldRole, self.buttonBox) 58 | 59 | self.retranslateUi(NewSubscriptionDialog) 60 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewSubscriptionDialog.accept) 61 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), NewSubscriptionDialog.reject) 62 | QtCore.QMetaObject.connectSlotsByName(NewSubscriptionDialog) 63 | 64 | def retranslateUi(self, NewSubscriptionDialog): 65 | NewSubscriptionDialog.setWindowTitle(_translate("NewSubscriptionDialog", "Add new entry", None)) 66 | self.label_2.setText(_translate("NewSubscriptionDialog", "Label", None)) 67 | self.label.setText(_translate("NewSubscriptionDialog", "Address", None)) 68 | self.checkBoxDisplayMessagesAlreadyInInventory.setText(_translate("NewSubscriptionDialog", "Enter an address above.", None)) 69 | 70 | -------------------------------------------------------------------------------- /src/bitmessageqt/newsubscriptiondialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | NewSubscriptionDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 368 10 | 173 11 | 12 | 13 | 14 | Add new entry 15 | 16 | 17 | 18 | 19 | 20 | Label 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | Address 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | true 44 | 45 | 46 | 47 | 48 | 49 | 50 | false 51 | 52 | 53 | CheckBox 54 | 55 | 56 | 57 | 58 | 59 | 60 | Qt::Horizontal 61 | 62 | 63 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | buttonBox 73 | accepted() 74 | NewSubscriptionDialog 75 | accept() 76 | 77 | 78 | 360 79 | 234 80 | 81 | 82 | 157 83 | 256 84 | 85 | 86 | 87 | 88 | buttonBox 89 | rejected() 90 | NewSubscriptionDialog 91 | reject() 92 | 93 | 94 | 360 95 | 240 96 | 97 | 98 | 286 99 | 256 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/bitmessageqt/retranslateui.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from PyQt4 import QtGui 3 | from debug import logger 4 | import widgets 5 | 6 | class RetranslateMixin(object): 7 | def retranslateUi(self): 8 | defaults = QtGui.QWidget() 9 | widgets.load(self.__class__.__name__.lower() + '.ui', defaults) 10 | for attr, value in defaults.__dict__.iteritems(): 11 | setTextMethod = getattr(value, "setText", None) 12 | if callable(setTextMethod): 13 | getattr(self, attr).setText(getattr(defaults, attr).text()) 14 | elif isinstance(value, QtGui.QTableWidget): 15 | for i in range (value.columnCount()): 16 | getattr(self, attr).horizontalHeaderItem(i).setText(getattr(defaults, attr).horizontalHeaderItem(i).text()) 17 | for i in range (value.rowCount()): 18 | getattr(self, attr).verticalHeaderItem(i).setText(getattr(defaults, attr).verticalHeaderItem(i).text()) 19 | -------------------------------------------------------------------------------- /src/bitmessageqt/safehtmlparser.py: -------------------------------------------------------------------------------- 1 | from HTMLParser import HTMLParser 2 | import inspect 3 | import re 4 | from urllib import quote, quote_plus 5 | from urlparse import urlparse 6 | 7 | class SafeHTMLParser(HTMLParser): 8 | # from html5lib.sanitiser 9 | acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', 10 | 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', 11 | 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 12 | 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', 13 | 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', 14 | 'figcaption', 'figure', 'footer', 'font', 'header', 'h1', 15 | 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', 16 | 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter', 17 | 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option', 18 | 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', 19 | 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 20 | 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 21 | 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] 22 | replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] 23 | src_schemes = [ "data" ] 24 | uriregex1 = re.compile(r'(?i)\b((?:(https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?]))') 25 | uriregex2 = re.compile(r' 1 and text[0] == " ": 33 | text = " " + text[1:] 34 | return text 35 | 36 | def __init__(self, *args, **kwargs): 37 | HTMLParser.__init__(self, *args, **kwargs) 38 | self.reset_safe() 39 | 40 | def reset_safe(self): 41 | self.elements = set() 42 | self.raw = u"" 43 | self.sanitised = u"" 44 | self.has_html = False 45 | self.allow_picture = False 46 | self.allow_external_src = False 47 | 48 | def add_if_acceptable(self, tag, attrs = None): 49 | if not tag in SafeHTMLParser.acceptable_elements: 50 | return 51 | self.sanitised += "<" 52 | if inspect.stack()[1][3] == "handle_endtag": 53 | self.sanitised += "/" 54 | self.sanitised += tag 55 | if not attrs is None: 56 | for attr, val in attrs: 57 | if tag == "img" and attr == "src" and not self.allow_picture: 58 | val = "" 59 | elif attr == "src" and not self.allow_external_src: 60 | url = urlparse(val) 61 | if url.scheme not in SafeHTMLParser.src_schemes: 62 | val == "" 63 | self.sanitised += " " + quote_plus(attr) 64 | if not (val is None): 65 | self.sanitised += "=\"" + val + "\"" 66 | if inspect.stack()[1][3] == "handle_startendtag": 67 | self.sanitised += "/" 68 | self.sanitised += ">" 69 | 70 | def handle_starttag(self, tag, attrs): 71 | if tag in SafeHTMLParser.acceptable_elements: 72 | self.has_html = True 73 | self.add_if_acceptable(tag, attrs) 74 | 75 | def handle_endtag(self, tag): 76 | self.add_if_acceptable(tag) 77 | 78 | def handle_startendtag(self, tag, attrs): 79 | if tag in SafeHTMLParser.acceptable_elements: 80 | self.has_html = True 81 | self.add_if_acceptable(tag, attrs) 82 | 83 | def handle_data(self, data): 84 | self.sanitised += unicode(data, 'utf-8', 'replace') 85 | 86 | def handle_charref(self, name): 87 | self.sanitised += "&#" + name + ";" 88 | 89 | def handle_entityref(self, name): 90 | self.sanitised += "&" + name + ";" 91 | 92 | def feed(self, data): 93 | HTMLParser.feed(self, data) 94 | tmp = SafeHTMLParser.multi_replace(data) 95 | tmp = SafeHTMLParser.uriregex1.sub( 96 | r'\1', 97 | unicode(tmp, 'utf-8', 'replace')) 98 | tmp = SafeHTMLParser.uriregex2.sub(r'\1', tmp) 100 | self.raw += tmp 101 | 102 | def is_html(self, text = None, allow_picture = False): 103 | if text: 104 | self.reset() 105 | self.reset_safe() 106 | self.allow_picture = allow_picture 107 | self.feed(text) 108 | self.close() 109 | return self.has_html 110 | -------------------------------------------------------------------------------- /src/bitmessageqt/settingsmixin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | from PyQt4 import QtCore, QtGui 4 | 5 | class SettingsMixin(object): 6 | def warnIfNoObjectName(self): 7 | if self.objectName() == "": 8 | # TODO: logger 9 | pass 10 | 11 | def writeState(self, source): 12 | self.warnIfNoObjectName() 13 | settings = QtCore.QSettings() 14 | settings.beginGroup(self.objectName()) 15 | settings.setValue("state", source.saveState()) 16 | settings.endGroup() 17 | 18 | def writeGeometry(self, source): 19 | self.warnIfNoObjectName() 20 | settings = QtCore.QSettings() 21 | settings.beginGroup(self.objectName()) 22 | settings.setValue("geometry", source.saveGeometry()) 23 | settings.endGroup() 24 | 25 | def readGeometry(self, target): 26 | self.warnIfNoObjectName() 27 | settings = QtCore.QSettings() 28 | try: 29 | geom = settings.value("/".join([str(self.objectName()), "geometry"])) 30 | target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom) 31 | except Exception as e: 32 | pass 33 | 34 | def readState(self, target): 35 | self.warnIfNoObjectName() 36 | settings = QtCore.QSettings() 37 | try: 38 | state = settings.value("/".join([str(self.objectName()), "state"])) 39 | target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state) 40 | except Exception as e: 41 | pass 42 | 43 | 44 | class SMainWindow(QtGui.QMainWindow, SettingsMixin): 45 | def loadSettings(self): 46 | self.readGeometry(self) 47 | self.readState(self) 48 | 49 | def saveSettings(self): 50 | self.writeState(self) 51 | self.writeGeometry(self) 52 | 53 | 54 | class STableWidget(QtGui.QTableWidget, SettingsMixin): 55 | def loadSettings(self): 56 | self.readState(self.horizontalHeader()) 57 | 58 | def saveSettings(self): 59 | self.writeState(self.horizontalHeader()) 60 | 61 | 62 | class SSplitter(QtGui.QSplitter, SettingsMixin): 63 | def loadSettings(self): 64 | self.readState(self) 65 | 66 | def saveSettings(self): 67 | self.writeState(self) 68 | 69 | 70 | class STreeWidget(QtGui.QTreeWidget, SettingsMixin): 71 | def loadSettings(self): 72 | #recurse children 73 | #self.readState(self) 74 | pass 75 | 76 | def saveSettings(self): 77 | #recurse children 78 | #self.writeState(self) 79 | pass 80 | -------------------------------------------------------------------------------- /src/bitmessageqt/specialaddressbehavior.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'specialaddressbehavior.ui' 4 | # 5 | # Created: Fri Apr 26 17:43:31 2013 6 | # by: PyQt4 UI code generator 4.9.4 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | _fromUtf8 = lambda s: s 16 | 17 | class Ui_SpecialAddressBehaviorDialog(object): 18 | def setupUi(self, SpecialAddressBehaviorDialog): 19 | SpecialAddressBehaviorDialog.setObjectName(_fromUtf8("SpecialAddressBehaviorDialog")) 20 | SpecialAddressBehaviorDialog.resize(386, 172) 21 | self.gridLayout = QtGui.QGridLayout(SpecialAddressBehaviorDialog) 22 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 23 | self.radioButtonBehaveNormalAddress = QtGui.QRadioButton(SpecialAddressBehaviorDialog) 24 | self.radioButtonBehaveNormalAddress.setChecked(True) 25 | self.radioButtonBehaveNormalAddress.setObjectName(_fromUtf8("radioButtonBehaveNormalAddress")) 26 | self.gridLayout.addWidget(self.radioButtonBehaveNormalAddress, 0, 0, 1, 1) 27 | self.radioButtonBehaviorMailingList = QtGui.QRadioButton(SpecialAddressBehaviorDialog) 28 | self.radioButtonBehaviorMailingList.setObjectName(_fromUtf8("radioButtonBehaviorMailingList")) 29 | self.gridLayout.addWidget(self.radioButtonBehaviorMailingList, 1, 0, 1, 1) 30 | self.label = QtGui.QLabel(SpecialAddressBehaviorDialog) 31 | self.label.setWordWrap(True) 32 | self.label.setObjectName(_fromUtf8("label")) 33 | self.gridLayout.addWidget(self.label, 2, 0, 1, 1) 34 | self.label_2 = QtGui.QLabel(SpecialAddressBehaviorDialog) 35 | self.label_2.setObjectName(_fromUtf8("label_2")) 36 | self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1) 37 | self.lineEditMailingListName = QtGui.QLineEdit(SpecialAddressBehaviorDialog) 38 | self.lineEditMailingListName.setEnabled(False) 39 | self.lineEditMailingListName.setObjectName(_fromUtf8("lineEditMailingListName")) 40 | self.gridLayout.addWidget(self.lineEditMailingListName, 4, 0, 1, 1) 41 | self.buttonBox = QtGui.QDialogButtonBox(SpecialAddressBehaviorDialog) 42 | self.buttonBox.setMinimumSize(QtCore.QSize(368, 0)) 43 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 44 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) 45 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 46 | self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 1) 47 | 48 | self.retranslateUi(SpecialAddressBehaviorDialog) 49 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), SpecialAddressBehaviorDialog.accept) 50 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), SpecialAddressBehaviorDialog.reject) 51 | QtCore.QObject.connect(self.radioButtonBehaviorMailingList, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditMailingListName.setEnabled) 52 | QtCore.QObject.connect(self.radioButtonBehaveNormalAddress, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditMailingListName.setDisabled) 53 | QtCore.QMetaObject.connectSlotsByName(SpecialAddressBehaviorDialog) 54 | SpecialAddressBehaviorDialog.setTabOrder(self.radioButtonBehaveNormalAddress, self.radioButtonBehaviorMailingList) 55 | SpecialAddressBehaviorDialog.setTabOrder(self.radioButtonBehaviorMailingList, self.lineEditMailingListName) 56 | SpecialAddressBehaviorDialog.setTabOrder(self.lineEditMailingListName, self.buttonBox) 57 | 58 | def retranslateUi(self, SpecialAddressBehaviorDialog): 59 | SpecialAddressBehaviorDialog.setWindowTitle(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Special Address Behavior", None, QtGui.QApplication.UnicodeUTF8)) 60 | self.radioButtonBehaveNormalAddress.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Behave as a normal address", None, QtGui.QApplication.UnicodeUTF8)) 61 | self.radioButtonBehaviorMailingList.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Behave as a pseudo-mailing-list address", None, QtGui.QApplication.UnicodeUTF8)) 62 | self.label.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public).", None, QtGui.QApplication.UnicodeUTF8)) 63 | self.label_2.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Name of the pseudo-mailing-list:", None, QtGui.QApplication.UnicodeUTF8)) 64 | 65 | -------------------------------------------------------------------------------- /src/bitmessageqt/specialaddressbehavior.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SpecialAddressBehaviorDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 386 10 | 172 11 | 12 | 13 | 14 | Special Address Behavior 15 | 16 | 17 | 18 | 19 | 20 | Behave as a normal address 21 | 22 | 23 | true 24 | 25 | 26 | 27 | 28 | 29 | 30 | Behave as a pseudo-mailing-list address 31 | 32 | 33 | 34 | 35 | 36 | 37 | Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). 38 | 39 | 40 | true 41 | 42 | 43 | 44 | 45 | 46 | 47 | Name of the pseudo-mailing-list: 48 | 49 | 50 | 51 | 52 | 53 | 54 | false 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 368 63 | 0 64 | 65 | 66 | 67 | Qt::Horizontal 68 | 69 | 70 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 71 | 72 | 73 | 74 | 75 | 76 | 77 | radioButtonBehaveNormalAddress 78 | radioButtonBehaviorMailingList 79 | lineEditMailingListName 80 | buttonBox 81 | 82 | 83 | 84 | 85 | buttonBox 86 | accepted() 87 | SpecialAddressBehaviorDialog 88 | accept() 89 | 90 | 91 | 227 92 | 152 93 | 94 | 95 | 157 96 | 171 97 | 98 | 99 | 100 | 101 | buttonBox 102 | rejected() 103 | SpecialAddressBehaviorDialog 104 | reject() 105 | 106 | 107 | 295 108 | 158 109 | 110 | 111 | 286 112 | 171 113 | 114 | 115 | 116 | 117 | radioButtonBehaviorMailingList 118 | clicked(bool) 119 | lineEditMailingListName 120 | setEnabled(bool) 121 | 122 | 123 | 95 124 | 40 125 | 126 | 127 | 94 128 | 123 129 | 130 | 131 | 132 | 133 | radioButtonBehaveNormalAddress 134 | clicked(bool) 135 | lineEditMailingListName 136 | setDisabled(bool) 137 | 138 | 139 | 139 140 | 19 141 | 142 | 143 | 187 144 | 123 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /src/bitmessageqt/support.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | from PyQt4 import QtCore, QtGui 3 | import ssl 4 | import sys 5 | import time 6 | 7 | import account 8 | from debug import logger 9 | from foldertree import AccountMixin 10 | from helper_sql import * 11 | from l10n import getTranslationLanguage 12 | from openclpow import has_opencl 13 | from proofofwork import bmpow 14 | from pyelliptic.openssl import OpenSSL 15 | import shared 16 | 17 | # this is BM support address going to Peter Surda 18 | SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' 19 | SUPPORT_LABEL = 'PyBitmessage support' 20 | SUPPORT_MY_LABEL = 'My new address' 21 | SUPPORT_SUBJECT = 'Support request' 22 | SUPPORT_MESSAGE = '''You can use this message to send a report to one of the PyBitmessage core developers regarding PyBitmessage or the mailchuck.com email service. If you are using PyBitmessage involuntarily, for example because your computer was infected with ransomware, this is not an appropriate venue for resolving such issues. 23 | 24 | Please describe what you are trying to do: 25 | 26 | Please describe what you expect to happen: 27 | 28 | Please describe what happens instead: 29 | 30 | 31 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 32 | Please write above this line and if possible, keep the information about your environment below intact. 33 | 34 | PyBitmesage version: {} 35 | Operating system: {} 36 | Architecture: {}bit 37 | Python Version: {} 38 | OpenSSL Version: {} 39 | Frozen: {} 40 | Portable mode: {} 41 | C PoW: {} 42 | OpenCL PoW: {} 43 | Locale: {} 44 | SOCKS: {} 45 | UPnP: {} 46 | Connected hosts: {} 47 | ''' 48 | 49 | def checkAddressBook(myapp): 50 | queryreturn = sqlQuery('''SELECT * FROM addressbook WHERE address=?''', SUPPORT_ADDRESS) 51 | if queryreturn == []: 52 | sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', str(QtGui.QApplication.translate("Support", SUPPORT_LABEL)), SUPPORT_ADDRESS) 53 | myapp.rerenderAddressBook() 54 | 55 | def checkHasNormalAddress(): 56 | for address in account.getSortedAccounts(): 57 | acct = account.accountClass(address) 58 | if acct.type == AccountMixin.NORMAL and shared.safeConfigGetBoolean(address, 'enabled'): 59 | return address 60 | return False 61 | 62 | def createAddressIfNeeded(myapp): 63 | if not checkHasNormalAddress(): 64 | shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, shared.networkDefaultProofOfWorkNonceTrialsPerByte, shared.networkDefaultPayloadLengthExtraBytes)) 65 | while shared.shutdown == 0 and not checkHasNormalAddress(): 66 | time.sleep(.2) 67 | myapp.rerenderComboBoxSendFrom() 68 | return checkHasNormalAddress() 69 | 70 | def createSupportMessage(myapp): 71 | checkAddressBook(myapp) 72 | address = createAddressIfNeeded(myapp) 73 | if shared.shutdown: 74 | return 75 | 76 | myapp.ui.lineEditSubject.setText(str(QtGui.QApplication.translate("Support", SUPPORT_SUBJECT))) 77 | addrIndex = myapp.ui.comboBoxSendFrom.findData(address, QtCore.Qt.UserRole, QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive) 78 | if addrIndex == -1: # something is very wrong 79 | return 80 | myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) 81 | myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) 82 | 83 | version = shared.softwareVersion 84 | os = sys.platform 85 | if os == "win32": 86 | windowsversion = sys.getwindowsversion() 87 | os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1]) 88 | else: 89 | try: 90 | from os import uname 91 | unixversion = uname() 92 | os = unixversion[0] + " " + unixversion[2] 93 | except: 94 | pass 95 | architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" 96 | pythonversion = sys.version 97 | 98 | SSLEAY_VERSION = 0 99 | OpenSSL._lib.SSLeay.restype = ctypes.c_long 100 | OpenSSL._lib.SSLeay_version.restype = ctypes.c_char_p 101 | OpenSSL._lib.SSLeay_version.argtypes = [ctypes.c_int] 102 | opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) 103 | 104 | frozen = "N/A" 105 | if shared.frozen: 106 | frozen = shared.frozen 107 | portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" 108 | cpow = "True" if bmpow else "False" 109 | #cpow = QtGui.QApplication.translate("Support", cpow) 110 | openclpow = "True" if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and has_opencl() else "False" 111 | #openclpow = QtGui.QApplication.translate("Support", openclpow) 112 | locale = getTranslationLanguage() 113 | try: 114 | socks = shared.config.get('bitmessagesettings', 'socksproxytype') 115 | except: 116 | socks = "N/A" 117 | try: 118 | upnp = shared.config.get('bitmessagesettings', 'upnp') 119 | except: 120 | upnp = "N/A" 121 | connectedhosts = len(shared.connectedHostsList) 122 | 123 | myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, pythonversion, opensslversion, frozen, portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts)) 124 | 125 | # single msg tab 126 | myapp.ui.tabWidgetSend.setCurrentIndex(0) 127 | # send tab 128 | myapp.ui.tabWidget.setCurrentIndex(1) 129 | -------------------------------------------------------------------------------- /src/bitmessageqt/uisignaler.py: -------------------------------------------------------------------------------- 1 | 2 | from PyQt4.QtCore import QThread, SIGNAL 3 | import shared 4 | import sys 5 | 6 | 7 | class UISignaler(QThread): 8 | _instance = None 9 | 10 | def __init__(self, parent=None): 11 | QThread.__init__(self, parent) 12 | 13 | @classmethod 14 | def get(cls): 15 | if not cls._instance: 16 | cls._instance = UISignaler() 17 | return cls._instance 18 | 19 | def run(self): 20 | while True: 21 | command, data = shared.UISignalQueue.get() 22 | if command == 'writeNewAddressToTable': 23 | label, address, streamNumber = data 24 | self.emit(SIGNAL( 25 | "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), label, address, str(streamNumber)) 26 | elif command == 'updateStatusBar': 27 | self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data) 28 | elif command == 'updateSentItemStatusByToAddress': 29 | toAddress, message = data 30 | self.emit(SIGNAL( 31 | "updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message) 32 | elif command == 'updateSentItemStatusByAckdata': 33 | ackData, message = data 34 | self.emit(SIGNAL( 35 | "updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), ackData, message) 36 | elif command == 'displayNewInboxMessage': 37 | inventoryHash, toAddress, fromAddress, subject, body = data 38 | self.emit(SIGNAL( 39 | "displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), 40 | inventoryHash, toAddress, fromAddress, subject, body) 41 | elif command == 'displayNewSentMessage': 42 | toAddress, fromLabel, fromAddress, subject, message, ackdata = data 43 | self.emit(SIGNAL( 44 | "displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), 45 | toAddress, fromLabel, fromAddress, subject, message, ackdata) 46 | elif command == 'updateNetworkStatusTab': 47 | self.emit(SIGNAL("updateNetworkStatusTab()")) 48 | elif command == 'updateNumberOfMessagesProcessed': 49 | self.emit(SIGNAL("updateNumberOfMessagesProcessed()")) 50 | elif command == 'updateNumberOfPubkeysProcessed': 51 | self.emit(SIGNAL("updateNumberOfPubkeysProcessed()")) 52 | elif command == 'updateNumberOfBroadcastsProcessed': 53 | self.emit(SIGNAL("updateNumberOfBroadcastsProcessed()")) 54 | elif command == 'setStatusIcon': 55 | self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"), data) 56 | elif command == 'changedInboxUnread': 57 | self.emit(SIGNAL("changedInboxUnread(PyQt_PyObject)"), data) 58 | elif command == 'rerenderMessagelistFromLabels': 59 | self.emit(SIGNAL("rerenderMessagelistFromLabels()")) 60 | elif command == 'rerenderMessagelistToLabels': 61 | self.emit(SIGNAL("rerenderMessagelistToLabels()")) 62 | elif command == 'rerenderAddressBook': 63 | self.emit(SIGNAL("rerenderAddressBook()")) 64 | elif command == 'rerenderSubscriptions': 65 | self.emit(SIGNAL("rerenderSubscriptions()")) 66 | elif command == 'rerenderBlackWhiteList': 67 | self.emit(SIGNAL("rerenderBlackWhiteList()")) 68 | elif command == 'removeInboxRowByMsgid': 69 | self.emit(SIGNAL("removeInboxRowByMsgid(PyQt_PyObject)"), data) 70 | elif command == 'newVersionAvailable': 71 | self.emit(SIGNAL("newVersionAvailable(PyQt_PyObject)"), data) 72 | elif command == 'alert': 73 | title, text, exitAfterUserClicksOk = data 74 | self.emit(SIGNAL("displayAlert(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), title, text, exitAfterUserClicksOk) 75 | else: 76 | sys.stderr.write( 77 | 'Command sent to UISignaler not recognized: %s\n' % command) 78 | -------------------------------------------------------------------------------- /src/bitmessageqt/utils.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import QtGui 2 | import hashlib 3 | import os 4 | import shared 5 | from addresses import addBMIfNotPresent 6 | 7 | str_broadcast_subscribers = '[Broadcast subscribers]' 8 | 9 | def identiconize(address): 10 | size = 48 11 | 12 | # If you include another identicon library, please generate an 13 | # example identicon with the following md5 hash: 14 | # 3fd4bf901b9d4ea1394f0fb358725b28 15 | 16 | try: 17 | identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib') 18 | except: 19 | # default to qidenticon_two_x 20 | identicon_lib = 'qidenticon_two_x' 21 | 22 | # As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.) 23 | # It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk 24 | # of attacks where someone creates an address to mimic someone else's identicon. 25 | identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix') 26 | 27 | if not shared.config.getboolean('bitmessagesettings', 'useidenticons'): 28 | idcon = QtGui.QIcon() 29 | return idcon 30 | 31 | if (identicon_lib[:len('qidenticon')] == 'qidenticon'): 32 | # print identicon_lib 33 | # originally by: 34 | # :Author:Shin Adachi 35 | # Licesensed under FreeBSD License. 36 | # stripped from PIL and uses QT instead (by sendiulo, same license) 37 | import qidenticon 38 | hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest() 39 | use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two') 40 | opacity = int(not((identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x') | (identicon_lib == 'qidenticon_b') | (identicon_lib == 'qidenticon_two_b')))*255 41 | penwidth = 0 42 | image = qidenticon.render_identicon(int(hash, 16), size, use_two_colors, opacity, penwidth) 43 | # filename = './images/identicons/'+hash+'.png' 44 | # image.save(filename) 45 | idcon = QtGui.QIcon() 46 | idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off) 47 | return idcon 48 | elif identicon_lib == 'pydenticon': 49 | # print identicon_lib 50 | # Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source) 51 | from pydenticon import Pydenticon 52 | # It is not included in the source, because it is licensed under GPLv3 53 | # GPLv3 is a copyleft license that would influence our licensing 54 | # Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py 55 | # note that it requires PIL to be installed: http://www.pythonware.com/products/pil/ 56 | idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size*3) 57 | rendering = idcon_render._render() 58 | data = rendering.convert("RGBA").tostring("raw", "RGBA") 59 | qim = QImage(data, size, size, QImage.Format_ARGB32) 60 | pix = QPixmap.fromImage(qim) 61 | idcon = QtGui.QIcon() 62 | idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off) 63 | return idcon 64 | 65 | def avatarize(address): 66 | """ 67 | loads a supported image for the given address' hash form 'avatars' folder 68 | falls back to default avatar if 'default.*' file exists 69 | falls back to identiconize(address) 70 | """ 71 | idcon = QtGui.QIcon() 72 | hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest() 73 | str_broadcast_subscribers = '[Broadcast subscribers]' 74 | if address == str_broadcast_subscribers: 75 | # don't hash [Broadcast subscribers] 76 | hash = address 77 | # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats 78 | # print QImageReader.supportedImageFormats () 79 | # QImageReader.supportedImageFormats () 80 | extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] 81 | # try to find a specific avatar 82 | for ext in extensions: 83 | lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower() 84 | upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper() 85 | if os.path.isfile(lower_hash): 86 | # print 'found avatar of ', address 87 | idcon.addFile(lower_hash) 88 | return idcon 89 | elif os.path.isfile(upper_hash): 90 | # print 'found avatar of ', address 91 | idcon.addFile(upper_hash) 92 | return idcon 93 | # if we haven't found any, try to find a default avatar 94 | for ext in extensions: 95 | lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower() 96 | upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper() 97 | if os.path.isfile(lower_default): 98 | default = lower_default 99 | idcon.addFile(lower_default) 100 | return idcon 101 | elif os.path.isfile(upper_default): 102 | default = upper_default 103 | idcon.addFile(upper_default) 104 | return idcon 105 | # If no avatar is found 106 | return identiconize(address) 107 | -------------------------------------------------------------------------------- /src/bitmessageqt/widgets.py: -------------------------------------------------------------------------------- 1 | from PyQt4 import uic 2 | import os.path 3 | import sys 4 | from shared import codePath 5 | 6 | def resource_path(resFile): 7 | baseDir = codePath() 8 | for subDir in ["ui", "bitmessageqt"]: 9 | if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)): 10 | return os.path.join(baseDir, subDir, resFile) 11 | 12 | def load(resFile, widget): 13 | uic.loadUi(resource_path(resFile), widget) 14 | -------------------------------------------------------------------------------- /src/bitmsghash/Makefile: -------------------------------------------------------------------------------- 1 | UNAME_S := $(shell uname -s) 2 | ifeq ($(UNAME_S),Darwin) 3 | CCFLAGS += -I/usr/local/Cellar/openssl/1.0.2d_1/include 4 | LDFLAGS += -L/usr/local/Cellar/openssl/1.0.2d_1/lib 5 | endif 6 | 7 | all: bitmsghash.so 8 | 9 | powtest: 10 | ./testpow.py 11 | 12 | bitmsghash.so: bitmsghash.o 13 | g++ bitmsghash.o -shared -fPIC -lpthread -lcrypto $(LDFLAGS) -o bitmsghash.so 14 | 15 | bitmsghash.o: 16 | g++ -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp 17 | 18 | clean: 19 | rm -f bitmsghash.o bitmsghash.so 20 | 21 | -------------------------------------------------------------------------------- /src/bitmsghash/bitmsghash.cpp: -------------------------------------------------------------------------------- 1 | // bitmessage cracker, build with g++ or MSVS to a shared library, use included python code for usage under bitmessage 2 | #ifdef _WIN32 3 | #include "Winsock.h" 4 | #include "Windows.h" 5 | #define uint64_t unsigned __int64 6 | #else 7 | #include 8 | #include 9 | #include 10 | #endif 11 | #include 12 | #include 13 | #include 14 | #ifdef __APPLE__ 15 | #include 16 | #include 17 | #endif 18 | 19 | #include "openssl/sha.h" 20 | 21 | #define HASH_SIZE 64 22 | #define BUFLEN 16384 23 | 24 | #if defined(__GNUC__) 25 | #define EXPORT __attribute__ ((__visibility__("default"))) 26 | #elif defined(_WIN32) 27 | #define EXPORT __declspec(dllexport) 28 | #endif 29 | 30 | #ifndef __APPLE__ 31 | #define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) ) 32 | #endif 33 | 34 | unsigned long long max_val; 35 | unsigned char *initialHash; 36 | unsigned long long successval = 0; 37 | unsigned int numthreads = 0; 38 | 39 | #ifdef _WIN32 40 | DWORD WINAPI threadfunc(LPVOID param) { 41 | #else 42 | void * threadfunc(void* param) { 43 | #endif 44 | unsigned int incamt = *((unsigned int*)param); 45 | SHA512_CTX sha; 46 | unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 }; 47 | unsigned char output[HASH_SIZE] = { 0 }; 48 | 49 | memcpy(buf + sizeof(uint64_t), initialHash, HASH_SIZE); 50 | 51 | unsigned long long tmpnonce = incamt; 52 | unsigned long long * nonce = (unsigned long long *)buf; 53 | unsigned long long * hash = (unsigned long long *)output; 54 | while (successval == 0) { 55 | tmpnonce += numthreads; 56 | 57 | (*nonce) = ntohll(tmpnonce); /* increment nonce */ 58 | SHA512_Init(&sha); 59 | SHA512_Update(&sha, buf, HASH_SIZE + sizeof(uint64_t)); 60 | SHA512_Final(output, &sha); 61 | SHA512_Init(&sha); 62 | SHA512_Update(&sha, output, HASH_SIZE); 63 | SHA512_Final(output, &sha); 64 | 65 | if (ntohll(*hash) < max_val) { 66 | successval = tmpnonce; 67 | } 68 | } 69 | return NULL; 70 | } 71 | 72 | void getnumthreads() 73 | { 74 | #ifdef _WIN32 75 | DWORD_PTR dwProcessAffinity, dwSystemAffinity; 76 | #elif __linux__ 77 | cpu_set_t dwProcessAffinity; 78 | #else 79 | int dwProcessAffinity = 0; 80 | int32_t core_count = 0; 81 | #endif 82 | size_t len = sizeof(dwProcessAffinity); 83 | if (numthreads > 0) 84 | return; 85 | #ifdef _WIN32 86 | GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); 87 | #elif __linux__ 88 | sched_getaffinity(0, len, &dwProcessAffinity); 89 | #else 90 | if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0) == 0) 91 | numthreads = core_count; 92 | #endif 93 | for (unsigned int i = 0; i < len * 8; i++) 94 | #if defined(_WIN32) 95 | if (dwProcessAffinity & (1i64 << i)) { 96 | #elif defined __linux__ 97 | if (CPU_ISSET(i, &dwProcessAffinity)) { 98 | #else 99 | if (dwProcessAffinity & (1 << i)) { 100 | #endif 101 | numthreads++; 102 | printf("Detected core on: %u\n", i); 103 | } 104 | printf("Number of threads: %i\n", (int)numthreads); 105 | } 106 | 107 | extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) 108 | { 109 | successval = 0; 110 | max_val = target; 111 | getnumthreads(); 112 | initialHash = (unsigned char *)starthash; 113 | # ifdef _WIN32 114 | HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads); 115 | # else 116 | pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads); 117 | struct sched_param schparam; 118 | schparam.sched_priority = 0; 119 | # endif 120 | unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); 121 | for (unsigned int i = 0; i < numthreads; i++) { 122 | threaddata[i] = i; 123 | # ifdef _WIN32 124 | threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)&threaddata[i], 0, NULL); 125 | SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE); 126 | # else 127 | pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); 128 | # ifdef __linux__ 129 | pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); 130 | # else 131 | pthread_setschedparam(threads[i], SCHED_RR, &schparam); 132 | # endif 133 | # endif 134 | } 135 | # ifdef _WIN32 136 | WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE); 137 | # else 138 | for (unsigned int i = 0; i < numthreads; i++) { 139 | pthread_join(threads[i], NULL); 140 | } 141 | # endif 142 | free(threads); 143 | free(threaddata); 144 | return successval; 145 | } 146 | -------------------------------------------------------------------------------- /src/build_osx.py: -------------------------------------------------------------------------------- 1 | from glob import glob 2 | import os 3 | from PyQt4 import QtCore 4 | from setuptools import setup 5 | 6 | name = "Bitmessage" 7 | version = os.getenv("PYBITMESSAGEVERSION", "custom") 8 | mainscript = ["bitmessagemain.py"] 9 | 10 | DATA_FILES = [ 11 | ('', ['sslkeys', 'images']), 12 | ('bitmsghash', ['bitmsghash/bitmsghash.cl', 'bitmsghash/bitmsghash.so']), 13 | ('translations', glob('translations/*.qm')), 14 | ('ui', glob('bitmessageqt/*.ui')), 15 | ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??.qm')), 16 | ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??_??.qm')), 17 | ] 18 | 19 | setup( 20 | name = name, 21 | version = version, 22 | app = mainscript, 23 | data_files = DATA_FILES, 24 | setup_requires = ["py2app"], 25 | options = dict( 26 | py2app = dict( 27 | includes = ['sip', 'PyQt4._qt'], 28 | iconfile = "images/bitmessage.icns" 29 | ) 30 | ) 31 | ) 32 | -------------------------------------------------------------------------------- /src/class_objectHashHolder.py: -------------------------------------------------------------------------------- 1 | # objectHashHolder is a timer-driven thread. One objectHashHolder thread is used 2 | # by each sendDataThread. The sendDataThread uses it whenever it needs to 3 | # advertise an object to peers in an inv message, or advertise a peer to other 4 | # peers in an addr message. Instead of sending them out immediately, it must 5 | # wait a random number of seconds for each connection so that different peers 6 | # get different objects at different times. Thus an attacker who is 7 | # connecting to many network nodes who receives a message first from Alice 8 | # cannot be sure if Alice is the node who originated the message. 9 | 10 | import random 11 | import time 12 | import threading 13 | 14 | class objectHashHolder(threading.Thread): 15 | size = 10 16 | def __init__(self, sendDataThreadMailbox): 17 | threading.Thread.__init__(self) 18 | self.shutdown = False 19 | self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. 20 | self.collectionOfHashLists = {} 21 | self.collectionOfPeerLists = {} 22 | for i in range(self.size): 23 | self.collectionOfHashLists[i] = [] 24 | self.collectionOfPeerLists[i] = [] 25 | 26 | def run(self): 27 | iterator = 0 28 | while not self.shutdown: 29 | if len(self.collectionOfHashLists[iterator]) > 0: 30 | self.sendDataThreadMailbox.put((0, 'sendinv', self.collectionOfHashLists[iterator])) 31 | self.collectionOfHashLists[iterator] = [] 32 | if len(self.collectionOfPeerLists[iterator]) > 0: 33 | self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) 34 | self.collectionOfPeerLists[iterator] = [] 35 | iterator += 1 36 | iterator %= self.size 37 | time.sleep(1) 38 | 39 | def holdHash(self,hash): 40 | self.collectionOfHashLists[random.randrange(0, self.size)].append(hash) 41 | 42 | def hasHash(self, hash): 43 | if hash in (hashlist for hashlist in self.collectionOfHashLists): 44 | logger.debug("Hash in hashHolder") 45 | return True 46 | return False 47 | 48 | def holdPeer(self,peerDetails): 49 | self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails) 50 | 51 | def hashCount(self): 52 | return sum([len(x) for x in self.collectionOfHashLists]) 53 | 54 | def close(self): 55 | self.shutdown = True 56 | -------------------------------------------------------------------------------- /src/class_objectProcessorQueue.py: -------------------------------------------------------------------------------- 1 | import shared 2 | 3 | import Queue 4 | import threading 5 | import time 6 | 7 | class ObjectProcessorQueue(Queue.Queue): 8 | maxSize = 32000000 9 | 10 | def __init__(self): 11 | Queue.Queue.__init__(self) 12 | self.sizeLock = threading.Lock() 13 | self.curSize = 0 # in Bytes. We maintain this to prevent nodes from flooing us with objects which take up too much memory. If this gets too big we'll sleep before asking for further objects. 14 | 15 | def put(self, item, block = True, timeout = None): 16 | while self.curSize >= self.maxSize: 17 | time.sleep(1) 18 | with self.sizeLock: 19 | self.curSize += len(item[1]) 20 | Queue.Queue.put(self, item, block, timeout) 21 | 22 | def get(self, block = True, timeout = None): 23 | try: 24 | item = Queue.Queue.get(self, block, timeout) 25 | except Queue.Empty as e: 26 | raise Queue.Empty() 27 | with self.sizeLock: 28 | self.curSize -= len(item[1]) 29 | return item 30 | -------------------------------------------------------------------------------- /src/debug.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Logging and debuging facility 4 | ============================= 5 | 6 | Levels: 7 | DEBUG Detailed information, typically of interest only when diagnosing problems. 8 | INFO Confirmation that things are working as expected. 9 | WARNING An indication that something unexpected happened, or indicative of some problem in the 10 | near future (e.g. ‘disk space low’). The software is still working as expected. 11 | ERROR Due to a more serious problem, the software has not been able to perform some function. 12 | CRITICAL A serious error, indicating that the program itself may be unable to continue running. 13 | 14 | There are three loggers: `console_only`, `file_only` and `both`. 15 | 16 | Use: `from debug import logger` to import this facility into whatever module you wish to log messages from. 17 | Logging is thread-safe so you don't have to worry about locks, just import and log. 18 | ''' 19 | import logging 20 | import logging.config 21 | import os 22 | import shared 23 | import sys 24 | import traceback 25 | import helper_startup 26 | helper_startup.loadConfig() 27 | 28 | # Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface 29 | # examples are here: https://bitmessage.org/forum/index.php/topic,4820.msg11163.html#msg11163 30 | log_level = 'WARNING' 31 | 32 | def log_uncaught_exceptions(ex_cls, ex, tb): 33 | logging.critical(''.join(traceback.format_tb(tb))) 34 | logging.critical('{0}: {1}'.format(ex_cls, ex)) 35 | 36 | def configureLogging(): 37 | have_logging = False 38 | try: 39 | logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) 40 | have_logging = True 41 | print "Loaded debug config from %s" % (os.path.join(shared.appdata, 'logging.dat')) 42 | except: 43 | print "Failed to load debug config from %s, using default logging config" % (os.path.join(shared.appdata, 'logging.dat')) 44 | print sys.exc_info() 45 | 46 | sys.excepthook = log_uncaught_exceptions 47 | 48 | if have_logging: 49 | return False 50 | 51 | logging.config.dictConfig({ 52 | 'version': 1, 53 | 'formatters': { 54 | 'default': { 55 | 'format': '%(asctime)s - %(levelname)s - %(message)s', 56 | }, 57 | }, 58 | 'handlers': { 59 | 'console': { 60 | 'class': 'logging.StreamHandler', 61 | 'formatter': 'default', 62 | 'level': log_level, 63 | 'stream': 'ext://sys.stdout' 64 | }, 65 | 'file': { 66 | 'class': 'logging.handlers.RotatingFileHandler', 67 | 'formatter': 'default', 68 | 'level': log_level, 69 | 'filename': shared.appdata + 'debug.log', 70 | 'maxBytes': 2097152, # 2 MiB 71 | 'backupCount': 1, 72 | } 73 | }, 74 | 'loggers': { 75 | 'console_only': { 76 | 'handlers': ['console'], 77 | 'propagate' : 0 78 | }, 79 | 'file_only': { 80 | 'handlers': ['file'], 81 | 'propagate' : 0 82 | }, 83 | 'both': { 84 | 'handlers': ['console', 'file'], 85 | 'propagate' : 0 86 | }, 87 | }, 88 | 'root': { 89 | 'level': log_level, 90 | 'handlers': ['console'], 91 | }, 92 | }) 93 | return True 94 | 95 | # TODO (xj9): Get from a config file. 96 | #logger = logging.getLogger('console_only') 97 | if configureLogging(): 98 | if '-c' in sys.argv: 99 | logger = logging.getLogger('file_only') 100 | else: 101 | logger = logging.getLogger('both') 102 | else: 103 | logger = logging.getLogger('default') 104 | 105 | def restartLoggingInUpdatedAppdataLocation(): 106 | global logger 107 | for i in list(logger.handlers): 108 | logger.removeHandler(i) 109 | i.flush() 110 | i.close() 111 | if configureLogging(): 112 | if '-c' in sys.argv: 113 | logger = logging.getLogger('file_only') 114 | else: 115 | logger = logging.getLogger('both') 116 | else: 117 | logger = logging.getLogger('default') 118 | 119 | -------------------------------------------------------------------------------- /src/defaultKnownNodes.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import socket 3 | from struct import * 4 | import time 5 | import random 6 | import sys 7 | from time import strftime, localtime 8 | import shared 9 | 10 | def createDefaultKnownNodes(appdata): 11 | ############## Stream 1 ################ 12 | stream1 = {} 13 | 14 | #stream1[shared.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) 15 | stream1[shared.Peer('5.45.99.75', 8444)] = int(time.time()) 16 | stream1[shared.Peer('75.167.159.54', 8444)] = int(time.time()) 17 | stream1[shared.Peer('95.165.168.168', 8444)] = int(time.time()) 18 | stream1[shared.Peer('85.180.139.241', 8444)] = int(time.time()) 19 | stream1[shared.Peer('158.222.211.81', 8080)] = int(time.time()) 20 | stream1[shared.Peer('178.62.12.187', 8448)] = int(time.time()) 21 | stream1[shared.Peer('24.188.198.204', 8111)] = int(time.time()) 22 | stream1[shared.Peer('109.147.204.113', 1195)] = int(time.time()) 23 | stream1[shared.Peer('178.11.46.221', 8444)] = int(time.time()) 24 | 25 | ############# Stream 2 ################# 26 | stream2 = {} 27 | # None yet 28 | 29 | ############# Stream 3 ################# 30 | stream3 = {} 31 | # None yet 32 | 33 | allKnownNodes = {} 34 | allKnownNodes[1] = stream1 35 | allKnownNodes[2] = stream2 36 | allKnownNodes[3] = stream3 37 | 38 | #print stream1 39 | #print allKnownNodes 40 | 41 | with open(appdata + 'knownnodes.dat', 'wb') as output: 42 | # Pickle dictionary using protocol 0. 43 | pickle.dump(allKnownNodes, output) 44 | 45 | return allKnownNodes 46 | 47 | def readDefaultKnownNodes(appdata): 48 | pickleFile = open(appdata + 'knownnodes.dat', 'rb') 49 | knownNodes = pickle.load(pickleFile) 50 | pickleFile.close() 51 | for stream, storedValue in knownNodes.items(): 52 | for host,value in storedValue.items(): 53 | try: 54 | # Old knownNodes format. 55 | port, storedtime = value 56 | except: 57 | # New knownNodes format. 58 | host, port = host 59 | storedtime = value 60 | print host, '\t', port, '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(storedtime)),'utf-8') 61 | 62 | if __name__ == "__main__": 63 | 64 | APPNAME = "PyBitmessage" 65 | from os import path, environ 66 | if sys.platform == 'darwin': 67 | from AppKit import NSSearchPathForDirectoriesInDomains # @UnresolvedImport 68 | # http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains 69 | # NSApplicationSupportDirectory = 14 70 | # NSUserDomainMask = 1 71 | # True for expanding the tilde into a fully qualified path 72 | appdata = path.join(NSSearchPathForDirectoriesInDomains(14, 1, True)[0], APPNAME) + '/' 73 | elif 'win' in sys.platform: 74 | appdata = path.join(environ['APPDATA'], APPNAME) + '\\' 75 | else: 76 | appdata = path.expanduser(path.join("~", "." + APPNAME + "/")) 77 | 78 | 79 | print 'New list of all known nodes:', createDefaultKnownNodes(appdata) 80 | readDefaultKnownNodes(appdata) 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/helper_bitcoin.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from pyelliptic import arithmetic 3 | 4 | # This function expects that pubkey begin with \x04 5 | def calculateBitcoinAddressFromPubkey(pubkey): 6 | if len(pubkey) != 65: 7 | print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey), 'bytes long rather than 65.' 8 | return "error" 9 | ripe = hashlib.new('ripemd160') 10 | sha = hashlib.new('sha256') 11 | sha.update(pubkey) 12 | ripe.update(sha.digest()) 13 | ripeWithProdnetPrefix = '\x00' + ripe.digest() 14 | 15 | checksum = hashlib.sha256(hashlib.sha256( 16 | ripeWithProdnetPrefix).digest()).digest()[:4] 17 | binaryBitcoinAddress = ripeWithProdnetPrefix + checksum 18 | numberOfZeroBytesOnBinaryBitcoinAddress = 0 19 | while binaryBitcoinAddress[0] == '\x00': 20 | numberOfZeroBytesOnBinaryBitcoinAddress += 1 21 | binaryBitcoinAddress = binaryBitcoinAddress[1:] 22 | base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58) 23 | return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded 24 | 25 | 26 | def calculateTestnetAddressFromPubkey(pubkey): 27 | if len(pubkey) != 65: 28 | print 'Could not calculate Bitcoin address from pubkey because function was passed a pubkey that was', len(pubkey), 'bytes long rather than 65.' 29 | return "error" 30 | ripe = hashlib.new('ripemd160') 31 | sha = hashlib.new('sha256') 32 | sha.update(pubkey) 33 | ripe.update(sha.digest()) 34 | ripeWithProdnetPrefix = '\x6F' + ripe.digest() 35 | 36 | checksum = hashlib.sha256(hashlib.sha256( 37 | ripeWithProdnetPrefix).digest()).digest()[:4] 38 | binaryBitcoinAddress = ripeWithProdnetPrefix + checksum 39 | numberOfZeroBytesOnBinaryBitcoinAddress = 0 40 | while binaryBitcoinAddress[0] == '\x00': 41 | numberOfZeroBytesOnBinaryBitcoinAddress += 1 42 | binaryBitcoinAddress = binaryBitcoinAddress[1:] 43 | base58encoded = arithmetic.changebase(binaryBitcoinAddress, 256, 58) 44 | return "1" * numberOfZeroBytesOnBinaryBitcoinAddress + base58encoded 45 | -------------------------------------------------------------------------------- /src/helper_bootstrap.py: -------------------------------------------------------------------------------- 1 | import shared 2 | import socket 3 | import defaultKnownNodes 4 | import pickle 5 | import time 6 | 7 | from debug import logger 8 | import socks 9 | 10 | def knownNodes(): 11 | try: 12 | # We shouldn't have to use the shared.knownNodesLock because this had 13 | # better be the only thread accessing knownNodes right now. 14 | pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb') 15 | loadedKnownNodes = pickle.load(pickleFile) 16 | pickleFile.close() 17 | # The old format of storing knownNodes was as a 'host: (port, time)' 18 | # mapping. The new format is as 'Peer: time' pairs. If we loaded 19 | # data in the old format, transform it to the new style. 20 | for stream, nodes in loadedKnownNodes.items(): 21 | shared.knownNodes[stream] = {} 22 | for node_tuple in nodes.items(): 23 | try: 24 | host, (port, time) = node_tuple 25 | peer = shared.Peer(host, port) 26 | except: 27 | peer, time = node_tuple 28 | shared.knownNodes[stream][peer] = time 29 | except: 30 | shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) 31 | if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: 32 | logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.') 33 | raise SystemExit 34 | 35 | def dns(): 36 | # DNS bootstrap. This could be programmed to use the SOCKS proxy to do the 37 | # DNS lookup some day but for now we will just rely on the entries in 38 | # defaultKnownNodes.py. Hopefully either they are up to date or the user 39 | # has run Bitmessage recently without SOCKS turned on and received good 40 | # bootstrap nodes using that method. 41 | if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': 42 | try: 43 | for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): 44 | logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') 45 | shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) 46 | except: 47 | logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') 48 | try: 49 | for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): 50 | logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') 51 | shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) 52 | except: 53 | logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') 54 | elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': 55 | shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) 56 | logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") 57 | for port in [8080, 8444]: 58 | logger.debug("Resolving %i through SOCKS...", port) 59 | address_family = socket.AF_INET 60 | sock = socks.socksocket(address_family, socket.SOCK_STREAM) 61 | sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 62 | sock.settimeout(20) 63 | proxytype = socks.PROXY_TYPE_SOCKS5 64 | sockshostname = shared.config.get( 65 | 'bitmessagesettings', 'sockshostname') 66 | socksport = shared.config.getint( 67 | 'bitmessagesettings', 'socksport') 68 | rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. 69 | if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): 70 | socksusername = shared.config.get( 71 | 'bitmessagesettings', 'socksusername') 72 | sockspassword = shared.config.get( 73 | 'bitmessagesettings', 'sockspassword') 74 | sock.setproxy( 75 | proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) 76 | else: 77 | sock.setproxy( 78 | proxytype, sockshostname, socksport, rdns) 79 | try: 80 | ip = sock.resolve("bootstrap" + str(port) + ".bitmessage.org") 81 | sock.shutdown(socket.SHUT_RDWR) 82 | sock.close() 83 | except: 84 | logger.error("SOCKS DNS resolving failed", exc_info=True) 85 | if ip is not None: 86 | logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') 87 | shared.knownNodes[1][shared.Peer(ip, port)] = time.time() 88 | else: 89 | logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') 90 | 91 | -------------------------------------------------------------------------------- /src/helper_generic.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import sys 3 | from binascii import hexlify, unhexlify 4 | 5 | import shared 6 | 7 | def convertIntToString(n): 8 | a = __builtins__.hex(n) 9 | if a[-1:] == 'L': 10 | a = a[:-1] 11 | if (len(a) % 2) == 0: 12 | return unhexlify(a[2:]) 13 | else: 14 | return unhexlify('0' + a[2:]) 15 | 16 | 17 | def convertStringToInt(s): 18 | return int(hexlify(s), 16) 19 | 20 | 21 | def signal_handler(signal, frame): 22 | if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): 23 | shared.doCleanShutdown() 24 | sys.exit(0) 25 | else: 26 | print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' 27 | 28 | def isHostInPrivateIPRange(host): 29 | if ":" in host: #IPv6 30 | hostAddr = socket.inet_pton(socket.AF_INET6, host) 31 | if hostAddr == ('\x00' * 15) + '\x01': 32 | return False 33 | if hostAddr[0] == '\xFE' and (ord(hostAddr[1]) & 0xc0) == 0x80: 34 | return False 35 | if (ord(hostAddr[0]) & 0xfe) == 0xfc: 36 | return False 37 | pass 38 | else: 39 | if host[:3] == '10.': 40 | return True 41 | if host[:4] == '172.': 42 | if host[6] == '.': 43 | if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: 44 | return True 45 | if host[:8] == '192.168.': 46 | return True 47 | return False 48 | 49 | def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): 50 | return data + paddingChar * (desiredMsgLength - len(data)) 51 | -------------------------------------------------------------------------------- /src/helper_inbox.py: -------------------------------------------------------------------------------- 1 | from helper_sql import * 2 | import shared 3 | 4 | def insert(t): 5 | sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) 6 | #shouldn't emit changedInboxUnread and displayNewInboxMessage at the same time 7 | #shared.UISignalQueue.put(('changedInboxUnread', None)) 8 | 9 | def trash(msgid): 10 | sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) 11 | shared.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) 12 | 13 | def isMessageAlreadyInInbox(sigHash): 14 | queryReturn = sqlQuery( 15 | '''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash) 16 | return queryReturn[0][0] != 0 -------------------------------------------------------------------------------- /src/helper_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2.7 2 | 3 | from helper_sql import * 4 | 5 | try: 6 | from PyQt4 import QtCore, QtGui 7 | haveQt = True 8 | except: 9 | haveQt = False 10 | 11 | def search_translate (context, text): 12 | if haveQt: 13 | return QtGui.QApplication.translate(context, text) 14 | else: 15 | return text.lower() 16 | 17 | def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = None, what = None, unreadOnly = False): 18 | if what is not None and what != "": 19 | what = "%" + what + "%" 20 | if where == search_translate("MainWindow", "To"): 21 | where = "toaddress" 22 | elif where == search_translate("MainWindow", "From"): 23 | where = "fromaddress" 24 | elif where == search_translate("MainWindow", "Subject"): 25 | where = "subject" 26 | elif where == search_translate("MainWindow", "Message"): 27 | where = "message" 28 | else: 29 | where = "toaddress || fromaddress || subject || message" 30 | else: 31 | what = None 32 | 33 | if folder == "sent": 34 | sqlStatementBase = ''' 35 | SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime 36 | FROM sent ''' 37 | else: 38 | sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read 39 | FROM inbox ''' 40 | 41 | sqlStatementParts = [] 42 | sqlArguments = [] 43 | if account is not None: 44 | if xAddress == 'both': 45 | sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)") 46 | sqlArguments.append(account) 47 | sqlArguments.append(account) 48 | else: 49 | sqlStatementParts.append(xAddress + " = ? ") 50 | sqlArguments.append(account) 51 | if folder is not None: 52 | if folder == "new": 53 | folder = "inbox" 54 | unreadOnly = True 55 | sqlStatementParts.append("folder = ? ") 56 | sqlArguments.append(folder) 57 | else: 58 | sqlStatementParts.append("folder != ?") 59 | sqlArguments.append("trash") 60 | if what is not None: 61 | sqlStatementParts.append("%s LIKE ?" % (where)) 62 | sqlArguments.append(what) 63 | if unreadOnly: 64 | sqlStatementParts.append("read = 0") 65 | if len(sqlStatementParts) > 0: 66 | sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) 67 | if folder == "sent": 68 | sqlStatementBase += " ORDER BY lastactiontime" 69 | return sqlQuery(sqlStatementBase, sqlArguments) 70 | 71 | def check_match(toAddress, fromAddress, subject, message, where = None, what = None): 72 | if what is not None and what != "": 73 | if where in (search_translate("MainWindow", "To"), search_translate("MainWindow", "All")): 74 | if what.lower() not in toAddress.lower(): 75 | return False 76 | elif where in (search_translate("MainWindow", "From"), search_translate("MainWindow", "All")): 77 | if what.lower() not in fromAddress.lower(): 78 | return False 79 | elif where in (search_translate("MainWindow", "Subject"), search_translate("MainWindow", "All")): 80 | if what.lower() not in subject.lower(): 81 | return False 82 | elif where in (search_translate("MainWindow", "Message"), search_translate("MainWindow", "All")): 83 | if what.lower() not in message.lower(): 84 | return False 85 | return True 86 | -------------------------------------------------------------------------------- /src/helper_sent.py: -------------------------------------------------------------------------------- 1 | from helper_sql import * 2 | 3 | def insert(t): 4 | sqlExecute('''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) 5 | -------------------------------------------------------------------------------- /src/helper_sql.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import Queue 3 | 4 | sqlSubmitQueue = Queue.Queue() #SQLITE3 is so thread-unsafe that they won't even let you call it from different threads using your own locks. SQL objects can only be called from one thread. 5 | sqlReturnQueue = Queue.Queue() 6 | sqlLock = threading.Lock() 7 | 8 | def sqlQuery(sqlStatement, *args): 9 | sqlLock.acquire() 10 | sqlSubmitQueue.put(sqlStatement) 11 | 12 | if args == (): 13 | sqlSubmitQueue.put('') 14 | elif type(args[0]) in [list, tuple]: 15 | sqlSubmitQueue.put(args[0]) 16 | else: 17 | sqlSubmitQueue.put(args) 18 | 19 | queryreturn, rowcount = sqlReturnQueue.get() 20 | sqlLock.release() 21 | 22 | return queryreturn 23 | 24 | def sqlExecute(sqlStatement, *args): 25 | sqlLock.acquire() 26 | sqlSubmitQueue.put(sqlStatement) 27 | 28 | if args == (): 29 | sqlSubmitQueue.put('') 30 | else: 31 | sqlSubmitQueue.put(args) 32 | 33 | queryreturn, rowcount = sqlReturnQueue.get() 34 | sqlSubmitQueue.put('commit') 35 | sqlLock.release() 36 | return rowcount 37 | 38 | def sqlStoredProcedure(procName): 39 | sqlLock.acquire() 40 | sqlSubmitQueue.put(procName) 41 | sqlLock.release() 42 | 43 | class SqlBulkExecute: 44 | def __enter__(self): 45 | sqlLock.acquire() 46 | return self 47 | 48 | def __exit__(self, type, value, traceback): 49 | sqlSubmitQueue.put('commit') 50 | sqlLock.release() 51 | 52 | def execute(self, sqlStatement, *args): 53 | sqlSubmitQueue.put(sqlStatement) 54 | 55 | if args == (): 56 | sqlSubmitQueue.put('') 57 | else: 58 | sqlSubmitQueue.put(args) 59 | sqlReturnQueue.get() 60 | 61 | def query(self, sqlStatement, *args): 62 | sqlSubmitQueue.put(sqlStatement) 63 | 64 | if args == (): 65 | sqlSubmitQueue.put('') 66 | else: 67 | sqlSubmitQueue.put(args) 68 | return sqlReturnQueue.get() 69 | 70 | -------------------------------------------------------------------------------- /src/helper_threading.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | class StoppableThread(object): 4 | def initStop(self): 5 | self.stop = threading.Event() 6 | self._stopped = False 7 | 8 | def stopThread(self): 9 | self._stopped = True 10 | self.stop.set() -------------------------------------------------------------------------------- /src/highlevelcrypto.py: -------------------------------------------------------------------------------- 1 | from binascii import hexlify 2 | import pyelliptic 3 | from pyelliptic import arithmetic as a, OpenSSL 4 | def makeCryptor(privkey): 5 | private_key = a.changebase(privkey, 16, 256, minlen=32) 6 | public_key = pointMult(private_key) 7 | privkey_bin = '\x02\xca\x00\x20' + private_key 8 | pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:] 9 | cryptor = pyelliptic.ECC(curve='secp256k1',privkey=privkey_bin,pubkey=pubkey_bin) 10 | return cryptor 11 | def hexToPubkey(pubkey): 12 | pubkey_raw = a.changebase(pubkey[2:],16,256,minlen=64) 13 | pubkey_bin = '\x02\xca\x00 '+pubkey_raw[:32]+'\x00 '+pubkey_raw[32:] 14 | return pubkey_bin 15 | def makePubCryptor(pubkey): 16 | pubkey_bin = hexToPubkey(pubkey) 17 | return pyelliptic.ECC(curve='secp256k1',pubkey=pubkey_bin) 18 | # Converts hex private key into hex public key 19 | def privToPub(privkey): 20 | private_key = a.changebase(privkey, 16, 256, minlen=32) 21 | public_key = pointMult(private_key) 22 | return hexlify(public_key) 23 | # Encrypts message with hex public key 24 | def encrypt(msg,hexPubkey): 25 | return pyelliptic.ECC(curve='secp256k1').encrypt(msg,hexToPubkey(hexPubkey)) 26 | # Decrypts message with hex private key 27 | def decrypt(msg,hexPrivkey): 28 | return makeCryptor(hexPrivkey).decrypt(msg) 29 | # Decrypts message with an existing pyelliptic.ECC.ECC object 30 | def decryptFast(msg,cryptor): 31 | return cryptor.decrypt(msg) 32 | # Signs with hex private key 33 | def sign(msg,hexPrivkey): 34 | # pyelliptic is upgrading from SHA1 to SHA256 for signing. We must 35 | # upgrade PyBitmessage gracefully. 36 | # https://github.com/yann2192/pyelliptic/pull/33 37 | # More discussion: https://github.com/yann2192/pyelliptic/issues/32 38 | return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_ecdsa) # SHA1 39 | #return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) # SHA256. We should switch to this eventually. 40 | # Verifies with hex public key 41 | def verify(msg,sig,hexPubkey): 42 | # As mentioned above, we must upgrade gracefully to use SHA256. So 43 | # let us check the signature using both SHA1 and SHA256 and if one 44 | # of them passes then we will be satisfied. Eventually this can 45 | # be simplified and we'll only check with SHA256. 46 | try: 47 | sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.EVP_ecdsa) # old SHA1 algorithm. 48 | except: 49 | sigVerifyPassed = False 50 | if sigVerifyPassed: 51 | # The signature check passed using SHA1 52 | return True 53 | # The signature check using SHA1 failed. Let us try it with SHA256. 54 | try: 55 | return makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.EVP_sha256) 56 | except: 57 | return False 58 | 59 | # Does an EC point multiplication; turns a private key into a public key. 60 | def pointMult(secret): 61 | while True: 62 | try: 63 | """ 64 | Evidently, this type of error can occur very rarely: 65 | 66 | File "highlevelcrypto.py", line 54, in pointMult 67 | group = OpenSSL.EC_KEY_get0_group(k) 68 | WindowsError: exception: access violation reading 0x0000000000000008 69 | """ 70 | k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) 71 | priv_key = OpenSSL.BN_bin2bn(secret, 32, None) 72 | group = OpenSSL.EC_KEY_get0_group(k) 73 | pub_key = OpenSSL.EC_POINT_new(group) 74 | 75 | OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) 76 | OpenSSL.EC_KEY_set_private_key(k, priv_key) 77 | OpenSSL.EC_KEY_set_public_key(k, pub_key) 78 | 79 | size = OpenSSL.i2o_ECPublicKey(k, None) 80 | mb = OpenSSL.create_string_buffer(size) 81 | OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) 82 | 83 | OpenSSL.EC_POINT_free(pub_key) 84 | OpenSSL.BN_free(priv_key) 85 | OpenSSL.EC_KEY_free(k) 86 | return mb.raw 87 | 88 | except Exception as e: 89 | import traceback 90 | import time 91 | traceback.print_exc() 92 | time.sleep(0.2) 93 | 94 | -------------------------------------------------------------------------------- /src/images/addressbook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/addressbook.png -------------------------------------------------------------------------------- /src/images/bitmessage.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/bitmessage.icns -------------------------------------------------------------------------------- /src/images/blacklist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/blacklist.png -------------------------------------------------------------------------------- /src/images/can-icon-16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon-16px.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon-24px-green.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon-24px-red.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon-24px-yellow.png -------------------------------------------------------------------------------- /src/images/can-icon-24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon-24px.png -------------------------------------------------------------------------------- /src/images/can-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/can-icon.ico -------------------------------------------------------------------------------- /src/images/greenicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/greenicon.png -------------------------------------------------------------------------------- /src/images/identities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/identities.png -------------------------------------------------------------------------------- /src/images/inbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/inbox.png -------------------------------------------------------------------------------- /src/images/networkstatus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/networkstatus.png -------------------------------------------------------------------------------- /src/images/no_identicons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/no_identicons.png -------------------------------------------------------------------------------- /src/images/qidenticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/qidenticon.png -------------------------------------------------------------------------------- /src/images/qidenticon_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/qidenticon_two.png -------------------------------------------------------------------------------- /src/images/qidenticon_two_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/qidenticon_two_x.png -------------------------------------------------------------------------------- /src/images/qidenticon_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/qidenticon_x.png -------------------------------------------------------------------------------- /src/images/redicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/redicon.png -------------------------------------------------------------------------------- /src/images/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/send.png -------------------------------------------------------------------------------- /src/images/sent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/sent.png -------------------------------------------------------------------------------- /src/images/subscriptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/subscriptions.png -------------------------------------------------------------------------------- /src/images/yellowicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/images/yellowicon.png -------------------------------------------------------------------------------- /src/l10n.py: -------------------------------------------------------------------------------- 1 | 2 | import logging 3 | import time 4 | 5 | import shared 6 | 7 | 8 | #logger = logging.getLogger(__name__) 9 | logger = logging.getLogger('file_only') 10 | 11 | 12 | DEFAULT_ENCODING = 'ISO8859-1' 13 | DEFAULT_LANGUAGE = 'en_US' 14 | DEFAULT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S' 15 | 16 | encoding = DEFAULT_ENCODING 17 | language = DEFAULT_LANGUAGE 18 | 19 | windowsLanguageMap = { 20 | "ar": "arabic", 21 | "cs": "czech", 22 | "da": "danish", 23 | "de": "german", 24 | "en": "english", 25 | "eo": "esperanto", 26 | "fr": "french", 27 | "it": "italian", 28 | "ja": "japanese", 29 | "nl": "dutch", 30 | "no": "norwegian", 31 | "pl": "polish", 32 | "pt": "portuguese", 33 | "ru": "russian", 34 | "sk": "slovak", 35 | "zh": "chinese", 36 | "zh_CN": "chinese-simplified", 37 | "zh_HK": "chinese-traditional", 38 | "zh_SG": "chinese-simplified", 39 | "zh_TW": "chinese-traditional" 40 | } 41 | 42 | try: 43 | import locale 44 | encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING 45 | language = locale.getlocale()[0] or locale.getdefaultlocale()[0] or DEFAULT_LANGUAGE 46 | except: 47 | logger.exception('Could not determine language or encoding') 48 | 49 | 50 | if shared.config.has_option('bitmessagesettings', 'timeformat'): 51 | time_format = shared.config.get('bitmessagesettings', 'timeformat') 52 | #Test the format string 53 | try: 54 | time.strftime(time_format) 55 | except: 56 | logger.exception('Could not format timestamp') 57 | time_format = DEFAULT_TIME_FORMAT 58 | else: 59 | time_format = DEFAULT_TIME_FORMAT 60 | 61 | #It seems some systems lie about the encoding they use so we perform 62 | #comprehensive decoding tests 63 | if time_format != DEFAULT_TIME_FORMAT: 64 | try: 65 | #Check day names 66 | for i in xrange(7): 67 | unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)), encoding) 68 | #Check month names 69 | for i in xrange(1, 13): 70 | unicode(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)), encoding) 71 | #Check AM/PM 72 | unicode(time.strftime(time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0)), encoding) 73 | unicode(time.strftime(time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0)), encoding) 74 | #Check DST 75 | unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1)), encoding) 76 | except: 77 | logger.exception('Could not decode locale formatted timestamp') 78 | time_format = DEFAULT_TIME_FORMAT 79 | encoding = DEFAULT_ENCODING 80 | 81 | 82 | def formatTimestamp(timestamp = None, as_unicode = True): 83 | #For some reason some timestamps are strings so we need to sanitize. 84 | if timestamp is not None and not isinstance(timestamp, int): 85 | try: 86 | timestamp = int(timestamp) 87 | except: 88 | timestamp = None 89 | 90 | #timestamp can't be less than 0. 91 | if timestamp is not None and timestamp < 0: 92 | timestamp = None 93 | 94 | if timestamp is None: 95 | timestring = time.strftime(time_format) 96 | else: 97 | #In case timestamp is too far in the future 98 | try: 99 | timestring = time.strftime(time_format, time.localtime(timestamp)) 100 | except ValueError: 101 | timestring = time.strftime(time_format) 102 | 103 | if as_unicode: 104 | return unicode(timestring, encoding) 105 | return timestring 106 | 107 | def getTranslationLanguage(): 108 | userlocale = None 109 | if shared.config.has_option('bitmessagesettings', 'userlocale'): 110 | userlocale = shared.config.get('bitmessagesettings', 'userlocale') 111 | 112 | if userlocale in [None, '', 'system']: 113 | return language 114 | 115 | return userlocale 116 | 117 | def getWindowsLocale(posixLocale): 118 | if posixLocale in windowsLanguageMap: 119 | return windowsLanguageMap[posixLocale] 120 | if "." in posixLocale: 121 | loc = posixLocale.split(".", 1) 122 | if loc[0] in windowsLanguageMap: 123 | return windowsLanguageMap[loc[0]] 124 | if "_" in posixLocale: 125 | loc = posixLocale.split("_", 1) 126 | if loc[0] in windowsLanguageMap: 127 | return windowsLanguageMap[loc[0]] 128 | if posixLocale != DEFAULT_LANGUAGE: 129 | return getWindowsLocale(DEFAULT_LANGUAGE) 130 | return None 131 | -------------------------------------------------------------------------------- /src/message_data_reader.py: -------------------------------------------------------------------------------- 1 | #This program can be used to print out everything in your Inbox or Sent folders and also take things out of the trash. 2 | #Scroll down to the bottom to see the functions that you can uncomment. Save then run this file. 3 | #The functions which only read the database file seem to function just fine even if you have Bitmessage running but you should definitly close it before running the functions that make changes (like taking items out of the trash). 4 | 5 | import sqlite3 6 | from time import strftime, localtime 7 | import sys 8 | import shared 9 | import string 10 | from binascii import hexlify 11 | 12 | appdata = shared.lookupAppdataFolder() 13 | 14 | conn = sqlite3.connect( appdata + 'messages.dat' ) 15 | conn.text_factory = str 16 | cur = conn.cursor() 17 | 18 | def readInbox(): 19 | print 'Printing everything in inbox table:' 20 | item = '''select * from inbox''' 21 | parameters = '' 22 | cur.execute(item, parameters) 23 | output = cur.fetchall() 24 | for row in output: 25 | print row 26 | 27 | def readSent(): 28 | print 'Printing everything in Sent table:' 29 | item = '''select * from sent where folder !='trash' ''' 30 | parameters = '' 31 | cur.execute(item, parameters) 32 | output = cur.fetchall() 33 | for row in output: 34 | msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, sleeptill, status, retrynumber, folder, encodingtype, ttl = row 35 | print hexlify(msgid), toaddress, 'toripe:', hexlify(toripe), 'fromaddress:', fromaddress, 'ENCODING TYPE:', encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', hexlify(ackdata), lastactiontime, status, retrynumber, folder 36 | 37 | def readSubscriptions(): 38 | print 'Printing everything in subscriptions table:' 39 | item = '''select * from subscriptions''' 40 | parameters = '' 41 | cur.execute(item, parameters) 42 | output = cur.fetchall() 43 | for row in output: 44 | print row 45 | 46 | def readPubkeys(): 47 | print 'Printing everything in pubkeys table:' 48 | item = '''select address, transmitdata, time, usedpersonally from pubkeys''' 49 | parameters = '' 50 | cur.execute(item, parameters) 51 | output = cur.fetchall() 52 | for row in output: 53 | address, transmitdata, time, usedpersonally = row 54 | print 'Address:', address, '\tTime first broadcast:', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(time)),'utf-8'), '\tUsed by me personally:', usedpersonally, '\tFull pubkey message:', hexlify(transmitdata) 55 | 56 | def readInventory(): 57 | print 'Printing everything in inventory table:' 58 | item = '''select hash, objecttype, streamnumber, payload, expirestime from inventory''' 59 | parameters = '' 60 | cur.execute(item, parameters) 61 | output = cur.fetchall() 62 | for row in output: 63 | hash, objecttype, streamnumber, payload, expirestime = row 64 | print 'Hash:', hexlify(hash), objecttype, streamnumber, '\t', hexlify(payload), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(expirestime)),'utf-8') 65 | 66 | 67 | def takeInboxMessagesOutOfTrash(): 68 | item = '''update inbox set folder='inbox' where folder='trash' ''' 69 | parameters = '' 70 | cur.execute(item, parameters) 71 | output = cur.fetchall() 72 | conn.commit() 73 | print 'done' 74 | 75 | def takeSentMessagesOutOfTrash(): 76 | item = '''update sent set folder='sent' where folder='trash' ''' 77 | parameters = '' 78 | cur.execute(item, parameters) 79 | output = cur.fetchall() 80 | conn.commit() 81 | print 'done' 82 | 83 | def markAllInboxMessagesAsUnread(): 84 | item = '''update inbox set read='0' ''' 85 | parameters = '' 86 | cur.execute(item, parameters) 87 | output = cur.fetchall() 88 | conn.commit() 89 | shared.UISignalQueue.put(('changedInboxUnread', None)) 90 | print 'done' 91 | 92 | def vacuum(): 93 | item = '''VACUUM''' 94 | parameters = '' 95 | cur.execute(item, parameters) 96 | output = cur.fetchall() 97 | conn.commit() 98 | print 'done' 99 | 100 | #takeInboxMessagesOutOfTrash() 101 | #takeSentMessagesOutOfTrash() 102 | #markAllInboxMessagesAsUnread() 103 | readInbox() 104 | #readSent() 105 | #readPubkeys() 106 | #readSubscriptions() 107 | #readInventory() 108 | #vacuum() #will defragment and clean empty space from the messages.dat file. 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/openclpow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | from struct import pack, unpack 3 | import time 4 | import hashlib 5 | import random 6 | import os 7 | 8 | from shared import codePath, safeConfigGetBoolean, shutdown 9 | from debug import logger 10 | 11 | libAvailable = True 12 | ctx = False 13 | queue = False 14 | program = False 15 | gpus = [] 16 | hash_dt = None 17 | 18 | try: 19 | import numpy 20 | import pyopencl as cl 21 | except: 22 | libAvailable = False 23 | 24 | def initCL(): 25 | global ctx, queue, program, gpus, hash_dt 26 | try: 27 | hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) 28 | for platform in cl.get_platforms(): 29 | gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) 30 | if (len(gpus) > 0): 31 | ctx = cl.Context(devices=gpus) 32 | queue = cl.CommandQueue(ctx) 33 | f = open(os.path.join(codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') 34 | fstr = ''.join(f.readlines()) 35 | program = cl.Program(ctx, fstr).build(options="") 36 | logger.info("Loaded OpenCL kernel") 37 | else: 38 | logger.info("No OpenCL GPUs found") 39 | ctx = False 40 | except Exception as e: 41 | logger.error("OpenCL fail: ", exc_info=True) 42 | ctx = False 43 | 44 | def has_opencl(): 45 | global ctx 46 | return (ctx != False) 47 | 48 | def do_opencl_pow(hash, target): 49 | global ctx, queue, program, gpus, hash_dt 50 | 51 | output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) 52 | if (ctx == False): 53 | return output[0][0] 54 | 55 | data = numpy.zeros(1, dtype=hash_dt, order='C') 56 | data[0]['v'] = ("0000000000000000" + hash).decode("hex") 57 | data[0]['target'] = target 58 | 59 | hash_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=data) 60 | dest_buf = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, output.nbytes) 61 | 62 | kernel = program.kernel_sha512 63 | worksize = kernel.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, gpus[0]) 64 | 65 | kernel.set_arg(0, hash_buf) 66 | kernel.set_arg(1, dest_buf) 67 | 68 | start = time.time() 69 | progress = 0 70 | globamt = worksize*2000 71 | 72 | while output[0][0] == 0 and shutdown == 0: 73 | kernel.set_arg(2, pack("Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) 94 | print "{} - value {} < {}".format(nonce, trialValue, target) 95 | 96 | -------------------------------------------------------------------------------- /src/protocol.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import shared 3 | 4 | def getBitfield(address): 5 | # bitfield of features supported by me (see the wiki). 6 | bitfield = 0 7 | # send ack 8 | if not shared.safeConfigGetBoolean(address, 'dontsendack'): 9 | bitfield |= shared.BITFIELD_DOESACK 10 | return struct.pack('>I', bitfield) 11 | 12 | def checkBitfield(bitfieldBinary, flags): 13 | bitfield, = struct.unpack('>I', bitfieldBinary) 14 | return (bitfield & flags) == flags -------------------------------------------------------------------------------- /src/pyelliptic/README.md: -------------------------------------------------------------------------------- 1 | # PyElliptic 2 | 3 | PyElliptic is a high level wrapper for the cryptographic library : OpenSSL. 4 | Under the GNU General Public License 5 | 6 | Python3 compatible. For GNU/Linux and Windows. 7 | Require OpenSSL 8 | 9 | ## Features 10 | 11 | ### Asymmetric cryptography using Elliptic Curve Cryptography (ECC) 12 | 13 | * Key agreement : ECDH 14 | * Digital signatures : ECDSA 15 | * Hybrid encryption : ECIES (like RSA) 16 | 17 | ### Symmetric cryptography 18 | 19 | * AES-128 (CBC, OFB, CFB) 20 | * AES-256 (CBC, OFB, CFB) 21 | * Blowfish (CFB and CBC) 22 | * RC4 23 | 24 | ### Other 25 | 26 | * CSPRNG 27 | * HMAC (using SHA512) 28 | * PBKDF2 (SHA256 and SHA512) 29 | 30 | ## Example 31 | 32 | ```python 33 | #!/usr/bin/python 34 | 35 | import pyelliptic 36 | 37 | # Symmetric encryption 38 | iv = pyelliptic.Cipher.gen_IV('aes-256-cfb') 39 | ctx = pyelliptic.Cipher("secretkey", iv, 1, ciphername='aes-256-cfb') 40 | 41 | ciphertext = ctx.update('test1') 42 | ciphertext += ctx.update('test2') 43 | ciphertext += ctx.final() 44 | 45 | ctx2 = pyelliptic.Cipher("secretkey", iv, 0, ciphername='aes-256-cfb') 46 | print ctx2.ciphering(ciphertext) 47 | 48 | # Asymmetric encryption 49 | alice = pyelliptic.ECC() # default curve: sect283r1 50 | bob = pyelliptic.ECC(curve='sect571r1') 51 | 52 | ciphertext = alice.encrypt("Hello Bob", bob.get_pubkey()) 53 | print bob.decrypt(ciphertext) 54 | 55 | signature = bob.sign("Hello Alice") 56 | # alice's job : 57 | print pyelliptic.ECC(pubkey=bob.get_pubkey()).verify(signature, "Hello Alice") 58 | 59 | # ERROR !!! 60 | try: 61 | key = alice.get_ecdh_key(bob.get_pubkey()) 62 | except: print("For ECDH key agreement, the keys must be defined on the same curve !") 63 | 64 | alice = pyelliptic.ECC(curve='sect571r1') 65 | print alice.get_ecdh_key(bob.get_pubkey()).encode('hex') 66 | print bob.get_ecdh_key(alice.get_pubkey()).encode('hex') 67 | ``` 68 | -------------------------------------------------------------------------------- /src/pyelliptic/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010 2 | # Author: Yann GUIBET 3 | # Contact: 4 | 5 | __version__ = '1.3' 6 | 7 | __all__ = [ 8 | 'OpenSSL', 9 | 'ECC', 10 | 'Cipher', 11 | 'hmac_sha256', 12 | 'hmac_sha512', 13 | 'pbkdf2' 14 | ] 15 | 16 | from .openssl import OpenSSL 17 | from .ecc import ECC 18 | from .cipher import Cipher 19 | from .hash import hmac_sha256, hmac_sha512, pbkdf2 20 | -------------------------------------------------------------------------------- /src/pyelliptic/arithmetic.py: -------------------------------------------------------------------------------- 1 | import hashlib, re 2 | 3 | P = 2**256-2**32-2**9-2**8-2**7-2**6-2**4-1 4 | A = 0 5 | Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 6 | Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424 7 | G = (Gx,Gy) 8 | 9 | def inv(a,n): 10 | lm, hm = 1,0 11 | low, high = a%n,n 12 | while low > 1: 13 | r = high/low 14 | nm, new = hm-lm*r, high-low*r 15 | lm, low, hm, high = nm, new, lm, low 16 | return lm % n 17 | 18 | def get_code_string(base): 19 | if base == 2: return '01' 20 | elif base == 10: return '0123456789' 21 | elif base == 16: return "0123456789abcdef" 22 | elif base == 58: return "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" 23 | elif base == 256: return ''.join([chr(x) for x in range(256)]) 24 | else: raise ValueError("Invalid base!") 25 | 26 | def encode(val,base,minlen=0): 27 | code_string = get_code_string(base) 28 | result = "" 29 | while val > 0: 30 | result = code_string[val % base] + result 31 | val /= base 32 | if len(result) < minlen: 33 | result = code_string[0]*(minlen-len(result))+result 34 | return result 35 | 36 | def decode(string,base): 37 | code_string = get_code_string(base) 38 | result = 0 39 | if base == 16: string = string.lower() 40 | while len(string) > 0: 41 | result *= base 42 | result += code_string.find(string[0]) 43 | string = string[1:] 44 | return result 45 | 46 | def changebase(string,frm,to,minlen=0): 47 | return encode(decode(string,frm),to,minlen) 48 | 49 | def base10_add(a,b): 50 | if a == None: return b[0],b[1] 51 | if b == None: return a[0],a[1] 52 | if a[0] == b[0]: 53 | if a[1] == b[1]: return base10_double(a[0],a[1]) 54 | else: return None 55 | m = ((b[1]-a[1]) * inv(b[0]-a[0],P)) % P 56 | x = (m*m-a[0]-b[0]) % P 57 | y = (m*(a[0]-x)-a[1]) % P 58 | return (x,y) 59 | 60 | def base10_double(a): 61 | if a == None: return None 62 | m = ((3*a[0]*a[0]+A)*inv(2*a[1],P)) % P 63 | x = (m*m-2*a[0]) % P 64 | y = (m*(a[0]-x)-a[1]) % P 65 | return (x,y) 66 | 67 | def base10_multiply(a,n): 68 | if n == 0: return G 69 | if n == 1: return a 70 | if (n%2) == 0: return base10_double(base10_multiply(a,n/2)) 71 | if (n%2) == 1: return base10_add(base10_double(base10_multiply(a,n/2)),a) 72 | 73 | def hex_to_point(h): return (decode(h[2:66],16),decode(h[66:],16)) 74 | 75 | def point_to_hex(p): return '04'+encode(p[0],16,64)+encode(p[1],16,64) 76 | 77 | def multiply(privkey,pubkey): 78 | return point_to_hex(base10_multiply(hex_to_point(pubkey),decode(privkey,16))) 79 | 80 | def privtopub(privkey): 81 | return point_to_hex(base10_multiply(G,decode(privkey,16))) 82 | 83 | def add(p1,p2): 84 | if (len(p1)==32): 85 | return encode(decode(p1,16) + decode(p2,16) % P,16,32) 86 | else: 87 | return point_to_hex(base10_add(hex_to_point(p1),hex_to_point(p2))) 88 | 89 | def hash_160(string): 90 | intermed = hashlib.sha256(string).digest() 91 | ripemd160 = hashlib.new('ripemd160') 92 | ripemd160.update(intermed) 93 | return ripemd160.digest() 94 | 95 | def dbl_sha256(string): 96 | return hashlib.sha256(hashlib.sha256(string).digest()).digest() 97 | 98 | def bin_to_b58check(inp): 99 | inp_fmtd = '\x00' + inp 100 | leadingzbytes = len(re.match('^\x00*',inp_fmtd).group(0)) 101 | checksum = dbl_sha256(inp_fmtd)[:4] 102 | return '1' * leadingzbytes + changebase(inp_fmtd+checksum,256,58) 103 | 104 | #Convert a public key (in hex) to a Bitcoin address 105 | def pubkey_to_address(pubkey): 106 | return bin_to_b58check(hash_160(changebase(pubkey,16,256))) 107 | -------------------------------------------------------------------------------- /src/pyelliptic/cipher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (C) 2011 Yann GUIBET 5 | # See LICENSE for details. 6 | 7 | from pyelliptic.openssl import OpenSSL 8 | 9 | 10 | class Cipher: 11 | """ 12 | Symmetric encryption 13 | 14 | import pyelliptic 15 | iv = pyelliptic.Cipher.gen_IV('aes-256-cfb') 16 | ctx = pyelliptic.Cipher("secretkey", iv, 1, ciphername='aes-256-cfb') 17 | ciphertext = ctx.update('test1') 18 | ciphertext += ctx.update('test2') 19 | ciphertext += ctx.final() 20 | 21 | ctx2 = pyelliptic.Cipher("secretkey", iv, 0, ciphername='aes-256-cfb') 22 | print ctx2.ciphering(ciphertext) 23 | """ 24 | def __init__(self, key, iv, do, ciphername='aes-256-cbc'): 25 | """ 26 | do == 1 => Encrypt; do == 0 => Decrypt 27 | """ 28 | self.cipher = OpenSSL.get_cipher(ciphername) 29 | self.ctx = OpenSSL.EVP_CIPHER_CTX_new() 30 | if do == 1 or do == 0: 31 | k = OpenSSL.malloc(key, len(key)) 32 | IV = OpenSSL.malloc(iv, len(iv)) 33 | OpenSSL.EVP_CipherInit_ex( 34 | self.ctx, self.cipher.get_pointer(), 0, k, IV, do) 35 | else: 36 | raise Exception("RTFM ...") 37 | 38 | @staticmethod 39 | def get_all_cipher(): 40 | """ 41 | static method, returns all ciphers available 42 | """ 43 | return OpenSSL.cipher_algo.keys() 44 | 45 | @staticmethod 46 | def get_blocksize(ciphername): 47 | cipher = OpenSSL.get_cipher(ciphername) 48 | return cipher.get_blocksize() 49 | 50 | @staticmethod 51 | def gen_IV(ciphername): 52 | cipher = OpenSSL.get_cipher(ciphername) 53 | return OpenSSL.rand(cipher.get_blocksize()) 54 | 55 | def update(self, input): 56 | i = OpenSSL.c_int(0) 57 | buffer = OpenSSL.malloc(b"", len(input) + self.cipher.get_blocksize()) 58 | inp = OpenSSL.malloc(input, len(input)) 59 | if OpenSSL.EVP_CipherUpdate(self.ctx, OpenSSL.byref(buffer), 60 | OpenSSL.byref(i), inp, len(input)) == 0: 61 | raise Exception("[OpenSSL] EVP_CipherUpdate FAIL ...") 62 | return buffer.raw[0:i.value] 63 | 64 | def final(self): 65 | i = OpenSSL.c_int(0) 66 | buffer = OpenSSL.malloc(b"", self.cipher.get_blocksize()) 67 | if (OpenSSL.EVP_CipherFinal_ex(self.ctx, OpenSSL.byref(buffer), 68 | OpenSSL.byref(i))) == 0: 69 | raise Exception("[OpenSSL] EVP_CipherFinal_ex FAIL ...") 70 | return buffer.raw[0:i.value] 71 | 72 | def ciphering(self, input): 73 | """ 74 | Do update and final in one method 75 | """ 76 | buff = self.update(input) 77 | return buff + self.final() 78 | 79 | def __del__(self): 80 | OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) 81 | OpenSSL.EVP_CIPHER_CTX_free(self.ctx) 82 | -------------------------------------------------------------------------------- /src/pyelliptic/hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright (C) 2011 Yann GUIBET 5 | # See LICENSE for details. 6 | 7 | from pyelliptic.openssl import OpenSSL 8 | 9 | 10 | # For python3 11 | def _equals_bytes(a, b): 12 | if len(a) != len(b): 13 | return False 14 | result = 0 15 | for x, y in zip(a, b): 16 | result |= x ^ y 17 | return result == 0 18 | 19 | 20 | def _equals_str(a, b): 21 | if len(a) != len(b): 22 | return False 23 | result = 0 24 | for x, y in zip(a, b): 25 | result |= ord(x) ^ ord(y) 26 | return result == 0 27 | 28 | 29 | def equals(a, b): 30 | if isinstance(a, str): 31 | return _equals_str(a, b) 32 | else: 33 | return _equals_bytes(a, b) 34 | 35 | 36 | def hmac_sha256(k, m): 37 | """ 38 | Compute the key and the message with HMAC SHA5256 39 | """ 40 | key = OpenSSL.malloc(k, len(k)) 41 | d = OpenSSL.malloc(m, len(m)) 42 | md = OpenSSL.malloc(0, 32) 43 | i = OpenSSL.pointer(OpenSSL.c_int(0)) 44 | OpenSSL.HMAC(OpenSSL.EVP_sha256(), key, len(k), d, len(m), md, i) 45 | return md.raw 46 | 47 | 48 | def hmac_sha512(k, m): 49 | """ 50 | Compute the key and the message with HMAC SHA512 51 | """ 52 | key = OpenSSL.malloc(k, len(k)) 53 | d = OpenSSL.malloc(m, len(m)) 54 | md = OpenSSL.malloc(0, 64) 55 | i = OpenSSL.pointer(OpenSSL.c_int(0)) 56 | OpenSSL.HMAC(OpenSSL.EVP_sha512(), key, len(k), d, len(m), md, i) 57 | return md.raw 58 | 59 | 60 | def pbkdf2(password, salt=None, i=10000, keylen=64): 61 | if salt is None: 62 | salt = OpenSSL.rand(8) 63 | p_password = OpenSSL.malloc(password, len(password)) 64 | p_salt = OpenSSL.malloc(salt, len(salt)) 65 | output = OpenSSL.malloc(0, keylen) 66 | OpenSSL.PKCS5_PBKDF2_HMAC(p_password, len(password), p_salt, 67 | len(p_salt), i, OpenSSL.EVP_sha256(), 68 | keylen, output) 69 | return salt, output.raw 70 | -------------------------------------------------------------------------------- /src/singleton.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import atexit 4 | import errno 5 | from multiprocessing import Process 6 | import os 7 | import sys 8 | import shared 9 | 10 | try: 11 | import fcntl # @UnresolvedImport 12 | except: 13 | pass 14 | 15 | class singleinstance: 16 | """ 17 | Implements a single instance application by creating a lock file at appdata. 18 | 19 | This is based upon the singleton class from tendo https://github.com/pycontribs/tendo 20 | which is under the Python Software Foundation License version 2 21 | """ 22 | def __init__(self, flavor_id="", daemon=False): 23 | self.initialized = False 24 | self.daemon = daemon 25 | self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) 26 | 27 | if not self.daemon: 28 | # Tells the already running (if any) application to get focus. 29 | import bitmessageqt 30 | bitmessageqt.init() 31 | 32 | if sys.platform == 'win32': 33 | try: 34 | # file already exists, we try to remove (in case previous execution was interrupted) 35 | if os.path.exists(self.lockfile): 36 | os.unlink(self.lockfile) 37 | self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR) 38 | except OSError: 39 | type, e, tb = sys.exc_info() 40 | if e.errno == 13: 41 | print 'Another instance of this application is already running' 42 | sys.exit(-1) 43 | print(e.errno) 44 | raise 45 | else: # non Windows 46 | self.fp = open(self.lockfile, 'w') 47 | try: 48 | fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) 49 | except IOError: 50 | print 'Another instance of this application is already running' 51 | sys.exit(-1) 52 | self.initialized = True 53 | atexit.register(self.cleanup) 54 | 55 | def cleanup(self): 56 | if not self.initialized: 57 | return 58 | print "Cleaning up lockfile" 59 | try: 60 | if sys.platform == 'win32': 61 | if hasattr(self, 'fd'): 62 | os.close(self.fd) 63 | os.unlink(self.lockfile) 64 | else: 65 | fcntl.lockf(self.fp, fcntl.LOCK_UN) 66 | if os.path.isfile(self.lockfile): 67 | os.unlink(self.lockfile) 68 | except Exception, e: 69 | pass 70 | -------------------------------------------------------------------------------- /src/socks/BUGS: -------------------------------------------------------------------------------- 1 | SocksiPy version 1.00 2 | A Python SOCKS module. 3 | (C) 2006 Dan-Haim. All rights reserved. 4 | See LICENSE file for details. 5 | 6 | 7 | KNOWN BUGS AND ISSUES 8 | ---------------------- 9 | 10 | There are no currently known bugs in this module. 11 | There are some limits though: 12 | 13 | 1) Only outgoing connections are supported - This module currently only supports 14 | outgoing TCP connections, though some servers may support incoming connections 15 | as well. UDP is not supported either. 16 | 17 | 2) GSSAPI Socks5 authenticaion is not supported. 18 | 19 | 20 | If you find any new bugs, please contact the author at: 21 | 22 | negativeiq@users.sourceforge.net 23 | 24 | 25 | Thank you! 26 | -------------------------------------------------------------------------------- /src/socks/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2006 Dan-Haim. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 1. Redistributions of source code must retain the above copyright notice, this 6 | list of conditions and the following disclaimer. 7 | 2. Redistributions in binary form must reproduce the above copyright notice, 8 | this list of conditions and the following disclaimer in the documentation 9 | and/or other materials provided with the distribution. 10 | 3. Neither the name of Dan Haim nor the names of his contributors may be used 11 | to endorse or promote products derived from this software without specific 12 | prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED 15 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA 20 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 22 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. 23 | -------------------------------------------------------------------------------- /src/sslkeys/cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICWDCCAcGgAwIBAgIJAJs5yni/cDh5MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV 3 | BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX 4 | aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTEzMDk1NTU3WhcNMTUxMTE0MDk1NTU3WjBF 5 | MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 6 | ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB 7 | gQCg8XkFpIAYsTSBealTubvu4dzpMnnAOwANG5K9TJeclG9O65cmKWpH8k3hNDif 8 | xagIAI8UanBsQo6SQrK1Iby2kz6DCKmySO1OwoNOOF0Ok31N+5aWsQvYF1wLbk2m 9 | Ti/CSLWBgL25ywCCiP3Mgr+krapT4TrfvF4gCchUdcxMQQIDAQABo1AwTjAdBgNV 10 | HQ4EFgQUWuFUJQC6zu6OTDgHZzhfZxsgJOMwHwYDVR0jBBgwFoAUWuFUJQC6zu6O 11 | TDgHZzhfZxsgJOMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAT1I/x 12 | GbsYAE4pM4sVQrcuz7jLwr3k5Zve0z4WKR41W17Nc44G3DyLbkTWYESLfAYsivkx 13 | tRRtYTtJm1qmTPtedXQJK+wJGNHCWRfwSB2CYwmO7+C2rYYzkFndN68kB6RJmyOr 14 | eCX+9vkbQqgh7KfiNquJxCfMSDfhA2RszU43jg== 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /src/sslkeys/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKDxeQWkgBixNIF5 3 | qVO5u+7h3OkyecA7AA0bkr1Ml5yUb07rlyYpakfyTeE0OJ/FqAgAjxRqcGxCjpJC 4 | srUhvLaTPoMIqbJI7U7Cg044XQ6TfU37lpaxC9gXXAtuTaZOL8JItYGAvbnLAIKI 5 | /cyCv6StqlPhOt+8XiAJyFR1zExBAgMBAAECgYEAmd2hpQpayMCJgQsOHhRgnoXi 6 | jDOMgIInj2CADmguPi0OqTXEoGBR0ozNdfNV+zGdbmESaSNFbcrHwP7xGQgzABlv 7 | 5ANLgBYrHnW/oFCCuw4Lj/CAAHRA4its+2wzf13BYoVitDiYBt3JMRqwLV03aHyy 8 | Oqhvt2nVicz85+HERj0CQQDMJAPUIyOQLO+BPC5MsuxyQFJgie0aB5swumxanOv4 9 | J8GIvulNEJMG/dq+h/x4paV2LGDlUAOsBUmjXfTPMQAHAkEAydQtYorqYqhFZWWD 10 | 3lUMAoa8pGb6BfNXUqxdH0H8fk6B7OxYPpvwm7ce1lD1Oje3/+rMnn8i6A1p9HUy 11 | l9wvdwJAdhxIUs7Z3qsBD8bgCuRixV/NyalDk5HfCnxyAKNWK8fkw9ehaEM0rhDm 12 | JOLNAojkiND4ZvS6iyasCmdsIwx4tQJAAV+eR3NmkPFQN5ZvRU4S3NmJ4xyISw4S 13 | 5A8kOxg53aovHCunlhV9l7GxVggLAzBp4iX46oM2+5lLxUwe4gWvlQJBAK0IR8bB 14 | 85bKZ+M/O8rbs9kQHjx6GCbbDxH+qbIKkNcvLUvMgwwIFKiwqX+Tedtu2xET0mQM 15 | 9tEE5eMBOJ8GrxQ= 16 | -----END PRIVATE KEY----- 17 | -------------------------------------------------------------------------------- /src/tr.py: -------------------------------------------------------------------------------- 1 | import shared 2 | import os 3 | 4 | # This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions. 5 | class translateClass: 6 | def __init__(self, context, text): 7 | self.context = context 8 | self.text = text 9 | def arg(self,argument): 10 | if '%' in self.text: 11 | return translateClass(self.context, self.text.replace('%','',1)) # This doesn't actually do anything with the arguments because we don't have a UI in which to display this information anyway. 12 | else: 13 | return self.text 14 | 15 | def _translate(context, text, disambiguation = None, encoding = None, n = None): 16 | return translateText(context, text, n) 17 | 18 | def translateText(context, text, n = None): 19 | if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): 20 | try: 21 | from PyQt4 import QtCore, QtGui 22 | except Exception as err: 23 | print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download PyQt from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\'. If you want to run in daemon mode, see https://bitmessage.org/wiki/Daemon' 24 | print 'Error message:', err 25 | os._exit(0) 26 | if n is None: 27 | return QtGui.QApplication.translate(context, text) 28 | else: 29 | return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) 30 | else: 31 | if '%' in text: 32 | return translateClass(context, text.replace('%','',1)) 33 | else: 34 | return text 35 | -------------------------------------------------------------------------------- /src/translations/bitmessage.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_outgoingSynSender.py\ 5 | ../class_objectProcessor.py\ 6 | ../class_receiveDataThread.py\ 7 | ../class_sendDataThread.py\ 8 | ../class_singleCleaner.py\ 9 | ../class_singleListener.py\ 10 | ../class_singleWorker.py\ 11 | ../class_sqlThread.py\ 12 | ../helper_bitcoin.py\ 13 | ../helper_bootstrap.py\ 14 | ../helper_generic.py\ 15 | ../helper_inbox.py\ 16 | ../helper_sent.py\ 17 | ../helper_startup.py\ 18 | ../shared.py\ 19 | ../upnp.py\ 20 | ../bitmessageqt/__init__.py\ 21 | ../bitmessageqt/about.py\ 22 | ../bitmessageqt/account.py\ 23 | ../bitmessageqt/addaddressdialog.py\ 24 | ../bitmessageqt/bitmessageui.py\ 25 | ../bitmessageqt/blacklist.py\ 26 | ../bitmessageqt/connect.py\ 27 | ../bitmessageqt/emailgateway.py\ 28 | ../bitmessageqt/foldertree.py\ 29 | ../bitmessageqt/help.py\ 30 | ../bitmessageqt/iconglossary.py\ 31 | ../bitmessageqt/languagebox.py\ 32 | ../bitmessageqt/messagecompose.py\ 33 | ../bitmessageqt/messageview.py\ 34 | ../bitmessageqt/networkstatus.py\ 35 | ../bitmessageqt/newaddressdialog.py\ 36 | ../bitmessageqt/newchandialog.py\ 37 | ../bitmessageqt/newsubscriptiondialog.py\ 38 | ../bitmessageqt/regenerateaddresses.py\ 39 | ../bitmessageqt/safehtmlparser.py\ 40 | ../bitmessageqt/settings.py\ 41 | ../bitmessageqt/specialaddressbehavior.py 42 | 43 | FORMS = \ 44 | ../bitmessageqt/blacklist.ui\ 45 | ../bitmessageqt/networkstatus.ui 46 | 47 | TRANSLATIONS = \ 48 | bitmessage_ar.ts \ 49 | bitmessage_cs.ts \ 50 | bitmessage_da.ts \ 51 | bitmessage_de.ts \ 52 | bitmessage_en.ts \ 53 | bitmessage_en_pirate.ts \ 54 | bitmessage_eo.ts \ 55 | bitmessage_fr.ts \ 56 | bitmessage_it.ts \ 57 | bitmessage_ja.ts \ 58 | bitmessage_nl.ts \ 59 | bitmessage_no.ts \ 60 | bitmessage_sk.ts \ 61 | bitmessage_ru.ts \ 62 | bitmessage_zh_cn.ts 63 | 64 | CODECFORTR = UTF-8 65 | -------------------------------------------------------------------------------- /src/translations/bitmessage_ar.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_ar.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_cs.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_cs.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_da.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_da.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_de.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_de.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_en.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_en.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_en_pirate.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_en_pirate.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_eo.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_eo.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_fr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_fr.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_it.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_it.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_ja.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_ja.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_nl.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_nl.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_no.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_no.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_ru.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_ru.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_sk.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_sk.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_zh_cn.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mailchuck/PyBitmessage/ec3de1de7b61b073e46a18c6373a7af05ab81a4e/src/translations/bitmessage_zh_cn.qm --------------------------------------------------------------------------------