├── .gitignore ├── COPYING ├── INSTALL.md ├── LICENSE ├── Makefile ├── README.md ├── arch.sh ├── archpackage └── PKGBUILD ├── 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 ├── ebuildpackage └── pybitmessage-0.3.5-1.ebuild ├── generate.sh ├── man └── pybitmessage.1.gz ├── osx.sh ├── puppy.sh ├── puppypackage ├── icon14.xpm └── pybitmessage-0.3.5.pet.specs ├── rpm.sh ├── rpmpackage └── pybitmessage.spec ├── slack.sh ├── slackpackage ├── doinst.sh └── slack-desc └── src ├── addresses.py ├── api.py ├── api_client.py ├── bitmessagecurses └── __init__.py ├── bitmessagemain.py ├── bitmessageqt ├── __init__.py ├── about.py ├── about.ui ├── addaddressdialog.py ├── addaddressdialog.ui ├── addpeer.ui ├── bitmessage_icons.qrc ├── bitmessage_icons_rc.py ├── bitmessageui.py ├── bitmessageui.ui ├── connect.py ├── connect.ui ├── help.py ├── help.ui ├── iconglossary.py ├── iconglossary.ui ├── newaddressdialog.py ├── newaddressdialog.ui ├── newchandialog.py ├── newchandialog.ui ├── newsubscriptiondialog.py ├── newsubscriptiondialog.ui ├── regenerateaddresses.py ├── regenerateaddresses.ui ├── settings.py ├── settings.ui ├── specialaddressbehavior.py ├── specialaddressbehavior.ui └── wanlan.ui ├── build_osx.py ├── class_addressGenerator.py ├── class_objectHashHolder.py ├── class_objectProcessor.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_sent.py ├── helper_sql.py ├── helper_startup.py ├── highlevelcrypto.py ├── i2p ├── BaseHTTPServer.py ├── CGIHTTPServer.py ├── SimpleHTTPServer.py ├── SocketServer.py ├── __init__.py ├── eep.py ├── pylib │ └── __init__.py ├── router.py ├── samclasses.py ├── select.py ├── socket.py ├── test │ ├── test_eep.py │ ├── test_samclasses.py │ ├── test_select.py │ ├── test_socket.py │ └── test_tunnel.py └── tunnel.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 ├── proofofwork.py ├── pyelliptic ├── LICENSE ├── README.md ├── __init__.py ├── arithmetic.py ├── cipher.py ├── ecc.py ├── hash.py └── openssl.py ├── qidenticon.py ├── recversion_debug.py ├── seedless.py ├── seedless_util.py ├── shared.py ├── singleton.py ├── socks ├── BUGS ├── LICENSE ├── README └── __init__.py ├── tr.py └── translations ├── bitmessage_ar.pro ├── bitmessage_ar.qm ├── bitmessage_ar.ts ├── bitmessage_cs.pro ├── bitmessage_cs.qm ├── bitmessage_cs.ts ├── bitmessage_de.pro ├── bitmessage_de.qm ├── bitmessage_de.ts ├── bitmessage_en_pirate.pro ├── bitmessage_en_pirate.qm ├── bitmessage_en_pirate.ts ├── bitmessage_eo.pro ├── bitmessage_eo.qm ├── bitmessage_eo.ts ├── bitmessage_fr.pro ├── bitmessage_fr.qm ├── bitmessage_fr.ts ├── bitmessage_ja.pro ├── bitmessage_ja.qm ├── bitmessage_ja.ts ├── bitmessage_nl.pro ├── bitmessage_nl.qm ├── bitmessage_nl.ts ├── bitmessage_no.pro ├── bitmessage_no.qm ├── bitmessage_no.ts ├── bitmessage_ru.pro ├── bitmessage_ru.qm ├── bitmessage_ru.ts ├── bitmessage_zh_cn.pro ├── bitmessage_zh_cn.qm └── bitmessage_zh_cn.ts /.gitignore: -------------------------------------------------------------------------------- 1 | **pyc 2 | **dat 3 | **txt 4 | **bak 5 | **.DS_Store 6 | src/build 7 | src/dist 8 | src/.project 9 | src/.pydevproject 10 | src/.settings/ -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2015 Jonathan Warren 2 | Copyright (c) 2013-2015 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-2014 Jonathan Warren 3 | Copyright (c) 2013-2014 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-I2P 2 | ============ 3 | 4 | This is a fork of PyBitmessage that runs natively over I2P (ONLY) 5 | It requires a running I2P router with SAM Bridge activated. 6 | 7 | **UPDATE: A Windows binary has been created using PyInstaller. 8 | It has been tested and is working under Windows 8.1. 9 | It is available from the GitHub repository at:** 10 | 11 | https://github.com/metamarcdw/PyBitmessage-I2P/releases/ 12 | 13 | Differences from vanilla Bitmessage 14 | ---------- 15 | PyBitmessage-I2P has several important differences from vanilla Bitmessage. 16 | Always remember _THIS IS A SEPARATE NETWORK_! PyBitmessage-I2P forms a completely 17 | new and separate Bitmessage network inside of I2P. Since this is a new network, 18 | the client must bootstrap by accessing an eepsite and reading a list of known nodes. 19 | This bootstrapping process can cause delays if your I2P router is not well 20 | integrated with the I2P network. Another important difference to take note of 21 | is that the format for Bitmessage addresses has been changed slightly to signify 22 | that you are seeing a BM-I2P address rather than a vanilla address. 23 | PyBitmessage-I2P addresses start with "BM+" rather than "BM-". 24 | 25 | If you would like to contribute to the network by running a node 24/7 for newcomers 26 | to bootstrap from, navigate to your Network Settings dialog and send a copy of 27 | your I2P destination string to: 28 | 29 | BM+2cToiiYrW92SSZ3616VTgQYmSmg5bVDi8w (PyBItmessage-I2P) 30 | 31 | BM-2cToiiYrW92SSZ3616VTgQYmSmg5bVDi8w (Vanilla Bitmessage) 32 | 33 | ---------- 34 | Bitmessage is a P2P communications protocol used to send encrypted messages to 35 | another person or to many subscribers. It is decentralized and trustless, 36 | meaning that you need-not inherently trust any entities like root certificate 37 | authorities. It uses strong authentication, which means that the sender of a 38 | message cannot be spoofed, and it aims to hide "non-content" data, like the 39 | sender and receiver of messages, from passive eavesdroppers like those running 40 | warrantless wiretapping programs. 41 | 42 | 43 | Development 44 | ---------- 45 | Bitmessage is a collaborative project. You are welcome to submit pull requests 46 | although if you plan to put a non-trivial amount of work into coding new 47 | features, it is recommended that you first solicit feedback on the DevTalk 48 | pseudo-mailing list: 49 | BM-2D9QKN4teYRvoq2fyzpiftPh9WP9qggtzh 50 | 51 | 52 | References 53 | ---------- 54 | * [Project Website](https://bitmessage.org) 55 | * [Protocol Specification](https://bitmessage.org/wiki/Protocol_specification) 56 | * [Whitepaper](https://bitmessage.org/bitmessage.pdf) 57 | * [Installation](https://bitmessage.org/wiki/Compiling_instructions) 58 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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) 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, libqt4-dev (>= 4.8.0), python-qt4-dev, sqlite3, libsqlite3-dev, 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 2014 Bob Mottram (4096 bits) 7 | License: MIT 8 | 9 | Files: debian/* 10 | Copyright: Copyright 2014 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/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/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 | -------------------------------------------------------------------------------- /ebuildpackage/pybitmessage-0.3.5-1.ebuild: -------------------------------------------------------------------------------- 1 | # $Header: $ 2 | 3 | EAPI=5 4 | 5 | inherit git-2 python-r1 6 | 7 | PYTHON_COMPAT=( python2_7 ) 8 | PYTHON_REQ_USE="sqlite" 9 | REQUIRED_USE="${PYTHON_REQUIRED_USE}" 10 | DESCRIPTION="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" 12 | EGIT_REPO_URI="https://github.com/Bitmessage/PyBitmessage.git" 13 | LICENSE="MIT" 14 | SLOT="0" 15 | KEYWORDS="x86" 16 | DEPEND="dev-libs/popt 17 | ${PYTHON_DEPS}" 18 | RDEPEND="${DEPEND} 19 | dev-libs/openssl 20 | dev-python/PyQt4[]" 21 | 22 | src_configure() { 23 | econf --with-popt 24 | } 25 | 26 | src_compile() { :; } 27 | 28 | src_install() { 29 | emake DESTDIR="${D}" PREFIX="/usr" install 30 | # Install README and (Debian) changelog 31 | dodoc README.md debian/changelog 32 | } 33 | -------------------------------------------------------------------------------- /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/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/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 | cd src && python2.7 build_osx.py py2app 18 | 19 | if [[ $? = "0" ]]; then 20 | hdiutil create -fs HFS+ -volname "Bitmessage" -srcfolder dist/Bitmessage.app dist/bitmessage-v$1.dmg 21 | else 22 | echo "Problem creating Bitmessage.app, stopping." 23 | exit 24 | fi 25 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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: Fri May 29 23:16:58 2015 6 | # by: PyQt4 UI code generator 4.11.2 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(50, 110, 131, 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, 110, 161, 20)) 45 | self.labelVersion.setObjectName(_fromUtf8("labelVersion")) 46 | self.label_2 = QtGui.QLabel(aboutDialog) 47 | self.label_2.setGeometry(QtCore.QRect(10, 134, 341, 51)) 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-I2P", None)) 68 | self.labelVersion.setText(_translate("aboutDialog", "version v0.1.0", None)) 69 | self.label_2.setText(_translate("aboutDialog", "

Copyright © 2012-2014 Jonathan Warren
Copyright © 2013-2014 The Bitmessage Developers
Copyright © 2015 Marc Wood

", 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 | 50 36 | 110 37 | 131 38 | 20 39 | 40 | 41 | 42 | 43 | 75 44 | true 45 | 46 | 47 | 48 | PyBitmessage-I2P 49 | 50 | 51 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 52 | 53 | 54 | 55 | 56 | 57 | 190 58 | 110 59 | 161 60 | 20 61 | 62 | 63 | 64 | version v0.1.0 65 | 66 | 67 | 68 | 69 | 70 | 10 71 | 134 72 | 341 73 | 51 74 | 75 | 76 | 77 | <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers<br/>Copyright © 2015 Marc Wood</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/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/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.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'iconglossary.ui' 4 | # 5 | # Created: Thu Jun 13 20:15:48 2013 6 | # by: PyQt4 UI code generator 4.10.1 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_iconGlossaryDialog(object): 27 | def setupUi(self, iconGlossaryDialog): 28 | iconGlossaryDialog.setObjectName(_fromUtf8("iconGlossaryDialog")) 29 | iconGlossaryDialog.resize(424, 282) 30 | self.gridLayout = QtGui.QGridLayout(iconGlossaryDialog) 31 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 32 | self.groupBox = QtGui.QGroupBox(iconGlossaryDialog) 33 | self.groupBox.setObjectName(_fromUtf8("groupBox")) 34 | self.gridLayout_2 = QtGui.QGridLayout(self.groupBox) 35 | self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) 36 | self.label = QtGui.QLabel(self.groupBox) 37 | self.label.setText(_fromUtf8("")) 38 | self.label.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png"))) 39 | self.label.setObjectName(_fromUtf8("label")) 40 | self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) 41 | self.label_2 = QtGui.QLabel(self.groupBox) 42 | self.label_2.setObjectName(_fromUtf8("label_2")) 43 | self.gridLayout_2.addWidget(self.label_2, 0, 1, 1, 1) 44 | self.label_3 = QtGui.QLabel(self.groupBox) 45 | self.label_3.setText(_fromUtf8("")) 46 | self.label_3.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/yellowicon.png"))) 47 | self.label_3.setObjectName(_fromUtf8("label_3")) 48 | self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1) 49 | self.label_4 = QtGui.QLabel(self.groupBox) 50 | self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) 51 | self.label_4.setWordWrap(True) 52 | self.label_4.setObjectName(_fromUtf8("label_4")) 53 | self.gridLayout_2.addWidget(self.label_4, 1, 1, 2, 1) 54 | spacerItem = QtGui.QSpacerItem(20, 73, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) 55 | self.gridLayout_2.addItem(spacerItem, 2, 0, 2, 1) 56 | self.labelPortNumber = QtGui.QLabel(self.groupBox) 57 | self.labelPortNumber.setObjectName(_fromUtf8("labelPortNumber")) 58 | self.gridLayout_2.addWidget(self.labelPortNumber, 3, 1, 1, 1) 59 | self.label_5 = QtGui.QLabel(self.groupBox) 60 | self.label_5.setText(_fromUtf8("")) 61 | self.label_5.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/greenicon.png"))) 62 | self.label_5.setObjectName(_fromUtf8("label_5")) 63 | self.gridLayout_2.addWidget(self.label_5, 4, 0, 1, 1) 64 | self.label_6 = QtGui.QLabel(self.groupBox) 65 | self.label_6.setWordWrap(True) 66 | self.label_6.setObjectName(_fromUtf8("label_6")) 67 | self.gridLayout_2.addWidget(self.label_6, 4, 1, 1, 1) 68 | self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1) 69 | self.buttonBox = QtGui.QDialogButtonBox(iconGlossaryDialog) 70 | self.buttonBox.setOrientation(QtCore.Qt.Horizontal) 71 | self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) 72 | self.buttonBox.setObjectName(_fromUtf8("buttonBox")) 73 | self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) 74 | 75 | self.retranslateUi(iconGlossaryDialog) 76 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), iconGlossaryDialog.accept) 77 | QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), iconGlossaryDialog.reject) 78 | QtCore.QMetaObject.connectSlotsByName(iconGlossaryDialog) 79 | 80 | def retranslateUi(self, iconGlossaryDialog): 81 | iconGlossaryDialog.setWindowTitle(_translate("iconGlossaryDialog", "Icon Glossary", None)) 82 | self.groupBox.setTitle(_translate("iconGlossaryDialog", "Icon Glossary", None)) 83 | self.label_2.setText(_translate("iconGlossaryDialog", "You have no connections with other peers. ", None)) 84 | self.label_4.setText(_translate("iconGlossaryDialog", "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.", None)) 85 | self.labelPortNumber.setText(_translate("iconGlossaryDialog", "You are using TCP port ?. (This can be changed in the settings).", None)) 86 | self.label_6.setText(_translate("iconGlossaryDialog", "You do have connections with other peers and your firewall is correctly configured.", None)) 87 | 88 | import bitmessage_icons_rc 89 | 90 | if __name__ == "__main__": 91 | import sys 92 | app = QtGui.QApplication(sys.argv) 93 | iconGlossaryDialog = QtGui.QDialog() 94 | ui = Ui_iconGlossaryDialog() 95 | ui.setupUi(iconGlossaryDialog) 96 | iconGlossaryDialog.show() 97 | sys.exit(app.exec_()) 98 | 99 | -------------------------------------------------------------------------------- /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/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", "CheckBox", 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/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/build_osx.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | name = "Bitmessage" 4 | version = "0.4.4" 5 | mainscript = ["bitmessagemain.py"] 6 | 7 | setup( 8 | name = name, 9 | version = version, 10 | app = mainscript, 11 | setup_requires = ["py2app"], 12 | options = dict( 13 | py2app = dict( 14 | resources = ["images", "translations"], 15 | includes = ['sip', 'PyQt4._qt'], 16 | iconfile = "images/bitmessage.icns" 17 | ) 18 | ) 19 | ) 20 | -------------------------------------------------------------------------------- /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 | def __init__(self, sendDataThreadMailbox): 16 | threading.Thread.__init__(self) 17 | self.shutdown = False 18 | self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. 19 | self.collectionOfHashLists = {} 20 | self.collectionOfPeerLists = {} 21 | for i in range(10): 22 | self.collectionOfHashLists[i] = [] 23 | self.collectionOfPeerLists[i] = [] 24 | 25 | def run(self): 26 | iterator = 0 27 | while not self.shutdown: 28 | if len(self.collectionOfHashLists[iterator]) > 0: 29 | self.sendDataThreadMailbox.put((0, 'sendinv', self.collectionOfHashLists[iterator])) 30 | self.collectionOfHashLists[iterator] = [] 31 | if len(self.collectionOfPeerLists[iterator]) > 0: 32 | self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) 33 | self.collectionOfPeerLists[iterator] = [] 34 | iterator += 1 35 | iterator %= 10 36 | time.sleep(1) 37 | 38 | def holdHash(self,hash): 39 | self.collectionOfHashLists[random.randrange(0, 10)].append(hash) 40 | 41 | def holdPeer(self,peerDetails): 42 | self.collectionOfPeerLists[random.randrange(0, 10)].append(peerDetails) 43 | 44 | def close(self): 45 | self.shutdown = True -------------------------------------------------------------------------------- /src/class_singleListener.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import shared 3 | from i2p import socket 4 | from class_sendDataThread import * 5 | from class_receiveDataThread import * 6 | import helper_bootstrap 7 | import errno 8 | import re 9 | 10 | # Only one singleListener thread will ever exist. It creates the 11 | # receiveDataThread and sendDataThread for each incoming connection. Note 12 | # that it cannot set the stream number because it is not known yet- the 13 | # other node will have to tell us its stream number in a version message. 14 | # If we don't care about their stream, we will close the connection 15 | # (within the recversion function of the recieveData thread) 16 | 17 | 18 | class singleListener(threading.Thread): 19 | 20 | def __init__(self): 21 | threading.Thread.__init__(self) 22 | 23 | def setup(self, selfInitiatedConnections): 24 | self.selfInitiatedConnections = selfInitiatedConnections 25 | 26 | def _createListenSocket(self, session=shared.i2psession): 27 | sock = socket.socket(session, socket.SOCK_STREAM) 28 | # This option apparently avoids the TIME_WAIT state so that we can 29 | # rebind faster 30 | # sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 31 | # sock.bind((HOST, PORT)) 32 | sock.listen(2) 33 | return sock 34 | 35 | def run(self): 36 | # If there is a trusted peer then we don't want to accept 37 | # incoming connections so we'll just abandon the thread 38 | if shared.trustedPeer: 39 | return 40 | 41 | while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): 42 | time.sleep(1) 43 | 44 | # First try listening on an IPv6 socket. This should also be 45 | # able to accept connections on IPv4. If that's not available 46 | # we'll fall back to IPv4-only. 47 | try: 48 | sock = self._createListenSocket() 49 | except socket.Error, e: 50 | if (isinstance(e.args, tuple) and 51 | e.args[0] in (errno.EAFNOSUPPORT, 52 | errno.EPFNOSUPPORT, 53 | errno.ENOPROTOOPT)): 54 | sock = self._createListenSocket() 55 | else: 56 | raise 57 | 58 | shared.myDestination = sock.dest 59 | shared.do_scrapePeers() 60 | with shared.printLock: 61 | print 'Listening for incoming connections.' 62 | print 'Listening on:', sock.dest 63 | 64 | while True: 65 | while len(shared.connectedHostsList) > 220: 66 | with shared.printLock: 67 | print 'We are connected to too many people. Not accepting further incoming connections for ten seconds.' 68 | 69 | time.sleep(10) 70 | 71 | while True: 72 | socketObject, sockdest = sock.accept() 73 | 74 | # The following code will, unfortunately, block an 75 | # incoming connection if someone else on the same LAN 76 | # is already connected because the two computers will 77 | # share the same external IP. This is here to prevent 78 | # connection flooding. 79 | if sockdest in shared.connectedHostsList: 80 | socketObject.close() 81 | with shared.printLock: 82 | print 'We are already connected to', sockdest + '. Ignoring connection.' 83 | else: 84 | break 85 | 86 | someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. 87 | sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. 88 | socketObject.settimeout(600) 89 | 90 | sd = sendDataThread(sendDataThreadQueue) 91 | sd.setup( 92 | socketObject, sockdest, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware) 93 | sd.start() 94 | 95 | rd = receiveDataThread() 96 | rd.daemon = True # close the main program even if there are threads left 97 | rd.setup( 98 | socketObject, sockdest, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue) 99 | rd.start() 100 | 101 | with shared.printLock: 102 | print self, 'connected to', sockdest, 'during INCOMING request.' 103 | 104 | -------------------------------------------------------------------------------- /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 shared 22 | import sys 23 | import helper_startup 24 | helper_startup.loadConfig() 25 | 26 | # TODO(xj9): Get from a config file. 27 | log_level = 'DEBUG' 28 | 29 | def configureLogging(): 30 | logging.config.dictConfig({ 31 | 'version': 1, 32 | 'formatters': { 33 | 'default': { 34 | 'format': '%(asctime)s - %(levelname)s - %(message)s', 35 | }, 36 | }, 37 | 'handlers': { 38 | 'console': { 39 | 'class': 'logging.StreamHandler', 40 | 'formatter': 'default', 41 | 'level': log_level, 42 | 'stream': 'ext://sys.stdout' 43 | }, 44 | 'file': { 45 | 'class': 'logging.handlers.RotatingFileHandler', 46 | 'formatter': 'default', 47 | 'level': log_level, 48 | 'filename': shared.appdata + 'debug.log', 49 | 'maxBytes': 2097152, # 2 MiB 50 | 'backupCount': 1, 51 | } 52 | }, 53 | 'loggers': { 54 | 'console_only': { 55 | 'handlers': ['console'], 56 | 'propagate' : 0 57 | }, 58 | 'file_only': { 59 | 'handlers': ['file'], 60 | 'propagate' : 0 61 | }, 62 | 'both': { 63 | 'handlers': ['console', 'file'], 64 | 'propagate' : 0 65 | }, 66 | }, 67 | 'root': { 68 | 'level': log_level, 69 | 'handlers': ['console'], 70 | }, 71 | }) 72 | # TODO (xj9): Get from a config file. 73 | #logger = logging.getLogger('console_only') 74 | configureLogging() 75 | if '-c' in sys.argv: 76 | logger = logging.getLogger('file_only') 77 | else: 78 | logger = logging.getLogger('both') 79 | 80 | def restartLoggingInUpdatedAppdataLocation(): 81 | global logger 82 | for i in list(logger.handlers): 83 | logger.removeHandler(i) 84 | i.flush() 85 | i.close() 86 | configureLogging() 87 | if '-c' in sys.argv: 88 | logger = logging.getLogger('file_only') 89 | else: 90 | logger = logging.getLogger('both') 91 | 92 | -------------------------------------------------------------------------------- /src/defaultKnownNodes.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | from i2p 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 getBootstrapListFromEepsite(): 11 | try: 12 | dest = shared.config.get('bitmessagesettings', 'bootstrapeepsite') 13 | except: 14 | return [] 15 | 16 | if not dest or dest == '': 17 | return [] 18 | 19 | while True: 20 | print 'Getting some defaultKnownNodes from eepsite', dest 21 | try: 22 | S = socket.socket('', socket.SOCK_STREAM) 23 | S.connect(dest) 24 | S.send('GET /bootstrap.json HTTP/1.0\r\n\r\n') # Send request 25 | break 26 | except socket.NetworkError as ne: 27 | print "I2P Network Error:", ne 28 | continue 29 | 30 | f = S.makefile() # File object 31 | 32 | while True: # Read header 33 | line = f.readline().strip() # Read a line 34 | if line == '': break # Content begins 35 | 36 | str = f.read() # Read file object 37 | f.close() # Close file, connection 38 | S.close() 39 | 40 | import json 41 | return json.loads(str) # Load list from JSON and return 42 | 43 | def createDefaultKnownNodes(appdata): 44 | ############## Stream 1 ################ 45 | stream1 = {} 46 | #stream1[shared.Peer('VXVZRtml-XDgkwFcehckXBQ1qOx8whwjYlPZnKyIp3L5OFhwF6moUjkAoN~4J5TmdBLP5jxoOEwe5pC6TcgkKAvEXLqGvb607LPr9XhhWdgfHFyfcEG1zGhMziisOSHwmnUAjlvd5FT9H7ouv2on5JvLAHRiqe-vO0Ifz~dnkQyhd-IouWArdTlXQqhm7ArMS1-vHQKaslktY9BrFS8ZxKojbAMxcrBrt-9IND1f9-KpRBwtKp0Hup6jzIk3cNGbP4eadZ3F-Zic6oy-ktsH0iz5FBKmpMdc36SQDG8rReMjngKZntl4OhxjAZ7eYLllA6T3X5wdICkoqNJEobByGx9TEYXq6bVlyp7aoxGuB8~piqJWoCqbgfcIDUznP050YoCKp3Uk6u9DmROP4pckzg910FdKSF3TRlebKRRzB7KHWXV~CY3xZEp8CKblBljJEw3FNv0IZ5Guq0tNi9bjs6uXtY1IPviEN9cVfmT3EZ5WK8b~3JdvZrDGKoWAJkRAAAAA')] = int(time.time()) 47 | 48 | # eepsite_list = getBootstrapListFromEepsite() 49 | # for dest in eepsite_list: 50 | # stream1[shared.Peer( str(dest) )] = int(time.time()) 51 | 52 | ############# Stream 2 ################# 53 | stream2 = {} 54 | # None yet 55 | 56 | ############# Stream 3 ################# 57 | stream3 = {} 58 | # None yet 59 | 60 | allKnownNodes = {} 61 | allKnownNodes[1] = stream1 62 | allKnownNodes[2] = stream2 63 | allKnownNodes[3] = stream3 64 | 65 | #print stream1 66 | #print allKnownNodes 67 | 68 | with open(appdata + 'knownnodes.dat', 'wb') as output: 69 | # Pickle dictionary using protocol 0. 70 | pickle.dump(allKnownNodes, output) 71 | 72 | return allKnownNodes 73 | 74 | def readDefaultKnownNodes(appdata): 75 | pickleFile = open(appdata + 'knownnodes.dat', 'rb') 76 | knownNodes = pickle.load(pickleFile) 77 | pickleFile.close() 78 | for stream, storedValue in knownNodes.items(): 79 | for dest,value in storedValue.items(): 80 | # New knownNodes format. 81 | storedtime = value 82 | print dest, '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(storedtime)),'utf-8') 83 | 84 | if __name__ == "__main__": 85 | 86 | APPNAME = "config/PyBitmessage" 87 | from os import path, environ 88 | if sys.platform == 'darwin': 89 | from AppKit import NSSearchPathForDirectoriesInDomains # @UnresolvedImport 90 | # http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains 91 | # NSApplicationSupportDirectory = 14 92 | # NSUserDomainMask = 1 93 | # True for expanding the tilde into a fully qualified path 94 | appdata = path.join(NSSearchPathForDirectoriesInDomains(14, 1, True)[0], APPNAME) + '/' 95 | elif 'win' in sys.platform: 96 | appdata = path.join(environ['APPDATA'], APPNAME) + '\\' 97 | else: 98 | appdata = path.expanduser(path.join("~", "." + APPNAME + "/")) 99 | 100 | 101 | print 'New list of all known nodes:', createDefaultKnownNodes(appdata) 102 | readDefaultKnownNodes(appdata) 103 | 104 | 105 | -------------------------------------------------------------------------------- /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 | def knownNodes(): 8 | try: 9 | # We shouldn't have to use the shared.knownNodesLock because this had 10 | # better be the only thread accessing knownNodes right now. 11 | pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb') 12 | loadedKnownNodes = pickle.load(pickleFile) 13 | pickleFile.close() 14 | 15 | for stream, nodes in loadedKnownNodes.items(): 16 | shared.knownNodes[stream] = {} 17 | for node_tuple in nodes.items(): 18 | peer, time = node_tuple 19 | shared.knownNodes[stream][peer] = time 20 | except: 21 | shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) 22 | if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: 23 | print 'Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.' 24 | raise SystemExit 25 | 26 | def dns(): 27 | # DNS bootstrap. This could be programmed to use the SOCKS proxy to do the 28 | # DNS lookup some day but for now we will just rely on the entries in 29 | # defaultKnownNodes.py. Hopefully either they are up to date or the user 30 | # has run Bitmessage recently without SOCKS turned on and received good 31 | # bootstrap nodes using that method. 32 | with shared.printLock: 33 | if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': 34 | try: 35 | for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): 36 | print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' 37 | shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) 38 | except: 39 | print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.' 40 | try: 41 | for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): 42 | print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' 43 | shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) 44 | except: 45 | print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.' 46 | else: 47 | print 'DNS bootstrap skipped because SOCKS is used.' 48 | 49 | -------------------------------------------------------------------------------- /src/helper_generic.py: -------------------------------------------------------------------------------- 1 | import shared 2 | import sys 3 | 4 | def convertIntToString(n): 5 | a = __builtins__.hex(n) 6 | if a[-1:] == 'L': 7 | a = a[:-1] 8 | if (len(a) % 2) == 0: 9 | return a[2:].decode('hex') 10 | else: 11 | return ('0' + a[2:]).decode('hex') 12 | 13 | 14 | def convertStringToInt(s): 15 | return int(s.encode('hex'), 16) 16 | 17 | 18 | def signal_handler(signal, frame): 19 | if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): 20 | shared.doCleanShutdown() 21 | sys.exit(0) 22 | else: 23 | print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' 24 | 25 | def isHostInPrivateIPRange(host): 26 | if host[:3] == '10.': 27 | return True 28 | if host[:4] == '172.': 29 | if host[6] == '.': 30 | if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: 31 | return True 32 | if host[:8] == '192.168.': 33 | return True 34 | return False 35 | 36 | def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): 37 | return data + paddingChar * (desiredMsgLength - len(data)) 38 | -------------------------------------------------------------------------------- /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 | shared.UISignalQueue.put(('changedInboxUnread', None)) 7 | 8 | def trash(msgid): 9 | sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) 10 | shared.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) 11 | 12 | def isMessageAlreadyInInbox(sigHash): 13 | queryReturn = sqlQuery( 14 | '''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash) 15 | return queryReturn[0][0] != 0 -------------------------------------------------------------------------------- /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 | else: 15 | sqlSubmitQueue.put(args) 16 | 17 | queryreturn = sqlReturnQueue.get() 18 | sqlLock.release() 19 | 20 | return queryreturn 21 | 22 | def sqlExecute(sqlStatement, *args): 23 | sqlLock.acquire() 24 | sqlSubmitQueue.put(sqlStatement) 25 | 26 | if args == (): 27 | sqlSubmitQueue.put('') 28 | else: 29 | sqlSubmitQueue.put(args) 30 | 31 | sqlReturnQueue.get() 32 | sqlSubmitQueue.put('commit') 33 | sqlLock.release() 34 | 35 | def sqlStoredProcedure(procName): 36 | sqlLock.acquire() 37 | sqlSubmitQueue.put(procName) 38 | sqlLock.release() 39 | 40 | class SqlBulkExecute: 41 | def __enter__(self): 42 | sqlLock.acquire() 43 | return self 44 | 45 | def __exit__(self, type, value, traceback): 46 | sqlSubmitQueue.put('commit') 47 | sqlLock.release() 48 | 49 | def execute(self, sqlStatement, *args): 50 | sqlSubmitQueue.put(sqlStatement) 51 | 52 | if args == (): 53 | sqlSubmitQueue.put('') 54 | else: 55 | sqlSubmitQueue.put(args) 56 | sqlReturnQueue.get() 57 | 58 | def query(self, sqlStatement, *args): 59 | sqlSubmitQueue.put(sqlStatement) 60 | 61 | if args == (): 62 | sqlSubmitQueue.put('') 63 | else: 64 | sqlSubmitQueue.put(args) 65 | return sqlReturnQueue.get() 66 | 67 | -------------------------------------------------------------------------------- /src/highlevelcrypto.py: -------------------------------------------------------------------------------- 1 | import pyelliptic 2 | from pyelliptic import arithmetic as a, OpenSSL 3 | def makeCryptor(privkey): 4 | private_key = a.changebase(privkey, 16, 256, minlen=32) 5 | public_key = pointMult(private_key) 6 | privkey_bin = '\x02\xca\x00\x20' + private_key 7 | pubkey_bin = '\x02\xca\x00\x20' + public_key[1:-32] + '\x00\x20' + public_key[-32:] 8 | cryptor = pyelliptic.ECC(curve='secp256k1',privkey=privkey_bin,pubkey=pubkey_bin) 9 | return cryptor 10 | def hexToPubkey(pubkey): 11 | pubkey_raw = a.changebase(pubkey[2:],16,256,minlen=64) 12 | pubkey_bin = '\x02\xca\x00 '+pubkey_raw[:32]+'\x00 '+pubkey_raw[32:] 13 | return pubkey_bin 14 | def makePubCryptor(pubkey): 15 | pubkey_bin = hexToPubkey(pubkey) 16 | return pyelliptic.ECC(curve='secp256k1',pubkey=pubkey_bin) 17 | # Converts hex private key into hex public key 18 | def privToPub(privkey): 19 | private_key = a.changebase(privkey, 16, 256, minlen=32) 20 | public_key = pointMult(private_key) 21 | return public_key.encode('hex') 22 | # Encrypts message with hex public key 23 | def encrypt(msg,hexPubkey): 24 | return pyelliptic.ECC(curve='secp256k1').encrypt(msg,hexToPubkey(hexPubkey)) 25 | # Decrypts message with hex private key 26 | def decrypt(msg,hexPrivkey): 27 | return makeCryptor(hexPrivkey).decrypt(msg) 28 | # Decrypts message with an existing pyelliptic.ECC.ECC object 29 | def decryptFast(msg,cryptor): 30 | return cryptor.decrypt(msg) 31 | # Signs with hex private key 32 | def sign(msg,hexPrivkey): 33 | # pyelliptic is upgrading from SHA1 to SHA256 for signing. We must 34 | # upgrade PyBitmessage gracefully. 35 | # https://github.com/yann2192/pyelliptic/pull/33 36 | # More discussion: https://github.com/yann2192/pyelliptic/issues/32 37 | return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_ecdsa) # SHA1 38 | #return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) # SHA256. We should switch to this eventually. 39 | # Verifies with hex public key 40 | def verify(msg,sig,hexPubkey): 41 | # As mentioned above, we must upgrade gracefully to use SHA256. So 42 | # let us check the signature using both SHA1 and SHA256 and if one 43 | # of them passes then we will be satisfied. Eventually this can 44 | # be simplified and we'll only check with SHA256. 45 | try: 46 | sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.EVP_ecdsa) # old SHA1 algorithm. 47 | except: 48 | sigVerifyPassed = False 49 | if sigVerifyPassed: 50 | # The signature check passed using SHA1 51 | return True 52 | # The signature check using SHA1 failed. Let us try it with SHA256. 53 | try: 54 | return makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.EVP_sha256) 55 | except: 56 | return False 57 | 58 | # Does an EC point multiplication; turns a private key into a public key. 59 | def pointMult(secret): 60 | while True: 61 | try: 62 | """ 63 | Evidently, this type of error can occur very rarely: 64 | 65 | File "highlevelcrypto.py", line 54, in pointMult 66 | group = OpenSSL.EC_KEY_get0_group(k) 67 | WindowsError: exception: access violation reading 0x0000000000000008 68 | """ 69 | k = OpenSSL.EC_KEY_new_by_curve_name(OpenSSL.get_curve('secp256k1')) 70 | priv_key = OpenSSL.BN_bin2bn(secret, 32, None) 71 | group = OpenSSL.EC_KEY_get0_group(k) 72 | pub_key = OpenSSL.EC_POINT_new(group) 73 | 74 | OpenSSL.EC_POINT_mul(group, pub_key, priv_key, None, None, None) 75 | OpenSSL.EC_KEY_set_private_key(k, priv_key) 76 | OpenSSL.EC_KEY_set_public_key(k, pub_key) 77 | 78 | size = OpenSSL.i2o_ECPublicKey(k, None) 79 | mb = OpenSSL.create_string_buffer(size) 80 | OpenSSL.i2o_ECPublicKey(k, OpenSSL.byref(OpenSSL.pointer(mb))) 81 | 82 | OpenSSL.EC_POINT_free(pub_key) 83 | OpenSSL.BN_free(priv_key) 84 | OpenSSL.EC_KEY_free(k) 85 | return mb.raw 86 | 87 | except Exception as e: 88 | import traceback 89 | import time 90 | traceback.print_exc() 91 | time.sleep(0.2) 92 | 93 | -------------------------------------------------------------------------------- /src/i2p/BaseHTTPServer.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | """ 4 | Emulation of Python BaseHTTPServer module using I2P sockets. 5 | 6 | The Python module is described at 7 | http://www.python.org/doc/current/lib/module-BaseHTTPServer.html 8 | 9 | To get a server going, use: 10 | 11 | >>> from i2p import BaseHTTPServer 12 | >>> BaseHTTPServer.test(). 13 | 14 | Consult the documentation for function test() to change basic 15 | server settings, such as the session name. 16 | 17 | A fully customizable example: 18 | 19 | >>> from i2p import BaseHTTPServer 20 | >>> session = "mytestxxx.i2p" # SAM session name 21 | >>> class MyServer(BaseHTTPServer.HTTPServer): pass 22 | >>> class MyRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): pass 23 | >>> httpd = MyServer(session, MyRequestHandler) 24 | >>> httpd.socket.dest 25 | (Base64 Destination of server) 26 | >>> httpd.serve_forever() 27 | 28 | """ 29 | 30 | # By aum. 31 | 32 | # Hack to keep Python from importing from current directory: 33 | # Use pylib package, then use = signs instead of from x import y. 34 | import pylib 35 | BaseHTTPServer = pylib.BaseHTTPServer 36 | 37 | import sys 38 | import i2p.SocketServer 39 | 40 | __version__ = "0.3" 41 | 42 | __all__ = ["HTTPServer", "BaseHTTPRequestHandler", "test"] 43 | 44 | DEFAULT_ERROR_MESSAGE = BaseHTTPServer.DEFAULT_ERROR_MESSAGE 45 | 46 | class HTTPServer(i2p.SocketServer.TCPServer, BaseHTTPServer.HTTPServer): 47 | """ 48 | Same interface as Python class 49 | BaseHTTPServer.HTTPServer. 50 | """ 51 | 52 | class BaseHTTPRequestHandler( 53 | i2p.SocketServer.StreamRequestHandler, 54 | BaseHTTPServer.BaseHTTPRequestHandler): 55 | """ 56 | Same interface as Python class 57 | BaseHTTPServer.BaseHTTPRequestHandler. 58 | """ 59 | 60 | def test(HandlerClass = BaseHTTPRequestHandler, 61 | ServerClass = HTTPServer, protocol="HTTP/1.0", 62 | session = "mytestxxx.i2p"): 63 | """ 64 | Test the HTTP request handler class. 65 | 66 | This runs an I2P TCP server under SAM session 'session'. 67 | If a single command line argument is given, the argument is used 68 | instead as the SAM session name. 69 | """ 70 | 71 | if sys.argv[1:] and __name__ == '__main__': 72 | session = sys.argv[1] 73 | 74 | HandlerClass.protocol_version = protocol 75 | httpd = ServerClass(session, HandlerClass) 76 | 77 | print "Serving HTTP on", session, "..." 78 | print "Destination follows:" 79 | print httpd.socket.dest 80 | httpd.serve_forever() 81 | 82 | if __name__ == '__main__': 83 | test() 84 | -------------------------------------------------------------------------------- /src/i2p/CGIHTTPServer.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | """ 4 | Emulation of Python CGIHTTPServer module using I2P sockets. 5 | 6 | The Python module is described at 7 | http://www.python.org/doc/current/lib/module-CGIHTTPServer.html 8 | 9 | To get a server going, use: 10 | 11 | >>> from i2p import CGIHTTPServer 12 | >>> CGIHTTPServer.test(). 13 | 14 | Consult the documentation for function test() to change basic 15 | server settings, such as the session name. 16 | 17 | A fully customizable example: 18 | 19 | >>> from i2p import BaseHTTPServer, CGIHTTPServer 20 | >>> session = "mytestxxx.i2p" # SAM session name 21 | >>> class MyServer(BaseHTTPServer.HTTPServer): pass 22 | >>> class MyRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): pass 23 | >>> httpd = MyServer(session, MyRequestHandler) 24 | >>> httpd.socket.dest 25 | (Base64 Destination of server) 26 | >>> httpd.serve_forever() 27 | 28 | """ 29 | 30 | # By aum. 31 | __all__ = ["CGIHTTPRequestHandler", "test"] 32 | 33 | # Hack to keep Python from importing from current directory: 34 | # Use pylib package, then use = signs instead of from x import y. 35 | import pylib 36 | CGIHTTPServer = pylib.CGIHTTPServer 37 | nobody_uid = CGIHTTPServer.nobody_uid 38 | executable = CGIHTTPServer.executable 39 | 40 | import sys 41 | import i2p.BaseHTTPServer 42 | import i2p.SimpleHTTPServer 43 | 44 | HTTPServer = i2p.BaseHTTPServer.HTTPServer 45 | class CGIHTTPRequestHandler(CGIHTTPServer.CGIHTTPRequestHandler): 46 | """ 47 | Same interface as Python class 48 | CGIHTTPServer.CGIHTTPRequestHandler. 49 | """ 50 | 51 | def test(HandlerClass = CGIHTTPRequestHandler, 52 | ServerClass = i2p.BaseHTTPServer.HTTPServer, 53 | session = "mytestxxx.i2p"): 54 | """ 55 | Test the HTTP CGI request handler class. 56 | 57 | This runs an I2P TCP server under SAM session 'session'. 58 | If a single command line argument is given, the argument is used 59 | instead as the SAM session name. 60 | """ 61 | if sys.argv[1:] and __name__ == '__main__': 62 | session = sys.argv[1] 63 | 64 | i2p.SimpleHTTPServer.test(HandlerClass, ServerClass, 65 | session=session) 66 | 67 | if __name__ == '__main__': 68 | test() 69 | 70 | -------------------------------------------------------------------------------- /src/i2p/SimpleHTTPServer.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | """ 4 | Emulation of Python SimpleHTTPServer module using I2P sockets. 5 | 6 | The Python module is described at 7 | http://www.python.org/doc/current/lib/module-SimpleHTTPServer.html 8 | 9 | To get a server going, use: 10 | 11 | >>> from i2p import SimpleHTTPServer 12 | >>> SimpleHTTPServer.test(). 13 | 14 | Consult the documentation for function test() to change basic 15 | server settings, such as the session name. 16 | 17 | A fully customizable example: 18 | 19 | >>> from i2p import BaseHTTPServer, SimpleHTTPServer 20 | >>> session = "mytestxxx.i2p" # SAM session name 21 | >>> class MyServer(BaseHTTPServer.HTTPServer): pass 22 | >>> class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): pass 23 | >>> httpd = MyServer(session, MyRequestHandler) 24 | >>> httpd.socket.dest 25 | (Base64 Destination of server) 26 | >>> httpd.serve_forever() 27 | 28 | """ 29 | 30 | # By aum. 31 | 32 | # Hack to keep Python from importing from current directory: 33 | # Use pylib package, then use = signs instead of from x import y. 34 | import pylib 35 | SimpleHTTPServer = pylib.SimpleHTTPServer 36 | 37 | import sys 38 | import i2p.BaseHTTPServer 39 | 40 | __version__ = "0.1.0" 41 | 42 | __all__ = ["SimpleHTTPRequestHandler", "test"] 43 | 44 | HTTPServer = i2p.BaseHTTPServer.HTTPServer 45 | class SimpleHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 46 | """ 47 | Same interface as Python class 48 | SimpleHTTPServer.SimpleHTTPRequestHandler. 49 | """ 50 | 51 | def test(HandlerClass = SimpleHTTPRequestHandler, 52 | ServerClass = i2p.BaseHTTPServer.HTTPServer, 53 | session = "mytestxxx.i2p"): 54 | """ 55 | Test the HTTP simple request handler class. 56 | 57 | This runs an I2P TCP server under SAM session 'session'. 58 | If a single command line argument is given, the argument is used 59 | instead as the SAM session name. 60 | """ 61 | if sys.argv[1:] and __name__ == '__main__': 62 | session = sys.argv[1] 63 | 64 | i2p.BaseHTTPServer.test(HandlerClass, ServerClass, 65 | session=session) 66 | 67 | if __name__ == '__main__': 68 | test() 69 | -------------------------------------------------------------------------------- /src/i2p/SocketServer.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Emulation of Python SocketServer module using I2P sockets. 4 | 5 | The Python module is described at 6 | http://www.python.org/doc/current/lib/module-SocketServer.html 7 | 8 | """ 9 | 10 | # By aum. 11 | 12 | # Hack to keep Python from importing from current directory: 13 | # Use pylib package, then use = signs instead of from x import y. 14 | import pylib 15 | SocketServer = pylib.SocketServer 16 | 17 | import i2p.socket 18 | class BaseServer(SocketServer.BaseServer): 19 | pass 20 | class TCPServer(SocketServer.TCPServer, BaseServer): 21 | 22 | socket_type = i2p.socket.SOCK_STREAM 23 | 24 | def __init__(self, session, RequestHandlerClass): 25 | """ 26 | Constructor. May be extended, do not override. 27 | 28 | The 'session' argument indicates the SAM session 29 | name that should be used for the server. See module 30 | i2p.socket for details on SAM sessions. 31 | """ 32 | BaseServer.__init__(self, session, RequestHandlerClass) 33 | 34 | #self.socket = socket.socket(self.address_family, 35 | # self.socket_type) 36 | self.session = session 37 | self.socket = i2p.socket.socket(session, self.socket_type) 38 | 39 | self.server_bind() 40 | self.server_activate() 41 | 42 | class UDPServer(TCPServer, SocketServer.UDPServer): 43 | pass 44 | 45 | class ForkingMixIn(SocketServer.ForkingMixIn): 46 | pass 47 | 48 | class ThreadingMixIn(SocketServer.ThreadingMixIn): 49 | pass 50 | 51 | class ForkingUDPServer(ForkingMixIn, UDPServer): 52 | pass 53 | 54 | class ForkingTCPServer(ForkingMixIn, TCPServer): 55 | pass 56 | 57 | class ThreadingUDPServer(ThreadingMixIn, UDPServer): 58 | pass 59 | 60 | class ThreadingTCPServer(ThreadingMixIn, TCPServer): 61 | pass 62 | 63 | class BaseRequestHandler(SocketServer.BaseRequestHandler): 64 | pass 65 | 66 | class StreamRequestHandler(SocketServer.StreamRequestHandler): 67 | pass 68 | 69 | class DatagramRequestHandler(SocketServer.DatagramRequestHandler): 70 | pass 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/i2p/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | i2p -- I2P Python interface 3 | """ 4 | 5 | __all__ = [ 6 | 'BaseHTTPServer', 7 | 'CGIHTTPServer', 8 | 'eep', 9 | 'router', 10 | 'select', 11 | 'SimpleHTTPServer', 12 | 'socket', 13 | 'SocketServer', 14 | 'tunnel', 15 | ] 16 | 17 | class Error(Exception): 18 | """Base class for all I2P errors.""" 19 | 20 | class RouterError(Error): 21 | """Could not connect to router.""" 22 | 23 | -------------------------------------------------------------------------------- /src/i2p/eep.py: -------------------------------------------------------------------------------- 1 | 2 | # ------------------------------------------------------------- 3 | # eep.py: Eeproxy access module 4 | # ------------------------------------------------------------- 5 | 6 | """ 7 | Eeproxy access module 8 | """ 9 | 10 | import urllib2 11 | 12 | eepaddr = '127.0.0.1:4444' # Default port for eeproxy 13 | 14 | # -------------------------------------------------- 15 | # Functions 16 | # -------------------------------------------------- 17 | 18 | def urlopen(url, eepaddr=eepaddr): 19 | """Like urllib2.urlopen(url), but only works for eep-sites. 20 | Example: f = urlopen('http://duck.i2p/index.html')""" 21 | if url.find('http://') != 0: url = 'http://' + url 22 | 23 | # Handle I2P Destination 24 | if len(url) >= 256: 25 | suffix = url[len('http://'):] 26 | if suffix[:4] != 'i2p/': url = 'http://i2p/' + suffix 27 | 28 | # Add trailing slash 29 | if url.find('/', len('http://')) < 0: url = url + '/' 30 | 31 | # Remove http:// and trailing slash from eepaddr. 32 | if eepaddr.find('http://') == 0: eepaddr = eepaddr[len('http://'):] 33 | eepaddr = eepaddr.rstrip('/') 34 | 35 | proxy = urllib2.ProxyHandler( \ 36 | {'http': 'http://' + eepaddr}) 37 | opener = urllib2.build_opener(proxy, urllib2.HTTPHandler) 38 | return opener.open(url) 39 | 40 | def urlget(url, eepaddr=eepaddr): 41 | """Get contents of an eepsite. 42 | Example: urlget('http://duck.i2p/').""" 43 | f = urlopen(url, eepaddr=eepaddr) 44 | ans = f.read() 45 | f.close() 46 | return ans 47 | -------------------------------------------------------------------------------- /src/i2p/pylib/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # ------------------------------------------------ 3 | # Hack to import the Python library modules 4 | # when names conflict in our package. 5 | # ------------------------------------------------ 6 | 7 | import sys 8 | sys.path.reverse() 9 | 10 | import socket 11 | import select 12 | import BaseHTTPServer 13 | import SocketServer 14 | import CGIHTTPServer 15 | import SimpleHTTPServer 16 | 17 | sys.path.reverse() 18 | -------------------------------------------------------------------------------- /src/i2p/select.py: -------------------------------------------------------------------------------- 1 | 2 | # ------------------------------------------------------------- 3 | # select.py: Emulation of Python select module. 4 | # ------------------------------------------------------------- 5 | 6 | """ 7 | I2P Python API - Emulation of Python select module. 8 | """ 9 | 10 | import time 11 | 12 | import i2p.socket 13 | from i2p.pylib import select as pyselect # Import Python select 14 | 15 | # -------------------------------------------------- 16 | # Poll and select 17 | # -------------------------------------------------- 18 | 19 | POLLIN = 1 # There is data to read 20 | POLLPRI = 1 # Same as POLLIN 21 | POLLOUT = 4 # Ready for output 22 | POLLERR = 8 # Wait for error condition 23 | POLLHUP = 16 # Not implemented 24 | POLLNVAL = 32 # Not implemented 25 | 26 | class Poll: 27 | """Class implementing poll interface. Works for Python sockets 28 | and SAM sockets.""" 29 | def __init__(self): 30 | self.fds = {} # Maps _hash() -> (socket, mask) 31 | def _hash(self, fd): 32 | """Get a unique number for each object.""" 33 | if isinstance(fd, int): 34 | return fd # Use the fd itself if integer. 35 | else: 36 | return id(fd) # Use object address (no copies!) 37 | def register(self, fd, eventmask=POLLIN|POLLOUT|POLLERR): 38 | self.fds[self._hash(fd)] = (fd, eventmask) 39 | def unregister(self, fd): 40 | del self.fds[self._hash(fd)] 41 | def poll(self, timeout=None): 42 | readlist, writelist, errlist = [], [], [] 43 | for F, mask in self.fds.values(): 44 | if mask & POLLIN: readlist += [F] 45 | if mask & POLLOUT: writelist += [F] 46 | if mask & POLLERR: errlist += [F] 47 | (Rs, Ws, Es) = select(readlist, writelist, errlist, 48 | timeout=timeout) 49 | ans = [] 50 | for R in Rs: ans.append((R, POLLIN)) 51 | for W in Ws: ans.append((W, POLLOUT)) 52 | for E in Es: ans.append((E, POLLERR)) 53 | return ans 54 | 55 | def poll(): 56 | """Returns a polling object. Works on SAM sockets and Python 57 | sockets. See select.poll() in the Python library for more 58 | information. 59 | 60 | Polling flags specified in this module: 61 | - POLLIN 62 | - POLLOUT 63 | - POLLERR 64 | - POLLHUP 65 | - POLLNVAL 66 | - POLLPRI 67 | """ 68 | return Poll() 69 | 70 | def _has_data(S): 71 | """True if the given I2P socket has data waiting.""" 72 | try: 73 | S.recv(1, i2p.socket.MSG_PEEK | i2p.socket.MSG_DONTWAIT) 74 | return True 75 | except: 76 | return False 77 | 78 | def _noblock_select(readlist, writelist, errlist): 79 | """Makes a single query of the given sockets, like 80 | select() with timeout 0.0.""" 81 | Rans = [] 82 | Wans = [] 83 | Eans = [] 84 | 85 | # Check for read availability. 86 | for R in readlist: 87 | if isinstance(R, int) or hasattr(R, 'fileno'): 88 | # Python socket 89 | if len(pyselect.select([R], [], [], 0.0)[0]) > 0: 90 | Rans.append(R) 91 | else: 92 | # SAM Socket 93 | if _has_data(R): 94 | Rans.append(R) 95 | # if R.type == i2p.socket.SOCK_STREAM: 96 | # try: 97 | # R._verify_connected() 98 | # Rans.append(R) 99 | # except: 100 | # pass 101 | # else: 102 | # if len(R.sessobj) > 0: Rans.append(R) 103 | 104 | # Check for write availability. 105 | for W in writelist: 106 | if isinstance(W, int) or hasattr(W, 'fileno'): 107 | # Python socket 108 | if len(pyselect.select([], [W], [], 0.0)[1]) > 0: 109 | Wans.append(W) 110 | else: 111 | # SAM Socket 112 | if W.type == i2p.socket.SOCK_STREAM: 113 | try: 114 | W._verify_connected() 115 | Wans.append(W) 116 | except: 117 | pass 118 | else: 119 | Wans.append(W) 120 | 121 | # Check for error conditions. 122 | # These can only be stream errors. 123 | for E in errlist: 124 | if isinstance(E, int) or hasattr(E, 'fileno'): 125 | # Python socket 126 | if len(pyselect.select([], [], [E], 0.0)[2]) > 0: 127 | Eans.append(E) 128 | else: 129 | if E.type == i2p.socket.SOCK_STREAM: 130 | try: 131 | # FIXME: Use a ._get_error() function for errors. 132 | # Socket can only have an error if it connected. 133 | E._verify_connected() 134 | if E.sessobj.err != None: 135 | Eans.append(E) 136 | except: 137 | pass 138 | 139 | return (Rans, Wans, Eans) 140 | 141 | 142 | def select(readlist, writelist, errlist, timeout=None): 143 | """Performs a select call. Works on SAM sockets and Python 144 | sockets. See select.select() in the Python library for more 145 | information.""" 146 | 147 | if timeout != None: end = time.time() + timeout 148 | while True: 149 | # FIXME: Check performance. 150 | # Use pyselect.poll for Python sockets, if needed for speed. 151 | (Rans, Wans, Eans) = _noblock_select(readlist,writelist,errlist) 152 | 153 | if timeout != None and time.time() >= end: break 154 | if len(Rans) != 0 or len(Wans) != 0 or len(Eans) != 0: 155 | # One or more sockets are ready. 156 | if timeout != 0.0: 157 | # Check again, because sockets may have changed state while 158 | # we did _noblock_select (it's safer to check twice, since 159 | # they usually go from no data => data ready, and so forth). 160 | (Rans, Wans, Eans) = _noblock_select(readlist, writelist, 161 | errlist) 162 | return (Rans, Wans, Eans) 163 | 164 | time.sleep(0.01) 165 | 166 | return (Rans, Wans, Eans) 167 | -------------------------------------------------------------------------------- /src/i2p/test/test_eep.py: -------------------------------------------------------------------------------- 1 | 2 | # ----------------------------------------------------- 3 | # test_eep.py: Unit tests for eep.py. 4 | # ----------------------------------------------------- 5 | 6 | # Make sure we can import i2p 7 | import sys; sys.path += ['../../'] 8 | 9 | import traceback, sys 10 | from i2p import eep 11 | 12 | def verify_html(s): 13 | """Raise an error if s does not end with """ 14 | assert s.strip().lower()[-7:] == '' 15 | 16 | def eepget_test(): 17 | try: 18 | verify_html(eep.urlget('http://duck.i2p/index.html')) 19 | verify_html(eep.urlget('http://duck.i2p/')) 20 | verify_html(eep.urlget('http://duck.i2p')) 21 | verify_html(eep.urlget('duck.i2p/')) 22 | verify_html(eep.urlget('duck.i2p')) 23 | except Exception, e: 24 | print 'Unit test failed for eepget' 25 | print "Note that urllib2.urlopen uses IE's proxy settings " + \ 26 | "in Windows." 27 | print "This may cause " + \ 28 | "urllib2.urlopen('http://www.google.com/') to fail." 29 | traceback.print_exc(); sys.exit() 30 | print 'eepget: OK' 31 | 32 | def test(): 33 | eepget_test() 34 | 35 | if __name__ == '__main__': 36 | print 'Testing:' 37 | test() 38 | -------------------------------------------------------------------------------- /src/i2p/test/test_select.py: -------------------------------------------------------------------------------- 1 | 2 | # ----------------------------------------------------- 3 | # test_select.py: Unit tests for select.py. 4 | # ----------------------------------------------------- 5 | 6 | # Make sure we can import i2p 7 | import sys; sys.path += ['../../'] 8 | 9 | import time 10 | 11 | import traceback, sys 12 | from i2p import socket, select 13 | import i2p.socket 14 | import socket as pysocket 15 | 16 | def minitest_select(rans, wans, eans, timeout, 17 | f1=None, f4=None, c1=None, c4=None): 18 | """Mini-unit test for select (Python and I2P sockets). 19 | Calls f1() on socket S1, f4() on socket S4, uses select() 20 | timeout 'timeout'. rans, wans, and eans should be lists 21 | containing indexes 1...6 of the sockets defined below. The 22 | result of i2p.select.select() will be verified against these 23 | lists. After this, calls c1() on S1, and c4() on S4.""" 24 | S1 = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_STREAM) 25 | S2 = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_DGRAM) 26 | S3 = pysocket.socket(pysocket.AF_INET, pysocket.SOCK_RAW) 27 | 28 | kw = {'in_depth':0, 'out_depth':0} 29 | S4 = socket.socket('Fella', socket.SOCK_STREAM, **kw) 30 | S5 = socket.socket('Boar', socket.SOCK_DGRAM, **kw) 31 | S6 = socket.socket('Gehka', socket.SOCK_RAW, **kw) 32 | 33 | if f1: f1(S1) 34 | if f4: f4(S4) 35 | 36 | L = [S1, S2, S3, S4, S5, S6] 37 | 38 | start = time.time() 39 | ans = select.select(L, L, L, timeout) 40 | ans1 = select.select(L, [], [], timeout) 41 | ans2 = select.select([], L, [], timeout) 42 | ans3 = select.select([], [], L, timeout) 43 | end = time.time() 44 | T = end - start 45 | 46 | ans = [[L.index(x) + 1 for x in ans [i]] for i in range(3)] 47 | ans1 = [[L.index(x) + 1 for x in ans1[i]] for i in range(3)] 48 | ans2 = [[L.index(x) + 1 for x in ans2[i]] for i in range(3)] 49 | ans3 = [[L.index(x) + 1 for x in ans3[i]] for i in range(3)] 50 | 51 | assert ans1[0] == rans 52 | assert ans2[1] == wans 53 | assert ans3[2] == eans 54 | assert ans == [rans, wans, eans] 55 | assert T < 4 * timeout + 0.1 56 | 57 | if c1: c1(S1) 58 | if c4: c4(S4) 59 | 60 | def test_select(): 61 | """Unit test for select (Python and I2P sockets).""" 62 | 63 | def connect1(S): 64 | """Connect regular Python socket to Google.""" 65 | ip = pysocket.gethostbyname('www.google.com') 66 | S.connect((ip, 80)) 67 | 68 | def connect4(S): 69 | """Connect I2P Python socket to duck.i2p.""" 70 | S.connect('duck.i2p') 71 | 72 | def full1(S): 73 | """Connect regular Python socket to Google, and send.""" 74 | connect1(S) 75 | S.sendall('GET / HTTP/1.0\r\n\r\n') 76 | S.recv(1) 77 | 78 | def full4(S): 79 | """Connect I2P Python socket to duck.i2p, and send.""" 80 | connect4(S) 81 | S.sendall('GET / HTTP/1.0\r\n\r\n') 82 | S.recv(1) 83 | # Peek twice (make sure peek code isn't causing problems). 84 | S.recv(1, i2p.socket.MSG_PEEK | i2p.socket.MSG_DONTWAIT) 85 | S.recv(1, i2p.socket.MSG_PEEK | i2p.socket.MSG_DONTWAIT) 86 | 87 | def check(S): 88 | """Verify that three chars recv()d are 'TTP'.""" 89 | assert S.recv(3) == 'TTP' 90 | 91 | try: 92 | for t in [0.0, 1.0]: 93 | minitest_select([], [2, 3, 5, 6], [], t) 94 | minitest_select([], [1, 2, 3, 4, 5, 6], [], t, 95 | f1=connect1, f4=connect4) 96 | minitest_select([], [1, 2, 3, 5, 6], [], t, 97 | f1=connect1) 98 | minitest_select([], [2, 3, 4, 5, 6], [], t, 99 | f4=connect4) 100 | minitest_select([1, 4], [1, 2, 3, 4, 5, 6], [], t, 101 | f1=full1, f4=full4, c1=check, c4=check) 102 | except: 103 | print 'Unit test failed for i2p.select.select().' 104 | traceback.print_exc(); sys.exit() 105 | print 'i2p.select.select(): OK' 106 | 107 | 108 | if __name__ == '__main__': 109 | test_select() 110 | -------------------------------------------------------------------------------- /src/i2p/test/test_tunnel.py: -------------------------------------------------------------------------------- 1 | 2 | # -------------------------------------------------------- 3 | # test_tunnel.py: Demos for tunnel (unit tests needed). 4 | # -------------------------------------------------------- 5 | 6 | # Make sure we can import i2p 7 | import sys; sys.path += ['../../'] 8 | 9 | import time 10 | from i2p import tunnel 11 | 12 | def tunnel_server_demo(): 13 | """Demo for tunnel.TunnelServer.""" 14 | 15 | T = tunnel.TunnelServer('Alisick', 8080, in_depth=0, out_depth=0) 16 | 17 | print 'Server ready at:' 18 | print T.dest 19 | while True: 20 | time.sleep(0.01) 21 | 22 | def tunnel_client_demo(): 23 | """Demo for tunnel.TunnelClient.""" 24 | 25 | T = tunnel.TunnelClient('Alliaha', 8001, 'duck.i2p', \ 26 | in_depth=0, out_depth=0) 27 | 28 | print 'Serving up duck.i2p at http://127.0.0.1:8001/' 29 | while True: 30 | time.sleep(0.01) 31 | 32 | 33 | 34 | def test(): 35 | print 'Demo:' 36 | 37 | # Demos: 38 | # tunnel_server_demo() 39 | tunnel_client_demo() 40 | 41 | if __name__ == '__main__': 42 | test() 43 | -------------------------------------------------------------------------------- /src/images/addressbook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/addressbook.png -------------------------------------------------------------------------------- /src/images/bitmessage.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/bitmessage.icns -------------------------------------------------------------------------------- /src/images/blacklist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/blacklist.png -------------------------------------------------------------------------------- /src/images/can-icon-16px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon-16px.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon-24px-green.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon-24px-red.png -------------------------------------------------------------------------------- /src/images/can-icon-24px-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon-24px-yellow.png -------------------------------------------------------------------------------- /src/images/can-icon-24px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon-24px.png -------------------------------------------------------------------------------- /src/images/can-icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/can-icon.ico -------------------------------------------------------------------------------- /src/images/greenicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/greenicon.png -------------------------------------------------------------------------------- /src/images/identities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/identities.png -------------------------------------------------------------------------------- /src/images/inbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/inbox.png -------------------------------------------------------------------------------- /src/images/networkstatus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/networkstatus.png -------------------------------------------------------------------------------- /src/images/no_identicons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/no_identicons.png -------------------------------------------------------------------------------- /src/images/qidenticon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/qidenticon.png -------------------------------------------------------------------------------- /src/images/qidenticon_two.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/qidenticon_two.png -------------------------------------------------------------------------------- /src/images/qidenticon_two_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/qidenticon_two_x.png -------------------------------------------------------------------------------- /src/images/qidenticon_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/qidenticon_x.png -------------------------------------------------------------------------------- /src/images/redicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/redicon.png -------------------------------------------------------------------------------- /src/images/send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/send.png -------------------------------------------------------------------------------- /src/images/sent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/sent.png -------------------------------------------------------------------------------- /src/images/subscriptions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/images/subscriptions.png -------------------------------------------------------------------------------- /src/images/yellowicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/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 | try: 20 | import locale 21 | encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING 22 | language = locale.getlocale()[0] or locale.getdefaultlocale()[0] or DEFAULT_LANGUAGE 23 | except: 24 | logger.exception('Could not determine language or encoding') 25 | 26 | 27 | if shared.config.has_option('bitmessagesettings', 'timeformat'): 28 | time_format = shared.config.get('bitmessagesettings', 'timeformat') 29 | #Test the format string 30 | try: 31 | time.strftime(time_format) 32 | except: 33 | logger.exception('Could not format timestamp') 34 | time_format = DEFAULT_TIME_FORMAT 35 | else: 36 | time_format = DEFAULT_TIME_FORMAT 37 | 38 | #It seems some systems lie about the encoding they use so we perform 39 | #comprehensive decoding tests 40 | if time_format != DEFAULT_TIME_FORMAT: 41 | try: 42 | #Check day names 43 | for i in xrange(7): 44 | unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, i, 0, 0)), encoding) 45 | #Check month names 46 | for i in xrange(1, 13): 47 | unicode(time.strftime(time_format, (0, i, 0, 0, 0, 0, 0, 0, 0)), encoding) 48 | #Check AM/PM 49 | unicode(time.strftime(time_format, (0, 0, 0, 11, 0, 0, 0, 0, 0)), encoding) 50 | unicode(time.strftime(time_format, (0, 0, 0, 13, 0, 0, 0, 0, 0)), encoding) 51 | #Check DST 52 | unicode(time.strftime(time_format, (0, 0, 0, 0, 0, 0, 0, 0, 1)), encoding) 53 | except: 54 | logger.exception('Could not decode locale formatted timestamp') 55 | time_format = DEFAULT_TIME_FORMAT 56 | encoding = DEFAULT_ENCODING 57 | 58 | 59 | def formatTimestamp(timestamp = None, as_unicode = True): 60 | #For some reason some timestamps are strings so we need to sanitize. 61 | if timestamp is not None and not isinstance(timestamp, int): 62 | try: 63 | timestamp = int(timestamp) 64 | except: 65 | timestamp = None 66 | 67 | #timestamp can't be less than 0. 68 | if timestamp is not None and timestamp < 0: 69 | timestamp = None 70 | 71 | if timestamp is None: 72 | timestring = time.strftime(time_format) 73 | else: 74 | #In case timestamp is too far in the future 75 | try: 76 | timestring = time.strftime(time_format, time.localtime(timestamp)) 77 | except ValueError: 78 | timestring = time.strftime(time_format) 79 | 80 | if as_unicode: 81 | return unicode(timestring, encoding) 82 | return timestring 83 | 84 | def getTranslationLanguage(): 85 | userlocale = None 86 | if shared.config.has_option('bitmessagesettings', 'userlocale'): 87 | userlocale = shared.config.get('bitmessagesettings', 'userlocale') 88 | 89 | if userlocale in [None, '', 'system']: 90 | return language 91 | 92 | return userlocale 93 | 94 | -------------------------------------------------------------------------------- /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 | 11 | appdata = shared.lookupAppdataFolder() 12 | 13 | conn = sqlite3.connect( appdata + 'messages.dat' ) 14 | conn.text_factory = str 15 | cur = conn.cursor() 16 | 17 | def readInbox(): 18 | print 'Printing everything in inbox table:' 19 | item = '''select * from inbox''' 20 | parameters = '' 21 | cur.execute(item, parameters) 22 | output = cur.fetchall() 23 | for row in output: 24 | print row 25 | 26 | def readSent(): 27 | print 'Printing everything in Sent table:' 28 | item = '''select * from sent where folder !='trash' ''' 29 | parameters = '' 30 | cur.execute(item, parameters) 31 | output = cur.fetchall() 32 | for row in output: 33 | msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, sleeptill, status, retrynumber, folder, encodingtype, ttl = row 34 | print msgid.encode('hex'), toaddress, 'toripe:', toripe.encode('hex'), 'fromaddress:', fromaddress, 'ENCODING TYPE:', encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', ackdata.encode('hex'), lastactiontime, status, retrynumber, folder 35 | 36 | def readSubscriptions(): 37 | print 'Printing everything in subscriptions table:' 38 | item = '''select * from subscriptions''' 39 | parameters = '' 40 | cur.execute(item, parameters) 41 | output = cur.fetchall() 42 | for row in output: 43 | print row 44 | 45 | def readPubkeys(): 46 | print 'Printing everything in pubkeys table:' 47 | item = '''select address, transmitdata, time, usedpersonally from pubkeys''' 48 | parameters = '' 49 | cur.execute(item, parameters) 50 | output = cur.fetchall() 51 | for row in output: 52 | address, transmitdata, time, usedpersonally = row 53 | 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:', transmitdata.encode('hex') 54 | 55 | def readInventory(): 56 | print 'Printing everything in inventory table:' 57 | item = '''select hash, objecttype, streamnumber, payload, expirestime from inventory''' 58 | parameters = '' 59 | cur.execute(item, parameters) 60 | output = cur.fetchall() 61 | for row in output: 62 | hash, objecttype, streamnumber, payload, expirestime = row 63 | print 'Hash:', hash.encode('hex'), objecttype, streamnumber, '\t', payload.encode('hex'), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(expirestime)),'utf-8') 64 | 65 | 66 | def takeInboxMessagesOutOfTrash(): 67 | item = '''update inbox set folder='inbox' where folder='trash' ''' 68 | parameters = '' 69 | cur.execute(item, parameters) 70 | output = cur.fetchall() 71 | conn.commit() 72 | print 'done' 73 | 74 | def takeSentMessagesOutOfTrash(): 75 | item = '''update sent set folder='sent' where folder='trash' ''' 76 | parameters = '' 77 | cur.execute(item, parameters) 78 | output = cur.fetchall() 79 | conn.commit() 80 | print 'done' 81 | 82 | def markAllInboxMessagesAsUnread(): 83 | item = '''update inbox set read='0' ''' 84 | parameters = '' 85 | cur.execute(item, parameters) 86 | output = cur.fetchall() 87 | conn.commit() 88 | shared.UISignalQueue.put(('changedInboxUnread', None)) 89 | print 'done' 90 | 91 | def vacuum(): 92 | item = '''VACUUM''' 93 | parameters = '' 94 | cur.execute(item, parameters) 95 | output = cur.fetchall() 96 | conn.commit() 97 | print 'done' 98 | 99 | #takeInboxMessagesOutOfTrash() 100 | #takeSentMessagesOutOfTrash() 101 | #markAllInboxMessagesAsUnread() 102 | readInbox() 103 | #readSent() 104 | #readPubkeys() 105 | #readSubscriptions() 106 | #readInventory() 107 | #vacuum() #will defragment and clean empty space from the messages.dat file. 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /src/proofofwork.py: -------------------------------------------------------------------------------- 1 | #import shared 2 | #import time 3 | #from multiprocessing import Pool, cpu_count 4 | import hashlib 5 | from struct import unpack, pack 6 | import sys 7 | from shared import config, frozen 8 | import shared 9 | #import os 10 | 11 | def _set_idle(): 12 | if 'linux' in sys.platform: 13 | import os 14 | os.nice(20) # @UndefinedVariable 15 | else: 16 | try: 17 | sys.getwindowsversion() 18 | import win32api,win32process,win32con # @UnresolvedImport 19 | pid = win32api.GetCurrentProcessId() 20 | handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid) 21 | win32process.SetPriorityClass(handle, win32process.IDLE_PRIORITY_CLASS) 22 | except: 23 | #Windows 64-bit 24 | pass 25 | 26 | def _pool_worker(nonce, initialHash, target, pool_size): 27 | _set_idle() 28 | trialValue = float('inf') 29 | while trialValue > target: 30 | nonce += pool_size 31 | trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) 32 | return [trialValue, nonce] 33 | 34 | def _doSafePoW(target, initialHash): 35 | nonce = 0 36 | trialValue = float('inf') 37 | while trialValue > target: 38 | nonce += 1 39 | trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) 40 | return [trialValue, nonce] 41 | 42 | def _doFastPoW(target, initialHash): 43 | import time 44 | from multiprocessing import Pool, cpu_count 45 | try: 46 | pool_size = cpu_count() 47 | except: 48 | pool_size = 4 49 | try: 50 | maxCores = config.getint('bitmessagesettings', 'maxcores') 51 | except: 52 | maxCores = 99999 53 | if pool_size > maxCores: 54 | pool_size = maxCores 55 | pool = Pool(processes=pool_size) 56 | result = [] 57 | for i in range(pool_size): 58 | result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) 59 | while True: 60 | if shared.shutdown >= 1: 61 | pool.terminate() 62 | while True: 63 | time.sleep(10) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py 64 | return 65 | for i in range(pool_size): 66 | if result[i].ready(): 67 | result = result[i].get() 68 | pool.terminate() 69 | pool.join() #Wait for the workers to exit... 70 | return result[0], result[1] 71 | time.sleep(0.2) 72 | 73 | def run(target, initialHash): 74 | target = int(target) 75 | if frozen == "macosx_app" or not frozen: 76 | return _doFastPoW(target, initialHash) 77 | else: 78 | return _doSafePoW(target, initialHash) 79 | -------------------------------------------------------------------------------- /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/recversion_debug.py: -------------------------------------------------------------------------------- 1 | from struct import unpack, pack 2 | from addresses import decodeVarint 3 | import time 4 | 5 | # We have received a version message 6 | def recversion(data): 7 | remoteProtocolVersion, = unpack('>L', data[:4]) 8 | print 'remoteProtocolVersion:', remoteProtocolVersion 9 | if remoteProtocolVersion < 3: 10 | print 'Closing connection to old protocol version', remoteProtocolVersion, 'node: ', 'peer' 11 | return 12 | timestamp, = unpack('>Q', data[12:20]) 13 | print 'timestamp:', timestamp 14 | timeOffset = timestamp - int(time.time()) 15 | myExternalDest = data[28:544] 16 | print 'myExternalDest:', myExternalDest 17 | 18 | useragentLength, lengthOfUseragentVarint = decodeVarint(data[1076:1080]) 19 | readPosition = 1076 + lengthOfUseragentVarint 20 | useragent = data[readPosition:readPosition + useragentLength] 21 | readPosition += useragentLength 22 | numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( 23 | data[readPosition:]) 24 | readPosition += lengthOfNumberOfStreamsInVersionMessage 25 | streamNumber, lengthOfRemoteStreamNumber = decodeVarint( 26 | data[readPosition:]) 27 | print 'Remote node useragent:', useragent, '\nstream number:', streamNumber, '\ntime offset:', timeOffset, 'seconds.' 28 | 29 | if streamNumber != 1: 30 | print 'Closed connection to', 'peer', 'because they are interested in stream', streamNumber, '.' 31 | return 32 | if data[1068:1076] == 'Z\xef\x86\x05\x1f\x06\xb0\x9e': 33 | print 'Closing connection to myself: ', 'peer' 34 | return 35 | 36 | packet = "\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00UO\x9f\x05\x00\x00\x00\x00\x00\x00\x00\x01Gl~Nx-u7ItPZM3vCF63xYamL4FYaGWI6HPDGbWzfTFuXhIBMH8W2PrFEny6FPSxNXmDHT8aQvyysuBms9F3xSFhIV5HEQy2evlx~kfLz2RvW91xnvi6YBGpXAOTZEqLD~g20UhnBdASKnN7UkimJ6jjW4rXb180BY-TM1-~mOn4zh4Rz-9zj-VOVw49~lJVKtwfzfZbKGzNOfFR59f82QMIrATS5d1TPN2Jnme~WN8oXnNBsK-gaohJKnJtUCIokhK8FsxGJ2sHHk~kZ9g73Fzpxf1mw6DYBialGkCQy0HqovF6tybudL4KVpbjAcAJdqK~P9C2SMRTaQazZ6mNL4S0UnCSZRZ4PciUF15QqmuwLXNgPRLBgBxXBkOKXvwjs9uUncitiUOkUy4y5DPcl1gmlaKw2K7HkapKujc0xsPCnNCIyVCtLuZjz5k3UN8b7XMufHAEdq-y2CAYXIH8gogrus-bVu7BR0SX2x3H0omA2UKmo-yORzKMSJXVoOQ5rAAAA\x00\x00\x00\x00\x00\x00\x00\x01VXVZRtml-XDgkwFcehckXBQ1qOx8whwjYlPZnKyIp3L5OFhwF6moUjkAoN~4J5TmdBLP5jxoOEwe5pC6TcgkKAvEXLqGvb607LPr9XhhWdgfHFyfcEG1zGhMziisOSHwmnUAjlvd5FT9H7ouv2on5JvLAHRiqe-vO0Ifz~dnkQyhd-IouWArdTlXQqhm7ArMS1-vHQKaslktY9BrFS8ZxKojbAMxcrBrt-9IND1f9-KpRBwtKp0Hup6jzIk3cNGbP4eadZ3F-Zic6oy-ktsH0iz5FBKmpMdc36SQDG8rReMjngKZntl4OhxjAZ7eYLllA6T3X5wdICkoqNJEobByGx9TEYXq6bVlyp7aoxGuB8~piqJWoCqbgfcIDUznP050YoCKp3Uk6u9DmROP4pckzg910FdKSF3TRlebKRRzB7KHWXV~CY3xZEp8CKblBljJEw3FNv0IZ5Guq0tNi9bjs6uXtY1IPviEN9cVfmT3EZ5WK8b~3JdvZrDGKoWAJkRAAAAAZ\xef\x86\x05\x1f\x06\xb0\x9e\x14/PyBitmessage:0.4.4/\x01\x01" 37 | recversion(packet) 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/seedless.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from urllib2 import * 4 | from base64 import b64encode, urlsafe_b64decode 5 | 6 | knownSeedlessServers = [ 7 | "rx6qfevnrak7fljbotcw2xibpqfzsnwsbf5ouk6f7shwdepmlp5a.b32.i2p", 8 | "vnmf4apo3mpxitki2nzqjx24cq4ykuiptpdmihgyecomcql5ttaa.b32.i2p", 9 | "zy37tq6ynucp3ufoyeegswqjaeofmj57cpm5ecd7nbanh2h6f2ja.b32.i2p"] 10 | 11 | def pad_b64(b64, size=3): 12 | mod = len(b64) % size 13 | if mod != 0: 14 | eq = "=" * (size - mod) 15 | b64 += eq 16 | return b64 17 | 18 | def call_seedless(url, cmd, query): 19 | b64_query = b64encode(query) 20 | req = Request( url, headers={"X-Seedless": "%s %s" % (cmd, b64_query)} ) 21 | res = urlopen(req, timeout=100) 22 | 23 | list = [] 24 | for b64 in res: 25 | b64 = pad_b64( b64.strip() ) 26 | list.append( urlsafe_b64decode(b64) ) 27 | return ( res.info().headers, list ) 28 | 29 | def call_seedless_server(b32, cmd, query): 30 | proxy = ProxyHandler({'http': 'localhost:4444'}) 31 | opener = build_opener(proxy) 32 | install_opener(opener) 33 | 34 | url = "http://%s/Seedless/seedless" % b32 35 | return call_seedless(url, cmd, query) 36 | 37 | def call_seedless_plugin(cmd, query): 38 | url = "http://localhost:7657/SeedlessConsole/Service" 39 | return call_seedless(url, cmd, query) 40 | 41 | if __name__ == "__main__": 42 | default_b32 = knownSeedlessServers[0] 43 | default_cmd = "locate" 44 | 45 | b32 = raw_input("B32: ") 46 | cmd = raw_input("COMMAND: ") 47 | query = raw_input("QUERY: ") 48 | 49 | if not b32: 50 | b32 = default_b32 51 | if not cmd: 52 | cmd = default_cmd 53 | 54 | if b32 == "local": 55 | result = call_seedless_plugin(cmd, query) 56 | else: 57 | result = call_seedless_server(b32, cmd, query) 58 | print result 59 | -------------------------------------------------------------------------------- /src/seedless_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import seedless 4 | from random import choice 5 | from urllib2 import HTTPError 6 | from socket import timeout 7 | 8 | def result_to_list(result, index): 9 | list = [] 10 | for entry in result[1]: 11 | item = entry.split(" ")[index] 12 | list.append(item) 13 | return list 14 | 15 | service = "" 16 | 17 | def scrapePeers(dest): 18 | # LOCATE 19 | tryPlugin = True 20 | while True: # Try plugin first, then keep trying random servers 21 | cmd = "locate" 22 | query = "seedless %s" % service 23 | try: 24 | if tryPlugin: 25 | tryPlugin = False 26 | res = seedless.call_seedless_plugin(cmd, query) 27 | else: 28 | randomServer = choice(seedless.knownSeedlessServers) 29 | res = seedless.call_seedless_server(randomServer, cmd, query) 30 | except ( HTTPError, timeout ) as e: 31 | if e.code != 404: 32 | print "Seedless:locate", e 33 | continue 34 | 35 | currentServerList = result_to_list(res, 0) 36 | if len(currentServerList) > 0: 37 | print "servers: ", len(currentServerList) 38 | break 39 | 40 | maxServers = len(currentServerList) 41 | if maxServers > 3: 42 | maxServers = 3 43 | elif maxServers <= 0: 44 | raise Exception("No %s compatible seedless servers were found." % service) 45 | 46 | # ANNOUNCE 47 | for server in currentServerList: 48 | while True: 49 | try: 50 | ann_res = seedless.call_seedless_server( \ 51 | server, "announce", "%s %s" % (service, dest) ) 52 | except ( HTTPError, timeout ) as e: 53 | print "Seedless:announce", e 54 | continue 55 | if ann_res: 56 | break 57 | 58 | # SCRAPE 59 | peerDestinations = set() 60 | serversScraped = 0 61 | while True: 62 | currentServer = choice(currentServerList) 63 | try: 64 | res = seedless.call_seedless_server( \ 65 | currentServer, "locate", "%s " % service) 66 | except ( HTTPError, timeout ) as e: 67 | print "Seedless:scrape", e 68 | continue 69 | 70 | peers = result_to_list(res, 2) 71 | if len(peers) > 0: 72 | currentServerList.remove(currentServer) 73 | peerDestinations.update(peers) 74 | serversScraped += 1 75 | 76 | if serversScraped >= maxServers: 77 | break 78 | 79 | return list( peerDestinations ) 80 | 81 | if __name__ == "__main__": 82 | service = "pybitmsg-i2p" 83 | mydest = "fmzq6Y8MLj2IPwmym2d1xuM5oSRT2-Db0Zv4yAPS3deGZNDPTZu4ZguWXQrqcZ6~lptHql4~h4y6ttjzg3NA2cGF44x5JvGTkOwmcopLLx5WsD-LzXwDqU1ncO6K7nmRQovgwZCWgqOrjs9TugN9ci3c2QzUIqN4TgUVMMJHm4yMScAsR4tFBlJpSXe9RnWyXskgf3IvcDWNmCuiNryXNMlb~hyy1lnC29rNIgjYh1nHL9RQ0RUyPuUiyid~GkBCNeSfwzCYi5W8pMErEYmKSwLBcR1MSaRcXD~Tkr3K4KNSPQNCxaCnsuOZoDVMw64NECqAkVVHMnZKU1R0exHiDEds4gJelP-5qSdlYXR6azVde4rrC559Mh9XM1Dlw6kAS1Gv3B7ZyGt6HPhn2uN8rwLvpk60N03J0vi8oubBqkmAhHI2w~FL4apkORdjquz~m~r5bW3CPxH7P1LadnrsNE-m5gO6Sts~9UwVRG-Wmz-L2Za~cDXTP~HXG61IE9IKAAAA" 84 | print scrapePeers(mydest) 85 | 86 | -------------------------------------------------------------------------------- /src/singleton.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import errno 6 | import tempfile 7 | from multiprocessing import Process 8 | 9 | 10 | class singleinstance: 11 | """ 12 | Implements a single instance application by creating a lock file based on the full path to the script file. 13 | 14 | This is based upon the singleton class from tendo https://github.com/pycontribs/tendo 15 | which is under the Python Software Foundation License version 2 16 | """ 17 | def __init__(self, flavor_id=""): 18 | import sys 19 | self.initialized = False 20 | basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock' 21 | self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename) 22 | 23 | if sys.platform == 'win32': 24 | try: 25 | # file already exists, we try to remove (in case previous execution was interrupted) 26 | if os.path.exists(self.lockfile): 27 | os.unlink(self.lockfile) 28 | self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR) 29 | except OSError: 30 | type, e, tb = sys.exc_info() 31 | if e.errno == 13: 32 | print 'Another instance of this application is already running' 33 | sys.exit(-1) 34 | print(e.errno) 35 | raise 36 | else: # non Windows 37 | import fcntl # @UnresolvedImport 38 | self.fp = open(self.lockfile, 'w') 39 | try: 40 | fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) 41 | except IOError: 42 | print 'Another instance of this application is already running' 43 | sys.exit(-1) 44 | self.initialized = True 45 | 46 | def __del__(self): 47 | import sys 48 | if not self.initialized: 49 | return 50 | try: 51 | if sys.platform == 'win32': 52 | if hasattr(self, 'fd'): 53 | os.close(self.fd) 54 | os.unlink(self.lockfile) 55 | else: 56 | import fcntl # @UnresolvedImport 57 | fcntl.lockf(self.fp, fcntl.LOCK_UN) 58 | if os.path.isfile(self.lockfile): 59 | os.unlink(self.lockfile) 60 | except Exception, e: 61 | sys.exit(-1) 62 | -------------------------------------------------------------------------------- /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/socks/__init__.py: -------------------------------------------------------------------------------- 1 | """SocksiPy - Python SOCKS module. 2 | Version 1.00 3 | 4 | Copyright 2006 Dan-Haim. All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, 7 | are permitted provided that the following conditions are met: 8 | 1. Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 3. Neither the name of Dan Haim nor the names of his contributors may be used 14 | to endorse or promote products derived from this software without specific 15 | prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY DAN HAIM "AS IS" AND ANY EXPRESS OR IMPLIED 18 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 20 | EVENT SHALL DAN HAIM OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 21 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA 23 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMANGE. 26 | 27 | 28 | This module provides a standard socket-like interface for Python 29 | for tunneling connections through SOCKS proxies. 30 | 31 | """ 32 | 33 | """ 34 | 35 | Minor modifications made by Christopher Gilbert (http://motomastyle.com/) 36 | for use in PyLoris (http://pyloris.sourceforge.net/) 37 | 38 | Minor modifications made by Mario Vilas (http://breakingcode.wordpress.com/) 39 | mainly to merge bug fixes found in Sourceforge 40 | 41 | This module has been GUTTED rather than bypassed by Marc D. Wood for i2pbm 42 | 43 | """ 44 | 45 | from i2p import socket 46 | 47 | _orgsocket = socket.Socket 48 | 49 | class ProxyError(Exception): pass 50 | class GeneralProxyError(ProxyError): pass 51 | 52 | _generalerrors = ("success", 53 | "invalid data", 54 | "not connected", 55 | "not available", 56 | "bad proxy type", 57 | "bad input") 58 | 59 | class socksocket(socket.Socket): 60 | """socksocket([family[, type[, proto]]]) -> socket object 61 | Open a SOCKS enabled socket. The parameters are the same as 62 | those of the standard socket init. In order for SOCKS to work, 63 | you must specify family=AF_INET, type=SOCK_STREAM and proto=0. 64 | """ 65 | 66 | def __init__(self, session, type=socket.SOCK_STREAM, samaddr=socket.samaddr, **kwargs): 67 | _orgsocket.__init__(self, session, type, samaddr, **kwargs) 68 | 69 | def __recvall(self, count): 70 | """__recvall(count) -> data 71 | Receive EXACTLY the number of bytes requested from the socket. 72 | Blocks until the required number of bytes have been received. 73 | """ 74 | data = self.recv(count) 75 | while len(data) < count: 76 | d = self.recv(count-len(data)) 77 | if not d: raise GeneralProxyError((0, "connection closed unexpectedly")) 78 | data = data + d 79 | return data 80 | 81 | def connect(self, destpair): 82 | """connect(self, despair) 83 | Connects to the specified destination through a proxy. 84 | destpar - A tuple of the IP/DNS address and the port number. 85 | (identical to socket's connect). 86 | To select the proxy server use setproxy(). 87 | """ 88 | # Do a minimal input check first 89 | if type(destpair) is not str or destpair == '': 90 | raise GeneralProxyError((5, _generalerrors[5])) 91 | 92 | _orgsocket.connect(self, destpair) 93 | 94 | -------------------------------------------------------------------------------- /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): 16 | return translateText(context, text) 17 | 18 | def translateText(context, text): 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 | return QtGui.QApplication.translate(context, text) 27 | else: 28 | if '%' in text: 29 | return translateClass(context, text.replace('%','',1)) 30 | else: 31 | return text -------------------------------------------------------------------------------- /src/translations/bitmessage_ar.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_ar.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_ar.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_ar.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_cs.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_objectProcessor.py\ 5 | ../class_outgoingSynSender.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_cs.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_cs.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_cs.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_de.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_de.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_de.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_de.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_en_pirate.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_en_pirate.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_en_pirate.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_en_pirate.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_eo.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_objectProcessor.py\ 5 | ../class_outgoingSynSender.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_eo.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_eo.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_eo.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_fr.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_objectProcessor.py\ 5 | ../class_outgoingSynSender.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_fr.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_fr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_fr.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_ja.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_outgoingSynSender.py\ 5 | ../class_receiveDataThread.py\ 6 | ../class_sendDataThread.py\ 7 | ../class_singleCleaner.py\ 8 | ../class_singleListener.py\ 9 | ../class_singleWorker.py\ 10 | ../class_sqlThread.py\ 11 | ../helper_bitcoin.py\ 12 | ../helper_bootstrap.py\ 13 | ../helper_generic.py\ 14 | ../helper_inbox.py\ 15 | ../helper_sent.py\ 16 | ../helper_startup.py\ 17 | ../shared.py\ 18 | ../bitmessageqt/__init__.py\ 19 | ../bitmessageqt/about.py\ 20 | ../bitmessageqt/bitmessageui.py\ 21 | ../bitmessageqt/connect.py\ 22 | ../bitmessageqt/help.py\ 23 | ../bitmessageqt/iconglossary.py\ 24 | ../bitmessageqt/newaddressdialog.py\ 25 | ../bitmessageqt/newchandialog.py\ 26 | ../bitmessageqt/newsubscriptiondialog.py\ 27 | ../bitmessageqt/regenerateaddresses.py\ 28 | ../bitmessageqt/settings.py\ 29 | ../bitmessageqt/specialaddressbehavior.py 30 | 31 | 32 | TRANSLATIONS = bitmessage_ja.ts 33 | CODECFORTR = UTF-8 34 | -------------------------------------------------------------------------------- /src/translations/bitmessage_ja.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_ja.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_nl.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_nl.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_nl.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_nl.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_no.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_objectProcessor.py\ 5 | ../class_outgoingSynSender.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_no.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_no.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_no.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_ru.pro: -------------------------------------------------------------------------------- 1 | SOURCES = ../addresses.py\ 2 | ../bitmessagemain.py\ 3 | ../class_addressGenerator.py\ 4 | ../class_objectProcessor.py\ 5 | ../class_outgoingSynSender.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_ru.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_ru.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_ru.qm -------------------------------------------------------------------------------- /src/translations/bitmessage_zh_cn.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 | ../bitmessageqt/__init__.py\ 20 | ../bitmessageqt/about.py\ 21 | ../bitmessageqt/addaddressdialog.py\ 22 | ../bitmessageqt/bitmessageui.py\ 23 | ../bitmessageqt/connect.py\ 24 | ../bitmessageqt/help.py\ 25 | ../bitmessageqt/iconglossary.py\ 26 | ../bitmessageqt/newaddressdialog.py\ 27 | ../bitmessageqt/newchandialog.py\ 28 | ../bitmessageqt/newsubscriptiondialog.py\ 29 | ../bitmessageqt/regenerateaddresses.py\ 30 | ../bitmessageqt/settings.py\ 31 | ../bitmessageqt/specialaddressbehavior.py 32 | 33 | 34 | TRANSLATIONS = bitmessage_zh_cn.ts 35 | CODECFORTR = UTF-8 36 | -------------------------------------------------------------------------------- /src/translations/bitmessage_zh_cn.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/metamarcdw/PyBitmessage-I2P/a6e4f956dd7f8329af4f4b225539bff591b577ff/src/translations/bitmessage_zh_cn.qm --------------------------------------------------------------------------------