diff --git a/.gitignore b/.gitignore index a11f6fad..8e9f9031 100644 --- a/.gitignore +++ b/.gitignore @@ -5,11 +5,4 @@ src/build src/dist src/.project src/.pydevproject -src/.settings/ -src/**/.dll -src/**/*.o -src/**/*.so -build/lib.* -build/temp.* -dist -*.egg-info +src/.settings/ \ No newline at end of file diff --git a/COPYING b/COPYING index 4fe0f2b0..dfa169ea 100644 --- a/COPYING +++ b/COPYING @@ -1,5 +1,5 @@ -Copyright (c) 2012-2016 Jonathan Warren -Copyright (c) 2013-2016 The Bitmessage Developers +Copyright (c) 2012-2015 Jonathan Warren +Copyright (c) 2013-2015 The Bitmessage Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/INSTALL.md b/INSTALL.md index 19a22f3d..823608fe 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,4 +1,4 @@ -# PyBitmessage Installation Instructions +#PyBitmessage Installation Instructions For an up-to-date version of these instructions, please visit the [Bitmessage Wiki](https://bitmessage.org/wiki/Compiling_instructions). @@ -6,7 +6,7 @@ For an up-to-date version of these instructions, please visit the PyBitmessage can be run either straight from source or from an installed package. -## Dependencies +##Dependencies Before running PyBitmessage, make sure you have all the necessary dependencies installed on your system. @@ -16,12 +16,12 @@ Here's a list of dependencies needed for PyBitmessage - openssl - (Fedora & Redhat only) openssl-compat-bitcoin-libs -## Running PyBitmessage +##Running PyBitmessage PyBitmessage can be run two ways: straight from source or via a package which is installed on your system. Since PyBitmessage is Beta, it is best to run PyBitmessage from source, so that you may update as needed. -#### Updating +####Updating To update PyBitmessage from source (Linux/OS X), you can do these easy steps: ``` cd PyBitmessage/src/ @@ -31,7 +31,7 @@ python bitmessagemain.py ``` Voilà! Bitmessage is updated! -#### Linux +####Linux To run PyBitmessage from the command-line, you must download the source, then run `src/bitmessagemain.py`. ``` @@ -41,7 +41,7 @@ cd PyBitmessage/ && python src/bitmessagemain.py That's it! *Honestly*! -#### Windows +####Windows On Windows you can download an executable for Bitmessage [here](https://bitmessage.org/download/windows/Bitmessage.exe). @@ -49,7 +49,7 @@ However, if you would like to run PyBitmessage via Python in Windows, you can go [here](https://bitmessage.org/wiki/Compiling_instructions#Windows) for information on how to do so. -#### OS X +####OS X First off, install Homebrew. ``` ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" @@ -66,12 +66,13 @@ git clone git://github.com/Bitmessage/PyBitmessage.git cd PyBitmessage && python src/bitmessagemain.py ``` -## Creating a package for installation +##Creating a package for installation If you really want, you can make a package for PyBitmessage, which you may install yourself or distribute to friends. This isn't recommended, since PyBitmessage is in Beta, and subject to frequent change. -#### Linux +####Linux + First off, since PyBitmessage uses something nifty called [packagemonkey](https://github.com/fuzzgun/packagemonkey), go ahead and get that installed. You may have to build it from source. @@ -89,12 +90,11 @@ rpm.sh - create a RPM package slack.sh - create a package for Slackware ``` -#### OS X +####OS X Please refer to [this page](https://bitmessage.org/forum/index.php/topic,2761.0.html) on the forums for instructions on how to create a package on OS X. Please note that some versions of OS X don't work. - -#### Windows -## TODO: Create Windows package creation instructions +###Windows +#TODO: Create Windows package creation instructions diff --git a/LICENSE b/LICENSE index d2afc3c4..56ac8e3a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2012-2016 Jonathan Warren -Copyright (c) 2013-2016 The Bitmessage Developers +Copyright (c) 2012-2014 Jonathan Warren +Copyright (c) 2013-2014 The Bitmessage Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 2d29971b..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,3 +0,0 @@ -include COPYING -include README.md -recursive-include desktop * diff --git a/packages/unmaintained/Makefile b/Makefile similarity index 93% rename from packages/unmaintained/Makefile rename to Makefile index fa1c4c91..3078ee94 100644 --- a/packages/unmaintained/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ APP=pybitmessage -APPDIR=`basename "\`pwd\`"` -VERSION=0.6.0 +VERSION=0.4.4 RELEASE=1 ARCH_TYPE=`uname -m` PREFIX?=/usr/local @@ -9,7 +8,7 @@ LIBDIR=lib all: debug: source: - tar -cvf ../${APP}_${VERSION}.orig.tar ../${APPDIR} --exclude-vcs + tar -cvf ../${APP}_${VERSION}.orig.tar ../${APP}-${VERSION} --exclude-vcs gzip -f9n ../${APP}_${VERSION}.orig.tar install: mkdir -p ${DESTDIR}/usr @@ -58,5 +57,5 @@ clean: rm -f puppypackage/*.gz puppypackage/*.pet slackpackage/*.txz sourcedeb: - tar -cvf ../${APP}_${VERSION}.orig.tar ../${APPDIR} --exclude-vcs --exclude 'debian' + tar -cvf ../${APP}_${VERSION}.orig.tar ../${APP}-${VERSION} --exclude-vcs --exclude 'debian' gzip -f9n ../${APP}_${VERSION}.orig.tar diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 91c3bc96..00000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,14 +0,0 @@ -## Code contributions to the Bitmessage project - -- try to explain what the code is about -- try to follow [PEP0008](https://www.python.org/dev/peps/pep-0008/) -- make the pull request against the ["v0.6" branch](https://github.com/Bitmessage/PyBitmessage/tree/v0.6) -- it should be possible to do a fast-forward merge of the pull requests -- PGP-sign the commits included in the pull request -- You can get paid for merged commits if you register at [Tip4Commit](https://tip4commit.com/github/Bitmessage/PyBitmessage) - -If for some reason you don't want to use github, you can submit the patch using Bitmessage to the "bitmessage" chan, or to one of the developers. -## Translations - -For helping with translations, please use [Transifex](https://www.transifex.com/bitmessage-project/pybitmessage/). There is no need to submit pull requests for translations. -For translating technical terms it is recommended to consult the [Microsoft Language Portal](https://www.microsoft.com/Language/en-US/Default.aspx). \ No newline at end of file diff --git a/README.md b/README.md index 0ea6144b..7a161d04 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ 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 metadata, like the +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. diff --git a/packages/unmaintained/arch.sh b/arch.sh similarity index 99% rename from packages/unmaintained/arch.sh rename to arch.sh index 5f7982bb..96d2e8d8 100755 --- a/packages/unmaintained/arch.sh +++ b/arch.sh @@ -2,7 +2,7 @@ APP=pybitmessage PREV_VERSION=0.4.4 -VERSION=0.6.0 +VERSION=0.4.4 RELEASE=1 ARCH_TYPE=any CURRDIR=`pwd` diff --git a/packages/unmaintained/archpackage/PKGBUILD b/archpackage/PKGBUILD similarity index 98% rename from packages/unmaintained/archpackage/PKGBUILD rename to archpackage/PKGBUILD index 9fd8eadd..5c2c78eb 100644 --- a/packages/unmaintained/archpackage/PKGBUILD +++ b/archpackage/PKGBUILD @@ -1,6 +1,6 @@ # Maintainer: Bob Mottram (4096 bits) pkgname=pybitmessage -pkgver=0.6.0 +pkgver=0.4.4 pkgrel=1 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." arch=('any') diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 248d2c41..00000000 --- a/build/README.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains scripts that are helpful for developers when building -or maintaining PyBitmessage. diff --git a/build/changelang.sh b/build/changelang.sh deleted file mode 100755 index 915c5dea..00000000 --- a/build/changelang.sh +++ /dev/null @@ -1,16 +0,0 @@ -export LANG=de_DE.UTF-8 -export LANGUAGE=de_DE -export LC_CTYPE="de_DE.UTF-8" -export LC_NUMERIC=de_DE.UTF-8 -export LC_TIME=de_DE.UTF-8 -export LC_COLLATE="de_DE.UTF-8" -export LC_MONETARY=de_DE.UTF-8 -export LC_MESSAGES="de_DE.UTF-8" -export LC_PAPER=de_DE.UTF-8 -export LC_NAME=de_DE.UTF-8 -export LC_ADDRESS=de_DE.UTF-8 -export LC_TELEPHONE=de_DE.UTF-8 -export LC_MEASUREMENT=de_DE.UTF-8 -export LC_IDENTIFICATION=de_DE.UTF-8 -export LC_ALL= -python2.7 src/bitmessagemain.py diff --git a/build/compiletest.py b/build/compiletest.py deleted file mode 100755 index fdbf7db1..00000000 --- a/build/compiletest.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python2.7 - -import ctypes -import fnmatch -import os -import sys -import traceback - -matches = [] -for root, dirnames, filenames in os.walk('src'): - for filename in fnmatch.filter(filenames, '*.py'): - matches.append(os.path.join(root, filename)) - -for filename in matches: - source = open(filename, 'r').read() + '\n' - try: - compile(source, filename, 'exec') - except Exception as e: - if 'win' in sys.platform: - ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) - else: - print "Exception in %s: %s" % (filename, traceback.format_exc()) - sys.exit(1) diff --git a/build/mergepullrequest.sh b/build/mergepullrequest.sh deleted file mode 100755 index 35e87566..00000000 --- a/build/mergepullrequest.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -if [ -z "$1" ]; then - echo "You must specify pull request number" - exit -fi - -git pull -git checkout v0.6 -git fetch origin pull/"$1"/head:"$1" -git merge --ff-only "$1" diff --git a/build/updatetranslations.sh b/build/updatetranslations.sh deleted file mode 100755 index ba5a3fdb..00000000 --- a/build/updatetranslations.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -if [ ! -f "$1" ]; then - echo "$1 not found, please specify the file name for source" - exit -fi - -srcdir=`mktemp -d` - -unzip "$1" -d $srcdir - -for i in $srcdir/*ts; do - o=`basename $i|cut -b3-` - o="${o,,}" - o="${o//@/_}" - echo "$i -> $o" - mv "$i" "$HOME/src/PyBitmessage/src/translations/$o" -done - -rm -rf -- $srcdir - -lrelease-qt4 "$HOME/src/PyBitmessage/src/translations/bitmessage.pro" diff --git a/checkdeps.py b/checkdeps.py deleted file mode 100644 index 05f00944..00000000 --- a/checkdeps.py +++ /dev/null @@ -1,215 +0,0 @@ -"""Check dependendies and give recommendations about how to satisfy them""" - -from distutils.errors import CompileError -try: - from setuptools.dist import Distribution - from setuptools.extension import Extension - from setuptools.command.build_ext import build_ext - HAVE_SETUPTOOLS = True -except ImportError: - HAVE_SETUPTOOLS = False -from importlib import import_module -import os -import sys - -PACKAGE_MANAGER = { - "OpenBSD": "pkg_add", - "FreeBSD": "pkg install", - "Debian": "apt-get install", - "Ubuntu": "apt-get install", - "Ubuntu 12": "apt-get install", - "openSUSE": "zypper install", - "Fedora": "dnf install", - "Guix": "guix package -i", - "Gentoo": "emerge" -} - -PACKAGES = { - "PyQt4": { - "OpenBSD": "py-qt4", - "FreeBSD": "py27-qt4", - "Debian": "python-qt4", - "Ubuntu": "python-qt4", - "Ubuntu 12": "python-qt4", - "openSUSE": "python-qt", - "Fedora": "PyQt4", - "Guix": "python2-pyqt@4.11.4", - "Gentoo": "dev-python/PyQt4", - 'optional': True, - 'description': "You only need PyQt if you want to use the GUI. " \ - "When only running as a daemon, this can be skipped.\n" \ - "However, you would have to install it manually " \ - "because setuptools does not support PyQt." - }, - "msgpack": { - "OpenBSD": "py-msgpack", - "FreeBSD": "py27-msgpack-python", - "Debian": "python-msgpack", - "Ubuntu": "python-msgpack", - "Ubuntu 12": "msgpack-python", - "openSUSE": "python-msgpack-python", - "Fedora": "python2-msgpack", - "Guix": "python2-msgpack", - "Gentoo": "dev-python/msgpack", - "optional": True, - "description": "python-msgpack is recommended for improved performance of message encoding/decoding" - }, - "pyopencl": { - "FreeBSD": "py27-pyopencl", - "Debian": "python-pyopencl", - "Ubuntu": "python-pyopencl", - "Ubuntu 12": "python-pyopencl", - "Fedora": "python2-pyopencl", - "openSUSE": "", - "OpenBSD": "", - "Guix": "", - "Gentoo": "dev-python/pyopencl", - "optional": True, - 'description': "If you install pyopencl, you will be able to use " \ - "GPU acceleration for proof of work. \n" \ - "You also need a compatible GPU and drivers." - }, - "setuptools": { - "OpenBSD": "py-setuptools", - "FreeBSD": "py27-setuptools", - "Debian": "python-setuptools", - "Ubuntu": "python-setuptools", - "Ubuntu 12": "python-setuptools", - "Fedora": "python2-setuptools", - "openSUSE": "python-setuptools", - "Guix": "python2-setuptools", - "Gentoo": "", - "optional": False, - } -} - -COMPILING = { - "Debian": "build-essential libssl-dev", - "Ubuntu": "build-essential libssl-dev", - "Fedora": "gcc-c++ redhat-rpm-config python-devel openssl-devel", - "openSUSE": "gcc-c++ libopenssl-devel python-devel", - "optional": False, -} - -def detectOSRelease(): - with open("/etc/os-release", 'r') as osRelease: - version = None - for line in osRelease: - if line.startswith("NAME="): - line = line.lower() - if "fedora" in line: - detectOS.result = "Fedora" - elif "opensuse" in line: - detectOS.result = "openSUSE" - elif "ubuntu" in line: - detectOS.result = "Ubuntu" - elif "debian" in line: - detectOS.result = "Debian" - elif "gentoo" in line or "calculate" in line: - detectOS.result = "Gentoo" - else: - detectOS.result = None - if line.startswith("VERSION_ID="): - try: - version = float(line.split("=")[1].replace("\"", "")) - except ValueError: - pass - if detectOS.result == "Ubuntu" and version < 14: - detectOS.result = "Ubuntu 12" - -def detectOS(): - if detectOS.result is not None: - return detectOS.result - if sys.platform.startswith('openbsd'): - detectOS.result = "OpenBSD" - elif sys.platform.startswith('freebsd'): - detectOS.result = "FreeBSD" - elif sys.platform.startswith('win'): - detectOS.result = "Windows" - elif os.path.isfile("/etc/os-release"): - detectOSRelease() - elif os.path.isfile("/etc/config.scm"): - detectOS.result = "Guix" - return detectOS.result - -def detectPrereqs(missing=True): - available = [] - for module in PACKAGES: - try: - import_module(module) - if not missing: - available.append(module) - except ImportError: - if missing: - available.append(module) - return available - -def prereqToPackages(): - if not detectPrereqs(): - return - print "%s %s" % ( - PACKAGE_MANAGER[detectOS()], " ".join( - PACKAGES[x][detectOS()] for x in detectPrereqs())) - -def compilerToPackages(): - if not detectOS() in COMPILING: - return - print "%s %s" % ( - PACKAGE_MANAGER[detectOS.result], COMPILING[detectOS.result]) - -def testCompiler(): - if not HAVE_SETUPTOOLS: - # silent, we can't test without setuptools - return True - - bitmsghash = Extension( - 'bitmsghash', - sources=['src/bitmsghash/bitmsghash.cpp'], - libraries=['pthread', 'crypto'], - ) - - dist = Distribution() - dist.ext_modules = [bitmsghash] - cmd = build_ext(dist) - cmd.initialize_options() - cmd.finalize_options() - cmd.force = True - try: - cmd.run() - except CompileError: - return False - else: - fullPath = os.path.join(cmd.build_lib, cmd.get_ext_filename("bitmsghash")) - return os.path.isfile(fullPath) - -detectOS.result = None -prereqs = detectPrereqs() - -compiler = testCompiler() - -if (not compiler or prereqs) and detectOS() in PACKAGE_MANAGER: - print "It looks like you're using %s. " \ - "It is highly recommended to use the package manager\n" \ - "to install the missing dependencies." % (detectOS.result) - -if not compiler: - print "Building the bitmsghash module failed.\n" \ - "You may be missing a C++ compiler and/or the OpenSSL headers." - -if prereqs: - mandatory = list(x for x in prereqs if "optional" not in PACKAGES[x] or not PACKAGES[x]["optional"]) - optional = list(x for x in prereqs if "optional" in PACKAGES[x] and PACKAGES[x]["optional"]) - if mandatory: - print "Missing mandatory dependencies: %s" % (" ".join(mandatory)) - if optional: - print "Missing optional dependencies: %s" % (" ".join(optional)) - for package in optional: - print PACKAGES[package].get('description') - -if (not compiler or prereqs) and detectOS() in PACKAGE_MANAGER: - print "You can install the missing dependencies by running, as root:" - if not compiler: - compilerToPackages() - prereqToPackages() -else: - print "All the dependencies satisfied, you can install PyBitmessage" diff --git a/packages/unmaintained/debian.sh b/debian.sh similarity index 88% rename from packages/unmaintained/debian.sh rename to debian.sh index 9caed2dc..3a4edbe5 100755 --- a/packages/unmaintained/debian.sh +++ b/debian.sh @@ -1,13 +1,11 @@ #!/bin/bash APP=pybitmessage -PREV_VERSION=0.4.4 -VERSION=0.6.0 +PREV_VERSION=0.4.2 +VERSION=0.4.4 RELEASE=1 ARCH_TYPE=all DIR=${APP}-${VERSION} -CURDIR=`pwd` -SHORTDIR=`basename ${CURDIR}` if [ $ARCH_TYPE == "x86_64" ]; then ARCH_TYPE="amd64" @@ -32,17 +30,17 @@ make clean make # Change the parent directory name to Debian format -mv ../${SHORTDIR} ../${DIR} +mv ../${APP} ../${DIR} # Create a source archive make sourcedeb # Build the package -dpkg-buildpackage -F -us -uc +dpkg-buildpackage -F # Sign files gpg -ba ../${APP}_${VERSION}-1_${ARCH_TYPE}.deb gpg -ba ../${APP}_${VERSION}.orig.tar.gz # Restore the parent directory name -mv ../${DIR} ../${SHORTDIR} +mv ../${DIR} ../${APP} diff --git a/packages/unmaintained/debian/changelog b/debian/changelog similarity index 98% rename from packages/unmaintained/debian/changelog rename to debian/changelog index 9fc04ddb..415dc400 100644 --- a/packages/unmaintained/debian/changelog +++ b/debian/changelog @@ -1,12 +1,3 @@ -pybitmessage (0.6.0-1) trusty; urgency=low - - * Bugfixes - * UI improvements - * performance and security improvements - * integration with email gateway (mailchuck.com) - - -- Peter Surda Mon, 2 May 2016 16:25:00 +0200 - pybitmessage (0.4.4-1) utopic; urgency=low * Added ability to limit network transfer rate diff --git a/packages/unmaintained/debian/compat b/debian/compat similarity index 100% rename from packages/unmaintained/debian/compat rename to debian/compat diff --git a/packages/unmaintained/debian/control b/debian/control similarity index 100% rename from packages/unmaintained/debian/control rename to debian/control diff --git a/packages/unmaintained/debian/copyright b/debian/copyright similarity index 90% rename from packages/unmaintained/debian/copyright rename to debian/copyright index b341b873..55863ba1 100644 --- a/packages/unmaintained/debian/copyright +++ b/debian/copyright @@ -3,11 +3,11 @@ Upstream-Name: Source: Files: * -Copyright: Copyright 2016 Bob Mottram (4096 bits) +Copyright: Copyright 2014 Bob Mottram (4096 bits) License: MIT Files: debian/* -Copyright: Copyright 2016 Bob Mottram (4096 bits) +Copyright: Copyright 2014 Bob Mottram (4096 bits) License: MIT License: MIT diff --git a/packages/unmaintained/debian/docs b/debian/docs similarity index 100% rename from packages/unmaintained/debian/docs rename to debian/docs diff --git a/packages/unmaintained/debian/manpages b/debian/manpages similarity index 100% rename from packages/unmaintained/debian/manpages rename to debian/manpages diff --git a/packages/unmaintained/debian/pybm b/debian/pybm similarity index 100% rename from packages/unmaintained/debian/pybm rename to debian/pybm diff --git a/packages/unmaintained/debian/rules b/debian/rules similarity index 100% rename from packages/unmaintained/debian/rules rename to debian/rules diff --git a/packages/unmaintained/debian/source/format b/debian/source/format similarity index 100% rename from packages/unmaintained/debian/source/format rename to debian/source/format diff --git a/packages/unmaintained/debian/source/include-binaries b/debian/source/include-binaries similarity index 100% rename from packages/unmaintained/debian/source/include-binaries rename to debian/source/include-binaries diff --git a/desktop/can-icon.svg b/desktop/can-icon.svg index 7c854e34..b4c2bd89 100644 --- a/desktop/can-icon.svg +++ b/desktop/can-icon.svg @@ -9,11 +9,11 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="793.70081" - height="1122.5197" + width="744.09448819" + height="1052.3622047" id="svg2" version="1.1" - inkscape:version="0.92.1 r" + inkscape:version="0.48.4 r9939" sodipodi:docname="can-icon.svg"> @@ -45,7 +45,7 @@ image/svg+xml - + @@ -55,95 +55,129 @@ id="layer1"> + transform="translate(9.8994953,147.07822)"> + + + + + + + + + + + + id="path3105" + d="M 320.96654,38.913858 51.9306,499.516" + style="fill:none;stroke:#000000;stroke-width:1.54755318px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + + d="M 370.82523,26.309365 105.49275,476.8148" + style="fill:#808080;stroke:#000000;stroke-width:1.54387176px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.11949684" /> + d="M 181.18883,489.0675 437.71536,40.464131" + style="fill:none;stroke:#000000;stroke-width:1.55417168px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.06918239" /> + + d="M 265.93611,524.57433 515.39415,72.865001" + style="fill:#b3b3b3;stroke:#000000;stroke-width:1.54755318px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.07547171" /> + + + d="M 414.69412,653.42954 657.84449,196.92693" + style="fill:none;stroke:#000000;stroke-width:1.54755318px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.21383649" /> + id="path3789" + d="m 432.89205,699.31284 c 0.17105,-7.00112 -5.92592,-25.26221 -12.06513,-36.13638 l -5.18621,-9.18613 6.39957,-11.51258 c 7.57517,-13.6274 209.52877,-392.42011 225.13618,-422.27505 l 10.74842,-20.5603 3.78885,6.2232 c 5.34342,8.77662 10.631,24.86087 11.21936,34.12823 0.47079,7.41538 -0.0329,8.8489 -8.73578,24.86068 -5.07938,9.34538 -58.93099,111.94581 -119.67008,228.00102 -60.73907,116.0552 -110.73218,211.10533 -111.09578,211.22251 -0.3636,0.11718 -0.60636,-2.02717 -0.53946,-4.76523 l 0,0 z M 383.58623,615.47494 629.5772,157.12597" + style="fill:#b3b3b3;stroke:#000000;stroke-width:1.54755318;stroke-opacity:0.21383649" /> + id="path3791" + d="m 408.26635,642.79453 c -2.77517,-3.91094 -9.09904,-11.83931 -14.05304,-17.6186 l -9.00726,-10.5078 11.06562,-19.93851 c 6.08602,-10.96623 60.695,-112.54525 121.35316,-225.73125 60.65817,-113.186 110.57207,-205.90346 110.91978,-206.03881 0.96223,-0.37455 11.55983,11.72618 19.91814,22.74327 l 7.46029,9.83339 -4.53134,9.80365 C 645.37692,218.35301 419.87091,640.72729 416.18164,645.8899 l -2.86948,4.01545 -5.04578,-7.1108 z" + style="fill:#cccccc;stroke:#000000;stroke-width:1.54755318;stroke-opacity:0.21383649" /> + id="path3092" + d="m 371.74406,601.83061 c -21.9825,-21.71509 -57.77462,-48.54944 -91.21678,-68.38776 -7.00036,-4.15271 -12.90367,-7.66798 -13.11848,-7.81172 -0.2148,-0.14376 51.06833,-93.4237 113.96253,-207.28879 C 444.26554,204.47725 499.99579,103.54769 505.21636,94.054416 l 9.49193,-17.260489 12.31004,7.244658 c 16.16532,9.513561 42.09046,26.931205 55.80488,37.492175 14.43229,11.11376 43.65233,37.36326 43.15949,38.77184 -1.19016,3.40165 -242.33727,452.21019 -242.92494,452.11733 -0.3889,-0.0615 -5.48007,-4.82664 -11.3137,-10.58932 l 0,0 z" + style="fill:#b3b3b3" /> - - - + id="path3094" + d="m 370.32984,599.64651 c -13.89342,-13.08279 -30.14402,-26.59088 -31.98957,-26.59088 -0.69915,0 -2.08148,-1.29748 -3.07184,-2.88329 -0.99036,-1.58582 -2.41623,-2.50287 -3.16861,-2.03787 -0.75238,0.46499 -1.36796,0.23149 -1.36796,-0.51889 0,-1.85189 -23.8082,-18.60406 -44.54773,-31.34517 -9.3338,-5.73412 -17.16014,-10.54638 -17.39186,-10.69391 -0.41663,-0.26524 97.56855,-178.64134 195.50085,-355.89748 48.34786,-87.508983 50.71018,-91.472283 53.61341,-89.948371 7.3399,3.852715 34.04527,20.993951 48.43449,31.088381 16.63992,11.67337 56.24235,44.92528 57.5435,48.31602 0.74942,1.95294 -57.86712,112.36525 -180.22205,339.47312 -32.74563,60.78045 -59.93672,110.92569 -60.42466,111.43384 -0.48793,0.50817 -6.29652,-4.1698 -12.90797,-10.3955 z" + style="fill:#e6e6e6" /> diff --git a/desktop/pybitmessage.desktop b/desktop/pybitmessage.desktop index 05970440..a97bd664 100644 --- a/desktop/pybitmessage.desktop +++ b/desktop/pybitmessage.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Type=Application Name=PyBitmessage -GenericName=Bitmessage Client +GenericName=PyBitmessage Comment=Send encrypted messages Exec=pybitmessage %F Icon=pybitmessage diff --git a/dev/README.md b/dev/README.md deleted file mode 100644 index 41bf59c8..00000000 --- a/dev/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains code for future features, but it's not integrated into -PyBitmessage and may not work at all. Developers can look at it if they are -interested. diff --git a/dev/bloomfiltertest.py b/dev/bloomfiltertest.py deleted file mode 100644 index 539d00f3..00000000 --- a/dev/bloomfiltertest.py +++ /dev/null @@ -1,60 +0,0 @@ -from math import ceil -from os import stat, getenv, path -from pybloom import BloomFilter as BloomFilter1 -from pybloomfilter import BloomFilter as BloomFilter2 -import sqlite3 -from time import time - -# Ubuntu: apt-get install python-pybloomfiltermmap - -conn = sqlite3.connect(path.join(getenv("HOME"), '.config/PyBitmessage/messages.dat')) - -conn.text_factory = str -cur = conn.cursor() -rawlen = 0 -itemcount = 0 - -cur.execute('''SELECT COUNT(hash) FROM inventory''') -for row in cur.fetchall(): - itemcount = row[0] - -filtersize = 1000 * (int(itemcount / 1000) + 1) -errorrate = 1.0 / 1000.0 - -bf1 = BloomFilter1(capacity=filtersize, error_rate=errorrate) -bf2 = BloomFilter2(capacity=filtersize, error_rate=errorrate) - -item = '''SELECT hash FROM inventory''' -cur.execute(item, '') -bf1time = 0 -bf2time = 0 -for row in cur.fetchall(): - rawlen += len(row[0]) - try: - times = [time()] - bf1.add(row[0]) - times.append(time()) - bf2.add(row[0]) - times.append(time()) - bf1time += times[1] - times[0] - bf2time += times[2] - times[1] - except IndexError: - pass - -#f = open("/home/shurdeek/tmp/bloom.dat", "wb") -#sb1.tofile(f) -#f.close() - - -print "Item count: %i" % (itemcount) -print "Raw length: %i" % (rawlen) -print "Bloom filter 1 length: %i, reduction to: %.2f%%" % \ - (bf1.bitarray.buffer_info()[1], - 100.0 * bf1.bitarray.buffer_info()[1] / rawlen) -print "Bloom filter 1 capacity: %i and error rate: %.3f%%" % (bf1.capacity, 100.0 * bf1.error_rate) -print "Bloom filter 1 took %.2fs" % (bf1time) -print "Bloom filter 2 length: %i, reduction to: %.3f%%" % \ - (bf2.num_bits / 8, - 100.0 * bf2.num_bits / 8 / rawlen) -print "Bloom filter 2 capacity: %i and error rate: %.3f%%" % (bf2.capacity, 100.0 * bf2.error_rate) -print "Bloom filter 2 took %.2fs" % (bf2time) diff --git a/dev/msgtest.py b/dev/msgtest.py deleted file mode 100644 index d5a8be8e..00000000 --- a/dev/msgtest.py +++ /dev/null @@ -1,27 +0,0 @@ -import importlib -from os import listdir, path -from pprint import pprint -import sys -import traceback - -data = {"": "message", "subject": "subject", "body": "body"} -#data = {"": "vote", "msgid": "msgid"} -#data = {"fsck": 1} - -import messagetypes - -if __name__ == '__main__': - try: - msgType = data[""] - except KeyError: - print "Message type missing" - sys.exit(1) - else: - print "Message type: %s" % (msgType) - msgObj = messagetypes.constructObject(data) - if msgObj is None: - sys.exit(1) - try: - msgObj.process() - except: - pprint(sys.exc_info()) diff --git a/dev/powinterrupttest.py b/dev/powinterrupttest.py deleted file mode 100644 index cc4c2197..00000000 --- a/dev/powinterrupttest.py +++ /dev/null @@ -1,49 +0,0 @@ -import ctypes -import hashlib -from multiprocessing import current_process -import os -import signal -from struct import unpack, pack -from threading import current_thread - -shutdown = 0 - - -def signal_handler(signal, frame): - global shutdown - print "Got signal %i in %s/%s" % (signal, current_process().name, current_thread().name) - if current_process().name != "MainProcess": - raise StopIteration("Interrupted") - if current_thread().name != "PyBitmessage": - return - shutdown = 1 - - -def _doCPoW(target, initialHash): -# global shutdown - h = initialHash - m = target - out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64)) - out_m = ctypes.c_ulonglong(m) - print "C PoW start" - for c in range(0, 200000): - print "Iter: %i" % (c) - nonce = bmpow(out_h, out_m) - if shutdown: - break - trialValue, = unpack('>Q', hashlib.sha512(hashlib.sha512(pack('>Q', nonce) + initialHash).digest()).digest()[0:8]) - if shutdown != 0: - raise StopIteration("Interrupted") - print "C PoW done" - return [trialValue, nonce] - - -signal.signal(signal.SIGINT, signal_handler) -signal.signal(signal.SIGTERM, signal_handler) - -bso = ctypes.CDLL(os.path.join("bitmsghash", "bitmsghash.so")) - -bmpow = bso.BitmessagePOW -bmpow.restype = ctypes.c_ulonglong - -_doCPoW(2**44, "") diff --git a/dev/ssltest.py b/dev/ssltest.py deleted file mode 100644 index 4ddca8ca..00000000 --- a/dev/ssltest.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -import select -import socket -import ssl -import sys -import traceback - -HOST = "127.0.0.1" -PORT = 8912 - -def sslProtocolVersion(): - # sslProtocolVersion - if sys.version_info >= (2,7,13): - # this means TLSv1 or higher - # in the future change to - # ssl.PROTOCOL_TLS1.2 - return ssl.PROTOCOL_TLS - elif sys.version_info >= (2,7,9): - # this means any SSL/TLS. SSLv2 and 3 are excluded with an option after context is created - return ssl.PROTOCOL_SSLv23 - else: - # this means TLSv1, there is no way to set "TLSv1 or higher" or - # "TLSv1.2" in < 2.7.9 - return ssl.PROTOCOL_TLSv1 - -def sslProtocolCiphers(): - if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000: - return "AECDH-AES256-SHA@SECLEVEL=0" - else: - return "AECDH-AES256-SHA" - -def connect(): - sock = socket.create_connection((HOST, PORT)) - return sock - -def listen(): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind((HOST, PORT)) - sock.listen(0) - return sock - -def sslHandshake(sock, server=False): - if sys.version_info >= (2,7,9): - context = ssl.SSLContext(sslProtocolVersion()) - context.set_ciphers(sslProtocolCiphers()) - context.set_ecdh_curve("secp256k1") - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE - sslSock = context.wrap_socket(sock, server_side = server, do_handshake_on_connect=False) - else: - sslSock = ssl.wrap_socket(sock, keyfile = os.path.join('src', 'sslkeys', 'key.pem'), certfile = os.path.join('src', 'sslkeys', 'cert.pem'), server_side = server, ssl_version=sslProtocolVersion(), do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') - - while True: - try: - sslSock.do_handshake() - break - except ssl.SSLWantReadError: - print "Waiting for SSL socket handhake read" - select.select([sslSock], [], [], 10) - except ssl.SSLWantWriteError: - print "Waiting for SSL socket handhake write" - select.select([], [sslSock], [], 10) - except Exception: - print "SSL socket handhake failed, shutting down connection" - traceback.print_exc() - return - print "Success!" - return sslSock - -if __name__ == "__main__": - if len(sys.argv) != 2: - print "Usage: ssltest.py client|server" - sys.exit(0) - elif sys.argv[1] == "server": - serversock = listen() - while True: - print "Waiting for connection" - sock, addr = serversock.accept() - print "Got connection from %s:%i" % (addr[0], addr[1]) - sslSock = sslHandshake(sock, True) - if sslSock: - sslSock.shutdown(socket.SHUT_RDWR) - sslSock.close() - elif sys.argv[1] == "client": - sock = connect() - sslSock = sslHandshake(sock, False) - if sslSock: - sslSock.shutdown(socket.SHUT_RDWR) - sslSock.close() - else: - print "Usage: ssltest.py client|server" - sys.exit(0) diff --git a/packages/unmaintained/ebuild.sh b/ebuild.sh similarity index 98% rename from packages/unmaintained/ebuild.sh rename to ebuild.sh index cd73685b..11a6f5be 100755 --- a/packages/unmaintained/ebuild.sh +++ b/ebuild.sh @@ -2,7 +2,7 @@ APP=pybitmessage PREV_VERSION=0.4.4 -VERSION=0.6.0 +VERSION=0.4.4 RELEASE=1 SOURCEDIR=. ARCH_TYPE=`uname -m` diff --git a/ebuildpackage/pybitmessage-0.3.5-1.ebuild b/ebuildpackage/pybitmessage-0.3.5-1.ebuild new file mode 100755 index 00000000..01eddc4f --- /dev/null +++ b/ebuildpackage/pybitmessage-0.3.5-1.ebuild @@ -0,0 +1,32 @@ +# $Header: $ + +EAPI=5 + +inherit git-2 python-r1 + +PYTHON_COMPAT=( python2_7 ) +PYTHON_REQ_USE="sqlite" +REQUIRED_USE="${PYTHON_REQUIRED_USE}" +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." +HOMEPAGE="https://github.com/Bitmessage/PyBitmessage" +EGIT_REPO_URI="https://github.com/Bitmessage/PyBitmessage.git" +LICENSE="MIT" +SLOT="0" +KEYWORDS="x86" +DEPEND="dev-libs/popt + ${PYTHON_DEPS}" +RDEPEND="${DEPEND} + dev-libs/openssl + dev-python/PyQt4[]" + +src_configure() { + econf --with-popt +} + +src_compile() { :; } + +src_install() { + emake DESTDIR="${D}" PREFIX="/usr" install + # Install README and (Debian) changelog + dodoc README.md debian/changelog +} diff --git a/packages/unmaintained/generate.sh b/generate.sh similarity index 100% rename from packages/unmaintained/generate.sh rename to generate.sh diff --git a/build/osx.sh b/osx.sh similarity index 95% rename from build/osx.sh rename to osx.sh index e58a49f4..eaa33183 100755 --- a/build/osx.sh +++ b/osx.sh @@ -14,8 +14,6 @@ fi echo "Creating OS X packages for Bitmessage." -export PYBITMESSAGEVERSION=$1 - cd src && python2.7 build_osx.py py2app if [[ $? = "0" ]]; then diff --git a/packages/README.md b/packages/README.md deleted file mode 100644 index ed2df3cc..00000000 --- a/packages/README.md +++ /dev/null @@ -1,36 +0,0 @@ -The `generate.sh` script is obsolete, but is included for historical reasons. - -Maintained packages can be obtained: - -Windows: -======== - -https://github.com/Bitmessage/PyBitmessage/releases - -Works on Windows XP or higher. - - -OSX: -==== - -https://github.com/Bitmessage/PyBitmessage/releases - -Wors on OSX 10.7.5 or higher - - -Arch linux: -=========== - -Releases matching PyBitmessage releases: - -https://aur.archlinux.org/packages/pybitmessage-git/ - -Development snapshot equivalent to the v0.6 git branch: - -https://aur.archlinux.org/packages/pybitmessage-dev-git/ - - -FreeBSD: -======== - -Use the FreeBSD ports. diff --git a/packages/collectd/pybitmessagestatus.py b/packages/collectd/pybitmessagestatus.py deleted file mode 100644 index 1db9f5b1..00000000 --- a/packages/collectd/pybitmessagestatus.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python2.7 - -import collectd -import json -import xmlrpclib - -pybmurl = "" -api = "" - -def init_callback(): - global api - api = xmlrpclib.ServerProxy(pybmurl) - collectd.info('pybitmessagestatus.py init done') - -def config_callback(ObjConfiguration): - global pybmurl - apiUsername = "" - apiPassword = "" - apiInterface = "127.0.0.1" - apiPort = 8445 - for node in ObjConfiguration.children: - key = node.key.lower() - if key.lower() == "apiusername" and node.values: - apiUsername = node.values[0] - elif key.lower() == "apipassword" and node.values: - apiPassword = node.values[0] - elif key.lower() == "apiinterface" and node.values: - apiInterface = node.values[0] - elif key.lower() == "apiport" and node.values: - apiPort = node.values[0] - pybmurl = "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface+ ":" + str(int(apiPort)) + "/" - collectd.info('pybitmessagestatus.py config done') - -def read_callback(): - try: - clientStatus = json.loads(api.clientStatus()) - except: - collectd.info("Exception loading or parsing JSON") - return - - for i in ["networkConnections", "numberOfPubkeysProcessed", "numberOfMessagesProcessed", "numberOfBroadcastsProcessed"]: - metric = collectd.Values() - metric.plugin = "pybitmessagestatus" - if i[0:6] == "number": - metric.type = 'counter' - else: - metric.type = 'gauge' - metric.type_instance = i.lower() - try: - metric.values = [clientStatus[i]] - except: - collectd.info("Value for %s missing" % (i)) - metric.dispatch() - -if __name__ == "__main__": - main() -else: - collectd.register_init(init_callback) - collectd.register_config(config_callback) - collectd.register_read(read_callback) diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec deleted file mode 100644 index 06cf6e76..00000000 --- a/packages/pyinstaller/bitmessagemain.spec +++ /dev/null @@ -1,79 +0,0 @@ -import ctypes -import os -import time - -srcPath = "C:\\src\\PyBitmessage\\src\\" -qtPath = "C:\\Qt-4.8.7\\" -openSSLPath = "C:\\OpenSSL-1.0.2j\\bin\\" -outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" -today = time.strftime("%Y%m%d") -snapshot = False - -os.rename(os.path.join(srcPath, '__init__.py'), os.path.join(srcPath, '__init__.py.backup')) - -# -*- mode: python -*- -a = Analysis([srcPath + 'bitmessagemain.py'], - pathex=[outPath], - hiddenimports=[], - hookspath=None, - runtime_hooks=None) - -os.rename(os.path.join(srcPath, '__init__.py.backup'), os.path.join(srcPath, '__init__.py')) - -def addTranslations(): - import os - extraDatas = [] - for file in os.listdir(srcPath + 'translations'): - if file[-3:] != ".qm": - continue - extraDatas.append((os.path.join('translations', file), os.path.join(srcPath, 'translations', file), 'DATA')) - for file in os.listdir(qtPath + 'translations'): - if file[0:3] != "qt_" or file[5:8] != ".qm": - continue - extraDatas.append((os.path.join('translations', file), os.path.join(qtPath, 'translations', file), 'DATA')) - return extraDatas - -def addUIs(): - import os - extraDatas = [] - for file in os.listdir(srcPath + 'bitmessageqt'): - if file[-3:] != ".ui": - continue - extraDatas.append((os.path.join('ui', file), os.path.join(srcPath, 'bitmessageqt', file), 'DATA')) - return extraDatas - -# append the translations directory -a.datas += addTranslations() -a.datas += addUIs() - -if ctypes.sizeof(ctypes.c_voidp) == 4: - arch=32 -else: - arch=64 - -a.binaries += [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), - (os.path.join('bitmsghash', 'bitmsghash%i.dll' % (arch)), os.path.join(srcPath, 'bitmsghash', 'bitmsghash%i.dll' % (arch)), 'BINARY'), - (os.path.join('bitmsghash', 'bitmsghash.cl'), os.path.join(srcPath, 'bitmsghash', 'bitmsghash.cl'), 'BINARY'), - (os.path.join('sslkeys', 'cert.pem'), os.path.join(srcPath, 'sslkeys', 'cert.pem'), 'BINARY'), - (os.path.join('sslkeys', 'key.pem'), os.path.join(srcPath, 'sslkeys', 'key.pem'), 'BINARY') - ] - -with open(os.path.join(srcPath, 'version.py'), 'rt') as f: - softwareVersion = f.readline().split('\'')[1] - -fname = 'Bitmessage_%s_%s.exe' % ("x86" if arch == 32 else "x64", softwareVersion) -if snapshot: - fname = 'Bitmessagedev_%s_%s.exe' % ("x86" if arch == 32 else "x64", today) - -pyz = PYZ(a.pure) -exe = EXE(pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - a.binaries, - name=fname, - debug=False, - strip=None, - upx=False, - console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) diff --git a/packages/systemd/bitmessage.service b/packages/systemd/bitmessage.service deleted file mode 100644 index 1a9f7f47..00000000 --- a/packages/systemd/bitmessage.service +++ /dev/null @@ -1,18 +0,0 @@ -[Unit] -Description=Bitmessage Daemon -After=network.target auditd.service - -[Service] -ExecStart=/usr/bin/python2 /usr/src/PyBitmessage/src/bitmessagemain.py -ExecReload=/bin/kill -HUP $MAINPID -KillMode=process -Restart=on-failure -Type=forking -PIDFile=/var/lib/bitmessage/.config/PyBitmessage/singleton.lock -User=bitmessage -Group=nogroup -WorkingDirectory=/var/lib/bitmessage -Environment="HOME=/var/lib/bitmessage" - -[Install] -WantedBy=multi-user.target diff --git a/packages/upstart/bitmessage.conf b/packages/upstart/bitmessage.conf deleted file mode 100644 index 970fd4a7..00000000 --- a/packages/upstart/bitmessage.conf +++ /dev/null @@ -1,37 +0,0 @@ -# This is an upstart script for bitmessage for when using daemon mode -# Bitmessage forks more than twice before daemonizing, so a workaround is -# necessary - -description "bitmessage" -author "Peter Surda" - -start on (local-filesystems and net-device-up) -stop on runlevel [!2345] - -setuid bitmessage -setgid bitmessage - -chdir /home/bitmessage -env HOME="/home/bitmessage" - -pre-start script - /usr/src/PyBitmessage/src/bitmessagemain.py -end script - -script - while [ ! -f $HOME/.config/PyBitmessage/singleton.lock ]; do - sleep 1 - done - while [ -f $HOME/.config/PyBitmessage/singleton.lock ]; do - sleep 1 - done -end script - -post-stop script - if [ -f $HOME/.config/PyBitmessage/singleton.lock ]; then - pid=`lsof -F p $HOME/.config/PyBitmessage/singleton.lock|cut -b2-` - if [ -n "$pid" ]; then - kill $pid - fi - fi -end script diff --git a/packages/unmaintained/puppy.sh b/puppy.sh similarity index 99% rename from packages/unmaintained/puppy.sh rename to puppy.sh index a78e021c..48832734 100755 --- a/packages/unmaintained/puppy.sh +++ b/puppy.sh @@ -2,7 +2,7 @@ APP=pybitmessage PREV_VERSION=0.4.4 -VERSION=0.6.0 +VERSION=0.4.4 RELEASE=1 BUILDDIR=~/petbuild CURRDIR=`pwd` diff --git a/packages/unmaintained/puppypackage/icon14.xpm b/puppypackage/icon14.xpm similarity index 100% rename from packages/unmaintained/puppypackage/icon14.xpm rename to puppypackage/icon14.xpm diff --git a/packages/unmaintained/puppypackage/pybitmessage-0.3.5.pet.specs b/puppypackage/pybitmessage-0.3.5.pet.specs similarity index 100% rename from packages/unmaintained/puppypackage/pybitmessage-0.3.5.pet.specs rename to puppypackage/pybitmessage-0.3.5.pet.specs diff --git a/packages/unmaintained/rpm.sh b/rpm.sh similarity index 100% rename from packages/unmaintained/rpm.sh rename to rpm.sh diff --git a/packages/unmaintained/rpmpackage/pybitmessage.spec b/rpmpackage/pybitmessage.spec similarity index 99% rename from packages/unmaintained/rpmpackage/pybitmessage.spec rename to rpmpackage/pybitmessage.spec index 1235251a..258636f8 100644 --- a/packages/unmaintained/rpmpackage/pybitmessage.spec +++ b/rpmpackage/pybitmessage.spec @@ -1,5 +1,5 @@ Name: pybitmessage -Version: 0.6.0 +Version: 0.4.4 Release: 1%{?dist} Summary: Send encrypted messages License: MIT diff --git a/setup.py b/setup.py deleted file mode 100644 index ba34f6df..00000000 --- a/setup.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python2.7 - -import os -import sys -import shutil -from setuptools import setup, Extension -from setuptools.command.install import install - -from src.version import softwareVersion - -class InstallCmd(install): - def run(self): - # prepare icons directories - try: - os.makedirs('desktop/icons/scalable') - except os.error: - pass - shutil.copyfile( - 'desktop/can-icon.svg', 'desktop/icons/scalable/pybitmessage.svg') - try: - os.makedirs('desktop/icons/24x24') - except os.error: - pass - shutil.copyfile( - 'desktop/icon24.png', 'desktop/icons/24x24/pybitmessage.png') - - return install.run(self) - - -if __name__ == "__main__": - here = os.path.abspath(os.path.dirname(__file__)) - with open(os.path.join(here, 'README.md')) as f: - README = f.read() - - bitmsghash = Extension( - 'pybitmessage.bitmsghash.bitmsghash', - sources=['src/bitmsghash/bitmsghash.cpp'], - libraries=['pthread', 'crypto'], - ) - - installRequires = [] - packages = [ - 'pybitmessage', - 'pybitmessage.bitmessageqt', - 'pybitmessage.bitmessagecurses', - 'pybitmessage.messagetypes', - 'pybitmessage.network', - 'pybitmessage.pyelliptic', - 'pybitmessage.socks', - 'pybitmessage.storage', - 'pybitmessage.plugins' - ] - - # this will silently accept alternative providers of msgpack - # if they are already installed - - try: - import msgpack - installRequires.append("msgpack-python") - except ImportError: - try: - import umsgpack - installRequires.append("umsgpack") - except ImportError: - packages += ['pybitmessage.fallback', 'pybitmessage.fallback.umsgpack'] - - dist = setup( - name='pybitmessage', - version=softwareVersion, - description="Reference client for Bitmessage: " - "a P2P communications protocol", - long_description=README, - license='MIT', - # TODO: add author info - #author='', - #author_email='', - url='https://bitmessage.org', - # TODO: add keywords - #keywords='', - install_requires=installRequires, - extras_require={ - 'gir': ['pygobject'], - 'qrcode': ['qrcode'], - 'pyopencl': ['pyopencl'], - 'notify2': ['notify2'], - 'sound;platform_system=="Windows"': ['winsound'] - }, - classifiers=[ - "License :: OSI Approved :: MIT License" - "Operating System :: OS Independent", - "Programming Language :: Python :: 2.7 :: Only", - "Topic :: Internet", - "Topic :: Security :: Cryptography", - "Topic :: Software Development :: Libraries :: Python Modules", - ], - package_dir={'pybitmessage': 'src'}, - packages=packages, - package_data={'': [ - 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', - 'translations/*.ts', 'translations/*.qm', - 'images/*.png', 'images/*.ico', 'images/*.icns' - ]}, - data_files=[ - ('share/applications/', - ['desktop/pybitmessage.desktop']), - ('share/icons/hicolor/scalable/apps/', - ['desktop/icons/scalable/pybitmessage.svg']), - ('share/icons/hicolor/24x24/apps/', - ['desktop/icons/24x24/pybitmessage.png']) - ], - ext_modules=[bitmsghash], - zip_safe=False, - entry_points={ - 'bitmessage.gui.menu': [ - 'popMenuYourIdentities.qrcode = ' - 'pybitmessage.plugins.qrcodeui [qrcode]' - ], - 'bitmessage.notification.message': [ - 'notify2 = pybitmessage.plugins.notification_notify2' - '[gir, notify2]' - ], - 'bitmessage.notification.sound': [ - 'theme.canberra = pybitmessage.plugins.sound_canberra', - 'file.gstreamer = pybitmessage.plugins.sound_gstreamer' - '[gir]', - 'file.fallback = pybitmessage.plugins.sound_playfile' - '[sound]' - ], - 'bitmessage.indicator': [ - 'libmessaging =' - 'pybitmessage.plugins.indicator_libmessaging [gir]' - ], - # 'console_scripts': [ - # 'pybitmessage = pybitmessage.bitmessagemain:main' - # ] - }, - scripts=['src/pybitmessage'], - cmdclass={'install': InstallCmd} - ) diff --git a/packages/unmaintained/slack.sh b/slack.sh similarity index 99% rename from packages/unmaintained/slack.sh rename to slack.sh index f7495e46..c19ff954 100755 --- a/packages/unmaintained/slack.sh +++ b/slack.sh @@ -2,7 +2,7 @@ APP=pybitmessage PREV_VERSION=0.4.4 -VERSION=0.6.0 +VERSION=0.4.4 RELEASE=1 ARCH_TYPE=`uname -m` BUILDDIR=~/slackbuild diff --git a/packages/unmaintained/slackpackage/doinst.sh b/slackpackage/doinst.sh similarity index 100% rename from packages/unmaintained/slackpackage/doinst.sh rename to slackpackage/doinst.sh diff --git a/packages/unmaintained/slackpackage/slack-desc b/slackpackage/slack-desc similarity index 100% rename from packages/unmaintained/slackpackage/slack-desc rename to slackpackage/slack-desc diff --git a/src/__init__.py b/src/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/addresses.py b/src/addresses.py index c8caaf82..f6fbbf73 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -1,9 +1,8 @@ import hashlib from struct import * from pyelliptic import arithmetic -from binascii import hexlify, unhexlify -#from debug import logger + #There is another copy of this function in Bitmessagemain.py def convertIntToString(n): @@ -11,9 +10,9 @@ def convertIntToString(n): if a[-1:] == 'L': a = a[:-1] if (len(a) % 2) == 0: - return unhexlify(a[2:]) + return a[2:].decode('hex') else: - return unhexlify('0'+a[2:]) + return ('0'+a[2:]).decode('hex') ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -56,7 +55,7 @@ def decodeBase58(string, alphabet=ALPHABET): def encodeVarint(integer): if integer < 0: - logger.error('varint cannot be < 0') + print 'varint cannot be < 0' raise SystemExit if integer < 253: return pack('>B',integer) @@ -67,7 +66,7 @@ def encodeVarint(integer): if integer >= 4294967296 and integer < 18446744073709551616: return pack('>B',255) + pack('>Q',integer) if integer >= 18446744073709551616: - logger.error('varint cannot be >= 18446744073709551616') + print 'varint cannot be >= 18446744073709551616' raise SystemExit class varintDecodeError(Exception): @@ -143,7 +142,7 @@ def encodeAddress(version,stream,ripe): sha.update(currentHash) checksum = sha.digest()[0:4] - asInt = int(hexlify(storedBinaryData) + hexlify(checksum),16) + asInt = int(storedBinaryData.encode('hex') + checksum.encode('hex'),16) return 'BM-'+ encodeBase58(asInt) def decodeAddress(address): @@ -166,7 +165,7 @@ def decodeAddress(address): #print 'hexdata', hexdata - data = unhexlify(hexdata) + data = hexdata.decode('hex') checksum = data[-4:] sha = hashlib.new('sha512') @@ -186,25 +185,25 @@ def decodeAddress(address): try: addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9]) except varintDecodeError as e: - logger.error(str(e)) + print e status = 'varintmalformed' return status,0,0,"" #print 'addressVersionNumber', addressVersionNumber #print 'bytesUsedByVersionNumber', bytesUsedByVersionNumber if addressVersionNumber > 4: - logger.error('cannot decode address version numbers this high') + print 'cannot decode address version numbers this high' status = 'versiontoohigh' return status,0,0,"" elif addressVersionNumber == 0: - logger.error('cannot decode address version numbers of zero.') + print 'cannot decode address version numbers of zero.' status = 'versiontoohigh' return status,0,0,"" try: streamNumber, bytesUsedByStreamNumber = decodeVarint(data[bytesUsedByVersionNumber:]) except varintDecodeError as e: - logger.error(str(e)) + print e status = 'varintmalformed' return status,0,0,"" #print streamNumber @@ -269,7 +268,7 @@ if __name__ == "__main__": ripe.update(sha.digest()) addressVersionNumber = 2 streamNumber = 1 - print 'Ripe digest that we will encode in the address:', hexlify(ripe.digest()) + print 'Ripe digest that we will encode in the address:', ripe.digest().encode('hex') returnedAddress = encodeAddress(addressVersionNumber,streamNumber,ripe.digest()) print 'Encoded address:', returnedAddress status,addressVersionNumber,streamNumber,data = decodeAddress(returnedAddress) @@ -278,5 +277,5 @@ if __name__ == "__main__": print 'addressVersionNumber', addressVersionNumber print 'streamNumber', streamNumber print 'length of data(the ripe hash):', len(data) - print 'ripe data:', hexlify(data) + print 'ripe data:', data.encode('hex') diff --git a/src/api.py b/src/api.py index edb9e23d..f142953b 100644 --- a/src/api.py +++ b/src/api.py @@ -1,5 +1,5 @@ -# Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2016 The Bitmessage developers +# Copyright (c) 2012-2014 Jonathan Warren +# Copyright (c) 2012-2014 The Bitmessage developers comment= """ This is not what you run to run the Bitmessage API. Instead, enable the API @@ -12,33 +12,22 @@ if __name__ == "__main__": import sys sys.exit(0) -from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer -import base64 +from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler import json -from binascii import hexlify, unhexlify import shared import time from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError -from bmconfigparser import BMConfigParser -import defaults import helper_inbox import helper_sent import hashlib -import state from pyelliptic.openssl import OpenSSL -import queues -import shutdown from struct import pack -import network.stats # Classes -from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure -from helper_ackPayload import genAckPayload +from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute from debug import logger -from inventory import Inventory -from version import softwareVersion # Helper Functions import proofofwork @@ -54,15 +43,6 @@ class APIError(Exception): def __str__(self): return "API Error %04i: %s" % (self.error_number, self.error_message) - -class StoppableXMLRPCServer(SimpleXMLRPCServer): - allow_reuse_address = True - - def serve_forever(self): - while state.shutdown == 0: - self.handle_request() - - # This is one of several classes that constitute the API # This class was written by Vaibhav Bhatia. Modified by Jonathan Warren (Atheros). # http://code.activestate.com/recipes/501148-xmlrpc-serverclient-which-does-cookie-handling-and/ @@ -131,7 +111,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # handle Basic authentication (enctype, encstr) = self.headers.get('Authorization').split() (emailid, password) = encstr.decode('base64').split(':') - if emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and password == BMConfigParser().get('bitmessagesettings', 'apipassword'): + if emailid == shared.config.get('bitmessagesettings', 'apiusername') and password == shared.config.get('bitmessagesettings', 'apipassword'): return True else: return False @@ -144,10 +124,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def _decode(self, text, decode_type): try: - if decode_type == 'hex': - return unhexlify(text) - elif decode_type == 'base64': - return base64.b64decode(text) + return text.decode(decode_type) except Exception as e: raise APIError(22, "Decode error - " + str(e) + ". Had trouble while decoding string: " + repr(text)) @@ -177,39 +154,34 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleListAddresses(self, method): data = '{"addresses":[' - for addressInKeysFile in BMConfigParser().addresses(): - status, addressVersionNumber, streamNumber, hash01 = decodeAddress( - addressInKeysFile) - if len(data) > 20: - data += ',' - if BMConfigParser().has_option(addressInKeysFile, 'chan'): - chan = BMConfigParser().getboolean(addressInKeysFile, 'chan') - else: - chan = False - label = BMConfigParser().get(addressInKeysFile, 'label') - if method == 'listAddresses2': - label = base64.b64encode(label) - data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': - streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + status, addressVersionNumber, streamNumber, hash01 = decodeAddress( + addressInKeysFile) + if len(data) > 20: + data += ',' + if shared.config.has_option(addressInKeysFile, 'chan'): + chan = shared.config.getboolean(addressInKeysFile, 'chan') + else: + chan = False + label = shared.config.get(addressInKeysFile, 'label') + if method == 'listAddresses2': + label = label.encode('base64') + data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': + streamNumber, 'enabled': shared.config.getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) data += ']}' return data def HandleListAddressBookEntries(self, params): - if len(params) == 1: - label, = params - label = self._decode(label, "base64") - queryreturn = sqlQuery('''SELECT label, address from addressbook WHERE label = ?''', label) - elif len(params) > 1: - raise APIError(0, "Too many paremeters, max 1") - else: - queryreturn = sqlQuery('''SELECT label, address from addressbook''') + queryreturn = sqlQuery('''SELECT label, address from addressbook''') data = '{"addresses":[' for row in queryreturn: label, address = row label = shared.fixPotentiallyInvalidUTF8Data(label) if len(data) > 20: data += ',' - data += json.dumps({'label':base64.b64encode(label), 'address': address}, indent=4, separators=(',', ': ')) + data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -225,9 +197,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You already have this address in your address book.') sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) - queues.UISignalQueue.put(('rerenderAddressBook','')) + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderAddressBook','')) return "Added address %s to address book" % address def HandleDeleteAddressBookEntry(self, params): @@ -237,9 +209,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) self._verifyAddress(address) sqlExecute('DELETE FROM addressbook WHERE address=?', address) - queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) - queues.UISignalQueue.put(('rerenderAddressBook','')) + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderAddressBook','')) return "Deleted address book entry for %s if it existed" % address def HandleCreateRandomAddress(self, params): @@ -248,28 +220,28 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 1: label, = params eighteenByteRipe = False - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: label, eighteenByteRipe = params - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = BMConfigParser().get( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -277,11 +249,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): unicode(label, 'utf-8') except: raise APIError(17, 'Label is not valid UTF-8 data.') - queues.apiAddressGeneratorReturnQueue.queue.clear() + shared.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 - queues.addressGeneratorQueue.put(( + shared.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) - return queues.apiAddressGeneratorReturnQueue.get() + return shared.apiAddressGeneratorReturnQueue.get() def HandleCreateDeterministicAddresses(self, params): if len(params) == 0: @@ -292,52 +264,52 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params eighteenByteRipe = False - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params - nonceTrialsPerByte = BMConfigParser().get( + nonceTrialsPerByte = shared.config.get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = BMConfigParser().get( + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = BMConfigParser().get( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = shared.config.get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if len(passphrase) == 0: @@ -357,13 +329,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(4, 'Why would you ask me to generate 0 addresses for you?') if numberOfAddresses > 999: raise APIError(5, 'You have (accidentally?) specified too many addresses to make. Maximum 999. This check only exists to prevent mischief; if you really want to create more addresses than this, contact the Bitmessage developers and we can modify the check or you can do it yourself by searching the source code for this message.') - queues.apiAddressGeneratorReturnQueue.queue.clear() + shared.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) - queues.addressGeneratorQueue.put( + shared.addressGeneratorQueue.put( ('createDeterministicAddresses', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) data = '{"addresses":[' - queueReturn = queues.apiAddressGeneratorReturnQueue.get() + queueReturn = shared.apiAddressGeneratorReturnQueue.get() for item in queueReturn: if len(data) > 20: data += ',' @@ -384,12 +356,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(2, 'The address version number currently must be 3 or 4. ' + addressVersionNumber + ' isn\'t supported.') if streamNumber != 1: raise APIError(3, ' The stream number must be 1. Others aren\'t supported.') - queues.apiAddressGeneratorReturnQueue.queue.clear() + shared.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) - queues.addressGeneratorQueue.put( + shared.addressGeneratorQueue.put( ('getDeterministicAddress', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) - return queues.apiAddressGeneratorReturnQueue.get() + return shared.apiAddressGeneratorReturnQueue.get() def HandleCreateChan(self, params): if len(params) == 0: @@ -409,10 +381,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 4 streamNumber = 1 - queues.apiAddressGeneratorReturnQueue.queue.clear() + shared.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create chan %s.', passphrase) - queues.addressGeneratorQueue.put(('createChan', addressVersionNumber, streamNumber, label, passphrase, True)) - queueReturn = queues.apiAddressGeneratorReturnQueue.get() + shared.addressGeneratorQueue.put(('createChan', addressVersionNumber, streamNumber, label, passphrase)) + queueReturn = shared.apiAddressGeneratorReturnQueue.get() if len(queueReturn) == 0: raise APIError(24, 'Chan address is already present.') address = queueReturn[0] @@ -436,11 +408,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(suppliedAddress) suppliedAddress = addBMIfNotPresent(suppliedAddress) - queues.apiAddressGeneratorReturnQueue.queue.clear() - queues.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase, True)) - addressGeneratorReturnValue = queues.apiAddressGeneratorReturnQueue.get() + shared.apiAddressGeneratorReturnQueue.queue.clear() + shared.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase)) + addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() - if addressGeneratorReturnValue[0] == 'chan name does not match address': + if addressGeneratorReturnValue == 'chan name does not match address': raise APIError(18, 'Chan name does not match address.') if len(addressGeneratorReturnValue) == 0: raise APIError(24, 'Chan address is already present.') @@ -455,13 +427,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) - if not BMConfigParser().has_section(address): + if not shared.config.has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') - if not BMConfigParser().safeGetBoolean(address, 'chan'): + if not shared.safeConfigGetBoolean(address, 'chan'): raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') - BMConfigParser().remove_section(address) - with open(state.appdata + 'keys.dat', 'wb') as configfile: - BMConfigParser().write(configfile) + shared.config.remove_section(address) + with open(shared.appdata + 'keys.dat', 'wb') as configfile: + shared.config.write(configfile) return 'success' def HandleDeleteAddress(self, params): @@ -471,13 +443,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) - if not BMConfigParser().has_section(address): + if not shared.config.has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') - BMConfigParser().remove_section(address) - with open(state.appdata + 'keys.dat', 'wb') as configfile: - BMConfigParser().write(configfile) - queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) + shared.config.remove_section(address) + with open(shared.appdata + 'keys.dat', 'wb') as configfile: + shared.config.write(configfile) + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSentToLabels','')) shared.reloadMyAddressHashes() return 'success' @@ -491,10 +463,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid': hexlify(msgid), 'toAddress': toAddress, - 'fromAddress': fromAddress, 'subject': base64.b64encode(subject), - 'message': base64.b64encode(message), 'encodingType': encodingtype, - 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid': msgid.encode('hex'), 'toAddress': toAddress, 'fromAddress': fromAddress, 'subject': subject.encode( + 'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -506,7 +476,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid = row[0] if len(data) > 25: data += ',' - data += json.dumps({'msgid': hexlify(msgid)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -524,14 +494,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # UPDATE is slow, only update if status is different if queryreturn != [] and (queryreturn[0][0] == 1) != readStatus: sqlExecute('''UPDATE inbox set read = ? WHERE msgid=?''', readStatus, msgid) - queues.UISignalQueue.put(('changedInboxUnread', None)) + shared.UISignalQueue.put(('changedInboxUnread', None)) queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox WHERE msgid=?''', msgid) data = '{"inboxMessage":[' for row in queryreturn: msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -544,7 +514,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -555,7 +525,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid = row[0] if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -571,7 +541,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'receivedTime':received}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -585,7 +555,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -602,7 +572,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -617,7 +587,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':base64.b64encode(subject), 'message':base64.b64encode(message), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':msgid.encode('hex'), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':ackdata.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -658,8 +628,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 4*24*60*60 elif len(params) == 6: toAddress, fromAddress, subject, message, encodingType, TTL = params - if encodingType not in [2, 3]: - raise APIError(6, 'The encoding type must be 2 or 3.') + if encodingType != 2: + raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): @@ -673,15 +643,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = BMConfigParser().getboolean( + fromAddressEnabled = shared.config.getboolean( fromAddress, 'enabled') except: raise APIError(13, 'Could not find your fromAddress in the keys.dat file.') if not fromAddressEnabled: raise APIError(14, 'Your fromAddress is disabled. Cannot send.') - stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) + ackdata = OpenSSL.rand(32) t = ('', toAddress, @@ -706,12 +675,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): for row in queryreturn: toLabel, = row # apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) - queues.UISignalQueue.put(('displayNewSentMessage', ( + shared.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) - queues.workerQueue.put(('sendmessage', toAddress)) + shared.workerQueue.put(('sendmessage', toAddress)) - return hexlify(ackdata) + return ackdata.encode('hex') def HandleSendBroadcast(self, params): if len(params) == 0: @@ -725,8 +694,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 4*24*60*60 elif len(params) == 5: fromAddress, subject, message, encodingType, TTL = params - if encodingType not in [2, 3]: - raise APIError(6, 'The encoding type must be 2 or 3.') + if encodingType != 2: + raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): @@ -738,11 +707,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): fromAddress = addBMIfNotPresent(fromAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = BMConfigParser().getboolean( + fromAddressEnabled = shared.config.getboolean( fromAddress, 'enabled') except: raise APIError(13, 'could not find your fromAddress in the keys.dat file.') - ackdata = genAckPayload(streamNumber, 0) + ackdata = OpenSSL.rand(32) toAddress = '[Broadcast subscribers]' ripe = '' @@ -764,11 +733,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): helper_sent.insert(t) toLabel = '[Broadcast subscribers]' - queues.UISignalQueue.put(('displayNewSentMessage', ( + shared.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) - queues.workerQueue.put(('sendbroadcast', '')) + shared.workerQueue.put(('sendbroadcast', '')) - return hexlify(ackdata) + return ackdata.encode('hex') def HandleGetStatus(self, params): if len(params) != 1: @@ -810,8 +779,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You are already subscribed to that address.') sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',label, address, True) shared.reloadBroadcastSendersForWhichImWatching() - queues.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) - queues.UISignalQueue.put(('rerenderSubscriptions', '')) + shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) + shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Added subscription.' def HandleDeleteSubscription(self, params): @@ -821,18 +790,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) sqlExecute('''DELETE FROM subscriptions WHERE address=?''', address) shared.reloadBroadcastSendersForWhichImWatching() - queues.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) - queues.UISignalQueue.put(('rerenderSubscriptions', '')) + shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) + shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' def ListSubscriptions(self, params): queryreturn = sqlQuery('''SELECT label, address, enabled FROM subscriptions''') - data = {'subscriptions': []} + data = '{"subscriptions":[' for row in queryreturn: label, address, enabled = row label = shared.fixPotentiallyInvalidUTF8Data(label) - data['subscriptions'].append({'label':base64.b64encode(label), 'address': address, 'enabled': enabled == 1}) - return json.dumps(data, indent=4, separators=(',',': ')) + if len(data) > 20: + data += ',' + data += json.dumps({'label':label.encode('base64'), 'address': address, 'enabled': enabled == 1}, indent=4, separators=(',',': ')) + data += ']}' + return data def HandleDisseminatePreEncryptedMsg(self, params): # The device issuing this command to PyBitmessage supplies a msg object that has @@ -847,7 +819,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # Let us do the POW and attach it to the front target = 2**64 / ((len(encryptedPayload)+requiredPayloadLengthExtraBytes+8) * requiredAverageProofOfWorkNonceTrialsPerByte) with shared.printLock: - print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes + print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -862,11 +834,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 TTL = 2.5 * 24 * 60 * 60 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') + shared.inventorySets[toStreamNumber].add(inventoryHash) with shared.printLock: - print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - queues.invQueue.put((toStreamNumber, inventoryHash)) + print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex') + shared.broadcastToSendDataQueues(( + toStreamNumber, 'advertiseobject', inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): # This API method should only be used when msgid is not available @@ -888,8 +862,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ((len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + - 8) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + + 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -908,11 +882,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType = 1 #todo: support v4 pubkeys TTL = 28 * 24 * 60 * 60 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') + shared.inventorySets[pubkeyStreamNumber].add(inventoryHash) with shared.printLock: - print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) + print 'broadcasting inv within API command disseminatePubkey with hash:', inventoryHash.encode('hex') + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): # Method will eventually be used by a particular Android app to @@ -945,18 +921,18 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload, = row if len(data) > 25: data += ',' - data += json.dumps({'data':hexlify(payload)}, indent=4, separators=(',', ': ')) + data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) data += ']}' return data def HandleClientStatus(self, params): - if len(network.stats.connectedHostsList()) == 0: + if len(shared.connectedHostsList) == 0: networkStatus = 'notConnected' - elif len(network.stats.connectedHostsList()) > 0 and not shared.clientHasReceivedIncomingConnections: + elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: networkStatus = 'connectedAndReceivingIncomingConnections' - return json.dumps({'networkConnections':len(network.stats.connectedHostsList()),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':softwareVersion}, indent=4, separators=(',', ': ')) + return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':shared.softwareVersion}, indent=4, separators=(',', ': ')) def HandleDecodeAddress(self, params): # Return a meaningful decoding of an address. @@ -965,7 +941,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersion, streamNumber, ripe = decodeAddress(address) return json.dumps({'status':status, 'addressVersion':addressVersion, - 'streamNumber':streamNumber, 'ripe':base64.b64encode(ripe)}, indent=4, + 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, separators=(',', ': ')) def HandleHelloWorld(self, params): @@ -978,17 +954,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleStatusBar(self, params): message, = params - queues.UISignalQueue.put(('updateStatusBar', message)) + shared.UISignalQueue.put(('updateStatusBar', message)) - def HandleDeleteAndVacuum(self, params): - if not params: - sqlStoredProcedure('deleteandvacuume') - return 'done' - - def HandleShutdown(self, params): - if not params: - shutdown.doCleanShutdown() - return 'done' handlers = {} handlers['helloWorld'] = HandleHelloWorld @@ -1039,12 +1006,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): handlers['getMessageDataByDestinationTag'] = HandleGetMessageDataByDestinationHash handlers['clientStatus'] = HandleClientStatus handlers['decodeAddress'] = HandleDecodeAddress - handlers['deleteAndVacuum'] = HandleDeleteAndVacuum - handlers['shutdown'] = HandleShutdown def _handle_request(self, method, params): if (self.handlers.has_key(method)): - return self.handlers[method](self, params) + return self.handlers[method](self ,params) else: raise APIError(20, 'Invalid method: %s' % method) @@ -1066,5 +1031,3 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): except Exception as e: logger.exception(e) return "API Error 0021: Unexpected API Failure - %s" % str(e) - - diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py deleted file mode 100644 index d7f4e5a9..00000000 --- a/src/bitmessagecli.py +++ /dev/null @@ -1,1773 +0,0 @@ -#!/usr/bin/python2.7 -# -*- coding: utf-8 -*- -# Created by Adam Melton (.dok) referenceing https://bitmessage.org/wiki/API_Reference for API documentation -# Distributed under the MIT/X11 software license. See http://www.opensource.org/licenses/mit-license.php. - -# This is an example of a daemon client for PyBitmessage 0.6.2, by .dok (Version 0.3.1) , modified - - -import xmlrpclib -import datetime -#import hashlib -#import getopt -import imghdr -import ntpath -import json -import socket -import time -import sys -import os - -from bmconfigparser import BMConfigParser - -api = '' -keysName = 'keys.dat' -keysPath = 'keys.dat' -usrPrompt = 0 #0 = First Start, 1 = prompt, 2 = no prompt if the program is starting up -knownAddresses = dict() - -def userInput(message): #Checks input for exit or quit. Also formats for input, etc - global usrPrompt - print '\n' + message - uInput = raw_input('> ') - - if (uInput.lower() == 'exit'): #Returns the user to the main menu - usrPrompt = 1 - main() - - elif (uInput.lower() == 'quit'): #Quits the program - print '\n Bye\n' - sys.exit() - os._exit() # _ - else: - return uInput - -def restartBmNotify(): #Prompts the user to restart Bitmessage. - print '\n *******************************************************************' - print ' WARNING: If Bitmessage is running locally, you must restart it now.' - print ' *******************************************************************\n' - -#Begin keys.dat interactions -def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py - APPNAME = "PyBitmessage" - from os import path, environ - if sys.platform == 'darwin': - if "HOME" in environ: - dataFolder = path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/' - else: - print ' Could not find home folder, please report this message and your OS X version to the Daemon Github.' - os._exit() - - elif 'win32' in sys.platform or 'win64' in sys.platform: - dataFolder = path.join(environ['APPDATA'], APPNAME) + '\\' - else: - dataFolder = path.expanduser(path.join("~", ".config/" + APPNAME + "/")) - return dataFolder - -def configInit(): - BMConfigParser().add_section('bitmessagesettings') - BMConfigParser().set('bitmessagesettings', 'port', '8444') #Sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely. - BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat - - with open(keysName, 'wb') as configfile: - BMConfigParser().write(configfile) - - print '\n ' + str(keysName) + ' Initalized in the same directory as daemon.py' - print ' You will now need to configure the ' + str(keysName) + ' file.\n' - -def apiInit(apiEnabled): - global usrPrompt - BMConfigParser().read(keysPath) - - - - if (apiEnabled == False): #API information there but the api is disabled. - uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower() - - if uInput == "y": # - BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat - with open(keysPath, 'wb') as configfile: - BMConfigParser().write(configfile) - - print 'Done' - restartBmNotify() - return True - - elif uInput == "n": - print ' \n************************************************************' - print ' Daemon will not work when the API is disabled. ' - print ' Please refer to the Bitmessage Wiki on how to setup the API.' - print ' ************************************************************\n' - usrPrompt = 1 - main() - - else: - print '\n Invalid Entry\n' - usrPrompt = 1 - main() - elif (apiEnabled == True): #API correctly setup - #Everything is as it should be - return True - - else: #API information was not present. - print '\n ' + str(keysPath) + ' not properly configured!\n' - uInput = userInput("Would you like to do this now, (Y)es or (N)o?").lower() - - if uInput == "y": #User said yes, initalize the api by writing these values to the keys.dat file - print ' ' - - apiUsr = userInput("API Username") - apiPwd = userInput("API Password") - #apiInterface = userInput("API Interface. (127.0.0.1)") - apiPort = userInput("API Port") - apiEnabled = userInput("API Enabled? (True) or (False)").lower() - daemon = userInput("Daemon mode Enabled? (True) or (False)").lower() - - if (daemon != 'true' and daemon != 'false'): - print '\n Invalid Entry for Daemon.\n' - uInput = 1 - main() - - print ' -----------------------------------\n' - - BMConfigParser().set('bitmessagesettings', 'port', '8444') #sets the bitmessage port to stop the warning about the api not properly being setup. This is in the event that the keys.dat is in a different directory or is created locally to connect to a machine remotely. - BMConfigParser().set('bitmessagesettings','apienabled','true') - BMConfigParser().set('bitmessagesettings', 'apiport', apiPort) - BMConfigParser().set('bitmessagesettings', 'apiinterface', '127.0.0.1') - BMConfigParser().set('bitmessagesettings', 'apiusername', apiUsr) - BMConfigParser().set('bitmessagesettings', 'apipassword', apiPwd) - BMConfigParser().set('bitmessagesettings', 'daemon', daemon) - with open(keysPath, 'wb') as configfile: - BMConfigParser().write(configfile) - - print '\n Finished configuring the keys.dat file with API information.\n' - restartBmNotify() - return True - - elif uInput == "n": - print '\n ***********************************************************' - print ' Please refer to the Bitmessage Wiki on how to setup the API.' - print ' ***********************************************************\n' - usrPrompt = 1 - main() - else: - print ' \nInvalid entry\n' - usrPrompt = 1 - main() - - -def apiData(): - global keysName - global keysPath - global usrPrompt - - BMConfigParser().read(keysPath) #First try to load the config file (the keys.dat file) from the program directory - - try: - BMConfigParser().get('bitmessagesettings','port') - appDataFolder = '' - except: - #Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. - appDataFolder = lookupAppdataFolder() - keysPath = appDataFolder + keysPath - BMConfigParser().read(keysPath) - - try: - BMConfigParser().get('bitmessagesettings','port') - except: - #keys.dat was not there either, something is wrong. - print '\n ******************************************************************' - print ' There was a problem trying to access the Bitmessage keys.dat file' - print ' or keys.dat is not set up correctly' - print ' Make sure that daemon is in the same directory as Bitmessage. ' - print ' ******************************************************************\n' - - uInput = userInput("Would you like to create a keys.dat in the local directory, (Y)es or (N)o?").lower() - - if (uInput == "y" or uInput == "yes"): - configInit() - keysPath = keysName - usrPrompt = 0 - main() - elif (uInput == "n" or uInput == "no"): - print '\n Trying Again.\n' - usrPrompt = 0 - main() - else: - print '\n Invalid Input.\n' - - usrPrompt = 1 - main() - - try: #checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after - BMConfigParser().get('bitmessagesettings', 'apiport') - BMConfigParser().get('bitmessagesettings', 'apiinterface') - BMConfigParser().get('bitmessagesettings', 'apiusername') - BMConfigParser().get('bitmessagesettings', 'apipassword') - except: - apiInit("") #Initalize the keys.dat file with API information - - #keys.dat file was found or appropriately configured, allow information retrieval - #apiEnabled = apiInit(BMConfigParser().safeGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true - - BMConfigParser().read(keysPath)#read again since changes have been made - apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport')) - apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface') - apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername') - apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword') - - print '\n API data successfully imported.\n' - - return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface+ ":" + str(apiPort) + "/" #Build the api credentials - -#End keys.dat interactions - - -def apiTest(): #Tests the API connection to bitmessage. Returns true if it is connected. - - try: - result = api.add(2,3) - except: - return False - - if (result == 5): - return True - else: - return False - -def bmSettings(): #Allows the viewing and modification of keys.dat settings. - global keysPath - global usrPrompt - keysPath = 'keys.dat' - - BMConfigParser().read(keysPath)#Read the keys.dat - try: - port = BMConfigParser().get('bitmessagesettings', 'port') - except: - print '\n File not found.\n' - usrPrompt = 0 - main() - - startonlogon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startonlogon') - minimizetotray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'minimizetotray') - showtraynotifications = BMConfigParser().safeGetBoolean('bitmessagesettings', 'showtraynotifications') - startintray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startintray') - defaultnoncetrialsperbyte = BMConfigParser().get('bitmessagesettings', 'defaultnoncetrialsperbyte') - defaultpayloadlengthextrabytes = BMConfigParser().get('bitmessagesettings', 'defaultpayloadlengthextrabytes') - daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') - - socksproxytype = BMConfigParser().get('bitmessagesettings', 'socksproxytype') - sockshostname = BMConfigParser().get('bitmessagesettings', 'sockshostname') - socksport = BMConfigParser().get('bitmessagesettings', 'socksport') - socksauthentication = BMConfigParser().safeGetBoolean('bitmessagesettings', 'socksauthentication') - socksusername = BMConfigParser().get('bitmessagesettings', 'socksusername') - sockspassword = BMConfigParser().get('bitmessagesettings', 'sockspassword') - - - print '\n -----------------------------------' - print ' | Current Bitmessage Settings |' - print ' -----------------------------------' - print ' port = ' + port - print ' startonlogon = ' + str(startonlogon) - print ' minimizetotray = ' + str(minimizetotray) - print ' showtraynotifications = ' + str(showtraynotifications) - print ' startintray = ' + str(startintray) - print ' defaultnoncetrialsperbyte = ' + defaultnoncetrialsperbyte - print ' defaultpayloadlengthextrabytes = ' + defaultpayloadlengthextrabytes - print ' daemon = ' + str(daemon) - print '\n ------------------------------------' - print ' | Current Connection Settings |' - print ' -----------------------------------' - print ' socksproxytype = ' + socksproxytype - print ' sockshostname = ' + sockshostname - print ' socksport = ' + socksport - print ' socksauthentication = ' + str(socksauthentication) - print ' socksusername = ' + socksusername - print ' sockspassword = ' + sockspassword - print ' ' - - uInput = userInput("Would you like to modify any of these settings, (Y)es or (N)o?").lower() - - if uInput == "y": - while True: #loops if they mistype the setting name, they can exit the loop with 'exit' - invalidInput = False - uInput = userInput("What setting would you like to modify?").lower() - print ' ' - - if uInput == "port": - print ' Current port number: ' + port - uInput = userInput("Enter the new port number.") - BMConfigParser().set('bitmessagesettings', 'port', str(uInput)) - elif uInput == "startonlogon": - print ' Current status: ' + str(startonlogon) - uInput = userInput("Enter the new status.") - BMConfigParser().set('bitmessagesettings', 'startonlogon', str(uInput)) - elif uInput == "minimizetotray": - print ' Current status: ' + str(minimizetotray) - uInput = userInput("Enter the new status.") - BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(uInput)) - elif uInput == "showtraynotifications": - print ' Current status: ' + str(showtraynotifications) - uInput = userInput("Enter the new status.") - BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(uInput)) - elif uInput == "startintray": - print ' Current status: ' + str(startintray) - uInput = userInput("Enter the new status.") - BMConfigParser().set('bitmessagesettings', 'startintray', str(uInput)) - elif uInput == "defaultnoncetrialsperbyte": - print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte - uInput = userInput("Enter the new defaultnoncetrialsperbyte.") - BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) - elif uInput == "defaultpayloadlengthextrabytes": - print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes - uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") - BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) - elif uInput == "daemon": - print ' Current status: ' + str(daemon) - uInput = userInput("Enter the new status.").lower() - BMConfigParser().set('bitmessagesettings', 'daemon', str(uInput)) - elif uInput == "socksproxytype": - print ' Current socks proxy type: ' + socksproxytype - print "Possibilities: 'none', 'SOCKS4a', 'SOCKS5'." - uInput = userInput("Enter the new socksproxytype.") - BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(uInput)) - elif uInput == "sockshostname": - print ' Current socks host name: ' + sockshostname - uInput = userInput("Enter the new sockshostname.") - BMConfigParser().set('bitmessagesettings', 'sockshostname', str(uInput)) - elif uInput == "socksport": - print ' Current socks port number: ' + socksport - uInput = userInput("Enter the new socksport.") - BMConfigParser().set('bitmessagesettings', 'socksport', str(uInput)) - elif uInput == "socksauthentication": - print ' Current status: ' + str(socksauthentication) - uInput = userInput("Enter the new status.") - BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(uInput)) - elif uInput == "socksusername": - print ' Current socks username: ' + socksusername - uInput = userInput("Enter the new socksusername.") - BMConfigParser().set('bitmessagesettings', 'socksusername', str(uInput)) - elif uInput == "sockspassword": - print ' Current socks password: ' + sockspassword - uInput = userInput("Enter the new password.") - BMConfigParser().set('bitmessagesettings', 'sockspassword', str(uInput)) - else: - print "\n Invalid input. Please try again.\n" - invalidInput = True - - if invalidInput != True: #don't prompt if they made a mistake. - uInput = userInput("Would you like to change another setting, (Y)es or (N)o?").lower() - - if uInput != "y": - print '\n Changes Made.\n' - with open(keysPath, 'wb') as configfile: - BMConfigParser().write(configfile) - restartBmNotify() - break - - - elif uInput == "n": - usrPrompt = 1 - main() - else: - print "Invalid input." - usrPrompt = 1 - main() - -def validAddress(address): - address_information = api.decodeAddress(address) - address_information = eval(address_information) - - if 'success' in str(address_information.get('status')).lower(): - return True - else: - return False - -def getAddress(passphrase,vNumber,sNumber): - passphrase = passphrase.encode('base64')#passphrase must be encoded - - return api.getDeterministicAddress(passphrase,vNumber,sNumber) - -def subscribe(): - global usrPrompt - - while True: - address = userInput("What address would you like to subscribe to?") - - if (address == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(address)== False): - print '\n Invalid. "c" to cancel. Please try again.\n' - else: - break - - label = userInput("Enter a label for this address.") - label = label.encode('base64') - - api.addSubscription(address,label) - print ('\n You are now subscribed to: ' + address + '\n') - -def unsubscribe(): - global usrPrompt - - while True: - address = userInput("What address would you like to unsubscribe from?") - - if (address == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(address)== False): - print '\n Invalid. "c" to cancel. Please try again.\n' - else: - break - - - userInput("Are you sure, (Y)es or (N)o?").lower() # #uInput = - - api.deleteSubscription(address) - print ('\n You are now unsubscribed from: ' + address + '\n') - -def listSubscriptions(): - global usrPrompt - #jsonAddresses = json.loads(api.listSubscriptions()) - #numAddresses = len(jsonAddresses['addresses']) #Number of addresses - print '\nLabel, Address, Enabled\n' - try: - print api.listSubscriptions() - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - '''for addNum in range (0, numAddresses): #processes all of the addresses and lists them out - label = jsonAddresses['addresses'][addNum]['label'] - address = jsonAddresses['addresses'][addNum]['address'] - enabled = jsonAddresses['addresses'][addNum]['enabled'] - - print label, address, enabled - ''' - print ' ' - -def createChan(): - global usrPrompt - password = userInput("Enter channel name") - password = password.encode('base64') - try: - print api.createChan(password) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - -def joinChan(): - global usrPrompt - while True: - address = userInput("Enter channel address") - - if (address == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(address)== False): - print '\n Invalid. "c" to cancel. Please try again.\n' - else: - break - - password = userInput("Enter channel name") - password = password.encode('base64') - try: - print api.joinChan(password,address) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def leaveChan(): - global usrPrompt - while True: - address = userInput("Enter channel address") - - if (address == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(address)== False): - print '\n Invalid. "c" to cancel. Please try again.\n' - else: - break - - try: - print api.leaveChan(address) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - -def listAdd(): #Lists all of the addresses and their info - global usrPrompt - try: - jsonAddresses = json.loads(api.listAddresses()) - numAddresses = len(jsonAddresses['addresses']) #Number of addresses - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - #print '\nAddress Number,Label,Address,Stream,Enabled\n' - print '\n --------------------------------------------------------------------------' - print ' | # | Label | Address |S#|Enabled|' - print ' |---|-------------------|-------------------------------------|--|-------|' - for addNum in range (0, numAddresses): #processes all of the addresses and lists them out - label = (jsonAddresses['addresses'][addNum]['label' ]).encode('utf') # may still misdiplay in some consoles - address = str(jsonAddresses['addresses'][addNum]['address']) - stream = str(jsonAddresses['addresses'][addNum]['stream']) - enabled = str(jsonAddresses['addresses'][addNum]['enabled']) - - if (len(label) > 19): - label = label[:16] + '...' - - print ' |' + str(addNum).ljust(3) + '|' + label.ljust(19) + '|' + address.ljust(37) + '|' + stream.ljust(1), '|' + enabled.ljust(7) + '|' - - print ' --------------------------------------------------------------------------\n' - -def genAdd(lbl,deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe): #Generate address - global usrPrompt - if deterministic == False: #Generates a new address with the user defined label. non-deterministic - addressLabel = lbl.encode('base64') - try: - generatedAddress = api.createRandomAddress(addressLabel) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - return generatedAddress - - elif deterministic == True: #Generates a new deterministic address with the user inputs. - passphrase = passphrase.encode('base64') - try: - generatedAddress = api.createDeterministicAddresses(passphrase, numOfAdd, addVNum, streamNum, ripe) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - return generatedAddress - else: - return 'Entry Error' - -def delMilAddr(): #Generate address - global usrPrompt - try: - response = api.listAddresses2() - # if api is too old just return then fail - if "API Error 0020" in response: return - addresses = json.loads(response) - for entry in addresses['addresses']: - if entry['label'].decode('base64')[:6] == "random": - api.deleteAddress(entry['address']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def genMilAddr(): #Generate address - global usrPrompt - maxn = 0 - try: - response = api.listAddresses2() - if "API Error 0020" in response: return - addresses = json.loads(response) - for entry in addresses['addresses']: - if entry['label'].decode('base64')[:6] == "random": - newn = int(entry['label'].decode('base64')[6:]) - if maxn < newn: - maxn = newn - except: - print "\n Some error\n" - print "\n Starting at " + str(maxn) + "\n" - for i in range(maxn, 10000): - lbl = "random" + str(i) - addressLabel = lbl.encode('base64') - try: - api.createRandomAddress(addressLabel) # generatedAddress = - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def saveFile(fileName, fileData): #Allows attachments and messages/broadcats to be saved - - #This section finds all invalid characters and replaces them with ~ - fileName = fileName.replace(" ", "") - fileName = fileName.replace("/", "~") - #fileName = fileName.replace("\\", "~") How do I get this to work...? - fileName = fileName.replace(":", "~") - fileName = fileName.replace("*", "~") - fileName = fileName.replace("?", "~") - fileName = fileName.replace('"', "~") - fileName = fileName.replace("<", "~") - fileName = fileName.replace(">", "~") - fileName = fileName.replace("|", "~") - - directory = 'attachments' - - if not os.path.exists(directory): - os.makedirs(directory) - - filePath = directory +'/'+ fileName - - '''try: #Checks if file already exists - with open(filePath): - print 'File Already Exists' - return - except IOError: pass''' - - - f = open(filePath, 'wb+') #Begin saving to file - f.write(fileData.decode("base64")) - f.close - - print '\n Successfully saved '+ filePath + '\n' - -def attachment(): #Allows users to attach a file to their message or broadcast - theAttachmentS = '' - - while True: - - isImage = False - theAttachment = '' - - while True:#loops until valid path is entered - filePath = userInput('\nPlease enter the path to the attachment or just the attachment name if in this folder.') - - try: - with open(filePath): break - except IOError: - print '\n %s was not found on your filesystem or can not be opened.\n' % filePath - pass - - #print filesize, and encoding estimate with confirmation if file is over X size (1mb?) - invSize = os.path.getsize(filePath) - invSize = (invSize / 1024) #Converts to kilobytes - round(invSize,2) #Rounds to two decimal places - - if (invSize > 500.0):#If over 500KB - print '\n WARNING:The file that you are trying to attach is ', invSize, 'KB and will take considerable time to send.\n' - uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower() - - if uInput != "y": - print '\n Attachment discarded.\n' - return '' - elif (invSize > 184320.0): #If larger than 180MB, discard. - print '\n Attachment too big, maximum allowed size:180MB\n' - main() - - pathLen = len(str(ntpath.basename(filePath))) #Gets the length of the filepath excluding the filename - fileName = filePath[(len(str(filePath)) - pathLen):] #reads the filename - - filetype = imghdr.what(filePath) #Tests if it is an image file - if filetype is not None: - print '\n ---------------------------------------------------' - print ' Attachment detected as an Image.' - print ' tags will automatically be included,' - print ' allowing the recipient to view the image' - print ' using the "View HTML code..." option in Bitmessage.' - print ' ---------------------------------------------------\n' - isImage = True - time.sleep(2) - - print '\n Encoding Attachment, Please Wait ...\n' #Alert the user that the encoding process may take some time. - - with open(filePath, 'rb') as f: #Begin the actual encoding - data = f.read(188743680) #Reads files up to 180MB, the maximum size for Bitmessage. - data = data.encode("base64") - - if (isImage == True): #If it is an image, include image tags in the message - theAttachment = """ - - - -Filename:%s -Filesize:%sKB -Encoding:base64 - -
-
- %s -
-
""" % (fileName,invSize,fileName,filetype,data) - else: #Else it is not an image so do not include the embedded image code. - theAttachment = """ - - - -Filename:%s -Filesize:%sKB -Encoding:base64 - -""" % (fileName,invSize,fileName,fileName,data) - - uInput = userInput('Would you like to add another attachment, (Y)es or (N)o?').lower() - - if (uInput == 'y' or uInput == 'yes'):#Allows multiple attachments to be added to one message - theAttachmentS = str(theAttachmentS) + str(theAttachment)+ '\n\n' - elif (uInput == 'n' or uInput == 'no'): - break - - theAttachmentS = theAttachmentS + theAttachment - return theAttachmentS - -def sendMsg(toAddress, fromAddress, subject, message): #With no arguments sent, sendMsg fills in the blanks. subject and message must be encoded before they are passed. - global usrPrompt - if (validAddress(toAddress)== False): - while True: - toAddress = userInput("What is the To Address?") - - if (toAddress == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(toAddress)== False): - print '\n Invalid Address. "c" to cancel. Please try again.\n' - else: - break - - - if (validAddress(fromAddress)== False): - try: - jsonAddresses = json.loads(api.listAddresses()) - numAddresses = len(jsonAddresses['addresses']) #Number of addresses - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - if (numAddresses > 1): #Ask what address to send from if multiple addresses - found = False - while True: - print ' ' - fromAddress = userInput("Enter an Address or Address Label to send from.") - - if fromAddress == "exit": - usrPrompt = 1 - main() - - for addNum in range (0, numAddresses): #processes all of the addresses - label = jsonAddresses['addresses'][addNum]['label'] - address = jsonAddresses['addresses'][addNum]['address'] - #stream = jsonAddresses['addresses'][addNum]['stream'] - #enabled = jsonAddresses['addresses'][addNum]['enabled'] - if (fromAddress == label): #address entered was a label and is found - fromAddress = address - found = True - break - - if (found == False): - if(validAddress(fromAddress)== False): - print '\n Invalid Address. Please try again.\n' - - else: - for addNum in range (0, numAddresses): #processes all of the addresses - #label = jsonAddresses['addresses'][addNum]['label'] - address = jsonAddresses['addresses'][addNum]['address'] - #stream = jsonAddresses['addresses'][addNum]['stream'] - #enabled = jsonAddresses['addresses'][addNum]['enabled'] - if (fromAddress == address): #address entered was a found in our addressbook. - found = True - break - - if (found == False): - print '\n The address entered is not one of yours. Please try again.\n' - - if (found == True): - break #Address was found - - else: #Only one address in address book - print '\n Using the only address in the addressbook to send from.\n' - fromAddress = jsonAddresses['addresses'][0]['address'] - - if (subject == ''): - subject = userInput("Enter your Subject.") - subject = subject.encode('base64') - if (message == ''): - message = userInput("Enter your Message.") - - uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() - if uInput == "y": - message = message + '\n\n' + attachment() - - message = message.encode('base64') - - try: - ackData = api.sendMessage(toAddress, fromAddress, subject, message) - print '\n Message Status:', api.getStatus(ackData), '\n' - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - -def sendBrd(fromAddress, subject, message): #sends a broadcast - global usrPrompt - if (fromAddress == ''): - - try: - jsonAddresses = json.loads(api.listAddresses()) - numAddresses = len(jsonAddresses['addresses']) #Number of addresses - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - if (numAddresses > 1): #Ask what address to send from if multiple addresses - found = False - while True: - fromAddress = userInput("\nEnter an Address or Address Label to send from.") - - if fromAddress == "exit": - usrPrompt = 1 - main() - - for addNum in range (0, numAddresses): #processes all of the addresses - label = jsonAddresses['addresses'][addNum]['label'] - address = jsonAddresses['addresses'][addNum]['address'] - #stream = jsonAddresses['addresses'][addNum]['stream'] - #enabled = jsonAddresses['addresses'][addNum]['enabled'] - if (fromAddress == label): #address entered was a label and is found - fromAddress = address - found = True - break - - if (found == False): - if(validAddress(fromAddress)== False): - print '\n Invalid Address. Please try again.\n' - - else: - for addNum in range (0, numAddresses): #processes all of the addresses - #label = jsonAddresses['addresses'][addNum]['label'] - address = jsonAddresses['addresses'][addNum]['address'] - #stream = jsonAddresses['addresses'][addNum]['stream'] - #enabled = jsonAddresses['addresses'][addNum]['enabled'] - if (fromAddress == address): #address entered was a found in our addressbook. - found = True - break - - if (found == False): - print '\n The address entered is not one of yours. Please try again.\n' - - if (found == True): - break #Address was found - - else: #Only one address in address book - print '\n Using the only address in the addressbook to send from.\n' - fromAddress = jsonAddresses['addresses'][0]['address'] - - if (subject == ''): - subject = userInput("Enter your Subject.") - subject = subject.encode('base64') - if (message == ''): - message = userInput("Enter your Message.") - - uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() - if uInput == "y": - message = message + '\n\n' + attachment() - - message = message.encode('base64') - - try: - ackData = api.sendBroadcast(fromAddress, subject, message) - print '\n Message Status:', api.getStatus(ackData), '\n' - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def inbox(unreadOnly = False): #Lists the messages by: Message Number, To Address Label, From Address Label, Subject, Received Time) - global usrPrompt - try: - inboxMessages = json.loads(api.getAllInboxMessages()) - numMessages = len(inboxMessages['inboxMessages']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - messagesPrinted = 0 - messagesUnread = 0 - for msgNum in range (0, numMessages): #processes all of the messages in the inbox - message = inboxMessages['inboxMessages'][msgNum] - # if we are displaying all messages or if this message is unread then display it - if not unreadOnly or not message['read']: - print ' -----------------------------------\n' - print ' Message Number:',msgNum #Message Number - print ' To:', getLabelForAddress(message['toAddress']) #Get the to address - print ' From:', getLabelForAddress(message['fromAddress']) #Get the from address - print ' Subject:', message['subject'].decode('base64') #Get the subject - print ' Received:', datetime.datetime.fromtimestamp(float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S') - messagesPrinted += 1 - if not message['read']: messagesUnread += 1 - - if (messagesPrinted%20 == 0 and messagesPrinted != 0): - userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = - - print '\n -----------------------------------' - print ' There are %d unread messages of %d messages in the inbox.' % (messagesUnread, numMessages) - print ' -----------------------------------\n' - -def outbox(): - global usrPrompt - try: - outboxMessages = json.loads(api.getAllSentMessages()) - numMessages = len(outboxMessages['sentMessages']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - for msgNum in range (0, numMessages): #processes all of the messages in the outbox - print '\n -----------------------------------\n' - print ' Message Number:',msgNum #Message Number - #print ' Message ID:', outboxMessages['sentMessages'][msgNum]['msgid'] - print ' To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress']) #Get the to address - print ' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress']) #Get the from address - print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') #Get the subject - print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] #Get the subject - - print ' Last Action Time:', datetime.datetime.fromtimestamp(float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S') - - if (msgNum%20 == 0 and msgNum != 0): - userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = - - print '\n -----------------------------------' - print ' There are ',numMessages,' messages in the outbox.' - print ' -----------------------------------\n' - -def readSentMsg(msgNum): #Opens a sent message for reading - global usrPrompt - try: - outboxMessages = json.loads(api.getAllSentMessages()) - numMessages = len(outboxMessages['sentMessages']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - print ' ' - - if (msgNum >= numMessages): - print '\n Invalid Message Number.\n' - main() - - #Begin attachment detection - message = outboxMessages['sentMessages'][msgNum]['message'].decode('base64') - - while True: #Allows multiple messages to be downloaded/saved - if (';base64,' in message): #Found this text in the message, there is probably an attachment. - attPos= message.index(";base64,") #Finds the attachment position - attEndPos = message.index("' />") #Finds the end of the attachment - #attLen = attEndPos - attPos #Finds the length of the message - - - if ('alt = "' in message): #We can get the filename too - fnPos = message.index('alt = "') #Finds position of the filename - fnEndPos = message.index('" src=') #Finds the end position - #fnLen = fnEndPos - fnPos #Finds the length of the filename - - fileName = message[fnPos+7:fnEndPos] - else: - fnPos = attPos - fileName = 'Attachment' - - uInput = userInput('\n Attachment Detected. Would you like to save the attachment, (Y)es or (N)o?').lower() - if (uInput == "y" or uInput == 'yes'): - - attachment = message[attPos+9:attEndPos] - saveFile(fileName,attachment) - - message = message[:fnPos] + '~~' + message[(attEndPos+4):] - - else: - break - - #End attachment Detection - - print '\n To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress']) #Get the to address - print ' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress']) #Get the from address - print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') #Get the subject - print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] #Get the subject - print ' Last Action Time:', datetime.datetime.fromtimestamp(float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S') - print ' Message:\n' - print message #inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') - print ' ' - -def readMsg(msgNum): #Opens a message for reading - global usrPrompt - try: - inboxMessages = json.loads(api.getAllInboxMessages()) - numMessages = len(inboxMessages['inboxMessages']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - if (msgNum >= numMessages): - print '\n Invalid Message Number.\n' - main() - - #Begin attachment detection - message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') - - while True: #Allows multiple messages to be downloaded/saved - if (';base64,' in message): #Found this text in the message, there is probably an attachment. - attPos= message.index(";base64,") #Finds the attachment position - attEndPos = message.index("' />") #Finds the end of the attachment - #attLen = attEndPos - attPos #Finds the length of the message - - - if ('alt = "' in message): #We can get the filename too - fnPos = message.index('alt = "') #Finds position of the filename - fnEndPos = message.index('" src=') #Finds the end position - #fnLen = fnEndPos - fnPos #Finds the length of the filename - - fileName = message[fnPos+7:fnEndPos] - else: - fnPos = attPos - fileName = 'Attachment' - - uInput = userInput('\n Attachment Detected. Would you like to save the attachment, (Y)es or (N)o?').lower() - if (uInput == "y" or uInput == 'yes'): - - attachment = message[attPos+9:attEndPos] - saveFile(fileName,attachment) - - message = message[:fnPos] + '~~' + message[(attEndPos+4):] - - else: - break - - #End attachment Detection - print '\n To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress']) #Get the to address - print ' From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress']) #Get the from address - print ' Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') #Get the subject - print ' Received:',datetime.datetime.fromtimestamp(float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S') - print ' Message:\n' - print message #inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') - print ' ' - return inboxMessages['inboxMessages'][msgNum]['msgid'] - -def replyMsg(msgNum,forwardORreply): #Allows you to reply to the message you are currently on. Saves typing in the addresses and subject. - global usrPrompt - forwardORreply = forwardORreply.lower() #makes it lowercase - try: - inboxMessages = json.loads(api.getAllInboxMessages()) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - fromAdd = inboxMessages['inboxMessages'][msgNum]['toAddress']#Address it was sent To, now the From address - message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') #Message that you are replying too. - - subject = inboxMessages['inboxMessages'][msgNum]['subject'] - subject = subject.decode('base64') - - if (forwardORreply == 'reply'): - toAdd = inboxMessages['inboxMessages'][msgNum]['fromAddress'] #Address it was From, now the To address - subject = "Re: " + subject - - elif (forwardORreply == 'forward'): - subject = "Fwd: " + subject - - while True: - toAdd = userInput("What is the To Address?") - - if (toAdd == "c"): - usrPrompt = 1 - print ' ' - main() - elif (validAddress(toAdd)== False): - print '\n Invalid Address. "c" to cancel. Please try again.\n' - else: - break - else: - print '\n Invalid Selection. Reply or Forward only' - usrPrompt = 0 - main() - - subject = subject.encode('base64') - - newMessage = userInput("Enter your Message.") - - uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() - if uInput == "y": - newMessage = newMessage + '\n\n' + attachment() - - newMessage = newMessage + '\n\n------------------------------------------------------\n' - newMessage = newMessage + message - newMessage = newMessage.encode('base64') - - sendMsg(toAdd, fromAdd, subject, newMessage) - - main() - -def delMsg(msgNum): #Deletes a specified message from the inbox - global usrPrompt - try: - inboxMessages = json.loads(api.getAllInboxMessages()) - msgId = inboxMessages['inboxMessages'][int(msgNum)]['msgid'] #gets the message ID via the message index number - - msgAck = api.trashMessage(msgId) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - return msgAck - -def delSentMsg(msgNum): #Deletes a specified message from the outbox - global usrPrompt - try: - outboxMessages = json.loads(api.getAllSentMessages()) - msgId = outboxMessages['sentMessages'][int(msgNum)]['msgid'] #gets the message ID via the message index number - msgAck = api.trashSentMessage(msgId) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - return msgAck - -def getLabelForAddress(address): - if address in knownAddresses: - return knownAddresses[address] - else: - buildKnownAddresses() - if address in knownAddresses: - return knownAddresses[address] - - return address - -def buildKnownAddresses(): - # add from address book - try: - response = api.listAddressBookEntries() - # if api is too old then fail - if "API Error 0020" in response: return - addressBook = json.loads(response) - for entry in addressBook['addresses']: - if entry['address'] not in knownAddresses: - knownAddresses[entry['address']] = "%s (%s)" % (entry['label'].decode('base64'), entry['address']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - - # add from my addresses - try: - response = api.listAddresses2() - # if api is too old just return then fail - if "API Error 0020" in response: return - addresses = json.loads(response) - for entry in addresses['addresses']: - if entry['address'] not in knownAddresses: - knownAddresses[entry['address']] = "%s (%s)" % (entry['label'].decode('base64'), entry['address']) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def listAddressBookEntries(): - try: - response = api.listAddressBookEntries() - if "API Error" in response: - return getAPIErrorCode(response) - addressBook = json.loads(response) - print - print ' --------------------------------------------------------------' - print ' | Label | Address |' - print ' |--------------------|---------------------------------------|' - for entry in addressBook['addresses']: - label = entry['label'].decode('base64') - address = entry['address'] - if (len(label) > 19): label = label[:16] + '...' - print ' | ' + label.ljust(19) + '| ' + address.ljust(37) + ' |' - print ' --------------------------------------------------------------' - print - - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def addAddressToAddressBook(address, label): - try: - response = api.addAddressBookEntry(address, label.encode('base64')) - if "API Error" in response: - return getAPIErrorCode(response) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def deleteAddressFromAddressBook(address): - try: - response = api.deleteAddressBookEntry(address) - if "API Error" in response: - return getAPIErrorCode(response) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def getAPIErrorCode(response): - if "API Error" in response: - # if we got an API error return the number by getting the number - # after the second space and removing the trailing colon - return int(response.split()[2][:-1]) - -def markMessageRead(messageID): - try: - response = api.getInboxMessageByID(messageID, True) - if "API Error" in response: - return getAPIErrorCode(response) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def markMessageUnread(messageID): - try: - response = api.getInboxMessageByID(messageID, False) - if "API Error" in response: - return getAPIErrorCode(response) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - -def markAllMessagesRead(): - try: - inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - for message in inboxMessages: - if not message['read']: - markMessageRead(message['msgid']) - -def markAllMessagesUnread(): - try: - inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - for message in inboxMessages: - if message['read']: - markMessageUnread(message['msgid']) - -def clientStatus(): - try: - clientStatus = json.loads(api.clientStatus()) - except: - print '\n Connection Error\n' - usrPrompt = 0 - main() - print "\nnetworkStatus: " + clientStatus['networkStatus'] + "\n" - print "\nnetworkConnections: " + str(clientStatus['networkConnections']) + "\n" - print "\nnumberOfPubkeysProcessed: " + str(clientStatus['numberOfPubkeysProcessed']) + "\n" - print "\nnumberOfMessagesProcessed: " + str(clientStatus['numberOfMessagesProcessed']) + "\n" - print "\nnumberOfBroadcastsProcessed: " + str(clientStatus['numberOfBroadcastsProcessed']) + "\n" - -def shutdown(): - try: - api.shutdown() - except socket.error: - pass - print "\nShutdown command relayed\n" - - -def UI(usrInput): #Main user menu - global usrPrompt - - if usrInput == "help" or usrInput == "h" or usrInput == "?": - print ' ' - print ' -------------------------------------------------------------------------' - print ' | https://github.com/Dokument/PyBitmessage-Daemon |' - print ' |-----------------------------------------------------------------------|' - print ' | Command | Description |' - print ' |------------------------|----------------------------------------------|' - print ' | help | This help file. |' - print ' | apiTest | Tests the API |' - print ' | addInfo | Returns address information (If valid) |' - print ' | bmSettings | BitMessage settings |' - print ' | exit | Use anytime to return to main menu |' - print ' | quit | Quits the program |' - print ' |------------------------|----------------------------------------------|' - print ' | listAddresses | Lists all of the users addresses |' - print ' | generateAddress | Generates a new address |' - print ' | getAddress | Get determinist address from passphrase |' - print ' |------------------------|----------------------------------------------|' - print ' | listAddressBookEntries | Lists entries from the Address Book |' - print ' | addAddressBookEntry | Add address to the Address Book |' - print ' | deleteAddressBookEntry | Deletes address from the Address Book |' - print ' |------------------------|----------------------------------------------|' - print ' | subscribe | Subscribes to an address |' - print ' | unsubscribe | Unsubscribes from an address |' - #print' | listSubscriptions | Lists all of the subscriptions. |' - print ' |------------------------|----------------------------------------------|' - print ' | create | Creates a channel |' - print ' | join | Joins a channel |' - print ' | leave | Leaves a channel |' - print ' |------------------------|----------------------------------------------|' - print ' | inbox | Lists the message information for the inbox |' - print ' | outbox | Lists the message information for the outbox |' - print ' | send | Send a new message or broadcast |' - print ' | unread | Lists all unread inbox messages |' - print ' | read | Reads a message from the inbox or outbox |' - print ' | save | Saves message to text file |' - print ' | delete | Deletes a message or all messages |' - print ' -------------------------------------------------------------------------' - print ' ' - main() - - elif usrInput == "apitest": #tests the API Connection. - if (apiTest() == True): - print '\n API connection test has: PASSED\n' - else: - print '\n API connection test has: FAILED\n' - main() - - elif usrInput == "addinfo": - tmp_address = userInput('\nEnter the Bitmessage Address.') - address_information = api.decodeAddress(tmp_address) - address_information = eval(address_information) - - print '\n------------------------------' - - if 'success' in str(address_information.get('status')).lower(): - print ' Valid Address' - print ' Address Version: %s' % str(address_information.get('addressVersion')) - print ' Stream Number: %s' % str(address_information.get('streamNumber')) - else: - print ' Invalid Address !' - - print '------------------------------\n' - main() - - elif usrInput == "bmsettings": #tests the API Connection. - bmSettings() - print ' ' - main() - - elif usrInput == "quit": #Quits the application - print '\n Bye\n' - sys.exit() - os._exit() - - elif usrInput == "listaddresses": #Lists all of the identities in the addressbook - listAdd() - main() - - elif usrInput == "generateaddress": #Generates a new address - uInput = userInput('\nWould you like to create a (D)eterministic or (R)andom address?').lower() - - if uInput == "d" or uInput == "determinstic": #Creates a deterministic address - deterministic = True - - #lbl = raw_input('Label the new address:') #currently not possible via the api - lbl = '' - passphrase = userInput('Enter the Passphrase.')#.encode('base64') - numOfAdd = int(userInput('How many addresses would you like to generate?')) - #addVNum = int(raw_input('Address version number (default "0"):')) - #streamNum = int(raw_input('Stream number (default "0"):')) - addVNum = 3 - streamNum = 1 - isRipe = userInput('Shorten the address, (Y)es or (N)o?').lower() - - if isRipe == "y": - ripe = True - print genAdd(lbl,deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe) - main() - elif isRipe == "n": - ripe = False - print genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe) - main() - elif isRipe == "exit": - usrPrompt = 1 - main() - else: - print '\n Invalid input\n' - main() - - - elif uInput == "r" or uInput == "random": #Creates a random address with user-defined label - deterministic = False - null = '' - lbl = userInput('Enter the label for the new address.') - - print genAdd(lbl,deterministic, null,null, null, null, null) - main() - - else: - print '\n Invalid input\n' - main() - - elif usrInput == "getaddress": #Gets the address for/from a passphrase - phrase = userInput("Enter the address passphrase.") - print '\n Working...\n' - #vNumber = int(raw_input("Enter the address version number:")) - #sNumber = int(raw_input("Enter the address stream number:")) - - address = getAddress(phrase,4,1)#,vNumber,sNumber) - print ('\n Address: ' + address + '\n') - - usrPrompt = 1 - main() - - elif usrInput == "subscribe": #Subsribe to an address - subscribe() - usrPrompt = 1 - main() - elif usrInput == "unsubscribe": #Unsubscribe from an address - unsubscribe() - usrPrompt = 1 - main() - elif usrInput == "listsubscriptions": #Unsubscribe from an address - listSubscriptions() - usrPrompt = 1 - main() - - elif usrInput == "create": - createChan() - usrPrompt = 1 - main() - - elif usrInput == "join": - joinChan() - usrPrompt = 1 - main() - - elif usrInput == "leave": - leaveChan() - usrPrompt = 1 - main() - - elif usrInput == "inbox": - print '\n Loading...\n' - inbox() - main() - - elif usrInput == "unread": - print '\n Loading...\n' - inbox(True) - main() - - elif usrInput == "outbox": - print '\n Loading...\n' - outbox() - main() - - elif usrInput == 'send': #Sends a message or broadcast - uInput = userInput('Would you like to send a (M)essage or (B)roadcast?').lower() - - if (uInput == 'm' or uInput == 'message'): - null = '' - sendMsg(null,null,null,null) - main() - elif (uInput =='b' or uInput == 'broadcast'): - null = '' - sendBrd(null,null,null) - main() - - - elif usrInput == "read": #Opens a message from the inbox for viewing. - - uInput = userInput("Would you like to read a message from the (I)nbox or (O)utbox?").lower() - - if (uInput != 'i' and uInput != 'inbox' and uInput != 'o' and uInput != 'outbox'): - print '\n Invalid Input.\n' - usrPrompt = 1 - main() - - msgNum = int(userInput("What is the number of the message you wish to open?")) - - if (uInput == 'i' or uInput == 'inbox'): - print '\n Loading...\n' - messageID = readMsg(msgNum) - - uInput = userInput("\nWould you like to keep this message unread, (Y)es or (N)o?").lower() - - if not (uInput == 'y' or uInput == 'yes'): - markMessageRead(messageID) - usrPrompt = 1 - - uInput = userInput("\nWould you like to (D)elete, (F)orward, (R)eply to, or (Exit) this message?").lower() - - if (uInput == 'r' or uInput == 'reply'): - print '\n Loading...\n' - print ' ' - replyMsg(msgNum,'reply') - usrPrompt = 1 - - elif (uInput == 'f' or uInput == 'forward'): - print '\n Loading...\n' - print ' ' - replyMsg(msgNum,'forward') - usrPrompt = 1 - - elif (uInput == "d" or uInput == 'delete'): - uInput = userInput("Are you sure, (Y)es or (N)o?").lower()#Prevent accidental deletion - - if uInput == "y": - delMsg(msgNum) - print '\n Message Deleted.\n' - usrPrompt = 1 - else: - usrPrompt = 1 - else: - print '\n Invalid entry\n' - usrPrompt = 1 - - elif (uInput == 'o' or uInput == 'outbox'): - readSentMsg(msgNum) - - uInput = userInput("Would you like to (D)elete, or (Exit) this message?").lower() #Gives the user the option to delete the message - - if (uInput == "d" or uInput == 'delete'): - uInput = userInput('Are you sure, (Y)es or (N)o?').lower() #Prevent accidental deletion - - if uInput == "y": - delSentMsg(msgNum) - print '\n Message Deleted.\n' - usrPrompt = 1 - else: - usrPrompt = 1 - else: - print '\n Invalid Entry\n' - usrPrompt = 1 - - main() - - elif usrInput == "save": - - uInput = userInput("Would you like to save a message from the (I)nbox or (O)utbox?").lower() - - if (uInput != 'i' and uInput == 'inbox' and uInput != 'o' and uInput == 'outbox'): - print '\n Invalid Input.\n' - usrPrompt = 1 - main() - - if (uInput == 'i' or uInput == 'inbox'): - inboxMessages = json.loads(api.getAllInboxMessages()) - numMessages = len(inboxMessages['inboxMessages']) - - while True: - msgNum = int(userInput("What is the number of the message you wish to save?")) - - if (msgNum >= numMessages): - print '\n Invalid Message Number.\n' - else: - break - - subject = inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') - message = inboxMessages['inboxMessages'][msgNum]['message']#Don't decode since it is done in the saveFile function - - elif (uInput == 'o' or uInput == 'outbox'): - outboxMessages = json.loads(api.getAllSentMessages()) - numMessages = len(outboxMessages['sentMessages']) - - while True: - msgNum = int(userInput("What is the number of the message you wish to save?")) - - if (msgNum >= numMessages): - print '\n Invalid Message Number.\n' - else: - break - - subject = outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') - message = outboxMessages['sentMessages'][msgNum]['message']#Don't decode since it is done in the saveFile function - - subject = subject +'.txt' - saveFile(subject,message) - - usrPrompt = 1 - main() - - elif usrInput == "delete": #will delete a message from the system, not reflected on the UI. - - uInput = userInput("Would you like to delete a message from the (I)nbox or (O)utbox?").lower() - - if (uInput == 'i' or uInput == 'inbox'): - inboxMessages = json.loads(api.getAllInboxMessages()) - numMessages = len(inboxMessages['inboxMessages']) - - while True: - msgNum = userInput('Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() - - if (msgNum == 'a' or msgNum == 'all'): - break - elif (int(msgNum) >= numMessages): - print '\n Invalid Message Number.\n' - else: - break - - uInput = userInput("Are you sure, (Y)es or (N)o?").lower()#Prevent accidental deletion - - if uInput == "y": - if (msgNum == 'a' or msgNum == 'all'): - print ' ' - for msgNum in range (0, numMessages): #processes all of the messages in the inbox - print ' Deleting message ', msgNum+1, ' of ', numMessages - delMsg(0) - - print '\n Inbox is empty.' - usrPrompt = 1 - else: - delMsg(int(msgNum)) - - print '\n Notice: Message numbers may have changed.\n' - main() - else: - usrPrompt = 1 - elif (uInput == 'o' or uInput == 'outbox'): - outboxMessages = json.loads(api.getAllSentMessages()) - numMessages = len(outboxMessages['sentMessages']) - - while True: - msgNum = userInput('Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() - - if (msgNum == 'a' or msgNum == 'all'): - break - elif (int(msgNum) >= numMessages): - print '\n Invalid Message Number.\n' - else: - break - - uInput = userInput("Are you sure, (Y)es or (N)o?").lower()#Prevent accidental deletion - - if uInput == "y": - if (msgNum == 'a' or msgNum == 'all'): - print ' ' - for msgNum in range (0, numMessages): #processes all of the messages in the outbox - print ' Deleting message ', msgNum+1, ' of ', numMessages - delSentMsg(0) - - print '\n Outbox is empty.' - usrPrompt = 1 - else: - delSentMsg(int(msgNum)) - print '\n Notice: Message numbers may have changed.\n' - main() - else: - usrPrompt = 1 - else: - print '\n Invalid Entry.\n' - usrPrompt = 1 - main() - - elif usrInput == "exit": - print '\n You are already at the main menu. Use "quit" to quit.\n' - usrPrompt = 1 - main() - - elif usrInput == "listaddressbookentries": - res = listAddressBookEntries() - if res == 20: print '\n Error: API function not supported.\n' - usrPrompt = 1 - main() - - elif usrInput == "addaddressbookentry": - address = userInput('Enter address') - label = userInput('Enter label') - res = addAddressToAddressBook(address, label) - if res == 16: print '\n Error: Address already exists in Address Book.\n' - if res == 20: print '\n Error: API function not supported.\n' - usrPrompt = 1 - main() - - elif usrInput == "deleteaddressbookentry": - address = userInput('Enter address') - res = deleteAddressFromAddressBook(address) - if res == 20: print '\n Error: API function not supported.\n' - usrPrompt = 1 - main() - - elif usrInput == "markallmessagesread": - markAllMessagesRead() - usrPrompt = 1 - main() - - elif usrInput == "markallmessagesunread": - markAllMessagesUnread() - usrPrompt = 1 - main() - - elif usrInput == "status": - clientStatus() - usrPrompt = 1 - main() - - elif usrInput == "shutdown": - shutdown() - usrPrompt = 1 - main() - - elif usrInput == "million+": - genMilAddr() - usrPrompt = 1 - main() - - elif usrInput == "million-": - delMilAddr() - usrPrompt = 1 - main() - - else: - print '\n "',usrInput,'" is not a command.\n' - usrPrompt = 1 - main() - -def main(): - global api - global usrPrompt - - if (usrPrompt == 0): - print '\n ------------------------------' - print ' | Bitmessage Daemon by .dok |' - print ' | Version 0.3.1 for BM 0.6.2 |' - print ' ------------------------------' - api = xmlrpclib.ServerProxy(apiData()) #Connect to BitMessage using these api credentials - - if (apiTest() == False): - print '\n ****************************************************************' - print ' WARNING: You are not connected to the Bitmessage client.' - print ' Either Bitmessage is not running or your settings are incorrect.' - print ' Use the command "apiTest" or "bmSettings" to resolve this issue.' - print ' ****************************************************************\n' - - print 'Type (H)elp for a list of commands.' #Startup message - usrPrompt = 2 - - #if (apiTest() == False):#Preform a connection test #taken out until I get the error handler working - # print '*************************************' - # print 'WARNING: No connection to Bitmessage.' - # print '*************************************' - # print ' ' - elif (usrPrompt == 1): - print '\nType (H)elp for a list of commands.' #Startup message - usrPrompt = 2 - - try: - UI((raw_input('>').lower()).replace(" ", "")) - except EOFError: - UI("quit") - -if __name__ == "__main__": - main() diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index fc1d74b2..77d09729 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -20,17 +20,12 @@ import curses import dialog from dialog import Dialog from helper_sql import * -from helper_ackPayload import genAckPayload -from addresses import * -import ConfigParser -from bmconfigparser import BMConfigParser -from inventory import Inventory -import l10n -from pyelliptic.openssl import OpenSSL -import queues import shared -import shutdown +import ConfigParser +from addresses import * +from pyelliptic.openssl import OpenSSL +import l10n quit = False menutab = 1 @@ -99,22 +94,10 @@ def drawmenu(stdscr): menustr += " " stdscr.addstr(2, 5, menustr, curses.A_UNDERLINE) -def set_background_title(d, title): - try: - d.set_background_title(title) - except: - d.add_persistent_args(("--backtitle", title)) - -def scrollbox(d, text, height=None, width=None): - try: - d.scrollbox(text, height, width, exit_label = "Continue") - except: - d.msgbox(text, height or 0, width or 0, ok_label = "Continue") - def resetlookups(): global inventorydata - inventorydata = Inventory().numberOfInventoryLookupsPerformed - Inventory().numberOfInventoryLookupsPerformed = 0 + inventorydata = shared.numberOfInventoryLookupsPerformed + shared.numberOfInventoryLookupsPerformed = 0 Timer(1, resetlookups, ()).start() def drawtab(stdscr): if menutab in range(1, len(menu)+1): @@ -277,7 +260,7 @@ def handlech(c, stdscr): curses.curs_set(1) d = Dialog(dialog="dialog") if menutab == 1: - set_background_title(d, "Inbox Message Dialog Box") + d.set_background_title("Inbox Message Dialog Box") r, t = d.menu("Do what with \""+inbox[inboxcur][5]+"\" from \""+inbox[inboxcur][3]+"\"?", choices=[("1", "View message"), ("2", "Mark message as unread"), @@ -287,7 +270,7 @@ def handlech(c, stdscr): ("6", "Move to trash")]) if r == d.DIALOG_OK: if t == "1": # View - set_background_title(d, "\""+inbox[inboxcur][5]+"\" from \""+inbox[inboxcur][3]+"\" to \""+inbox[inboxcur][1]+"\"") + d.set_background_title("\""+inbox[inboxcur][5]+"\" from \""+inbox[inboxcur][3]+"\" to \""+inbox[inboxcur][1]+"\"") data = "" ret = sqlQuery("SELECT message FROM inbox WHERE msgid=?", inbox[inboxcur][0]) if ret != []: @@ -297,11 +280,11 @@ def handlech(c, stdscr): msg = "" for i, item in enumerate(data.split("\n")): msg += fill(item, replace_whitespace=False)+"\n" - scrollbox(d, unicode(ascii(msg)), 30, 80) + d.scrollbox(unicode(ascii(msg)), 30, 80, exit_label="Continue") sqlExecute("UPDATE inbox SET read=1 WHERE msgid=?", inbox[inboxcur][0]) inbox[inboxcur][7] = 1 else: - scrollbox(d, unicode("Could not fetch message.")) + d.scrollbox(unicode("Could not fetch message."), exit_label="Continue") elif t == "2": # Mark unread sqlExecute("UPDATE inbox SET read=0 WHERE msgid=?", inbox[inboxcur][0]) inbox[inboxcur][7] = 0 @@ -315,7 +298,7 @@ def handlech(c, stdscr): ischan = True break if not addresses[i][1]: - scrollbox(d, unicode("Sending address disabled, please either enable it or choose a different address.")) + d.scrollbox(unicode("Sending address disabled, please either enable it or choose a different address."), exit_label="Continue") return toaddr = m[2] if ischan: @@ -334,6 +317,7 @@ def handlech(c, stdscr): sendMessage(fromaddr, toaddr, ischan, subject, body, True) dialogreset(stdscr) elif t == "4": # Add to Address Book + global addrbook addr = inbox[inboxcur][4] if addr not in [item[1] for i,item in enumerate(addrbook)]: r, t = d.inputbox("Label for address \""+addr+"\"") @@ -345,9 +329,9 @@ def handlech(c, stdscr): addrbook.append([label, addr]) addrbook.reverse() else: - scrollbox(d, unicode("The selected address is already in the Address Book.")) + d.scrollbox(unicode("The selected address is already in the Address Book."), exit_label="Continue") elif t == "5": # Save message - set_background_title(d, "Save \""+inbox[inboxcur][5]+"\" as text file") + d.set_background_title("Save \""+inbox[inboxcur][5]+"\" as text file") r, t = d.inputbox("Filename", init=inbox[inboxcur][5]+".txt") if r == d.DIALOG_OK: msg = "" @@ -359,24 +343,25 @@ def handlech(c, stdscr): fh.write(msg) fh.close() else: - scrollbox(d, unicode("Could not fetch message.")) + d.scrollbox(unicode("Could not fetch message."), exit_label="Continue") elif t == "6": # Move to trash sqlExecute("UPDATE inbox SET folder='trash' WHERE msgid=?", inbox[inboxcur][0]) del inbox[inboxcur] - scrollbox(d, unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it.")) + d.scrollbox(unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it."), + exit_label="Continue") elif menutab == 2: a = "" if addresses[addrcur][3] != 0: # if current address is a chan a = addresses[addrcur][2] sendMessage(addresses[addrcur][2], a) elif menutab == 3: - set_background_title(d, "Sent Messages Dialog Box") + d.set_background_title("Sent Messages Dialog Box") r, t = d.menu("Do what with \""+sentbox[sentcur][4]+"\" to \""+sentbox[sentcur][0]+"\"?", choices=[("1", "View message"), ("2", "Move to trash")]) if r == d.DIALOG_OK: if t == "1": # View - set_background_title(d, "\""+sentbox[sentcur][4]+"\" from \""+sentbox[sentcur][3]+"\" to \""+sentbox[sentcur][1]+"\"") + d.set_background_title("\""+sentbox[sentcur][4]+"\" from \""+sentbox[sentcur][3]+"\" to \""+sentbox[sentcur][1]+"\"") data = "" ret = sqlQuery("SELECT message FROM sent WHERE subject=? AND ackdata=?", sentbox[sentcur][4], sentbox[sentcur][6]) if ret != []: @@ -386,31 +371,28 @@ def handlech(c, stdscr): msg = "" for i, item in enumerate(data.split("\n")): msg += fill(item, replace_whitespace=False)+"\n" - scrollbox(d, unicode(ascii(msg)), 30, 80) + d.scrollbox(unicode(ascii(msg)), 30, 80, exit_label="Continue") else: - scrollbox(d, unicode("Could not fetch message.")) + d.scrollbox(unicode("Could not fetch message."), exit_label="Continue") elif t == "2": # Move to trash sqlExecute("UPDATE sent SET folder='trash' WHERE subject=? AND ackdata=?", sentbox[sentcur][4], sentbox[sentcur][6]) del sentbox[sentcur] - scrollbox(d, unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it.")) + d.scrollbox(unicode("Message moved to trash. There is no interface to view your trash, \nbut the message is still on disk if you are desperate to recover it."), + exit_label="Continue") elif menutab == 4: - set_background_title(d, "Your Identities Dialog Box") - if len(addresses) <= addrcur: - r, t = d.menu("Do what with addresses?", - choices=[("1", "Create new address")]) - else: - r, t = d.menu("Do what with \""+addresses[addrcur][0]+"\" : \""+addresses[addrcur][2]+"\"?", - choices=[("1", "Create new address"), - ("2", "Send a message from this address"), - ("3", "Rename"), - ("4", "Enable"), - ("5", "Disable"), - ("6", "Delete"), - ("7", "Special address behavior")]) + d.set_background_title("Your Identities Dialog Box") + r, t = d.menu("Do what with \""+addresses[addrcur][0]+"\" : \""+addresses[addrcur][2]+"\"?", + choices=[("1", "Create new address"), + ("2", "Send a message from this address"), + ("3", "Rename"), + ("4", "Enable"), + ("5", "Disable"), + ("6", "Delete"), + ("7", "Special address behavior")]) if r == d.DIALOG_OK: if t == "1": # Create new address - set_background_title(d, "Create new address") - scrollbox(d, unicode("Here you may generate as many addresses as you like.\n" + d.set_background_title("Create new address") + d.scrollbox(unicode("Here you may generate as many addresses as you like.\n" "Indeed, creating and abandoning addresses is encouraged.\n" "Deterministic addresses have several pros and cons:\n" "\nPros:\n" @@ -419,13 +401,14 @@ def handlech(c, stdscr): "Cons:\n" " * You must remember (or write down) your passphrase in order to recreate \n your keys if they are lost\n" " * You must also remember the address version and stream numbers\n" - " * If you choose a weak passphrase someone may be able to brute-force it \n and then send and receive messages as you")) + " * If you choose a weak passphrase someone may be able to brute-force it \n and then send and receive messages as you"), + exit_label="Continue") r, t = d.menu("Choose an address generation technique", choices=[("1", "Use a random number generator"), ("2", "Use a passphrase")]) if r == d.DIALOG_OK: if t == "1": - set_background_title(d, "Randomly generate address") + d.set_background_title("Randomly generate address") r, t = d.inputbox("Label (not shown to anyone except you)") label = "" if r == d.DIALOG_OK and len(t) > 0: @@ -445,12 +428,12 @@ def handlech(c, stdscr): stream = decodeAddress(addrs[int(t)][1])[2] shorten = False r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", 1 if shorten else 0)]) + choices=[("1", "Spend time shortening the address", shorten)]) if r == d.DIALOG_OK and "1" in t: shorten = True - queues.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) + shared.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) elif t == "2": - set_background_title(d, "Make deterministic addresses") + d.set_background_title("Make deterministic addresses") r, t = d.passwordform("Enter passphrase", [("Passphrase", 1, 1, "", 2, 1, 64, 128), ("Confirm passphrase", 3, 1, "", 4, 1, 64, 128)], @@ -465,15 +448,16 @@ def handlech(c, stdscr): stream = 1 shorten = False r, t = d.checklist("Miscellaneous options", - choices=[("1", "Spend time shortening the address", 1 if shorten else 0)]) + choices=[("1", "Spend time shortening the address", shorten)]) if r == d.DIALOG_OK and "1" in t: shorten = True - scrollbox(d, unicode("In addition to your passphrase, be sure to remember the following numbers:\n" + d.scrollbox(unicode("In addition to your passphrase, be sure to remember the following numbers:\n" "\n * Address version number: "+str(4)+"\n" - " * Stream number: "+str(stream))) - queues.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) + " * Stream number: "+str(stream)), + exit_label="Continue") + shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) else: - scrollbox(d, unicode("Passphrases do not match")) + d.scrollbox(unicode("Passphrases do not match"), exit_label="Continue") elif t == "2": # Send a message a = "" if addresses[addrcur][3] != 0: # if current address is a chan @@ -485,19 +469,19 @@ def handlech(c, stdscr): r, t = d.inputbox("New address label", init=label) if r == d.DIALOG_OK: label = t - BMConfigParser().set(a, "label", label) + shared.config.set(a, "label", label) # Write config - BMConfigParser().save() + shared.writeKeysFile() addresses[addrcur][0] = label elif t == "4": # Enable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "true") # Set config + shared.config.set(a, "enabled", "true") # Set config # Write config - BMConfigParser().save() + shared.writeKeysFile() # Change color - if BMConfigParser().safeGetBoolean(a, 'chan'): + if shared.safeConfigGetBoolean(a, 'chan'): addresses[addrcur][3] = 9 # orange - elif BMConfigParser().safeGetBoolean(a, 'mailinglist'): + elif shared.safeConfigGetBoolean(a, 'mailinglist'): addresses[addrcur][3] = 5 # magenta else: addresses[addrcur][3] = 0 # black @@ -505,59 +489,55 @@ def handlech(c, stdscr): shared.reloadMyAddressHashes() # Reload address hashes elif t == "5": # Disable address a = addresses[addrcur][2] - BMConfigParser().set(a, "enabled", "false") # Set config + shared.config.set(a, "enabled", "false") # Set config addresses[addrcur][3] = 8 # Set color to gray # Write config - BMConfigParser().save() + shared.writeKeysFile() addresses[addrcur][1] = False shared.reloadMyAddressHashes() # Reload address hashes elif t == "6": # Delete address r, t = d.inputbox("Type in \"I want to delete this address\"", width=50) if r == d.DIALOG_OK and t == "I want to delete this address": - BMConfigParser().remove_section(addresses[addrcur][2]) - BMConfigParser().save() + shared.config.remove_section(addresses[addrcur][2]) + shared.writeKeysFile() del addresses[addrcur] elif t == "7": # Special address behavior a = addresses[addrcur][2] - set_background_title(d, "Special address behavior") - if BMConfigParser().safeGetBoolean(a, "chan"): - scrollbox(d, unicode("This is a chan address. You cannot use it as a pseudo-mailing list.")) + d.set_background_title("Special address behavior") + if shared.safeConfigGetBoolean(a, "chan"): + d.scrollbox(unicode("This is a chan address. You cannot use it as a pseudo-mailing list."), exit_label="Continue") else: - m = BMConfigParser().safeGetBoolean(a, "mailinglist") + m = shared.safeConfigGetBoolean(a, "mailinglist") r, t = d.radiolist("Select address behavior", choices=[("1", "Behave as a normal address", not m), ("2", "Behave as a pseudo-mailing-list address", m)]) if r == d.DIALOG_OK: if t == "1" and m == True: - BMConfigParser().set(a, "mailinglist", "false") + shared.config.set(a, "mailinglist", "false") if addresses[addrcur][1]: addresses[addrcur][3] = 0 # Set color to black else: addresses[addrcur][3] = 8 # Set color to gray elif t == "2" and m == False: try: - mn = BMConfigParser().get(a, "mailinglistname") + mn = shared.config.get(a, "mailinglistname") except ConfigParser.NoOptionError: mn = "" r, t = d.inputbox("Mailing list name", init=mn) if r == d.DIALOG_OK: mn = t - BMConfigParser().set(a, "mailinglist", "true") - BMConfigParser().set(a, "mailinglistname", mn) + shared.config.set(a, "mailinglist", "true") + shared.config.set(a, "mailinglistname", mn) addresses[addrcur][3] = 6 # Set color to magenta # Write config - BMConfigParser().save() + shared.writeKeysFile() elif menutab == 5: - set_background_title(d, "Subscriptions Dialog Box") - if len(subscriptions) <= subcur: - r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", - choices=[("1", "Add new subscription")]) - else: - r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", - choices=[("1", "Add new subscription"), - ("2", "Delete this subscription"), - ("3", "Enable"), - ("4", "Disable")]) + d.set_background_title("Subscriptions Dialog Box") + r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?", + choices=[("1", "Add new subscription"), + ("2", "Delete this subscription"), + ("3", "Enable"), + ("4", "Disable")]) if r == d.DIALOG_OK: if t == "1": r, t = d.inputbox("New subscription address") @@ -572,7 +552,7 @@ def handlech(c, stdscr): subscriptions.append([label, addr, True]) subscriptions.reverse() - sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True) + sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, address, True) shared.reloadBroadcastSendersForWhichImWatching() elif t == "2": r, t = d.inpuxbox("Type in \"I want to delete this subscription\"") @@ -589,16 +569,12 @@ def handlech(c, stdscr): shared.reloadBroadcastSendersForWhichImWatching() subscriptions[subcur][2] = False elif menutab == 6: - set_background_title(d, "Address Book Dialog Box") - if len(addrbook) <= abookcur: - r, t = d.menu("Do what with addressbook?", - choices=[("3", "Add new address to Address Book")]) - else: - r, t = d.menu("Do what with \""+addrbook[abookcur][0]+"\" : \""+addrbook[abookcur][1]+"\"", - choices=[("1", "Send a message to this address"), - ("2", "Subscribe to this address"), - ("3", "Add new address to Address Book"), - ("4", "Delete this address")]) + d.set_background_title("Address Book Dialog Box") + r, t = d.menu("Do what with \""+addrbook[abookcur][0]+"\" : \""+addrbook[abookcur][1]+"\"", + choices=[("1", "Send a message to this address"), + ("2", "Subscribe to this address"), + ("3", "Add new address to Address Book"), + ("4", "Delete this address")]) if r == d.DIALOG_OK: if t == "1": sendMessage(recv=addrbook[abookcur][1]) @@ -611,7 +587,7 @@ def handlech(c, stdscr): subscriptions.append([label, addr, True]) subscriptions.reverse() - sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True) + sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, address, True) shared.reloadBroadcastSendersForWhichImWatching() elif t == "3": r, t = d.inputbox("Input new address") @@ -626,14 +602,14 @@ def handlech(c, stdscr): addrbook.append([t, addr]) addrbook.reverse() else: - scrollbox(d, unicode("The selected address is already in the Address Book.")) + d.scrollbox(unicode("The selected address is already in the Address Book."), exit_label="Continue") elif t == "4": r, t = d.inputbox("Type in \"I want to delete this Address Book entry\"") if r == d.DIALOG_OK and t == "I want to delete this Address Book entry": sqlExecute("DELETE FROM addressbook WHERE label=? AND address=?", addrbook[abookcur][0], addrbook[abookcur][1]) del addrbook[abookcur] elif menutab == 7: - set_background_title(d, "Blacklist Dialog Box") + d.set_background_title("Blacklist Dialog Box") r, t = d.menu("Do what with \""+blacklist[blackcur][0]+"\" : \""+blacklist[blackcur][1]+"\"?", choices=[("1", "Delete"), ("2", "Enable"), @@ -709,7 +685,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F if sender == "": return d = Dialog(dialog="dialog") - set_background_title(d, "Send a message") + d.set_background_title("Send a message") if recv == "": r, t = d.inputbox("Recipient address (Cancel to load from the Address Book or leave blank to broadcast)", 10, 60) if r != d.DIALOG_OK: @@ -719,8 +695,8 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F recv = t if broadcast == None and sender != recv: r, t = d.radiolist("How to send the message?", - choices=[("1", "Send to one or more specific people", 1), - ("2", "Broadcast to everyone who is subscribed to your address", 0)]) + choices=[("1", "Send to one or more specific people", True), + ("2", "Broadcast to everyone who is subscribed to your address", False)]) if r != d.DIALOG_OK: return broadcast = False @@ -747,7 +723,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F if addr != "": status, version, stream, ripe = decodeAddress(addr) if status != "success": - set_background_title(d, "Recipient address error") + d.set_background_title("Recipient address error") err = "Could not decode" + addr + " : " + status + "\n\n" if status == "missingbm": err += "Bitmessage addresses should start with \"BM-\"." @@ -765,22 +741,24 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F err += "Some data encoded in the address is malformed. There might be something wrong with the software of your acquaintance." else: err += "It is unknown what is wrong with the address." - scrollbox(d, unicode(err)) + d.scrollbox(unicode(err), exit_label="Continue") else: addr = addBMIfNotPresent(addr) if version > 4 or version <= 1: - set_background_title(d, "Recipient address error") - scrollbox(d, unicode("Could not understand version number " + version + "of address" + addr + ".")) + d.set_background_title("Recipient address error") + d.scrollbox(unicode("Could not understand version number " + version + "of address" + addr + "."), + exit_label="Continue") continue if stream > 1 or stream == 0: - set_background_title(d, "Recipient address error") - scrollbox(d, unicode("Bitmessage currently only supports stream numbers of 1, unlike as requested for address " + addr + ".")) + d.set_background_title("Recipient address error") + d.scrollbox(unicode("Bitmessage currently only supports stream numbers of 1, unlike as requested for address " + addr + "."), + exit_label="Continue") continue if len(shared.connectedHostsList) == 0: - set_background_title(d, "Not connected warning") - scrollbox(d, unicode("Because you are not currently connected to the network, ")) - stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) + d.set_background_title("Not connected warning") + d.scrollbox(unicode("Because you are not currently connected to the network, "), + exit_label="Continue") + ackdata = OpenSSL.rand(32) sqlExecute( "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", @@ -797,15 +775,15 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", 2, # encodingType - BMConfigParser().getint('bitmessagesettings', 'ttl')) - queues.workerQueue.put(("sendmessage", addr)) + shared.config.getint('bitmessagesettings', 'ttl')) + shared.workerQueue.put(("sendmessage", addr)) else: # Broadcast if recv == "": - set_background_title(d, "Empty sender error") - scrollbox(d, unicode("You must specify an address to send the message from.")) + d.set_background_title("Empty sender error") + d.scrollbox(unicode("You must specify an address to send the message from."), + exit_label="Continue") else: - # dummy ackdata, no need for stealth - ackdata = genAckPayload(streamNumber, 0) + ackdata = OpenSSL.rand(32) recv = BROADCAST_STR ripe = "" sqlExecute( @@ -824,8 +802,8 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", # folder 2, # encodingType - BMConfigParser().getint('bitmessagesettings', 'ttl')) - queues.workerQueue.put(('sendbroadcast', '')) + shared.config.getint('bitmessagesettings', 'ttl')) + shared.workerQueue.put(('sendbroadcast', '')) def loadInbox(): sys.stdout = sys.__stdout__ @@ -838,6 +816,7 @@ def loadInbox(): FROM inbox WHERE folder='inbox' AND %s LIKE ? ORDER BY received """ % (where,), what) + global inbox for row in ret: msgid, toaddr, fromaddr, subject, received, read = row subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject)) @@ -847,7 +826,7 @@ def loadInbox(): if toaddr == BROADCAST_STR: tolabel = BROADCAST_STR else: - tolabel = BMConfigParser().get(toaddr, "label") + tolabel = shared.config.get(toaddr, "label") except: tolabel = "" if tolabel == "": @@ -856,8 +835,8 @@ def loadInbox(): # Set label for from address fromlabel = "" - if BMConfigParser().has_section(fromaddr): - fromlabel = BMConfigParser().get(fromaddr, "label") + if shared.config.has_section(fromaddr): + fromlabel = shared.config.get(fromaddr, "label") if fromlabel == "": # Check Address Book qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) if qr != []: @@ -887,6 +866,7 @@ def loadSent(): FROM sent WHERE folder='sent' AND %s LIKE ? ORDER BY lastactiontime """ % (where,), what) + global sent for row in ret: toaddr, fromaddr, subject, status, ackdata, lastactiontime = row subject = ascii(shared.fixPotentiallyInvalidUTF8Data(subject)) @@ -903,15 +883,15 @@ def loadSent(): for r in qr: tolabel, = r if tolabel == "": - if BMConfigParser().has_section(toaddr): - tolabel = BMConfigParser().get(toaddr, "label") + if shared.config.has_section(toaddr): + tolabel = shared.config.get(toaddr, "label") if tolabel == "": tolabel = toaddr # Set label for from address fromlabel = "" - if BMConfigParser().has_section(fromaddr): - fromlabel = BMConfigParser().get(fromaddr, "label") + if shared.config.has_section(fromaddr): + fromlabel = shared.config.get(fromaddr, "label") if fromlabel == "": fromlabel = fromaddr @@ -930,7 +910,7 @@ def loadSent(): statstr = "Message sent at "+t+"." elif status == "doingmsgpow": statstr = "The proof of work required to send the message has been queued." - elif status == "ackreceived": + elif status == "askreceived": t = l10n.formatTimestamp(lastactiontime, False) statstr = "Acknowledgment of the message received at "+t+"." elif status == "broadcastqueued": @@ -958,6 +938,7 @@ def loadAddrBook(): sys.stdout = printlog ret = sqlQuery("SELECT label, address FROM addressbook") + global addrbook for row in ret: label, addr = row label = shared.fixPotentiallyInvalidUTF8Data(label) @@ -971,7 +952,7 @@ def loadSubscriptions(): subscriptions.reverse() def loadBlackWhiteList(): global bwtype - bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist") + bwtype = shared.config.get("bitmessagesettings", "blackwhitelist") if bwtype == "black": ret = sqlQuery("SELECT label, address, enabled FROM blacklist") else: @@ -1002,7 +983,7 @@ def runwrapper(): stdscr.timeout(1000) curses.wrapper(run) - doShutdown() + shutdown() def run(stdscr): # Schedule inventory lookup data @@ -1027,19 +1008,20 @@ def run(stdscr): curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish # Init list of address in 'Your Identities' tab - configSections = BMConfigParser().addressses() + configSections = shared.config.sections() for addressInKeysFile in configSections: - isEnabled = BMConfigParser().getboolean(addressInKeysFile, "enabled") - addresses.append([BMConfigParser().get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) - # Set address color - if not isEnabled: - addresses[len(addresses)-1].append(8) # gray - elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'): - addresses[len(addresses)-1].append(9) # orange - elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'): - addresses[len(addresses)-1].append(5) # magenta - else: - addresses[len(addresses)-1].append(0) # black + if addressInKeysFile != "bitmessagesettings": + isEnabled = shared.config.getboolean(addressInKeysFile, "enabled") + addresses.append([shared.config.get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) + # Set address color + if not isEnabled: + addresses[len(addresses)-1].append(8) # gray + elif shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): + addresses[len(addresses)-1].append(9) # orange + elif shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): + addresses[len(addresses)-1].append(5) # magenta + else: + addresses[len(addresses)-1].append(0) # black addresses.reverse() stdscr.clear() @@ -1048,11 +1030,11 @@ def run(stdscr): drawtab(stdscr) handlech(stdscr.getch(), stdscr) -def doShutdown(): +def shutdown(): sys.stdout = sys.__stdout__ print("Shutting down...") sys.stdout = printlog - shutdown.doCleanShutdown() + shared.doCleanShutdown() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index accd5740..daae1af9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,6 +1,6 @@ -#!/usr/bin/python2.7 -# Copyright (c) 2012-2016 Jonathan Warren -# Copyright (c) 2012-2016 The Bitmessage developers +#!/usr/bin/env python2.7 +# Copyright (c) 2012 Jonathan Warren +# Copyright (c) 2012 The Bitmessage developers # Distributed under the MIT/X11 software license. See the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,96 +9,65 @@ # The software version variable is now held in shared.py -import os -import sys - -app_dir = os.path.dirname(os.path.abspath(__file__)) -os.chdir(app_dir) -sys.path.insert(0, app_dir) - import depends depends.check_dependencies() import signal # Used to capture a Ctrl-C keypress so that Bitmessage can shutdown gracefully. # The next 3 are used for the API -from singleinstance import singleinstance -import errno +import singleton +import os import socket import ctypes from struct import pack +import sys from subprocess import call -from time import sleep -from random import randint -import getopt +import time -from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer +from SimpleXMLRPCServer import SimpleXMLRPCServer +from api import MySimpleXMLRPCRequestHandler from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections -import defaults import shared -import knownnodes -import state -import shutdown +from helper_sql import sqlQuery import threading # Classes from class_sqlThread import sqlThread from class_singleCleaner import singleCleaner from class_objectProcessor import objectProcessor +from class_outgoingSynSender import outgoingSynSender +from class_singleListener import singleListener from class_singleWorker import singleWorker from class_addressGenerator import addressGenerator -from class_smtpDeliver import smtpDeliver -from class_smtpServer import smtpServer -from bmconfigparser import BMConfigParser - -from inventory import Inventory - -from network.connectionpool import BMConnectionPool -from network.dandelion import Dandelion -from network.networkthread import BMNetworkThread -from network.receivequeuethread import ReceiveQueueThread -from network.announcethread import AnnounceThread -from network.invthread import InvThread -from network.addrthread import AddrThread -from network.downloadthread import DownloadThread +from debug import logger # Helper Functions import helper_bootstrap import helper_generic -import helper_threading - +import upnp + def connectToStream(streamNumber): - state.streamsInWhichIAmParticipating.append(streamNumber) + shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' selfInitiatedConnections[streamNumber] = {} + shared.inventorySets[streamNumber] = set() + queryData = sqlQuery('''SELECT hash FROM inventory WHERE streamnumber=?''', streamNumber) + for row in queryData: + shared.inventorySets[streamNumber].add(row[0]) + if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): # Some XP and Vista systems can only have 10 outgoing connections at a time. - state.maximumNumberOfHalfOpenConnections = 9 + maximumNumberOfHalfOpenConnections = 9 else: - state.maximumNumberOfHalfOpenConnections = 64 - try: - # don't overload Tor - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': - state.maximumNumberOfHalfOpenConnections = 4 - except: - pass - - with knownnodes.knownNodesLock: - if streamNumber not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber] = {} - if streamNumber*2 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2] = {} - if streamNumber*2+1 not in knownnodes.knownNodes: - knownnodes.knownNodes[streamNumber*2+1] = {} + maximumNumberOfHalfOpenConnections = 64 + for i in range(maximumNumberOfHalfOpenConnections): + a = outgoingSynSender() + a.setup(streamNumber, selfInitiatedConnections) + a.start() - BMConnectionPool().connectToStream(streamNumber) - -def _fixSocket(): - if sys.platform.startswith('linux'): - socket.SO_BINDTODEVICE = 25 - - if not sys.platform.startswith('win'): +def _fixWinsock(): + if not ('win32' in sys.platform) and not ('win64' in sys.platform): return # Python 2 on Windows doesn't define a wrapper for @@ -149,42 +118,14 @@ def _fixSocket(): socket.IPV6_V6ONLY = 27 # This thread, of which there is only one, runs the API. -class singleAPI(threading.Thread, helper_threading.StoppableThread): +class singleAPI(threading.Thread): + def __init__(self): - threading.Thread.__init__(self, name="singleAPI") - self.initStop() - - def stopThread(self): - super(singleAPI, self).stopThread() - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( - 'bitmessagesettings', 'apiport'))) - s.shutdown(socket.SHUT_RDWR) - s.close() - except: - pass + threading.Thread.__init__(self) def run(self): - port = BMConfigParser().getint('bitmessagesettings', 'apiport') - try: - from errno import WSAEADDRINUSE - except (ImportError, AttributeError): - errno.WSAEADDRINUSE = errno.EADDRINUSE - for attempt in range(50): - try: - if attempt > 0: - port = randint(32767, 65535) - se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), port), - MySimpleXMLRPCRequestHandler, True, True) - except socket.error as e: - if e.errno in (errno.EADDRINUSE, errno.WSAEADDRINUSE): - continue - else: - if attempt > 0: - BMConfigParser().set("bitmessagesettings", "apiport", str(port)) - BMConfigParser().save() - break + se = SimpleXMLRPCServer((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + 'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) se.register_introspection_functions() se.serve_forever() @@ -192,50 +133,29 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): selfInitiatedConnections = {} if shared.useVeryEasyProofOfWorkForTesting: - defaults.networkDefaultProofOfWorkNonceTrialsPerByte = int( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) - defaults.networkDefaultPayloadLengthExtraBytes = int( - defaults.networkDefaultPayloadLengthExtraBytes / 100) + shared.networkDefaultProofOfWorkNonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte / 100) + shared.networkDefaultPayloadLengthExtraBytes = int( + shared.networkDefaultPayloadLengthExtraBytes / 100) class Main: - def start(self): - _fixSocket() - - daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') - - try: - opts, args = getopt.getopt(sys.argv[1:], "hcd", - ["help", "curses", "daemon"]) - - except getopt.GetoptError: - self.usage() - sys.exit(2) - - for opt, arg in opts: - if opt in ("-h", "--help"): - self.usage() - sys.exit() - elif opt in ("-d", "--daemon"): - daemon = True - elif opt in ("-c", "--curses"): - state.curses = True + def start(self, daemon=False): + _fixWinsock() + shared.daemon = daemon # is the application already running? If yes then exit. - shared.thisapp = singleinstance("", daemon) + thisapp = singleton.singleinstance() - if daemon: - with shared.printLock: - print('Running as a daemon. Send TERM signal to end.') - self.daemonize() + import upnp + upnp.createPortMapping() - self.setSignalHandler() + # get curses flag + curses = False + if '-c' in sys.argv: + curses = True - helper_threading.set_thread_name("PyBitmessage") - - state.dandelion = BMConfigParser().safeGetInt('network', 'dandelion') - # dandelion requires outbound connections, without them, stem objects will get stuck forever - if state.dandelion and not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): - state.dandelion = 0 + signal.signal(signal.SIGINT, helper_generic.signal_handler) + # signal.signal(signal.SIGINT, signal.SIG_DFL) helper_bootstrap.knownNodes() # Start the address generation thread @@ -253,19 +173,6 @@ class Main: sqlLookup.daemon = False # DON'T close the main program even if there are threads left. The closeEvent should command this thread to exit gracefully. sqlLookup.start() - Inventory() # init - Dandelion() # init, needs to be early because other thread may access it early - - # SMTP delivery thread - if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': - smtpDeliveryThread = smtpDeliver() - smtpDeliveryThread.start() - - # SMTP daemon thread - if daemon and BMConfigParser().safeGetBoolean("bitmessagesettings", "smtpd"): - smtpServerThread = smtpServer() - smtpServerThread.start() - # Start the thread that calculates POWs objectProcessorThread = objectProcessor() objectProcessorThread.daemon = False # DON'T close the main program even the thread remains. This thread checks the shutdown variable after processing each object. @@ -279,9 +186,9 @@ class Main: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = BMConfigParser().get( + apiNotifyPath = shared.config.get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -294,36 +201,15 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() - BMConnectionPool() - asyncoreThread = BMNetworkThread() - asyncoreThread.daemon = True - asyncoreThread.start() - for i in range(BMConfigParser().getint("threads", "receive")): - receiveQueueThread = ReceiveQueueThread(i) - receiveQueueThread.daemon = True - receiveQueueThread.start() - announceThread = AnnounceThread() - announceThread.daemon = True - announceThread.start() - state.invThread = InvThread() - state.invThread.daemon = True - state.invThread.start() - state.addrThread = AddrThread() - state.addrThread.daemon = True - state.addrThread.start() - state.downloadThread = DownloadThread() - state.downloadThread.daemon = True - state.downloadThread.start() - connectToStream(1) - if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'): - import upnp - upnpThread = upnp.uPnPThread() - upnpThread.start() + singleListenerThread = singleListener() + singleListenerThread.setup(selfInitiatedConnections) + singleListenerThread.daemon = True # close the main program even if there are threads left + singleListenerThread.start() - if daemon == False and BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') == False: - if state.curses == False: + if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False: + if curses == False: if not depends.check_pyqt(): 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') print('You can also run PyBitmessage with the new curses interface by providing \'-c\' as a commandline argument.') @@ -332,107 +218,40 @@ class Main: import bitmessageqt bitmessageqt.run() else: - if True: -# if depends.check_curses(): + if depends.check_curses(): print('Running with curses') import bitmessagecurses bitmessagecurses.runwrapper() else: - BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + shared.config.remove_option('bitmessagesettings', 'dontconnect') - if daemon: - while state.shutdown == 0: - sleep(1) - - def daemonize(self): - grandfatherPid = os.getpid() - parentPid = None - try: - if os.fork(): - # unlock - shared.thisapp.cleanup() - # wait until grandchild ready + if daemon: + with shared.printLock: + print('Running as a daemon. The main program should exit this thread.') + else: + with shared.printLock: + print('Running as a daemon. You can use Ctrl+C to exit.') while True: - sleep(1) - os._exit(0) - except AttributeError: - # fork not implemented - pass - else: - parentPid = os.getpid() - shared.thisapp.lock() # relock - os.umask(0) - try: - os.setsid() - except AttributeError: - # setsid not implemented - pass - try: - if os.fork(): - # unlock - shared.thisapp.cleanup() - # wait until child ready - while True: - sleep(1) - os._exit(0) - except AttributeError: - # fork not implemented - pass - else: - shared.thisapp.lock() # relock - shared.thisapp.lockPid = None # indicate we're the final child - sys.stdout.flush() - sys.stderr.flush() - if not sys.platform.startswith('win'): - si = file(os.devnull, 'r') - so = file(os.devnull, 'a+') - se = file(os.devnull, 'a+', 0) - os.dup2(si.fileno(), sys.stdin.fileno()) - os.dup2(so.fileno(), sys.stdout.fileno()) - os.dup2(se.fileno(), sys.stderr.fileno()) - if parentPid: - # signal ready - os.kill(parentPid, signal.SIGTERM) - os.kill(grandfatherPid, signal.SIGTERM) - - def setSignalHandler(self): - signal.signal(signal.SIGINT, helper_generic.signal_handler) - signal.signal(signal.SIGTERM, helper_generic.signal_handler) - # signal.signal(signal.SIGINT, signal.SIG_DFL) - - def usage(self): - print 'Usage: ' + sys.argv[0] + ' [OPTIONS]' - print ''' -Options: - -h, --help show this help message and exit - -c, --curses use curses (text mode) interface - -d, --daemon run in daemon (background) mode - -All parameters are optional. -''' + time.sleep(20) def stop(self): with shared.printLock: print('Stopping Bitmessage Deamon.') - shutdown.doCleanShutdown() + shared.doCleanShutdown() #TODO: nice function but no one is using this def getApiAddress(self): - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): return None - address = BMConfigParser().get('bitmessagesettings', 'apiinterface') - port = BMConfigParser().getint('bitmessagesettings', 'apiport') + address = shared.config.get('bitmessagesettings', 'apiinterface') + port = shared.config.getint('bitmessagesettings', 'apiport') return {'address':address,'port':port} - -def main(): +if __name__ == "__main__": mainprogram = Main() mainprogram.start() -if __name__ == "__main__": - main() - # So far, the creation of and management of the Bitmessage protocol and this # client is a one-man operation. Bitcoin tips are quite appreciated. diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7bbd7dd9..1819628b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1,132 +1,194 @@ -from debug import logger -import sys - +withMessagingMenu = False try: - from PyQt4 import QtCore, QtGui - from PyQt4.QtNetwork import QLocalSocket, QLocalServer -except Exception as err: - logmsg = 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).' - logger.critical(logmsg, exc_info=True) - sys.exit() + from gi.repository import MessagingMenu + from gi.repository import Notify + withMessagingMenu = True +except ImportError: + MessagingMenu = None -from tr import _translate -from addresses import decodeAddress, addBMIfNotPresent +from addresses import * import shared -from bitmessageui import Ui_MainWindow -from bmconfigparser import BMConfigParser -import defaults -from namecoin import namecoinConnection -from messageview import MessageView -from migrationwizard import Ui_MigrationWizard -from foldertree import ( - AccountMixin, Ui_FolderWidget, Ui_AddressWidget, Ui_SubscriptionWidget, - MessageList_AddressWidget, MessageList_SubjectWidget, - Ui_AddressBookWidgetItemLabel, Ui_AddressBookWidgetItemAddress) -from settings import Ui_settingsDialog -import settingsmixin -import support -import locale +from bitmessageui import * +from namecoin import namecoinConnection, ensureNamecoinOptions +from newaddressdialog import * +from addaddressdialog import * +from newsubscriptiondialog import * +from regenerateaddresses import * +from newchandialog import * +from specialaddressbehavior import * +from settings import * +from about import * +from help import * +from iconglossary import * +from connect import * +import sys +from time import strftime, localtime, gmtime import time import os import hashlib from pyelliptic.openssl import OpenSSL +import pickle +import platform import textwrap import debug -import random -from sqlite3 import register_adapter -import string -from datetime import datetime, timedelta -from helper_ackPayload import genAckPayload -from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure -import helper_search +from debug import logger +import subprocess +import datetime +from helper_sql import * import l10n -import openclpow -from utils import str_broadcast_subscribers, avatarize -from account import ( - getSortedAccounts, getSortedSubscriptions, accountClass, BMAccount, - GatewayAccount, MailchuckAccount, AccountColor) -import dialogs -from helper_generic import powQueueSize -from inventory import ( - PendingDownloadQueue, PendingUpload, - PendingUploadDeadlineException) -from uisignaler import UISignaler -import knownnodes -import paths -from proofofwork import getPowType -import queues -import shutdown -import state -from statusbar import BMStatusBar -from network.asyncore_pollchoose import set_rates -import sound - try: - from plugins.plugin import get_plugin, get_plugins -except ImportError: - get_plugins = False + from PyQt4 import QtCore, QtGui + from PyQt4.QtCore import * + from PyQt4.QtGui import * + +except Exception as err: + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).' + print 'Error message:', err + sys.exit() + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 +except AttributeError: + print 'QtGui.QApplication.UnicodeUTF8 error:', err + +def _translate(context, text): + return QtGui.QApplication.translate(context, text) -def change_translation(newlocale): - global qmytranslator, qsystranslator +def identiconize(address): + size = 48 + + # If you include another identicon library, please generate an + # example identicon with the following md5 hash: + # 3fd4bf901b9d4ea1394f0fb358725b28 + try: - if not qmytranslator.isEmpty(): - QtGui.QApplication.removeTranslator(qmytranslator) + identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib') except: - pass - try: - if not qsystranslator.isEmpty(): - QtGui.QApplication.removeTranslator(qsystranslator) - except: - pass + # default to qidenticon_two_x + identicon_lib = 'qidenticon_two_x' - qmytranslator = QtCore.QTranslator() - translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale) - qmytranslator.load(translationpath) - QtGui.QApplication.installTranslator(qmytranslator) - - qsystranslator = QtCore.QTranslator() - if paths.frozen: - translationpath = os.path.join (paths.codePath(), 'translations', 'qt_' + newlocale) - else: - translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) - qsystranslator.load(translationpath) - QtGui.QApplication.installTranslator(qsystranslator) - - lang = locale.normalize(l10n.getTranslationLanguage()) - langs = [lang.split(".")[0] + "." + l10n.encoding, lang.split(".")[0] + "." + 'UTF-8', lang] - if 'win32' in sys.platform or 'win64' in sys.platform: - langs = [l10n.getWindowsLocale(lang)] - for lang in langs: - try: - l10n.setlocale(locale.LC_ALL, lang) - if 'win32' not in sys.platform and 'win64' not in sys.platform: - l10n.encoding = locale.nl_langinfo(locale.CODESET) - else: - l10n.encoding = locale.getlocale()[1] - logger.info("Successfully set locale to %s", lang) - break - except: - logger.error("Failed to set locale to %s", lang, exc_info=True) + # As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.) + # It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk + # of attacks where someone creates an address to mimic someone else's identicon. + identiconsuffix = shared.config.get('bitmessagesettings', 'identiconsuffix') + + if not shared.config.getboolean('bitmessagesettings', 'useidenticons'): + idcon = QtGui.QIcon() + return idcon + + if (identicon_lib[:len('qidenticon')] == 'qidenticon'): + # print identicon_lib + # originally by: + # :Author:Shin Adachi + # Licesensed under FreeBSD License. + # stripped from PIL and uses QT instead (by sendiulo, same license) + import qidenticon + hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest() + use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two') + opacity = int(not((identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x') | (identicon_lib == 'qidenticon_b') | (identicon_lib == 'qidenticon_two_b')))*255 + penwidth = 0 + image = qidenticon.render_identicon(int(hash, 16), size, use_two_colors, opacity, penwidth) + # filename = './images/identicons/'+hash+'.png' + # image.save(filename) + idcon = QtGui.QIcon() + idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off) + return idcon + elif identicon_lib == 'pydenticon': + # print identicon_lib + # Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source) + from pydenticon import Pydenticon + # It is not included in the source, because it is licensed under GPLv3 + # GPLv3 is a copyleft license that would influence our licensing + # Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py + # note that it requires PIL to be installed: http://www.pythonware.com/products/pil/ + idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size*3) + rendering = idcon_render._render() + data = rendering.convert("RGBA").tostring("raw", "RGBA") + qim = QImage(data, size, size, QImage.Format_ARGB32) + pix = QPixmap.fromImage(qim) + idcon = QtGui.QIcon() + idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off) + return idcon + +def avatarize(address): + """ + loads a supported image for the given address' hash form 'avatars' folder + falls back to default avatar if 'default.*' file exists + falls back to identiconize(address) + """ + idcon = QtGui.QIcon() + hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest() + str_broadcast_subscribers = '[Broadcast subscribers]' + if address == str_broadcast_subscribers: + # don't hash [Broadcast subscribers] + hash = address + # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats + # print QImageReader.supportedImageFormats () + # QImageReader.supportedImageFormats () + extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] + # try to find a specific avatar + for ext in extensions: + lower_hash = shared.appdata + 'avatars/' + hash + '.' + ext.lower() + upper_hash = shared.appdata + 'avatars/' + hash + '.' + ext.upper() + if os.path.isfile(lower_hash): + # print 'found avatar of ', address + idcon.addFile(lower_hash) + return idcon + elif os.path.isfile(upper_hash): + # print 'found avatar of ', address + idcon.addFile(upper_hash) + return idcon + # if we haven't found any, try to find a default avatar + for ext in extensions: + lower_default = shared.appdata + 'avatars/' + 'default.' + ext.lower() + upper_default = shared.appdata + 'avatars/' + 'default.' + ext.upper() + if os.path.isfile(lower_default): + default = lower_default + idcon.addFile(lower_default) + return idcon + elif os.path.isfile(upper_default): + default = upper_default + idcon.addFile(upper_default) + return idcon + # If no avatar is found + return identiconize(address) + +def change_translation(locale): + global qtranslator + qtranslator = QtCore.QTranslator() + translationpath = os.path.join( + getattr(sys, '_MEIPASS', sys.path[0]), + 'translations', + 'bitmessage_' + locale + ) + qtranslator.load(translationpath) + QtGui.QApplication.installTranslator(qtranslator) -class MyForm(settingsmixin.SMainWindow): +class MyForm(QtGui.QMainWindow): + + # sound type constants + SOUND_NONE = 0 + SOUND_KNOWN = 1 + SOUND_UNKNOWN = 2 + SOUND_CONNECTED = 3 + SOUND_DISCONNECTED = 4 + SOUND_CONNECTION_GREEN = 5 # the last time that a message arrival sound was played - lastSoundTime = datetime.now() - timedelta(days=1) + lastSoundTime = datetime.datetime.now() - datetime.timedelta(days=1) # the maximum frequency of message sounds in seconds maxSoundFrequencySec = 60 - REPLY_TYPE_SENDER = 0 - REPLY_TYPE_CHAN = 1 + str_broadcast_subscribers = '[Broadcast subscribers]' + str_chan = '[chan]' def init_file_menu(self): QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL( "triggered()"), self.quit) - QtCore.QObject.connect(self.ui.actionNetworkSwitch, QtCore.SIGNAL( - "triggered()"), self.network_switch) QtCore.QObject.connect(self.ui.actionManageKeys, QtCore.SIGNAL( "triggered()"), self.click_actionManageKeys) QtCore.QObject.connect(self.ui.actionDeleteAllTrashedMessages, @@ -137,29 +199,39 @@ class MyForm(settingsmixin.SMainWindow): QtCore.SIGNAL( "triggered()"), self.click_actionRegenerateDeterministicAddresses) - QtCore.QObject.connect(self.ui.pushButtonAddChan, QtCore.SIGNAL( - "clicked()"), + QtCore.QObject.connect(self.ui.actionJoinChan, QtCore.SIGNAL( + "triggered()"), self.click_actionJoinChan) # also used for creating chans. QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL( "clicked()"), self.click_NewAddressDialog) + QtCore.QObject.connect(self.ui.comboBoxSendFrom, QtCore.SIGNAL( + "activated(int)"), self.redrawLabelFrom) QtCore.QObject.connect(self.ui.pushButtonAddAddressBook, QtCore.SIGNAL( "clicked()"), self.click_pushButtonAddAddressBook) QtCore.QObject.connect(self.ui.pushButtonAddSubscription, QtCore.SIGNAL( "clicked()"), self.click_pushButtonAddSubscription) + QtCore.QObject.connect(self.ui.pushButtonAddBlacklist, QtCore.SIGNAL( + "clicked()"), self.click_pushButtonAddBlacklist) QtCore.QObject.connect(self.ui.pushButtonTTL, QtCore.SIGNAL( "clicked()"), self.click_pushButtonTTL) - QtCore.QObject.connect(self.ui.pushButtonClear, QtCore.SIGNAL( - "clicked()"), self.click_pushButtonClear) QtCore.QObject.connect(self.ui.pushButtonSend, QtCore.SIGNAL( "clicked()"), self.click_pushButtonSend) + QtCore.QObject.connect(self.ui.pushButtonLoadFromAddressBook, + QtCore.SIGNAL( + "clicked()"), + self.click_pushButtonLoadFromAddressBook) QtCore.QObject.connect(self.ui.pushButtonFetchNamecoinID, QtCore.SIGNAL( "clicked()"), self.click_pushButtonFetchNamecoinID) + QtCore.QObject.connect(self.ui.radioButtonBlacklist, QtCore.SIGNAL( + "clicked()"), self.click_radioButtonBlacklist) + QtCore.QObject.connect(self.ui.radioButtonWhitelist, QtCore.SIGNAL( + "clicked()"), self.click_radioButtonWhitelist) + QtCore.QObject.connect(self.ui.pushButtonStatusIcon, QtCore.SIGNAL( + "clicked()"), self.click_pushButtonStatusIcon) QtCore.QObject.connect(self.ui.actionSettings, QtCore.SIGNAL( "triggered()"), self.click_actionSettings) QtCore.QObject.connect(self.ui.actionAbout, QtCore.SIGNAL( "triggered()"), self.click_actionAbout) - QtCore.QObject.connect(self.ui.actionSupport, QtCore.SIGNAL( - "triggered()"), self.click_actionSupport) QtCore.QObject.connect(self.ui.actionHelp, QtCore.SIGNAL( "triggered()"), self.click_actionHelp) @@ -168,23 +240,14 @@ class MyForm(settingsmixin.SMainWindow): self.ui.inboxContextMenuToolbar = QtGui.QToolBar() # Actions self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate( - "MainWindow", "Reply to sender"), self.on_action_InboxReply) - self.actionReplyChan = self.ui.inboxContextMenuToolbar.addAction(_translate( - "MainWindow", "Reply to channel"), self.on_action_InboxReplyChan) + "MainWindow", "Reply"), self.on_action_InboxReply) self.actionAddSenderToAddressBook = self.ui.inboxContextMenuToolbar.addAction( _translate( "MainWindow", "Add sender to your Address Book"), self.on_action_InboxAddSenderToAddressBook) - self.actionAddSenderToBlackList = self.ui.inboxContextMenuToolbar.addAction( - _translate( - "MainWindow", "Add sender to your Blacklist"), - self.on_action_InboxAddSenderToBlackList) self.actionTrashInboxMessage = self.ui.inboxContextMenuToolbar.addAction( _translate("MainWindow", "Move to Trash"), self.on_action_InboxTrash) - self.actionUndeleteTrashedMessage = self.ui.inboxContextMenuToolbar.addAction( - _translate("MainWindow", "Undelete"), - self.on_action_TrashUndelete) self.actionForceHtml = self.ui.inboxContextMenuToolbar.addAction( _translate( "MainWindow", "View HTML code as formatted text"), @@ -196,101 +259,61 @@ class MyForm(settingsmixin.SMainWindow): self.actionMarkUnread = self.ui.inboxContextMenuToolbar.addAction( _translate( "MainWindow", "Mark Unread"), self.on_action_InboxMarkUnread) - - # contextmenu messagelists self.ui.tableWidgetInbox.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: self.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuInbox) - self.ui.tableWidgetInboxSubscriptions.setContextMenuPolicy( - QtCore.Qt.CustomContextMenu) - if connectSignal: - self.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL( - 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuInbox) - self.ui.tableWidgetInboxChans.setContextMenuPolicy( - QtCore.Qt.CustomContextMenu) - if connectSignal: - self.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL( - 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuInbox) + self.popMenuInbox = QtGui.QMenu(self) + self.popMenuInbox.addAction(self.actionForceHtml) + self.popMenuInbox.addAction(self.actionMarkUnread) + self.popMenuInbox.addSeparator() + self.popMenuInbox.addAction(self.actionReply) + self.popMenuInbox.addAction(self.actionAddSenderToAddressBook) + self.popMenuInbox.addSeparator() + self.popMenuInbox.addAction(self.actionSaveMessageAs) + self.popMenuInbox.addAction(self.actionTrashInboxMessage) def init_identities_popup_menu(self, connectSignal=True): # Popup menu for the Your Identities tab - self.ui.addressContextMenuToolbarYourIdentities = QtGui.QToolBar() - # Actions - self.actionNewYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction(_translate( - "MainWindow", "New"), self.on_action_YourIdentitiesNew) - self.actionEnableYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Enable"), self.on_action_Enable) - self.actionDisableYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Disable"), self.on_action_Disable) - self.actionSetAvatarYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Set avatar..."), - self.on_action_TreeWidgetSetAvatar) - self.actionClipboardYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Copy address to clipboard"), - self.on_action_Clipboard) - self.actionSpecialAddressBehaviorYourIdentities = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Special address behavior..."), - self.on_action_SpecialAddressBehaviorDialog) - self.actionEmailGateway = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Email gateway"), - self.on_action_EmailGatewayDialog) - self.actionMarkAllRead = self.ui.addressContextMenuToolbarYourIdentities.addAction( - _translate( - "MainWindow", "Mark all messages as read"), - self.on_action_MarkAllRead) - - self.ui.treeWidgetYourIdentities.setContextMenuPolicy( - QtCore.Qt.CustomContextMenu) - if connectSignal: - self.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL( - 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuYourIdentities) - - def init_chan_popup_menu(self, connectSignal=True): - # Popup menu for the Channels tab self.ui.addressContextMenuToolbar = QtGui.QToolBar() # Actions self.actionNew = self.ui.addressContextMenuToolbar.addAction(_translate( "MainWindow", "New"), self.on_action_YourIdentitiesNew) - self.actionDelete = self.ui.addressContextMenuToolbar.addAction( - _translate("MainWindow", "Delete"), - self.on_action_YourIdentitiesDelete) self.actionEnable = self.ui.addressContextMenuToolbar.addAction( _translate( - "MainWindow", "Enable"), self.on_action_Enable) + "MainWindow", "Enable"), self.on_action_YourIdentitiesEnable) self.actionDisable = self.ui.addressContextMenuToolbar.addAction( _translate( - "MainWindow", "Disable"), self.on_action_Disable) + "MainWindow", "Disable"), self.on_action_YourIdentitiesDisable) self.actionSetAvatar = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Set avatar..."), - self.on_action_TreeWidgetSetAvatar) + self.on_action_YourIdentitiesSetAvatar) self.actionClipboard = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Copy address to clipboard"), - self.on_action_Clipboard) + self.on_action_YourIdentitiesClipboard) self.actionSpecialAddressBehavior = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Special address behavior..."), self.on_action_SpecialAddressBehaviorDialog) - - self.ui.treeWidgetChans.setContextMenuPolicy( + self.ui.tableWidgetYourIdentities.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: - self.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( + self.connect(self.ui.tableWidgetYourIdentities, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuChan) + self.on_context_menuYourIdentities) + self.popMenu = QtGui.QMenu(self) + self.popMenu.addAction(self.actionNew) + self.popMenu.addSeparator() + self.popMenu.addAction(self.actionClipboard) + self.popMenu.addSeparator() + self.popMenu.addAction(self.actionEnable) + self.popMenu.addAction(self.actionDisable) + self.popMenu.addAction(self.actionSetAvatar) + self.popMenu.addAction(self.actionSpecialAddressBehavior) def init_addressbook_popup_menu(self, connectSignal=True): # Popup menu for the Address Book page @@ -312,10 +335,6 @@ class MyForm(settingsmixin.SMainWindow): _translate( "MainWindow", "Set avatar..."), self.on_action_AddressBookSetAvatar) - self.actionAddressBookSetSound = \ - self.ui.addressBookContextMenuToolbar.addAction( - _translate("MainWindow", "Set notification sound..."), - self.on_action_AddressBookSetSound) self.actionAddressBookNew = self.ui.addressBookContextMenuToolbar.addAction( _translate( "MainWindow", "Add New Address"), self.on_action_AddressBookNew) @@ -328,6 +347,14 @@ class MyForm(settingsmixin.SMainWindow): self.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuAddressBook) + self.popMenuAddressBook = QtGui.QMenu(self) + self.popMenuAddressBook.addAction(self.actionAddressBookSend) + self.popMenuAddressBook.addAction(self.actionAddressBookClipboard) + self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe) + self.popMenuAddressBook.addAction(self.actionAddressBookSetAvatar) + self.popMenuAddressBook.addSeparator() + self.popMenuAddressBook.addAction(self.actionAddressBookNew) + self.popMenuAddressBook.addAction(self.actionAddressBookDelete) def init_subscriptions_popup_menu(self, connectSignal=True): # Popup menu for the Subscriptions page @@ -349,13 +376,22 @@ class MyForm(settingsmixin.SMainWindow): self.on_action_SubscriptionsDisable) self.actionsubscriptionsSetAvatar = self.ui.subscriptionsContextMenuToolbar.addAction( _translate("MainWindow", "Set avatar..."), - self.on_action_TreeWidgetSetAvatar) - self.ui.treeWidgetSubscriptions.setContextMenuPolicy( + self.on_action_SubscriptionsSetAvatar) + self.ui.tableWidgetSubscriptions.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: - self.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( + self.connect(self.ui.tableWidgetSubscriptions, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuSubscriptions) + self.popMenuSubscriptions = QtGui.QMenu(self) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete) + self.popMenuSubscriptions.addSeparator() + self.popMenuSubscriptions.addAction(self.actionsubscriptionsEnable) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsDisable) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsSetAvatar) + self.popMenuSubscriptions.addSeparator() + self.popMenuSubscriptions.addAction(self.actionsubscriptionsClipboard) def init_sent_popup_menu(self, connectSignal=True): # Popup menu for the Sent page @@ -371,207 +407,55 @@ class MyForm(settingsmixin.SMainWindow): self.actionForceSend = self.ui.sentContextMenuToolbar.addAction( _translate( "MainWindow", "Force send"), self.on_action_ForceSend) + self.ui.tableWidgetSent.setContextMenuPolicy( + QtCore.Qt.CustomContextMenu) + if connectSignal: + self.connect(self.ui.tableWidgetSent, QtCore.SIGNAL( + 'customContextMenuRequested(const QPoint&)'), + self.on_context_menuSent) # self.popMenuSent = QtGui.QMenu( self ) # self.popMenuSent.addAction( self.actionSentClipboard ) # self.popMenuSent.addAction( self.actionTrashSentMessage ) - def rerenderTabTreeSubscriptions(self): - treeWidget = self.ui.treeWidgetSubscriptions - folders = Ui_FolderWidget.folderWeight.keys() - folders.remove("new") - - # sort ascending when creating - if treeWidget.topLevelItemCount() == 0: - treeWidget.header().setSortIndicator( - 0, QtCore.Qt.AscendingOrder) - # init dictionary - - db = getSortedSubscriptions(True) - for address in db: - for folder in folders: - if not folder in db[address]: - db[address][folder] = {} - - if treeWidget.isSortingEnabled(): - treeWidget.setSortingEnabled(False) - - widgets = {} - i = 0 - while i < treeWidget.topLevelItemCount(): - widget = treeWidget.topLevelItem(i) - if widget is not None: - toAddress = widget.address - else: - toAddress = None - - if not toAddress in db: - treeWidget.takeTopLevelItem(i) - # no increment - continue - unread = 0 - j = 0 - while j < widget.childCount(): - subwidget = widget.child(j) - try: - subwidget.setUnreadCount(db[toAddress][subwidget.folderName]['count']) - unread += db[toAddress][subwidget.folderName]['count'] - db[toAddress].pop(subwidget.folderName, None) - except: - widget.takeChild(j) - # no increment - continue - j += 1 - - # add missing folders - if len(db[toAddress]) > 0: - j = 0 - for f, c in db[toAddress].iteritems(): - try: - subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count']) - except KeyError: - subwidget = Ui_FolderWidget(widget, j, toAddress, f, 0) - j += 1 - widget.setUnreadCount(unread) - db.pop(toAddress, None) - i += 1 - - i = 0 - for toAddress in db: - widget = Ui_SubscriptionWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]['count'], db[toAddress]["inbox"]['label'], db[toAddress]["inbox"]['enabled']) - j = 0 - unread = 0 - for folder in folders: - try: - subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]['count']) - unread += db[toAddress][folder]['count'] - except KeyError: - subwidget = Ui_FolderWidget(widget, j, toAddress, folder, 0) - j += 1 - widget.setUnreadCount(unread) - i += 1 - - treeWidget.setSortingEnabled(True) - - - def rerenderTabTreeMessages(self): - self.rerenderTabTree('messages') - - def rerenderTabTreeChans(self): - self.rerenderTabTree('chan') - - def rerenderTabTree(self, tab): - if tab == 'messages': - treeWidget = self.ui.treeWidgetYourIdentities - elif tab == 'chan': - treeWidget = self.ui.treeWidgetChans - folders = Ui_FolderWidget.folderWeight.keys() - - # sort ascending when creating - if treeWidget.topLevelItemCount() == 0: - treeWidget.header().setSortIndicator( - 0, QtCore.Qt.AscendingOrder) - # init dictionary - db = {} - enabled = {} - - for toAddress in getSortedAccounts(): - isEnabled = BMConfigParser().getboolean( - toAddress, 'enabled') - isChan = BMConfigParser().safeGetBoolean( - toAddress, 'chan') - isMaillinglist = BMConfigParser().safeGetBoolean( - toAddress, 'mailinglist') - - if treeWidget == self.ui.treeWidgetYourIdentities: - if isChan: - continue - elif treeWidget == self.ui.treeWidgetChans: - if not isChan: - continue - - db[toAddress] = {} - for folder in folders: - db[toAddress][folder] = 0 - - enabled[toAddress] = isEnabled - - # get number of (unread) messages - total = 0 - queryreturn = sqlQuery('SELECT toaddress, folder, count(msgid) as cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder') - for row in queryreturn: - toaddress, folder, cnt = row - total += cnt - if toaddress in db and folder in db[toaddress]: - db[toaddress][folder] = cnt - if treeWidget == self.ui.treeWidgetYourIdentities: - db[None] = {} - db[None]["inbox"] = total - db[None]["new"] = total - db[None]["sent"] = 0 - db[None]["trash"] = 0 - enabled[None] = True - - if treeWidget.isSortingEnabled(): - treeWidget.setSortingEnabled(False) - - widgets = {} - i = 0 - while i < treeWidget.topLevelItemCount(): - widget = treeWidget.topLevelItem(i) - if widget is not None: - toAddress = widget.address - else: - toAddress = None - - if not toAddress in db: - treeWidget.takeTopLevelItem(i) - # no increment - continue - unread = 0 - j = 0 - while j < widget.childCount(): - subwidget = widget.child(j) - try: - subwidget.setUnreadCount(db[toAddress][subwidget.folderName]) - if subwidget.folderName not in ["new", "trash", "sent"]: - unread += db[toAddress][subwidget.folderName] - db[toAddress].pop(subwidget.folderName, None) - except: - widget.takeChild(j) - # no increment - continue - j += 1 - - # add missing folders - if len(db[toAddress]) > 0: - j = 0 - for f, c in db[toAddress].iteritems(): - if toAddress is not None and tab == 'messages' and folder == "new": - continue - subwidget = Ui_FolderWidget(widget, j, toAddress, f, c) - if subwidget.folderName not in ["new", "trash", "sent"]: - unread += c - j += 1 - widget.setUnreadCount(unread) - db.pop(toAddress, None) - i += 1 - - i = 0 - for toAddress in db: - widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"], enabled[toAddress]) - j = 0 - unread = 0 - for folder in folders: - if toAddress is not None and tab == 'messages' and folder == "new": - continue - subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]) - if subwidget.folderName not in ["new", "trash", "sent"]: - unread += db[toAddress][folder] - j += 1 - widget.setUnreadCount(unread) - i += 1 - - treeWidget.setSortingEnabled(True) + def init_blacklist_popup_menu(self, connectSignal=True): + # Popup menu for the Blacklist page + self.ui.blacklistContextMenuToolbar = QtGui.QToolBar() + # Actions + self.actionBlacklistNew = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Add new entry"), self.on_action_BlacklistNew) + self.actionBlacklistDelete = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Delete"), self.on_action_BlacklistDelete) + self.actionBlacklistClipboard = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Copy address to clipboard"), + self.on_action_BlacklistClipboard) + self.actionBlacklistEnable = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Enable"), self.on_action_BlacklistEnable) + self.actionBlacklistDisable = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Disable"), self.on_action_BlacklistDisable) + self.actionBlacklistSetAvatar = self.ui.blacklistContextMenuToolbar.addAction( + _translate( + "MainWindow", "Set avatar..."), + self.on_action_BlacklistSetAvatar) + self.ui.tableWidgetBlacklist.setContextMenuPolicy( + QtCore.Qt.CustomContextMenu) + if connectSignal: + self.connect(self.ui.tableWidgetBlacklist, QtCore.SIGNAL( + 'customContextMenuRequested(const QPoint&)'), + self.on_context_menuBlacklist) + self.popMenuBlacklist = QtGui.QMenu(self) + # self.popMenuBlacklist.addAction( self.actionBlacklistNew ) + self.popMenuBlacklist.addAction(self.actionBlacklistDelete) + self.popMenuBlacklist.addSeparator() + self.popMenuBlacklist.addAction(self.actionBlacklistClipboard) + self.popMenuBlacklist.addSeparator() + self.popMenuBlacklist.addAction(self.actionBlacklistEnable) + self.popMenuBlacklist.addAction(self.actionBlacklistDisable) + self.popMenuBlacklist.addAction(self.actionBlacklistSetAvatar) def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) @@ -580,28 +464,30 @@ class MyForm(settingsmixin.SMainWindow): # Ask the user if we may delete their old version 1 addresses if they # have any. - for addressInKeysFile in getSortedAccounts(): - status, addressVersionNumber, streamNumber, hash = decodeAddress( - addressInKeysFile) - if addressVersionNumber == 1: - displayMsg = _translate( - "MainWindow", "One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. " - + "May we delete it now?").arg(addressInKeysFile) - reply = QtGui.QMessageBox.question( - self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) - if reply == QtGui.QMessageBox.Yes: - BMConfigParser().remove_section(addressInKeysFile) - BMConfigParser().save() + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + status, addressVersionNumber, streamNumber, hash = decodeAddress( + addressInKeysFile) + if addressVersionNumber == 1: + displayMsg = _translate( + "MainWindow", "One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. " + + "May we delete it now?").arg(addressInKeysFile) + reply = QtGui.QMessageBox.question( + self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) + if reply == QtGui.QMessageBox.Yes: + shared.config.remove_section(addressInKeysFile) + shared.writeKeysFile() # Configure Bitmessage to start on startup (or remove the # configuration) based on the setting in the keys.dat file if 'win32' in sys.platform or 'win64' in sys.platform: # Auto-startup for Windows RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" - self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat) + self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) self.settings.remove( "PyBitmessage") # In case the user moves the program and the registry entry is no longer valid, this will delete the old registry entry. - if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): + if shared.config.getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) elif 'darwin' in sys.platform: # startup for mac @@ -610,36 +496,63 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux pass - # e.g. for editing labels - self.recurDepth = 0 - - # switch back to this when replying - self.replyFromTab = None - # so that quit won't loop - self.quitAccepted = False + self.totalNumberOfBytesReceived = 0 + self.totalNumberOfBytesSent = 0 + self.ui.labelSendBroadcastWarning.setVisible(False) + + self.timer = QtCore.QTimer() + self.timer.start(2000) # milliseconds + QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + self.init_file_menu() self.init_inbox_popup_menu() self.init_identities_popup_menu() self.init_addressbook_popup_menu() self.init_subscriptions_popup_menu() - self.init_chan_popup_menu() self.init_sent_popup_menu() + self.init_blacklist_popup_menu() - # Initialize the user's list of addresses on the 'Chan' tab. - self.rerenderTabTreeChans() + # Initialize the user's list of addresses on the 'Your Identities' tab. + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + isEnabled = shared.config.getboolean( + addressInKeysFile, 'enabled') + newItem = QtGui.QTableWidgetItem(unicode( + shared.config.get(addressInKeysFile, 'label'), 'utf-8)')) + if not isEnabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetYourIdentities.insertRow(0) + newItem.setIcon(avatarize(addressInKeysFile)) + self.ui.tableWidgetYourIdentities.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(addressInKeysFile) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): + newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange + if not isEnabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + if shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): + newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta + self.ui.tableWidgetYourIdentities.setItem(0, 1, newItem) + newItem = QtGui.QTableWidgetItem(str( + decodeAddress(addressInKeysFile)[2])) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not isEnabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetYourIdentities.setItem(0, 2, newItem) + if isEnabled: + status, addressVersionNumber, streamNumber, hash = decodeAddress( + addressInKeysFile) - # Initialize the user's list of addresses on the 'Messages' tab. - self.rerenderTabTreeMessages() + # Load inbox from messages database file + self.loadInbox() - # Set welcome message - self.ui.textEditInboxMessage.setText(_translate("MainWindow", """ - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - """)) + # Load Sent items from database + self.loadSent() # Initialize the address book self.rerenderAddressBook() @@ -649,79 +562,49 @@ class MyForm(settingsmixin.SMainWindow): # Initialize the inbox search QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditReturnPressed) - QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditReturnPressed) - QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditReturnPressed) - QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL( - "textChanged(QString)"), self.inboxSearchLineEditUpdated) - QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL( - "textChanged(QString)"), self.inboxSearchLineEditUpdated) - QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL( - "textChanged(QString)"), self.inboxSearchLineEditUpdated) + "returnPressed()"), self.inboxSearchLineEditPressed) - # Initialize addressbook + # Initialize the sent search + QtCore.QObject.connect(self.ui.sentSearchLineEdit, QtCore.SIGNAL( + "returnPressed()"), self.sentSearchLineEditPressed) + + # Initialize the Blacklist or Whitelist + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': + self.ui.tabWidget.setTabText(6, 'Whitelist') + self.ui.radioButtonWhitelist.click() + self.rerenderBlackWhiteList() + + QtCore.QObject.connect(self.ui.tableWidgetYourIdentities, QtCore.SIGNAL( + "itemChanged(QTableWidgetItem *)"), self.tableWidgetYourIdentitiesItemChanged) QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( "itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged) - # This is necessary for the completer to work if multiple recipients - QtCore.QObject.connect(self.ui.lineEditTo, QtCore.SIGNAL( - "cursorPositionChanged(int, int)"), self.ui.lineEditTo.completer().onCursorPositionChanged) - - # show messages from message list + QtCore.QObject.connect(self.ui.tableWidgetSubscriptions, QtCore.SIGNAL( + "itemChanged(QTableWidgetItem *)"), self.tableWidgetSubscriptionsItemChanged) QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL( "itemSelectionChanged ()"), self.tableWidgetInboxItemClicked) - QtCore.QObject.connect(self.ui.tableWidgetInboxSubscriptions, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.tableWidgetInboxItemClicked) - QtCore.QObject.connect(self.ui.tableWidgetInboxChans, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.tableWidgetInboxItemClicked) - - # tree address lists - QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.treeWidgetItemClicked) - QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL( - "itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged) - QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.treeWidgetItemClicked) - QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( - "itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged) - QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.treeWidgetItemClicked) - QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( - "itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged) - QtCore.QObject.connect( - self.ui.tabWidget, QtCore.SIGNAL("currentChanged(int)"), - self.tabWidgetCurrentChanged - ) + QtCore.QObject.connect(self.ui.tableWidgetSent, QtCore.SIGNAL( + "itemSelectionChanged ()"), self.tableWidgetSentItemClicked) # Put the colored icon on the status bar - # self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) - self.setStatusBar(BMStatusBar()) + # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) self.statusbar = self.statusBar() - - self.pushButtonStatusIcon = QtGui.QPushButton(self) - self.pushButtonStatusIcon.setText('') - self.pushButtonStatusIcon.setIcon( - QtGui.QIcon(':/newPrefix/images/redicon.png')) - self.pushButtonStatusIcon.setFlat(True) - self.statusbar.insertPermanentWidget(0, self.pushButtonStatusIcon) - QtCore.QObject.connect(self.pushButtonStatusIcon, QtCore.SIGNAL( - "clicked()"), self.click_pushButtonStatusIcon) - + self.statusbar.insertPermanentWidget(0, self.ui.pushButtonStatusIcon) + self.ui.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( + l10n.formatTimestamp())) self.numberOfMessagesProcessed = 0 self.numberOfBroadcastsProcessed = 0 self.numberOfPubkeysProcessed = 0 - self.unreadCount = 0 # Set the icon sizes for the identicons identicon_size = 3*7 self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.treeWidgetChans.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.treeWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.tableWidgetSent.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.tableWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.tableWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.tableWidgetBlacklist.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.UISignalThread = UISignaler.get() + self.UISignalThread = UISignaler() QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -734,49 +617,41 @@ class MyForm(settingsmixin.SMainWindow): "displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayNewInboxMessage) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayNewSentMessage) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( + "updateNetworkStatusTab()"), self.updateNetworkStatusTab) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( + "updateNumberOfMessagesProcessed()"), self.updateNumberOfMessagesProcessed) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( + "updateNumberOfPubkeysProcessed()"), self.updateNumberOfPubkeysProcessed) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( + "updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "setStatusIcon(PyQt_PyObject)"), self.setStatusIcon) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "changedInboxUnread(PyQt_PyObject)"), self.changedInboxUnread) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderMessagelistFromLabels()"), self.rerenderMessagelistFromLabels) + "rerenderInboxFromLabels()"), self.rerenderInboxFromLabels) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderMessgelistToLabels()"), self.rerenderMessagelistToLabels) + "rerenderSentToLabels()"), self.rerenderSentToLabels) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "rerenderAddressBook()"), self.rerenderAddressBook) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "rerenderSubscriptions()"), self.rerenderSubscriptions) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid) + "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "newVersionAvailable(PyQt_PyObject)"), self.newVersionAvailable) + "removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "displayAlert(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayAlert) self.UISignalThread.start() - # Key press in tree view - self.ui.treeWidgetYourIdentities.keyPressEvent = self.treeWidgetKeyPressEvent - self.ui.treeWidgetSubscriptions.keyPressEvent = self.treeWidgetKeyPressEvent - self.ui.treeWidgetChans.keyPressEvent = self.treeWidgetKeyPressEvent - - # Key press in messagelist - self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetKeyPressEvent - self.ui.tableWidgetInboxSubscriptions.keyPressEvent = self.tableWidgetKeyPressEvent - self.ui.tableWidgetInboxChans.keyPressEvent = self.tableWidgetKeyPressEvent - - # Key press in messageview - self.ui.textEditInboxMessage.keyPressEvent = self.textEditKeyPressEvent - self.ui.textEditInboxMessageSubscriptions.keyPressEvent = self.textEditKeyPressEvent - self.ui.textEditInboxMessageChans.keyPressEvent = self.textEditKeyPressEvent - # Below this point, it would be good if all of the necessary global data # structures were initialized. self.rerenderComboBoxSendFrom() - self.rerenderComboBoxSendFromBroadcast() # Put the TTL slider in the correct spot - TTL = BMConfigParser().getint('bitmessagesettings', 'ttl') + TTL = shared.config.getint('bitmessagesettings', 'ttl') if TTL < 3600: # an hour TTL = 3600 elif TTL > 28*24*60*60: # 28 days @@ -786,49 +661,38 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( "valueChanged(int)"), self.updateTTL) - - self.initSettings() - + # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} - options["type"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') - options["host"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpchost') - options["port"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcport') - options["user"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser') - options["password"] = BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword') + options["type"] = shared.config.get('bitmessagesettings', 'namecoinrpctype') + options["host"] = shared.config.get('bitmessagesettings', 'namecoinrpchost') + options["port"] = shared.config.get('bitmessagesettings', 'namecoinrpcport') + options["user"] = shared.config.get('bitmessagesettings', 'namecoinrpcuser') + options["password"] = shared.config.get('bitmessagesettings', 'namecoinrpcpassword') nc = namecoinConnection(options) if nc.test()[0] == 'failed': self.ui.pushButtonFetchNamecoinID.hide() except: - logger.error('There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button') + print 'There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button' self.ui.pushButtonFetchNamecoinID.hide() def updateTTL(self, sliderPosition): TTL = int(sliderPosition ** 3.199 + 3600) self.updateHumanFriendlyTTLDescription(TTL) - BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) - BMConfigParser().save() + shared.config.set('bitmessagesettings', 'ttl', str(TTL)) + shared.writeKeysFile() def updateHumanFriendlyTTLDescription(self, TTL): numberOfHours = int(round(TTL / (60*60))) - font = QtGui.QFont() - stylesheet = "" - if numberOfHours < 48: - self.ui.labelHumanFriendlyTTLDescription.setText( - _translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfHours) + - ", " + - _translate("MainWindow", "not recommended for chans", None, QtCore.QCoreApplication.CodecForTr) - ) - stylesheet = "QLabel { color : red; }" - font.setBold(True) + if numberOfHours == 1: + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "1 hour")) + else: + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%1 hours").arg(numberOfHours)) else: numberOfDays = int(round(TTL / (24*60*60))) - self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n day(s)", None, QtCore.QCoreApplication.CodecForTr, numberOfDays)) - font.setBold(False) - self.ui.labelHumanFriendlyTTLDescription.setStyleSheet(stylesheet) - self.ui.labelHumanFriendlyTTLDescription.setFont(font) + self.ui.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%1 days").arg(numberOfDays)) # Show or hide the application window after clicking an item within the # tray icon or, on Windows, the try icon itself. @@ -836,19 +700,30 @@ class MyForm(settingsmixin.SMainWindow): if not self.actionShow.isChecked(): self.hide() else: + if sys.platform[0:3] == 'win': + self.setWindowFlags(Qt.Window) + # else: + # self.showMaximized() self.show() self.setWindowState( self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) - self.raise_() self.activateWindow() + # pointer to the application + # app = None + # The most recent message + newMessageItem = None + + # The most recent broadcast + newBroadcastItem = None + # show the application window def appIndicatorShow(self): if self.actionShow is None: return if not self.actionShow.isChecked(): self.actionShow.setChecked(True) - self.appIndicatorShowOrHideWindow() + self.appIndicatorShowOrHideWindow() # unchecks the show item on the application indicator def appIndicatorHide(self): @@ -858,12 +733,6 @@ class MyForm(settingsmixin.SMainWindow): self.actionShow.setChecked(False) self.appIndicatorShowOrHideWindow() - def appIndicatorSwitchQuietMode(self): - BMConfigParser().set( - 'bitmessagesettings', 'showtraynotifications', - str(not self.actionQuiet.isChecked()) - ) - # application indicator show or hide """# application indicator show or hide def appIndicatorShowBitmessage(self): @@ -877,308 +746,285 @@ class MyForm(settingsmixin.SMainWindow): self.appIndicatorShowOrHideWindow()""" # Show the program window and select inbox tab - def appIndicatorInbox(self, item=None): + def appIndicatorInbox(self, mm_app, source_id): self.appIndicatorShow() # select inbox - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.inbox) - ) - self.ui.treeWidgetYourIdentities.setCurrentItem( - self.ui.treeWidgetYourIdentities.topLevelItem(0).child(0) - ) - - if item: - self.ui.tableWidgetInbox.setCurrentItem(item) + self.ui.tabWidget.setCurrentIndex(0) + selectedItem = None + if source_id == 'Subscriptions': + # select unread broadcast + if self.newBroadcastItem is not None: + selectedItem = self.newBroadcastItem + self.newBroadcastItem = None + else: + # select unread message + if self.newMessageItem is not None: + selectedItem = self.newMessageItem + self.newMessageItem = None + # make it the current item + if selectedItem is not None: + try: + self.ui.tableWidgetInbox.setCurrentItem(selectedItem) + except Exception: + self.ui.tableWidgetInbox.setCurrentCell(0, 0) self.tableWidgetInboxItemClicked() else: + # just select the first item self.ui.tableWidgetInbox.setCurrentCell(0, 0) + self.tableWidgetInboxItemClicked() # Show the program window and select send tab def appIndicatorSend(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) + self.ui.tabWidget.setCurrentIndex(1) # Show the program window and select subscriptions tab def appIndicatorSubscribe(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.subscriptions) - ) + self.ui.tabWidget.setCurrentIndex(4) - # Show the program window and select channels tab - def appIndicatorChannel(self): + # Show the program window and select the address book tab + def appIndicatorAddressBook(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.chans) - ) - - def updateUnreadStatus(self, widget, row, msgid, unread=True): - """ - Switch unread for item of msgid and related items in - other STableWidgets "All Accounts" and "Chans" - """ - related = [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans] - try: - related.remove(widget) - related = related.pop() - except ValueError: - rrow = None - related = [] - else: - # maybe use instead: - # rrow = related.row(msgid), msgid should be QTableWidgetItem - # related = related.findItems(msgid, QtCore.Qt.MatchExactly), - # returns an empty list - for rrow in xrange(related.rowCount()): - if msgid == str(related.item(rrow, 3).data( - QtCore.Qt.UserRole).toPyObject()): - break - else: - rrow = None - - status = widget.item(row, 0).unread - if status == unread: - font = QtGui.QFont() - font.setBold(not status) - widget.item(row, 3).setFont(font) - for col in (0, 1, 2): - widget.item(row, col).setUnread(not status) - - try: - related.item(rrow, 3).setFont(font) - except (TypeError, AttributeError): - pass - else: - for col in (0, 1, 2): - related.item(rrow, col).setUnread(not status) - - def propagateUnreadCount(self, address = None, folder = "inbox", widget = None, type = 1): - widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] - queryReturn = sqlQuery("SELECT toaddress, folder, COUNT(msgid) AS cnt FROM inbox WHERE read = 0 GROUP BY toaddress, folder") - totalUnread = {} - normalUnread = {} - for row in queryReturn: - normalUnread[row[0]] = {} - if row[1] in ["trash"]: - continue - normalUnread[row[0]][row[1]] = row[2] - if row[1] in totalUnread: - totalUnread[row[1]] += row[2] - else: - totalUnread[row[1]] = row[2] - queryReturn = sqlQuery("SELECT fromaddress, folder, COUNT(msgid) AS cnt FROM inbox WHERE read = 0 AND toaddress = ? GROUP BY fromaddress, folder", str_broadcast_subscribers) - broadcastsUnread = {} - for row in queryReturn: - broadcastsUnread[row[0]] = {} - broadcastsUnread[row[0]][row[1]] = row[2] - - for treeWidget in widgets: - root = treeWidget.invisibleRootItem() - for i in range(root.childCount()): - addressItem = root.child(i) - newCount = 0 - if addressItem.type == AccountMixin.ALL: - newCount = sum(totalUnread.itervalues()) - self.drawTrayIcon(self.currentTrayIconFileName, newCount) - elif addressItem.type == AccountMixin.SUBSCRIPTION: - if addressItem.address in broadcastsUnread: - newCount = sum(broadcastsUnread[addressItem.address].itervalues()) - elif addressItem.address in normalUnread: - newCount = sum(normalUnread[addressItem.address].itervalues()) - if newCount != addressItem.unreadCount: - addressItem.setUnreadCount(newCount) - if addressItem.childCount == 0: - continue - for j in range(addressItem.childCount()): - folderItem = addressItem.child(j) - newCount = 0 - folderName = folderItem.folderName - if folderName == "new": - folderName = "inbox" - if addressItem.type == AccountMixin.ALL and folderName in totalUnread: - newCount = totalUnread[folderName] - elif addressItem.type == AccountMixin.SUBSCRIPTION: - if addressItem.address in broadcastsUnread and folderName in broadcastsUnread[addressItem.address]: - newCount = broadcastsUnread[addressItem.address][folderName] - elif addressItem.address in normalUnread and folderName in normalUnread[addressItem.address]: - newCount = normalUnread[addressItem.address][folderName] - if newCount != folderItem.unreadCount: - folderItem.setUnreadCount(newCount) - - def addMessageListItem(self, tableWidget, items): - sortingEnabled = tableWidget.isSortingEnabled() - if sortingEnabled: - tableWidget.setSortingEnabled(False) - tableWidget.insertRow(0) - for i in range(len(items)): - tableWidget.setItem(0, i, items[i]) - if sortingEnabled: - tableWidget.setSortingEnabled(True) - - def addMessageListItemSent(self, tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime): - acct = accountClass(fromAddress) - if acct is None: - acct = BMAccount(fromAddress) - acct.parseMessage(toAddress, fromAddress, subject, "") - - items = [] - MessageList_AddressWidget(items, str(toAddress), unicode(acct.toLabel, 'utf-8')) - MessageList_AddressWidget(items, str(fromAddress), unicode(acct.fromLabel, 'utf-8')) - MessageList_SubjectWidget(items, str(subject), unicode(acct.subject, 'utf-8', 'replace')) - - if status == 'awaitingpubkey': - statusText = _translate( - "MainWindow", "Waiting for their encryption key. Will request it again soon.") - elif status == 'doingpowforpubkey': - statusText = _translate( - "MainWindow", "Doing work necessary to request encryption key.") - elif status == 'msgqueued': - statusText = _translate( - "MainWindow", "Queued.") - elif status == 'msgsent': - statusText = _translate("MainWindow", "Message sent. Waiting for acknowledgement. Sent at %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'msgsentnoackexpected': - statusText = _translate("MainWindow", "Message sent. Sent at %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'doingmsgpow': - statusText = _translate( - "MainWindow", "Doing work necessary to send message.") - elif status == 'ackreceived': - statusText = _translate("MainWindow", "Acknowledgement of the message received %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'broadcastqueued': - statusText = _translate( - "MainWindow", "Broadcast queued.") - elif status == 'doingbroadcastpow': - statusText = _translate( - "MainWindow", "Doing work necessary to send broadcast.") - elif status == 'broadcastsent': - statusText = _translate("MainWindow", "Broadcast on %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'toodifficult': - statusText = _translate("MainWindow", "Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'badkey': - statusText = _translate("MainWindow", "Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg( - l10n.formatTimestamp(lastactiontime)) - elif status == 'forcepow': - statusText = _translate( - "MainWindow", "Forced difficulty override. Send should start soon.") - else: - statusText = _translate("MainWindow", "Unknown status: %1 %2").arg(status).arg( - l10n.formatTimestamp(lastactiontime)) - newItem = myTableWidgetItem(statusText) - newItem.setToolTip(statusText) - newItem.setData(QtCore.Qt.UserRole, QtCore.QByteArray(ackdata)) - newItem.setData(33, int(lastactiontime)) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - items.append(newItem) - self.addMessageListItem(tableWidget, items) - return acct - - def addMessageListItemInbox(self, tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read): - font = QtGui.QFont() - font.setBold(True) - if toAddress == str_broadcast_subscribers: - acct = accountClass(fromAddress) - else: - acct = accountClass(toAddress) - if acct is None: - acct = accountClass(fromAddress) - if acct is None: - acct = BMAccount(fromAddress) - acct.parseMessage(toAddress, fromAddress, subject, "") - - items = [] - #to - MessageList_AddressWidget(items, toAddress, unicode(acct.toLabel, 'utf-8'), not read) - # from - MessageList_AddressWidget(items, fromAddress, unicode(acct.fromLabel, 'utf-8'), not read) - # subject - MessageList_SubjectWidget(items, str(subject), unicode(acct.subject, 'utf-8', 'replace'), not read) - # time received - time_item = myTableWidgetItem(l10n.formatTimestamp(received)) - time_item.setToolTip(l10n.formatTimestamp(received)) - time_item.setData(QtCore.Qt.UserRole, QtCore.QByteArray(msgid)) - time_item.setData(33, int(received)) - time_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - time_item.setFont(font) - items.append(time_item) - self.addMessageListItem(tableWidget, items) - return acct + self.ui.tabWidget.setCurrentIndex(5) # Load Sent items from database - def loadSent(self, tableWidget, account, where="", what=""): - if tableWidget == self.ui.tableWidgetInboxSubscriptions: - tableWidget.setColumnHidden(0, True) - tableWidget.setColumnHidden(1, False) - xAddress = 'toaddress' - elif tableWidget == self.ui.tableWidgetInboxChans: - tableWidget.setColumnHidden(0, False) - tableWidget.setColumnHidden(1, True) - xAddress = 'both' + def loadSent(self, where="", what=""): + what = "%" + what + "%" + if where == "To": + where = "toaddress" + elif where == "From": + where = "fromaddress" + elif where == "Subject": + where = "subject" + elif where == "Message": + where = "message" else: - tableWidget.setColumnHidden(0, False) - if account is None: - tableWidget.setColumnHidden(1, False) - else: - tableWidget.setColumnHidden(1, True) - xAddress = 'fromaddress' + where = "toaddress || fromaddress || subject || message" - tableWidget.setUpdatesEnabled(False) - tableWidget.setSortingEnabled(False) - tableWidget.setRowCount(0) - queryreturn = helper_search.search_sql(xAddress, account, "sent", where, what, False) + sqlStatement = ''' + SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime + FROM sent WHERE folder="sent" AND %s LIKE ? + ORDER BY lastactiontime + ''' % (where,) + while self.ui.tableWidgetSent.rowCount() > 0: + self.ui.tableWidgetSent.removeRow(0) + + queryreturn = sqlQuery(sqlStatement, what) for row in queryreturn: toAddress, fromAddress, subject, status, ackdata, lastactiontime = row - self.addMessageListItemSent(tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime) + subject = shared.fixPotentiallyInvalidUTF8Data(subject) - tableWidget.horizontalHeader().setSortIndicator( - 3, QtCore.Qt.DescendingOrder) - tableWidget.setSortingEnabled(True) - tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Sent", None)) - tableWidget.setUpdatesEnabled(True) + if shared.config.has_section(fromAddress): + fromLabel = shared.config.get(fromAddress, 'label') + else: + fromLabel = fromAddress - # Load messages from database file - def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what="", unreadOnly = False): - if folder == 'sent': - self.loadSent(tableWidget, account, where, what) - return + toLabel = '' + queryreturn = sqlQuery( + '''select label from addressbook where address=?''', toAddress) + if queryreturn != []: + for row in queryreturn: + toLabel, = row + if toLabel == '': + # It might be a broadcast message. We should check for that + # label. + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', toAddress) - if tableWidget == self.ui.tableWidgetInboxSubscriptions: - xAddress = "fromaddress" + if queryreturn != []: + for row in queryreturn: + toLabel, = row + + if toLabel == '': + if shared.config.has_section(toAddress): + toLabel = shared.config.get(toAddress, 'label') + if toLabel == '': + toLabel = toAddress + + self.ui.tableWidgetSent.insertRow(0) + toAddressItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) + toAddressItem.setToolTip(unicode(toLabel, 'utf-8')) + toAddressItem.setIcon(avatarize(toAddress)) + toAddressItem.setData(Qt.UserRole, str(toAddress)) + toAddressItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetSent.setItem(0, 0, toAddressItem) + + if fromLabel == '': + fromLabel = fromAddress + fromAddressItem = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) + fromAddressItem.setToolTip(unicode(fromLabel, 'utf-8')) + fromAddressItem.setIcon(avatarize(fromAddress)) + fromAddressItem.setData(Qt.UserRole, str(fromAddress)) + fromAddressItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetSent.setItem(0, 1, fromAddressItem) + + subjectItem = QtGui.QTableWidgetItem(unicode(subject, 'utf-8')) + subjectItem.setToolTip(unicode(subject, 'utf-8')) + subjectItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetSent.setItem(0, 2, subjectItem) + + if status == 'awaitingpubkey': + statusText = _translate( + "MainWindow", "Waiting for their encryption key. Will request it again soon.") + elif status == 'doingpowforpubkey': + statusText = _translate( + "MainWindow", "Encryption key request queued.") + elif status == 'msgqueued': + statusText = _translate( + "MainWindow", "Queued.") + elif status == 'msgsent': + statusText = _translate("MainWindow", "Message sent. Waiting for acknowledgement. Sent at %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'msgsentnoackexpected': + statusText = _translate("MainWindow", "Message sent. Sent at %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'doingmsgpow': + statusText = _translate( + "MainWindow", "Need to do work to send message. Work is queued.") + elif status == 'ackreceived': + statusText = _translate("MainWindow", "Acknowledgement of the message received %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'broadcastqueued': + statusText = _translate( + "MainWindow", "Broadcast queued.") + elif status == 'broadcastsent': + statusText = _translate("MainWindow", "Broadcast on %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'toodifficult': + statusText = _translate("MainWindow", "Problem: The work demanded by the recipient is more difficult than you are willing to do. %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'badkey': + statusText = _translate("MainWindow", "Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1").arg( + l10n.formatTimestamp(lastactiontime)) + elif status == 'forcepow': + statusText = _translate( + "MainWindow", "Forced difficulty override. Send should start soon.") + else: + statusText = _translate("MainWindow", "Unknown status: %1 %2").arg(status).arg( + l10n.formatTimestamp(lastactiontime)) + newItem = myTableWidgetItem(statusText) + newItem.setToolTip(statusText) + newItem.setData(Qt.UserRole, QByteArray(ackdata)) + newItem.setData(33, int(lastactiontime)) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetSent.setItem(0, 3, newItem) + self.ui.tableWidgetSent.sortItems(3, Qt.DescendingOrder) + self.ui.tableWidgetSent.keyPressEvent = self.tableWidgetSentKeyPressEvent + + # Load inbox from messages database file + def loadInbox(self, where="", what=""): + what = "%" + what + "%" + if where == "To": + where = "toaddress" + elif where == "From": + where = "fromaddress" + elif where == "Subject": + where = "subject" + elif where == "Message": + where = "message" else: - xAddress = "toaddress" - if account is not None: - tableWidget.setColumnHidden(0, True) - tableWidget.setColumnHidden(1, False) - else: - tableWidget.setColumnHidden(0, False) - tableWidget.setColumnHidden(1, False) + where = "toaddress || fromaddress || subject || message" - tableWidget.setUpdatesEnabled(False) - tableWidget.setSortingEnabled(False) - tableWidget.setRowCount(0) + sqlStatement = ''' + SELECT msgid, toaddress, fromaddress, subject, received, read + FROM inbox WHERE folder="inbox" AND %s LIKE ? + ORDER BY received + ''' % (where,) - queryreturn = helper_search.search_sql(xAddress, account, folder, where, what, unreadOnly) - + while self.ui.tableWidgetInbox.rowCount() > 0: + self.ui.tableWidgetInbox.removeRow(0) + + font = QFont() + font.setBold(True) + queryreturn = sqlQuery(sqlStatement, what) for row in queryreturn: - msgfolder, msgid, toAddress, fromAddress, subject, received, read = row - self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read) + msgid, toAddress, fromAddress, subject, received, read = row + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + try: + if toAddress == self.str_broadcast_subscribers: + toLabel = self.str_broadcast_subscribers + else: + toLabel = shared.config.get(toAddress, 'label') + except: + toLabel = '' + if toLabel == '': + toLabel = toAddress - tableWidget.horizontalHeader().setSortIndicator( - 3, QtCore.Qt.DescendingOrder) - tableWidget.setSortingEnabled(True) - tableWidget.selectRow(0) - tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Received", None)) - tableWidget.setUpdatesEnabled(True) + fromLabel = '' + if shared.config.has_section(fromAddress): + fromLabel = shared.config.get(fromAddress, 'label') + + if fromLabel == '': # If the fromAddress isn't one of our addresses and isn't a chan + queryreturn = sqlQuery( + '''select label from addressbook where address=?''', fromAddress) + if queryreturn != []: + for row in queryreturn: + fromLabel, = row + + if fromLabel == '': # If this address wasn't in our address book... + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', fromAddress) + if queryreturn != []: + for row in queryreturn: + fromLabel, = row + if fromLabel == '': + fromLabel = fromAddress + + # message row + self.ui.tableWidgetInbox.insertRow(0) + # to + to_item = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) + to_item.setToolTip(unicode(toLabel, 'utf-8')) + to_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + to_item.setFont(font) + to_item.setData(Qt.UserRole, str(toAddress)) + if shared.safeConfigGetBoolean(toAddress, 'mailinglist'): + to_item.setTextColor(QtGui.QColor(137, 04, 177)) # magenta + if shared.safeConfigGetBoolean(str(toAddress), 'chan'): + to_item.setTextColor(QtGui.QColor(216, 119, 0)) # orange + to_item.setIcon(avatarize(toAddress)) + self.ui.tableWidgetInbox.setItem(0, 0, to_item) + # from + from_item = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) + from_item.setToolTip(unicode(fromLabel, 'utf-8')) + from_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + from_item.setFont(font) + from_item.setData(Qt.UserRole, str(fromAddress)) + if shared.safeConfigGetBoolean(str(fromAddress), 'chan'): + from_item.setTextColor(QtGui.QColor(216, 119, 0)) # orange + from_item.setIcon(avatarize(fromAddress)) + self.ui.tableWidgetInbox.setItem(0, 1, from_item) + # subject + subject_item = QtGui.QTableWidgetItem(unicode(subject, 'utf-8')) + subject_item.setToolTip(unicode(subject, 'utf-8')) + subject_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + subject_item.setFont(font) + self.ui.tableWidgetInbox.setItem(0, 2, subject_item) + # time received + time_item = myTableWidgetItem(l10n.formatTimestamp(received)) + time_item.setToolTip(l10n.formatTimestamp(received)) + time_item.setData(Qt.UserRole, QByteArray(msgid)) + time_item.setData(33, int(received)) + time_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + time_item.setFont(font) + self.ui.tableWidgetInbox.setItem(0, 3, time_item) + + self.ui.tableWidgetInbox.sortItems(3, Qt.DescendingOrder) + self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent # create application indicator def appIndicatorInit(self, app): @@ -1187,7 +1033,7 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.tray, QtCore.SIGNAL( traySignal), self.__icon_activated) - m = QtGui.QMenu() + m = QMenu() self.actionStatus = QtGui.QAction(_translate( "MainWindow", "Not Connected"), m, checkable=False) @@ -1201,20 +1047,12 @@ class MyForm(settingsmixin.SMainWindow): # show bitmessage self.actionShow = QtGui.QAction(_translate( "MainWindow", "Show Bitmessage"), m, checkable=True) - self.actionShow.setChecked(not BMConfigParser().getboolean( + self.actionShow.setChecked(not shared.config.getboolean( 'bitmessagesettings', 'startintray')) self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow) if not sys.platform[0:3] == 'win': m.addAction(self.actionShow) - # quiet mode - self.actionQuiet = QtGui.QAction(_translate( - "MainWindow", "Quiet Mode"), m, checkable=True) - self.actionQuiet.setChecked(not BMConfigParser().getboolean( - 'bitmessagesettings', 'showtraynotifications')) - self.actionQuiet.triggered.connect(self.appIndicatorSwitchQuietMode) - m.addAction(self.actionQuiet) - # Send actionSend = QtGui.QAction(_translate( "MainWindow", "Send"), m, checkable=False) @@ -1227,11 +1065,11 @@ class MyForm(settingsmixin.SMainWindow): actionSubscribe.triggered.connect(self.appIndicatorSubscribe) m.addAction(actionSubscribe) - # Channels - actionSubscribe = QtGui.QAction(_translate( - "MainWindow", "Channel"), m, checkable=False) - actionSubscribe.triggered.connect(self.appIndicatorChannel) - m.addAction(actionSubscribe) + # Address book + actionAddressBook = QtGui.QAction(_translate( + "MainWindow", "Address Book"), m, checkable=False) + actionAddressBook.triggered.connect(self.appIndicatorAddressBook) + m.addAction(actionAddressBook) # separator actionSeparator = QtGui.QAction('', m, checkable=False) @@ -1245,364 +1083,525 @@ class MyForm(settingsmixin.SMainWindow): self.tray.setContextMenu(m) self.tray.show() + # Ubuntu Messaging menu object + mmapp = None + + # is the operating system Ubuntu? + def isUbuntu(self): + for entry in platform.uname(): + if "Ubuntu" in entry: + return True + return False + + # When an unread inbox row is selected on then clear the messaging menu + def ubuntuMessagingMenuClear(self, inventoryHash): + global withMessagingMenu + + # if this isn't ubuntu then don't do anything + if not self.isUbuntu(): + return + + # has messageing menu been installed + if not withMessagingMenu: + return + + # if there are no items on the messaging menu then + # the subsequent query can be avoided + if not (self.mmapp.has_source("Subscriptions") or self.mmapp.has_source("Messages")): + return + + queryreturn = sqlQuery( + '''SELECT toaddress, read FROM inbox WHERE msgid=?''', inventoryHash) + for row in queryreturn: + toAddress, read = row + if not read: + if toAddress == self.str_broadcast_subscribers: + if self.mmapp.has_source("Subscriptions"): + self.mmapp.remove_source("Subscriptions") + else: + if self.mmapp.has_source("Messages"): + self.mmapp.remove_source("Messages") + # returns the number of unread messages and subscriptions def getUnread(self): - counters = [0, 0] + unreadMessages = 0 + unreadSubscriptions = 0 - queryreturn = sqlQuery(''' - SELECT msgid, toaddress, read FROM inbox where folder='inbox' - ''') - for msgid, toAddress, read in queryreturn: + queryreturn = sqlQuery( + '''SELECT msgid, toaddress, read FROM inbox where folder='inbox' ''') + for row in queryreturn: + msgid, toAddress, read = row + + try: + if toAddress == self.str_broadcast_subscribers: + toLabel = self.str_broadcast_subscribers + else: + toLabel = shared.config.get(toAddress, 'label') + except: + toLabel = '' + if toLabel == '': + toLabel = toAddress if not read: - # increment the unread subscriptions if True (1) - # else messages (0) - counters[toAddress == str_broadcast_subscribers] += 1 + if toLabel == self.str_broadcast_subscribers: + # increment the unread subscriptions + unreadSubscriptions = unreadSubscriptions + 1 + else: + # increment the unread messages + unreadMessages = unreadMessages + 1 + return unreadMessages, unreadSubscriptions - return counters + # show the number of unread messages and subscriptions on the messaging + # menu + def ubuntuMessagingMenuUnread(self, drawAttention): + unreadMessages, unreadSubscriptions = self.getUnread() + # unread messages + if unreadMessages > 0: + self.mmapp.append_source( + "Messages", None, "Messages (" + str(unreadMessages) + ")") + if drawAttention: + self.mmapp.draw_attention("Messages") + + # unread subscriptions + if unreadSubscriptions > 0: + self.mmapp.append_source("Subscriptions", None, "Subscriptions (" + str( + unreadSubscriptions) + ")") + if drawAttention: + self.mmapp.draw_attention("Subscriptions") + + # initialise the Ubuntu messaging menu + def ubuntuMessagingMenuInit(self): + global withMessagingMenu + + # if this isn't ubuntu then don't do anything + if not self.isUbuntu(): + return + + # has messageing menu been installed + if not withMessagingMenu: + print 'WARNING: MessagingMenu is not available. Is libmessaging-menu-dev installed?' + return + + # create the menu server + if withMessagingMenu: + try: + self.mmapp = MessagingMenu.App( + desktop_id='pybitmessage.desktop') + self.mmapp.register() + self.mmapp.connect('activate-source', self.appIndicatorInbox) + self.ubuntuMessagingMenuUnread(True) + except Exception: + withMessagingMenu = False + print 'WARNING: messaging menu disabled' + + # update the Ubuntu messaging menu + def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel): + global withMessagingMenu + + # if this isn't ubuntu then don't do anything + if not self.isUbuntu(): + return + + # has messageing menu been installed + if not withMessagingMenu: + print 'WARNING: messaging menu disabled or libmessaging-menu-dev not installed' + return + + # remember this item to that the messaging menu can find it + if toLabel == self.str_broadcast_subscribers: + self.newBroadcastItem = newItem + else: + self.newMessageItem = newItem + + # Remove previous messages and subscriptions entries, then recreate them + # There might be a better way to do it than this + if self.mmapp.has_source("Messages"): + self.mmapp.remove_source("Messages") + + if self.mmapp.has_source("Subscriptions"): + self.mmapp.remove_source("Subscriptions") + + # update the menu entries + self.ubuntuMessagingMenuUnread(drawAttention) + + # returns true if the given sound category is a connection sound + # rather than a received message sound + def isConnectionSound(self, category): + if (category is self.SOUND_CONNECTED or + category is self.SOUND_DISCONNECTED or + category is self.SOUND_CONNECTION_GREEN): + return True + return False # play a sound def playSound(self, category, label): # filename of the sound to be played soundFilename = None - def _choose_ext(basename): - for ext in sound.extensions: - if os.path.isfile(os.extsep.join([basename, ext])): - return os.extsep + ext + # whether to play a sound or not + play = True # if the address had a known label in the address book - if label: + if label is not None: # Does a sound file exist for this particular contact? - soundFilename = state.appdata + 'sounds/' + label - ext = _choose_ext(soundFilename) - if not ext: - category = sound.SOUND_KNOWN - soundFilename = None + if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or + os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')): + soundFilename = shared.appdata + 'sounds/' + label + + # Avoid making sounds more frequently than the threshold. + # This suppresses playing sounds repeatedly when there + # are many new messages + if (soundFilename is None and + not self.isConnectionSound(category)): + # elapsed time since the last sound was played + dt = datetime.datetime.now() - self.lastSoundTime + # suppress sounds which are more frequent than the threshold + if dt.total_seconds() < self.maxSoundFrequencySec: + play = False if soundFilename is None: - # Avoid making sounds more frequently than the threshold. - # This suppresses playing sounds repeatedly when there - # are many new messages - if not sound.is_connection_sound(category): - # elapsed time since the last sound was played - dt = datetime.now() - self.lastSoundTime - # suppress sounds which are more frequent than the threshold - if dt.total_seconds() < self.maxSoundFrequencySec: - return - # the sound is for an address which exists in the address book - if category is sound.SOUND_KNOWN: - soundFilename = state.appdata + 'sounds/known' + if category is self.SOUND_KNOWN: + soundFilename = shared.appdata + 'sounds/known' # the sound is for an unknown address - elif category is sound.SOUND_UNKNOWN: - soundFilename = state.appdata + 'sounds/unknown' + elif category is self.SOUND_UNKNOWN: + soundFilename = shared.appdata + 'sounds/unknown' # initial connection sound - elif category is sound.SOUND_CONNECTED: - soundFilename = state.appdata + 'sounds/connected' + elif category is self.SOUND_CONNECTED: + soundFilename = shared.appdata + 'sounds/connected' # disconnected sound - elif category is sound.SOUND_DISCONNECTED: - soundFilename = state.appdata + 'sounds/disconnected' + elif category is self.SOUND_DISCONNECTED: + soundFilename = shared.appdata + 'sounds/disconnected' # sound when the connection status becomes green - elif category is sound.SOUND_CONNECTION_GREEN: - soundFilename = state.appdata + 'sounds/green' + elif category is self.SOUND_CONNECTION_GREEN: + soundFilename = shared.appdata + 'sounds/green' - if soundFilename is None: - logger.warning("Probably wrong category number in playSound()") - return + if soundFilename is not None and play is True: + if not self.isConnectionSound(category): + # record the last time that a received message sound was played + self.lastSoundTime = datetime.datetime.now() - if not sound.is_connection_sound(category): - # record the last time that a received message sound was played - self.lastSoundTime = datetime.now() + # if not wav then try mp3 format + if not os.path.isfile(soundFilename + '.wav'): + soundFilename = soundFilename + '.mp3' + else: + soundFilename = soundFilename + '.wav' - try: # try already known format - soundFilename += ext - except (TypeError, NameError): - ext = _choose_ext(soundFilename) - if not ext: - try: # if no user sound file found try to play from theme - return self._theme_player(category, label) - except TypeError: - return - - soundFilename += ext - - self._player(soundFilename) - - # Adapters and converters for QT <-> sqlite - def sqlInit(self): - register_adapter(QtCore.QByteArray, str) - - # Try init the distro specific appindicator, - # for example the Ubuntu MessagingMenu - def indicatorInit(self): - def _noop_update(*args, **kwargs): - pass - - try: - self.indicatorUpdate = get_plugin('indicator')(self) - except (NameError, TypeError): - logger.warning("No indicator plugin found") - self.indicatorUpdate = _noop_update + if os.path.isfile(soundFilename): + if 'linux' in sys.platform: + # Note: QSound was a nice idea but it didn't work + if '.mp3' in soundFilename: + gst_available=False + try: + subprocess.call(["gst123", soundFilename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + gst_available=True + except: + print "WARNING: gst123 must be installed in order to play mp3 sounds" + if not gst_available: + try: + subprocess.call(["mpg123", soundFilename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + gst_available=True + except: + print "WARNING: mpg123 must be installed in order to play mp3 sounds" + else: + try: + subprocess.call(["aplay", soundFilename], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + except: + print "WARNING: aplay must be installed in order to play WAV sounds" + elif sys.platform[0:3] == 'win': + # use winsound on Windows + import winsound + winsound.PlaySound(soundFilename, winsound.SND_FILENAME) # initialise the message notifier def notifierInit(self): - def _simple_notify( - title, subtitle, category, label=None, icon=None): + global withMessagingMenu + if withMessagingMenu: + Notify.init('pybitmessage') + + # shows a notification + def notifierShow(self, title, subtitle, fromCategory, label): + global withMessagingMenu + + self.playSound(fromCategory, label) + + if withMessagingMenu: + n = Notify.Notification.new( + title, subtitle, 'notification-message-email') + try: + n.show() + except: + # n.show() has been known to throw this exception: + # gi._glib.GError: GDBus.Error:org.freedesktop.Notifications. + # MaxNotificationsExceeded: Exceeded maximum number of + # notifications + pass + return + else: self.tray.showMessage(title, subtitle, 1, 2000) - self._notifier = _simple_notify - # does nothing if isAvailable returns false - self._player = QtGui.QSound.play - - if not get_plugins: - return - - _plugin = get_plugin('notification.message') - if _plugin: - self._notifier = _plugin - else: - logger.warning("No notification.message plugin found") - - self._theme_player = get_plugin('notification.sound', 'theme') - - if not QtGui.QSound.isAvailable(): - _plugin = get_plugin( - 'notification.sound', 'file', fallback='file.fallback') - if _plugin: - self._player = _plugin - else: - logger.warning("No notification.sound plugin found") - - def notifierShow( - self, title, subtitle, category, label=None, icon=None): - self.playSound(category, label) - self._notifier( - unicode(title), unicode(subtitle), category, label, icon) - - # tree - def treeWidgetKeyPressEvent(self, event): - return self.handleKeyPress(event, self.getCurrentTreeWidget()) - - # inbox / sent - def tableWidgetKeyPressEvent(self, event): - return self.handleKeyPress(event, self.getCurrentMessagelist()) - - # messageview - def textEditKeyPressEvent(self, event): - return self.handleKeyPress(event, self.getCurrentMessageTextedit()) - - def handleKeyPress(self, event, focus = None): - messagelist = self.getCurrentMessagelist() - folder = self.getCurrentFolder() + def tableWidgetInboxKeyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Delete: - if isinstance (focus, MessageView) or isinstance(focus, QtGui.QTableWidget): - if folder == "sent": - self.on_action_SentTrash() - else: - self.on_action_InboxTrash() - event.ignore() - elif QtGui.QApplication.queryKeyboardModifiers() == QtCore.Qt.NoModifier: - if event.key() == QtCore.Qt.Key_N: - currentRow = messagelist.currentRow() - if currentRow < messagelist.rowCount() - 1: - messagelist.selectRow(currentRow + 1) - event.ignore() - elif event.key() == QtCore.Qt.Key_P: - currentRow = messagelist.currentRow() - if currentRow > 0: - messagelist.selectRow(currentRow - 1) - event.ignore() - elif event.key() == QtCore.Qt.Key_R: - if messagelist == self.ui.tableWidgetInboxChans: - self.on_action_InboxReplyChan() - else: - self.on_action_InboxReply() - event.ignore() - elif event.key() == QtCore.Qt.Key_C: - currentAddress = self.getCurrentAccount() - if currentAddress: - self.setSendFromComboBox(currentAddress) - self.ui.tabWidgetSend.setCurrentIndex( - self.ui.tabWidgetSend.indexOf(self.ui.sendDirect) - ) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) - self.ui.lineEditTo.setFocus() - event.ignore() - elif event.key() == QtCore.Qt.Key_F: - searchline = self.getCurrentSearchLine(retObj = True) - if searchline: - searchline.setFocus() - event.ignore() - if not event.isAccepted(): - return - if isinstance (focus, MessageView): - return MessageView.keyPressEvent(focus, event) - elif isinstance (focus, QtGui.QTableWidget): - return QtGui.QTableWidget.keyPressEvent(focus, event) - elif isinstance (focus, QtGui.QTreeWidget): - return QtGui.QTreeWidget.keyPressEvent(focus, event) + self.on_action_InboxTrash() + return QtGui.QTableWidget.keyPressEvent(self.ui.tableWidgetInbox, event) + + def tableWidgetSentKeyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Delete: + self.on_action_SentTrash() + return QtGui.QTableWidget.keyPressEvent(self.ui.tableWidgetSent, event) - # menu button 'manage keys' def click_actionManageKeys(self): if 'darwin' in sys.platform or 'linux' in sys.platform: - if state.appdata == '': + if shared.appdata == '': # reply = QtGui.QMessageBox.information(self, 'keys.dat?','You # may manage your keys by editing the keys.dat file stored in # the same directory as this program. It is important that you # back up this file.', QMessageBox.Ok) reply = QtGui.QMessageBox.information(self, 'keys.dat?', _translate( - "MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file."), QtGui.QMessageBox.Ok) + "MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file."), QMessageBox.Ok) else: QtGui.QMessageBox.information(self, 'keys.dat?', _translate( - "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file.").arg(state.appdata), QtGui.QMessageBox.Ok) + "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file.").arg(shared.appdata), QMessageBox.Ok) elif sys.platform == 'win32' or sys.platform == 'win64': - if state.appdata == '': + if shared.appdata == '': reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( "MainWindow", "You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) else: reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( - "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(state.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) + "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(shared.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: shared.openKeysFile() - # menu button 'delete all treshed messages' def click_actionDeleteAllTrashedMessages(self): if QtGui.QMessageBox.question(self, _translate("MainWindow", "Delete trash?"), _translate("MainWindow", "Are you sure you want to delete all trashed messages?"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No: return sqlStoredProcedure('deleteandvacuume') - self.rerenderTabTreeMessages() - self.rerenderTabTreeSubscriptions() - self.rerenderTabTreeChans() - if self.getCurrentFolder(self.ui.treeWidgetYourIdentities) == "trash": - self.loadMessagelist(self.ui.tableWidgetInbox, self.getCurrentAccount(self.ui.treeWidgetYourIdentities), "trash") - elif self.getCurrentFolder(self.ui.treeWidgetSubscriptions) == "trash": - self.loadMessagelist(self.ui.tableWidgetInboxSubscriptions, self.getCurrentAccount(self.ui.treeWidgetSubscriptions), "trash") - elif self.getCurrentFolder(self.ui.treeWidgetChans) == "trash": - self.loadMessagelist(self.ui.tableWidgetInboxChans, self.getCurrentAccount(self.ui.treeWidgetChans), "trash") - # menu button 'regenerate deterministic addresses' def click_actionRegenerateDeterministicAddresses(self): - dialog = dialogs.RegenerateAddressesDialog(self) - if dialog.exec_(): - if dialog.lineEditPassphrase.text() == "": - QtGui.QMessageBox.about( - self, _translate("MainWindow", "bad passphrase"), - _translate( - "MainWindow", - "You must type your passphrase. If you don\'t" - " have one then this is not the form for you." - )) + self.regenerateAddressesDialogInstance = regenerateAddressesDialog( + self) + if self.regenerateAddressesDialogInstance.exec_(): + if self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text() == "": + QMessageBox.about(self, _translate("MainWindow", "bad passphrase"), _translate( + "MainWindow", "You must type your passphrase. If you don\'t have one then this is not the form for you.")) return - streamNumberForAddress = int(dialog.lineEditStreamNumber.text()) + streamNumberForAddress = int( + self.regenerateAddressesDialogInstance.ui.lineEditStreamNumber.text()) try: addressVersionNumber = int( - dialog.lineEditAddressVersionNumber.text()) + self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text()) except: - QtGui.QMessageBox.about( - self, - _translate("MainWindow", "Bad address version number"), - _translate( - "MainWindow", - "Your address version number must be a number:" - " either 3 or 4." - )) + QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate( + "MainWindow", "Your address version number must be a number: either 3 or 4.")) return if addressVersionNumber < 3 or addressVersionNumber > 4: - QtGui.QMessageBox.about( - self, - _translate("MainWindow", "Bad address version number"), - _translate( - "MainWindow", - "Your address version number must be either 3 or 4." - )) + QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate( + "MainWindow", "Your address version number must be either 3 or 4.")) return - queues.addressGeneratorQueue.put(( - 'createDeterministicAddresses', - addressVersionNumber, streamNumberForAddress, - "regenerated deterministic address", - dialog.spinBoxNumberOfAddressesToMake.value(), - dialog.lineEditPassphrase.text().toUtf8(), - dialog.checkBoxEighteenByteRipe.isChecked() - )) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.chans) - ) + shared.addressGeneratorQueue.put(('createDeterministicAddresses', addressVersionNumber, streamNumberForAddress, "regenerated deterministic address", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value( + ), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) + self.ui.tabWidget.setCurrentIndex(3) - # opens 'join chan' dialog def click_actionJoinChan(self): - dialogs.NewChanDialog(self) + self.newChanDialogInstance = newChanDialog(self) + if self.newChanDialogInstance.exec_(): + if self.newChanDialogInstance.ui.radioButtonCreateChan.isChecked(): + if self.newChanDialogInstance.ui.lineEditChanNameCreate.text() == "": + QMessageBox.about(self, _translate("MainWindow", "Chan name needed"), _translate( + "MainWindow", "You didn't enter a chan name.")) + return + shared.apiAddressGeneratorReturnQueue.queue.clear() + shared.addressGeneratorQueue.put(('createChan', 4, 1, self.str_chan + ' ' + str(self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8()), self.newChanDialogInstance.ui.lineEditChanNameCreate.text().toUtf8())) + addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() + print 'addressGeneratorReturnValue', addressGeneratorReturnValue + if len(addressGeneratorReturnValue) == 0: + QMessageBox.about(self, _translate("MainWindow", "Address already present"), _translate( + "MainWindow", "Could not add chan because it appears to already be one of your identities.")) + return + createdAddress = addressGeneratorReturnValue[0] + QMessageBox.about(self, _translate("MainWindow", "Success"), _translate( + "MainWindow", "Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'.").arg(createdAddress)) + self.ui.tabWidget.setCurrentIndex(3) + elif self.newChanDialogInstance.ui.radioButtonJoinChan.isChecked(): + if self.newChanDialogInstance.ui.lineEditChanNameJoin.text() == "": + QMessageBox.about(self, _translate("MainWindow", "Chan name needed"), _translate( + "MainWindow", "You didn't enter a chan name.")) + return + if decodeAddress(self.newChanDialogInstance.ui.lineEditChanBitmessageAddress.text())[0] == 'versiontoohigh': + QMessageBox.about(self, _translate("MainWindow", "Address too new"), _translate( + "MainWindow", "Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage.")) + return + if decodeAddress(self.newChanDialogInstance.ui.lineEditChanBitmessageAddress.text())[0] != 'success': + QMessageBox.about(self, _translate("MainWindow", "Address invalid"), _translate( + "MainWindow", "That Bitmessage address is not valid.")) + return + shared.apiAddressGeneratorReturnQueue.queue.clear() + shared.addressGeneratorQueue.put(('joinChan', addBMIfNotPresent(self.newChanDialogInstance.ui.lineEditChanBitmessageAddress.text()), self.str_chan + ' ' + str(self.newChanDialogInstance.ui.lineEditChanNameJoin.text().toUtf8()), self.newChanDialogInstance.ui.lineEditChanNameJoin.text().toUtf8())) + addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() + print 'addressGeneratorReturnValue', addressGeneratorReturnValue + if addressGeneratorReturnValue == 'chan name does not match address': + QMessageBox.about(self, _translate("MainWindow", "Address does not match chan name"), _translate( + "MainWindow", "Although the Bitmessage address you entered was valid, it doesn\'t match the chan name.")) + return + if len(addressGeneratorReturnValue) == 0: + QMessageBox.about(self, _translate("MainWindow", "Address already present"), _translate( + "MainWindow", "Could not add chan because it appears to already be one of your identities.")) + return + createdAddress = addressGeneratorReturnValue[0] + QMessageBox.about(self, _translate("MainWindow", "Success"), _translate( + "MainWindow", "Successfully joined chan. ")) + self.ui.tabWidget.setCurrentIndex(3) def showConnectDialog(self): - dialog = dialogs.ConnectDialog(self) - if dialog.exec_(): - if dialog.radioButtonConnectNow.isChecked(): - BMConfigParser().remove_option( - 'bitmessagesettings', 'dontconnect') - BMConfigParser().save() - elif dialog.radioButtonConfigureNetwork.isChecked(): + self.connectDialogInstance = connectDialog(self) + if self.connectDialogInstance.exec_(): + if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): + shared.config.remove_option('bitmessagesettings', 'dontconnect') + shared.writeKeysFile() + else: self.click_actionSettings() - def showMigrationWizard(self, level): - self.migrationWizardInstance = Ui_MigrationWizard(["a"]) - if self.migrationWizardInstance.exec_(): - pass - else: - pass - def changeEvent(self, event): if event.type() == QtCore.QEvent.LanguageChange: self.ui.retranslateUi(self) self.init_inbox_popup_menu(False) self.init_identities_popup_menu(False) - self.init_chan_popup_menu(False) self.init_addressbook_popup_menu(False) self.init_subscriptions_popup_menu(False) self.init_sent_popup_menu(False) - self.ui.blackwhitelist.init_blacklist_popup_menu(False) + self.init_blacklist_popup_menu(False) if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: - if BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: - QtCore.QTimer.singleShot(0, self.appIndicatorHide) + if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: + self.appIndicatorHide() + if 'win32' in sys.platform or 'win64' in sys.platform: + self.setWindowFlags(Qt.ToolTip) elif event.oldState() & QtCore.Qt.WindowMinimized: # The window state has just been changed to # Normal/Maximised/FullScreen pass # QtGui.QWidget.changeEvent(self, event) + def __icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.actionShow.setChecked(not self.actionShow.isChecked()) self.appIndicatorShowOrHideWindow() + def updateNumberOfMessagesProcessed(self): + self.ui.labelMessageCount.setText(_translate( + "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) + + def updateNumberOfBroadcastsProcessed(self): + self.ui.labelBroadcastCount.setText(_translate( + "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) + + def updateNumberOfPubkeysProcessed(self): + self.ui.labelPubkeyCount.setText(_translate( + "MainWindow", "Processed %1 public keys.").arg(str(shared.numberOfPubkeysProcessed))) + + def formatBytes(self, num): + for x in ['bytes','KB','MB','GB']: + if num < 1000.0: + return "%3.0f %s" % (num, x) + num /= 1000.0 + return "%3.0f %s" % (num, 'TB') + + def formatByteRate(self, num): + num /= 1000 + return "%4.0f KB" % num + + def updateNumberOfBytes(self): + """ + This function is run every two seconds, so we divide the rate of bytes + sent and received by 2. + """ + self.ui.labelBytesRecvCount.setText(_translate( + "MainWindow", "Down: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesReceived/2), self.formatBytes(self.totalNumberOfBytesReceived))) + self.ui.labelBytesSentCount.setText(_translate( + "MainWindow", "Up: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesSent/2), self.formatBytes(self.totalNumberOfBytesSent))) + self.totalNumberOfBytesReceived += shared.numberOfBytesReceived + self.totalNumberOfBytesSent += shared.numberOfBytesSent + shared.numberOfBytesReceived = 0 + shared.numberOfBytesSent = 0 + + def updateNetworkStatusTab(self): + # print 'updating network status tab' + totalNumberOfConnectionsFromAllStreams = 0 # One would think we could use len(sendDataQueues) for this but the number doesn't always match: just because we have a sendDataThread running doesn't mean that the connection has been fully established (with the exchange of version messages). + streamNumberTotals = {} + for host, streamNumber in shared.connectedHostsList.items(): + if not streamNumber in streamNumberTotals: + streamNumberTotals[streamNumber] = 1 + else: + streamNumberTotals[streamNumber] += 1 + + while self.ui.tableWidgetConnectionCount.rowCount() > 0: + self.ui.tableWidgetConnectionCount.removeRow(0) + for streamNumber, connectionCount in streamNumberTotals.items(): + self.ui.tableWidgetConnectionCount.insertRow(0) + if streamNumber == 0: + newItem = QtGui.QTableWidgetItem("?") + else: + newItem = QtGui.QTableWidgetItem(str(streamNumber)) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetConnectionCount.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(str(connectionCount)) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetConnectionCount.setItem(0, 1, newItem) + """for currentRow in range(self.ui.tableWidgetConnectionCount.rowCount()): + rowStreamNumber = int(self.ui.tableWidgetConnectionCount.item(currentRow,0).text()) + if streamNumber == rowStreamNumber: + foundTheRowThatNeedsUpdating = True + self.ui.tableWidgetConnectionCount.item(currentRow,1).setText(str(connectionCount)) + #totalNumberOfConnectionsFromAllStreams += connectionCount + if foundTheRowThatNeedsUpdating == False: + #Add a line to the table for this stream number and update its count with the current connection count. + self.ui.tableWidgetConnectionCount.insertRow(0) + newItem = QtGui.QTableWidgetItem(str(streamNumber)) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + self.ui.tableWidgetConnectionCount.setItem(0,0,newItem) + newItem = QtGui.QTableWidgetItem(str(connectionCount)) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + self.ui.tableWidgetConnectionCount.setItem(0,1,newItem) + totalNumberOfConnectionsFromAllStreams += connectionCount""" + self.ui.labelTotalConnections.setText(_translate( + "MainWindow", "Total Connections: %1").arg(str(len(shared.connectedHostsList)))) + if len(shared.connectedHostsList) > 0 and shared.statusIconColor == 'red': # FYI: The 'singlelistener' thread sets the icon color to green when it receives an incoming connection, meaning that the user's firewall is configured correctly. + self.setStatusIcon('yellow') + elif len(shared.connectedHostsList) == 0: + self.setStatusIcon('red') + + # timer driven + def runEveryTwoSeconds(self): + self.ui.labelLookupsPerSecond.setText(_translate( + "MainWindow", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) + shared.numberOfInventoryLookupsPerformed = 0 + self.updateNumberOfBytes() + # Indicates whether or not there is a connection to the Bitmessage network connected = False def setStatusIcon(self, color): + global withMessagingMenu # print 'setting status icon color' - _notifications_enabled = not BMConfigParser().getboolean( - 'bitmessagesettings', 'hidetrayconnectionnotifications') if color == 'red': - self.pushButtonStatusIcon.setIcon( - QtGui.QIcon(":/newPrefix/images/redicon.png")) + self.ui.pushButtonStatusIcon.setIcon( + QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # if the connection is lost then show a notification - if self.connected and _notifications_enabled: - self.notifierShow( - 'Bitmessage', - _translate("MainWindow", "Connection lost"), - sound.SOUND_DISCONNECTED) - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ - BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": - self.updateStatusBar( - _translate( - "MainWindow", - "Problems connecting? Try enabling UPnP in the Network" - " Settings" - )) + if self.connected: + self.notifierShow('Bitmessage', unicode(_translate( + "MainWindow", "Connection lost").toUtf8(),'utf-8'), + self.SOUND_DISCONNECTED, None) self.connected = False if self.actionStatus is not None: @@ -1610,17 +1609,16 @@ class MyForm(settingsmixin.SMainWindow): "MainWindow", "Not Connected")) self.setTrayIconFile("can-icon-24px-red.png") if color == 'yellow': - if self.statusbar.currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': - self.statusbar.clearMessage() - self.pushButtonStatusIcon.setIcon( - QtGui.QIcon(":/newPrefix/images/yellowicon.png")) + if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': + self.statusBar().showMessage('') + self.ui.pushButtonStatusIcon.setIcon(QIcon( + ":/newPrefix/images/yellowicon.png")) shared.statusIconColor = 'yellow' # if a new connection has been established then show a notification - if not self.connected and _notifications_enabled: - self.notifierShow( - 'Bitmessage', - _translate("MainWindow", "Connected"), - sound.SOUND_CONNECTED) + if not self.connected: + self.notifierShow('Bitmessage', unicode(_translate( + "MainWindow", "Connected").toUtf8(),'utf-8'), + self.SOUND_CONNECTED, None) self.connected = True if self.actionStatus is not None: @@ -1628,16 +1626,15 @@ class MyForm(settingsmixin.SMainWindow): "MainWindow", "Connected")) self.setTrayIconFile("can-icon-24px-yellow.png") if color == 'green': - if self.statusbar.currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': - self.statusbar.clearMessage() - self.pushButtonStatusIcon.setIcon( - QtGui.QIcon(":/newPrefix/images/greenicon.png")) + if self.statusBar().currentMessage() == 'Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.': + self.statusBar().showMessage('') + self.ui.pushButtonStatusIcon.setIcon( + QIcon(":/newPrefix/images/greenicon.png")) shared.statusIconColor = 'green' - if not self.connected and _notifications_enabled: - self.notifierShow( - 'Bitmessage', - _translate("MainWindow", "Connected"), - sound.SOUND_CONNECTION_GREEN) + if not self.connected: + self.notifierShow('Bitmessage', unicode(_translate( + "MainWindow", "Connected").toUtf8(),'utf-8'), + self.SOUND_CONNECTION_GREEN, None) self.connected = True if self.actionStatus is not None: @@ -1647,7 +1644,7 @@ class MyForm(settingsmixin.SMainWindow): def initTrayIcon(self, iconFileName, app): self.currentTrayIconFileName = iconFileName - self.tray = QtGui.QSystemTrayIcon( + self.tray = QSystemTrayIcon( self.calcTrayIcon(iconFileName, self.findInboxUnreadCount()), app) def setTrayIconFile(self, iconFileName): @@ -1676,10 +1673,9 @@ class MyForm(settingsmixin.SMainWindow): fontMetrics = QtGui.QFontMetrics(font) rect = fontMetrics.boundingRect(txt) # draw text - painter = QtGui.QPainter() + painter = QPainter() painter.begin(pixmap) - painter.setPen( - QtGui.QPen(QtGui.QColor(255, 0, 0), QtCore.Qt.SolidPattern)) + painter.setPen(QtGui.QPen(QtGui.QColor(255, 0, 0), Qt.SolidPattern)) painter.setFont(font) painter.drawText(24-rect.right()-marginX, -rect.top()+marginY, txt) painter.end() @@ -1688,357 +1684,298 @@ class MyForm(settingsmixin.SMainWindow): def drawTrayIcon(self, iconFileName, inboxUnreadCount): self.tray.setIcon(self.calcTrayIcon(iconFileName, inboxUnreadCount)) - def changedInboxUnread(self, row=None): - self.drawTrayIcon( - self.currentTrayIconFileName, self.findInboxUnreadCount()) - self.rerenderTabTreeMessages() - self.rerenderTabTreeSubscriptions() - self.rerenderTabTreeChans() + def changedInboxUnread(self): + self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) - def findInboxUnreadCount(self, count=None): - if count is None: - queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''') - cnt = 0 - for row in queryreturn: - cnt, = row - self.unreadCount = int(cnt) - else: - self.unreadCount = count - return self.unreadCount + def findInboxUnreadCount(self): + queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''') + cnt = 0 + for row in queryreturn: + cnt, = row + return int(cnt) def updateSentItemStatusByToAddress(self, toAddress, textToDisplay): - for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: - treeWidget = self.widgetConvert(sent) - if self.getCurrentFolder(treeWidget) != "sent": - continue - if treeWidget in [self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] and self.getCurrentAccount(treeWidget) != toAddress: - continue - - for i in range(sent.rowCount()): - rowAddress = sent.item(i, 0).data(QtCore.Qt.UserRole) - if toAddress == rowAddress: - sent.item(i, 3).setToolTip(textToDisplay) - try: - newlinePosition = textToDisplay.indexOf('\n') - except: # If someone misses adding a "_translate" to a string before passing it to this function, this function won't receive a qstring which will cause an exception. - newlinePosition = 0 - if newlinePosition > 1: - sent.item(i, 3).setText( - textToDisplay[:newlinePosition]) - else: - sent.item(i, 3).setText(textToDisplay) + for i in range(self.ui.tableWidgetSent.rowCount()): + rowAddress = str(self.ui.tableWidgetSent.item( + i, 0).data(Qt.UserRole).toPyObject()) + if toAddress == rowAddress: + self.ui.tableWidgetSent.item(i, 3).setToolTip(textToDisplay) + try: + newlinePosition = textToDisplay.indexOf('\n') + except: # If someone misses adding a "_translate" to a string before passing it to this function, this function won't receive a qstring which will cause an exception. + newlinePosition = 0 + if newlinePosition > 1: + self.ui.tableWidgetSent.item(i, 3).setText( + textToDisplay[:newlinePosition]) + else: + self.ui.tableWidgetSent.item(i, 3).setText(textToDisplay) def updateSentItemStatusByAckdata(self, ackdata, textToDisplay): - for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: - treeWidget = self.widgetConvert(sent) - if self.getCurrentFolder(treeWidget) != "sent": - continue - for i in range(sent.rowCount()): - toAddress = sent.item( - i, 0).data(QtCore.Qt.UserRole) - tableAckdata = sent.item( - i, 3).data(QtCore.Qt.UserRole).toPyObject() - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) - if ackdata == tableAckdata: - sent.item(i, 3).setToolTip(textToDisplay) - try: - newlinePosition = textToDisplay.indexOf('\n') - except: # If someone misses adding a "_translate" to a string before passing it to this function, this function won't receive a qstring which will cause an exception. - newlinePosition = 0 - if newlinePosition > 1: - sent.item(i, 3).setText( - textToDisplay[:newlinePosition]) - else: - sent.item(i, 3).setText(textToDisplay) + for i in range(self.ui.tableWidgetSent.rowCount()): + toAddress = str(self.ui.tableWidgetSent.item( + i, 0).data(Qt.UserRole).toPyObject()) + tableAckdata = self.ui.tableWidgetSent.item( + i, 3).data(Qt.UserRole).toPyObject() + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress) + if ackdata == tableAckdata: + self.ui.tableWidgetSent.item(i, 3).setToolTip(textToDisplay) + try: + newlinePosition = textToDisplay.indexOf('\n') + except: # If someone misses adding a "_translate" to a string before passing it to this function, this function won't receive a qstring which will cause an exception. + newlinePosition = 0 + if newlinePosition > 1: + self.ui.tableWidgetSent.item(i, 3).setText( + textToDisplay[:newlinePosition]) + else: + self.ui.tableWidgetSent.item(i, 3).setText(textToDisplay) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing - for inbox in ([ - self.ui.tableWidgetInbox, - self.ui.tableWidgetInboxSubscriptions, - self.ui.tableWidgetInboxChans]): - for i in range(inbox.rowCount()): - if msgid == str(inbox.item(i, 3).data(QtCore.Qt.UserRole).toPyObject()): - self.updateStatusBar( - _translate("MainWindow", "Message trashed")) - treeWidget = self.widgetConvert(inbox) - self.propagateUnreadCount(inbox.item(i, 1 if inbox.item(i, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder(treeWidget), treeWidget, 0) - inbox.removeRow(i) - break - - def newVersionAvailable(self, version): - self.notifiedNewVersion = ".".join(str(n) for n in version) - self.updateStatusBar(_translate( - "MainWindow", - "New version of PyBitmessage is available: %1. Download it" - " from https://github.com/Bitmessage/PyBitmessage/releases/latest" - ).arg(self.notifiedNewVersion) - ) + for i in range(self.ui.tableWidgetInbox.rowCount()): + if msgid == str(self.ui.tableWidgetInbox.item(i, 3).data(Qt.UserRole).toPyObject()): + self.statusBar().showMessage(_translate( + "MainWindow", "Message trashed")) + self.ui.tableWidgetInbox.removeRow(i) + break + self.changedInboxUnread() def displayAlert(self, title, text, exitAfterUserClicksOk): - self.updateStatusBar(text) - QtGui.QMessageBox.critical(self, title, text, QtGui.QMessageBox.Ok) + self.statusBar().showMessage(text) + QtGui.QMessageBox.critical(self, title, text, QMessageBox.Ok) if exitAfterUserClicksOk: os._exit(0) - def rerenderMessagelistFromLabels(self): - for messagelist in (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions): - for i in range(messagelist.rowCount()): - messagelist.item(i, 1).setLabel() + def rerenderInboxFromLabels(self): + for i in range(self.ui.tableWidgetInbox.rowCount()): + addressToLookup = str(self.ui.tableWidgetInbox.item( + i, 1).data(Qt.UserRole).toPyObject()) + fromLabel = '' + queryreturn = sqlQuery( + '''select label from addressbook where address=?''', addressToLookup) - def rerenderMessagelistToLabels(self): - for messagelist in (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions): - for i in range(messagelist.rowCount()): - messagelist.item(i, 0).setLabel() + if queryreturn != []: + for row in queryreturn: + fromLabel, = row + + if fromLabel == '': + # It might be a broadcast message. We should check for that + # label. + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', addressToLookup) + + if queryreturn != []: + for row in queryreturn: + fromLabel, = row + if fromLabel == '': + # Message might be from an address we own like a chan address. Let's look for that label. + if shared.config.has_section(addressToLookup): + fromLabel = shared.config.get(addressToLookup, 'label') + if fromLabel == '': + fromLabel = addressToLookup + self.ui.tableWidgetInbox.item( + i, 1).setText(unicode(fromLabel, 'utf-8')) + self.ui.tableWidgetInbox.item( + i, 1).setIcon(avatarize(addressToLookup)) + # Set the color according to whether it is the address of a mailing + # list or not. + if shared.safeConfigGetBoolean(addressToLookup, 'chan'): + self.ui.tableWidgetInbox.item(i, 1).setTextColor(QtGui.QColor(216, 119, 0)) # orange + else: + self.ui.tableWidgetInbox.item( + i, 1).setTextColor(QApplication.palette().text().color()) + + + def rerenderInboxToLabels(self): + for i in range(self.ui.tableWidgetInbox.rowCount()): + toAddress = str(self.ui.tableWidgetInbox.item( + i, 0).data(Qt.UserRole).toPyObject()) + # Message might be to an address we own like a chan address. Let's look for that label. + if shared.config.has_section(toAddress): + toLabel = shared.config.get(toAddress, 'label') + else: + toLabel = toAddress + self.ui.tableWidgetInbox.item( + i, 0).setText(unicode(toLabel, 'utf-8')) + self.ui.tableWidgetInbox.item( + i, 0).setIcon(avatarize(toAddress)) + # Set the color according to whether it is the address of a mailing + # list, a chan or neither. + if shared.safeConfigGetBoolean(toAddress, 'chan'): + self.ui.tableWidgetInbox.item(i, 0).setTextColor(QtGui.QColor(216, 119, 0)) # orange + elif shared.safeConfigGetBoolean(toAddress, 'mailinglist'): + self.ui.tableWidgetInbox.item(i, 0).setTextColor(QtGui.QColor(137, 04, 177)) # magenta + else: + self.ui.tableWidgetInbox.item( + i, 0).setTextColor(QApplication.palette().text().color()) + + def rerenderSentFromLabels(self): + for i in range(self.ui.tableWidgetSent.rowCount()): + fromAddress = str(self.ui.tableWidgetSent.item( + i, 1).data(Qt.UserRole).toPyObject()) + # Message might be from an address we own like a chan address. Let's look for that label. + if shared.config.has_section(fromAddress): + fromLabel = shared.config.get(fromAddress, 'label') + else: + fromLabel = fromAddress + self.ui.tableWidgetSent.item( + i, 1).setText(unicode(fromLabel, 'utf-8')) + self.ui.tableWidgetSent.item( + i, 1).setIcon(avatarize(fromAddress)) + + def rerenderSentToLabels(self): + for i in range(self.ui.tableWidgetSent.rowCount()): + addressToLookup = str(self.ui.tableWidgetSent.item( + i, 0).data(Qt.UserRole).toPyObject()) + toLabel = '' + queryreturn = sqlQuery( + '''select label from addressbook where address=?''', addressToLookup) + if queryreturn != []: + for row in queryreturn: + toLabel, = row + + if toLabel == '': + # Message might be to an address we own like a chan address. Let's look for that label. + if shared.config.has_section(addressToLookup): + toLabel = shared.config.get(addressToLookup, 'label') + if toLabel == '': + toLabel = addressToLookup + self.ui.tableWidgetSent.item( + i, 0).setText(unicode(toLabel, 'utf-8')) def rerenderAddressBook(self): - def addRow (address, label, type): - self.ui.tableWidgetAddressBook.insertRow(0) - newItem = Ui_AddressBookWidgetItemLabel(address, unicode(label, 'utf-8'), type) - self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) - newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type) - self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) - - oldRows = {} - for i in range(self.ui.tableWidgetAddressBook.rowCount()): - item = self.ui.tableWidgetAddressBook.item(i, 0) - oldRows[item.address] = [item.label, item.type, i] - - if self.ui.tableWidgetAddressBook.rowCount() == 0: - self.ui.tableWidgetAddressBook.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) - if self.ui.tableWidgetAddressBook.isSortingEnabled(): - self.ui.tableWidgetAddressBook.setSortingEnabled(False) - - newRows = {} - # subscriptions - queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1') - for row in queryreturn: - label, address = row - newRows[address] = [label, AccountMixin.SUBSCRIPTION] - # chans - addresses = getSortedAccounts() - for address in addresses: - account = accountClass(address) - if (account.type == AccountMixin.CHAN and BMConfigParser().safeGetBoolean(address, 'enabled')): - newRows[address] = [account.getLabel(), AccountMixin.CHAN] - # normal accounts + self.ui.tableWidgetAddressBook.setRowCount(0) queryreturn = sqlQuery('SELECT * FROM addressbook') for row in queryreturn: label, address = row - newRows[address] = [label, AccountMixin.NORMAL] - - completerList = [] - for address in sorted(oldRows, key = lambda x: oldRows[x][2], reverse = True): - if address in newRows: - completerList.append(unicode(newRows[address][0], encoding="UTF-8") + " <" + address + ">") - newRows.pop(address) - else: - self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2]) - for address in newRows: - addRow(address, newRows[address][0], newRows[address][1]) - completerList.append(unicode(newRows[address][0], encoding="UTF-8") + " <" + address + ">") - - # sort - self.ui.tableWidgetAddressBook.sortByColumn( - 0, QtCore.Qt.AscendingOrder) - self.ui.tableWidgetAddressBook.setSortingEnabled(True) - self.ui.lineEditTo.completer().model().setStringList(completerList) + self.ui.tableWidgetAddressBook.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) def rerenderSubscriptions(self): - self.rerenderTabTreeSubscriptions() + self.ui.tableWidgetSubscriptions.setRowCount(0) + queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') + for row in queryreturn: + label, address, enabled = row + self.ui.tableWidgetSubscriptions.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + if not enabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetSubscriptions.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not enabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetSubscriptions.setItem(0, 1, newItem) + + def rerenderBlackWhiteList(self): + self.ui.tableWidgetBlacklist.setRowCount(0) + listType = shared.config.get('bitmessagesettings', 'blackwhitelist') + if listType == 'black': + queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') + else: + queryreturn = sqlQuery('''SELECT label, address, enabled FROM whitelist''') + for row in queryreturn: + label, address, enabled = row + self.ui.tableWidgetBlacklist.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + if not enabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetBlacklist.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not enabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetBlacklist.setItem(0, 1, newItem) def click_pushButtonTTL(self): QtGui.QMessageBox.information(self, 'Time To Live', _translate( - "MainWindow", """The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate."""), QtGui.QMessageBox.Ok) - - def click_pushButtonClear(self): - self.ui.lineEditSubject.setText("") - self.ui.lineEditTo.setText("") - self.ui.textEditMessage.setText("") - self.ui.comboBoxSendFrom.setCurrentIndex(0) + "MainWindow", "The TTL, or Time-To-Live is the length of time that the network will hold the message. \ +The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it \ +will resend the message automatically. The longer the Time-To-Live, the \ +more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate."), QMessageBox.Ok) def click_pushButtonSend(self): - encoding = 3 if QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier else 2 - - self.statusbar.clearMessage() - - if self.ui.tabWidgetSend.currentIndex() == \ - self.ui.tabWidgetSend.indexOf(self.ui.sendDirect): - # message to specific people - sendMessageToPeople = True - fromAddress = str(self.ui.comboBoxSendFrom.itemData( - self.ui.comboBoxSendFrom.currentIndex(), - QtCore.Qt.UserRole).toString()) - toAddresses = str(self.ui.lineEditTo.text().toUtf8()) - subject = str(self.ui.lineEditSubject.text().toUtf8()) - message = str( - self.ui.textEditMessage.document().toPlainText().toUtf8()) - else: - # broadcast message - sendMessageToPeople = False - fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData( - self.ui.comboBoxSendFromBroadcast.currentIndex(), - QtCore.Qt.UserRole).toString()) - subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8()) - message = str( - self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8()) + self.statusBar().showMessage('') + toAddresses = str(self.ui.lineEditTo.text()) + fromAddress = str(self.ui.labelFrom.text()) + subject = str(self.ui.lineEditSubject.text().toUtf8()) + message = str( + self.ui.textEditMessage.document().toPlainText().toUtf8()) """ - The whole network message must fit in 2^18 bytes. - Let's assume 500 bytes of overhead. If someone wants to get that - too an exact number you are welcome to but I think that it would - be a better use of time to support message continuation so that - users can send messages of any length. + The whole network message must fit in 2^18 bytes. Let's assume 500 + bytes of overhead. If someone wants to get that too an exact + number you are welcome to but I think that it would be a better + use of time to support message continuation so that users can + send messages of any length. """ - if len(message) > (2 ** 18 - 500): - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Message too long"), - _translate( - "MainWindow", - "The message that you are trying to send is too long" - " by %1 bytes. (The maximum is 261644 bytes). Please" - " cut it down before sending." - ).arg(len(message) - (2 ** 18 - 500))) + if len(message) > (2 ** 18 - 500): + QMessageBox.about(self, _translate("MainWindow", "Message too long"), _translate( + "MainWindow", "The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending.").arg(len(message) - (2 ** 18 - 500))) return - - acct = accountClass(fromAddress) - - if sendMessageToPeople: # To send a message to specific people (rather than broadcast) + if self.ui.radioButtonSpecific.isChecked(): # To send a message to specific people (rather than broadcast) toAddressesList = [s.strip() for s in toAddresses.replace(',', ';').split(';')] toAddressesList = list(set( toAddressesList)) # remove duplicate addresses. If the user has one address with a BM- and the same address without the BM-, this will not catch it. They'll send the message to the person twice. for toAddress in toAddressesList: if toAddress != '': - # label plus address - if "<" in toAddress and ">" in toAddress: - toAddress = toAddress.split('<')[1].split('>')[0] - # email address - if toAddress.find("@") >= 0: - if isinstance(acct, GatewayAccount): - acct.createMessage(toAddress, fromAddress, subject, message) - subject = acct.subject - toAddress = acct.toAddress - else: - if QtGui.QMessageBox.question(self, "Sending an email?", _translate("MainWindow", - "You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register?"), - QtGui.QMessageBox.Yes|QtGui.QMessageBox.No) != QtGui.QMessageBox.Yes: - continue - email = acct.getLabel() - if email[-14:] != "@mailchuck.com": #attempt register - # 12 character random email address - email = ''.join(random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)) + "@mailchuck.com" - acct = MailchuckAccount(fromAddress) - acct.register(email) - BMConfigParser().set(fromAddress, 'label', email) - BMConfigParser().set(fromAddress, 'gateway', 'mailchuck') - BMConfigParser().save() - self.updateStatusBar(_translate( - "MainWindow", - "Error: Your account wasn't registered at" - " an email gateway. Sending registration" - " now as %1, please wait for the registration" - " to be processed before retrying sending." - ).arg(email) - ) - return status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if status != 'success': - try: - toAddress = unicode(toAddress, 'utf-8', 'ignore') - except: - pass - logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status) + with shared.printLock: + print 'Error: Could not decode', toAddress, ':', status if status == 'missingbm': - self.updateStatusBar(_translate( - "MainWindow", - "Error: Bitmessage addresses start with" - " BM- Please check the recipient address %1" - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: Bitmessage addresses start with BM- Please check %1").arg(toAddress)) elif status == 'checksumfailed': - self.updateStatusBar(_translate( - "MainWindow", - "Error: The recipient address %1 is not" - " typed or copied correctly. Please check it." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: The address %1 is not typed or copied correctly. Please check it.").arg(toAddress)) elif status == 'invalidcharacters': - self.updateStatusBar(_translate( - "MainWindow", - "Error: The recipient address %1 contains" - " invalid characters. Please check it." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: The address %1 contains invalid characters. Please check it.").arg(toAddress)) elif status == 'versiontoohigh': - self.updateStatusBar(_translate( - "MainWindow", - "Error: The version of the recipient address" - " %1 is too high. Either you need to upgrade" - " your Bitmessage software or your" - " acquaintance is being clever." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever.").arg(toAddress)) elif status == 'ripetooshort': - self.updateStatusBar(_translate( - "MainWindow", - "Error: Some data encoded in the recipient" - " address %1 is too short. There might be" - " something wrong with the software of" - " your acquaintance." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance.").arg(toAddress)) elif status == 'ripetoolong': - self.updateStatusBar(_translate( - "MainWindow", - "Error: Some data encoded in the recipient" - " address %1 is too long. There might be" - " something wrong with the software of" - " your acquaintance." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance.").arg(toAddress)) elif status == 'varintmalformed': - self.updateStatusBar(_translate( - "MainWindow", - "Error: Some data encoded in the recipient" - " address %1 is malformed. There might be" - " something wrong with the software of" - " your acquaintance." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance.").arg(toAddress)) else: - self.updateStatusBar(_translate( - "MainWindow", - "Error: Something is wrong with the" - " recipient address %1." - ).arg(toAddress)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: Something is wrong with the address %1.").arg(toAddress)) elif fromAddress == '': - self.updateStatusBar(_translate( - "MainWindow", - "Error: You must specify a From address. If you" - " don\'t have one, go to the" - " \'Your Identities\' tab.") - ) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab.")) else: toAddress = addBMIfNotPresent(toAddress) - if addressVersionNumber > 4 or addressVersionNumber <= 1: - QtGui.QMessageBox.about(self, _translate("MainWindow", "Address version number"), _translate( + QMessageBox.about(self, _translate("MainWindow", "Address version number"), _translate( "MainWindow", "Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version.").arg(toAddress).arg(str(addressVersionNumber))) continue if streamNumber > 1 or streamNumber == 0: - QtGui.QMessageBox.about(self, _translate("MainWindow", "Stream number"), _translate( + QMessageBox.about(self, _translate("MainWindow", "Stream number"), _translate( "MainWindow", "Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version.").arg(toAddress).arg(str(streamNumber))) continue - self.statusbar.clearMessage() + self.statusBar().showMessage('') if shared.statusIconColor == 'red': - self.updateStatusBar(_translate( - "MainWindow", - "Warning: You are currently not connected." - " Bitmessage will do the work necessary to" - " send the message but it won\'t send until" - " you connect.") - ) - stealthLevel = BMConfigParser().safeGetInt( - 'bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) + self.statusBar().showMessage(_translate( + "MainWindow", "Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won\'t send until you connect.")) + ackdata = OpenSSL.rand(32) t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', @@ -2055,8 +1992,8 @@ class MyForm(settingsmixin.SMainWindow): 'msgqueued', 0, # retryNumber 'sent', # folder - encoding, # encodingtype - BMConfigParser().getint('bitmessagesettings', 'ttl') + 2, # encodingtype + shared.config.getint('bitmessagesettings', 'ttl') ) toLabel = '' @@ -2068,36 +2005,29 @@ class MyForm(settingsmixin.SMainWindow): self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) - queues.workerQueue.put(('sendmessage', toAddress)) + shared.workerQueue.put(('sendmessage', toAddress)) self.ui.comboBoxSendFrom.setCurrentIndex(0) + self.ui.labelFrom.setText('') self.ui.lineEditTo.setText('') self.ui.lineEditSubject.setText('') - self.ui.textEditMessage.reset() - if self.replyFromTab is not None: - self.ui.tabWidget.setCurrentIndex(self.replyFromTab) - self.replyFromTab = None - self.updateStatusBar(_translate( - "MainWindow", "Message queued.")) - # self.ui.tableWidgetInbox.setCurrentCell(0, 0) + self.ui.textEditMessage.setText('') + self.ui.tabWidget.setCurrentIndex(2) + self.ui.tableWidgetSent.setCurrentCell(0, 0) else: - self.updateStatusBar(_translate( + self.statusBar().showMessage(_translate( "MainWindow", "Your \'To\' field is empty.")) else: # User selected 'Broadcast' if fromAddress == '': - self.updateStatusBar(_translate( - "MainWindow", - "Error: You must specify a From address. If you don\'t" - " have one, go to the \'Your Identities\' tab." - )) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab.")) else: - self.statusbar.clearMessage() + self.statusBar().showMessage('') # We don't actually need the ackdata for acknowledgement since # this is a broadcast message, but we can use it to update the # user interface when the POW is done generating. - streamNumber = decodeAddress(fromAddress)[2] - ackdata = genAckPayload(streamNumber, 0) - toAddress = str_broadcast_subscribers + ackdata = OpenSSL.rand(32) + toAddress = self.str_broadcast_subscribers ripe = '' t = ('', # msgid. We don't know what this will be until the POW is done. toAddress, @@ -2112,405 +2042,408 @@ class MyForm(settingsmixin.SMainWindow): 'broadcastqueued', 0, # retryNumber 'sent', # folder - encoding, # encoding type - BMConfigParser().getint('bitmessagesettings', 'ttl') + 2, # encoding type + shared.config.getint('bitmessagesettings', 'ttl') ) sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) - toLabel = str_broadcast_subscribers + toLabel = self.str_broadcast_subscribers self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) - queues.workerQueue.put(('sendbroadcast', '')) + shared.workerQueue.put(('sendbroadcast', '')) - self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) - self.ui.lineEditSubjectBroadcast.setText('') - self.ui.textEditMessageBroadcast.reset() - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) - self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) - self.updateStatusBar(_translate( - "MainWindow", "Broadcast queued.")) + self.ui.comboBoxSendFrom.setCurrentIndex(0) + self.ui.labelFrom.setText('') + self.ui.lineEditTo.setText('') + self.ui.lineEditSubject.setText('') + self.ui.textEditMessage.setText('') + self.ui.tabWidget.setCurrentIndex(2) + self.ui.tableWidgetSent.setCurrentCell(0, 0) def click_pushButtonLoadFromAddressBook(self): self.ui.tabWidget.setCurrentIndex(5) for i in range(4): time.sleep(0.1) - self.statusbar.clearMessage() + self.statusBar().showMessage('') time.sleep(0.1) - self.updateStatusBar(_translate( - "MainWindow", - "Right click one or more entries in your address book and" - " select \'Send message to this address\'." - )) + self.statusBar().showMessage(_translate( + "MainWindow", "Right click one or more entries in your address book and select \'Send message to this address\'.")) def click_pushButtonFetchNamecoinID(self): nc = namecoinConnection() - identities = str(self.ui.lineEditTo.text().toUtf8()).split(";") - err, addr = nc.query(identities[-1].strip()) + err, addr = nc.query(str(self.ui.lineEditTo.text())) if err is not None: - self.updateStatusBar( - _translate("MainWindow", "Error: %1").arg(err)) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: " + err)) else: - identities[-1] = addr - self.ui.lineEditTo.setText("; ".join(identities)) - self.updateStatusBar(_translate( + self.ui.lineEditTo.setText(addr) + self.statusBar().showMessage(_translate( "MainWindow", "Fetched address from namecoin identity.")) - def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): + def redrawLabelFrom(self, index): + self.ui.labelFrom.setText( + self.ui.comboBoxSendFrom.itemData(index).toPyObject()) + self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(self.ui.comboBoxSendFrom.itemData(index).toPyObject()) + + def setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(self, address): # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. - self.ui.tabWidgetSend.setCurrentIndex( - self.ui.tabWidgetSend.indexOf( - self.ui.sendBroadcast - if BMConfigParser().safeGetBoolean(str(address), 'mailinglist') - else self.ui.sendDirect - )) + if shared.safeConfigGetBoolean(str(address), 'chan'): + self.ui.radioButtonSpecific.click() + self.ui.radioButtonBroadcast.setEnabled(False) + else: + self.ui.radioButtonBroadcast.setEnabled(True) def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() - for addressInKeysFile in getSortedAccounts(): - isEnabled = BMConfigParser().getboolean( - addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read. - isMaillinglist = BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist') - if isEnabled and not isMaillinglist: - label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() - if label == "": - label = addressInKeysFile - self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) -# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder) - for i in range(self.ui.comboBoxSendFrom.count()): - address = str(self.ui.comboBoxSendFrom.itemData( - i, QtCore.Qt.UserRole).toString()) - self.ui.comboBoxSendFrom.setItemData( - i, AccountColor(address).accountColor(), - QtCore.Qt.ForegroundRole) + self.ui.labelFrom.setText('') + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + isEnabled = shared.config.getboolean( + addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read. + if isEnabled: + self.ui.comboBoxSendFrom.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( + addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) self.ui.comboBoxSendFrom.insertItem(0, '', '') if(self.ui.comboBoxSendFrom.count() == 2): self.ui.comboBoxSendFrom.setCurrentIndex(1) + self.redrawLabelFrom(self.ui.comboBoxSendFrom.currentIndex()) else: self.ui.comboBoxSendFrom.setCurrentIndex(0) - def rerenderComboBoxSendFromBroadcast(self): - self.ui.comboBoxSendFromBroadcast.clear() - for addressInKeysFile in getSortedAccounts(): - isEnabled = BMConfigParser().getboolean( - addressInKeysFile, 'enabled') # I realize that this is poor programming practice but I don't care. It's easier for others to read. - isChan = BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan') - if isEnabled and not isChan: - label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() - if label == "": - label = addressInKeysFile - self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) - for i in range(self.ui.comboBoxSendFromBroadcast.count()): - address = str(self.ui.comboBoxSendFromBroadcast.itemData( - i, QtCore.Qt.UserRole).toString()) - self.ui.comboBoxSendFromBroadcast.setItemData( - i, AccountColor(address).accountColor(), - QtCore.Qt.ForegroundRole) - self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '') - if(self.ui.comboBoxSendFromBroadcast.count() == 2): - self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1) - else: - self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) - # This function is called by the processmsg function when that function # receives a message to an address that is acting as a # pseudo-mailing-list. The message will be broadcast out. This function # puts the message on the 'Sent' tab. def displayNewSentMessage(self, toAddress, toLabel, fromAddress, subject, message, ackdata): - acct = accountClass(fromAddress) - acct.parseMessage(toAddress, fromAddress, subject, message) - tab = -1 - for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: - tab += 1 - if tab == 1: - tab = 2 - treeWidget = self.widgetConvert(sent) - if self.getCurrentFolder(treeWidget) != "sent": - continue - if treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) != fromAddress: - continue - elif treeWidget in [self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] and self.getCurrentAccount(treeWidget) != toAddress: - continue - elif not helper_search.check_match(toAddress, fromAddress, subject, message, self.getCurrentSearchOption(tab), self.getCurrentSearchLine(tab)): - continue - - self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) - self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)', 'replace')) - sent.setCurrentCell(0, 0) + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + message = shared.fixPotentiallyInvalidUTF8Data(message) + try: + fromLabel = shared.config.get(fromAddress, 'label') + except: + fromLabel = '' + if fromLabel == '': + fromLabel = fromAddress + + self.ui.tableWidgetSent.setSortingEnabled(False) + self.ui.tableWidgetSent.insertRow(0) + if toLabel == '': + newItem = QtGui.QTableWidgetItem(unicode(toAddress, 'utf-8')) + newItem.setToolTip(unicode(toAddress, 'utf-8')) + else: + newItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) + newItem.setToolTip(unicode(toLabel, 'utf-8')) + newItem.setData(Qt.UserRole, str(toAddress)) + newItem.setIcon(avatarize(toAddress)) + self.ui.tableWidgetSent.setItem(0, 0, newItem) + if fromLabel == '': + newItem = QtGui.QTableWidgetItem(unicode(fromAddress, 'utf-8')) + newItem.setToolTip(unicode(fromAddress, 'utf-8')) + else: + newItem = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) + newItem.setToolTip(unicode(fromLabel, 'utf-8')) + newItem.setData(Qt.UserRole, str(fromAddress)) + newItem.setIcon(avatarize(fromAddress)) + self.ui.tableWidgetSent.setItem(0, 1, newItem) + newItem = QtGui.QTableWidgetItem(unicode(subject, 'utf-8)')) + newItem.setToolTip(unicode(subject, 'utf-8)')) + #newItem.setData(Qt.UserRole, unicode(message, 'utf-8)')) # No longer hold the message in the table; we'll use a SQL query to display it as needed. + self.ui.tableWidgetSent.setItem(0, 2, newItem) + # newItem = QtGui.QTableWidgetItem('Doing work necessary to send + # broadcast...'+ + # l10n.formatTimestamp()) + newItem = myTableWidgetItem(_translate("MainWindow", "Work is queued. %1").arg(l10n.formatTimestamp())) + newItem.setToolTip(_translate("MainWindow", "Work is queued. %1").arg(l10n.formatTimestamp())) + newItem.setData(Qt.UserRole, QByteArray(ackdata)) + newItem.setData(33, int(time.time())) + self.ui.tableWidgetSent.setItem(0, 3, newItem) + self.ui.textEditSentMessage.setPlainText(unicode(message, 'utf-8)')) + self.ui.tableWidgetSent.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): - if toAddress == str_broadcast_subscribers: - acct = accountClass(fromAddress) + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + fromLabel = '' + queryreturn = sqlQuery( + '''select label from addressbook where address=?''', fromAddress) + if queryreturn != []: + for row in queryreturn: + fromLabel, = row else: - acct = accountClass(toAddress) - inbox = self.getAccountMessagelist(acct) - ret = None - tab = -1 - for treeWidget in [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans]: - tab += 1 - if tab == 1: - tab = 2 - tableWidget = self.widgetConvert(treeWidget) - if not helper_search.check_match(toAddress, fromAddress, subject, message, self.getCurrentSearchOption(tab), self.getCurrentSearchLine(tab)): - continue - if tableWidget == inbox and self.getCurrentAccount(treeWidget) == acct.address and self.getCurrentFolder(treeWidget) in ["inbox", None]: - ret = self.addMessageListItemInbox(inbox, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) - elif treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) is None and self.getCurrentFolder(treeWidget) in ["inbox", "new", None]: - ret = self.addMessageListItemInbox(tableWidget, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) - if ret is None: - acct.parseMessage(toAddress, fromAddress, subject, "") - else: - acct = ret - self.propagateUnreadCount(acct.address) - if BMConfigParser().getboolean( - 'bitmessagesettings', 'showtraynotifications'): - self.notifierShow( - _translate("MainWindow", "New Message"), - _translate("MainWindow", "From %1").arg( - unicode(acct.fromLabel, 'utf-8')), - sound.SOUND_UNKNOWN - ) - if self.getCurrentAccount() is not None and ((self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) is not None) or self.getCurrentAccount(treeWidget) != acct.address): - # Ubuntu should notify of new message irespective of - # whether it's in current message list or not - self.indicatorUpdate(True, to_label=acct.toLabel) - # cannot find item to pass here ): - if hasattr(acct, "feedback") \ - and acct.feedback != GatewayAccount.ALL_OK: - if acct.feedback == GatewayAccount.REGISTRATION_DENIED: - dialogs.EmailGatewayDialog( - self, BMConfigParser(), acct).exec_() + # There might be a label in the subscriptions table + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', fromAddress) + if queryreturn != []: + for row in queryreturn: + fromLabel, = row - def click_pushButtonAddAddressBook(self, dialog=None): - if not dialog: - dialog = dialogs.AddAddressDialog(self) - dialog.exec_() try: - address, label = dialog.data - except AttributeError: - return + if toAddress == self.str_broadcast_subscribers: + toLabel = self.str_broadcast_subscribers + else: + toLabel = shared.config.get(toAddress, 'label') + except: + toLabel = '' + if toLabel == '': + toLabel = toAddress - # First we must check to see if the address is already in the - # address book. The user cannot add it again or else it will - # cause problems when updating and deleting the entry. - if shared.isAddressInMyAddressBook(address): - self.updateStatusBar(_translate( - "MainWindow", - "Error: You cannot add the same address to your" - " address book twice. Try renaming the existing one" - " if you want." - )) - return + font = QFont() + font.setBold(True) + self.ui.tableWidgetInbox.setSortingEnabled(False) + newItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) + newItem.setToolTip(unicode(toLabel, 'utf-8')) + newItem.setFont(font) + newItem.setData(Qt.UserRole, str(toAddress)) + if shared.safeConfigGetBoolean(str(toAddress), 'mailinglist'): + newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta + if shared.safeConfigGetBoolean(str(toAddress), 'chan'): + newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange + self.ui.tableWidgetInbox.insertRow(0) + newItem.setIcon(avatarize(toAddress)) + self.ui.tableWidgetInbox.setItem(0, 0, newItem) - self.addEntryToAddressBook(address, label) + if fromLabel == '': + newItem = QtGui.QTableWidgetItem(unicode(fromAddress, 'utf-8')) + newItem.setToolTip(unicode(fromAddress, 'utf-8')) + if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): + self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(fromAddress, 'utf-8'), self.SOUND_UNKNOWN, None) + else: + newItem = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) + newItem.setToolTip(unicode(unicode(fromLabel, 'utf-8'))) + if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): + self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(fromLabel, 'utf-8'), self.SOUND_KNOWN, unicode(fromLabel, 'utf-8')) + newItem.setData(Qt.UserRole, str(fromAddress)) + newItem.setFont(font) + newItem.setIcon(avatarize(fromAddress)) + self.ui.tableWidgetInbox.setItem(0, 1, newItem) + newItem = QtGui.QTableWidgetItem(unicode(subject, 'utf-8)')) + newItem.setToolTip(unicode(subject, 'utf-8)')) + #newItem.setData(Qt.UserRole, unicode(message, 'utf-8)')) # No longer hold the message in the table; we'll use a SQL query to display it as needed. + newItem.setFont(font) + self.ui.tableWidgetInbox.setItem(0, 2, newItem) + newItem = myTableWidgetItem(l10n.formatTimestamp()) + newItem.setToolTip(l10n.formatTimestamp()) + newItem.setData(Qt.UserRole, QByteArray(inventoryHash)) + newItem.setData(33, int(time.time())) + newItem.setFont(font) + self.ui.tableWidgetInbox.setItem(0, 3, newItem) + self.ui.tableWidgetInbox.setSortingEnabled(True) + self.ubuntuMessagingMenuUpdate(True, newItem, toLabel) - def addEntryToAddressBook(self, address, label): - if shared.isAddressInMyAddressBook(address): - return - sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', label, address) - self.rerenderMessagelistFromLabels() - self.rerenderMessagelistToLabels() - self.rerenderAddressBook() + def click_pushButtonAddAddressBook(self): + self.AddAddressDialogInstance = AddAddressDialog(self) + if self.AddAddressDialogInstance.exec_(): + if self.AddAddressDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): + # First we must check to see if the address is already in the + # address book. The user cannot add it again or else it will + # cause problems when updating and deleting the entry. + address = addBMIfNotPresent(str( + self.AddAddressDialogInstance.ui.lineEditAddress.text())) + label = self.AddAddressDialogInstance.ui.newAddressLabel.text().toUtf8() + self.addEntryToAddressBook(address,label) + else: + self.statusBar().showMessage(_translate( + "MainWindow", "The address you entered was invalid. Ignoring it.")) + + def addEntryToAddressBook(self,address,label): + queryreturn = sqlQuery('''select * from addressbook where address=?''', address) + if queryreturn == []: + self.ui.tableWidgetAddressBook.setSortingEnabled(False) + self.ui.tableWidgetAddressBook.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) + self.ui.tableWidgetAddressBook.setSortingEnabled(True) + sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', str(label), address) + self.rerenderInboxFromLabels() + self.rerenderSentToLabels() + else: + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want.")) def addSubscription(self, address, label): - # This should be handled outside of this function, for error displaying - # and such, but it must also be checked here. + address = addBMIfNotPresent(address) + #This should be handled outside of this function, for error displaying and such, but it must also be checked here. if shared.isAddressInMySubscriptionsList(address): return - # Add to database (perhaps this should be separated from the MyForm class) - sqlExecute( - '''INSERT INTO subscriptions VALUES (?,?,?)''', - label, address, True - ) - self.rerenderMessagelistFromLabels() + #Add to UI list + self.ui.tableWidgetSubscriptions.setSortingEnabled(False) + self.ui.tableWidgetSubscriptions.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetSubscriptions.setItem(0,0,newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + self.ui.tableWidgetSubscriptions.setItem(0,1,newItem) + self.ui.tableWidgetSubscriptions.setSortingEnabled(True) + #Add to database (perhaps this should be separated from the MyForm class) + sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',str(label),address,True) + self.rerenderInboxFromLabels() shared.reloadBroadcastSendersForWhichImWatching() - self.rerenderAddressBook() - self.rerenderTabTreeSubscriptions() def click_pushButtonAddSubscription(self): - dialog = dialogs.NewSubscriptionDialog(self) - dialog.exec_() - try: - address, label = dialog.data - except AttributeError: - return - - # We must check to see if the address is already in the - # subscriptions list. The user cannot add it again or else it - # will cause problems when updating and deleting the entry. - if shared.isAddressInMySubscriptionsList(address): - self.updateStatusBar(_translate( - "MainWindow", - "Error: You cannot add the same address to your" - " subscriptions twice. Perhaps rename the existing one" - " if you want." - )) - return - - self.addSubscription(address, label) - # Now, if the user wants to display old broadcasts, let's get - # them out of the inventory and put them - # to the objectProcessorQueue to be processed - if dialog.checkBoxDisplayMessagesAlreadyInInventory.isChecked(): - for value in dialog.recent: - queues.objectProcessorQueue.put(( - value.type, value.payload - )) + self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self) + if self.NewSubscriptionDialogInstance.exec_(): + if self.NewSubscriptionDialogInstance.ui.labelAddressCheck.text() != _translate("MainWindow", "Address is valid."): + self.statusBar().showMessage(_translate("MainWindow", "The address you entered was invalid. Ignoring it.")) + return + address = addBMIfNotPresent(str(self.NewSubscriptionDialogInstance.ui.lineEditSubscriptionAddress.text())) + # We must check to see if the address is already in the subscriptions list. The user cannot add it again or else it will cause problems when updating and deleting the entry. + if shared.isAddressInMySubscriptionsList(address): + self.statusBar().showMessage(_translate("MainWindow", "Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want.")) + return + label = self.NewSubscriptionDialogInstance.ui.newsubscriptionlabel.text().toUtf8() + self.addSubscription(address, label) + # Now, if the user wants to display old broadcasts, let's get them out of the inventory and put them + # in the objectProcessorQueue to be processed + if self.NewSubscriptionDialogInstance.ui.checkBoxDisplayMessagesAlreadyInInventory.isChecked(): + status, addressVersion, streamNumber, ripe = decodeAddress(address) + shared.flushInventory() + doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( + addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() + tag = doubleHashOfAddressData[32:] + queryreturn = sqlQuery( + '''select payload from inventory where objecttype=3 and tag=?''', tag) + for row in queryreturn: + payload, = row + objectType = 3 + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize += len(payload) + shared.objectProcessorQueue.put((objectType,payload)) def click_pushButtonStatusIcon(self): - dialogs.IconGlossaryDialog(self, config=BMConfigParser()).exec_() + print 'click_pushButtonStatusIcon' + self.iconGlossaryInstance = iconGlossaryDialog(self) + if self.iconGlossaryInstance.exec_(): + pass def click_actionHelp(self): - dialogs.HelpDialog(self).exec_() - - def click_actionSupport(self): - support.createSupportMessage(self) + self.helpDialogInstance = helpDialog(self) + self.helpDialogInstance.exec_() def click_actionAbout(self): - dialogs.AboutDialog(self).exec_() + self.aboutDialogInstance = aboutDialog(self) + self.aboutDialogInstance.exec_() def click_actionSettings(self): self.settingsDialogInstance = settingsDialog(self) - if self._firstrun: - self.settingsDialogInstance.ui.tabWidgetSettings.setCurrentIndex(1) if self.settingsDialogInstance.exec_(): - if self._firstrun: - BMConfigParser().remove_option( - 'bitmessagesettings', 'dontconnect') - BMConfigParser().set('bitmessagesettings', 'startonlogon', str( + shared.config.set('bitmessagesettings', 'startonlogon', str( self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) - BMConfigParser().set('bitmessagesettings', 'minimizetotray', str( + shared.config.set('bitmessagesettings', 'minimizetotray', str( self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) - BMConfigParser().set('bitmessagesettings', 'trayonclose', str( - self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) - BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', str( - self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked())) - BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str( + shared.config.set('bitmessagesettings', 'showtraynotifications', str( self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) - BMConfigParser().set('bitmessagesettings', 'startintray', str( + shared.config.set('bitmessagesettings', 'startintray', str( self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked())) - BMConfigParser().set('bitmessagesettings', 'willinglysendtomobile', str( + shared.config.set('bitmessagesettings', 'willinglysendtomobile', str( self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked())) - BMConfigParser().set('bitmessagesettings', 'useidenticons', str( + shared.config.set('bitmessagesettings', 'useidenticons', str( self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) - BMConfigParser().set('bitmessagesettings', 'replybelow', str( + shared.config.set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) - lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) - BMConfigParser().set('bitmessagesettings', 'userlocale', lang) - change_translation(l10n.getTranslationLanguage()) + lang_ind = int(self.settingsDialogInstance.ui.languageComboBox.currentIndex()) + if not languages[lang_ind] == 'other': + shared.config.set('bitmessagesettings', 'userlocale', languages[lang_ind]) + change_translation(languages[lang_ind]) - if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): - QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): + if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "MainWindow", "You must restart Bitmessage for the port number change to take effect.")) - BMConfigParser().set('bitmessagesettings', 'port', str( + shared.config.set('bitmessagesettings', 'port', str( self.settingsDialogInstance.ui.lineEditTCPPort.text())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): - BMConfigParser().set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked(): - import upnp - upnpThread = upnp.uPnPThread() - upnpThread.start() #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText()', self.settingsDialogInstance.ui.comboBoxProxyType.currentText() #print 'self.settingsDialogInstance.ui.comboBoxProxyType.currentText())[0:5]', self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': + if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': if shared.statusIconColor != 'red': - QtGui.QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "MainWindow", "Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any).")) - if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': - self.statusbar.clearMessage() - state.resetNetworkProtocolAvailability() # just in case we changed something in the network connectivity + if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': + self.statusBar().showMessage('') if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': - BMConfigParser().set('bitmessagesettings', 'socksproxytype', str( + shared.config.set('bitmessagesettings', 'socksproxytype', str( self.settingsDialogInstance.ui.comboBoxProxyType.currentText())) else: - BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') - BMConfigParser().set('bitmessagesettings', 'socksauthentication', str( + shared.config.set('bitmessagesettings', 'socksproxytype', 'none') + shared.config.set('bitmessagesettings', 'socksauthentication', str( self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked())) - BMConfigParser().set('bitmessagesettings', 'sockshostname', str( + shared.config.set('bitmessagesettings', 'sockshostname', str( self.settingsDialogInstance.ui.lineEditSocksHostname.text())) - BMConfigParser().set('bitmessagesettings', 'socksport', str( + shared.config.set('bitmessagesettings', 'socksport', str( self.settingsDialogInstance.ui.lineEditSocksPort.text())) - BMConfigParser().set('bitmessagesettings', 'socksusername', str( + shared.config.set('bitmessagesettings', 'socksusername', str( self.settingsDialogInstance.ui.lineEditSocksUsername.text())) - BMConfigParser().set('bitmessagesettings', 'sockspassword', str( + shared.config.set('bitmessagesettings', 'sockspassword', str( self.settingsDialogInstance.ui.lineEditSocksPassword.text())) - BMConfigParser().set('bitmessagesettings', 'sockslisten', str( + shared.config.set('bitmessagesettings', 'sockslisten', str( self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked())) try: # Rounding to integers just for aesthetics - BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', str( + shared.config.set('bitmessagesettings', 'maxdownloadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text())))) - BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str( + shared.config.set('bitmessagesettings', 'maxuploadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) - except ValueError: - QtGui.QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( + except: + QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) - else: - set_rates(BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"), - BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate")) - BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', str( - int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text())))) - - BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', + shared.config.set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) - BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str( + shared.config.set('bitmessagesettings', 'namecoinrpchost', str( self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcport', str( + shared.config.set('bitmessagesettings', 'namecoinrpcport', str( self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcuser', str( + shared.config.set('bitmessagesettings', 'namecoinrpcuser', str( self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) - BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( + shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str( self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: - BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) + shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( + self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: - BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) - - if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): - BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) - queues.workerQueue.put(('resetPoW', '')) + shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( + self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) acceptableDifficultyChanged = False if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: - if BMConfigParser().get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): + if shared.config.get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True - BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) + shared.config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) == 0: - if BMConfigParser().get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes)): + if shared.config.get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True - BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes))) + shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) if acceptableDifficultyChanged: # It might now be possible to send msgs which were previously marked as toodifficult. # Let us change them to 'msgqueued'. The singleWorker will try to send them and will again # mark them as toodifficult if the receiver's required difficulty is still higher than # we are willing to do. sqlExecute('''UPDATE sent SET status='msgqueued' WHERE status='toodifficult' ''') - queues.workerQueue.put(('sendmessage', '')) + shared.workerQueue.put(('sendmessage', '')) #start:UI setting to stop trying to send messages after X days/months # I'm open to changing this UI to something else if someone has a better idea. if ((self.settingsDialogInstance.ui.lineEditDays.text()=='') and (self.settingsDialogInstance.ui.lineEditMonths.text()=='')):#We need to handle this special case. Bitmessage has its default behavior. The input is blank/blank - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '') - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '') + shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '') + shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') try: float(self.settingsDialogInstance.ui.lineEditDays.text()) @@ -2530,24 +2463,24 @@ class MyForm(settingsmixin.SMainWindow): if (float(self.settingsDialogInstance.ui.lineEditDays.text()) >=0 and float(self.settingsDialogInstance.ui.lineEditMonths.text()) >=0): shared.maximumLengthOfTimeToBotherResendingMessages = (float(str(self.settingsDialogInstance.ui.lineEditDays.text())) * 24 * 60 * 60) + (float(str(self.settingsDialogInstance.ui.lineEditMonths.text())) * (60 * 60 * 24 *365)/12) if shared.maximumLengthOfTimeToBotherResendingMessages < 432000: # If the time period is less than 5 hours, we give zero values to all fields. No message will be sent again. - QtGui.QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate( + QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate( "MainWindow", "Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent.")) - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '0') - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '0') + shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '0') + shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '0') shared.maximumLengthOfTimeToBotherResendingMessages = 0 else: - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', str(float( + shared.config.set('bitmessagesettings', 'stopresendingafterxdays', str(float( self.settingsDialogInstance.ui.lineEditDays.text()))) - BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float( + shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(float( self.settingsDialogInstance.ui.lineEditMonths.text()))) - BMConfigParser().save() + shared.writeKeysFile() if 'win32' in sys.platform or 'win64' in sys.platform: # Auto-startup for Windows RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" - self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat) - if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): + self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) + if shared.config.getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) else: self.settings.remove("PyBitmessage") @@ -2558,17 +2491,21 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux pass - if state.appdata != paths.lookupExeFolder() and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... + if shared.appdata != '' and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') - with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: - BMConfigParser().write(configfile) + with open('keys.dat', 'wb') as configfile: + shared.config.write(configfile) # Write the knownnodes.dat file to disk in the new location - knownnodes.saveKnownNodes(paths.lookupExeFolder()) - os.remove(state.appdata + 'keys.dat') - os.remove(state.appdata + 'knownnodes.dat') - previousAppdataLocation = state.appdata - state.appdata = paths.lookupExeFolder() + shared.knownNodesLock.acquire() + output = open('knownnodes.dat', 'wb') + pickle.dump(shared.knownNodes, output) + output.close() + shared.knownNodesLock.release() + os.remove(shared.appdata + 'keys.dat') + os.remove(shared.appdata + 'knownnodes.dat') + previousAppdataLocation = shared.appdata + shared.appdata = '' debug.restartLoggingInUpdatedAppdataLocation() try: os.remove(previousAppdataLocation + 'debug.log') @@ -2576,106 +2513,143 @@ class MyForm(settingsmixin.SMainWindow): except: pass - if state.appdata == paths.lookupExeFolder() and not self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we ARE using portable mode now but the user selected that we shouldn't... - state.appdata = paths.lookupAppdataFolder() - if not os.path.exists(state.appdata): - os.makedirs(state.appdata) + if shared.appdata == '' and not self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we ARE using portable mode now but the user selected that we shouldn't... + shared.appdata = shared.lookupAppdataFolder() + if not os.path.exists(shared.appdata): + os.makedirs(shared.appdata) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location - BMConfigParser().save() + shared.writeKeysFile() # Write the knownnodes.dat file to disk in the new location - knownnodes.saveKnownNodes(state.appdata) - os.remove(paths.lookupExeFolder() + 'keys.dat') - os.remove(paths.lookupExeFolder() + 'knownnodes.dat') + shared.knownNodesLock.acquire() + output = open(shared.appdata + 'knownnodes.dat', 'wb') + pickle.dump(shared.knownNodes, output) + output.close() + shared.knownNodesLock.release() + os.remove('keys.dat') + os.remove('knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() try: - os.remove(paths.lookupExeFolder() + 'debug.log') - os.remove(paths.lookupExeFolder() + 'debug.log.1') + os.remove('debug.log') + os.remove('debug.log.1') except: pass + def click_radioButtonBlacklist(self): + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': + shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') + shared.writeKeysFile() + # self.ui.tableWidgetBlacklist.clearContents() + self.ui.tableWidgetBlacklist.setRowCount(0) + self.rerenderBlackWhiteList() + self.ui.tabWidget.setTabText(6, 'Blacklist') + + def click_radioButtonWhitelist(self): + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') + shared.writeKeysFile() + # self.ui.tableWidgetBlacklist.clearContents() + self.ui.tableWidgetBlacklist.setRowCount(0) + self.rerenderBlackWhiteList() + self.ui.tabWidget.setTabText(6, 'Whitelist') + + def click_pushButtonAddBlacklist(self): + self.NewBlacklistDialogInstance = AddAddressDialog(self) + if self.NewBlacklistDialogInstance.exec_(): + if self.NewBlacklistDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): + address = addBMIfNotPresent(str( + self.NewBlacklistDialogInstance.ui.lineEditAddress.text())) + # First we must check to see if the address is already in the + # address book. The user cannot add it again or else it will + # cause problems when updating and deleting the entry. + t = (address,) + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + sql = '''select * from blacklist where address=?''' + else: + sql = '''select * from whitelist where address=?''' + queryreturn = sqlQuery(sql,*t) + if queryreturn == []: + self.ui.tableWidgetBlacklist.setSortingEnabled(False) + self.ui.tableWidgetBlacklist.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode( + self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8(), 'utf-8')) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetBlacklist.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetBlacklist.setItem(0, 1, newItem) + self.ui.tableWidgetBlacklist.setSortingEnabled(True) + t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + sql = '''INSERT INTO blacklist VALUES (?,?,?)''' + else: + sql = '''INSERT INTO whitelist VALUES (?,?,?)''' + sqlExecute(sql, *t) + else: + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want.")) + else: + self.statusBar().showMessage(_translate( + "MainWindow", "The address you entered was invalid. Ignoring it.")) + def on_action_SpecialAddressBehaviorDialog(self): - dialogs.SpecialAddressBehaviorDialog(self, BMConfigParser()) - - def on_action_EmailGatewayDialog(self): - dialog = dialogs.EmailGatewayDialog(self, config=BMConfigParser()) + self.dialog = SpecialAddressBehaviorDialog(self) # For Modal dialogs - dialog.exec_() - try: - acct = dialog.data - except AttributeError: - return - - # Only settings remain here - acct.settings() - for i in range(self.ui.comboBoxSendFrom.count()): - if str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) \ - == acct.fromAddress: - self.ui.comboBoxSendFrom.setCurrentIndex(i) - break - else: - self.ui.comboBoxSendFrom.setCurrentIndex(0) - - self.ui.lineEditTo.setText(acct.toAddress) - self.ui.lineEditSubject.setText(acct.subject) - self.ui.textEditMessage.setText(acct.message) - self.ui.tabWidgetSend.setCurrentIndex( - self.ui.tabWidgetSend.indexOf(self.ui.sendDirect) - ) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) - self.ui.textEditMessage.setFocus() - - def on_action_MarkAllRead(self): - if QtGui.QMessageBox.question( - self, "Marking all messages as read?", - _translate( - "MainWindow", - "Are you sure you would like to mark all messages read?" - ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No - ) != QtGui.QMessageBox.Yes: - return - # addressAtCurrentRow = self.getCurrentAccount() - tableWidget = self.getCurrentMessagelist() - - idCount = tableWidget.rowCount() - if idCount == 0: - return - - font = QtGui.QFont() - font.setBold(False) - - msgids = [] - for i in range(0, idCount): - msgids.append(str(tableWidget.item( - i, 3).data(QtCore.Qt.UserRole).toPyObject())) - tableWidget.item(i, 0).setUnread(False) - tableWidget.item(i, 1).setUnread(False) - tableWidget.item(i, 2).setUnread(False) - tableWidget.item(i, 3).setFont(font) - - markread = sqlExecuteChunked( - "UPDATE %s SET read = 1 WHERE %s IN({0}) AND read=0" % ( - ('sent', 'ackdata') if self.getCurrentFolder() == 'sent' - else ('inbox', 'msgid') - ), idCount, *msgids - ) - - if markread > 0: - self.propagateUnreadCount() - # addressAtCurrentRow, self.getCurrentFolder(), None, 0) + if self.dialog.exec_(): + currentRow = self.ui.tableWidgetYourIdentities.currentRow() + addressAtCurrentRow = str( + self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) + if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): + return + if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): + shared.config.set(str( + addressAtCurrentRow), 'mailinglist', 'false') + # Set the color to either black or grey + if shared.config.getboolean(addressAtCurrentRow, 'enabled'): + self.ui.tableWidgetYourIdentities.item( + currentRow, 1).setTextColor(QApplication.palette() + .text().color()) + else: + self.ui.tableWidgetYourIdentities.item( + currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) + else: + shared.config.set(str( + addressAtCurrentRow), 'mailinglist', 'true') + shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( + self.dialog.ui.lineEditMailingListName.text().toUtf8())) + self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta + shared.writeKeysFile() + self.rerenderInboxToLabels() def click_NewAddressDialog(self): - dialogs.NewAddressDialog(self) - - def network_switch(self): - dontconnect_option = not BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'dontconnect') - BMConfigParser().set( - 'bitmessagesettings', 'dontconnect', str(dontconnect_option)) - BMConfigParser().save() - self.ui.updateNetworkSwitchMenuLabel(dontconnect_option) + self.dialog = NewAddressDialog(self) + # For Modal dialogs + if self.dialog.exec_(): + # self.dialog.ui.buttonBox.enabled = False + if self.dialog.ui.radioButtonRandomAddress.isChecked(): + if self.dialog.ui.radioButtonMostAvailable.isChecked(): + streamNumberForAddress = 1 + else: + # User selected 'Use the same stream as an existing + # address.' + streamNumberForAddress = decodeAddress( + self.dialog.ui.comboBoxExisting.currentText())[2] + shared.addressGeneratorQueue.put(('createRandomAddress', 4, streamNumberForAddress, str( + self.dialog.ui.newaddresslabel.text().toUtf8()), 1, "", self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) + else: + if self.dialog.ui.lineEditPassphrase.text() != self.dialog.ui.lineEditPassphraseAgain.text(): + QMessageBox.about(self, _translate("MainWindow", "Passphrase mismatch"), _translate( + "MainWindow", "The passphrase you entered twice doesn\'t match. Try again.")) + elif self.dialog.ui.lineEditPassphrase.text() == "": + QMessageBox.about(self, _translate( + "MainWindow", "Choose a passphrase"), _translate("MainWindow", "You really do need a passphrase.")) + else: + streamNumberForAddress = 1 # this will eventually have to be replaced by logic to determine the most available stream number. + shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, streamNumberForAddress, "unused deterministic address", self.dialog.ui.spinBoxNumberOfAddressesToMake.value( + ), self.dialog.ui.lineEditPassphrase.text().toUtf8(), self.dialog.ui.checkBoxEighteenByteRipe.isChecked())) + else: + print 'new address dialog box rejected' # Quit selected from menu or application indicator def quit(self): @@ -2686,191 +2660,39 @@ class MyForm(settingsmixin.SMainWindow): if reply is QtGui.QMessageBox.No: return ''' - - if self.quitAccepted: - return - - self.show() - self.raise_() - self.activateWindow() - - waitForPow = True - waitForConnection = False - waitForSync = False - - # C PoW currently doesn't support interrupting and OpenCL is untested - if getPowType() == "python" and (powQueueSize() > 0 or PendingUpload().len() > 0): - reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Proof of work pending"), - _translate("MainWindow", "%n object(s) pending proof of work", None, QtCore.QCoreApplication.CodecForTr, powQueueSize()) + ", " + - _translate("MainWindow", "%n object(s) waiting to be distributed", None, QtCore.QCoreApplication.CodecForTr, PendingUpload().len()) + "\n\n" + - _translate("MainWindow", "Wait until these tasks finish?"), - QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) - if reply == QtGui.QMessageBox.No: - waitForPow = False - elif reply == QtGui.QMessageBox.Cancel: - return - - if PendingDownloadQueue.totalSize() > 0: - reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Synchronisation pending"), - _translate("MainWindow", "Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes?", None, QtCore.QCoreApplication.CodecForTr, PendingDownloadQueue.totalSize()), - QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) - if reply == QtGui.QMessageBox.Yes: - waitForSync = True - elif reply == QtGui.QMessageBox.Cancel: - return - else: - PendingDownloadQueue.stop() - - if shared.statusIconColor == 'red' and not BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'dontconnect'): - reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Not connected"), - _translate("MainWindow", "Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes?"), - QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) - if reply == QtGui.QMessageBox.Yes: - waitForConnection = True - waitForSync = True - elif reply == QtGui.QMessageBox.Cancel: - return - - self.quitAccepted = True - - self.updateStatusBar(_translate( - "MainWindow", "Shutting down PyBitmessage... %1%").arg(0)) - - if waitForConnection: - self.updateStatusBar(_translate( - "MainWindow", "Waiting for network connection...")) - while shared.statusIconColor == 'red': - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - - # this probably will not work correctly, because there is a delay between the status icon turning red and inventory exchange, but it's better than nothing. - if waitForSync: - self.updateStatusBar(_translate( - "MainWindow", "Waiting for finishing synchronisation...")) - while PendingDownloadQueue.totalSize() > 0: - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - - if waitForPow: - # check if PoW queue empty - maxWorkerQueue = 0 - curWorkerQueue = powQueueSize() - while curWorkerQueue > 0: - # worker queue size - curWorkerQueue = powQueueSize() - if curWorkerQueue > maxWorkerQueue: - maxWorkerQueue = curWorkerQueue - if curWorkerQueue > 0: - self.updateStatusBar(_translate( - "MainWindow", "Waiting for PoW to finish... %1%" - ).arg(50 * (maxWorkerQueue - curWorkerQueue) - / maxWorkerQueue) - ) - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - - self.updateStatusBar(_translate( - "MainWindow", "Shutting down Pybitmessage... %1%").arg(50)) - - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - if maxWorkerQueue > 0: - # a bit of time so that the hashHolder is populated - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - - # check if upload (of objects created locally) pending - self.updateStatusBar(_translate( - "MainWindow", "Waiting for objects to be sent... %1%").arg(50)) - try: - while PendingUpload().progress() < 1: - self.updateStatusBar(_translate( - "MainWindow", - "Waiting for objects to be sent... %1%" - ).arg(int(50 + 20 * PendingUpload().progress())) - ) - time.sleep(0.5) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - except PendingUploadDeadlineException: - pass - - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - - # save state and geometry self and all widgets - self.updateStatusBar(_translate( - "MainWindow", "Saving settings... %1%").arg(70)) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - self.saveSettings() - for attr, obj in self.ui.__dict__.iteritems(): - if hasattr(obj, "__class__") \ - and isinstance(obj, settingsmixin.SettingsMixin): - saveMethod = getattr(obj, "saveSettings", None) - if callable(saveMethod): - obj.saveSettings() - - self.updateStatusBar(_translate( - "MainWindow", "Shutting down core... %1%").arg(80)) - QtCore.QCoreApplication.processEvents( - QtCore.QEventLoop.AllEvents, 1000 - ) - shutdown.doCleanShutdown() - self.updateStatusBar(_translate( - "MainWindow", "Stopping notifications... %1%").arg(90)) + shared.doCleanShutdown() self.tray.hide() - - self.updateStatusBar(_translate( - "MainWindow", "Shutdown imminent... %1%").arg(100)) - shared.thisapp.cleanup() - logger.info("Shutdown complete") - super(MyForm, myapp).close() - # return + # unregister the messaging system + if self.mmapp is not None: + self.mmapp.unregister() + self.statusBar().showMessage(_translate( + "MainWindow", "All done. Closing user interface...")) os._exit(0) # window close event def closeEvent(self, event): self.appIndicatorHide() - trayonclose = False + minimizeonclose = False try: - trayonclose = BMConfigParser().getboolean( - 'bitmessagesettings', 'trayonclose') + minimizeonclose = shared.config.getboolean( + 'bitmessagesettings', 'minimizeonclose') except Exception: pass - # always ignore, it shuts down by itself - if self.quitAccepted: - event.accept() - return - - event.ignore() - if not trayonclose: + if minimizeonclose: + # minimize the application + event.ignore() + else: # quit the application + event.accept() self.quit() def on_action_InboxMessageForceHtml(self): - msgid = self.getCurrentMessageId() - textEdit = self.getCurrentMessageTextedit() - if not msgid: - return + currentInboxRow = self.ui.tableWidgetInbox.currentRow() + + msgid = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: @@ -2891,46 +2713,33 @@ class MyForm(settingsmixin.SMainWindow): content = ' '.join(lines) # To keep the whitespace between lines content = shared.fixPotentiallyInvalidUTF8Data(content) content = unicode(content, 'utf-8)') - textEdit.setHtml(QtCore.QString(content)) + self.ui.textEditInboxMessage.setHtml(QtCore.QString(content)) def on_action_InboxMarkUnread(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - - msgids = set() - # modified = 0 - for row in tableWidget.selectedIndexes(): + font = QFont() + font.setBold(True) + inventoryHashesToMarkUnread = [] + for row in self.ui.tableWidgetInbox.selectedIndexes(): currentRow = row.row() - msgid = str(tableWidget.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - msgids.add(msgid) - # if not tableWidget.item(currentRow, 0).unread: - # modified += 1 - self.updateUnreadStatus(tableWidget, currentRow, msgid, False) - - # for 1081 - idCount = len(msgids) - # rowcount = - sqlExecuteChunked( - '''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''', - idCount, *msgids - ) - - self.propagateUnreadCount() - # if rowcount == 1: - # # performance optimisation - # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder()) - # else: - # self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) - # tableWidget.selectRow(currentRow + 1) + inventoryHashToMarkUnread = str(self.ui.tableWidgetInbox.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) + self.ui.tableWidgetInbox.item(currentRow, 0).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 1).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 2).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 3).setFont(font) + #sqlite requires the exact number of ?s to prevent injection + sqlExecute('''UPDATE inbox SET read=0 WHERE msgid IN (%s)''' % ( + "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) + self.changedInboxUnread() + # self.ui.tableWidgetInbox.selectRow(currentRow + 1) # This doesn't de-select the last message if you try to mark it unread, but that doesn't interfere. Might not be necessary. # We could also select upwards, but then our problem would be with the topmost message. - # tableWidget.clearSelection() manages to mark the message as read again. + # self.ui.tableWidgetInbox.clearSelection() manages to mark the message as read again. # Format predefined text on message reply. def quoted_text(self, message): - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow'): + if not shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow'): return '\n\n------------------------------------------------------\n' + message quoteWrapper = textwrap.TextWrapper(replace_whitespace = False, @@ -2950,245 +2759,114 @@ class MyForm(settingsmixin.SMainWindow): return quoteWrapper.fill(line) return '\n'.join([quote_line(l) for l in message.splitlines()]) + '\n\n' - def setSendFromComboBox(self, address = None): - if address is None: - messagelist = self.getCurrentMessagelist() - if messagelist: - currentInboxRow = messagelist.currentRow() - address = messagelist.item( - currentInboxRow, 0).address - for box in [self.ui.comboBoxSendFrom, self.ui.comboBoxSendFromBroadcast]: - listOfAddressesInComboBoxSendFrom = [str(box.itemData(i).toPyObject()) for i in range(box.count())] - if address in listOfAddressesInComboBoxSendFrom: - currentIndex = listOfAddressesInComboBoxSendFrom.index(address) - box.setCurrentIndex(currentIndex) - else: - box.setCurrentIndex(0) - - def on_action_InboxReplyChan(self): - self.on_action_InboxReply(self.REPLY_TYPE_CHAN) - - def on_action_InboxReply(self, replyType = None): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - - if replyType is None: - replyType = self.REPLY_TYPE_SENDER - - # save this to return back after reply is done - self.replyFromTab = self.ui.tabWidget.currentIndex() - - currentInboxRow = tableWidget.currentRow() - toAddressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 0).address - acct = accountClass(toAddressAtCurrentInboxRow) - fromAddressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).address - msgid = str(tableWidget.item( - currentInboxRow, 3).data(QtCore.Qt.UserRole).toPyObject()) + def on_action_InboxReply(self): + currentInboxRow = self.ui.tableWidgetInbox.currentRow() + toAddressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 0).data(Qt.UserRole).toPyObject()) + fromAddressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 1).data(Qt.UserRole).toPyObject()) + msgid = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: for row in queryreturn: messageAtCurrentInboxRow, = row - acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, tableWidget.item(currentInboxRow, 2).subject, messageAtCurrentInboxRow) - widget = { - 'subject': self.ui.lineEditSubject, - 'from': self.ui.comboBoxSendFrom, - 'message': self.ui.textEditMessage - } - if toAddressAtCurrentInboxRow == str_broadcast_subscribers: - self.ui.tabWidgetSend.setCurrentIndex( - self.ui.tabWidgetSend.indexOf(self.ui.sendDirect) - ) -# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow - elif not BMConfigParser().has_section(toAddressAtCurrentInboxRow): + if toAddressAtCurrentInboxRow == self.str_broadcast_subscribers: + self.ui.labelFrom.setText('') + elif not shared.config.has_section(toAddressAtCurrentInboxRow): QtGui.QMessageBox.information(self, _translate("MainWindow", "Address is gone"), _translate( - "MainWindow", "Bitmessage cannot find your address %1. Perhaps you removed it?").arg(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok) - elif not BMConfigParser().getboolean(toAddressAtCurrentInboxRow, 'enabled'): + "MainWindow", "Bitmessage cannot find your address %1. Perhaps you removed it?").arg(toAddressAtCurrentInboxRow), QMessageBox.Ok) + self.ui.labelFrom.setText('') + elif not shared.config.getboolean(toAddressAtCurrentInboxRow, 'enabled'): QtGui.QMessageBox.information(self, _translate("MainWindow", "Address disabled"), _translate( - "MainWindow", "Error: The address from which you are trying to send is disabled. You\'ll have to enable it on the \'Your Identities\' tab before using it."), QtGui.QMessageBox.Ok) + "MainWindow", "Error: The address from which you are trying to send is disabled. You\'ll have to enable it on the \'Your Identities\' tab before using it."), QMessageBox.Ok) + self.ui.labelFrom.setText('') else: - self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow) - broadcast_tab_index = self.ui.tabWidgetSend.indexOf( - self.ui.sendBroadcast - ) - if self.ui.tabWidgetSend.currentIndex() == broadcast_tab_index: - widget = { - 'subject': self.ui.lineEditSubjectBroadcast, - 'from': self.ui.comboBoxSendFromBroadcast, - 'message': self.ui.textEditMessageBroadcast - } - self.ui.tabWidgetSend.setCurrentIndex(broadcast_tab_index) - toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow - if fromAddressAtCurrentInboxRow == tableWidget.item(currentInboxRow, 1).label or ( - isinstance(acct, GatewayAccount) and fromAddressAtCurrentInboxRow == acct.relayAddress): - self.ui.lineEditTo.setText(str(acct.fromAddress)) - else: - self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 1).label + " <" + str(acct.fromAddress) + ">") + self.ui.labelFrom.setText(toAddressAtCurrentInboxRow) + self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) + + self.ui.lineEditTo.setText(str(fromAddressAtCurrentInboxRow)) # If the previous message was to a chan then we should send our reply to the chan rather than to the particular person who sent the message. - if acct.type == AccountMixin.CHAN and replyType == self.REPLY_TYPE_CHAN: - logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') - if toAddressAtCurrentInboxRow == tableWidget.item(currentInboxRow, 0).label: + if shared.config.has_section(toAddressAtCurrentInboxRow): + if shared.safeConfigGetBoolean(toAddressAtCurrentInboxRow, 'chan'): + print 'original sent to a chan. Setting the to address in the reply to the chan address.' self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) - else: - self.ui.lineEditTo.setText(tableWidget.item(currentInboxRow, 0).label + " <" + str(acct.toAddress) + ">") - self.setSendFromComboBox(toAddressAtCurrentInboxRow) - - quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) - widget['message'].setPlainText(quotedText) - if acct.subject[0:3] in ['Re:', 'RE:']: - widget['subject'].setText(tableWidget.item(currentInboxRow, 2).label) + listOfAddressesInComboBoxSendFrom = [str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) for i in range(self.ui.comboBoxSendFrom.count())] + if toAddressAtCurrentInboxRow in listOfAddressesInComboBoxSendFrom: + currentIndex = listOfAddressesInComboBoxSendFrom.index(toAddressAtCurrentInboxRow) + self.ui.comboBoxSendFrom.setCurrentIndex(currentIndex) else: - widget['subject'].setText('Re: ' + tableWidget.item(currentInboxRow, 2).label) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) - widget['message'].setFocus() + self.ui.comboBoxSendFrom.setCurrentIndex(0) + + quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8')) + self.ui.textEditMessage.setText(quotedText) + if self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()[0:3] in ['Re:', 'RE:']: + self.ui.lineEditSubject.setText( + self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()) + else: + self.ui.lineEditSubject.setText( + 'Re: ' + self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()) + self.ui.radioButtonSpecific.setChecked(True) + self.ui.tabWidget.setCurrentIndex(1) def on_action_InboxAddSenderToAddressBook(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - currentInboxRow = tableWidget.currentRow() - # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() - addressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).data(QtCore.Qt.UserRole) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) - self.click_pushButtonAddAddressBook( - dialogs.AddAddressDialog(self, addressAtCurrentInboxRow)) - - def on_action_InboxAddSenderToBlackList(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - currentInboxRow = tableWidget.currentRow() - # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() - addressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).data(QtCore.Qt.UserRole) - recipientAddress = tableWidget.item( - currentInboxRow, 0).data(QtCore.Qt.UserRole) + currentInboxRow = self.ui.tableWidgetInbox.currentRow() + # self.ui.tableWidgetInbox.item(currentRow,1).data(Qt.UserRole).toPyObject() + addressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 1).data(Qt.UserRole).toPyObject()) # Let's make sure that it isn't already in the address book - queryreturn = sqlQuery('''select * from blacklist where address=?''', + queryreturn = sqlQuery('''select * from addressbook where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + BMConfigParser().get(recipientAddress, "label") - sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', - label, - addressAtCurrentInboxRow, True) - self.ui.blackwhitelist.rerenderBlackWhiteList() - self.updateStatusBar(_translate( - "MainWindow", - "Entry added to the blacklist. Edit the label to your liking.") - ) + self.ui.tableWidgetAddressBook.insertRow(0) + newItem = QtGui.QTableWidgetItem( + '--New entry. Change label in Address Book.--') + self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) + newItem.setIcon(avatarize(addressAtCurrentInboxRow)) + newItem = QtGui.QTableWidgetItem(addressAtCurrentInboxRow) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) + sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', + '--New entry. Change label in Address Book.--', + addressAtCurrentInboxRow) + self.ui.tabWidget.setCurrentIndex(5) + self.ui.tableWidgetAddressBook.setCurrentCell(0, 0) + self.statusBar().showMessage(_translate( + "MainWindow", "Entry added to the Address Book. Edit the label to your liking.")) else: - self.updateStatusBar(_translate( - "MainWindow", - "Error: You cannot add the same address to your blacklist" - " twice. Try renaming the existing one if you want.")) - - def deleteRowFromMessagelist(self, row = None, inventoryHash = None, ackData = None, messageLists = None): - if messageLists is None: - messageLists = (self.ui.tableWidgetInbox, self.ui.tableWidgetInboxChans, self.ui.tableWidgetInboxSubscriptions) - elif type(messageLists) not in (list, tuple): - messageLists = (messageLists) - for messageList in messageLists: - if row is not None: - inventoryHash = str(messageList.item(row, 3).data( - QtCore.Qt.UserRole).toPyObject()) - messageList.removeRow(row) - elif inventoryHash is not None: - for i in range(messageList.rowCount() - 1, -1, -1): - if messageList.item(i, 3).data(QtCore.Qt.UserRole).toPyObject() == inventoryHash: - messageList.removeRow(i) - elif ackData is not None: - for i in range(messageList.rowCount() - 1, -1, -1): - if messageList.item(i, 3).data(QtCore.Qt.UserRole).toPyObject() == ackData: - messageList.removeRow(i) + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want.")) # Send item on the Inbox tab to trash def on_action_InboxTrash(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - currentRow = 0 - folder = self.getCurrentFolder() - shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier - tableWidget.setUpdatesEnabled(False); - inventoryHashesToTrash = [] - # ranges in reversed order - for r in sorted(tableWidget.selectedRanges(), key=lambda r: r.topRow())[::-1]: - for i in range(r.bottomRow()-r.topRow()+1): - inventoryHashToTrash = str(tableWidget.item( - r.topRow()+i, 3).data(QtCore.Qt.UserRole).toPyObject()) - if inventoryHashToTrash in inventoryHashesToTrash: - continue - inventoryHashesToTrash.append(inventoryHashToTrash) - currentRow = r.topRow() - self.getCurrentMessageTextedit().setText("") - tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) - idCount = len(inventoryHashesToTrash) - if folder == "trash" or shifted: - sqlExecuteChunked('''DELETE FROM inbox WHERE msgid IN ({0})''', - idCount, *inventoryHashesToTrash) - else: - sqlExecuteChunked('''UPDATE inbox SET folder='trash' WHERE msgid IN ({0})''', - idCount, *inventoryHashesToTrash) - tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) - tableWidget.setUpdatesEnabled(True) - self.propagateUnreadCount(self.getCurrentAccount, folder) - self.updateStatusBar(_translate( - "MainWindow", "Moved items to trash.")) - - def on_action_TrashUndelete(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - currentRow = 0 - tableWidget.setUpdatesEnabled(False) - inventoryHashesToTrash = [] - # ranges in reversed order - for r in sorted(tableWidget.selectedRanges(), key=lambda r: r.topRow())[::-1]: - for i in range(r.bottomRow()-r.topRow()+1): - inventoryHashToTrash = str(tableWidget.item( - r.topRow()+i, 3).data(QtCore.Qt.UserRole).toPyObject()) - if inventoryHashToTrash in inventoryHashesToTrash: - continue - inventoryHashesToTrash.append(inventoryHashToTrash) - currentRow = r.topRow() - self.getCurrentMessageTextedit().setText("") - tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) + while self.ui.tableWidgetInbox.selectedIndexes() != []: + currentRow = self.ui.tableWidgetInbox.selectedIndexes()[0].row() + inventoryHashToTrash = str(self.ui.tableWidgetInbox.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) + self.ui.textEditInboxMessage.setText("") + self.ui.tableWidgetInbox.removeRow(currentRow) + self.statusBar().showMessage(_translate( + "MainWindow", "Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back.")) if currentRow == 0: - tableWidget.selectRow(currentRow) + self.ui.tableWidgetInbox.selectRow(currentRow) else: - tableWidget.selectRow(currentRow - 1) - idCount = len(inventoryHashesToTrash) - sqlExecuteChunked('''UPDATE inbox SET folder='inbox' WHERE msgid IN({0})''', - idCount, *inventoryHashesToTrash) - tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) - tableWidget.setUpdatesEnabled(True) - self.propagateUnreadCount(self.getCurrentAccount) - self.updateStatusBar(_translate("MainWindow", "Undeleted item.")) + self.ui.tableWidgetInbox.selectRow(currentRow - 1) def on_action_InboxSaveMessageAs(self): - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - currentInboxRow = tableWidget.currentRow() + currentInboxRow = self.ui.tableWidgetInbox.currentRow() try: - subjectAtCurrentInboxRow = str(tableWidget.item( - currentInboxRow, 2).data(QtCore.Qt.UserRole)) + subjectAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item(currentInboxRow,2).text()) except: subjectAtCurrentInboxRow = '' # Retrieve the message data out of the SQL database - msgid = str(tableWidget.item( - currentInboxRow, 3).data(QtCore.Qt.UserRole).toPyObject()) + msgid = str(self.ui.tableWidgetInbox.item( + currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: @@ -3196,48 +2874,37 @@ class MyForm(settingsmixin.SMainWindow): message, = row defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt' - filename = QtGui.QFileDialog.getSaveFileName(self, _translate("MainWindow","Save As..."), defaultFilename, "Text files (*.txt);;All files (*.*)") + filename = QFileDialog.getSaveFileName(self, _translate("MainWindow","Save As..."), defaultFilename, "Text files (*.txt);;All files (*.*)") if filename == '': return try: f = open(filename, 'w') f.write(message) f.close() - except Exception: - logger.exception('Message not saved', exc_info=True) - self.updateStatusBar(_translate("MainWindow", "Write error.")) + except Exception, e: + sys.stderr.write('Write error: '+ e) + self.statusBar().showMessage(_translate("MainWindow", "Write error.")) # Send item on the Sent tab to trash def on_action_SentTrash(self): - currentRow = 0 - unread = False - tableWidget = self.getCurrentMessagelist() - if not tableWidget: - return - folder = self.getCurrentFolder() - shifted = (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier) > 0 - while tableWidget.selectedIndexes() != []: - currentRow = tableWidget.selectedIndexes()[0].row() - ackdataToTrash = str(tableWidget.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - if folder == "trash" or shifted: - sqlExecute('''DELETE FROM sent WHERE ackdata=?''', ackdataToTrash) - else: - sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) - if tableWidget.item(currentRow, 0).unread: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) - self.getCurrentMessageTextedit().setPlainText("") - tableWidget.removeRow(currentRow) - self.updateStatusBar(_translate( - "MainWindow", "Moved items to trash.")) - - self.ui.tableWidgetInbox.selectRow( - currentRow if currentRow == 0 else currentRow - 1) + while self.ui.tableWidgetSent.selectedIndexes() != []: + currentRow = self.ui.tableWidgetSent.selectedIndexes()[0].row() + ackdataToTrash = str(self.ui.tableWidgetSent.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) + self.ui.textEditSentMessage.setPlainText("") + self.ui.tableWidgetSent.removeRow(currentRow) + self.statusBar().showMessage(_translate( + "MainWindow", "Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back.")) + if currentRow == 0: + self.ui.tableWidgetSent.selectRow(currentRow) + else: + self.ui.tableWidgetSent.selectRow(currentRow - 1) def on_action_ForceSend(self): - currentRow = self.ui.tableWidgetInbox.currentRow() - addressAtCurrentRow = self.ui.tableWidgetInbox.item( - currentRow, 0).data(QtCore.Qt.UserRole) + currentRow = self.ui.tableWidgetSent.currentRow() + addressAtCurrentRow = str(self.ui.tableWidgetSent.item( + currentRow, 0).data(Qt.UserRole).toPyObject()) toRipe = decodeAddress(addressAtCurrentRow)[3] sqlExecute( '''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''', @@ -3245,14 +2912,14 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''') for row in queryreturn: ackdata, = row - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, 'Overriding maximum-difficulty setting. Work queued.'))) - queues.workerQueue.put(('sendmessage', '')) + shared.workerQueue.put(('sendmessage', '')) def on_action_SentClipboard(self): - currentRow = self.ui.tableWidgetInbox.currentRow() - addressAtCurrentRow = self.ui.tableWidgetInbox.item( - currentRow, 0).data(QtCore.Qt.UserRole) + currentRow = self.ui.tableWidgetSent.currentRow() + addressAtCurrentRow = str(self.ui.tableWidgetSent.item( + currentRow, 0).data(Qt.UserRole).toPyObject()) clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) @@ -3271,8 +2938,8 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''DELETE FROM addressbook WHERE label=? AND address=?''', str(labelAtCurrentRow), str(addressAtCurrentRow)) self.ui.tableWidgetAddressBook.removeRow(currentRow) - self.rerenderMessagelistFromLabels() - self.rerenderMessagelistToLabels() + self.rerenderInboxFromLabels() + self.rerenderSentToLabels() def on_action_AddressBookClipboard(self): fullStringOfAddresses = '' @@ -3297,23 +2964,18 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tableWidgetAddressBook.selectedIndexes()[i].row()] = 0 for currentRow in listOfSelectedRows: addressAtCurrentRow = self.ui.tableWidgetAddressBook.item( - currentRow, 0).address - labelAtCurrentRow = self.ui.tableWidgetAddressBook.item( - currentRow, 0).label - stringToAdd = labelAtCurrentRow + " <" + addressAtCurrentRow + ">" + currentRow, 1).text() if self.ui.lineEditTo.text() == '': - self.ui.lineEditTo.setText(stringToAdd) + self.ui.lineEditTo.setText(str(addressAtCurrentRow)) else: - self.ui.lineEditTo.setText(unicode( - self.ui.lineEditTo.text().toUtf8(), encoding="UTF-8") + '; ' + stringToAdd) + self.ui.lineEditTo.setText(str( + self.ui.lineEditTo.text()) + '; ' + str(addressAtCurrentRow)) if listOfSelectedRows == {}: - self.updateStatusBar(_translate( + self.statusBar().showMessage(_translate( "MainWindow", "No addresses selected.")) else: - self.statusbar.clearMessage() - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.send) - ) + self.statusBar().showMessage('') + self.ui.tabWidget.setCurrentIndex(1) def on_action_AddressBookSubscribe(self): listOfSelectedRows = {} @@ -3323,390 +2985,201 @@ class MyForm(settingsmixin.SMainWindow): addressAtCurrentRow = str(self.ui.tableWidgetAddressBook.item(currentRow,1).text()) # Then subscribe to it... provided it's not already in the address book if shared.isAddressInMySubscriptionsList(addressAtCurrentRow): - self.updateStatusBar(_translate( - "MainWindow", - "Error: You cannot add the same address to your" - " subscriptions twice. Perhaps rename the existing" - " one if you want.")) + self.statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want.")) continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) - self.ui.tabWidget.setCurrentIndex( - self.ui.tabWidget.indexOf(self.ui.subscriptions) - ) + self.ui.tabWidget.setCurrentIndex(4) def on_context_menuAddressBook(self, point): - self.popMenuAddressBook = QtGui.QMenu(self) - self.popMenuAddressBook.addAction(self.actionAddressBookSend) - self.popMenuAddressBook.addAction(self.actionAddressBookClipboard) - self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe) - self.popMenuAddressBook.addAction(self.actionAddressBookSetAvatar) - self.popMenuAddressBook.addAction(self.actionAddressBookSetSound) - self.popMenuAddressBook.addSeparator() - self.popMenuAddressBook.addAction(self.actionAddressBookNew) - normal = True - for row in self.ui.tableWidgetAddressBook.selectedIndexes(): - currentRow = row.row() - type = self.ui.tableWidgetAddressBook.item( - currentRow, 0).type - if type != AccountMixin.NORMAL: - normal = False - if normal: - # only if all selected addressbook items are normal, allow delete - self.popMenuAddressBook.addAction(self.actionAddressBookDelete) self.popMenuAddressBook.exec_( self.ui.tableWidgetAddressBook.mapToGlobal(point)) # Group of functions for the Subscriptions dialog box def on_action_SubscriptionsNew(self): self.click_pushButtonAddSubscription() - + def on_action_SubscriptionsDelete(self): - if QtGui.QMessageBox.question( - self, "Delete subscription?", - _translate( - "MainWindow", - "If you delete the subscription, messages that you" - " already received will become inaccessible. Maybe" - " you can consider disabling the subscription instead." - " Disabled subscriptions will not receive new" - " messages, but you can still view messages you" - " already received.\n\nAre you sure you want to" - " delete the subscription?" - ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No - ) != QtGui.QMessageBox.Yes: - return - address = self.getCurrentAccount() - sqlExecute('''DELETE FROM subscriptions WHERE address=?''', - address) - self.rerenderTabTreeSubscriptions() - self.rerenderMessagelistFromLabels() - self.rerenderAddressBook() + print 'clicked Delete' + currentRow = self.ui.tableWidgetSubscriptions.currentRow() + labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 0).text().toUtf8() + addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 1).text() + sqlExecute('''DELETE FROM subscriptions WHERE label=? AND address=?''', + str(labelAtCurrentRow), str(addressAtCurrentRow)) + self.ui.tableWidgetSubscriptions.removeRow(currentRow) + self.rerenderInboxFromLabels() shared.reloadBroadcastSendersForWhichImWatching() def on_action_SubscriptionsClipboard(self): - address = self.getCurrentAccount() + currentRow = self.ui.tableWidgetSubscriptions.currentRow() + addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 1).text() clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(address)) + clipboard.setText(str(addressAtCurrentRow)) def on_action_SubscriptionsEnable(self): - address = self.getCurrentAccount() + currentRow = self.ui.tableWidgetSubscriptions.currentRow() + labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 0).text().toUtf8() + addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 1).text() sqlExecute( - '''update subscriptions set enabled=1 WHERE address=?''', - address) - account = self.getCurrentItem() - account.setEnabled(True) - self.rerenderAddressBook() + '''update subscriptions set enabled=1 WHERE label=? AND address=?''', + str(labelAtCurrentRow), str(addressAtCurrentRow)) + self.ui.tableWidgetSubscriptions.item( + currentRow, 0).setTextColor(QApplication.palette().text().color()) + self.ui.tableWidgetSubscriptions.item( + currentRow, 1).setTextColor(QApplication.palette().text().color()) shared.reloadBroadcastSendersForWhichImWatching() def on_action_SubscriptionsDisable(self): - address = self.getCurrentAccount() + currentRow = self.ui.tableWidgetSubscriptions.currentRow() + labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 0).text().toUtf8() + addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 1).text() sqlExecute( - '''update subscriptions set enabled=0 WHERE address=?''', - address) - account = self.getCurrentItem() - account.setEnabled(False) - self.rerenderAddressBook() + '''update subscriptions set enabled=0 WHERE label=? AND address=?''', + str(labelAtCurrentRow), str(addressAtCurrentRow)) + self.ui.tableWidgetSubscriptions.item( + currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetSubscriptions.item( + currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): - currentItem = self.getCurrentItem() - self.popMenuSubscriptions = QtGui.QMenu(self) - if isinstance(currentItem, Ui_AddressWidget): - self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew) - self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete) - self.popMenuSubscriptions.addSeparator() - if currentItem.isEnabled: - self.popMenuSubscriptions.addAction(self.actionsubscriptionsDisable) - else: - self.popMenuSubscriptions.addAction(self.actionsubscriptionsEnable) - self.popMenuSubscriptions.addAction(self.actionsubscriptionsSetAvatar) - self.popMenuSubscriptions.addSeparator() - self.popMenuSubscriptions.addAction(self.actionsubscriptionsClipboard) - self.popMenuSubscriptions.addSeparator() - self.popMenuSubscriptions.addAction(self.actionMarkAllRead) self.popMenuSubscriptions.exec_( - self.ui.treeWidgetSubscriptions.mapToGlobal(point)) + self.ui.tableWidgetSubscriptions.mapToGlobal(point)) - def widgetConvert (self, widget): - if widget == self.ui.tableWidgetInbox: - return self.ui.treeWidgetYourIdentities - elif widget == self.ui.tableWidgetInboxSubscriptions: - return self.ui.treeWidgetSubscriptions - elif widget == self.ui.tableWidgetInboxChans: - return self.ui.treeWidgetChans - elif widget == self.ui.treeWidgetYourIdentities: - return self.ui.tableWidgetInbox - elif widget == self.ui.treeWidgetSubscriptions: - return self.ui.tableWidgetInboxSubscriptions - elif widget == self.ui.treeWidgetChans: - return self.ui.tableWidgetInboxChans + # Group of functions for the Blacklist dialog box + def on_action_BlacklistNew(self): + self.click_pushButtonAddBlacklist() + + def on_action_BlacklistDelete(self): + currentRow = self.ui.tableWidgetBlacklist.currentRow() + labelAtCurrentRow = self.ui.tableWidgetBlacklist.item( + currentRow, 0).text().toUtf8() + addressAtCurrentRow = self.ui.tableWidgetBlacklist.item( + currentRow, 1).text() + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + sqlExecute( + '''DELETE FROM blacklist WHERE label=? AND address=?''', + str(labelAtCurrentRow), str(addressAtCurrentRow)) else: - return None + sqlExecute( + '''DELETE FROM whitelist WHERE label=? AND address=?''', + str(labelAtCurrentRow), str(addressAtCurrentRow)) + self.ui.tableWidgetBlacklist.removeRow(currentRow) - def getCurrentTreeWidget(self): - currentIndex = self.ui.tabWidget.currentIndex(); - treeWidgetList = [ - self.ui.treeWidgetYourIdentities, - False, - self.ui.treeWidgetSubscriptions, - self.ui.treeWidgetChans - ] - if currentIndex >= 0 and currentIndex < len(treeWidgetList): - return treeWidgetList[currentIndex] + def on_action_BlacklistClipboard(self): + currentRow = self.ui.tableWidgetBlacklist.currentRow() + addressAtCurrentRow = self.ui.tableWidgetBlacklist.item( + currentRow, 1).text() + clipboard = QtGui.QApplication.clipboard() + clipboard.setText(str(addressAtCurrentRow)) + + def on_context_menuBlacklist(self, point): + self.popMenuBlacklist.exec_( + self.ui.tableWidgetBlacklist.mapToGlobal(point)) + + def on_action_BlacklistEnable(self): + currentRow = self.ui.tableWidgetBlacklist.currentRow() + addressAtCurrentRow = self.ui.tableWidgetBlacklist.item( + currentRow, 1).text() + self.ui.tableWidgetBlacklist.item( + currentRow, 0).setTextColor(QApplication.palette().text().color()) + self.ui.tableWidgetBlacklist.item( + currentRow, 1).setTextColor(QApplication.palette().text().color()) + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + sqlExecute( + '''UPDATE blacklist SET enabled=1 WHERE address=?''', + str(addressAtCurrentRow)) else: - return False + sqlExecute( + '''UPDATE whitelist SET enabled=1 WHERE address=?''', + str(addressAtCurrentRow)) - def getAccountTreeWidget(self, account): - try: - if account.type == AccountMixin.CHAN: - return self.ui.treeWidgetChans - elif account.type == AccountMixin.SUBSCRIPTION: - return self.ui.treeWidgetSubscriptions - else: - return self.ui.treeWidgetYourIdentities - except: - return self.ui.treeWidgetYourIdentities - - def getCurrentMessagelist(self): - currentIndex = self.ui.tabWidget.currentIndex(); - messagelistList = [ - self.ui.tableWidgetInbox, - False, - self.ui.tableWidgetInboxSubscriptions, - self.ui.tableWidgetInboxChans, - ] - if currentIndex >= 0 and currentIndex < len(messagelistList): - return messagelistList[currentIndex] + def on_action_BlacklistDisable(self): + currentRow = self.ui.tableWidgetBlacklist.currentRow() + addressAtCurrentRow = self.ui.tableWidgetBlacklist.item( + currentRow, 1).text() + self.ui.tableWidgetBlacklist.item( + currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetBlacklist.item( + currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + sqlExecute( + '''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) else: - return False - - def getAccountMessagelist(self, account): - try: - if account.type == AccountMixin.CHAN: - return self.ui.tableWidgetInboxChans - elif account.type == AccountMixin.SUBSCRIPTION: - return self.ui.tableWidgetInboxSubscriptions - else: - return self.ui.tableWidgetInbox - except: - return self.ui.tableWidgetInbox - - def getCurrentMessageId(self): - messagelist = self.getCurrentMessagelist() - if messagelist: - currentRow = messagelist.currentRow() - if currentRow >= 0: - msgid = str(messagelist.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - # data is saved at the 4. column of the table... - return msgid - return False - - def getCurrentMessageTextedit(self): - currentIndex = self.ui.tabWidget.currentIndex() - messagelistList = [ - self.ui.textEditInboxMessage, - False, - self.ui.textEditInboxMessageSubscriptions, - self.ui.textEditInboxMessageChans, - ] - if currentIndex >= 0 and currentIndex < len(messagelistList): - return messagelistList[currentIndex] - else: - return False - - def getAccountTextedit(self, account): - try: - if account.type == AccountMixin.CHAN: - return self.ui.textEditInboxMessageChans - elif account.type == AccountMixin.SUBSCRIPTION: - return self.ui.textEditInboxSubscriptions - else: - return self.ui.textEditInboxMessage - except: - return self.ui.textEditInboxMessage - - def getCurrentSearchLine(self, currentIndex=None, retObj=False): - if currentIndex is None: - currentIndex = self.ui.tabWidget.currentIndex() - messagelistList = [ - self.ui.inboxSearchLineEdit, - False, - self.ui.inboxSearchLineEditSubscriptions, - self.ui.inboxSearchLineEditChans, - ] - if currentIndex >= 0 and currentIndex < len(messagelistList): - if retObj: - return messagelistList[currentIndex] - else: - return messagelistList[currentIndex].text().toUtf8().data() - else: - return None - - def getCurrentSearchOption(self, currentIndex=None): - if currentIndex is None: - currentIndex = self.ui.tabWidget.currentIndex() - messagelistList = [ - self.ui.inboxSearchOption, - False, - self.ui.inboxSearchOptionSubscriptions, - self.ui.inboxSearchOptionChans, - ] - if currentIndex >= 0 and currentIndex < len(messagelistList): - return messagelistList[currentIndex].currentText().toUtf8().data() - else: - return None + sqlExecute( + '''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) # Group of functions for the Your Identities dialog box - def getCurrentItem(self, treeWidget=None): - if treeWidget is None: - treeWidget = self.getCurrentTreeWidget() - if treeWidget: - currentItem = treeWidget.currentItem() - if currentItem: - return currentItem - return False - - def getCurrentAccount(self, treeWidget=None): - currentItem = self.getCurrentItem(treeWidget) - if currentItem: - account = currentItem.address - return account - else: - # TODO need debug msg? - return False - - def getCurrentFolder(self, treeWidget=None): - if treeWidget is None: - treeWidget = self.getCurrentTreeWidget() - #treeWidget = self.ui.treeWidgetYourIdentities - if treeWidget: - currentItem = treeWidget.currentItem() - if currentItem and hasattr(currentItem, 'folderName'): - return currentItem.folderName - else: - return None - - def setCurrentItemColor(self, color): - treeWidget = self.getCurrentTreeWidget() - if treeWidget: - brush = QtGui.QBrush() - brush.setStyle(QtCore.Qt.NoBrush) - brush.setColor(color) - currentItem = treeWidget.currentItem() - currentItem.setForeground(0, brush) - def on_action_YourIdentitiesNew(self): self.click_NewAddressDialog() - def on_action_YourIdentitiesDelete(self): - account = self.getCurrentItem() - if account.type == AccountMixin.NORMAL: - return # maybe in the future - elif account.type == AccountMixin.CHAN: - if QtGui.QMessageBox.question( - self, "Delete channel?", - _translate( - "MainWindow", - "If you delete the channel, messages that you" - " already received will become inaccessible." - " Maybe you can consider disabling the channel" - " instead. Disabled channels will not receive new" - " messages, but you can still view messages you" - " already received.\n\nAre you sure you want to" - " delete the channel?" - ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No - ) == QtGui.QMessageBox.Yes: - BMConfigParser().remove_section(str(account.address)) - else: - return - else: - return - BMConfigParser().save() + def on_action_YourIdentitiesEnable(self): + currentRow = self.ui.tableWidgetYourIdentities.currentRow() + addressAtCurrentRow = str( + self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) + shared.config.set(addressAtCurrentRow, 'enabled', 'true') + shared.writeKeysFile() + self.ui.tableWidgetYourIdentities.item( + currentRow, 0).setTextColor(QApplication.palette().text().color()) + self.ui.tableWidgetYourIdentities.item( + currentRow, 1).setTextColor(QApplication.palette().text().color()) + self.ui.tableWidgetYourIdentities.item( + currentRow, 2).setTextColor(QApplication.palette().text().color()) + if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): + self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta + if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): + self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(216, 119, 0)) # orange shared.reloadMyAddressHashes() - self.rerenderAddressBook() - self.rerenderComboBoxSendFrom() - if account.type == AccountMixin.NORMAL: - self.rerenderTabTreeMessages() - elif account.type == AccountMixin.CHAN: - self.rerenderTabTreeChans() - def on_action_Enable(self): - addressAtCurrentRow = self.getCurrentAccount() - self.enableIdentity(addressAtCurrentRow) - account = self.getCurrentItem() - account.setEnabled(True) - - def enableIdentity(self, address): - BMConfigParser().set(address, 'enabled', 'true') - BMConfigParser().save() + def on_action_YourIdentitiesDisable(self): + currentRow = self.ui.tableWidgetYourIdentities.currentRow() + addressAtCurrentRow = str( + self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) + shared.config.set(str(addressAtCurrentRow), 'enabled', 'false') + self.ui.tableWidgetYourIdentities.item( + currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetYourIdentities.item( + currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetYourIdentities.item( + currentRow, 2).setTextColor(QtGui.QColor(128, 128, 128)) + if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): + self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta + shared.writeKeysFile() shared.reloadMyAddressHashes() - self.rerenderAddressBook() - def on_action_Disable(self): - address = self.getCurrentAccount() - self.disableIdentity(address) - account = self.getCurrentItem() - account.setEnabled(False) - - def disableIdentity(self, address): - BMConfigParser().set(str(address), 'enabled', 'false') - BMConfigParser().save() - shared.reloadMyAddressHashes() - self.rerenderAddressBook() - - def on_action_Clipboard(self): - address = self.getCurrentAccount() + def on_action_YourIdentitiesClipboard(self): + currentRow = self.ui.tableWidgetYourIdentities.currentRow() + addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item( + currentRow, 1).text() clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(address)) - - def on_action_ClipboardMessagelist(self): - tableWidget = self.getCurrentMessagelist() - currentColumn = tableWidget.currentColumn() - currentRow = tableWidget.currentRow() - if currentColumn not in [0, 1, 2]: # to, from, subject - if self.getCurrentFolder() == "sent": - currentColumn = 0 - else: - currentColumn = 1 - if self.getCurrentFolder() == "sent": - myAddress = tableWidget.item(currentRow, 1).data(QtCore.Qt.UserRole) - otherAddress = tableWidget.item(currentRow, 0).data(QtCore.Qt.UserRole) - else: - myAddress = tableWidget.item(currentRow, 0).data(QtCore.Qt.UserRole) - otherAddress = tableWidget.item(currentRow, 1).data(QtCore.Qt.UserRole) - account = accountClass(myAddress) - if isinstance(account, GatewayAccount) and otherAddress == account.relayAddress and ( - (currentColumn in [0, 2] and self.getCurrentFolder() == "sent") or - (currentColumn in [1, 2] and self.getCurrentFolder() != "sent")): - text = str(tableWidget.item(currentRow, currentColumn).label) - else: - text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole) - text = unicode(str(text), 'utf-8', 'ignore') - clipboard = QtGui.QApplication.clipboard() - clipboard.setText(text) - - #set avatar functions - def on_action_TreeWidgetSetAvatar(self): - address = self.getCurrentAccount() - self.setAvatar(address) + clipboard.setText(str(addressAtCurrentRow)) + def on_action_YourIdentitiesSetAvatar(self): + self.on_action_SetAvatar(self.ui.tableWidgetYourIdentities) + def on_action_AddressBookSetAvatar(self): self.on_action_SetAvatar(self.ui.tableWidgetAddressBook) + def on_action_SubscriptionsSetAvatar(self): + self.on_action_SetAvatar(self.ui.tableWidgetSubscriptions) + + def on_action_BlacklistSetAvatar(self): + self.on_action_SetAvatar(self.ui.tableWidgetBlacklist) + def on_action_SetAvatar(self, thisTableWidget): + # thisTableWidget = self.ui.tableWidgetYourIdentities + if not os.path.exists(shared.appdata + 'avatars/'): + os.makedirs(shared.appdata + 'avatars/') currentRow = thisTableWidget.currentRow() addressAtCurrentRow = thisTableWidget.item( currentRow, 1).text() - setToIdenticon = not self.setAvatar(addressAtCurrentRow) - if setToIdenticon: - thisTableWidget.item( - currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) - - def setAvatar(self, addressAtCurrentRow): - if not os.path.exists(state.appdata + 'avatars/'): - os.makedirs(state.appdata + 'avatars/') hash = hashlib.md5(addBMIfNotPresent(addressAtCurrentRow)).hexdigest() extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats @@ -3717,20 +3190,17 @@ class MyForm(settingsmixin.SMainWindow): for ext in extensions: filters += [ names[ext] + ' (*.' + ext.lower() + ')' ] all_images_filter += [ '*.' + ext.lower() ] - upper = state.appdata + 'avatars/' + hash + '.' + ext.upper() - lower = state.appdata + 'avatars/' + hash + '.' + ext.lower() + upper = shared.appdata + 'avatars/' + hash + '.' + ext.upper() + lower = shared.appdata + 'avatars/' + hash + '.' + ext.lower() if os.path.isfile(lower): current_files += [lower] elif os.path.isfile(upper): current_files += [upper] filters[0:0] = ['Image files (' + ' '.join(all_images_filter) + ')'] filters[1:1] = ['All files (*.*)'] - sourcefile = QtGui.QFileDialog.getOpenFileName( - self, _translate("MainWindow", "Set avatar..."), - filter = ';;'.join(filters) - ) + sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters)) # determine the correct filename (note that avatars don't use the suffix) - destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1] + destination = shared.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1] exists = QtCore.QFile.exists(destination) if sourcefile == '': # ask for removal of avatar @@ -3759,146 +3229,25 @@ class MyForm(settingsmixin.SMainWindow): if sourcefile != '': copied = QtCore.QFile.copy(sourcefile, destination) if not copied: - logger.error('couldn\'t copy :(') + print 'couldn\'t copy :(' + return False # set the icon - self.rerenderTabTreeMessages() - self.rerenderTabTreeSubscriptions() - self.rerenderTabTreeChans() + thisTableWidget.item( + currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) + self.rerenderSubscriptions() self.rerenderComboBoxSendFrom() - self.rerenderComboBoxSendFromBroadcast() - self.rerenderMessagelistFromLabels() - self.rerenderMessagelistToLabels() - self.ui.blackwhitelist.rerenderBlackWhiteList() - # generate identicon - return False - - return True - - def on_action_AddressBookSetSound(self): - widget = self.ui.tableWidgetAddressBook - self.setAddressSound(widget.item(widget.currentRow(), 0).text()) - - def setAddressSound(self, addr): - filters = [unicode(_translate( - "MainWindow", "Sound files (%s)" % - ' '.join(['*%s%s' % (os.extsep, ext) for ext in sound.extensions]) - ))] - sourcefile = unicode(QtGui.QFileDialog.getOpenFileName( - self, _translate("MainWindow", "Set notification sound..."), - filter=';;'.join(filters) - )) - - if not sourcefile: - return - - destdir = os.path.join(state.appdata, 'sounds') - destfile = unicode(addr) + os.path.splitext(sourcefile)[-1] - destination = os.path.join(destdir, destfile) - - if sourcefile == destination: - return - - pattern = destfile.lower() - for item in os.listdir(destdir): - if item.lower() == pattern: - overwrite = QtGui.QMessageBox.question( - self, _translate("MainWindow", "Message"), - _translate( - "MainWindow", - "You have already set a notification sound" - " for this address book entry." - " Do you really want to overwrite it?"), - QtGui.QMessageBox.Yes, QtGui.QMessageBox.No - ) == QtGui.QMessageBox.Yes - if overwrite: - QtCore.QFile.remove(os.path.join(destdir, item)) - break - - if not QtCore.QFile.copy(sourcefile, destination): - logger.error( - 'couldn\'t copy %s to %s', sourcefile, destination) - + self.rerenderInboxFromLabels() + self.rerenderInboxToLabels() + self.rerenderSentFromLabels() + self.rerenderSentToLabels() + self.rerenderBlackWhiteList() + def on_context_menuYourIdentities(self, point): - currentItem = self.getCurrentItem() - self.popMenuYourIdentities = QtGui.QMenu(self) - if isinstance(currentItem, Ui_AddressWidget): - self.popMenuYourIdentities.addAction(self.actionNewYourIdentities) - self.popMenuYourIdentities.addSeparator() - self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities) - self.popMenuYourIdentities.addSeparator() - if currentItem.isEnabled: - self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities) - else: - self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities) - self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities) - self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) - self.popMenuYourIdentities.addAction(self.actionEmailGateway) - self.popMenuYourIdentities.addSeparator() - self.popMenuYourIdentities.addAction(self.actionMarkAllRead) - - if get_plugins: - for plugin in get_plugins( - 'gui.menu', 'popMenuYourIdentities'): - plugin(self) - - self.popMenuYourIdentities.exec_( - self.ui.treeWidgetYourIdentities.mapToGlobal(point)) - - # TODO make one popMenu - def on_context_menuChan(self, point): - currentItem = self.getCurrentItem() - self.popMenu = QtGui.QMenu(self) - if isinstance(currentItem, Ui_AddressWidget): - self.popMenu.addAction(self.actionNew) - self.popMenu.addAction(self.actionDelete) - self.popMenu.addSeparator() - self.popMenu.addAction(self.actionClipboard) - self.popMenu.addSeparator() - if currentItem.isEnabled: - self.popMenu.addAction(self.actionDisable) - else: - self.popMenu.addAction(self.actionEnable) - self.popMenu.addAction(self.actionSetAvatar) - self.popMenu.addSeparator() - self.popMenu.addAction(self.actionMarkAllRead) self.popMenu.exec_( - self.ui.treeWidgetChans.mapToGlobal(point)) + self.ui.tableWidgetYourIdentities.mapToGlobal(point)) def on_context_menuInbox(self, point): - tableWidget = self.getCurrentMessagelist() - if tableWidget: - currentFolder = self.getCurrentFolder() - if currentFolder is None: - pass - if currentFolder == 'sent': - self.on_context_menuSent(point) - else: - self.popMenuInbox = QtGui.QMenu(self) - self.popMenuInbox.addAction(self.actionForceHtml) - self.popMenuInbox.addAction(self.actionMarkUnread) - self.popMenuInbox.addSeparator() - address = tableWidget.item( - tableWidget.currentRow(), 0).data(QtCore.Qt.UserRole) - account = accountClass(address) - if account.type == AccountMixin.CHAN: - self.popMenuInbox.addAction(self.actionReplyChan) - self.popMenuInbox.addAction(self.actionReply) - self.popMenuInbox.addAction(self.actionAddSenderToAddressBook) - self.actionClipboardMessagelist = self.ui.inboxContextMenuToolbar.addAction( - _translate("MainWindow", - "Copy subject to clipboard" if tableWidget.currentColumn() == 2 else "Copy address to clipboard" - ), - self.on_action_ClipboardMessagelist) - self.popMenuInbox.addAction(self.actionClipboardMessagelist) - self.popMenuInbox.addSeparator() - self.popMenuInbox.addAction(self.actionAddSenderToBlackList) - self.popMenuInbox.addSeparator() - self.popMenuInbox.addAction(self.actionSaveMessageAs) - if currentFolder == "trash": - self.popMenuInbox.addAction(self.actionUndeleteTrashedMessage) - else: - self.popMenuInbox.addAction(self.actionTrashInboxMessage) - self.popMenuInbox.exec_(tableWidget.mapToGlobal(point)) + self.popMenuInbox.exec_(self.ui.tableWidgetInbox.mapToGlobal(point)) def on_context_menuSent(self, point): self.popMenuSent = QtGui.QMenu(self) @@ -3907,189 +3256,193 @@ class MyForm(settingsmixin.SMainWindow): # Check to see if this item is toodifficult and display an additional # menu option (Force Send) if it is. - currentRow = self.ui.tableWidgetInbox.currentRow() - if currentRow >= 0: - ackData = str(self.ui.tableWidgetInbox.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData) - for row in queryreturn: - status, = row - if status == 'toodifficult': - self.popMenuSent.addAction(self.actionForceSend) + currentRow = self.ui.tableWidgetSent.currentRow() + ackData = str(self.ui.tableWidgetSent.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData) + for row in queryreturn: + status, = row + if status == 'toodifficult': + self.popMenuSent.addAction(self.actionForceSend) + self.popMenuSent.exec_(self.ui.tableWidgetSent.mapToGlobal(point)) - self.popMenuSent.exec_(self.ui.tableWidgetInbox.mapToGlobal(point)) + def inboxSearchLineEditPressed(self): + searchKeyword = self.ui.inboxSearchLineEdit.text().toUtf8().data() + searchOption = self.ui.inboxSearchOptionCB.currentText().toUtf8().data() + self.ui.inboxSearchLineEdit.setText(QString("")) + self.ui.textEditInboxMessage.setPlainText(QString("")) + self.loadInbox(searchOption, searchKeyword) - def inboxSearchLineEditUpdated(self, text): - # dynamic search for too short text is slow - if len(str(text)) < 3: - return - messagelist = self.getCurrentMessagelist() - searchOption = self.getCurrentSearchOption() - if messagelist: - account = self.getCurrentAccount() - folder = self.getCurrentFolder() - self.loadMessagelist(messagelist, account, folder, searchOption, str(text)) - - def inboxSearchLineEditReturnPressed(self): - logger.debug("Search return pressed") - searchLine = self.getCurrentSearchLine() - messagelist = self.getCurrentMessagelist() - if len(str(searchLine)) < 3: - searchOption = self.getCurrentSearchOption() - account = self.getCurrentAccount() - folder = self.getCurrentFolder() - self.loadMessagelist(messagelist, account, folder, searchOption, searchLine) - if messagelist: - messagelist.setFocus() - - def treeWidgetItemClicked(self): - searchLine = self.getCurrentSearchLine() - searchOption = self.getCurrentSearchOption() - messageTextedit = self.getCurrentMessageTextedit() - if messageTextedit: - messageTextedit.setPlainText(QtCore.QString("")) - messagelist = self.getCurrentMessagelist() - if messagelist: - account = self.getCurrentAccount() - folder = self.getCurrentFolder() - treeWidget = self.getCurrentTreeWidget() - # refresh count indicator - self.propagateUnreadCount(account.address if hasattr(account, 'address') else None, folder, treeWidget, 0) - self.loadMessagelist(messagelist, account, folder, searchOption, searchLine) - - def treeWidgetItemChanged(self, item, column): - # only for manual edits. automatic edits (setText) are ignored - if column != 0: - return - # only account names of normal addresses (no chans/mailinglists) - if (not isinstance(item, Ui_AddressWidget)) or (not self.getCurrentTreeWidget()) or self.getCurrentTreeWidget().currentItem() is None: - return - # not visible - if (not self.getCurrentItem()) or (not isinstance (self.getCurrentItem(), Ui_AddressWidget)): - return - # only currently selected item - if item.address != self.getCurrentAccount(): - return - # "All accounts" can't be renamed - if item.type == AccountMixin.ALL: - return - - newLabel = unicode(item.text(0), 'utf-8', 'ignore') - oldLabel = item.defaultLabel() - - # unchanged, do not do anything either - if newLabel == oldLabel: - return - - # recursion prevention - if self.recurDepth > 0: - return - - self.recurDepth += 1 - if item.type == AccountMixin.NORMAL or item.type == AccountMixin.MAILINGLIST: - self.rerenderComboBoxSendFromBroadcast() - if item.type == AccountMixin.NORMAL or item.type == AccountMixin.CHAN: - self.rerenderComboBoxSendFrom() - self.rerenderMessagelistFromLabels() - if item.type != AccountMixin.SUBSCRIPTION: - self.rerenderMessagelistToLabels() - if item.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.SUBSCRIPTION): - self.rerenderAddressBook() - self.recurDepth -= 1 + def sentSearchLineEditPressed(self): + searchKeyword = self.ui.sentSearchLineEdit.text().toUtf8().data() + searchOption = self.ui.sentSearchOptionCB.currentText().toUtf8().data() + self.ui.sentSearchLineEdit.setText(QString("")) + self.ui.textEditInboxMessage.setPlainText(QString("")) + self.loadSent(searchOption, searchKeyword) def tableWidgetInboxItemClicked(self): - folder = self.getCurrentFolder() - messageTextedit = self.getCurrentMessageTextedit() - if not messageTextedit: - return - - msgid = self.getCurrentMessageId() - if msgid: + currentRow = self.ui.tableWidgetInbox.currentRow() + if currentRow >= 0: + font = QFont() + font.setBold(False) + self.ui.textEditInboxMessage.setCurrentFont(font) + + fromAddress = str(self.ui.tableWidgetInbox.item( + currentRow, 1).data(Qt.UserRole).toPyObject()) + msgid = str(self.ui.tableWidgetInbox.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( - '''SELECT message FROM %s WHERE %s=?''' % ( - ('sent', 'ackdata') if folder == 'sent' - else ('inbox', 'msgid') - ), msgid - ) + '''select message from inbox where msgid=?''', msgid) + if queryreturn != []: + for row in queryreturn: + messageText, = row + messageText = shared.fixPotentiallyInvalidUTF8Data(messageText) + messageText = unicode(messageText, 'utf-8)') + if len(messageText) > 30000: + messageText = ( + messageText[:30000] + '\n' + + '--- Display of the remainder of the message ' + + 'truncated because it is too long.\n' + + '--- To see the full message, right-click in the ' + + 'Inbox view and select "View HTML code as formatted ' + + 'text",\n' + + '--- or select "Save message as..." to save it to a ' + + 'file, or select "Reply" and ' + + 'view the full message in the quote.') + # If we have received this message from either a broadcast address + # or from someone in our address book, display as HTML + if decodeAddress(fromAddress)[3] in shared.broadcastSendersForWhichImWatching or shared.isAddressInMyAddressBook(fromAddress): + self.ui.textEditInboxMessage.setText(messageText) + else: + self.ui.textEditInboxMessage.setPlainText(messageText) - try: - message = queryreturn[-1][0] - except NameError: - message = "" - except IndexError: - message = _translate( - "MainWindow", - "Error occurred: could not load message from disk." - ) - else: - tableWidget = self.getCurrentMessagelist() - currentRow = tableWidget.currentRow() - # refresh - if tableWidget.item(currentRow, 0).unread is True: - self.updateUnreadStatus(tableWidget, currentRow, msgid) - # propagate - if folder != 'sent' and sqlExecute( - '''UPDATE inbox SET read=1 WHERE msgid=? AND read=0''', - msgid - ) > 0: - self.propagateUnreadCount() + self.ui.tableWidgetInbox.item(currentRow, 0).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 1).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 2).setFont(font) + self.ui.tableWidgetInbox.item(currentRow, 3).setFont(font) - messageTextedit.setCurrentFont(QtGui.QFont()) - messageTextedit.setTextColor(QtGui.QColor()) - messageTextedit.setContent(message) + inventoryHash = str(self.ui.tableWidgetInbox.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + self.ubuntuMessagingMenuClear(inventoryHash) + sqlExecute('''update inbox set read=1 WHERE msgid=?''', inventoryHash) + self.changedInboxUnread() - def tableWidgetAddressBookItemChanged(self, item): - if item.type == AccountMixin.CHAN: + def tableWidgetSentItemClicked(self): + currentRow = self.ui.tableWidgetSent.currentRow() + if currentRow >= 0: + ackdata = str(self.ui.tableWidgetSent.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + queryreturn = sqlQuery( + '''select message from sent where ackdata=?''', ackdata) + if queryreturn != []: + for row in queryreturn: + message, = row + else: + message = "Error occurred: could not load message from disk." + message = unicode(message, 'utf-8)') + self.ui.textEditSentMessage.setPlainText(message) + + def tableWidgetYourIdentitiesItemChanged(self): + currentRow = self.ui.tableWidgetYourIdentities.currentRow() + if currentRow >= 0: + addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item( + currentRow, 1).text() + shared.config.set(str(addressAtCurrentRow), 'label', str( + self.ui.tableWidgetYourIdentities.item(currentRow, 0).text().toUtf8())) + shared.writeKeysFile() self.rerenderComboBoxSendFrom() - self.rerenderMessagelistFromLabels() - self.rerenderMessagelistToLabels() - completerList = self.ui.lineEditTo.completer().model().stringList() - for i in range(len(completerList)): - if unicode(completerList[i]).endswith(" <" + item.address + ">"): - completerList[i] = item.label + " <" + item.address + ">" - self.ui.lineEditTo.completer().model().setStringList(completerList) + # self.rerenderInboxFromLabels() + self.rerenderInboxToLabels() + self.rerenderSentFromLabels() + # self.rerenderSentToLabels() - def tabWidgetCurrentChanged(self, n): - if n == self.ui.tabWidget.indexOf(self.ui.networkstatus): - self.ui.networkstatus.startUpdate() - else: - self.ui.networkstatus.stopUpdate() + def tableWidgetAddressBookItemChanged(self): + currentRow = self.ui.tableWidgetAddressBook.currentRow() + if currentRow >= 0: + addressAtCurrentRow = self.ui.tableWidgetAddressBook.item( + currentRow, 1).text() + sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', + str(self.ui.tableWidgetAddressBook.item(currentRow, 0).text().toUtf8()), + str(addressAtCurrentRow)) + self.rerenderInboxFromLabels() + self.rerenderSentToLabels() + + def tableWidgetSubscriptionsItemChanged(self): + currentRow = self.ui.tableWidgetSubscriptions.currentRow() + if currentRow >= 0: + addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( + currentRow, 1).text() + sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', + str(self.ui.tableWidgetSubscriptions.item(currentRow, 0).text().toUtf8()), + str(addressAtCurrentRow)) + self.rerenderInboxFromLabels() + self.rerenderSentToLabels() def writeNewAddressToTable(self, label, address, streamNumber): - self.rerenderTabTreeMessages() - self.rerenderTabTreeSubscriptions() - self.rerenderTabTreeChans() + self.ui.tableWidgetYourIdentities.setSortingEnabled(False) + self.ui.tableWidgetYourIdentities.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) + newItem.setIcon(avatarize(address)) + self.ui.tableWidgetYourIdentities.setItem( + 0, 0, newItem) + newItem = QtGui.QTableWidgetItem(address) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if shared.safeConfigGetBoolean(address, 'chan'): + newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange + self.ui.tableWidgetYourIdentities.setItem(0, 1, newItem) + newItem = QtGui.QTableWidgetItem(streamNumber) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.ui.tableWidgetYourIdentities.setItem(0, 2, newItem) + # self.ui.tableWidgetYourIdentities.setSortingEnabled(True) self.rerenderComboBoxSendFrom() - self.rerenderComboBoxSendFromBroadcast() - self.rerenderAddressBook() def updateStatusBar(self, data): - if type(data) is tuple or type(data) is list: - option = data[1] - message = data[0] - else: - option = 0 - message = data - if message != "": - logger.info('Status bar: ' + message) + if data != "": + with shared.printLock: + print 'Status bar:', data - if option == 1: - self.statusbar.addImportant(message) - else: - self.statusbar.showMessage(message, 10000) + self.statusBar().showMessage(data) - def initSettings(self): - QtCore.QCoreApplication.setOrganizationName("PyBitmessage") - QtCore.QCoreApplication.setOrganizationDomain("bitmessage.org") - QtCore.QCoreApplication.setApplicationName("pybitmessageqt") - self.loadSettings() - for attr, obj in self.ui.__dict__.iteritems(): - if hasattr(obj, "__class__") and \ - isinstance(obj, settingsmixin.SettingsMixin): - loadMethod = getattr(obj, "loadSettings", None) - if callable(loadMethod): - obj.loadSettings() +class helpDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_helpDialog() + self.ui.setupUi(self) + self.parent = parent + self.ui.labelHelpURI.setOpenExternalLinks(True) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + +class connectDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_connectDialog() + self.ui.setupUi(self) + self.parent = parent + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + +class aboutDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_aboutDialog() + self.ui.setupUi(self) + self.parent = parent + self.ui.labelVersion.setText('version ' + shared.softwareVersion) + + +class regenerateAddressesDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_regenerateAddressesDialog() + self.ui.setupUi(self) + self.parent = parent + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) class settingsDialog(QtGui.QDialog): @@ -4099,35 +3452,31 @@ class settingsDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent self.ui.checkBoxStartOnLogon.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'startonlogon')) + shared.config.getboolean('bitmessagesettings', 'startonlogon')) self.ui.checkBoxMinimizeToTray.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray')) - self.ui.checkBoxTrayOnClose.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'trayonclose')) - self.ui.checkBoxHideTrayConnectionNotifications.setChecked( - BMConfigParser().getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) + shared.config.getboolean('bitmessagesettings', 'minimizetotray')) self.ui.checkBoxShowTrayNotifications.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications')) + shared.config.getboolean('bitmessagesettings', 'showtraynotifications')) self.ui.checkBoxStartInTray.setChecked( - BMConfigParser().getboolean('bitmessagesettings', 'startintray')) + shared.config.getboolean('bitmessagesettings', 'startintray')) self.ui.checkBoxWillinglySendToMobile.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) + shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile')) self.ui.checkBoxUseIdenticons.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) + shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons')) self.ui.checkBoxReplyBelow.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) + shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow')) - if state.appdata == paths.lookupExeFolder(): - self.ui.checkBoxPortableMode.setChecked(True) + global languages + languages = ['system','en','eo','fr','de','es','ru','no','ar','zh_cn','ja','nl','cs','en_pirate','other'] + user_countrycode = str(shared.config.get('bitmessagesettings', 'userlocale')) + if user_countrycode in languages: + curr_index = languages.index(user_countrycode) else: - try: - import tempfile - tempfile.NamedTemporaryFile( - dir=paths.lookupExeFolder(), delete=True - ).close() # should autodelete - except: - self.ui.checkBoxPortableMode.setDisabled(True) - + curr_index = languages.index('other') + self.ui.languageComboBox.setCurrentIndex(curr_index) + + if shared.appdata == '': + self.ui.checkBoxPortableMode.setChecked(True) if 'darwin' in sys.platform: self.ui.checkBoxStartOnLogon.setDisabled(True) self.ui.checkBoxStartOnLogon.setText(_translate( @@ -4144,14 +3493,12 @@ class settingsDialog(QtGui.QDialog): "MainWindow", "Start-on-login not yet supported on your OS.")) # On the Network settings tab: self.ui.lineEditTCPPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'port'))) - self.ui.checkBoxUPnP.setChecked( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp')) - self.ui.checkBoxAuthentication.setChecked(BMConfigParser().getboolean( + shared.config.get('bitmessagesettings', 'port'))) + self.ui.checkBoxAuthentication.setChecked(shared.config.getboolean( 'bitmessagesettings', 'socksauthentication')) - self.ui.checkBoxSocksListen.setChecked(BMConfigParser().getboolean( + self.ui.checkBoxSocksListen.setChecked(shared.config.getboolean( 'bitmessagesettings', 'sockslisten')) - if str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'none': + if str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'none': self.ui.comboBoxProxyType.setCurrentIndex(0) self.ui.lineEditSocksHostname.setEnabled(False) self.ui.lineEditSocksPort.setEnabled(False) @@ -4159,64 +3506,50 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(False) self.ui.checkBoxAuthentication.setEnabled(False) self.ui.checkBoxSocksListen.setEnabled(False) - elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': + elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': self.ui.comboBoxProxyType.setCurrentIndex(1) - elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': + self.ui.lineEditTCPPort.setEnabled(False) + elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': self.ui.comboBoxProxyType.setCurrentIndex(2) + self.ui.lineEditTCPPort.setEnabled(False) self.ui.lineEditSocksHostname.setText(str( - BMConfigParser().get('bitmessagesettings', 'sockshostname'))) + shared.config.get('bitmessagesettings', 'sockshostname'))) self.ui.lineEditSocksPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'socksport'))) + shared.config.get('bitmessagesettings', 'socksport'))) self.ui.lineEditSocksUsername.setText(str( - BMConfigParser().get('bitmessagesettings', 'socksusername'))) + shared.config.get('bitmessagesettings', 'socksusername'))) self.ui.lineEditSocksPassword.setText(str( - BMConfigParser().get('bitmessagesettings', 'sockspassword'))) + shared.config.get('bitmessagesettings', 'sockspassword'))) QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL( "currentIndexChanged(int)"), self.comboBoxProxyTypeChanged) self.ui.lineEditMaxDownloadRate.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxdownloadrate'))) + shared.config.get('bitmessagesettings', 'maxdownloadrate'))) self.ui.lineEditMaxUploadRate.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxuploadrate'))) - self.ui.lineEditMaxOutboundConnections.setText(str( - BMConfigParser().get('bitmessagesettings', 'maxoutboundconnections'))) + shared.config.get('bitmessagesettings', 'maxuploadrate'))) # Demanded difficulty tab - self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) + self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint( + 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab - self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) - - # OpenCL - if openclpow.openclAvailable(): - self.ui.comboBoxOpenCL.setEnabled(True) - else: - self.ui.comboBoxOpenCL.setEnabled(False) - self.ui.comboBoxOpenCL.clear() - self.ui.comboBoxOpenCL.addItem("None") - self.ui.comboBoxOpenCL.addItems(openclpow.vendors) - self.ui.comboBoxOpenCL.setCurrentIndex(0) - for i in range(self.ui.comboBoxOpenCL.count()): - if self.ui.comboBoxOpenCL.itemText(i) == BMConfigParser().safeGet('bitmessagesettings', 'opencl'): - self.ui.comboBoxOpenCL.setCurrentIndex(i) - break + self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(shared.config.getint( + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # Namecoin integration tab - nmctype = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') + nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') self.ui.lineEditNamecoinHost.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpchost'))) + shared.config.get('bitmessagesettings', 'namecoinrpchost'))) self.ui.lineEditNamecoinPort.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcport'))) + shared.config.get('bitmessagesettings', 'namecoinrpcport'))) self.ui.lineEditNamecoinUser.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser'))) + shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) self.ui.lineEditNamecoinPassword.setText(str( - BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword'))) + shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) if nmctype == "namecoind": self.ui.radioButtonNamecoinNamecoind.setChecked(True) @@ -4238,14 +3571,14 @@ class settingsDialog(QtGui.QDialog): #Message Resend tab self.ui.lineEditDays.setText(str( - BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) + shared.config.get('bitmessagesettings', 'stopresendingafterxdays'))) self.ui.lineEditMonths.setText(str( - BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) + shared.config.get('bitmessagesettings', 'stopresendingafterxmonths'))) #'System' tab removed for now. """try: - maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') + maxCores = shared.config.getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if maxCores <= 1: @@ -4271,6 +3604,7 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(False) self.ui.checkBoxAuthentication.setEnabled(False) self.ui.checkBoxSocksListen.setEnabled(False) + self.ui.lineEditTCPPort.setEnabled(True) elif comboBoxIndex == 1 or comboBoxIndex == 2: self.ui.lineEditSocksHostname.setEnabled(True) self.ui.lineEditSocksPort.setEnabled(True) @@ -4279,6 +3613,7 @@ class settingsDialog(QtGui.QDialog): if self.ui.checkBoxAuthentication.isChecked(): self.ui.lineEditSocksUsername.setEnabled(True) self.ui.lineEditSocksPassword.setEnabled(True) + self.ui.lineEditTCPPort.setEnabled(False) # Check status of namecoin integration radio buttons and translate # it to a string as in the options. @@ -4301,7 +3636,7 @@ class settingsDialog(QtGui.QDialog): self.ui.labelNamecoinPassword.setEnabled(isNamecoind) if isNamecoind: - self.ui.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) + self.ui.lineEditNamecoinPort.setText(shared.namecoinDefaultRpcPort) else: self.ui.lineEditNamecoinPort.setText("9000") @@ -4311,10 +3646,10 @@ class settingsDialog(QtGui.QDialog): "MainWindow", "Testing...")) options = {} options["type"] = self.getNamecoinType() - options["host"] = str(self.ui.lineEditNamecoinHost.text().toUtf8()) - options["port"] = str(self.ui.lineEditNamecoinPort.text().toUtf8()) - options["user"] = str(self.ui.lineEditNamecoinUser.text().toUtf8()) - options["password"] = str(self.ui.lineEditNamecoinPassword.text().toUtf8()) + options["host"] = self.ui.lineEditNamecoinHost.text() + options["port"] = self.ui.lineEditNamecoinPort.text() + options["user"] = self.ui.lineEditNamecoinUser.text() + options["password"] = self.ui.lineEditNamecoinPassword.text() nc = namecoinConnection(options) response = nc.test() responseStatus = response[0] @@ -4324,102 +3659,260 @@ class settingsDialog(QtGui.QDialog): self.parent.ui.pushButtonFetchNamecoinID.show() +class SpecialAddressBehaviorDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_SpecialAddressBehaviorDialog() + self.ui.setupUi(self) + self.parent = parent + currentRow = parent.ui.tableWidgetYourIdentities.currentRow() + addressAtCurrentRow = str( + parent.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) + if not shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): + if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): + self.ui.radioButtonBehaviorMailingList.click() + else: + self.ui.radioButtonBehaveNormalAddress.click() + try: + mailingListName = shared.config.get( + addressAtCurrentRow, 'mailinglistname') + except: + mailingListName = '' + self.ui.lineEditMailingListName.setText( + unicode(mailingListName, 'utf-8')) + else: # if addressAtCurrentRow is a chan address + self.ui.radioButtonBehaviorMailingList.setDisabled(True) + self.ui.lineEditMailingListName.setText(_translate( + "MainWindow", "This is a chan address. You cannot use it as a pseudo-mailing list.")) + + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + +class AddAddressDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_AddAddressDialog() + self.ui.setupUi(self) + self.parent = parent + QtCore.QObject.connect(self.ui.lineEditAddress, QtCore.SIGNAL( + "textChanged(QString)"), self.addressChanged) + + def addressChanged(self, QString): + status, a, b, c = decodeAddress(str(QString)) + if status == 'missingbm': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address should start with ''BM-''")) + elif status == 'checksumfailed': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address is not typed or copied correctly (the checksum failed).")) + elif status == 'versiontoohigh': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The version number of this address is higher than this software can support. Please upgrade Bitmessage.")) + elif status == 'invalidcharacters': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address contains invalid characters.")) + elif status == 'ripetooshort': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is too short.")) + elif status == 'ripetoolong': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is too long.")) + elif status == 'varintmalformed': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is malformed.")) + elif status == 'success': + self.ui.labelAddressCheck.setText( + _translate("MainWindow", "Address is valid.")) + +class NewSubscriptionDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_NewSubscriptionDialog() + self.ui.setupUi(self) + self.parent = parent + QtCore.QObject.connect(self.ui.lineEditSubscriptionAddress, QtCore.SIGNAL( + "textChanged(QString)"), self.addressChanged) + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( + _translate("MainWindow", "Enter an address above.")) + + def addressChanged(self, QString): + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(False) + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setChecked(False) + status, addressVersion, streamNumber, ripe = decodeAddress(str(QString)) + if status == 'missingbm': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address should start with ''BM-''")) + elif status == 'checksumfailed': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address is not typed or copied correctly (the checksum failed).")) + elif status == 'versiontoohigh': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The version number of this address is higher than this software can support. Please upgrade Bitmessage.")) + elif status == 'invalidcharacters': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "The address contains invalid characters.")) + elif status == 'ripetooshort': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is too short.")) + elif status == 'ripetoolong': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is too long.")) + elif status == 'varintmalformed': + self.ui.labelAddressCheck.setText(_translate( + "MainWindow", "Some data encoded in the address is malformed.")) + elif status == 'success': + self.ui.labelAddressCheck.setText( + _translate("MainWindow", "Address is valid.")) + if addressVersion <= 3: + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( + _translate("MainWindow", "Address is an old type. We cannot display its past broadcasts.")) + else: + shared.flushInventory() + doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( + addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() + tag = doubleHashOfAddressData[32:] + queryreturn = sqlQuery( + '''select hash from inventory where objecttype=3 and tag=?''', tag) + if len(queryreturn) == 0: + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( + _translate("MainWindow", "There are no recent broadcasts from this address to display.")) + elif len(queryreturn) == 1: + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( + _translate("MainWindow", "Display the %1 recent broadcast from this address.").arg(str(len(queryreturn)))) + else: + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) + self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( + _translate("MainWindow", "Display the %1 recent broadcasts from this address.").arg(str(len(queryreturn)))) + + +class NewAddressDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_NewAddressDialog() + self.ui.setupUi(self) + self.parent = parent + row = 1 + # Let's fill out the 'existing address' combo box with addresses from + # the 'Your Identities' tab. + while self.parent.ui.tableWidgetYourIdentities.item(row - 1, 1): + self.ui.radioButtonExisting.click() + self.ui.comboBoxExisting.addItem( + self.parent.ui.tableWidgetYourIdentities.item(row - 1, 1).text()) + row += 1 + self.ui.groupBoxDeterministic.setHidden(True) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + +class newChanDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_newChanDialog() + self.ui.setupUi(self) + self.parent = parent + self.ui.groupBoxCreateChan.setHidden(True) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + +class iconGlossaryDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_iconGlossaryDialog() + self.ui.setupUi(self) + self.parent = parent + self.ui.labelPortNumber.setText(_translate( + "MainWindow", "You are using TCP port %1. (This can be changed in the settings).").arg(str(shared.config.getint('bitmessagesettings', 'port')))) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + # In order for the time columns on the Inbox and Sent tabs to be sorted # correctly (rather than alphabetically), we need to overload the < # operator and use this class instead of QTableWidgetItem. -class myTableWidgetItem(QtGui.QTableWidgetItem): +class myTableWidgetItem(QTableWidgetItem): def __lt__(self, other): return int(self.data(33).toPyObject()) < int(other.data(33).toPyObject()) +class UISignaler(QThread): -app = None -myapp = None - - -class MySingleApplication(QtGui.QApplication): - """ - Listener to allow our Qt form to get focus when another instance of the - application is open. - - Based off this nice reimplmentation of MySingleApplication: - http://stackoverflow.com/a/12712362/2679626 - """ - - # Unique identifier for this application - uuid = '6ec0149b-96e1-4be1-93ab-1465fb3ebf7c' - - def __init__(self, *argv): - super(MySingleApplication, self).__init__(*argv) - id = MySingleApplication.uuid - - self.server = None - self.is_running = False - - socket = QLocalSocket() - socket.connectToServer(id) - self.is_running = socket.waitForConnected() - - # Cleanup past crashed servers - if not self.is_running: - if socket.error() == QLocalSocket.ConnectionRefusedError: - socket.disconnectFromServer() - QLocalServer.removeServer(id) - - socket.abort() - - # Checks if there's an instance of the local server id running - if self.is_running: - # This should be ignored, singleinstance.py will take care of exiting me. - pass - else: - # Nope, create a local server with this id and assign on_new_connection - # for whenever a second instance tries to run focus the application. - self.server = QLocalServer() - self.server.listen(id) - self.server.newConnection.connect(self.on_new_connection) - - def __del__(self): - if self.server: - self.server.close() - - def on_new_connection(self): - if myapp: - myapp.appIndicatorShow() - - -def init(): - global app - if not app: - app = MySingleApplication(sys.argv) - return app + def __init__(self, parent=None): + QThread.__init__(self, parent) + def run(self): + while True: + command, data = shared.UISignalQueue.get() + if command == 'writeNewAddressToTable': + label, address, streamNumber = data + self.emit(SIGNAL( + "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), label, address, str(streamNumber)) + elif command == 'updateStatusBar': + self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data) + elif command == 'updateSentItemStatusByToAddress': + toAddress, message = data + self.emit(SIGNAL( + "updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message) + elif command == 'updateSentItemStatusByAckdata': + ackData, message = data + self.emit(SIGNAL( + "updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), ackData, message) + elif command == 'displayNewInboxMessage': + inventoryHash, toAddress, fromAddress, subject, body = data + self.emit(SIGNAL( + "displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), + inventoryHash, toAddress, fromAddress, subject, body) + elif command == 'displayNewSentMessage': + toAddress, fromLabel, fromAddress, subject, message, ackdata = data + self.emit(SIGNAL( + "displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), + toAddress, fromLabel, fromAddress, subject, message, ackdata) + elif command == 'updateNetworkStatusTab': + self.emit(SIGNAL("updateNetworkStatusTab()")) + elif command == 'updateNumberOfMessagesProcessed': + self.emit(SIGNAL("updateNumberOfMessagesProcessed()")) + elif command == 'updateNumberOfPubkeysProcessed': + self.emit(SIGNAL("updateNumberOfPubkeysProcessed()")) + elif command == 'updateNumberOfBroadcastsProcessed': + self.emit(SIGNAL("updateNumberOfBroadcastsProcessed()")) + elif command == 'setStatusIcon': + self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"), data) + elif command == 'changedInboxUnread': + self.emit(SIGNAL("changedInboxUnread(PyQt_PyObject)"), data) + elif command == 'rerenderInboxFromLabels': + self.emit(SIGNAL("rerenderInboxFromLabels()")) + elif command == 'rerenderSentToLabels': + self.emit(SIGNAL("rerenderSentToLabels()")) + elif command == 'rerenderAddressBook': + self.emit(SIGNAL("rerenderAddressBook()")) + elif command == 'rerenderSubscriptions': + self.emit(SIGNAL("rerenderSubscriptions()")) + elif command == 'rerenderBlackWhiteList': + self.emit(SIGNAL("rerenderBlackWhiteList()")) + elif command == 'removeInboxRowByMsgid': + self.emit(SIGNAL("removeInboxRowByMsgid(PyQt_PyObject)"), data) + elif command == 'alert': + title, text, exitAfterUserClicksOk = data + self.emit(SIGNAL("displayAlert(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), title, text, exitAfterUserClicksOk) + else: + sys.stderr.write( + 'Command sent to UISignaler not recognized: %s\n' % command) def run(): - global myapp - app = init() + app = QtGui.QApplication(sys.argv) change_translation(l10n.getTranslationLanguage()) app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() - myapp.sqlInit() - myapp.appIndicatorInit(app) - myapp.indicatorInit() - myapp.notifierInit() - myapp._firstrun = BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'dontconnect') - if myapp._firstrun: - myapp.showConnectDialog() # ask the user if we may connect - myapp.ui.updateNetworkSwitchMenuLabel() - -# try: -# if BMConfigParser().get('bitmessagesettings', 'mailchuck') < 1: -# myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck')) -# except: -# myapp.showMigrationWizard(0) - - # only show after wizards and connect dialogs have completed - if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'): + if not shared.config.getboolean('bitmessagesettings', 'startintray'): myapp.show() + myapp.appIndicatorInit(app) + myapp.ubuntuMessagingMenuInit() + myapp.notifierInit() + if shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + myapp.showConnectDialog() # ask the user if we may connect sys.exit(app.exec_()) diff --git a/src/bitmessageqt/about.py b/src/bitmessageqt/about.py new file mode 100644 index 00000000..d2687532 --- /dev/null +++ b/src/bitmessageqt/about.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'about.ui' +# +# Created: Tue Jan 21 22:29:38 2014 +# by: PyQt4 UI code generator 4.10.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_aboutDialog(object): + def setupUi(self, aboutDialog): + aboutDialog.setObjectName(_fromUtf8("aboutDialog")) + aboutDialog.resize(360, 315) + self.buttonBox = QtGui.QDialogButtonBox(aboutDialog) + self.buttonBox.setGeometry(QtCore.QRect(20, 280, 311, 32)) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.label = QtGui.QLabel(aboutDialog) + self.label.setGeometry(QtCore.QRect(70, 126, 111, 20)) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label.setObjectName(_fromUtf8("label")) + self.labelVersion = QtGui.QLabel(aboutDialog) + self.labelVersion.setGeometry(QtCore.QRect(190, 126, 161, 20)) + self.labelVersion.setObjectName(_fromUtf8("labelVersion")) + self.label_2 = QtGui.QLabel(aboutDialog) + self.label_2.setGeometry(QtCore.QRect(10, 150, 341, 41)) + self.label_2.setAlignment(QtCore.Qt.AlignCenter) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.label_3 = QtGui.QLabel(aboutDialog) + self.label_3.setGeometry(QtCore.QRect(20, 200, 331, 71)) + self.label_3.setWordWrap(True) + self.label_3.setOpenExternalLinks(True) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.label_5 = QtGui.QLabel(aboutDialog) + self.label_5.setGeometry(QtCore.QRect(10, 190, 341, 20)) + self.label_5.setAlignment(QtCore.Qt.AlignCenter) + self.label_5.setObjectName(_fromUtf8("label_5")) + + self.retranslateUi(aboutDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), aboutDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), aboutDialog.reject) + QtCore.QMetaObject.connectSlotsByName(aboutDialog) + + def retranslateUi(self, aboutDialog): + aboutDialog.setWindowTitle(_translate("aboutDialog", "About", None)) + self.label.setText(_translate("aboutDialog", "PyBitmessage", None)) + self.labelVersion.setText(_translate("aboutDialog", "version ?", None)) + self.label_2.setText(_translate("aboutDialog", "

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

", None)) + self.label_3.setText(_translate("aboutDialog", "

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

", None)) + self.label_5.setText(_translate("aboutDialog", "This is Beta software.", None)) + diff --git a/src/bitmessageqt/about.ui b/src/bitmessageqt/about.ui index 8ec7159c..3deab41b 100644 --- a/src/bitmessageqt/about.ui +++ b/src/bitmessageqt/about.ui @@ -6,91 +6,117 @@ 0 0 - 430 - 340 + 360 + 315 About - - - - - - - - :/newPrefix/images/can-icon-24px.png - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - <html><head/><body><p><a href="https://github.com/Bitmessage/PyBitmessage/tree/:branch:"><span style="text-decoration:none; color:#0000ff;">PyBitmessage :version:</span></a></p></body></html> - - - Qt::AlignCenter - - - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - - - Qt::AlignLeft - - - - - - - This is Beta software. - - - Qt::AlignCenter - - - - - - - <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> - - - true - - - true - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - - + + + + 20 + 280 + 311 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + 70 + 126 + 111 + 20 + + + + + 75 + true + + + + PyBitmessage + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 190 + 126 + 161 + 20 + + + + version ? + + + + + + 10 + 150 + 341 + 41 + + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + + Qt::AlignCenter + + + + + + 20 + 200 + 331 + 71 + + + + <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> + + + true + + + true + + + + + + 10 + 190 + 341 + 20 + + + + This is Beta software. + + + Qt::AlignCenter + + - - - + buttonBox diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py deleted file mode 100644 index 92d497f8..00000000 --- a/src/bitmessageqt/account.py +++ /dev/null @@ -1,305 +0,0 @@ -from PyQt4 import QtCore, QtGui - -import queues -import re -import sys -import inspect -from helper_sql import * -from helper_ackPayload import genAckPayload -from addresses import decodeAddress -from bmconfigparser import BMConfigParser -from foldertree import AccountMixin -from pyelliptic.openssl import OpenSSL -from utils import str_broadcast_subscribers -import time - -def getSortedAccounts(): - configSections = BMConfigParser().addresses() - configSections.sort(cmp = - lambda x,y: cmp(unicode(BMConfigParser().get(x, 'label'), 'utf-8').lower(), unicode(BMConfigParser().get(y, 'label'), 'utf-8').lower()) - ) - return configSections - -def getSortedSubscriptions(count = False): - queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions ORDER BY label COLLATE NOCASE ASC') - ret = {} - for row in queryreturn: - label, address, enabled = row - ret[address] = {} - ret[address]["inbox"] = {} - ret[address]["inbox"]['label'] = label - ret[address]["inbox"]['enabled'] = enabled - ret[address]["inbox"]['count'] = 0 - if count: - queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt - FROM inbox, subscriptions ON subscriptions.address = inbox.fromaddress - WHERE read = 0 AND toaddress = ? - GROUP BY inbox.fromaddress, folder''', str_broadcast_subscribers) - for row in queryreturn: - address, folder, cnt = row - if not folder in ret[address]: - ret[address][folder] = { - 'label': ret[address]['inbox']['label'], - 'enabled': ret[address]['inbox']['enabled'] - } - ret[address][folder]['count'] = cnt - return ret - -def accountClass(address): - if not BMConfigParser().has_section(address): - # FIXME: This BROADCAST section makes no sense - if address == str_broadcast_subscribers: - subscription = BroadcastAccount(address) - if subscription.type != AccountMixin.BROADCAST: - return None - else: - subscription = SubscriptionAccount(address) - if subscription.type != AccountMixin.SUBSCRIPTION: - # e.g. deleted chan - return NoAccount(address) - return subscription - try: - gateway = BMConfigParser().get(address, "gateway") - for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): -# obj = g(address) - if issubclass(cls, GatewayAccount) and cls.gatewayName == gateway: - return cls(address) - # general gateway - return GatewayAccount(address) - except: - pass - # no gateway - return BMAccount(address) - -class AccountColor(AccountMixin): - def __init__(self, address, type = None): - self.isEnabled = True - self.address = address - if type is None: - if address is None: - self.type = AccountMixin.ALL - elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): - self.type = AccountMixin.MAILINGLIST - elif BMConfigParser().safeGetBoolean(self.address, 'chan'): - self.type = AccountMixin.CHAN - elif sqlQuery( - '''select label from subscriptions where address=?''', self.address): - self.type = AccountMixin.SUBSCRIPTION - else: - self.type = AccountMixin.NORMAL - else: - self.type = type - - -class BMAccount(object): - def __init__(self, address = None): - self.address = address - self.type = AccountMixin.NORMAL - if BMConfigParser().has_section(address): - if BMConfigParser().safeGetBoolean(self.address, 'chan'): - self.type = AccountMixin.CHAN - elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): - self.type = AccountMixin.MAILINGLIST - elif self.address == str_broadcast_subscribers: - self.type = AccountMixin.BROADCAST - else: - queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', self.address) - if queryreturn: - self.type = AccountMixin.SUBSCRIPTION - - def getLabel(self, address = None): - if address is None: - address = self.address - label = address - if BMConfigParser().has_section(address): - label = BMConfigParser().get(address, 'label') - queryreturn = sqlQuery( - '''select label from addressbook where address=?''', address) - if queryreturn != []: - for row in queryreturn: - label, = row - else: - queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', address) - if queryreturn != []: - for row in queryreturn: - label, = row - return label - - def parseMessage(self, toAddress, fromAddress, subject, message): - self.toAddress = toAddress - self.fromAddress = fromAddress - if isinstance(subject, unicode): - self.subject = str(subject) - else: - self.subject = subject - self.message = message - self.fromLabel = self.getLabel(fromAddress) - self.toLabel = self.getLabel(toAddress) - - -class NoAccount(BMAccount): - def __init__(self, address = None): - self.address = address - self.type = AccountMixin.NORMAL - - def getLabel(self, address = None): - if address is None: - address = self.address - return address - - -class SubscriptionAccount(BMAccount): - pass - - -class BroadcastAccount(BMAccount): - pass - - -class GatewayAccount(BMAccount): - gatewayName = None - ALL_OK = 0 - REGISTRATION_DENIED = 1 - def __init__(self, address): - super(GatewayAccount, self).__init__(address) - - def send(self): - status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) - stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) - t = () - sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - self.toAddress, - ripe, - self.fromAddress, - self.subject, - self.message, - ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. - 'msgqueued', - 0, # retryNumber - 'sent', # folder - 2, # encodingtype - min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days - ) - - queues.workerQueue.put(('sendmessage', self.toAddress)) - - def parseMessage(self, toAddress, fromAddress, subject, message): - super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) - -class MailchuckAccount(GatewayAccount): - # set "gateway" in keys.dat to this - gatewayName = "mailchuck" - registrationAddress = "BM-2cVYYrhaY5Gbi3KqrX9Eae2NRNrkfrhCSA" - unregistrationAddress = "BM-2cVMAHTRjZHCTPMue75XBK5Tco175DtJ9J" - relayAddress = "BM-2cWim8aZwUNqxzjMxstnUMtVEUQJeezstf" - regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") - regExpOutgoing = re.compile("(\S+) (.*)") - def __init__(self, address): - super(MailchuckAccount, self).__init__(address) - self.feedback = self.ALL_OK - - def createMessage(self, toAddress, fromAddress, subject, message): - self.subject = toAddress + " " + subject - self.toAddress = self.relayAddress - self.fromAddress = fromAddress - self.message = message - - def register(self, email): - self.toAddress = self.registrationAddress - self.subject = email - self.message = "" - self.fromAddress = self.address - self.send() - - def unregister(self): - self.toAddress = self.unregistrationAddress - self.subject = "" - self.message = "" - self.fromAddress = self.address - self.send() - - def status(self): - self.toAddress = self.registrationAddress - self.subject = "status" - self.message = "" - self.fromAddress = self.address - self.send() - - def settings(self): - self.toAddress = self.registrationAddress - self.subject = "config" - self.message = QtGui.QApplication.translate("Mailchuck", """# You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. -""") - self.fromAddress = self.address - - def parseMessage(self, toAddress, fromAddress, subject, message): - super(MailchuckAccount, self).parseMessage(toAddress, fromAddress, subject, message) - if fromAddress == self.relayAddress: - matches = self.regExpIncoming.search(subject) - if not matches is None: - self.subject = "" - if not matches.group(1) is None: - self.subject += matches.group(1) - if not matches.group(3) is None: - self.subject += matches.group(3) - if not matches.group(2) is None: - self.fromLabel = matches.group(2) - self.fromAddress = matches.group(2) - if toAddress == self.relayAddress: - matches = self.regExpOutgoing.search(subject) - if not matches is None: - if not matches.group(2) is None: - self.subject = matches.group(2) - if not matches.group(1) is None: - self.toLabel = matches.group(1) - self.toAddress = matches.group(1) - self.feedback = self.ALL_OK - if fromAddress == self.registrationAddress and self.subject == "Registration Request Denied": - self.feedback = self.REGISTRATION_DENIED - return self.feedback diff --git a/src/bitmessageqt/addaddressdialog.py b/src/bitmessageqt/addaddressdialog.py new file mode 100644 index 00000000..5ed19e0a --- /dev/null +++ b/src/bitmessageqt/addaddressdialog.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'addaddressdialog.ui' +# +# Created: Sat Nov 30 20:35:38 2013 +# by: PyQt4 UI code generator 4.10.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_AddAddressDialog(object): + def setupUi(self, AddAddressDialog): + AddAddressDialog.setObjectName(_fromUtf8("AddAddressDialog")) + AddAddressDialog.resize(368, 162) + self.formLayout = QtGui.QFormLayout(AddAddressDialog) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.label_2 = QtGui.QLabel(AddAddressDialog) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.formLayout.setWidget(0, QtGui.QFormLayout.SpanningRole, self.label_2) + self.newAddressLabel = QtGui.QLineEdit(AddAddressDialog) + self.newAddressLabel.setObjectName(_fromUtf8("newAddressLabel")) + self.formLayout.setWidget(2, QtGui.QFormLayout.SpanningRole, self.newAddressLabel) + self.label = QtGui.QLabel(AddAddressDialog) + self.label.setObjectName(_fromUtf8("label")) + self.formLayout.setWidget(4, QtGui.QFormLayout.LabelRole, self.label) + self.lineEditAddress = QtGui.QLineEdit(AddAddressDialog) + self.lineEditAddress.setObjectName(_fromUtf8("lineEditAddress")) + self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.lineEditAddress) + self.labelAddressCheck = QtGui.QLabel(AddAddressDialog) + self.labelAddressCheck.setText(_fromUtf8("")) + self.labelAddressCheck.setWordWrap(True) + self.labelAddressCheck.setObjectName(_fromUtf8("labelAddressCheck")) + self.formLayout.setWidget(6, QtGui.QFormLayout.SpanningRole, self.labelAddressCheck) + self.buttonBox = QtGui.QDialogButtonBox(AddAddressDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.formLayout.setWidget(7, QtGui.QFormLayout.FieldRole, self.buttonBox) + + self.retranslateUi(AddAddressDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), AddAddressDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), AddAddressDialog.reject) + QtCore.QMetaObject.connectSlotsByName(AddAddressDialog) + + def retranslateUi(self, AddAddressDialog): + AddAddressDialog.setWindowTitle(_translate("AddAddressDialog", "Add new entry", None)) + self.label_2.setText(_translate("AddAddressDialog", "Label", None)) + self.label.setText(_translate("AddAddressDialog", "Address", None)) + diff --git a/src/bitmessageqt/addaddressdialog.ui b/src/bitmessageqt/addaddressdialog.ui index 09701fa4..d7963e0a 100644 --- a/src/bitmessageqt/addaddressdialog.ui +++ b/src/bitmessageqt/addaddressdialog.ui @@ -7,15 +7,9 @@ 0 0 368 - 232 + 162 - - - 368 - 200 - - Add new entry @@ -31,7 +25,7 @@ - + @@ -53,7 +47,7 @@ - + Qt::Horizontal @@ -63,19 +57,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py deleted file mode 100644 index 2ea5cef8..00000000 --- a/src/bitmessageqt/address_dialogs.py +++ /dev/null @@ -1,354 +0,0 @@ -from PyQt4 import QtCore, QtGui -from addresses import decodeAddress, encodeVarint, addBMIfNotPresent -from account import ( - GatewayAccount, MailchuckAccount, AccountMixin, accountClass, - getSortedAccounts -) -from tr import _translate -from retranslateui import RetranslateMixin -import widgets - -import queues -import hashlib -from inventory import Inventory - - -class AddressCheckMixin(object): - - def __init__(self): - self.valid = False - QtCore.QObject.connect(self.lineEditAddress, QtCore.SIGNAL( - "textChanged(QString)"), self.addressChanged) - - def _onSuccess(self, addressVersion, streamNumber, ripe): - pass - - def addressChanged(self, QString): - status, addressVersion, streamNumber, ripe = decodeAddress( - str(QString)) - self.valid = status == 'success' - if self.valid: - self.labelAddressCheck.setText( - _translate("MainWindow", "Address is valid.")) - self._onSuccess(addressVersion, streamNumber, ripe) - elif status == 'missingbm': - self.labelAddressCheck.setText(_translate( - "MainWindow", # dialog name should be here - "The address should start with ''BM-''" - )) - elif status == 'checksumfailed': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "The address is not typed or copied correctly" - " (the checksum failed)." - )) - elif status == 'versiontoohigh': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "The version number of this address is higher than this" - " software can support. Please upgrade Bitmessage." - )) - elif status == 'invalidcharacters': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "The address contains invalid characters." - )) - elif status == 'ripetooshort': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "Some data encoded in the address is too short." - )) - elif status == 'ripetoolong': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "Some data encoded in the address is too long." - )) - elif status == 'varintmalformed': - self.labelAddressCheck.setText(_translate( - "MainWindow", - "Some data encoded in the address is malformed." - )) - - -class AddressDataDialog(QtGui.QDialog, AddressCheckMixin): - def __init__(self, parent): - super(AddressDataDialog, self).__init__(parent) - self.parent = parent - - def accept(self): - if self.valid: - self.data = ( - addBMIfNotPresent(str(self.lineEditAddress.text())), - str(self.lineEditLabel.text().toUtf8()) - ) - else: - queues.UISignalQueue.put(('updateStatusBar', _translate( - "MainWindow", - "The address you entered was invalid. Ignoring it." - ))) - super(AddressDataDialog, self).accept() - - -class AddAddressDialog(AddressDataDialog, RetranslateMixin): - - def __init__(self, parent=None, address=None): - super(AddAddressDialog, self).__init__(parent) - widgets.load('addaddressdialog.ui', self) - AddressCheckMixin.__init__(self) - if address: - self.lineEditAddress.setText(address) - - -class NewAddressDialog(QtGui.QDialog, RetranslateMixin): - - def __init__(self, parent=None): - super(NewAddressDialog, self).__init__(parent) - widgets.load('newaddressdialog.ui', self) - - # Let's fill out the 'existing address' combo box with addresses - # from the 'Your Identities' tab. - for address in getSortedAccounts(): - self.radioButtonExisting.click() - self.comboBoxExisting.addItem(address) - self.groupBoxDeterministic.setHidden(True) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - self.show() - - def accept(self): - self.hide() - # self.buttonBox.enabled = False - if self.radioButtonRandomAddress.isChecked(): - if self.radioButtonMostAvailable.isChecked(): - streamNumberForAddress = 1 - else: - # User selected 'Use the same stream as an existing - # address.' - streamNumberForAddress = decodeAddress( - self.comboBoxExisting.currentText())[2] - queues.addressGeneratorQueue.put(( - 'createRandomAddress', 4, streamNumberForAddress, - str(self.newaddresslabel.text().toUtf8()), 1, "", - self.checkBoxEighteenByteRipe.isChecked() - )) - else: - if self.lineEditPassphrase.text() != \ - self.lineEditPassphraseAgain.text(): - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Passphrase mismatch"), - _translate( - "MainWindow", - "The passphrase you entered twice doesn\'t" - " match. Try again.") - ) - elif self.lineEditPassphrase.text() == "": - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Choose a passphrase"), - _translate( - "MainWindow", "You really do need a passphrase.") - ) - else: - # this will eventually have to be replaced by logic - # to determine the most available stream number. - streamNumberForAddress = 1 - queues.addressGeneratorQueue.put(( - 'createDeterministicAddresses', 4, streamNumberForAddress, - "unused deterministic address", - self.spinBoxNumberOfAddressesToMake.value(), - self.lineEditPassphrase.text().toUtf8(), - self.checkBoxEighteenByteRipe.isChecked() - )) - - -class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): - - def __init__(self, parent=None): - super(NewSubscriptionDialog, self).__init__(parent) - widgets.load('newsubscriptiondialog.ui', self) - AddressCheckMixin.__init__(self) - - def _onSuccess(self, addressVersion, streamNumber, ripe): - if addressVersion <= 3: - self.checkBoxDisplayMessagesAlreadyInInventory.setText(_translate( - "MainWindow", - "Address is an old type. We cannot display its past" - " broadcasts." - )) - else: - Inventory().flush() - doubleHashOfAddressData = hashlib.sha512(hashlib.sha512( - encodeVarint(addressVersion) + - encodeVarint(streamNumber) + ripe - ).digest()).digest() - tag = doubleHashOfAddressData[32:] - self.recent = Inventory().by_type_and_tag(3, tag) - count = len(self.recent) - if count == 0: - self.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate( - "MainWindow", - "There are no recent broadcasts from this address" - " to display." - )) - else: - self.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) - self.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate( - "MainWindow", - "Display the %n recent broadcast(s) from this address.", - None, - QtCore.QCoreApplication.CodecForTr, - count - )) - - -class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(RegenerateAddressesDialog, self).__init__(parent) - widgets.load('regenerateaddresses.ui', self) - self.groupBox.setTitle('') - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - -class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin): - - def __init__(self, parent=None, config=None): - super(SpecialAddressBehaviorDialog, self).__init__(parent) - widgets.load('specialaddressbehavior.ui', self) - self.address = parent.getCurrentAccount() - self.parent = parent - self.config = config - - try: - self.address_is_chan = config.safeGetBoolean( - self.address, 'chan' - ) - except AttributeError: - pass - else: - if self.address_is_chan: # address is a chan address - self.radioButtonBehaviorMailingList.setDisabled(True) - self.lineEditMailingListName.setText(_translate( - "SpecialAddressBehaviorDialog", - "This is a chan address. You cannot use it as a" - " pseudo-mailing list." - )) - else: - if config.safeGetBoolean(self.address, 'mailinglist'): - self.radioButtonBehaviorMailingList.click() - else: - self.radioButtonBehaveNormalAddress.click() - try: - mailingListName = config.get( - self.address, 'mailinglistname') - except: - mailingListName = '' - self.lineEditMailingListName.setText( - unicode(mailingListName, 'utf-8') - ) - - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - self.show() - - def accept(self): - self.hide() - if self.address_is_chan: - return - if self.radioButtonBehaveNormalAddress.isChecked(): - self.config.set(str(self.address), 'mailinglist', 'false') - # Set the color to either black or grey - if self.config.getboolean(self.address, 'enabled'): - self.parent.setCurrentItemColor( - QtGui.QApplication.palette().text().color() - ) - else: - self.parent.setCurrentItemColor(QtGui.QColor(128, 128, 128)) - else: - self.config.set(str(self.address), 'mailinglist', 'true') - self.config.set(str(self.address), 'mailinglistname', str( - self.lineEditMailingListName.text().toUtf8())) - self.parent.setCurrentItemColor( - QtGui.QColor(137, 04, 177)) # magenta - self.parent.rerenderComboBoxSendFrom() - self.parent.rerenderComboBoxSendFromBroadcast() - self.config.save() - self.parent.rerenderMessagelistToLabels() - - -class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent, config=None, account=None): - super(EmailGatewayDialog, self).__init__(parent) - widgets.load('emailgateway.ui', self) - self.parent = parent - self.config = config - if account: - self.acct = account - self.setWindowTitle(_translate( - "EmailGatewayDialog", "Registration failed:")) - self.label.setText(_translate( - "EmailGatewayDialog", - "The requested email address is not available," - " please try a new one." - )) - self.radioButtonRegister.hide() - self.radioButtonStatus.hide() - self.radioButtonSettings.hide() - self.radioButtonUnregister.hide() - else: - address = parent.getCurrentAccount() - self.acct = accountClass(address) - try: - label = config.get(address, 'label') - except AttributeError: - pass - else: - if "@" in label: - self.lineEditEmail.setText(label) - if isinstance(self.acct, GatewayAccount): - self.radioButtonUnregister.setEnabled(True) - self.radioButtonStatus.setEnabled(True) - self.radioButtonStatus.setChecked(True) - self.radioButtonSettings.setEnabled(True) - self.lineEditEmail.setEnabled(False) - else: - self.acct = MailchuckAccount(address) - self.lineEditEmail.setFocus() - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - def accept(self): - self.hide() - # no chans / mailinglists - if self.acct.type != AccountMixin.NORMAL: - return - - if not isinstance(self.acct, GatewayAccount): - return - - if self.radioButtonRegister.isChecked() \ - or self.radioButtonRegister.isHidden(): - email = str(self.lineEditEmail.text().toUtf8()) - self.acct.register(email) - self.config.set(self.acct.fromAddress, 'label', email) - self.config.set(self.acct.fromAddress, 'gateway', 'mailchuck') - self.config.save() - queues.UISignalQueue.put(('updateStatusBar', _translate( - "EmailGatewayDialog", - "Sending email gateway registration request" - ))) - elif self.radioButtonUnregister.isChecked(): - self.acct.unregister() - self.config.remove_option(self.acct.fromAddress, 'gateway') - self.config.save() - queues.UISignalQueue.put(('updateStatusBar', _translate( - "EmailGatewayDialog", - "Sending email gateway unregistration request" - ))) - elif self.radioButtonStatus.isChecked(): - self.acct.status() - queues.UISignalQueue.put(('updateStatusBar', _translate( - "EmailGatewayDialog", - "Sending email gateway status request" - ))) - elif self.radioButtonSettings.isChecked(): - self.data = self.acct - - super(EmailGatewayDialog, self).accept() diff --git a/src/bitmessageqt/addressvalidator.py b/src/bitmessageqt/addressvalidator.py deleted file mode 100644 index f9de70a2..00000000 --- a/src/bitmessageqt/addressvalidator.py +++ /dev/null @@ -1,144 +0,0 @@ -from PyQt4 import QtGui -from Queue import Empty - -from addresses import decodeAddress, addBMIfNotPresent -from account import getSortedAccounts -from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue -from tr import _translate -from utils import str_chan - -class AddressPassPhraseValidatorMixin(): - def setParams(self, passPhraseObject=None, addressObject=None, feedBackObject=None, buttonBox=None, addressMandatory=True): - self.addressObject = addressObject - self.passPhraseObject = passPhraseObject - self.feedBackObject = feedBackObject - self.buttonBox = buttonBox - self.addressMandatory = addressMandatory - self.isValid = False - # save default text - self.okButtonLabel = self.buttonBox.button(QtGui.QDialogButtonBox.Ok).text() - - def setError(self, string): - if string is not None and self.feedBackObject is not None: - font = QtGui.QFont() - font.setBold(True) - self.feedBackObject.setFont(font) - self.feedBackObject.setStyleSheet("QLabel { color : red; }") - self.feedBackObject.setText(string) - self.isValid = False - if self.buttonBox: - self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False) - if string is not None and self.feedBackObject is not None: - self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(_translate("AddressValidator", "Invalid")) - else: - self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(_translate("AddressValidator", "Validating...")) - - def setOK(self, string): - if string is not None and self.feedBackObject is not None: - font = QtGui.QFont() - font.setBold(False) - self.feedBackObject.setFont(font) - self.feedBackObject.setStyleSheet("QLabel { }") - self.feedBackObject.setText(string) - self.isValid = True - if self.buttonBox: - self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True) - self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setText(self.okButtonLabel) - - def checkQueue(self): - gotOne = False - - # wait until processing is done - if not addressGeneratorQueue.empty(): - self.setError(None) - return - - while True: - try: - addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(False) - except Empty: - if gotOne: - break - else: - return - else: - gotOne = True - - if len(addressGeneratorReturnValue) == 0: - self.setError(_translate("AddressValidator", "Address already present as one of your identities.")) - return (QtGui.QValidator.Intermediate, 0) - if addressGeneratorReturnValue[0] == 'chan name does not match address': - self.setError(_translate("AddressValidator", "Although the Bitmessage address you entered was valid, it doesn\'t match the chan name.")) - return (QtGui.QValidator.Intermediate, 0) - self.setOK(_translate("MainWindow", "Passphrase and address appear to be valid.")) - - def returnValid(self): - if self.isValid: - return QtGui.QValidator.Acceptable - else: - return QtGui.QValidator.Intermediate - - def validate(self, s, pos): - if self.addressObject is None: - address = None - else: - address = str(self.addressObject.text().toUtf8()) - if address == "": - address = None - if self.passPhraseObject is None: - passPhrase = "" - else: - passPhrase = str(self.passPhraseObject.text().toUtf8()) - if passPhrase == "": - passPhrase = None - - # no chan name - if passPhrase is None: - self.setError(_translate("AddressValidator", "Chan name/passphrase needed. You didn't enter a chan name.")) - return (QtGui.QValidator.Intermediate, pos) - - if self.addressMandatory or address is not None: - # check if address already exists: - if address in getSortedAccounts(): - self.setError(_translate("AddressValidator", "Address already present as one of your identities.")) - return (QtGui.QValidator.Intermediate, pos) - - # version too high - if decodeAddress(address)[0] == 'versiontoohigh': - self.setError(_translate("AddressValidator", "Address too new. Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage.")) - return (QtGui.QValidator.Intermediate, pos) - - # invalid - if decodeAddress(address)[0] != 'success': - self.setError(_translate("AddressValidator", "The Bitmessage address is not valid.")) - return (QtGui.QValidator.Intermediate, pos) - - # this just disables the OK button without changing the feedback text - # but only if triggered by textEdited, not by clicking the Ok button - if not self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus(): - self.setError(None) - - # check through generator - if address is None: - addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + str(passPhrase), passPhrase, False)) - else: - addressGeneratorQueue.put(('joinChan', addBMIfNotPresent(address), str_chan + ' ' + str(passPhrase), passPhrase, False)) - - if self.buttonBox.button(QtGui.QDialogButtonBox.Ok).hasFocus(): - return (self.returnValid(), pos) - else: - return (QtGui.QValidator.Intermediate, pos) - - def checkData(self): - return self.validate("", 0) - -class AddressValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin): - def __init__(self, parent=None, passPhraseObject=None, feedBackObject=None, buttonBox=None, addressMandatory=True): - super(AddressValidator, self).__init__(parent) - self.setParams(passPhraseObject, parent, feedBackObject, buttonBox, addressMandatory) - - -class PassPhraseValidator(QtGui.QValidator, AddressPassPhraseValidatorMixin): - def __init__(self, parent=None, addressObject=None, feedBackObject=None, buttonBox=None, addressMandatory=False): - super(PassPhraseValidator, self).__init__(parent) - self.setParams(parent, addressObject, feedBackObject, buttonBox, addressMandatory) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index cb3578c0..e35b30cd 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,19 +2,12 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Mon Mar 23 22:18:07 2015 -# by: PyQt4 UI code generator 4.10.4 +# Created: Sun Mar 08 22:07:43 2015 +# by: PyQt4 UI code generator 4.10.3 # # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -from bmconfigparser import BMConfigParser -from foldertree import AddressBookCompleter -from messageview import MessageView -from messagecompose import MessageCompose -import settingsmixin -from networkstatus import NetworkStatus -from blacklist import Blacklist try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -24,17 +17,11 @@ except AttributeError: try: _encoding = QtGui.QApplication.UnicodeUTF8 - def _translate(context, text, disambig, encoding = QtCore.QCoreApplication.CodecForTr, n = None): - if n is None: - return QtGui.QApplication.translate(context, text, disambig, _encoding) - else: - return QtGui.QApplication.translate(context, text, disambig, _encoding, n) + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) except AttributeError: - def _translate(context, text, disambig, encoding = QtCore.QCoreApplication.CodecForTr, n = None): - if n is None: - return QtGui.QApplication.translate(context, text, disambig) - else: - return QtGui.QApplication.translate(context, text, disambig, QtCore.QCoreApplication.CodecForTr, n) + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) class Ui_MainWindow(object): def setupUi(self, MainWindow): @@ -46,8 +33,9 @@ class Ui_MainWindow(object): MainWindow.setTabShape(QtGui.QTabWidget.Rounded) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) - self.gridLayout_10 = QtGui.QGridLayout(self.centralwidget) - self.gridLayout_10.setObjectName(_fromUtf8("gridLayout_10")) + self.gridLayout = QtGui.QGridLayout(self.centralwidget) + self.gridLayout.setMargin(0) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.tabWidget = QtGui.QTabWidget(self.centralwidget) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -64,52 +52,27 @@ class Ui_MainWindow(object): self.tabWidget.setObjectName(_fromUtf8("tabWidget")) self.inbox = QtGui.QWidget() self.inbox.setObjectName(_fromUtf8("inbox")) - self.gridLayout = QtGui.QGridLayout(self.inbox) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.horizontalSplitter_3 = settingsmixin.SSplitter() - self.horizontalSplitter_3.setObjectName(_fromUtf8("horizontalSplitter_3")) - self.verticalSplitter_12 = settingsmixin.SSplitter() - self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12")) - self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetYourIdentities = settingsmixin.STreeWidget(self.inbox) - self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities")) - self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height()) - icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - self.treeWidgetYourIdentities.headerItem().setIcon(0, icon1) - self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities) - self.pushButtonNewAddress = QtGui.QPushButton(self.inbox) - self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) - self.pushButtonNewAddress.resize(200, self.pushButtonNewAddress.height()) - self.verticalSplitter_12.addWidget(self.pushButtonNewAddress) - self.verticalSplitter_12.setStretchFactor(0, 1) - self.verticalSplitter_12.setStretchFactor(1, 0) - self.verticalSplitter_12.setCollapsible(0, False) - self.verticalSplitter_12.setCollapsible(1, False) - self.verticalSplitter_12.handle(1).setEnabled(False) - self.horizontalSplitter_3.addWidget(self.verticalSplitter_12) - self.verticalSplitter_7 = settingsmixin.SSplitter() - self.verticalSplitter_7.setObjectName(_fromUtf8("verticalSplitter_7")) - self.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitterSearch = QtGui.QSplitter() - self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch")) + self.verticalLayout_2 = QtGui.QVBoxLayout(self.inbox) + self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) + self.horizontalLayoutSearch = QtGui.QHBoxLayout() + self.horizontalLayoutSearch.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayoutSearch.setObjectName(_fromUtf8("horizontalLayoutSearch")) self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox) self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit")) - self.horizontalSplitterSearch.addWidget(self.inboxSearchLineEdit) - self.inboxSearchOption = QtGui.QComboBox(self.inbox) - self.inboxSearchOption.setObjectName(_fromUtf8("inboxSearchOption")) - self.inboxSearchOption.addItem(_fromUtf8("")) - self.inboxSearchOption.addItem(_fromUtf8("")) - self.inboxSearchOption.addItem(_fromUtf8("")) - self.inboxSearchOption.addItem(_fromUtf8("")) - self.inboxSearchOption.addItem(_fromUtf8("")) - self.inboxSearchOption.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) - self.horizontalSplitterSearch.addWidget(self.inboxSearchOption) - self.horizontalSplitterSearch.handle(1).setEnabled(False) - self.horizontalSplitterSearch.setStretchFactor(0, 1) - self.horizontalSplitterSearch.setStretchFactor(1, 0) - self.verticalSplitter_7.addWidget(self.horizontalSplitterSearch) - self.tableWidgetInbox = settingsmixin.STableWidget(self.inbox) + self.horizontalLayoutSearch.addWidget(self.inboxSearchLineEdit) + self.inboxSearchOptionCB = QtGui.QComboBox(self.inbox) + self.inboxSearchOptionCB.setObjectName(_fromUtf8("inboxSearchOptionCB")) + self.inboxSearchOptionCB.addItem(_fromUtf8("")) + self.inboxSearchOptionCB.addItem(_fromUtf8("")) + self.inboxSearchOptionCB.addItem(_fromUtf8("")) + self.inboxSearchOptionCB.addItem(_fromUtf8("")) + self.inboxSearchOptionCB.addItem(_fromUtf8("")) + self.horizontalLayoutSearch.addWidget(self.inboxSearchOptionCB) + self.verticalLayout_2.addLayout(self.horizontalLayoutSearch) + self.splitter = QtGui.QSplitter(self.inbox) + self.splitter.setOrientation(QtCore.Qt.Vertical) + self.splitter.setObjectName(_fromUtf8("splitter")) + self.tableWidgetInbox = QtGui.QTableWidget(self.splitter) self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInbox.setAlternatingRowColors(True) self.tableWidgetInbox.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) @@ -134,176 +97,84 @@ class Ui_MainWindow(object): self.tableWidgetInbox.horizontalHeader().setStretchLastSection(True) self.tableWidgetInbox.verticalHeader().setVisible(False) self.tableWidgetInbox.verticalHeader().setDefaultSectionSize(26) - self.verticalSplitter_7.addWidget(self.tableWidgetInbox) - self.textEditInboxMessage = MessageView(self.inbox) + self.textEditInboxMessage = QtGui.QTextEdit(self.splitter) self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessage.setReadOnly(True) self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage")) - self.verticalSplitter_7.addWidget(self.textEditInboxMessage) - self.verticalSplitter_7.setStretchFactor(0, 0) - self.verticalSplitter_7.setStretchFactor(1, 1) - self.verticalSplitter_7.setStretchFactor(2, 2) - self.verticalSplitter_7.setCollapsible(0, False) - self.verticalSplitter_7.setCollapsible(1, False) - self.verticalSplitter_7.setCollapsible(2, False) - self.verticalSplitter_7.handle(1).setEnabled(False) - self.horizontalSplitter_3.addWidget(self.verticalSplitter_7) - self.horizontalSplitter_3.setStretchFactor(0, 0) - self.horizontalSplitter_3.setStretchFactor(1, 1) - self.horizontalSplitter_3.setCollapsible(0, False) - self.horizontalSplitter_3.setCollapsible(1, False) - self.gridLayout.addWidget(self.horizontalSplitter_3) - icon2 = QtGui.QIcon() - icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.inbox, icon2, _fromUtf8("")) + self.verticalLayout_2.addWidget(self.splitter) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.inbox, icon1, _fromUtf8("")) self.send = QtGui.QWidget() self.send.setObjectName(_fromUtf8("send")) - self.gridLayout_7 = QtGui.QGridLayout(self.send) - self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7")) - self.horizontalSplitter = settingsmixin.SSplitter() - self.horizontalSplitter.setObjectName(_fromUtf8("horizontalSplitter")) - self.verticalSplitter_2 = settingsmixin.SSplitter() - self.verticalSplitter_2.setObjectName(_fromUtf8("verticalSplitter_2")) - self.verticalSplitter_2.setOrientation(QtCore.Qt.Vertical) - self.tableWidgetAddressBook = settingsmixin.STableWidget(self.send) - self.tableWidgetAddressBook.setAlternatingRowColors(True) - self.tableWidgetAddressBook.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) - self.tableWidgetAddressBook.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableWidgetAddressBook.setObjectName(_fromUtf8("tableWidgetAddressBook")) - self.tableWidgetAddressBook.setColumnCount(2) - self.tableWidgetAddressBook.setRowCount(0) - self.tableWidgetAddressBook.resize(200, self.tableWidgetAddressBook.height()) - item = QtGui.QTableWidgetItem() - icon3 = QtGui.QIcon() - icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - item.setIcon(icon3) - self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item) - item = QtGui.QTableWidgetItem() - self.tableWidgetAddressBook.setHorizontalHeaderItem(1, item) - self.tableWidgetAddressBook.horizontalHeader().setCascadingSectionResizes(True) - self.tableWidgetAddressBook.horizontalHeader().setDefaultSectionSize(200) - self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False) - self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True) - self.tableWidgetAddressBook.verticalHeader().setVisible(False) - self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook) - self.addressBookCompleter = AddressBookCompleter() - self.addressBookCompleter.setCompletionMode(QtGui.QCompleter.PopupCompletion) - self.addressBookCompleter.setCaseSensitivity(QtCore.Qt.CaseInsensitive) - self.addressBookCompleterModel = QtGui.QStringListModel() - self.addressBookCompleter.setModel(self.addressBookCompleterModel) - self.pushButtonAddAddressBook = QtGui.QPushButton(self.send) - self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) - self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height()) - self.verticalSplitter_2.addWidget(self.pushButtonAddAddressBook) - self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send) - self.pushButtonFetchNamecoinID.resize(200, self.pushButtonFetchNamecoinID.height()) - self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) - self.verticalSplitter_2.addWidget(self.pushButtonFetchNamecoinID) - self.verticalSplitter_2.setStretchFactor(0, 1) - self.verticalSplitter_2.setStretchFactor(1, 0) - self.verticalSplitter_2.setStretchFactor(2, 0) - self.verticalSplitter_2.setCollapsible(0, False) - self.verticalSplitter_2.setCollapsible(1, False) - self.verticalSplitter_2.setCollapsible(2, False) - self.verticalSplitter_2.handle(1).setEnabled(False) - self.verticalSplitter_2.handle(2).setEnabled(False) - self.horizontalSplitter.addWidget(self.verticalSplitter_2) - self.verticalSplitter = settingsmixin.SSplitter() - self.verticalSplitter.setObjectName(_fromUtf8("verticalSplitter")) - self.verticalSplitter.setOrientation(QtCore.Qt.Vertical) - self.tabWidgetSend = QtGui.QTabWidget(self.send) - self.tabWidgetSend.setObjectName(_fromUtf8("tabWidgetSend")) - self.sendDirect = QtGui.QWidget() - self.sendDirect.setObjectName(_fromUtf8("sendDirect")) - self.gridLayout_8 = QtGui.QGridLayout(self.sendDirect) - self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) - self.verticalSplitter_5 = settingsmixin.SSplitter() - self.verticalSplitter_5.setObjectName(_fromUtf8("verticalSplitter_5")) - self.verticalSplitter_5.setOrientation(QtCore.Qt.Vertical) - self.gridLayout_2 = QtGui.QGridLayout() + self.gridLayout_2 = QtGui.QGridLayout(self.send) self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) - self.label_3 = QtGui.QLabel(self.sendDirect) + self.pushButtonLoadFromAddressBook = QtGui.QPushButton(self.send) + font = QtGui.QFont() + font.setPointSize(7) + self.pushButtonLoadFromAddressBook.setFont(font) + self.pushButtonLoadFromAddressBook.setObjectName(_fromUtf8("pushButtonLoadFromAddressBook")) + self.gridLayout_2.addWidget(self.pushButtonLoadFromAddressBook, 3, 2, 1, 1) + self.label_3 = QtGui.QLabel(self.send) self.label_3.setObjectName(_fromUtf8("label_3")) - self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1) - self.label_2 = QtGui.QLabel(self.sendDirect) - self.label_2.setObjectName(_fromUtf8("label_2")) - self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1) - self.lineEditSubject = QtGui.QLineEdit(self.sendDirect) - self.lineEditSubject.setText(_fromUtf8("")) - self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) - self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1) - self.label = QtGui.QLabel(self.sendDirect) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1) - self.comboBoxSendFrom = QtGui.QComboBox(self.sendDirect) + self.gridLayout_2.addWidget(self.label_3, 4, 0, 1, 1) + self.pushButtonSend = QtGui.QPushButton(self.send) + self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) + self.gridLayout_2.addWidget(self.pushButtonSend, 7, 8, 1, 1) + self.horizontalSliderTTL = QtGui.QSlider(self.send) + self.horizontalSliderTTL.setMinimumSize(QtCore.QSize(35, 0)) + self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(70, 16777215)) + self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal) + self.horizontalSliderTTL.setInvertedAppearance(False) + self.horizontalSliderTTL.setInvertedControls(False) + self.horizontalSliderTTL.setObjectName(_fromUtf8("horizontalSliderTTL")) + self.gridLayout_2.addWidget(self.horizontalSliderTTL, 7, 6, 1, 1) + spacerItem = QtGui.QSpacerItem(20, 297, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 6, 0, 1, 1) + self.comboBoxSendFrom = QtGui.QComboBox(self.send) self.comboBoxSendFrom.setMinimumSize(QtCore.QSize(300, 0)) self.comboBoxSendFrom.setObjectName(_fromUtf8("comboBoxSendFrom")) - self.gridLayout_2.addWidget(self.comboBoxSendFrom, 0, 1, 1, 1) - self.lineEditTo = QtGui.QLineEdit(self.sendDirect) - self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) - self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) - self.lineEditTo.setCompleter(self.addressBookCompleter) - self.gridLayout_2_Widget = QtGui.QWidget() - self.gridLayout_2_Widget.setLayout(self.gridLayout_2) - self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget) - self.textEditMessage = MessageCompose(self.sendDirect) - self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) - self.verticalSplitter_5.addWidget(self.textEditMessage) - self.verticalSplitter_5.setStretchFactor(0, 0) - self.verticalSplitter_5.setStretchFactor(1, 1) - self.verticalSplitter_5.setCollapsible(0, False) - self.verticalSplitter_5.setCollapsible(1, False) - self.verticalSplitter_5.handle(1).setEnabled(False) - self.gridLayout_8.addWidget(self.verticalSplitter_5, 0, 0, 1, 1) - self.tabWidgetSend.addTab(self.sendDirect, _fromUtf8("")) - self.sendBroadcast = QtGui.QWidget() - self.sendBroadcast.setObjectName(_fromUtf8("sendBroadcast")) - self.gridLayout_9 = QtGui.QGridLayout(self.sendBroadcast) - self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) - self.verticalSplitter_6 = settingsmixin.SSplitter() - self.verticalSplitter_6.setObjectName(_fromUtf8("verticalSplitter_6")) - self.verticalSplitter_6.setOrientation(QtCore.Qt.Vertical) - self.gridLayout_5 = QtGui.QGridLayout() - self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) - self.label_8 = QtGui.QLabel(self.sendBroadcast) - self.label_8.setObjectName(_fromUtf8("label_8")) - self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1) - self.lineEditSubjectBroadcast = QtGui.QLineEdit(self.sendBroadcast) - self.lineEditSubjectBroadcast.setText(_fromUtf8("")) - self.lineEditSubjectBroadcast.setObjectName(_fromUtf8("lineEditSubjectBroadcast")) - self.gridLayout_5.addWidget(self.lineEditSubjectBroadcast, 1, 1, 1, 1) - self.label_7 = QtGui.QLabel(self.sendBroadcast) - self.label_7.setObjectName(_fromUtf8("label_7")) - self.gridLayout_5.addWidget(self.label_7, 1, 0, 1, 1) - self.comboBoxSendFromBroadcast = QtGui.QComboBox(self.sendBroadcast) - self.comboBoxSendFromBroadcast.setMinimumSize(QtCore.QSize(300, 0)) - self.comboBoxSendFromBroadcast.setObjectName(_fromUtf8("comboBoxSendFromBroadcast")) - self.gridLayout_5.addWidget(self.comboBoxSendFromBroadcast, 0, 1, 1, 1) - self.gridLayout_5_Widget = QtGui.QWidget() - self.gridLayout_5_Widget.setLayout(self.gridLayout_5) - self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget) - self.textEditMessageBroadcast = MessageCompose(self.sendBroadcast) - self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast")) - self.verticalSplitter_6.addWidget(self.textEditMessageBroadcast) - self.verticalSplitter_6.setStretchFactor(0, 0) - self.verticalSplitter_6.setStretchFactor(1, 1) - self.verticalSplitter_6.setCollapsible(0, False) - self.verticalSplitter_6.setCollapsible(1, False) - self.verticalSplitter_6.handle(1).setEnabled(False) - self.gridLayout_9.addWidget(self.verticalSplitter_6, 0, 0, 1, 1) - self.tabWidgetSend.addTab(self.sendBroadcast, _fromUtf8("")) - self.verticalSplitter.addWidget(self.tabWidgetSend) - self.tTLContainer = QtGui.QWidget() - self.tTLContainer.setSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) - self.horizontalLayout_5 = QtGui.QHBoxLayout() - self.tTLContainer.setLayout(self.horizontalLayout_5) - self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5")) + self.gridLayout_2.addWidget(self.comboBoxSendFrom, 2, 1, 1, 1) + self.labelHumanFriendlyTTLDescription = QtGui.QLabel(self.send) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth()) + self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy) + self.labelHumanFriendlyTTLDescription.setMinimumSize(QtCore.QSize(45, 0)) + self.labelHumanFriendlyTTLDescription.setMaximumSize(QtCore.QSize(45, 16777215)) + self.labelHumanFriendlyTTLDescription.setObjectName(_fromUtf8("labelHumanFriendlyTTLDescription")) + self.gridLayout_2.addWidget(self.labelHumanFriendlyTTLDescription, 7, 7, 1, 1) + self.label_4 = QtGui.QLabel(self.send) + self.label_4.setObjectName(_fromUtf8("label_4")) + self.gridLayout_2.addWidget(self.label_4, 5, 0, 1, 1) + self.label = QtGui.QLabel(self.send) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout_2.addWidget(self.label, 3, 0, 1, 1) + self.radioButtonSpecific = QtGui.QRadioButton(self.send) + self.radioButtonSpecific.setChecked(True) + self.radioButtonSpecific.setObjectName(_fromUtf8("radioButtonSpecific")) + self.gridLayout_2.addWidget(self.radioButtonSpecific, 0, 1, 1, 1) + self.labelSendBroadcastWarning = QtGui.QLabel(self.send) + self.labelSendBroadcastWarning.setEnabled(True) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.labelSendBroadcastWarning.sizePolicy().hasHeightForWidth()) + self.labelSendBroadcastWarning.setSizePolicy(sizePolicy) + self.labelSendBroadcastWarning.setIndent(-1) + self.labelSendBroadcastWarning.setObjectName(_fromUtf8("labelSendBroadcastWarning")) + self.gridLayout_2.addWidget(self.labelSendBroadcastWarning, 7, 1, 1, 4) + self.radioButtonBroadcast = QtGui.QRadioButton(self.send) + self.radioButtonBroadcast.setObjectName(_fromUtf8("radioButtonBroadcast")) + self.gridLayout_2.addWidget(self.radioButtonBroadcast, 1, 1, 1, 2) self.pushButtonTTL = QtGui.QPushButton(self.send) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButtonTTL.sizePolicy().hasHeightForWidth()) self.pushButtonTTL.setSizePolicy(sizePolicy) + self.pushButtonTTL.setMaximumSize(QtCore.QSize(32, 16777215)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) brush.setStyle(QtCore.Qt.SolidPattern) @@ -320,255 +191,301 @@ class Ui_MainWindow(object): self.pushButtonTTL.setFont(font) self.pushButtonTTL.setFlat(True) self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL")) - self.horizontalLayout_5.addWidget(self.pushButtonTTL, 0, QtCore.Qt.AlignRight) - self.horizontalSliderTTL = QtGui.QSlider(self.send) - self.horizontalSliderTTL.setMinimumSize(QtCore.QSize(70, 0)) - self.horizontalSliderTTL.setOrientation(QtCore.Qt.Horizontal) - self.horizontalSliderTTL.setInvertedAppearance(False) - self.horizontalSliderTTL.setInvertedControls(False) - self.horizontalSliderTTL.setObjectName(_fromUtf8("horizontalSliderTTL")) - self.horizontalLayout_5.addWidget(self.horizontalSliderTTL, 0, QtCore.Qt.AlignLeft) - self.labelHumanFriendlyTTLDescription = QtGui.QLabel(self.send) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.labelHumanFriendlyTTLDescription.sizePolicy().hasHeightForWidth()) - self.labelHumanFriendlyTTLDescription.setSizePolicy(sizePolicy) - self.labelHumanFriendlyTTLDescription.setMinimumSize(QtCore.QSize(45, 0)) - self.labelHumanFriendlyTTLDescription.setObjectName(_fromUtf8("labelHumanFriendlyTTLDescription")) - self.horizontalLayout_5.addWidget(self.labelHumanFriendlyTTLDescription, 1, QtCore.Qt.AlignLeft) - self.pushButtonClear = QtGui.QPushButton(self.send) - self.pushButtonClear.setObjectName(_fromUtf8("pushButtonClear")) - self.horizontalLayout_5.addWidget(self.pushButtonClear, 0, QtCore.Qt.AlignRight) - self.pushButtonSend = QtGui.QPushButton(self.send) - self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) - self.horizontalLayout_5.addWidget(self.pushButtonSend, 0, QtCore.Qt.AlignRight) - self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(105, self.pushButtonSend.height())) - self.verticalSplitter.addWidget(self.tTLContainer) - self.tTLContainer.adjustSize() - self.verticalSplitter.setStretchFactor(1, 0) - self.verticalSplitter.setStretchFactor(0, 1) - self.verticalSplitter.setCollapsible(0, False) - self.verticalSplitter.setCollapsible(1, False) - self.verticalSplitter.handle(1).setEnabled(False) - self.horizontalSplitter.addWidget(self.verticalSplitter) - self.horizontalSplitter.setStretchFactor(0, 0) - self.horizontalSplitter.setStretchFactor(1, 1) - self.horizontalSplitter.setCollapsible(0, False) - self.horizontalSplitter.setCollapsible(1, False) - self.gridLayout_7.addWidget(self.horizontalSplitter, 0, 0, 1, 1) + self.gridLayout_2.addWidget(self.pushButtonTTL, 7, 5, 1, 1) + self.label_2 = QtGui.QLabel(self.send) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 2, 0, 1, 1) + self.lineEditTo = QtGui.QLineEdit(self.send) + self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) + self.gridLayout_2.addWidget(self.lineEditTo, 3, 1, 1, 1) + self.textEditMessage = QtGui.QTextEdit(self.send) + self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) + self.gridLayout_2.addWidget(self.textEditMessage, 5, 1, 2, 8) + self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send) + font = QtGui.QFont() + font.setPointSize(7) + self.pushButtonFetchNamecoinID.setFont(font) + self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) + self.gridLayout_2.addWidget(self.pushButtonFetchNamecoinID, 3, 3, 1, 1) + self.labelFrom = QtGui.QLabel(self.send) + self.labelFrom.setText(_fromUtf8("")) + self.labelFrom.setObjectName(_fromUtf8("labelFrom")) + self.gridLayout_2.addWidget(self.labelFrom, 2, 2, 1, 7) + self.lineEditSubject = QtGui.QLineEdit(self.send) + self.lineEditSubject.setText(_fromUtf8("")) + self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) + self.gridLayout_2.addWidget(self.lineEditSubject, 4, 1, 1, 8) + icon2 = QtGui.QIcon() + icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.send, icon2, _fromUtf8("")) + self.sent = QtGui.QWidget() + self.sent.setObjectName(_fromUtf8("sent")) + self.verticalLayout = QtGui.QVBoxLayout(self.sent) + self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) + self.sentSearchLineEdit = QtGui.QLineEdit(self.sent) + self.sentSearchLineEdit.setObjectName(_fromUtf8("sentSearchLineEdit")) + self.horizontalLayout.addWidget(self.sentSearchLineEdit) + self.sentSearchOptionCB = QtGui.QComboBox(self.sent) + self.sentSearchOptionCB.setObjectName(_fromUtf8("sentSearchOptionCB")) + self.sentSearchOptionCB.addItem(_fromUtf8("")) + self.sentSearchOptionCB.addItem(_fromUtf8("")) + self.sentSearchOptionCB.addItem(_fromUtf8("")) + self.sentSearchOptionCB.addItem(_fromUtf8("")) + self.sentSearchOptionCB.addItem(_fromUtf8("")) + self.horizontalLayout.addWidget(self.sentSearchOptionCB) + self.verticalLayout.addLayout(self.horizontalLayout) + self.splitter_2 = QtGui.QSplitter(self.sent) + self.splitter_2.setOrientation(QtCore.Qt.Vertical) + self.splitter_2.setObjectName(_fromUtf8("splitter_2")) + self.tableWidgetSent = QtGui.QTableWidget(self.splitter_2) + self.tableWidgetSent.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.tableWidgetSent.setDragDropMode(QtGui.QAbstractItemView.DragDrop) + self.tableWidgetSent.setAlternatingRowColors(True) + self.tableWidgetSent.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + self.tableWidgetSent.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetSent.setWordWrap(False) + self.tableWidgetSent.setObjectName(_fromUtf8("tableWidgetSent")) + self.tableWidgetSent.setColumnCount(4) + self.tableWidgetSent.setRowCount(0) + item = QtGui.QTableWidgetItem() + self.tableWidgetSent.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetSent.setHorizontalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetSent.setHorizontalHeaderItem(2, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetSent.setHorizontalHeaderItem(3, item) + self.tableWidgetSent.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetSent.horizontalHeader().setDefaultSectionSize(130) + self.tableWidgetSent.horizontalHeader().setHighlightSections(False) + self.tableWidgetSent.horizontalHeader().setSortIndicatorShown(False) + self.tableWidgetSent.horizontalHeader().setStretchLastSection(True) + self.tableWidgetSent.verticalHeader().setVisible(False) + self.tableWidgetSent.verticalHeader().setStretchLastSection(False) + self.textEditSentMessage = QtGui.QTextEdit(self.splitter_2) + self.textEditSentMessage.setReadOnly(True) + self.textEditSentMessage.setObjectName(_fromUtf8("textEditSentMessage")) + self.verticalLayout.addWidget(self.splitter_2) + icon3 = QtGui.QIcon() + icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/sent.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.sent, icon3, _fromUtf8("")) + self.youridentities = QtGui.QWidget() + self.youridentities.setObjectName(_fromUtf8("youridentities")) + self.gridLayout_3 = QtGui.QGridLayout(self.youridentities) + self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) + self.pushButtonNewAddress = QtGui.QPushButton(self.youridentities) + self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) + self.gridLayout_3.addWidget(self.pushButtonNewAddress, 0, 0, 1, 1) + spacerItem1 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem1, 0, 1, 1, 1) + self.tableWidgetYourIdentities = QtGui.QTableWidget(self.youridentities) + self.tableWidgetYourIdentities.setFrameShadow(QtGui.QFrame.Sunken) + self.tableWidgetYourIdentities.setLineWidth(1) + self.tableWidgetYourIdentities.setAlternatingRowColors(True) + self.tableWidgetYourIdentities.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) + self.tableWidgetYourIdentities.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetYourIdentities.setObjectName(_fromUtf8("tableWidgetYourIdentities")) + self.tableWidgetYourIdentities.setColumnCount(3) + self.tableWidgetYourIdentities.setRowCount(0) + item = QtGui.QTableWidgetItem() + font = QtGui.QFont() + font.setKerning(True) + item.setFont(font) + self.tableWidgetYourIdentities.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetYourIdentities.setHorizontalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetYourIdentities.setHorizontalHeaderItem(2, item) + self.tableWidgetYourIdentities.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetYourIdentities.horizontalHeader().setDefaultSectionSize(346) + self.tableWidgetYourIdentities.horizontalHeader().setMinimumSectionSize(52) + self.tableWidgetYourIdentities.horizontalHeader().setSortIndicatorShown(True) + self.tableWidgetYourIdentities.horizontalHeader().setStretchLastSection(True) + self.tableWidgetYourIdentities.verticalHeader().setVisible(False) + self.tableWidgetYourIdentities.verticalHeader().setDefaultSectionSize(26) + self.tableWidgetYourIdentities.verticalHeader().setSortIndicatorShown(False) + self.tableWidgetYourIdentities.verticalHeader().setStretchLastSection(False) + self.gridLayout_3.addWidget(self.tableWidgetYourIdentities, 1, 0, 1, 2) icon4 = QtGui.QIcon() - icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/send.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.send, icon4, _fromUtf8("")) + icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/identities.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.youridentities, icon4, _fromUtf8("")) self.subscriptions = QtGui.QWidget() self.subscriptions.setObjectName(_fromUtf8("subscriptions")) - self.gridLayout_3 = QtGui.QGridLayout(self.subscriptions) - self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - self.horizontalSplitter_4 = settingsmixin.SSplitter() - self.horizontalSplitter_4.setObjectName(_fromUtf8("horizontalSplitter_4")) - self.verticalSplitter_3 = settingsmixin.SSplitter() - self.verticalSplitter_3.setObjectName(_fromUtf8("verticalSplitter_3")) - self.verticalSplitter_3.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetSubscriptions = settingsmixin.STreeWidget(self.subscriptions) - self.treeWidgetSubscriptions.setAlternatingRowColors(True) - self.treeWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) - self.treeWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions")) - self.treeWidgetSubscriptions.resize(200, self.treeWidgetSubscriptions.height()) - icon5 = QtGui.QIcon() - icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5) - self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions) + self.gridLayout_4 = QtGui.QGridLayout(self.subscriptions) + self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) + self.label_5 = QtGui.QLabel(self.subscriptions) + self.label_5.setWordWrap(True) + self.label_5.setObjectName(_fromUtf8("label_5")) + self.gridLayout_4.addWidget(self.label_5, 0, 0, 1, 2) self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) - self.pushButtonAddSubscription.resize(200, self.pushButtonAddSubscription.height()) - self.verticalSplitter_3.addWidget(self.pushButtonAddSubscription) - self.verticalSplitter_3.setStretchFactor(0, 1) - self.verticalSplitter_3.setStretchFactor(1, 0) - self.verticalSplitter_3.setCollapsible(0, False) - self.verticalSplitter_3.setCollapsible(1, False) - self.verticalSplitter_3.handle(1).setEnabled(False) - self.horizontalSplitter_4.addWidget(self.verticalSplitter_3) - self.verticalSplitter_4 = settingsmixin.SSplitter() - self.verticalSplitter_4.setObjectName(_fromUtf8("verticalSplitter_4")) - self.verticalSplitter_4.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitter_2 = QtGui.QSplitter() - self.horizontalSplitter_2.setObjectName(_fromUtf8("horizontalSplitter_2")) - self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions) - self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions")) - self.horizontalSplitter_2.addWidget(self.inboxSearchLineEditSubscriptions) - self.inboxSearchOptionSubscriptions = QtGui.QComboBox(self.subscriptions) - self.inboxSearchOptionSubscriptions.setObjectName(_fromUtf8("inboxSearchOptionSubscriptions")) - self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.inboxSearchOptionSubscriptions.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) - self.horizontalSplitter_2.addWidget(self.inboxSearchOptionSubscriptions) - self.horizontalSplitter_2.handle(1).setEnabled(False) - self.horizontalSplitter_2.setStretchFactor(0, 1) - self.horizontalSplitter_2.setStretchFactor(1, 0) - self.verticalSplitter_4.addWidget(self.horizontalSplitter_2) - self.tableWidgetInboxSubscriptions = settingsmixin.STableWidget(self.subscriptions) - self.tableWidgetInboxSubscriptions.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.tableWidgetInboxSubscriptions.setAlternatingRowColors(True) - self.tableWidgetInboxSubscriptions.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) - self.tableWidgetInboxSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableWidgetInboxSubscriptions.setWordWrap(False) - self.tableWidgetInboxSubscriptions.setObjectName(_fromUtf8("tableWidgetInboxSubscriptions")) - self.tableWidgetInboxSubscriptions.setColumnCount(4) - self.tableWidgetInboxSubscriptions.setRowCount(0) + self.gridLayout_4.addWidget(self.pushButtonAddSubscription, 1, 0, 1, 1) + spacerItem2 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_4.addItem(spacerItem2, 1, 1, 1, 1) + self.tableWidgetSubscriptions = QtGui.QTableWidget(self.subscriptions) + self.tableWidgetSubscriptions.setAlternatingRowColors(True) + self.tableWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) + self.tableWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetSubscriptions.setObjectName(_fromUtf8("tableWidgetSubscriptions")) + self.tableWidgetSubscriptions.setColumnCount(2) + self.tableWidgetSubscriptions.setRowCount(0) item = QtGui.QTableWidgetItem() - self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(0, item) + self.tableWidgetSubscriptions.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() - self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(1, item) + self.tableWidgetSubscriptions.setHorizontalHeaderItem(1, item) + self.tableWidgetSubscriptions.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetSubscriptions.horizontalHeader().setDefaultSectionSize(400) + self.tableWidgetSubscriptions.horizontalHeader().setHighlightSections(False) + self.tableWidgetSubscriptions.horizontalHeader().setSortIndicatorShown(False) + self.tableWidgetSubscriptions.horizontalHeader().setStretchLastSection(True) + self.tableWidgetSubscriptions.verticalHeader().setVisible(False) + self.gridLayout_4.addWidget(self.tableWidgetSubscriptions, 2, 0, 1, 2) + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.subscriptions, icon5, _fromUtf8("")) + self.addressbook = QtGui.QWidget() + self.addressbook.setObjectName(_fromUtf8("addressbook")) + self.gridLayout_5 = QtGui.QGridLayout(self.addressbook) + self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) + self.label_6 = QtGui.QLabel(self.addressbook) + self.label_6.setWordWrap(True) + self.label_6.setObjectName(_fromUtf8("label_6")) + self.gridLayout_5.addWidget(self.label_6, 0, 0, 1, 2) + self.pushButtonAddAddressBook = QtGui.QPushButton(self.addressbook) + self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) + self.gridLayout_5.addWidget(self.pushButtonAddAddressBook, 1, 0, 1, 1) + spacerItem3 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_5.addItem(spacerItem3, 1, 1, 1, 1) + self.tableWidgetAddressBook = QtGui.QTableWidget(self.addressbook) + self.tableWidgetAddressBook.setAlternatingRowColors(True) + self.tableWidgetAddressBook.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + self.tableWidgetAddressBook.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetAddressBook.setObjectName(_fromUtf8("tableWidgetAddressBook")) + self.tableWidgetAddressBook.setColumnCount(2) + self.tableWidgetAddressBook.setRowCount(0) item = QtGui.QTableWidgetItem() - self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(2, item) + self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() - self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(3, item) - self.tableWidgetInboxSubscriptions.horizontalHeader().setCascadingSectionResizes(True) - self.tableWidgetInboxSubscriptions.horizontalHeader().setDefaultSectionSize(200) - self.tableWidgetInboxSubscriptions.horizontalHeader().setHighlightSections(False) - self.tableWidgetInboxSubscriptions.horizontalHeader().setMinimumSectionSize(27) - self.tableWidgetInboxSubscriptions.horizontalHeader().setSortIndicatorShown(False) - self.tableWidgetInboxSubscriptions.horizontalHeader().setStretchLastSection(True) - self.tableWidgetInboxSubscriptions.verticalHeader().setVisible(False) - self.tableWidgetInboxSubscriptions.verticalHeader().setDefaultSectionSize(26) - self.verticalSplitter_4.addWidget(self.tableWidgetInboxSubscriptions) - self.textEditInboxMessageSubscriptions = MessageView(self.subscriptions) - self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500)) - self.textEditInboxMessageSubscriptions.setReadOnly(True) - self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions")) - self.verticalSplitter_4.addWidget(self.textEditInboxMessageSubscriptions) - self.verticalSplitter_4.setStretchFactor(0, 0) - self.verticalSplitter_4.setStretchFactor(1, 1) - self.verticalSplitter_4.setStretchFactor(2, 2) - self.verticalSplitter_4.setCollapsible(0, False) - self.verticalSplitter_4.setCollapsible(1, False) - self.verticalSplitter_4.setCollapsible(2, False) - self.verticalSplitter_4.handle(1).setEnabled(False) - self.horizontalSplitter_4.addWidget(self.verticalSplitter_4) - self.horizontalSplitter_4.setStretchFactor(0, 0) - self.horizontalSplitter_4.setStretchFactor(1, 1) - self.horizontalSplitter_4.setCollapsible(0, False) - self.horizontalSplitter_4.setCollapsible(1, False) - self.gridLayout_3.addWidget(self.horizontalSplitter_4, 0, 0, 1, 1) + self.tableWidgetAddressBook.setHorizontalHeaderItem(1, item) + self.tableWidgetAddressBook.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetAddressBook.horizontalHeader().setDefaultSectionSize(400) + self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False) + self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True) + self.tableWidgetAddressBook.verticalHeader().setVisible(False) + self.gridLayout_5.addWidget(self.tableWidgetAddressBook, 2, 0, 1, 2) icon6 = QtGui.QIcon() - icon6.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.subscriptions, icon6, _fromUtf8("")) - self.chans = QtGui.QWidget() - self.chans.setObjectName(_fromUtf8("chans")) - self.gridLayout_4 = QtGui.QGridLayout(self.chans) - self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) - self.horizontalSplitter_7 = settingsmixin.SSplitter() - self.horizontalSplitter_7.setObjectName(_fromUtf8("horizontalSplitter_7")) - self.verticalSplitter_17 = settingsmixin.SSplitter() - self.verticalSplitter_17.setObjectName(_fromUtf8("verticalSplitter_17")) - self.verticalSplitter_17.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetChans = settingsmixin.STreeWidget(self.chans) - self.treeWidgetChans.setFrameShadow(QtGui.QFrame.Sunken) - self.treeWidgetChans.setLineWidth(1) - self.treeWidgetChans.setAlternatingRowColors(True) - self.treeWidgetChans.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) - self.treeWidgetChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.treeWidgetChans.setObjectName(_fromUtf8("treeWidgetChans")) - self.treeWidgetChans.resize(200, self.treeWidgetChans.height()) + icon6.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/addressbook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.addressbook, icon6, _fromUtf8("")) + self.blackwhitelist = QtGui.QWidget() + self.blackwhitelist.setObjectName(_fromUtf8("blackwhitelist")) + self.gridLayout_6 = QtGui.QGridLayout(self.blackwhitelist) + self.gridLayout_6.setObjectName(_fromUtf8("gridLayout_6")) + self.radioButtonBlacklist = QtGui.QRadioButton(self.blackwhitelist) + self.radioButtonBlacklist.setChecked(True) + self.radioButtonBlacklist.setObjectName(_fromUtf8("radioButtonBlacklist")) + self.gridLayout_6.addWidget(self.radioButtonBlacklist, 0, 0, 1, 2) + self.radioButtonWhitelist = QtGui.QRadioButton(self.blackwhitelist) + self.radioButtonWhitelist.setObjectName(_fromUtf8("radioButtonWhitelist")) + self.gridLayout_6.addWidget(self.radioButtonWhitelist, 1, 0, 1, 2) + self.pushButtonAddBlacklist = QtGui.QPushButton(self.blackwhitelist) + self.pushButtonAddBlacklist.setObjectName(_fromUtf8("pushButtonAddBlacklist")) + self.gridLayout_6.addWidget(self.pushButtonAddBlacklist, 2, 0, 1, 1) + spacerItem4 = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_6.addItem(spacerItem4, 2, 1, 1, 1) + self.tableWidgetBlacklist = QtGui.QTableWidget(self.blackwhitelist) + self.tableWidgetBlacklist.setAlternatingRowColors(True) + self.tableWidgetBlacklist.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) + self.tableWidgetBlacklist.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetBlacklist.setObjectName(_fromUtf8("tableWidgetBlacklist")) + self.tableWidgetBlacklist.setColumnCount(2) + self.tableWidgetBlacklist.setRowCount(0) + item = QtGui.QTableWidgetItem() + self.tableWidgetBlacklist.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetBlacklist.setHorizontalHeaderItem(1, item) + self.tableWidgetBlacklist.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetBlacklist.horizontalHeader().setDefaultSectionSize(400) + self.tableWidgetBlacklist.horizontalHeader().setHighlightSections(False) + self.tableWidgetBlacklist.horizontalHeader().setSortIndicatorShown(False) + self.tableWidgetBlacklist.horizontalHeader().setStretchLastSection(True) + self.tableWidgetBlacklist.verticalHeader().setVisible(False) + self.gridLayout_6.addWidget(self.tableWidgetBlacklist, 3, 0, 1, 2) icon7 = QtGui.QIcon() - icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - self.treeWidgetChans.headerItem().setIcon(0, icon7) - self.verticalSplitter_17.addWidget(self.treeWidgetChans) - self.pushButtonAddChan = QtGui.QPushButton(self.chans) - self.pushButtonAddChan.setObjectName(_fromUtf8("pushButtonAddChan")) - self.pushButtonAddChan.resize(200, self.pushButtonAddChan.height()) - self.verticalSplitter_17.addWidget(self.pushButtonAddChan) - self.verticalSplitter_17.setStretchFactor(0, 1) - self.verticalSplitter_17.setStretchFactor(1, 0) - self.verticalSplitter_17.setCollapsible(0, False) - self.verticalSplitter_17.setCollapsible(1, False) - self.verticalSplitter_17.handle(1).setEnabled(False) - self.horizontalSplitter_7.addWidget(self.verticalSplitter_17) - self.verticalSplitter_8 = settingsmixin.SSplitter() - self.verticalSplitter_8.setObjectName(_fromUtf8("verticalSplitter_8")) - self.verticalSplitter_8.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitter_6 = QtGui.QSplitter() - self.horizontalSplitter_6.setObjectName(_fromUtf8("horizontalSplitter_6")) - self.inboxSearchLineEditChans = QtGui.QLineEdit(self.chans) - self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans")) - self.horizontalSplitter_6.addWidget(self.inboxSearchLineEditChans) - self.inboxSearchOptionChans = QtGui.QComboBox(self.chans) - self.inboxSearchOptionChans.setObjectName(_fromUtf8("inboxSearchOptionChans")) - self.inboxSearchOptionChans.addItem(_fromUtf8("")) - self.inboxSearchOptionChans.addItem(_fromUtf8("")) - self.inboxSearchOptionChans.addItem(_fromUtf8("")) - self.inboxSearchOptionChans.addItem(_fromUtf8("")) - self.inboxSearchOptionChans.addItem(_fromUtf8("")) - self.inboxSearchOptionChans.setSizeAdjustPolicy(QtGui.QComboBox.AdjustToContents) - self.horizontalSplitter_6.addWidget(self.inboxSearchOptionChans) - self.horizontalSplitter_6.handle(1).setEnabled(False) - self.horizontalSplitter_6.setStretchFactor(0, 1) - self.horizontalSplitter_6.setStretchFactor(1, 0) - self.verticalSplitter_8.addWidget(self.horizontalSplitter_6) - self.tableWidgetInboxChans = settingsmixin.STableWidget(self.chans) - self.tableWidgetInboxChans.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.tableWidgetInboxChans.setAlternatingRowColors(True) - self.tableWidgetInboxChans.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) - self.tableWidgetInboxChans.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableWidgetInboxChans.setWordWrap(False) - self.tableWidgetInboxChans.setObjectName(_fromUtf8("tableWidgetInboxChans")) - self.tableWidgetInboxChans.setColumnCount(4) - self.tableWidgetInboxChans.setRowCount(0) - item = QtGui.QTableWidgetItem() - self.tableWidgetInboxChans.setHorizontalHeaderItem(0, item) - item = QtGui.QTableWidgetItem() - self.tableWidgetInboxChans.setHorizontalHeaderItem(1, item) - item = QtGui.QTableWidgetItem() - self.tableWidgetInboxChans.setHorizontalHeaderItem(2, item) - item = QtGui.QTableWidgetItem() - self.tableWidgetInboxChans.setHorizontalHeaderItem(3, item) - self.tableWidgetInboxChans.horizontalHeader().setCascadingSectionResizes(True) - self.tableWidgetInboxChans.horizontalHeader().setDefaultSectionSize(200) - self.tableWidgetInboxChans.horizontalHeader().setHighlightSections(False) - self.tableWidgetInboxChans.horizontalHeader().setMinimumSectionSize(27) - self.tableWidgetInboxChans.horizontalHeader().setSortIndicatorShown(False) - self.tableWidgetInboxChans.horizontalHeader().setStretchLastSection(True) - self.tableWidgetInboxChans.verticalHeader().setVisible(False) - self.tableWidgetInboxChans.verticalHeader().setDefaultSectionSize(26) - self.verticalSplitter_8.addWidget(self.tableWidgetInboxChans) - self.textEditInboxMessageChans = MessageView(self.chans) - self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500)) - self.textEditInboxMessageChans.setReadOnly(True) - self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans")) - self.verticalSplitter_8.addWidget(self.textEditInboxMessageChans) - self.verticalSplitter_8.setStretchFactor(0, 0) - self.verticalSplitter_8.setStretchFactor(1, 1) - self.verticalSplitter_8.setStretchFactor(2, 2) - self.verticalSplitter_8.setCollapsible(0, False) - self.verticalSplitter_8.setCollapsible(1, False) - self.verticalSplitter_8.setCollapsible(2, False) - self.verticalSplitter_8.handle(1).setEnabled(False) - self.horizontalSplitter_7.addWidget(self.verticalSplitter_8) - self.horizontalSplitter_7.setStretchFactor(0, 0) - self.horizontalSplitter_7.setStretchFactor(1, 1) - self.horizontalSplitter_7.setCollapsible(0, False) - self.horizontalSplitter_7.setCollapsible(1, False) - self.gridLayout_4.addWidget(self.horizontalSplitter_7, 0, 0, 1, 1) + icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.blackwhitelist, icon7, _fromUtf8("")) + self.networkstatus = QtGui.QWidget() + self.networkstatus.setObjectName(_fromUtf8("networkstatus")) + self.pushButtonStatusIcon = QtGui.QPushButton(self.networkstatus) + self.pushButtonStatusIcon.setGeometry(QtCore.QRect(680, 440, 21, 23)) + self.pushButtonStatusIcon.setText(_fromUtf8("")) icon8 = QtGui.QIcon() - icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.chans, icon8, _fromUtf8("")) - self.blackwhitelist = Blacklist() - self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "") - # Initialize the Blacklist or Whitelist - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': - self.blackwhitelist.radioButtonWhitelist.click() - self.blackwhitelist.rerenderBlackWhiteList() - - self.networkstatus = NetworkStatus() - self.tabWidget.addTab(self.networkstatus, QtGui.QIcon(":/newPrefix/images/networkstatus.png"), "") - self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1) + icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pushButtonStatusIcon.setIcon(icon8) + self.pushButtonStatusIcon.setFlat(True) + self.pushButtonStatusIcon.setObjectName(_fromUtf8("pushButtonStatusIcon")) + self.tableWidgetConnectionCount = QtGui.QTableWidget(self.networkstatus) + self.tableWidgetConnectionCount.setGeometry(QtCore.QRect(20, 70, 241, 241)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(212, 208, 200)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(212, 208, 200)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(212, 208, 200)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.Base, brush) + self.tableWidgetConnectionCount.setPalette(palette) + self.tableWidgetConnectionCount.setFrameShape(QtGui.QFrame.Box) + self.tableWidgetConnectionCount.setFrameShadow(QtGui.QFrame.Plain) + self.tableWidgetConnectionCount.setProperty("showDropIndicator", False) + self.tableWidgetConnectionCount.setAlternatingRowColors(True) + self.tableWidgetConnectionCount.setSelectionMode(QtGui.QAbstractItemView.NoSelection) + self.tableWidgetConnectionCount.setObjectName(_fromUtf8("tableWidgetConnectionCount")) + self.tableWidgetConnectionCount.setColumnCount(2) + self.tableWidgetConnectionCount.setRowCount(0) + item = QtGui.QTableWidgetItem() + self.tableWidgetConnectionCount.setHorizontalHeaderItem(0, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetConnectionCount.setHorizontalHeaderItem(1, item) + self.tableWidgetConnectionCount.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetConnectionCount.horizontalHeader().setHighlightSections(False) + self.tableWidgetConnectionCount.horizontalHeader().setStretchLastSection(True) + self.tableWidgetConnectionCount.verticalHeader().setVisible(False) + self.labelTotalConnections = QtGui.QLabel(self.networkstatus) + self.labelTotalConnections.setGeometry(QtCore.QRect(20, 30, 401, 16)) + self.labelTotalConnections.setObjectName(_fromUtf8("labelTotalConnections")) + self.labelStartupTime = QtGui.QLabel(self.networkstatus) + self.labelStartupTime.setGeometry(QtCore.QRect(320, 110, 331, 20)) + self.labelStartupTime.setObjectName(_fromUtf8("labelStartupTime")) + self.labelMessageCount = QtGui.QLabel(self.networkstatus) + self.labelMessageCount.setGeometry(QtCore.QRect(350, 130, 361, 16)) + self.labelMessageCount.setObjectName(_fromUtf8("labelMessageCount")) + self.labelPubkeyCount = QtGui.QLabel(self.networkstatus) + self.labelPubkeyCount.setGeometry(QtCore.QRect(350, 170, 331, 16)) + self.labelPubkeyCount.setObjectName(_fromUtf8("labelPubkeyCount")) + self.labelBroadcastCount = QtGui.QLabel(self.networkstatus) + self.labelBroadcastCount.setGeometry(QtCore.QRect(350, 150, 351, 16)) + self.labelBroadcastCount.setObjectName(_fromUtf8("labelBroadcastCount")) + self.labelLookupsPerSecond = QtGui.QLabel(self.networkstatus) + self.labelLookupsPerSecond.setGeometry(QtCore.QRect(320, 250, 291, 16)) + self.labelLookupsPerSecond.setObjectName(_fromUtf8("labelLookupsPerSecond")) + self.labelBytesRecvCount = QtGui.QLabel(self.networkstatus) + self.labelBytesRecvCount.setGeometry(QtCore.QRect(350, 210, 251, 16)) + self.labelBytesRecvCount.setObjectName(_fromUtf8("labelBytesRecvCount")) + self.labelBytesSentCount = QtGui.QLabel(self.networkstatus) + self.labelBytesSentCount.setGeometry(QtCore.QRect(350, 230, 251, 16)) + self.labelBytesSentCount.setObjectName(_fromUtf8("labelBytesSentCount")) + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.networkstatus, icon9, _fromUtf8("")) + self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 885, 27)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 885, 21)) self.menubar.setObjectName(_fromUtf8("menubar")) self.menuFile = QtGui.QMenu(self.menubar) self.menuFile.setObjectName(_fromUtf8("menuFile")) @@ -589,8 +506,6 @@ class Ui_MainWindow(object): icon = QtGui.QIcon.fromTheme(_fromUtf8("dialog-password")) self.actionManageKeys.setIcon(icon) self.actionManageKeys.setObjectName(_fromUtf8("actionManageKeys")) - self.actionNetworkSwitch = QtGui.QAction(MainWindow) - self.actionNetworkSwitch.setObjectName(_fromUtf8("actionNetworkSwitch")) self.actionExit = QtGui.QAction(MainWindow) icon = QtGui.QIcon.fromTheme(_fromUtf8("application-exit")) self.actionExit.setIcon(icon) @@ -599,10 +514,6 @@ class Ui_MainWindow(object): icon = QtGui.QIcon.fromTheme(_fromUtf8("help-contents")) self.actionHelp.setIcon(icon) self.actionHelp.setObjectName(_fromUtf8("actionHelp")) - self.actionSupport = QtGui.QAction(MainWindow) - icon = QtGui.QIcon.fromTheme(_fromUtf8("help-support")) - self.actionSupport.setIcon(icon) - self.actionSupport.setObjectName(_fromUtf8("actionSupport")) self.actionAbout = QtGui.QAction(MainWindow) icon = QtGui.QIcon.fromTheme(_fromUtf8("help-about")) self.actionAbout.setIcon(icon) @@ -626,51 +537,54 @@ class Ui_MainWindow(object): self.menuFile.addAction(self.actionManageKeys) self.menuFile.addAction(self.actionDeleteAllTrashedMessages) self.menuFile.addAction(self.actionRegenerateDeterministicAddresses) - self.menuFile.addAction(self.actionNetworkSwitch) + self.menuFile.addAction(self.actionJoinChan) self.menuFile.addAction(self.actionExit) self.menuSettings.addAction(self.actionSettings) self.menuHelp.addAction(self.actionHelp) - self.menuHelp.addAction(self.actionSupport) self.menuHelp.addAction(self.actionAbout) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuSettings.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex( - self.tabWidget.indexOf(self.inbox) - ) - self.tabWidgetSend.setCurrentIndex( - self.tabWidgetSend.indexOf(self.sendDirect) - ) + self.tabWidget.setCurrentIndex(0) + QtCore.QObject.connect(self.radioButtonSpecific, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.lineEditTo.setEnabled) + QtCore.QObject.connect(self.radioButtonSpecific, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.labelSendBroadcastWarning.hide) + QtCore.QObject.connect(self.radioButtonBroadcast, QtCore.SIGNAL(_fromUtf8("clicked()")), self.labelSendBroadcastWarning.show) QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.tabWidget, self.tableWidgetInbox) MainWindow.setTabOrder(self.tableWidgetInbox, self.textEditInboxMessage) - MainWindow.setTabOrder(self.textEditInboxMessage, self.comboBoxSendFrom) + MainWindow.setTabOrder(self.textEditInboxMessage, self.radioButtonSpecific) + MainWindow.setTabOrder(self.radioButtonSpecific, self.radioButtonBroadcast) + MainWindow.setTabOrder(self.radioButtonBroadcast, self.comboBoxSendFrom) MainWindow.setTabOrder(self.comboBoxSendFrom, self.lineEditTo) - MainWindow.setTabOrder(self.lineEditTo, self.lineEditSubject) + MainWindow.setTabOrder(self.lineEditTo, self.pushButtonLoadFromAddressBook) + MainWindow.setTabOrder(self.pushButtonLoadFromAddressBook, self.lineEditSubject) MainWindow.setTabOrder(self.lineEditSubject, self.textEditMessage) - MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription) - - def updateNetworkSwitchMenuLabel(self, dontconnect=None): - if dontconnect is None: - dontconnect = BMConfigParser().safeGetBoolean( - 'bitmessagesettings', 'dontconnect') - self.actionNetworkSwitch.setText( - _translate("MainWindow", "Go online", None) - if dontconnect else - _translate("MainWindow", "Go offline", None) - ) + MainWindow.setTabOrder(self.textEditMessage, self.pushButtonSend) + MainWindow.setTabOrder(self.pushButtonSend, self.tableWidgetSent) + MainWindow.setTabOrder(self.tableWidgetSent, self.textEditSentMessage) + MainWindow.setTabOrder(self.textEditSentMessage, self.pushButtonNewAddress) + MainWindow.setTabOrder(self.pushButtonNewAddress, self.tableWidgetYourIdentities) + MainWindow.setTabOrder(self.tableWidgetYourIdentities, self.pushButtonAddSubscription) + MainWindow.setTabOrder(self.pushButtonAddSubscription, self.tableWidgetSubscriptions) + MainWindow.setTabOrder(self.tableWidgetSubscriptions, self.pushButtonAddAddressBook) + MainWindow.setTabOrder(self.pushButtonAddAddressBook, self.tableWidgetAddressBook) + MainWindow.setTabOrder(self.tableWidgetAddressBook, self.radioButtonBlacklist) + MainWindow.setTabOrder(self.radioButtonBlacklist, self.radioButtonWhitelist) + MainWindow.setTabOrder(self.radioButtonWhitelist, self.pushButtonAddBlacklist) + MainWindow.setTabOrder(self.pushButtonAddBlacklist, self.tableWidgetBlacklist) + MainWindow.setTabOrder(self.tableWidgetBlacklist, self.tableWidgetConnectionCount) + MainWindow.setTabOrder(self.tableWidgetConnectionCount, self.pushButtonStatusIcon) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) - self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) - self.pushButtonNewAddress.setText(_translate("MainWindow", "New Identity", None)) self.inboxSearchLineEdit.setPlaceholderText(_translate("MainWindow", "Search", None)) - self.inboxSearchOption.setItemText(0, _translate("MainWindow", "All", None)) - self.inboxSearchOption.setItemText(1, _translate("MainWindow", "To", None)) - self.inboxSearchOption.setItemText(2, _translate("MainWindow", "From", None)) - self.inboxSearchOption.setItemText(3, _translate("MainWindow", "Subject", None)) - self.inboxSearchOption.setItemText(4, _translate("MainWindow", "Message", None)) + self.inboxSearchOptionCB.setItemText(0, _translate("MainWindow", "All", None)) + self.inboxSearchOptionCB.setItemText(1, _translate("MainWindow", "To", None)) + self.inboxSearchOptionCB.setItemText(2, _translate("MainWindow", "From", None)) + self.inboxSearchOptionCB.setItemText(3, _translate("MainWindow", "Subject", None)) + self.inboxSearchOptionCB.setItemText(4, _translate("MainWindow", "Message", None)) self.tableWidgetInbox.setSortingEnabled(True) item = self.tableWidgetInbox.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "To", None)) @@ -680,73 +594,88 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Subject", None)) item = self.tableWidgetInbox.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Messages", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Inbox", None)) + self.pushButtonLoadFromAddressBook.setText(_translate("MainWindow", "Load from Address book", None)) + self.label_3.setText(_translate("MainWindow", "Subject:", None)) + self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) + self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "X days", None)) + self.label_4.setText(_translate("MainWindow", "Message:", None)) + self.label.setText(_translate("MainWindow", "To:", None)) + self.radioButtonSpecific.setText(_translate("MainWindow", "Send to one or more specific people", None)) + self.labelSendBroadcastWarning.setText(_translate("MainWindow", "Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them.", None)) + self.radioButtonBroadcast.setText(_translate("MainWindow", "Broadcast to everyone who is subscribed to your address", None)) + self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) + self.label_2.setText(_translate("MainWindow", "From:", None)) + self.textEditMessage.setHtml(_translate("MainWindow", "\n" +"\n" +"


", None)) + self.pushButtonFetchNamecoinID.setText(_translate("MainWindow", "Fetch Namecoin ID", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) + self.sentSearchLineEdit.setPlaceholderText(_translate("MainWindow", "Search", None)) + self.sentSearchOptionCB.setItemText(0, _translate("MainWindow", "All", None)) + self.sentSearchOptionCB.setItemText(1, _translate("MainWindow", "To", None)) + self.sentSearchOptionCB.setItemText(2, _translate("MainWindow", "From", None)) + self.sentSearchOptionCB.setItemText(3, _translate("MainWindow", "Subject", None)) + self.sentSearchOptionCB.setItemText(4, _translate("MainWindow", "Message", None)) + self.tableWidgetSent.setSortingEnabled(True) + item = self.tableWidgetSent.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "To", None)) + item = self.tableWidgetSent.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "From", None)) + item = self.tableWidgetSent.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Subject", None)) + item = self.tableWidgetSent.horizontalHeaderItem(3) + item.setText(_translate("MainWindow", "Status", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.sent), _translate("MainWindow", "Sent", None)) + self.pushButtonNewAddress.setText(_translate("MainWindow", "New", None)) + self.tableWidgetYourIdentities.setSortingEnabled(True) + item = self.tableWidgetYourIdentities.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Label (not shown to anyone)", None)) + item = self.tableWidgetYourIdentities.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Address", None)) + item = self.tableWidgetYourIdentities.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Stream", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.youridentities), _translate("MainWindow", "Your Identities", None)) + self.label_5.setText(_translate("MainWindow", "Here you can subscribe to \'broadcast messages\' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab.", None)) + self.pushButtonAddSubscription.setText(_translate("MainWindow", "Add new Subscription", None)) + self.tableWidgetSubscriptions.setSortingEnabled(True) + item = self.tableWidgetSubscriptions.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Label", None)) + item = self.tableWidgetSubscriptions.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Address", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) + self.label_6.setText(_translate("MainWindow", "The Address book is useful for adding names or labels to other people\'s Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the \'Add\' button, or from your inbox by right-clicking on a message.", None)) + self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add new entry", None)) self.tableWidgetAddressBook.setSortingEnabled(True) item = self.tableWidgetAddressBook.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Address book", None)) + item.setText(_translate("MainWindow", "Name or Label", None)) item = self.tableWidgetAddressBook.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "Address", None)) - self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add Contact", None)) - self.pushButtonFetchNamecoinID.setText(_translate("MainWindow", "Fetch Namecoin ID", None)) - self.label_3.setText(_translate("MainWindow", "Subject:", None)) - self.label_2.setText(_translate("MainWindow", "From:", None)) - self.label.setText(_translate("MainWindow", "To:", None)) - #self.textEditMessage.setHtml("") - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendDirect), _translate("MainWindow", "Send ordinary Message", None)) - self.label_8.setText(_translate("MainWindow", "From:", None)) - self.label_7.setText(_translate("MainWindow", "Subject:", None)) - #self.textEditMessageBroadcast.setHtml("") - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendBroadcast), _translate("MainWindow", "Send Message to your Subscribers", None)) - self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) - hours = 48 - try: - hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl')/60/60) - except: - pass - self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours)) - self.pushButtonClear.setText(_translate("MainWindow", "Clear", None)) - self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) - self.treeWidgetSubscriptions.headerItem().setText(0, _translate("MainWindow", "Subscriptions", None)) - self.pushButtonAddSubscription.setText(_translate("MainWindow", "Add new Subscription", None)) - self.inboxSearchLineEditSubscriptions.setPlaceholderText(_translate("MainWindow", "Search", None)) - self.inboxSearchOptionSubscriptions.setItemText(0, _translate("MainWindow", "All", None)) - self.inboxSearchOptionSubscriptions.setItemText(1, _translate("MainWindow", "To", None)) - self.inboxSearchOptionSubscriptions.setItemText(2, _translate("MainWindow", "From", None)) - self.inboxSearchOptionSubscriptions.setItemText(3, _translate("MainWindow", "Subject", None)) - self.inboxSearchOptionSubscriptions.setItemText(4, _translate("MainWindow", "Message", None)) - self.tableWidgetInboxSubscriptions.setSortingEnabled(True) - item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "To", None)) - item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "From", None)) - item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Subject", None)) - item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3) - item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) - self.treeWidgetChans.headerItem().setText(0, _translate("MainWindow", "Chans", None)) - self.pushButtonAddChan.setText(_translate("MainWindow", "Add Chan", None)) - self.inboxSearchLineEditChans.setPlaceholderText(_translate("MainWindow", "Search", None)) - self.inboxSearchOptionChans.setItemText(0, _translate("MainWindow", "All", None)) - self.inboxSearchOptionChans.setItemText(1, _translate("MainWindow", "To", None)) - self.inboxSearchOptionChans.setItemText(2, _translate("MainWindow", "From", None)) - self.inboxSearchOptionChans.setItemText(3, _translate("MainWindow", "Subject", None)) - self.inboxSearchOptionChans.setItemText(4, _translate("MainWindow", "Message", None)) - self.tableWidgetInboxChans.setSortingEnabled(True) - item = self.tableWidgetInboxChans.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "To", None)) - item = self.tableWidgetInboxChans.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "From", None)) - item = self.tableWidgetInboxChans.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Subject", None)) - item = self.tableWidgetInboxChans.horizontalHeaderItem(3) - item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", None)) - self.blackwhitelist.retranslateUi() - self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), _translate("blacklist", "Blacklist", None)) - self.networkstatus.retranslateUi() - self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("networkstatus", "Network Status", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.addressbook), _translate("MainWindow", "Address Book", None)) + self.radioButtonBlacklist.setText(_translate("MainWindow", "Use a Blacklist (Allow all incoming messages except those on the Blacklist)", None)) + self.radioButtonWhitelist.setText(_translate("MainWindow", "Use a Whitelist (Block all incoming messages except those on the Whitelist)", None)) + self.pushButtonAddBlacklist.setText(_translate("MainWindow", "Add new entry", None)) + self.tableWidgetBlacklist.setSortingEnabled(True) + item = self.tableWidgetBlacklist.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Name or Label", None)) + item = self.tableWidgetBlacklist.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Address", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.blackwhitelist), _translate("MainWindow", "Blacklist", None)) + item = self.tableWidgetConnectionCount.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Stream #", None)) + item = self.tableWidgetConnectionCount.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Connections", None)) + self.labelTotalConnections.setText(_translate("MainWindow", "Total connections:", None)) + self.labelStartupTime.setText(_translate("MainWindow", "Since startup:", None)) + self.labelMessageCount.setText(_translate("MainWindow", "Processed 0 person-to-person messages.", None)) + self.labelPubkeyCount.setText(_translate("MainWindow", "Processed 0 public keys.", None)) + self.labelBroadcastCount.setText(_translate("MainWindow", "Processed 0 broadcasts.", None)) + self.labelLookupsPerSecond.setText(_translate("MainWindow", "Inventory lookups per second: 0", None)) + self.labelBytesRecvCount.setText(_translate("MainWindow", "Down: 0 KB/s", None)) + self.labelBytesSentCount.setText(_translate("MainWindow", "Up: 0 KB/s", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("MainWindow", "Network Status", None)) self.menuFile.setTitle(_translate("MainWindow", "File", None)) self.menuSettings.setTitle(_translate("MainWindow", "Settings", None)) self.menuHelp.setTitle(_translate("MainWindow", "Help", None)) @@ -756,7 +685,6 @@ class Ui_MainWindow(object): self.actionExit.setShortcut(_translate("MainWindow", "Ctrl+Q", None)) self.actionHelp.setText(_translate("MainWindow", "Help", None)) self.actionHelp.setShortcut(_translate("MainWindow", "F1", None)) - self.actionSupport.setText(_translate("MainWindow", "Contact support", None)) self.actionAbout.setText(_translate("MainWindow", "About", None)) self.actionSettings.setText(_translate("MainWindow", "Settings", None)) self.actionRegenerateDeterministicAddresses.setText(_translate("MainWindow", "Regenerate deterministic addresses", None)) @@ -764,14 +692,3 @@ class Ui_MainWindow(object): self.actionJoinChan.setText(_translate("MainWindow", "Join / Create chan", None)) import bitmessage_icons_rc - -if __name__ == "__main__": - import sys - - app = QtGui.QApplication(sys.argv) - MainWindow = settingsmixin.SMainWindow() - ui = Ui_MainWindow() - ui.setupUi(MainWindow) - MainWindow.show() - sys.exit(app.exec_()) - diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index fef40be6..e45cc22d 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -21,7 +21,10 @@ QTabWidget::Rounded - + + + 0 + @@ -62,176 +65,134 @@ :/newPrefix/images/inbox.png:/newPrefix/images/inbox.png - Messages + Inbox - - - + + + + + 0 + - - - - - - 200 - 16777215 - - - - - Identities - - - - :/newPrefix/images/identities.png - - - - - - - - - - 200 - 16777215 - - - - New Indentitiy - - - - + + + Search + + - + - - - 0 - - - - - Search - - - - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - + + All + - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - true - - - false - - - true - - - 200 - - - false - - - 27 - - - false - - - true - - - false - - - 26 - - - - To - - - - - From - - - - - Subject - - - - - Received - - - + + To + - - - - 0 - 500 - - - - true - - + + From + - + + + Subject + + + + + Message + + +
+ + + + Qt::Vertical + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + 200 + + + false + + + 27 + + + false + + + true + + + false + + + 26 + + + + To + + + + + From + + + + + Subject + + + + + Received + + + + + + + 0 + 500 + + + + true + + + + @@ -242,366 +203,498 @@ Send - - + + + + + + 7 + + + + Load from Address book + + + + + + + Subject: + + + + + + + Send + + + + + + + + 35 + 0 + + + + + 70 + 16777215 + + + + Qt::Horizontal + + + false + + + false + + + + + + + Qt::Vertical + + + + 20 + 297 + + + + + + + + + 300 + 0 + + + + + + + + + 0 + 0 + + + + + 45 + 0 + + + + + 45 + 16777215 + + + + X days + + + + + + + Message: + + + + + + + To: + + + + + + + Send to one or more specific people + + + true + + + + + + + true + + + + 0 + 0 + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + + + -1 + + + + + + + Broadcast to everyone who is subscribed to your address + + + + + + + + 0 + 0 + + + + + 32 + 16777215 + + + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + + + true + + + + TTL: + + + true + + + + + + + From: + + + + + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + + + + 7 + + + + Fetch Namecoin ID + + + + + + + + + + + + + + + + + + + + + + + :/newPrefix/images/sent.png:/newPrefix/images/sent.png + + + Sent + + + + + 0 + - - - - - - 200 - 16777215 - - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - true - - - true - - - 200 - - - false - - - true - - - false - - - - Address book - - - - :/newPrefix/images/addressbook.png - - - - - - Address - - - - - - - - - 200 - 16777215 - - - - Add Contact - - - - - - - - 200 - 16777215 - - - - - 9 - - - - Fetch Namecoin ID - - - - + + + Search + + - + - - - 0 - - - - Send ordinary Message - - - - - - - - - - Subject: - - - - - - - From: - - - - - - - - - - - - - - To: - - - - - - - - 300 - 0 - - - - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> - - - - - - - - - - Send Message to your Subscribers - - - - - - - - - - From: - - - - - - - - - - - - - - Subject: - - - - - - - - 300 - 0 - - - - - - - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Droid Sans'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> - - - - - - - - + + All + - - - - - - 0 - 0 - - - - - 32 - 16777215 - - - - - - - - - 0 - 0 - 255 - - - - - - - - - 0 - 0 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - - - true - - - - TTL: - - - true - - - - - - - - 35 - 0 - - - - - 70 - 16777215 - - - - Qt::Horizontal - - - false - - - false - - - - - - - - 0 - 0 - - - - - 45 - 0 - - - - - 45 - 16777215 - - - - X days - - - - - - - - 16777215 - 16777215 - - - - Send - - - - + + To + - + + + From + + + + + Subject + + + + + Message + + + + + + + Qt::Vertical + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::DragDrop + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + 130 + + + false + + + false + + + true + + + false + + + false + + + + To + + + + + From + + + + + Subject + + + + + Status + + + + + + true + + + + + + + + + + :/newPrefix/images/identities.png:/newPrefix/images/identities.png + + + Your Identities + + + + + + New + + + + + + + Qt::Horizontal + + + + 689 + 20 + + + + + + + + QFrame::Sunken + + + 1 + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 346 + + + 52 + + + true + + + true + + + false + + + 26 + + + false + + + false + + + + Label (not shown to anyone) + + + + true + + + + + + Address + + + + + Stream + + + + - @@ -611,369 +704,162 @@ p, li { white-space: pre-wrap; } Subscriptions - - - - - - - - - - 200 - 16777215 - - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - - Subscriptions - - - - :/newPrefix/images/subscriptions.png - - - - - - - - - - 200 - 16777215 - - - - Add new Subscription - - - - - - - - - - - - - Search - - - - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - true - - - false - - - true - - - 200 - - - false - - - 27 - - - false - - - true - - - false - - - 26 - - - - To - - - - - From - - - - - Subject - - - - - Received - - - - - - - - - 0 - 500 - - - - true - - - - - - + + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + + + true + + + + + + + Add new Subscription + + + + + + + Qt::Horizontal + + + + 689 + 20 + + + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 400 + + + false + + + false + + + true + + + false + + + + Label + + + + + Address + + + - + - :/newPrefix/images/can-icon-16px.png:/newPrefix/images/can-icon-16px.png + :/newPrefix/images/addressbook.png:/newPrefix/images/addressbook.png - Chans + Address Book - - - - - - - - - - 200 - 16777215 - - - - QFrame::Sunken - - - 1 - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - - Chans - - - - :/newPrefix/images/can-icon-16px.png - - - - - - - - - - 200 - 16777215 - - - - Add Chan - - - - - - - - - - - - - Search - - - - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - - - - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectRows - - - true - - - false - - - true - - - 200 - - - false - - - 27 - - - false - - - true - - - false - - - 26 - - - - To - - - - - From - - - - - Subject - - - - - Received - - - - - - - - - 0 - 500 - - - - true - - - - - - + + + + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + + + true + + + + + + + Add new entry + + + + + + + Qt::Horizontal + + + + 689 + 20 + + + + + + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 400 + + + false + + + true + + + false + + + + Name or Label + + + + + Address + + + @@ -1296,7 +1182,7 @@ p, li { white-space: pre-wrap; } 0 0 885 - 27 + 21 @@ -1306,6 +1192,7 @@ p, li { white-space: pre-wrap; } + @@ -1432,14 +1319,25 @@ p, li { white-space: pre-wrap; } + tabWidget tableWidgetInbox textEditInboxMessage + radioButtonSpecific + radioButtonBroadcast comboBoxSendFrom lineEditTo + pushButtonLoadFromAddressBook lineEditSubject textEditMessage pushButtonSend + tableWidgetSent + textEditSentMessage + pushButtonNewAddress + tableWidgetYourIdentities pushButtonAddSubscription + tableWidgetSubscriptions + pushButtonAddAddressBook + tableWidgetAddressBook radioButtonBlacklist radioButtonWhitelist pushButtonAddBlacklist @@ -1450,5 +1348,54 @@ p, li { white-space: pre-wrap; } - + + + radioButtonSpecific + toggled(bool) + lineEditTo + setEnabled(bool) + + + 121 + 60 + + + 175 + 147 + + + + + radioButtonSpecific + clicked(bool) + labelSendBroadcastWarning + hide() + + + 95 + 59 + + + 129 + 528 + + + + + radioButtonBroadcast + clicked() + labelSendBroadcastWarning + show() + + + 108 + 84 + + + 177 + 519 + + + + diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py deleted file mode 100644 index e07f9469..00000000 --- a/src/bitmessageqt/blacklist.py +++ /dev/null @@ -1,241 +0,0 @@ -from PyQt4 import QtCore, QtGui -from tr import _translate -import l10n -import widgets -from addresses import addBMIfNotPresent -from bmconfigparser import BMConfigParser -from dialogs import AddAddressDialog -from helper_sql import sqlExecute, sqlQuery -from retranslateui import RetranslateMixin -from utils import avatarize -from uisignaler import UISignaler - - -class Blacklist(QtGui.QWidget, RetranslateMixin): - def __init__(self, parent=None): - super(Blacklist, self).__init__(parent) - widgets.load('blacklist.ui', self) - - QtCore.QObject.connect(self.radioButtonBlacklist, QtCore.SIGNAL( - "clicked()"), self.click_radioButtonBlacklist) - QtCore.QObject.connect(self.radioButtonWhitelist, QtCore.SIGNAL( - "clicked()"), self.click_radioButtonWhitelist) - QtCore.QObject.connect(self.pushButtonAddBlacklist, QtCore.SIGNAL( - "clicked()"), self.click_pushButtonAddBlacklist) - - self.init_blacklist_popup_menu() - - # Initialize blacklist - QtCore.QObject.connect(self.tableWidgetBlacklist, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged) - - # Set the icon sizes for the identicons - identicon_size = 3*7 - self.tableWidgetBlacklist.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - - self.UISignalThread = UISignaler.get() - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) - - def click_radioButtonBlacklist(self): - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': - BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') - BMConfigParser().save() - # self.tableWidgetBlacklist.clearContents() - self.tableWidgetBlacklist.setRowCount(0) - self.rerenderBlackWhiteList() - - def click_radioButtonWhitelist(self): - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'white') - BMConfigParser().save() - # self.tableWidgetBlacklist.clearContents() - self.tableWidgetBlacklist.setRowCount(0) - self.rerenderBlackWhiteList() - - def click_pushButtonAddBlacklist(self): - self.NewBlacklistDialogInstance = AddAddressDialog(self) - if self.NewBlacklistDialogInstance.exec_(): - if self.NewBlacklistDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): - address = addBMIfNotPresent(str( - self.NewBlacklistDialogInstance.ui.lineEditAddress.text())) - # First we must check to see if the address is already in the - # address book. The user cannot add it again or else it will - # cause problems when updating and deleting the entry. - t = (address,) - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - sql = '''select * from blacklist where address=?''' - else: - sql = '''select * from whitelist where address=?''' - queryreturn = sqlQuery(sql,*t) - if queryreturn == []: - self.tableWidgetBlacklist.setSortingEnabled(False) - self.tableWidgetBlacklist.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode( - self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8(), 'utf-8')) - newItem.setIcon(avatarize(address)) - self.tableWidgetBlacklist.setItem(0, 0, newItem) - newItem = QtGui.QTableWidgetItem(address) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.tableWidgetBlacklist.setItem(0, 1, newItem) - self.tableWidgetBlacklist.setSortingEnabled(True) - t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - sql = '''INSERT INTO blacklist VALUES (?,?,?)''' - else: - sql = '''INSERT INTO whitelist VALUES (?,?,?)''' - sqlExecute(sql, *t) - else: - self.statusBar().showMessage(_translate( - "MainWindow", "Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want.")) - else: - self.statusBar().showMessage(_translate( - "MainWindow", "The address you entered was invalid. Ignoring it.")) - - def tableWidgetBlacklistItemChanged(self, item): - if item.column() == 0: - addressitem = self.tableWidgetBlacklist.item(item.row(), 1) - if isinstance(addressitem, QtGui.QTableWidgetItem): - if self.radioButtonBlacklist.isChecked(): - sqlExecute('''UPDATE blacklist SET label=? WHERE address=?''', - str(item.text()), str(addressitem.text())) - else: - sqlExecute('''UPDATE whitelist SET label=? WHERE address=?''', - str(item.text()), str(addressitem.text())) - - def init_blacklist_popup_menu(self, connectSignal=True): - # Popup menu for the Blacklist page - self.blacklistContextMenuToolbar = QtGui.QToolBar() - # Actions - self.actionBlacklistNew = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Add new entry"), self.on_action_BlacklistNew) - self.actionBlacklistDelete = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Delete"), self.on_action_BlacklistDelete) - self.actionBlacklistClipboard = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Copy address to clipboard"), - self.on_action_BlacklistClipboard) - self.actionBlacklistEnable = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Enable"), self.on_action_BlacklistEnable) - self.actionBlacklistDisable = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Disable"), self.on_action_BlacklistDisable) - self.actionBlacklistSetAvatar = self.blacklistContextMenuToolbar.addAction( - _translate( - "MainWindow", "Set avatar..."), - self.on_action_BlacklistSetAvatar) - self.tableWidgetBlacklist.setContextMenuPolicy( - QtCore.Qt.CustomContextMenu) - if connectSignal: - self.connect(self.tableWidgetBlacklist, QtCore.SIGNAL( - 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuBlacklist) - self.popMenuBlacklist = QtGui.QMenu(self) - # self.popMenuBlacklist.addAction( self.actionBlacklistNew ) - self.popMenuBlacklist.addAction(self.actionBlacklistDelete) - self.popMenuBlacklist.addSeparator() - self.popMenuBlacklist.addAction(self.actionBlacklistClipboard) - self.popMenuBlacklist.addSeparator() - self.popMenuBlacklist.addAction(self.actionBlacklistEnable) - self.popMenuBlacklist.addAction(self.actionBlacklistDisable) - self.popMenuBlacklist.addAction(self.actionBlacklistSetAvatar) - - def rerenderBlackWhiteList(self): - tabs = self.parent().parent() - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Blacklist')) - else: - tabs.setTabText(tabs.indexOf(self), _translate('blacklist', 'Whitelist')) - self.tableWidgetBlacklist.setRowCount(0) - listType = BMConfigParser().get('bitmessagesettings', 'blackwhitelist') - if listType == 'black': - queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') - else: - queryreturn = sqlQuery('''SELECT label, address, enabled FROM whitelist''') - self.tableWidgetBlacklist.setSortingEnabled(False) - for row in queryreturn: - label, address, enabled = row - self.tableWidgetBlacklist.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) - if not enabled: - newItem.setTextColor(QtGui.QColor(128, 128, 128)) - newItem.setIcon(avatarize(address)) - self.tableWidgetBlacklist.setItem(0, 0, newItem) - newItem = QtGui.QTableWidgetItem(address) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not enabled: - newItem.setTextColor(QtGui.QColor(128, 128, 128)) - self.tableWidgetBlacklist.setItem(0, 1, newItem) - self.tableWidgetBlacklist.setSortingEnabled(True) - - # Group of functions for the Blacklist dialog box - def on_action_BlacklistNew(self): - self.click_pushButtonAddBlacklist() - - def on_action_BlacklistDelete(self): - currentRow = self.tableWidgetBlacklist.currentRow() - labelAtCurrentRow = self.tableWidgetBlacklist.item( - currentRow, 0).text().toUtf8() - addressAtCurrentRow = self.tableWidgetBlacklist.item( - currentRow, 1).text() - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - sqlExecute( - '''DELETE FROM blacklist WHERE label=? AND address=?''', - str(labelAtCurrentRow), str(addressAtCurrentRow)) - else: - sqlExecute( - '''DELETE FROM whitelist WHERE label=? AND address=?''', - str(labelAtCurrentRow), str(addressAtCurrentRow)) - self.tableWidgetBlacklist.removeRow(currentRow) - - def on_action_BlacklistClipboard(self): - currentRow = self.tableWidgetBlacklist.currentRow() - addressAtCurrentRow = self.tableWidgetBlacklist.item( - currentRow, 1).text() - clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(addressAtCurrentRow)) - - def on_context_menuBlacklist(self, point): - self.popMenuBlacklist.exec_( - self.tableWidgetBlacklist.mapToGlobal(point)) - - def on_action_BlacklistEnable(self): - currentRow = self.tableWidgetBlacklist.currentRow() - addressAtCurrentRow = self.tableWidgetBlacklist.item( - currentRow, 1).text() - self.tableWidgetBlacklist.item( - currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color()) - self.tableWidgetBlacklist.item( - currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color()) - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - sqlExecute( - '''UPDATE blacklist SET enabled=1 WHERE address=?''', - str(addressAtCurrentRow)) - else: - sqlExecute( - '''UPDATE whitelist SET enabled=1 WHERE address=?''', - str(addressAtCurrentRow)) - - def on_action_BlacklistDisable(self): - currentRow = self.tableWidgetBlacklist.currentRow() - addressAtCurrentRow = self.tableWidgetBlacklist.item( - currentRow, 1).text() - self.tableWidgetBlacklist.item( - currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) - self.tableWidgetBlacklist.item( - currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': - sqlExecute( - '''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) - else: - sqlExecute( - '''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) - - def on_action_BlacklistSetAvatar(self): - self.window().on_action_SetAvatar(self.tableWidgetBlacklist) - diff --git a/src/bitmessageqt/blacklist.ui b/src/bitmessageqt/blacklist.ui deleted file mode 100644 index 80993fac..00000000 --- a/src/bitmessageqt/blacklist.ui +++ /dev/null @@ -1,108 +0,0 @@ - - - blacklist - - - - 0 - 0 - 819 - 295 - - - - - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - true - - - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - - - Add new entry - - - - - - - Qt::Horizontal - - - - 689 - 20 - - - - - - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - true - - - true - - - 400 - - - false - - - false - - - true - - - false - - - - Name or Label - - - - - Address - - - - - - - - - STableWidget - QTableWidget -
bitmessageqt/settingsmixin.h
-
-
- - - - -
diff --git a/src/bitmessageqt/connect.py b/src/bitmessageqt/connect.py new file mode 100644 index 00000000..1e224afb --- /dev/null +++ b/src/bitmessageqt/connect.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'connect.ui' +# +# Created: Wed Jul 24 12:42:01 2013 +# by: PyQt4 UI code generator 4.10 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_connectDialog(object): + def setupUi(self, connectDialog): + connectDialog.setObjectName(_fromUtf8("connectDialog")) + connectDialog.resize(400, 124) + self.gridLayout = QtGui.QGridLayout(connectDialog) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.label = QtGui.QLabel(connectDialog) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout.addWidget(self.label, 0, 0, 1, 2) + self.radioButtonConnectNow = QtGui.QRadioButton(connectDialog) + self.radioButtonConnectNow.setChecked(True) + self.radioButtonConnectNow.setObjectName(_fromUtf8("radioButtonConnectNow")) + self.gridLayout.addWidget(self.radioButtonConnectNow, 1, 0, 1, 2) + self.radioButtonConfigureNetwork = QtGui.QRadioButton(connectDialog) + self.radioButtonConfigureNetwork.setObjectName(_fromUtf8("radioButtonConfigureNetwork")) + self.gridLayout.addWidget(self.radioButtonConfigureNetwork, 2, 0, 1, 2) + spacerItem = QtGui.QSpacerItem(185, 24, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(connectDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) + + self.retranslateUi(connectDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), connectDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), connectDialog.reject) + QtCore.QMetaObject.connectSlotsByName(connectDialog) + + def retranslateUi(self, connectDialog): + connectDialog.setWindowTitle(_translate("connectDialog", "Bitmessage", None)) + self.label.setText(_translate("connectDialog", "Bitmessage won\'t connect to anyone until you let it. ", None)) + self.radioButtonConnectNow.setText(_translate("connectDialog", "Connect now", None)) + self.radioButtonConfigureNetwork.setText(_translate("connectDialog", "Let me configure special network settings first", None)) + diff --git a/src/bitmessageqt/connect.ui b/src/bitmessageqt/connect.ui index 8b76f5ac..74173860 100644 --- a/src/bitmessageqt/connect.ui +++ b/src/bitmessageqt/connect.ui @@ -38,14 +38,7 @@
- - - - Work offline - - - - + Qt::Horizontal @@ -58,7 +51,7 @@ - + Qt::Horizontal diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py deleted file mode 100644 index cb82f348..00000000 --- a/src/bitmessageqt/dialogs.py +++ /dev/null @@ -1,76 +0,0 @@ -from PyQt4 import QtGui -from tr import _translate -from retranslateui import RetranslateMixin -import widgets - -from newchandialog import NewChanDialog -from address_dialogs import ( - AddAddressDialog, NewAddressDialog, NewSubscriptionDialog, - RegenerateAddressesDialog, SpecialAddressBehaviorDialog, EmailGatewayDialog -) - -import paths -from version import softwareVersion - - -__all__ = [ - "NewChanDialog", "AddAddressDialog", "NewAddressDialog", - "NewSubscriptionDialog", "RegenerateAddressesDialog", - "SpecialAddressBehaviorDialog", "EmailGatewayDialog" -] - - -class AboutDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(AboutDialog, self).__init__(parent) - widgets.load('about.ui', self) - last_commit = paths.lastCommit() - version = softwareVersion - commit = last_commit.get('commit') - if commit: - version += '-' + commit[:7] - self.labelVersion.setText( - self.labelVersion.text().replace( - ':version:', version - ).replace(':branch:', commit or 'v%s' % version) - ) - self.labelVersion.setOpenExternalLinks(True) - - try: - self.label_2.setText( - self.label_2.text().replace( - '2017', str(last_commit.get('time').year) - )) - except AttributeError: - pass - - self.setFixedSize(QtGui.QWidget.sizeHint(self)) - - -class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None, config=None): - super(IconGlossaryDialog, self).__init__(parent) - widgets.load('iconglossary.ui', self) - - # FIXME: check the window title visibility here - self.groupBox.setTitle('') - - self.labelPortNumber.setText(_translate( - "iconGlossaryDialog", - "You are using TCP port %1. (This can be changed in the settings)." - ).arg(config.getint('bitmessagesettings', 'port'))) - self.setFixedSize(QtGui.QWidget.sizeHint(self)) - - -class HelpDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(HelpDialog, self).__init__(parent) - widgets.load('help.ui', self) - self.setFixedSize(QtGui.QWidget.sizeHint(self)) - - -class ConnectDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(ConnectDialog, self).__init__(parent) - widgets.load('connect.ui', self) - self.setFixedSize(QtGui.QWidget.sizeHint(self)) diff --git a/src/bitmessageqt/emailgateway.ui b/src/bitmessageqt/emailgateway.ui deleted file mode 100644 index 77a66dec..00000000 --- a/src/bitmessageqt/emailgateway.ui +++ /dev/null @@ -1,224 +0,0 @@ - - - EmailGatewayDialog - - - - 0 - 0 - 386 - 240 - - - - Email gateway - - - - - - true - - - Desired email address (including @mailchuck.com): - - - - - - - Register on email gateway - - - true - - - - - - - - 368 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - true - - - @mailchuck.com - - - 0 - - - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - true - - - - - - - false - - - Account status at email gateway - - - false - - - - - - - false - - - Change account settings at email gateway - - - false - - - - - - - false - - - Unregister from email gateway - - - false - - - - - - - radioButtonRegister - lineEditEmail - radioButtonStatus - radioButtonSettings - radioButtonUnregister - buttonBox - - - - - buttonBox - accepted() - EmailGatewayDialog - accept() - - - 227 - 152 - - - 157 - 171 - - - - - buttonBox - rejected() - EmailGatewayDialog - reject() - - - 295 - 158 - - - 286 - 171 - - - - - radioButtonRegister - clicked(bool) - lineEditEmail - setEnabled(bool) - - - 95 - 40 - - - 94 - 123 - - - - - radioButtonUnregister - clicked(bool) - lineEditEmail - setDisabled(bool) - - - 139 - 19 - - - 187 - 123 - - - - - radioButtonStatus - clicked(bool) - lineEditEmail - setDisabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - radioButtonSettings - clicked(bool) - lineEditEmail - setDisabled(bool) - - - 20 - 20 - - - 20 - 20 - - - - - diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py deleted file mode 100644 index 11227fca..00000000 --- a/src/bitmessageqt/foldertree.py +++ /dev/null @@ -1,546 +0,0 @@ -from PyQt4 import QtCore, QtGui -from string import find, rfind, rstrip, lstrip - -from tr import _translate -from bmconfigparser import BMConfigParser -from helper_sql import * -from utils import * -from settingsmixin import SettingsMixin - -# for pylupdate -_translate("MainWindow", "inbox") -_translate("MainWindow", "new") -_translate("MainWindow", "sent") -_translate("MainWindow", "trash") - - -class AccountMixin(object): - ALL = 0 - NORMAL = 1 - CHAN = 2 - MAILINGLIST = 3 - SUBSCRIPTION = 4 - BROADCAST = 5 - - def accountColor (self): - if not self.isEnabled: - return QtGui.QColor(128, 128, 128) - elif self.type == self.CHAN: - return QtGui.QColor(216, 119, 0) - elif self.type in [self.MAILINGLIST, self.SUBSCRIPTION]: - return QtGui.QColor(137, 04, 177) - else: - return QtGui.QApplication.palette().text().color() - - def folderColor (self): - if not self.parent().isEnabled: - return QtGui.QColor(128, 128, 128) - else: - return QtGui.QApplication.palette().text().color() - - def accountBrush(self): - brush = QtGui.QBrush(self.accountColor()) - brush.setStyle(QtCore.Qt.NoBrush) - return brush - - def folderBrush(self): - brush = QtGui.QBrush(self.folderColor()) - brush.setStyle(QtCore.Qt.NoBrush) - return brush - - def setAddress(self, address): - if address is None: - self.address = None - else: - self.address = str(address) - - def setUnreadCount(self, cnt): - if hasattr(self, "unreadCount") and self.unreadCount == int(cnt): - return - self.unreadCount = int(cnt) - if isinstance(self, QtGui.QTreeWidgetItem): - self.emitDataChanged() - - def setEnabled(self, enabled): - self.isEnabled = enabled - if hasattr(self, "setExpanded"): - self.setExpanded(enabled) - if isinstance(self, Ui_AddressWidget): - for i in range(self.childCount()): - if isinstance(self.child(i), Ui_FolderWidget): - self.child(i).setEnabled(enabled) - if isinstance(self, QtGui.QTreeWidgetItem): - self.emitDataChanged() - - def setType(self): - self.setFlags(self.flags() | QtCore.Qt.ItemIsEditable) - if self.address is None: - self.type = self.ALL - self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable) - elif BMConfigParser().safeGetBoolean(self.address, 'chan'): - self.type = self.CHAN - elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): - self.type = self.MAILINGLIST - elif sqlQuery( - '''select label from subscriptions where address=?''', self.address): - self.type = AccountMixin.SUBSCRIPTION - else: - self.type = self.NORMAL - - def defaultLabel(self): - queryreturn = None - retval = None - if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): - try: - retval = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8') - except Exception as e: - queryreturn = sqlQuery( - '''select label from addressbook where address=?''', self.address) - elif self.type == AccountMixin.SUBSCRIPTION: - queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', self.address) - if queryreturn is not None: - if queryreturn != []: - for row in queryreturn: - retval, = row - retval = unicode(retval, 'utf-8') - elif self.address is None or self.type == AccountMixin.ALL: - return unicode( - str(_translate("MainWindow", "All accounts")), 'utf-8') - if retval is None: - return unicode(self.address, 'utf-8') - else: - return retval - - -class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): - folderWeight = {"inbox": 1, "new": 2, "sent": 3, "trash": 4} - def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0): - super(QtGui.QTreeWidgetItem, self).__init__() - self.setAddress(address) - self.setFolderName(folderName) - self.setUnreadCount(unreadCount) - parent.insertChild(pos, self) - - def setFolderName(self, fname): - self.folderName = str(fname) - - def data(self, column, role): - if column == 0: - if role == QtCore.Qt.DisplayRole: - return _translate("MainWindow", self.folderName) + ( - " (" + str(self.unreadCount) + ")" - if self.unreadCount > 0 else "" - ) - elif role in (QtCore.Qt.EditRole, QtCore.Qt.ToolTipRole): - return _translate("MainWindow", self.folderName) - elif role == QtCore.Qt.FontRole: - font = QtGui.QFont() - font.setBold(self.unreadCount > 0) - return font - elif role == QtCore.Qt.ForegroundRole: - return self.folderBrush() - return super(Ui_FolderWidget, self).data(column, role) - - # inbox, sent, thrash first, rest alphabetically - def __lt__(self, other): - if (isinstance(other, Ui_FolderWidget)): - if self.folderName in self.folderWeight: - x = self.folderWeight[self.folderName] - else: - x = 99 - if other.folderName in self.folderWeight: - y = self.folderWeight[other.folderName] - else: - y = 99 - reverse = False - if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: - reverse = True - if x == y: - return self.folderName < other.folderName - else: - return (x >= y if reverse else x < y) - - return super(QtGui.QTreeWidgetItem, self).__lt__(other) - - -class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): - def __init__(self, parent, pos = 0, address = None, unreadCount = 0, enabled = True): - super(QtGui.QTreeWidgetItem, self).__init__() - parent.insertTopLevelItem(pos, self) - # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) - self.setAddress(address) - self.setEnabled(enabled) - self.setUnreadCount(unreadCount) - self.setType() - - def _getLabel(self): - if self.address is None: - return unicode(_translate( - "MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') - else: - try: - return unicode( - BMConfigParser().get(self.address, 'label'), - 'utf-8', 'ignore') - except: - return unicode(self.address, 'utf-8') - - def _getAddressBracket(self, unreadCount = False): - ret = "" - if unreadCount: - ret += " (" + str(self.unreadCount) + ")" - if self.address is not None: - ret += " (" + self.address + ")" - return ret - - def data(self, column, role): - if column == 0: - if role == QtCore.Qt.DisplayRole: - if self.unreadCount > 0 and not self.isExpanded(): - return self._getLabel() + self._getAddressBracket(True) - else: - return self._getLabel() + self._getAddressBracket(False) - elif role == QtCore.Qt.EditRole: - return self._getLabel() - elif role == QtCore.Qt.ToolTipRole: - return self._getLabel() + self._getAddressBracket(False) - elif role == QtCore.Qt.DecorationRole: - if self.address is None: - return avatarize(self._getLabel().encode('utf8')) - else: - return avatarize(self.address) - elif role == QtCore.Qt.FontRole: - font = QtGui.QFont() - font.setBold(self.unreadCount > 0) - return font - elif role == QtCore.Qt.ForegroundRole: - return self.accountBrush() - return super(Ui_AddressWidget, self).data(column, role) - - def setData(self, column, role, value): - if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: - if isinstance(value, QtCore.QVariant): - BMConfigParser().set(str(self.address), 'label', str(value.toString().toUtf8())) - else: - BMConfigParser().set(str(self.address), 'label', str(value)) - BMConfigParser().save() - return super(Ui_AddressWidget, self).setData(column, role, value) - - def setAddress(self, address): - super(Ui_AddressWidget, self).setAddress(address) - self.setData(0, QtCore.Qt.UserRole, self.address) - - def setExpanded(self, expand): - super(Ui_AddressWidget, self).setExpanded(expand) - - def _getSortRank(self): - ret = self.type - if not self.isEnabled: - ret += 100 - return ret - - # label (or address) alphabetically, disabled at the end - def __lt__(self, other): - if (isinstance(other, Ui_AddressWidget)): - reverse = False - if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: - reverse = True - if self._getSortRank() == other._getSortRank(): - x = self._getLabel().lower() - y = other._getLabel().lower() - return x < y - return (not reverse if self._getSortRank() < other._getSortRank() else reverse) - - return super(QtGui.QTreeWidgetItem, self).__lt__(other) - - -class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): - def __init__(self, parent, pos = 0, address = "", unreadCount = 0, label = "", enabled = True): - super(QtGui.QTreeWidgetItem, self).__init__() - parent.insertTopLevelItem(pos, self) - # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) - self.setAddress(address) - self.setEnabled(enabled) - self.setType() - self.setUnreadCount(unreadCount) - - def _getLabel(self): - queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', self.address) - if queryreturn != []: - for row in queryreturn: - retval, = row - return unicode(retval, 'utf-8', 'ignore') - return unicode(self.address, 'utf-8') - - def setType(self): - super(Ui_SubscriptionWidget, self).setType() # sets it editable - self.type = AccountMixin.SUBSCRIPTION # overrides type - - def setData(self, column, role, value): - if role == QtCore.Qt.EditRole: - from debug import logger - if isinstance(value, QtCore.QVariant): - label = str(value.toString().toUtf8()).decode('utf-8', 'ignore') - else: - label = unicode(value, 'utf-8', 'ignore') - sqlExecute( - '''UPDATE subscriptions SET label=? WHERE address=?''', - label, self.address) - return super(Ui_SubscriptionWidget, self).setData(column, role, value) - - -class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMixin): - def __init__(self, parent, address = None, label = None, unread = False): - super(QtGui.QTableWidgetItem, self).__init__() - #parent.insertTopLevelItem(pos, self) - # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) - self.isEnabled = True - self.setAddress(address) - self.setLabel(label) - self.setUnread(unread) - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.setType() - parent.append(self) - - def setLabel(self, label = None): - newLabel = self.address - if label is None: - queryreturn = None - if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): - try: - newLabel = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') - except: - queryreturn = sqlQuery( - '''select label from addressbook where address=?''', self.address) - elif self.type == AccountMixin.SUBSCRIPTION: - queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', self.address) - if queryreturn is not None: - if queryreturn != []: - for row in queryreturn: - newLabel = unicode(row[0], 'utf-8', 'ignore') - else: - newLabel = label - if hasattr(self, 'label') and newLabel == self.label: - return - self.label = newLabel - - def setUnread(self, unread): - self.unread = unread - - def data(self, role): - if role == QtCore.Qt.DisplayRole: - return self.label - elif role == QtCore.Qt.EditRole: - return self.label - elif role == QtCore.Qt.ToolTipRole: - return self.label + " (" + self.address + ")" - elif role == QtCore.Qt.DecorationRole: - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): - if self.address is None: - return avatarize(self.label) - else: - return avatarize(self.address) - elif role == QtCore.Qt.FontRole: - font = QtGui.QFont() - font.setBold(self.unread) - return font - elif role == QtCore.Qt.ForegroundRole: - return self.accountBrush() - elif role == QtCore.Qt.UserRole: - return self.address - return super(MessageList_AddressWidget, self).data(role) - - def setData(self, role, value): - if role == QtCore.Qt.EditRole: - self.setLabel() - return super(MessageList_AddressWidget, self).setData(role, value) - - # label (or address) alphabetically, disabled at the end - def __lt__(self, other): - if (isinstance(other, MessageList_AddressWidget)): - return self.label.lower() < other.label.lower() - return super(QtGui.QTableWidgetItem, self).__lt__(other) - - -class MessageList_SubjectWidget(QtGui.QTableWidgetItem, SettingsMixin): - def __init__(self, parent, subject = None, label = None, unread = False): - super(QtGui.QTableWidgetItem, self).__init__() - #parent.insertTopLevelItem(pos, self) - # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) - self.setSubject(subject) - self.setLabel(label) - self.setUnread(unread) - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - parent.append(self) - - def setLabel(self, label): - self.label = label - - def setSubject(self, subject): - self.subject = subject - - def setUnread(self, unread): - self.unread = unread - - def data(self, role): - if role == QtCore.Qt.DisplayRole: - return self.label - elif role == QtCore.Qt.EditRole: - return self.label - elif role == QtCore.Qt.ToolTipRole: - return self.label - elif role == QtCore.Qt.FontRole: - font = QtGui.QFont() - font.setBold(self.unread) - return font - elif role == QtCore.Qt.UserRole: - return self.subject - return super(MessageList_SubjectWidget, self).data(role) - - def setData(self, role, value): - return super(MessageList_SubjectWidget, self).setData(role, value) - - # label (or address) alphabetically, disabled at the end - def __lt__(self, other): - if (isinstance(other, MessageList_SubjectWidget)): - return self.label.lower() < other.label.lower() - return super(QtGui.QTableWidgetItem, self).__lt__(other) - - -class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): - def __init__ (self, text, type = AccountMixin.NORMAL): - super(QtGui.QTableWidgetItem, self).__init__(text) - self.label = text - self.type = type - self.setEnabled(True) - - def data(self, role): - if role == QtCore.Qt.DisplayRole: - return self.label - elif role == QtCore.Qt.EditRole: - return self.label - elif role == QtCore.Qt.ToolTipRole: - return self.label + " (" + self.address + ")" - elif role == QtCore.Qt.DecorationRole: - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): - if self.address is None: - return avatarize(self.label) - else: - return avatarize(self.address) - elif role == QtCore.Qt.FontRole: - font = QtGui.QFont() - return font - elif role == QtCore.Qt.ForegroundRole: - return self.accountBrush() - elif role == QtCore.Qt.UserRole: - return self.type - return super(Ui_AddressBookWidgetItem, self).data(role) - - def setData(self, role, value): - if role == QtCore.Qt.EditRole: - if isinstance(value, QtCore.QVariant): - self.label = str(value.toString().toUtf8()) - else: - self.label = str(value) - if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): - try: - a = BMConfigParser().get(self.address, 'label') - BMConfigParser().set(self.address, 'label', self.label) - BMConfigParser().save() - except: - sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address) - elif self.type == AccountMixin.SUBSCRIPTION: - from debug import logger - sqlExecute('''UPDATE subscriptions set label=? WHERE address=?''', self.label, self.address) - else: - pass - return super(Ui_AddressBookWidgetItem, self).setData(role, value) - - def __lt__ (self, other): - if (isinstance(other, Ui_AddressBookWidgetItem)): - reverse = False - if self.tableWidget().horizontalHeader().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: - reverse = True - if self.type == other.type: - return self.label.lower() < other.label.lower() - else: - return (not reverse if self.type < other.type else reverse) - return super(QtGui.QTableWidgetItem, self).__lt__(other) - - -class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): - def __init__ (self, address, label, type): - Ui_AddressBookWidgetItem.__init__(self, label, type) - self.address = address - self.label = label - - def data(self, role): - self.label = self.defaultLabel() - return super(Ui_AddressBookWidgetItemLabel, self).data(role) - - -class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): - def __init__ (self, address, label, type): - Ui_AddressBookWidgetItem.__init__(self, address, type) - self.address = address - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - -class AddressBookCompleter(QtGui.QCompleter): - def __init__(self): - super(QtGui.QCompleter, self).__init__() - self.cursorPos = -1 - - def onCursorPositionChanged(self, oldPos, newPos): - if oldPos != self.cursorPos: - self.cursorPos = -1 - - def splitPath(self, path): - stringList = [] - text = unicode(path.toUtf8(), encoding="UTF-8") - splitIndex = rfind(text[0:self.widget().cursorPosition()], ";") + 1 - str = text[splitIndex:self.widget().cursorPosition()] - str = rstrip(lstrip(str)) - stringList.append(str) - return stringList - - def pathFromIndex(self, index): - autoString = unicode(index.data(QtCore.Qt.EditRole).toString().toUtf8(), encoding="UTF-8") - text = unicode(self.widget().text().toUtf8(), encoding="UTF-8") - - # If cursor position was saved, restore it, else save it - if self.cursorPos != -1: - self.widget().setCursorPosition(self.cursorPos) - else: - self.cursorPos = self.widget().cursorPosition() - - # Get current prosition - curIndex = self.widget().cursorPosition() - - # prev_delimiter_index should actually point at final white space AFTER the delimiter - # Get index of last delimiter before current position - prevDelimiterIndex = rfind(text[0:curIndex], ";") - while text[prevDelimiterIndex + 1] == " ": - prevDelimiterIndex += 1 - - # Get index of first delimiter after current position (or EOL if no delimiter after cursor) - nextDelimiterIndex = find(text, ";", curIndex) - if nextDelimiterIndex == -1: - nextDelimiterIndex = len(text) - - # Get part of string that occurs before cursor - part1 = text[0:prevDelimiterIndex + 1] - - # Get string value from before auto finished string is selected - pre = text[prevDelimiterIndex + 1:curIndex - 1]; - - # Get part of string that occurs AFTER cursor - part2 = text[nextDelimiterIndex:] - - return part1 + autoString + part2; diff --git a/src/bitmessageqt/help.py b/src/bitmessageqt/help.py new file mode 100644 index 00000000..ff876514 --- /dev/null +++ b/src/bitmessageqt/help.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'help.ui' +# +# Created: Wed Jan 14 22:42:39 2015 +# by: PyQt4 UI code generator 4.9.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + _fromUtf8 = lambda s: s + +class Ui_helpDialog(object): + def setupUi(self, helpDialog): + helpDialog.setObjectName(_fromUtf8("helpDialog")) + helpDialog.resize(335, 96) + self.formLayout = QtGui.QFormLayout(helpDialog) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.labelHelpURI = QtGui.QLabel(helpDialog) + self.labelHelpURI.setOpenExternalLinks(True) + self.labelHelpURI.setObjectName(_fromUtf8("labelHelpURI")) + self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.labelHelpURI) + self.label = QtGui.QLabel(helpDialog) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.formLayout.setWidget(0, QtGui.QFormLayout.SpanningRole, self.label) + spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.formLayout.setItem(2, QtGui.QFormLayout.LabelRole, spacerItem) + self.buttonBox = QtGui.QDialogButtonBox(helpDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.formLayout.setWidget(2, QtGui.QFormLayout.FieldRole, self.buttonBox) + + self.retranslateUi(helpDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), helpDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), helpDialog.reject) + QtCore.QMetaObject.connectSlotsByName(helpDialog) + + def retranslateUi(self, helpDialog): + helpDialog.setWindowTitle(QtGui.QApplication.translate("helpDialog", "Help", None, QtGui.QApplication.UnicodeUTF8)) + self.labelHelpURI.setText(QtGui.QApplication.translate("helpDialog", "https://bitmessage.org/wiki/PyBitmessage_Help", None, QtGui.QApplication.UnicodeUTF8)) + 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)) + diff --git a/src/bitmessageqt/iconglossary.py b/src/bitmessageqt/iconglossary.py new file mode 100644 index 00000000..32d92db6 --- /dev/null +++ b/src/bitmessageqt/iconglossary.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'iconglossary.ui' +# +# Created: Thu Jun 13 20:15:48 2013 +# by: PyQt4 UI code generator 4.10.1 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_iconGlossaryDialog(object): + def setupUi(self, iconGlossaryDialog): + iconGlossaryDialog.setObjectName(_fromUtf8("iconGlossaryDialog")) + iconGlossaryDialog.resize(424, 282) + self.gridLayout = QtGui.QGridLayout(iconGlossaryDialog) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.groupBox = QtGui.QGroupBox(iconGlossaryDialog) + self.groupBox.setObjectName(_fromUtf8("groupBox")) + self.gridLayout_2 = QtGui.QGridLayout(self.groupBox) + self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.label = QtGui.QLabel(self.groupBox) + self.label.setText(_fromUtf8("")) + self.label.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png"))) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtGui.QLabel(self.groupBox) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 0, 1, 1, 1) + self.label_3 = QtGui.QLabel(self.groupBox) + self.label_3.setText(_fromUtf8("")) + self.label_3.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/yellowicon.png"))) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1) + self.label_4 = QtGui.QLabel(self.groupBox) + self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label_4.setWordWrap(True) + self.label_4.setObjectName(_fromUtf8("label_4")) + self.gridLayout_2.addWidget(self.label_4, 1, 1, 2, 1) + spacerItem = QtGui.QSpacerItem(20, 73, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 2, 0, 2, 1) + self.labelPortNumber = QtGui.QLabel(self.groupBox) + self.labelPortNumber.setObjectName(_fromUtf8("labelPortNumber")) + self.gridLayout_2.addWidget(self.labelPortNumber, 3, 1, 1, 1) + self.label_5 = QtGui.QLabel(self.groupBox) + self.label_5.setText(_fromUtf8("")) + self.label_5.setPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/greenicon.png"))) + self.label_5.setObjectName(_fromUtf8("label_5")) + self.gridLayout_2.addWidget(self.label_5, 4, 0, 1, 1) + self.label_6 = QtGui.QLabel(self.groupBox) + self.label_6.setWordWrap(True) + self.label_6.setObjectName(_fromUtf8("label_6")) + self.gridLayout_2.addWidget(self.label_6, 4, 1, 1, 1) + self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(iconGlossaryDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1) + + self.retranslateUi(iconGlossaryDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), iconGlossaryDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), iconGlossaryDialog.reject) + QtCore.QMetaObject.connectSlotsByName(iconGlossaryDialog) + + def retranslateUi(self, iconGlossaryDialog): + iconGlossaryDialog.setWindowTitle(_translate("iconGlossaryDialog", "Icon Glossary", None)) + self.groupBox.setTitle(_translate("iconGlossaryDialog", "Icon Glossary", None)) + self.label_2.setText(_translate("iconGlossaryDialog", "You have no connections with other peers. ", None)) + 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)) + self.labelPortNumber.setText(_translate("iconGlossaryDialog", "You are using TCP port ?. (This can be changed in the settings).", None)) + self.label_6.setText(_translate("iconGlossaryDialog", "You do have connections with other peers and your firewall is correctly configured.", None)) + +import bitmessage_icons_rc + +if __name__ == "__main__": + import sys + app = QtGui.QApplication(sys.argv) + iconGlossaryDialog = QtGui.QDialog() + ui = Ui_iconGlossaryDialog() + ui.setupUi(iconGlossaryDialog) + iconGlossaryDialog.show() + sys.exit(app.exec_()) + diff --git a/src/bitmessageqt/iconglossary.ui b/src/bitmessageqt/iconglossary.ui index 1bac94c8..870a90ee 100644 --- a/src/bitmessageqt/iconglossary.ui +++ b/src/bitmessageqt/iconglossary.ui @@ -76,7 +76,7 @@ - You are using TCP port ?. (This can be changed in the settings). + You are using TCP port ?. (This can be changed in the settings). diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py deleted file mode 100644 index 552e0350..00000000 --- a/src/bitmessageqt/languagebox.py +++ /dev/null @@ -1,38 +0,0 @@ -import glob -import os -from PyQt4 import QtCore, QtGui - -from bmconfigparser import BMConfigParser -import paths - -class LanguageBox(QtGui.QComboBox): - languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} - def __init__(self, parent = None): - super(QtGui.QComboBox, self).__init__(parent) - self.populate() - - def populate(self): - self.languages = [] - self.clear() - localesPath = os.path.join (paths.codePath(), 'translations') - configuredLocale = "system" - try: - configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system") - except: - pass - self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system") - self.setCurrentIndex(0) - self.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) - for translationFile in sorted(glob.glob(os.path.join(localesPath, "bitmessage_*.qm"))): - localeShort = os.path.split(translationFile)[1].split("_", 1)[1][:-3] - locale = QtCore.QLocale(QtCore.QString(localeShort)) - if localeShort in LanguageBox.languageName: - self.addItem(LanguageBox.languageName[localeShort], localeShort) - elif locale.nativeLanguageName() == "": - self.addItem(localeShort, localeShort) - else: - self.addItem(locale.nativeLanguageName(), localeShort) - for i in range(self.count()): - if self.itemData(i) == configuredLocale: - self.setCurrentIndex(i) - break diff --git a/src/bitmessageqt/messagecompose.py b/src/bitmessageqt/messagecompose.py deleted file mode 100644 index f7d5dac3..00000000 --- a/src/bitmessageqt/messagecompose.py +++ /dev/null @@ -1,23 +0,0 @@ -from PyQt4 import QtCore, QtGui - -class MessageCompose(QtGui.QTextEdit): - - def __init__(self, parent = 0): - super(MessageCompose, self).__init__(parent) - self.setAcceptRichText(False) # we'll deal with this later when we have a new message format - self.defaultFontPointSize = self.currentFont().pointSize() - - def wheelEvent(self, event): - if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: - if event.delta() > 0: - self.zoomIn(1) - else: - self.zoomOut(1) - zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize - QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(str(zoom))) - else: - # in QTextEdit, super does not zoom, only scroll - super(MessageCompose, self).wheelEvent(event) - - def reset(self): - self.setText('') diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py deleted file mode 100644 index 4d2e768d..00000000 --- a/src/bitmessageqt/messageview.py +++ /dev/null @@ -1,138 +0,0 @@ -from PyQt4 import QtCore, QtGui - -import multiprocessing -import Queue -from urlparse import urlparse -from safehtmlparser import * - -class MessageView(QtGui.QTextBrowser): - MODE_PLAIN = 0 - MODE_HTML = 1 - - def __init__(self, parent = 0): - super(MessageView, self).__init__(parent) - self.mode = MessageView.MODE_PLAIN - self.html = None - self.setOpenExternalLinks(False) - self.setOpenLinks(False) - self.anchorClicked.connect(self.confirmURL) - self.out = "" - self.outpos = 0 - self.document().setUndoRedoEnabled(False) - self.rendering = False - self.defaultFontPointSize = self.currentFont().pointSize() - self.verticalScrollBar().valueChanged.connect(self.lazyRender) - self.setWrappingWidth() - - def resizeEvent(self, event): - super(MessageView, self).resizeEvent(event) - self.setWrappingWidth(event.size().width()) - - def mousePressEvent(self, event): - #text = textCursor.block().text() - if event.button() == QtCore.Qt.LeftButton and self.html and self.html.has_html and self.cursorForPosition(event.pos()).block().blockNumber() == 0: - if self.mode == MessageView.MODE_PLAIN: - self.showHTML() - else: - self.showPlain() - else: - super(MessageView, self).mousePressEvent(event) - - def wheelEvent(self, event): - # super will actually automatically take care of zooming - super(MessageView, self).wheelEvent(event) - if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: - zoom = self.currentFont().pointSize() * 100 / self.defaultFontPointSize - QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(str(zoom))) - - def setWrappingWidth(self, width=None): - self.setLineWrapMode(QtGui.QTextEdit.FixedPixelWidth) - if width is None: - width = self.width() - self.setLineWrapColumnOrWidth(width) - - def confirmURL(self, link): - if link.scheme() == "mailto": - window = QtGui.QApplication.activeWindow() - window.ui.lineEditTo.setText(link.path()) - if link.hasQueryItem("subject"): - window.ui.lineEditSubject.setText( - link.queryItemValue("subject")) - if link.hasQueryItem("body"): - window.ui.textEditMessage.setText( - link.queryItemValue("body")) - window.setSendFromComboBox() - window.ui.tabWidgetSend.setCurrentIndex(0) - window.ui.tabWidget.setCurrentIndex( - window.ui.tabWidget.indexOf(window.ui.send) - ) - window.ui.textEditMessage.setFocus() - return - reply = QtGui.QMessageBox.warning(self, - QtGui.QApplication.translate("MessageView", "Follow external link"), - QtGui.QApplication.translate("MessageView", "The link \"%1\" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure?").arg(unicode(link.toString())), - QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) - if reply == QtGui.QMessageBox.Yes: - QtGui.QDesktopServices.openUrl(link) - - def loadResource (self, restype, name): - if restype == QtGui.QTextDocument.ImageResource and name.scheme() == "bmmsg": - pass -# QImage correctImage; -# lookup the correct QImage from a cache -# return QVariant::fromValue(correctImage); -# elif restype == QtGui.QTextDocument.HtmlResource: -# elif restype == QtGui.QTextDocument.ImageResource: -# elif restype == QtGui.QTextDocument.StyleSheetResource: -# elif restype == QtGui.QTextDocument.UserResource: - else: - pass -# by default, this will interpret it as a local file -# QtGui.QTextBrowser.loadResource(restype, name) - - def lazyRender(self): - if self.rendering: - return - self.rendering = True - position = self.verticalScrollBar().value() - cursor = QtGui.QTextCursor(self.document()) - while self.outpos < len(self.out) and self.verticalScrollBar().value() >= self.document().size().height() - 2 * self.size().height(): - startpos = self.outpos - self.outpos += 10240 - # find next end of tag - if self.mode == MessageView.MODE_HTML: - pos = self.out.find(">", self.outpos) - if pos > self.outpos: - self.outpos = pos + 1 - cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor) - cursor.insertHtml(QtCore.QString(self.out[startpos:self.outpos])) - self.verticalScrollBar().setValue(position) - self.rendering = False - - def showPlain(self): - self.mode = MessageView.MODE_PLAIN - out = self.html.raw - if self.html.has_html: - out = "
" + unicode(QtGui.QApplication.translate("MessageView", "HTML detected, click here to display")) + "

" + out - self.out = out - self.outpos = 0 - self.setHtml("") - self.lazyRender() - - def showHTML(self): - self.mode = MessageView.MODE_HTML - out = self.html.sanitised - out = "
" + unicode(QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "

" + out - self.out = out - self.outpos = 0 - self.setHtml("") - self.lazyRender() - - def setContent(self, data): - self.html = SafeHTMLParser() - self.html.reset() - self.html.reset_safe() - self.html.allow_picture = True - self.html.feed(data) - self.html.close() - self.showPlain() diff --git a/src/bitmessageqt/migrationwizard.py b/src/bitmessageqt/migrationwizard.py deleted file mode 100644 index 6e80f1dc..00000000 --- a/src/bitmessageqt/migrationwizard.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python2.7 -from PyQt4 import QtCore, QtGui - -class MigrationWizardIntroPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Migrating configuration") - - label = QtGui.QLabel("This wizard will help you to migrate your configuration. " - "You can still keep using PyBitMessage once you migrate, the changes are backwards compatible.") - label.setWordWrap(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - - def nextId(self): - return 1 - - -class MigrationWizardAddressesPage(QtGui.QWizardPage): - def __init__(self, addresses): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Addresses") - - label = QtGui.QLabel("Please select addresses that you are already using with mailchuck. ") - label.setWordWrap(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - - def nextId(self): - return 10 - - -class MigrationWizardGPUPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("GPU") - - label = QtGui.QLabel("Are you using a GPU? ") - label.setWordWrap(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - - def nextId(self): - return 10 - - -class MigrationWizardConclusionPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("All done!") - - label = QtGui.QLabel("You successfully migrated.") - label.setWordWrap(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - - -class Ui_MigrationWizard(QtGui.QWizard): - def __init__(self, addresses): - super(QtGui.QWizard, self).__init__() - - self.pages = {} - - page = MigrationWizardIntroPage() - self.setPage(0, page) - self.setStartId(0) - page = MigrationWizardAddressesPage(addresses) - self.setPage(1, page) - page = MigrationWizardGPUPage() - self.setPage(2, page) - page = MigrationWizardConclusionPage() - self.setPage(10, page) - - self.setWindowTitle("Migration from PyBitMessage wizard") - self.adjustSize() - self.show() \ No newline at end of file diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py deleted file mode 100644 index 06b1e0ce..00000000 --- a/src/bitmessageqt/networkstatus.py +++ /dev/null @@ -1,172 +0,0 @@ -from PyQt4 import QtCore, QtGui -import time -import shared - -from tr import _translate -from inventory import Inventory, PendingDownloadQueue, PendingUpload -import knownnodes -import l10n -import network.stats -from retranslateui import RetranslateMixin -from uisignaler import UISignaler -import widgets - -from network.connectionpool import BMConnectionPool - - -class NetworkStatus(QtGui.QWidget, RetranslateMixin): - def __init__(self, parent=None): - super(NetworkStatus, self).__init__(parent) - widgets.load('networkstatus.ui', self) - - header = self.tableWidgetConnectionCount.horizontalHeader() - header.setResizeMode(QtGui.QHeaderView.ResizeToContents) - - # Somehow this value was 5 when I tested - if header.sortIndicatorSection() > 4: - header.setSortIndicator(0, QtCore.Qt.AscendingOrder) - - self.startup = time.localtime() - self.labelStartupTime.setText(_translate("networkstatus", "Since startup on %1").arg( - l10n.formatTimestamp(self.startup))) - - self.UISignalThread = UISignaler.get() - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateNumberOfMessagesProcessed()"), self.updateNumberOfMessagesProcessed) - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateNumberOfPubkeysProcessed()"), self.updateNumberOfPubkeysProcessed) - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed) - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab) - - self.timer = QtCore.QTimer() - - QtCore.QObject.connect( - self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) - - def startUpdate(self): - Inventory().numberOfInventoryLookupsPerformed = 0 - self.runEveryTwoSeconds() - self.timer.start(2000) # milliseconds - - def stopUpdate(self): - self.timer.stop() - - def formatBytes(self, num): - for x in [_translate("networkstatus", "byte(s)", None, QtCore.QCoreApplication.CodecForTr, num), "kB", "MB", "GB"]: - if num < 1000.0: - return "%3.0f %s" % (num, x) - num /= 1000.0 - return "%3.0f %s" % (num, 'TB') - - def formatByteRate(self, num): - num /= 1000 - return "%4.0f kB" % num - - def updateNumberOfObjectsToBeSynced(self): - self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, network.stats.pendingDownload() + network.stats.pendingUpload())) - - def updateNumberOfMessagesProcessed(self): - self.updateNumberOfObjectsToBeSynced() - self.labelMessageCount.setText(_translate( - "networkstatus", "Processed %n person-to-person message(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfMessagesProcessed)) - - def updateNumberOfBroadcastsProcessed(self): - self.updateNumberOfObjectsToBeSynced() - self.labelBroadcastCount.setText(_translate( - "networkstatus", "Processed %n broadcast message(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfBroadcastsProcessed)) - - def updateNumberOfPubkeysProcessed(self): - self.updateNumberOfObjectsToBeSynced() - self.labelPubkeyCount.setText(_translate( - "networkstatus", "Processed %n public key(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfPubkeysProcessed)) - - def updateNumberOfBytes(self): - """ - This function is run every two seconds, so we divide the rate of bytes - sent and received by 2. - """ - self.labelBytesRecvCount.setText(_translate( - "networkstatus", "Down: %1/s Total: %2").arg(self.formatByteRate(network.stats.downloadSpeed()), self.formatBytes(network.stats.receivedBytes()))) - self.labelBytesSentCount.setText(_translate( - "networkstatus", "Up: %1/s Total: %2").arg(self.formatByteRate(network.stats.uploadSpeed()), self.formatBytes(network.stats.sentBytes()))) - - def updateNetworkStatusTab(self, outbound, add, destination): - if outbound: - try: - c = BMConnectionPool().outboundConnections[destination] - except KeyError: - if add: - return - else: - try: - c = BMConnectionPool().inboundConnections[destination] - except KeyError: - try: - c = BMConnectionPool().inboundConnections[destination.host] - except KeyError: - if add: - return - - self.tableWidgetConnectionCount.setUpdatesEnabled(False) - self.tableWidgetConnectionCount.setSortingEnabled(False) - if add: - self.tableWidgetConnectionCount.insertRow(0) - self.tableWidgetConnectionCount.setItem(0, 0, - QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port)) - ) - self.tableWidgetConnectionCount.setItem(0, 2, - QtGui.QTableWidgetItem("%s" % (c.userAgent)) - ) - self.tableWidgetConnectionCount.setItem(0, 3, - QtGui.QTableWidgetItem("%s" % (c.tlsVersion)) - ) - self.tableWidgetConnectionCount.setItem(0, 4, - QtGui.QTableWidgetItem("%s" % (",".join(map(str,c.streams)))) - ) - try: - # FIXME hard coded stream no - rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating']) - except KeyError: - rating = "-" - self.tableWidgetConnectionCount.setItem(0, 1, - QtGui.QTableWidgetItem("%s" % (rating)) - ) - if outbound: - brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern) - else: - brush = QtGui.QBrush(QtGui.QColor("green"), QtCore.Qt.SolidPattern) - for j in (range(1)): - self.tableWidgetConnectionCount.item(0, j).setBackground(brush) - self.tableWidgetConnectionCount.item(0, 0).setData(QtCore.Qt.UserRole, destination) - self.tableWidgetConnectionCount.item(0, 1).setData(QtCore.Qt.UserRole, outbound) - else: - for i in range(self.tableWidgetConnectionCount.rowCount()): - if self.tableWidgetConnectionCount.item(i, 0).data(QtCore.Qt.UserRole).toPyObject() != destination: - continue - if self.tableWidgetConnectionCount.item(i, 1).data(QtCore.Qt.UserRole).toPyObject() == outbound: - self.tableWidgetConnectionCount.removeRow(i) - break - self.tableWidgetConnectionCount.setUpdatesEnabled(True) - self.tableWidgetConnectionCount.setSortingEnabled(True) - self.labelTotalConnections.setText(_translate( - "networkstatus", "Total Connections: %1").arg(str(self.tableWidgetConnectionCount.rowCount()))) - # FYI: The 'singlelistener' thread sets the icon color to green when it receives an incoming connection, meaning that the user's firewall is configured correctly. - if self.tableWidgetConnectionCount.rowCount() and shared.statusIconColor == 'red': - self.window().setStatusIcon('yellow') - elif self.tableWidgetConnectionCount.rowCount() == 0 and shared.statusIconColor != "red": - self.window().setStatusIcon('red') - - # timer driven - def runEveryTwoSeconds(self): - self.labelLookupsPerSecond.setText(_translate( - "networkstatus", "Inventory lookups per second: %1").arg(str(Inventory().numberOfInventoryLookupsPerformed/2))) - Inventory().numberOfInventoryLookupsPerformed = 0 - self.updateNumberOfBytes() - self.updateNumberOfObjectsToBeSynced() - - def retranslateUi(self): - super(NetworkStatus, self).retranslateUi() - self.labelStartupTime.setText(_translate("networkstatus", "Since startup on %1").arg( - l10n.formatTimestamp(self.startup))) diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui deleted file mode 100644 index e0c01b57..00000000 --- a/src/bitmessageqt/networkstatus.ui +++ /dev/null @@ -1,306 +0,0 @@ - - - networkstatus - - - - 0 - 0 - 602 - 254 - - - - - 0 - 0 - - - - - - - 20 - - - QLayout::SetNoConstraint - - - - - 20 - - - QLayout::SetMinimumSize - - - - - Total connections: - - - - - - - - - - - - 212 - 208 - 200 - - - - - - - - - 212 - 208 - 200 - - - - - - - - - 212 - 208 - 200 - - - - - - - - QFrame::Box - - - QFrame::Plain - - - QAbstractItemView::NoEditTriggers - - - false - - - false - - - QAbstractItemView::NoSelection - - - true - - - true - - - 80 - - - false - - - true - - - false - - - - Peer - - - IP address or hostname - - - - - Rating - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - - - - - User agent - - - Peer's self-reported software - - - - - TLS - - - Connection encryption - - - - - Stream # - - - List of streams negotiated between you and the peer - - - - - - - - - - 4 - - - QLayout::SetNoConstraint - - - - - - 0 - 9 - - - - - 0 - 50 - - - - Since startup: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - 0 - 0 - - - - Processed 0 person-to-person messages. - - - 0 - - - - - - - - 0 - 0 - - - - Processed 0 broadcasts. - - - - - - - - 0 - 0 - - - - Processed 0 public keys. - - - - - - - - 0 - 0 - - - - Objects to be synced: - - - - - - - - 0 - 0 - - - - Up: 0 kB/s - - - - - - - - 0 - 0 - - - - Down: 0 kB/s - - - - - - - - 0 - 0 - - - - Inventory lookups per second: 0 - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - - - - - - - - STableWidget - QTableWidget -
bitmessageqt/settingsmixin.h
-
-
- - - - -
diff --git a/src/bitmessageqt/newaddressdialog.py b/src/bitmessageqt/newaddressdialog.py new file mode 100644 index 00000000..afe6fa2d --- /dev/null +++ b/src/bitmessageqt/newaddressdialog.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'newaddressdialog.ui' +# +# Created: Sun Sep 15 23:53:31 2013 +# by: PyQt4 UI code generator 4.10.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_NewAddressDialog(object): + def setupUi(self, NewAddressDialog): + NewAddressDialog.setObjectName(_fromUtf8("NewAddressDialog")) + NewAddressDialog.resize(723, 704) + self.formLayout = QtGui.QFormLayout(NewAddressDialog) + self.formLayout.setFieldGrowthPolicy(QtGui.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.label = QtGui.QLabel(NewAddressDialog) + self.label.setAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.formLayout.setWidget(0, QtGui.QFormLayout.SpanningRole, self.label) + self.label_5 = QtGui.QLabel(NewAddressDialog) + self.label_5.setWordWrap(True) + self.label_5.setObjectName(_fromUtf8("label_5")) + self.formLayout.setWidget(2, QtGui.QFormLayout.SpanningRole, self.label_5) + self.line = QtGui.QFrame(NewAddressDialog) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.line.sizePolicy().hasHeightForWidth()) + self.line.setSizePolicy(sizePolicy) + self.line.setMinimumSize(QtCore.QSize(100, 2)) + self.line.setFrameShape(QtGui.QFrame.HLine) + self.line.setFrameShadow(QtGui.QFrame.Sunken) + self.line.setObjectName(_fromUtf8("line")) + self.formLayout.setWidget(4, QtGui.QFormLayout.SpanningRole, self.line) + self.radioButtonRandomAddress = QtGui.QRadioButton(NewAddressDialog) + self.radioButtonRandomAddress.setChecked(True) + self.radioButtonRandomAddress.setObjectName(_fromUtf8("radioButtonRandomAddress")) + self.buttonGroup = QtGui.QButtonGroup(NewAddressDialog) + self.buttonGroup.setObjectName(_fromUtf8("buttonGroup")) + self.buttonGroup.addButton(self.radioButtonRandomAddress) + self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.radioButtonRandomAddress) + self.radioButtonDeterministicAddress = QtGui.QRadioButton(NewAddressDialog) + self.radioButtonDeterministicAddress.setObjectName(_fromUtf8("radioButtonDeterministicAddress")) + self.buttonGroup.addButton(self.radioButtonDeterministicAddress) + self.formLayout.setWidget(6, QtGui.QFormLayout.LabelRole, self.radioButtonDeterministicAddress) + self.checkBoxEighteenByteRipe = QtGui.QCheckBox(NewAddressDialog) + self.checkBoxEighteenByteRipe.setObjectName(_fromUtf8("checkBoxEighteenByteRipe")) + self.formLayout.setWidget(9, QtGui.QFormLayout.SpanningRole, self.checkBoxEighteenByteRipe) + self.groupBoxDeterministic = QtGui.QGroupBox(NewAddressDialog) + self.groupBoxDeterministic.setObjectName(_fromUtf8("groupBoxDeterministic")) + self.gridLayout = QtGui.QGridLayout(self.groupBoxDeterministic) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.label_9 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_9.setObjectName(_fromUtf8("label_9")) + self.gridLayout.addWidget(self.label_9, 6, 0, 1, 1) + self.label_8 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_8.setObjectName(_fromUtf8("label_8")) + self.gridLayout.addWidget(self.label_8, 5, 0, 1, 3) + self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox(self.groupBoxDeterministic) + self.spinBoxNumberOfAddressesToMake.setMinimum(1) + self.spinBoxNumberOfAddressesToMake.setProperty("value", 8) + self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake")) + self.gridLayout.addWidget(self.spinBoxNumberOfAddressesToMake, 4, 3, 1, 1) + self.label_6 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_6.setObjectName(_fromUtf8("label_6")) + self.gridLayout.addWidget(self.label_6, 0, 0, 1, 1) + self.label_11 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_11.setObjectName(_fromUtf8("label_11")) + self.gridLayout.addWidget(self.label_11, 4, 0, 1, 3) + spacerItem = QtGui.QSpacerItem(73, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 6, 1, 1, 1) + self.label_10 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_10.setObjectName(_fromUtf8("label_10")) + self.gridLayout.addWidget(self.label_10, 6, 2, 1, 1) + spacerItem1 = QtGui.QSpacerItem(42, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 6, 3, 1, 1) + self.label_7 = QtGui.QLabel(self.groupBoxDeterministic) + self.label_7.setObjectName(_fromUtf8("label_7")) + self.gridLayout.addWidget(self.label_7, 2, 0, 1, 1) + self.lineEditPassphraseAgain = QtGui.QLineEdit(self.groupBoxDeterministic) + self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password) + self.lineEditPassphraseAgain.setObjectName(_fromUtf8("lineEditPassphraseAgain")) + self.gridLayout.addWidget(self.lineEditPassphraseAgain, 3, 0, 1, 4) + self.lineEditPassphrase = QtGui.QLineEdit(self.groupBoxDeterministic) + self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText) + self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password) + self.lineEditPassphrase.setObjectName(_fromUtf8("lineEditPassphrase")) + self.gridLayout.addWidget(self.lineEditPassphrase, 1, 0, 1, 4) + self.formLayout.setWidget(8, QtGui.QFormLayout.LabelRole, self.groupBoxDeterministic) + self.groupBox = QtGui.QGroupBox(NewAddressDialog) + self.groupBox.setObjectName(_fromUtf8("groupBox")) + self.gridLayout_2 = QtGui.QGridLayout(self.groupBox) + self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.label_2 = QtGui.QLabel(self.groupBox) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 2) + self.newaddresslabel = QtGui.QLineEdit(self.groupBox) + self.newaddresslabel.setObjectName(_fromUtf8("newaddresslabel")) + self.gridLayout_2.addWidget(self.newaddresslabel, 1, 0, 1, 2) + self.radioButtonMostAvailable = QtGui.QRadioButton(self.groupBox) + self.radioButtonMostAvailable.setChecked(True) + self.radioButtonMostAvailable.setObjectName(_fromUtf8("radioButtonMostAvailable")) + self.gridLayout_2.addWidget(self.radioButtonMostAvailable, 2, 0, 1, 2) + self.label_3 = QtGui.QLabel(self.groupBox) + self.label_3.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout_2.addWidget(self.label_3, 3, 1, 1, 1) + self.radioButtonExisting = QtGui.QRadioButton(self.groupBox) + self.radioButtonExisting.setChecked(False) + self.radioButtonExisting.setObjectName(_fromUtf8("radioButtonExisting")) + self.gridLayout_2.addWidget(self.radioButtonExisting, 4, 0, 1, 2) + self.label_4 = QtGui.QLabel(self.groupBox) + self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.label_4.setObjectName(_fromUtf8("label_4")) + self.gridLayout_2.addWidget(self.label_4, 5, 1, 1, 1) + spacerItem2 = QtGui.QSpacerItem(13, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_2.addItem(spacerItem2, 6, 0, 1, 1) + self.comboBoxExisting = QtGui.QComboBox(self.groupBox) + self.comboBoxExisting.setEnabled(False) + self.comboBoxExisting.setEditable(True) + self.comboBoxExisting.setObjectName(_fromUtf8("comboBoxExisting")) + self.gridLayout_2.addWidget(self.comboBoxExisting, 6, 1, 1, 1) + self.formLayout.setWidget(7, QtGui.QFormLayout.LabelRole, self.groupBox) + self.buttonBox = QtGui.QDialogButtonBox(NewAddressDialog) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox.sizePolicy().hasHeightForWidth()) + self.buttonBox.setSizePolicy(sizePolicy) + self.buttonBox.setMinimumSize(QtCore.QSize(160, 0)) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.formLayout.setWidget(10, QtGui.QFormLayout.SpanningRole, self.buttonBox) + + self.retranslateUi(NewAddressDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewAddressDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), NewAddressDialog.reject) + QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.comboBoxExisting.setEnabled) + QtCore.QObject.connect(self.radioButtonDeterministicAddress, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxDeterministic.setShown) + QtCore.QObject.connect(self.radioButtonRandomAddress, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBox.setShown) + QtCore.QMetaObject.connectSlotsByName(NewAddressDialog) + NewAddressDialog.setTabOrder(self.radioButtonRandomAddress, self.radioButtonDeterministicAddress) + NewAddressDialog.setTabOrder(self.radioButtonDeterministicAddress, self.newaddresslabel) + NewAddressDialog.setTabOrder(self.newaddresslabel, self.radioButtonMostAvailable) + NewAddressDialog.setTabOrder(self.radioButtonMostAvailable, self.radioButtonExisting) + NewAddressDialog.setTabOrder(self.radioButtonExisting, self.comboBoxExisting) + NewAddressDialog.setTabOrder(self.comboBoxExisting, self.lineEditPassphrase) + NewAddressDialog.setTabOrder(self.lineEditPassphrase, self.lineEditPassphraseAgain) + NewAddressDialog.setTabOrder(self.lineEditPassphraseAgain, self.spinBoxNumberOfAddressesToMake) + NewAddressDialog.setTabOrder(self.spinBoxNumberOfAddressesToMake, self.checkBoxEighteenByteRipe) + NewAddressDialog.setTabOrder(self.checkBoxEighteenByteRipe, self.buttonBox) + + def retranslateUi(self, NewAddressDialog): + NewAddressDialog.setWindowTitle(_translate("NewAddressDialog", "Create new Address", None)) + self.label.setText(_translate("NewAddressDialog", "Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a \"deterministic\" address.\n" +"The \'Random Number\' option is selected by default but deterministic addresses have several pros and cons:", None)) + self.label_5.setText(_translate("NewAddressDialog", "

Pros:
You can recreate your addresses on any computer from memory.
You need-not worry about backing up your keys.dat file as long as you can remember your passphrase.
Cons:
You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost.
You must remember the address version number and the stream number along with your passphrase.
If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.

", None)) + self.radioButtonRandomAddress.setText(_translate("NewAddressDialog", "Use a random number generator to make an address", None)) + self.radioButtonDeterministicAddress.setText(_translate("NewAddressDialog", "Use a passphrase to make addresses", None)) + self.checkBoxEighteenByteRipe.setText(_translate("NewAddressDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None)) + self.groupBoxDeterministic.setTitle(_translate("NewAddressDialog", "Make deterministic addresses", None)) + self.label_9.setText(_translate("NewAddressDialog", "Address version number: 4", None)) + self.label_8.setText(_translate("NewAddressDialog", "In addition to your passphrase, you must remember these numbers:", None)) + self.label_6.setText(_translate("NewAddressDialog", "Passphrase", None)) + self.label_11.setText(_translate("NewAddressDialog", "Number of addresses to make based on your passphrase:", None)) + self.label_10.setText(_translate("NewAddressDialog", "Stream number: 1", None)) + self.label_7.setText(_translate("NewAddressDialog", "Retype passphrase", None)) + self.groupBox.setTitle(_translate("NewAddressDialog", "Randomly generate address", None)) + self.label_2.setText(_translate("NewAddressDialog", "Label (not shown to anyone except you)", None)) + self.radioButtonMostAvailable.setText(_translate("NewAddressDialog", "Use the most available stream", None)) + self.label_3.setText(_translate("NewAddressDialog", " (best if this is the first of many addresses you will create)", None)) + self.radioButtonExisting.setText(_translate("NewAddressDialog", "Use the same stream as an existing address", None)) + self.label_4.setText(_translate("NewAddressDialog", "(saves you some bandwidth and processing power)", None)) + diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py deleted file mode 100644 index 2311239c..00000000 --- a/src/bitmessageqt/newaddresswizard.py +++ /dev/null @@ -1,354 +0,0 @@ -#!/usr/bin/env python2.7 -from PyQt4 import QtCore, QtGui - -class NewAddressWizardIntroPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Creating a new address") - - label = QtGui.QLabel("This wizard will help you create as many addresses as you like. Indeed, creating and abandoning addresses is encouraged.\n\n" - "What type of address would you like? Would you like to send emails or not?\n" - "You can still change your mind later, and register/unregister with an email service provider.\n\n") - label.setWordWrap(True) - - self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage address") - self.onlyBM = QtGui.QRadioButton("Bitmessage-only address (no email)") - self.emailAsWell.setChecked(True) - self.registerField("emailAsWell", self.emailAsWell) - self.registerField("onlyBM", self.onlyBM) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - layout.addWidget(self.emailAsWell) - layout.addWidget(self.onlyBM) - self.setLayout(layout) - - def nextId(self): - if self.emailAsWell.isChecked(): - return 4 - else: - return 1 - - -class NewAddressWizardRngPassphrasePage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Random or Passphrase") - - label = QtGui.QLabel("

You may generate addresses by using either random numbers or by using a passphrase. " - "If you use a passphrase, the address is called a "deterministic" address. " - "The \'Random Number\' option is selected by default but deterministic addresses have several pros and cons:

" - "" - "" - "
Pros:Cons:
You can recreate your addresses on any computer from memory. " - "You need-not worry about backing up your keys.dat file as long as you can remember your passphrase.You must remember (or write down) your passphrase if you expect to be able " - "to recreate your keys if they are lost. " -# "You must remember the address version number and the stream number along with your passphrase. " - "If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you." - "

") - label.setWordWrap(True) - - self.randomAddress = QtGui.QRadioButton("Use a random number generator to make an address") - self.deterministicAddress = QtGui.QRadioButton("Use a passphrase to make an address") - self.randomAddress.setChecked(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - layout.addWidget(self.randomAddress) - layout.addWidget(self.deterministicAddress) - self.setLayout(layout) - - def nextId(self): - if self.randomAddress.isChecked(): - return 2 - else: - return 3 - -class NewAddressWizardRandomPage(QtGui.QWizardPage): - def __init__(self, addresses): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Random") - - label = QtGui.QLabel("Random address.") - label.setWordWrap(True) - - labelLabel = QtGui.QLabel("Label (not shown to anyone except you):") - self.labelLineEdit = QtGui.QLineEdit() - - self.radioButtonMostAvailable = QtGui.QRadioButton("Use the most available stream\n" - "(best if this is the first of many addresses you will create)") - self.radioButtonExisting = QtGui.QRadioButton("Use the same stream as an existing address\n" - "(saves you some bandwidth and processing power)") - self.radioButtonMostAvailable.setChecked(True) - self.comboBoxExisting = QtGui.QComboBox() - self.comboBoxExisting.setEnabled(False) - self.comboBoxExisting.setEditable(True) - - for address in addresses: - self.comboBoxExisting.addItem(address) - -# self.comboBoxExisting.setObjectName(_fromUtf8("comboBoxExisting")) - self.checkBoxEighteenByteRipe = QtGui.QCheckBox("Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter") - - layout = QtGui.QGridLayout() - layout.addWidget(label, 0, 0) - layout.addWidget(labelLabel, 1, 0) - layout.addWidget(self.labelLineEdit, 2, 0) - layout.addWidget(self.radioButtonMostAvailable, 3, 0) - layout.addWidget(self.radioButtonExisting, 4, 0) - layout.addWidget(self.comboBoxExisting, 5, 0) - layout.addWidget(self.checkBoxEighteenByteRipe, 6, 0) - self.setLayout(layout) - - QtCore.QObject.connect(self.radioButtonExisting, QtCore.SIGNAL("toggled(bool)"), self.comboBoxExisting.setEnabled) - - self.registerField("label", self.labelLineEdit) - self.registerField("radioButtonMostAvailable", self.radioButtonMostAvailable) - self.registerField("radioButtonExisting", self.radioButtonExisting) - self.registerField("comboBoxExisting", self.comboBoxExisting) - -# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account") -# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)") -# self.emailAsWell.setChecked(True) - - def nextId(self): - return 6 - - -class NewAddressWizardPassphrasePage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Passphrase") - - label = QtGui.QLabel("Deterministric address.") - label.setWordWrap(True) - - passphraseLabel = QtGui.QLabel("Passphrase") - self.lineEditPassphrase = QtGui.QLineEdit() - self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password) - self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText) - retypePassphraseLabel = QtGui.QLabel("Retype passphrase") - self.lineEditPassphraseAgain = QtGui.QLineEdit() - self.lineEditPassphraseAgain.setEchoMode(QtGui.QLineEdit.Password) - - numberLabel = QtGui.QLabel("Number of addresses to make based on your passphrase:") - self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox() - self.spinBoxNumberOfAddressesToMake.setMinimum(1) - self.spinBoxNumberOfAddressesToMake.setProperty("value", 8) -# self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake")) - label2 = QtGui.QLabel("In addition to your passphrase, you must remember these numbers:") - label3 = QtGui.QLabel("Address version number: 4") - label4 = QtGui.QLabel("Stream number: 1") - - layout = QtGui.QGridLayout() - layout.addWidget(label, 0, 0, 1, 4) - layout.addWidget(passphraseLabel, 1, 0, 1, 4) - layout.addWidget(self.lineEditPassphrase, 2, 0, 1, 4) - layout.addWidget(retypePassphraseLabel, 3, 0, 1, 4) - layout.addWidget(self.lineEditPassphraseAgain, 4, 0, 1, 4) - layout.addWidget(numberLabel, 5, 0, 1, 3) - layout.addWidget(self.spinBoxNumberOfAddressesToMake, 5, 3) - layout.setColumnMinimumWidth(3, 1) - layout.addWidget(label2, 6, 0, 1, 4) - layout.addWidget(label3, 7, 0, 1, 2) - layout.addWidget(label4, 7, 2, 1, 2) - self.setLayout(layout) - - def nextId(self): - return 6 - - -class NewAddressWizardEmailProviderPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Choose email provider") - - label = QtGui.QLabel("Currently only Mailchuck email gateway is available " - "(@mailchuck.com email address). In the future, maybe other gateways will be available. " - "Press Next.") - label.setWordWrap(True) - -# self.mailchuck = QtGui.QRadioButton("Mailchuck email gateway (@mailchuck.com)") -# self.mailchuck.setChecked(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) -# layout.addWidget(self.mailchuck) - self.setLayout(layout) - - def nextId(self): - return 5 - - -class NewAddressWizardEmailAddressPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Email address") - - label = QtGui.QLabel("Choosing an email address. Address must end with @mailchuck.com") - label.setWordWrap(True) - - self.specificEmail = QtGui.QRadioButton("Pick your own email address:") - self.specificEmail.setChecked(True) - self.emailLineEdit = QtGui.QLineEdit() - self.randomEmail = QtGui.QRadioButton("Generate a random email address") - - QtCore.QObject.connect(self.specificEmail, QtCore.SIGNAL("toggled(bool)"), self.emailLineEdit.setEnabled) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - layout.addWidget(self.specificEmail) - layout.addWidget(self.emailLineEdit) - layout.addWidget(self.randomEmail) - self.setLayout(layout) - - def nextId(self): - return 6 - - -class NewAddressWizardWaitPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("Wait") - - self.label = QtGui.QLabel("Wait!") - self.label.setWordWrap(True) - self.progressBar = QtGui.QProgressBar() - self.progressBar.setMinimum(0) - self.progressBar.setMaximum(100) - self.progressBar.setValue(0) - -# self.emailAsWell = QtGui.QRadioButton("Combined email and bitmessage account") -# self.onlyBM = QtGui.QRadioButton("Bitmessage-only account (no email)") -# self.emailAsWell.setChecked(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(self.label) - layout.addWidget(self.progressBar) -# layout.addWidget(self.emailAsWell) -# layout.addWidget(self.onlyBM) - self.setLayout(layout) - - def update(self, i): - if i == 101 and self.wizard().currentId() == 6: - self.wizard().button(QtGui.QWizard.NextButton).click() - return - elif i == 101: - print "haha" - return - self.progressBar.setValue(i) - if i == 50: - self.emit(QtCore.SIGNAL('completeChanged()')) - - def isComplete(self): -# print "val = " + str(self.progressBar.value()) - if self.progressBar.value() >= 50: - return True - else: - return False - - def initializePage(self): - if self.field("emailAsWell").toBool(): - val = "yes/" - else: - val = "no/" - if self.field("onlyBM").toBool(): - val += "yes" - else: - val += "no" - - self.label.setText("Wait! " + val) -# self.wizard().button(QtGui.QWizard.NextButton).setEnabled(False) - self.progressBar.setValue(0) - self.thread = NewAddressThread() - self.connect(self.thread, self.thread.signal, self.update) - self.thread.start() - - def nextId(self): - return 10 - - -class NewAddressWizardConclusionPage(QtGui.QWizardPage): - def __init__(self): - super(QtGui.QWizardPage, self).__init__() - self.setTitle("All done!") - - label = QtGui.QLabel("You successfully created a new address.") - label.setWordWrap(True) - - layout = QtGui.QVBoxLayout() - layout.addWidget(label) - self.setLayout(layout) - -class Ui_NewAddressWizard(QtGui.QWizard): - def __init__(self, addresses): - super(QtGui.QWizard, self).__init__() - - self.pages = {} - - page = NewAddressWizardIntroPage() - self.setPage(0, page) - self.setStartId(0) - page = NewAddressWizardRngPassphrasePage() - self.setPage(1, page) - page = NewAddressWizardRandomPage(addresses) - self.setPage(2, page) - page = NewAddressWizardPassphrasePage() - self.setPage(3, page) - page = NewAddressWizardEmailProviderPage() - self.setPage(4, page) - page = NewAddressWizardEmailAddressPage() - self.setPage(5, page) - page = NewAddressWizardWaitPage() - self.setPage(6, page) - page = NewAddressWizardConclusionPage() - self.setPage(10, page) - - self.setWindowTitle("New address wizard") - self.adjustSize() - self.show() - -class NewAddressThread(QtCore.QThread): - def __init__(self): - QtCore.QThread.__init__(self) - self.signal = QtCore.SIGNAL("signal") - - def __del__(self): - self.wait() - - def createDeterministic(self): - pass - - def createPassphrase(self): - pass - - def broadcastAddress(self): - pass - - def registerMailchuck(self): - pass - - def waitRegistration(self): - pass - - def run(self): - import time - for i in range(1, 101): - time.sleep(0.1) # artificial time delay - self.emit(self.signal, i) - self.emit(self.signal, 101) -# self.terminate() - -if __name__ == '__main__': - - import sys - - app = QtGui.QApplication(sys.argv) - - wizard = Ui_NewAddressWizard(["a", "b", "c", "d"]) - if (wizard.exec_()): - print "Email: " + ("yes" if wizard.field("emailAsWell").toBool() else "no") - print "BM: " + ("yes" if wizard.field("onlyBM").toBool() else "no") - else: - print "Wizard cancelled" - sys.exit() diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index ed683b13..65da1f1f 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -1,51 +1,107 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'newchandialog.ui' +# +# Created: Wed Aug 7 16:51:29 2013 +# by: PyQt4 UI code generator 4.10 +# +# WARNING! All changes made in this file will be lost! + from PyQt4 import QtCore, QtGui -from addresses import addBMIfNotPresent -from addressvalidator import AddressValidator, PassPhraseValidator -from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue, UISignalQueue -from retranslateui import RetranslateMixin -from tr import _translate -from utils import str_chan -import widgets +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s -class NewChanDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(NewChanDialog, self).__init__(parent) - widgets.load('newchandialog.ui', self) - self.parent = parent - self.chanAddress.setValidator(AddressValidator(self.chanAddress, self.chanPassPhrase, self.validatorFeedback, self.buttonBox, False)) - self.chanPassPhrase.setValidator(PassPhraseValidator(self.chanPassPhrase, self.chanAddress, self.validatorFeedback, self.buttonBox, False)) +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) - self.timer = QtCore.QTimer() - QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.delayedUpdateStatus) - self.timer.start(500) # milliseconds - self.setAttribute(QtCore.Qt.WA_DeleteOnClose) - self.show() +class Ui_newChanDialog(object): + def setupUi(self, newChanDialog): + newChanDialog.setObjectName(_fromUtf8("newChanDialog")) + newChanDialog.resize(553, 422) + newChanDialog.setMinimumSize(QtCore.QSize(0, 0)) + self.formLayout = QtGui.QFormLayout(newChanDialog) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.radioButtonCreateChan = QtGui.QRadioButton(newChanDialog) + self.radioButtonCreateChan.setObjectName(_fromUtf8("radioButtonCreateChan")) + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.radioButtonCreateChan) + self.radioButtonJoinChan = QtGui.QRadioButton(newChanDialog) + self.radioButtonJoinChan.setChecked(True) + self.radioButtonJoinChan.setObjectName(_fromUtf8("radioButtonJoinChan")) + self.formLayout.setWidget(1, QtGui.QFormLayout.LabelRole, self.radioButtonJoinChan) + self.groupBoxCreateChan = QtGui.QGroupBox(newChanDialog) + self.groupBoxCreateChan.setObjectName(_fromUtf8("groupBoxCreateChan")) + self.gridLayout = QtGui.QGridLayout(self.groupBoxCreateChan) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.label_4 = QtGui.QLabel(self.groupBoxCreateChan) + self.label_4.setWordWrap(True) + self.label_4.setObjectName(_fromUtf8("label_4")) + self.gridLayout.addWidget(self.label_4, 0, 0, 1, 1) + self.label_5 = QtGui.QLabel(self.groupBoxCreateChan) + self.label_5.setObjectName(_fromUtf8("label_5")) + self.gridLayout.addWidget(self.label_5, 1, 0, 1, 1) + self.lineEditChanNameCreate = QtGui.QLineEdit(self.groupBoxCreateChan) + self.lineEditChanNameCreate.setObjectName(_fromUtf8("lineEditChanNameCreate")) + self.gridLayout.addWidget(self.lineEditChanNameCreate, 2, 0, 1, 1) + self.formLayout.setWidget(2, QtGui.QFormLayout.SpanningRole, self.groupBoxCreateChan) + self.groupBoxJoinChan = QtGui.QGroupBox(newChanDialog) + self.groupBoxJoinChan.setObjectName(_fromUtf8("groupBoxJoinChan")) + self.gridLayout_2 = QtGui.QGridLayout(self.groupBoxJoinChan) + self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.label = QtGui.QLabel(self.groupBoxJoinChan) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtGui.QLabel(self.groupBoxJoinChan) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1) + self.lineEditChanNameJoin = QtGui.QLineEdit(self.groupBoxJoinChan) + self.lineEditChanNameJoin.setObjectName(_fromUtf8("lineEditChanNameJoin")) + self.gridLayout_2.addWidget(self.lineEditChanNameJoin, 2, 0, 1, 1) + self.label_3 = QtGui.QLabel(self.groupBoxJoinChan) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout_2.addWidget(self.label_3, 3, 0, 1, 1) + self.lineEditChanBitmessageAddress = QtGui.QLineEdit(self.groupBoxJoinChan) + self.lineEditChanBitmessageAddress.setObjectName(_fromUtf8("lineEditChanBitmessageAddress")) + self.gridLayout_2.addWidget(self.lineEditChanBitmessageAddress, 4, 0, 1, 1) + self.formLayout.setWidget(3, QtGui.QFormLayout.SpanningRole, self.groupBoxJoinChan) + spacerItem = QtGui.QSpacerItem(389, 2, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) + self.formLayout.setItem(4, QtGui.QFormLayout.FieldRole, spacerItem) + self.buttonBox = QtGui.QDialogButtonBox(newChanDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.formLayout.setWidget(5, QtGui.QFormLayout.FieldRole, self.buttonBox) - def delayedUpdateStatus(self): - self.chanPassPhrase.validator().checkQueue() + self.retranslateUi(newChanDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), newChanDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), newChanDialog.reject) + QtCore.QObject.connect(self.radioButtonJoinChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxJoinChan.setShown) + QtCore.QObject.connect(self.radioButtonCreateChan, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.groupBoxCreateChan.setShown) + QtCore.QMetaObject.connectSlotsByName(newChanDialog) + newChanDialog.setTabOrder(self.radioButtonJoinChan, self.radioButtonCreateChan) + newChanDialog.setTabOrder(self.radioButtonCreateChan, self.lineEditChanNameCreate) + newChanDialog.setTabOrder(self.lineEditChanNameCreate, self.lineEditChanNameJoin) + newChanDialog.setTabOrder(self.lineEditChanNameJoin, self.lineEditChanBitmessageAddress) + newChanDialog.setTabOrder(self.lineEditChanBitmessageAddress, self.buttonBox) - def accept(self): - self.timer.stop() - self.hide() - apiAddressGeneratorReturnQueue.queue.clear() - if self.chanAddress.text().toUtf8() == "": - addressGeneratorQueue.put(('createChan', 4, 1, str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()), self.chanPassPhrase.text().toUtf8(), True)) - else: - addressGeneratorQueue.put(('joinChan', addBMIfNotPresent(self.chanAddress.text().toUtf8()), str_chan + ' ' + str(self.chanPassPhrase.text().toUtf8()), self.chanPassPhrase.text().toUtf8(), True)) - addressGeneratorReturnValue = apiAddressGeneratorReturnQueue.get(True) - if len(addressGeneratorReturnValue) > 0 and addressGeneratorReturnValue[0] != 'chan name does not match address': - UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Successfully created / joined chan %1").arg(unicode(self.chanPassPhrase.text())))) - self.parent.ui.tabWidget.setCurrentIndex( - self.parent.ui.tabWidget.indexOf(self.parent.ui.chans) - ) - self.done(QtGui.QDialog.Accepted) - else: - UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining failed"))) - self.done(QtGui.QDialog.Rejected) + def retranslateUi(self, newChanDialog): + newChanDialog.setWindowTitle(_translate("newChanDialog", "Dialog", None)) + self.radioButtonCreateChan.setText(_translate("newChanDialog", "Create a new chan", None)) + self.radioButtonJoinChan.setText(_translate("newChanDialog", "Join a chan", None)) + self.groupBoxCreateChan.setTitle(_translate("newChanDialog", "Create a chan", None)) + self.label_4.setText(_translate("newChanDialog", "

Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.

", None)) + self.label_5.setText(_translate("newChanDialog", "Chan name:", None)) + self.groupBoxJoinChan.setTitle(_translate("newChanDialog", "Join a chan", None)) + self.label.setText(_translate("newChanDialog", "

A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.

Chans are experimental and completely unmoderatable.

", None)) + self.label_2.setText(_translate("newChanDialog", "Chan name:", None)) + self.label_3.setText(_translate("newChanDialog", "Chan bitmessage address:", None)) - def reject(self): - self.timer.stop() - self.hide() - UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining cancelled"))) - self.done(QtGui.QDialog.Rejected) diff --git a/src/bitmessageqt/newchandialog.ui b/src/bitmessageqt/newchandialog.ui index 59dbb2bb..2d42b3db 100644 --- a/src/bitmessageqt/newchandialog.ui +++ b/src/bitmessageqt/newchandialog.ui @@ -6,16 +6,10 @@ 0 0 - 473 - 444 + 553 + 422 - - - 0 - 0 - - 0 @@ -23,90 +17,127 @@ - Create or join a chan + Dialog - - - - - - - 0 - 0 - - + - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> + Create a new chan - + + + + + + Join a chan + + true - - - - - - - - - Chan passphrase/name: - - - - - - - Optional, for advanced usage - - - - - - - - 0 - 0 - - - - Chan address - - - - + + + + Create a chan + + + + + + <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> + + + true + + + + + + + Chan name: + + + + + + + + + + + + + Join a chan + + + + + + <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> + + + true + + + + + + + Chan name: + + + + + + + + + + Chan bitmessage address: + + + + + + + + + + + Qt::Vertical + + + + 389 + 2 + + + + + + + Qt::Horizontal + QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - false - - - - - - - - 0 - 0 - - - - Please input chan name/passphrase: - - - true - + + radioButtonJoinChan + radioButtonCreateChan + lineEditChanNameCreate + lineEditChanNameJoin + lineEditChanBitmessageAddress + buttonBox + @@ -116,12 +147,12 @@ accept() - 240 - 372 + 428 + 454 - 236 - 221 + 157 + 274 @@ -132,12 +163,44 @@ reject() - 240 - 372 + 430 + 460 - 236 - 221 + 286 + 274 + + + + + radioButtonJoinChan + toggled(bool) + groupBoxJoinChan + setShown(bool) + + + 74 + 49 + + + 96 + 227 + + + + + radioButtonCreateChan + toggled(bool) + groupBoxCreateChan + setShown(bool) + + + 72 + 28 + + + 65 + 92 diff --git a/src/bitmessageqt/newsubscriptiondialog.py b/src/bitmessageqt/newsubscriptiondialog.py new file mode 100644 index 00000000..d71eec0c --- /dev/null +++ b/src/bitmessageqt/newsubscriptiondialog.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'newsubscriptiondialog.ui' +# +# Created: Sat Nov 30 21:53:38 2013 +# by: PyQt4 UI code generator 4.10.3 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_NewSubscriptionDialog(object): + def setupUi(self, NewSubscriptionDialog): + NewSubscriptionDialog.setObjectName(_fromUtf8("NewSubscriptionDialog")) + NewSubscriptionDialog.resize(368, 173) + self.formLayout = QtGui.QFormLayout(NewSubscriptionDialog) + self.formLayout.setObjectName(_fromUtf8("formLayout")) + self.label_2 = QtGui.QLabel(NewSubscriptionDialog) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.label_2) + self.newsubscriptionlabel = QtGui.QLineEdit(NewSubscriptionDialog) + self.newsubscriptionlabel.setObjectName(_fromUtf8("newsubscriptionlabel")) + self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.newsubscriptionlabel) + self.label = QtGui.QLabel(NewSubscriptionDialog) + self.label.setObjectName(_fromUtf8("label")) + self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.label) + self.lineEditSubscriptionAddress = QtGui.QLineEdit(NewSubscriptionDialog) + self.lineEditSubscriptionAddress.setObjectName(_fromUtf8("lineEditSubscriptionAddress")) + self.formLayout.setWidget(3, QtGui.QFormLayout.SpanningRole, self.lineEditSubscriptionAddress) + self.labelAddressCheck = QtGui.QLabel(NewSubscriptionDialog) + self.labelAddressCheck.setText(_fromUtf8("")) + self.labelAddressCheck.setWordWrap(True) + self.labelAddressCheck.setObjectName(_fromUtf8("labelAddressCheck")) + self.formLayout.setWidget(4, QtGui.QFormLayout.SpanningRole, self.labelAddressCheck) + self.checkBoxDisplayMessagesAlreadyInInventory = QtGui.QCheckBox(NewSubscriptionDialog) + self.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(False) + self.checkBoxDisplayMessagesAlreadyInInventory.setObjectName(_fromUtf8("checkBoxDisplayMessagesAlreadyInInventory")) + self.formLayout.setWidget(5, QtGui.QFormLayout.SpanningRole, self.checkBoxDisplayMessagesAlreadyInInventory) + self.buttonBox = QtGui.QDialogButtonBox(NewSubscriptionDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.formLayout.setWidget(6, QtGui.QFormLayout.FieldRole, self.buttonBox) + + self.retranslateUi(NewSubscriptionDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), NewSubscriptionDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), NewSubscriptionDialog.reject) + QtCore.QMetaObject.connectSlotsByName(NewSubscriptionDialog) + + def retranslateUi(self, NewSubscriptionDialog): + NewSubscriptionDialog.setWindowTitle(_translate("NewSubscriptionDialog", "Add new entry", None)) + self.label_2.setText(_translate("NewSubscriptionDialog", "Label", None)) + self.label.setText(_translate("NewSubscriptionDialog", "Address", None)) + self.checkBoxDisplayMessagesAlreadyInInventory.setText(_translate("NewSubscriptionDialog", "CheckBox", None)) + diff --git a/src/bitmessageqt/newsubscriptiondialog.ui b/src/bitmessageqt/newsubscriptiondialog.ui index ec67efa3..ed8615f4 100644 --- a/src/bitmessageqt/newsubscriptiondialog.ui +++ b/src/bitmessageqt/newsubscriptiondialog.ui @@ -7,15 +7,9 @@ 0 0 368 - 254 + 173 - - - 368 - 200 - - Add new entry @@ -28,7 +22,7 @@ - + @@ -38,7 +32,7 @@ - + @@ -50,17 +44,17 @@ - + false - Enter an address above. + CheckBox - + Qt::Horizontal @@ -70,19 +64,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/src/bitmessageqt/regenerateaddresses.py b/src/bitmessageqt/regenerateaddresses.py new file mode 100644 index 00000000..7129b632 --- /dev/null +++ b/src/bitmessageqt/regenerateaddresses.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'regenerateaddresses.ui' +# +# Created: Sun Sep 15 23:50:23 2013 +# by: PyQt4 UI code generator 4.10.2 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + def _fromUtf8(s): + return s + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig, _encoding) +except AttributeError: + def _translate(context, text, disambig): + return QtGui.QApplication.translate(context, text, disambig) + +class Ui_regenerateAddressesDialog(object): + def setupUi(self, regenerateAddressesDialog): + regenerateAddressesDialog.setObjectName(_fromUtf8("regenerateAddressesDialog")) + regenerateAddressesDialog.resize(532, 332) + self.gridLayout_2 = QtGui.QGridLayout(regenerateAddressesDialog) + self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) + self.buttonBox = QtGui.QDialogButtonBox(regenerateAddressesDialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.gridLayout_2.addWidget(self.buttonBox, 1, 0, 1, 1) + self.groupBox = QtGui.QGroupBox(regenerateAddressesDialog) + self.groupBox.setObjectName(_fromUtf8("groupBox")) + self.gridLayout = QtGui.QGridLayout(self.groupBox) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.label_6 = QtGui.QLabel(self.groupBox) + self.label_6.setObjectName(_fromUtf8("label_6")) + self.gridLayout.addWidget(self.label_6, 1, 0, 1, 1) + self.lineEditPassphrase = QtGui.QLineEdit(self.groupBox) + self.lineEditPassphrase.setInputMethodHints(QtCore.Qt.ImhHiddenText|QtCore.Qt.ImhNoAutoUppercase|QtCore.Qt.ImhNoPredictiveText) + self.lineEditPassphrase.setEchoMode(QtGui.QLineEdit.Password) + self.lineEditPassphrase.setObjectName(_fromUtf8("lineEditPassphrase")) + self.gridLayout.addWidget(self.lineEditPassphrase, 2, 0, 1, 5) + self.label_11 = QtGui.QLabel(self.groupBox) + self.label_11.setObjectName(_fromUtf8("label_11")) + self.gridLayout.addWidget(self.label_11, 3, 0, 1, 3) + self.spinBoxNumberOfAddressesToMake = QtGui.QSpinBox(self.groupBox) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.spinBoxNumberOfAddressesToMake.sizePolicy().hasHeightForWidth()) + self.spinBoxNumberOfAddressesToMake.setSizePolicy(sizePolicy) + self.spinBoxNumberOfAddressesToMake.setMinimum(1) + self.spinBoxNumberOfAddressesToMake.setProperty("value", 8) + self.spinBoxNumberOfAddressesToMake.setObjectName(_fromUtf8("spinBoxNumberOfAddressesToMake")) + self.gridLayout.addWidget(self.spinBoxNumberOfAddressesToMake, 3, 3, 1, 1) + spacerItem = QtGui.QSpacerItem(132, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem, 3, 4, 1, 1) + self.label_2 = QtGui.QLabel(self.groupBox) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout.addWidget(self.label_2, 4, 0, 1, 1) + self.lineEditAddressVersionNumber = QtGui.QLineEdit(self.groupBox) + self.lineEditAddressVersionNumber.setEnabled(True) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEditAddressVersionNumber.sizePolicy().hasHeightForWidth()) + self.lineEditAddressVersionNumber.setSizePolicy(sizePolicy) + self.lineEditAddressVersionNumber.setMaximumSize(QtCore.QSize(31, 16777215)) + self.lineEditAddressVersionNumber.setText(_fromUtf8("")) + self.lineEditAddressVersionNumber.setObjectName(_fromUtf8("lineEditAddressVersionNumber")) + self.gridLayout.addWidget(self.lineEditAddressVersionNumber, 4, 1, 1, 1) + spacerItem1 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem1, 4, 2, 1, 1) + self.label_3 = QtGui.QLabel(self.groupBox) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout.addWidget(self.label_3, 5, 0, 1, 1) + self.lineEditStreamNumber = QtGui.QLineEdit(self.groupBox) + self.lineEditStreamNumber.setEnabled(False) + sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEditStreamNumber.sizePolicy().hasHeightForWidth()) + self.lineEditStreamNumber.setSizePolicy(sizePolicy) + self.lineEditStreamNumber.setMaximumSize(QtCore.QSize(31, 16777215)) + self.lineEditStreamNumber.setObjectName(_fromUtf8("lineEditStreamNumber")) + self.gridLayout.addWidget(self.lineEditStreamNumber, 5, 1, 1, 1) + spacerItem2 = QtGui.QSpacerItem(325, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout.addItem(spacerItem2, 5, 2, 1, 3) + self.checkBoxEighteenByteRipe = QtGui.QCheckBox(self.groupBox) + self.checkBoxEighteenByteRipe.setObjectName(_fromUtf8("checkBoxEighteenByteRipe")) + self.gridLayout.addWidget(self.checkBoxEighteenByteRipe, 6, 0, 1, 5) + self.label_4 = QtGui.QLabel(self.groupBox) + self.label_4.setWordWrap(True) + self.label_4.setObjectName(_fromUtf8("label_4")) + self.gridLayout.addWidget(self.label_4, 7, 0, 1, 5) + self.label = QtGui.QLabel(self.groupBox) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout.addWidget(self.label, 0, 0, 1, 5) + self.gridLayout_2.addWidget(self.groupBox, 0, 0, 1, 1) + + self.retranslateUi(regenerateAddressesDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), regenerateAddressesDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), regenerateAddressesDialog.reject) + QtCore.QMetaObject.connectSlotsByName(regenerateAddressesDialog) + + def retranslateUi(self, regenerateAddressesDialog): + regenerateAddressesDialog.setWindowTitle(_translate("regenerateAddressesDialog", "Regenerate Existing Addresses", None)) + self.groupBox.setTitle(_translate("regenerateAddressesDialog", "Regenerate existing addresses", None)) + self.label_6.setText(_translate("regenerateAddressesDialog", "Passphrase", None)) + self.label_11.setText(_translate("regenerateAddressesDialog", "Number of addresses to make based on your passphrase:", None)) + self.label_2.setText(_translate("regenerateAddressesDialog", "Address version number:", None)) + self.label_3.setText(_translate("regenerateAddressesDialog", "Stream number:", None)) + self.lineEditStreamNumber.setText(_translate("regenerateAddressesDialog", "1", None)) + self.checkBoxEighteenByteRipe.setText(_translate("regenerateAddressesDialog", "Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter", None)) + self.label_4.setText(_translate("regenerateAddressesDialog", "You must check (or not check) this box just like you did (or didn\'t) when you made your addresses the first time.", None)) + self.label.setText(_translate("regenerateAddressesDialog", "If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you.", None)) + diff --git a/src/bitmessageqt/retranslateui.py b/src/bitmessageqt/retranslateui.py deleted file mode 100644 index e9d5bb3a..00000000 --- a/src/bitmessageqt/retranslateui.py +++ /dev/null @@ -1,18 +0,0 @@ -from os import path -from PyQt4 import QtGui -from debug import logger -import widgets - -class RetranslateMixin(object): - def retranslateUi(self): - defaults = QtGui.QWidget() - widgets.load(self.__class__.__name__.lower() + '.ui', defaults) - for attr, value in defaults.__dict__.iteritems(): - setTextMethod = getattr(value, "setText", None) - if callable(setTextMethod): - getattr(self, attr).setText(getattr(defaults, attr).text()) - elif isinstance(value, QtGui.QTableWidget): - for i in range (value.columnCount()): - getattr(self, attr).horizontalHeaderItem(i).setText(getattr(defaults, attr).horizontalHeaderItem(i).text()) - for i in range (value.rowCount()): - getattr(self, attr).verticalHeaderItem(i).setText(getattr(defaults, attr).verticalHeaderItem(i).text()) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py deleted file mode 100644 index d1d7910c..00000000 --- a/src/bitmessageqt/safehtmlparser.py +++ /dev/null @@ -1,122 +0,0 @@ -from HTMLParser import HTMLParser -import inspect -import re -from urllib import quote, quote_plus -from urlparse import urlparse - -class SafeHTMLParser(HTMLParser): - # from html5lib.sanitiser - acceptable_elements = ['a', 'abbr', 'acronym', 'address', 'area', - 'article', 'aside', 'audio', 'b', 'big', 'blockquote', 'br', 'button', - 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', - 'command', 'datagrid', 'datalist', 'dd', 'del', 'details', 'dfn', - 'dialog', 'dir', 'div', 'dl', 'dt', 'em', 'event-source', 'fieldset', - 'figcaption', 'figure', 'footer', 'font', 'header', 'h1', - 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins', - 'keygen', 'kbd', 'label', 'legend', 'li', 'm', 'map', 'menu', 'meter', - 'multicol', 'nav', 'nextid', 'ol', 'output', 'optgroup', 'option', - 'p', 'pre', 'progress', 'q', 's', 'samp', 'section', 'select', - 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', - 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', - 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] - replaces_pre = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"]] - replaces_post = [["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] - src_schemes = [ "data" ] - #uriregex1 = re.compile(r'(?i)\b((?:(https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?]))') - uriregex1 = re.compile(r'((https?|ftp|bitcoin):(?:/{1,3}|[a-z0-9%])(?:[a-zA-Z]|[0-9]|[$-_@.&+#]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)') - uriregex2 = re.compile(r' 1 and text[0] == " ": - text = " " + text[1:] - return text - - def __init__(self, *args, **kwargs): - HTMLParser.__init__(self, *args, **kwargs) - self.reset_safe() - - def reset_safe(self): - self.elements = set() - self.raw = u"" - self.sanitised = u"" - self.has_html = False - self.allow_picture = False - self.allow_external_src = False - - def add_if_acceptable(self, tag, attrs = None): - if tag not in SafeHTMLParser.acceptable_elements: - return - self.sanitised += "<" - if inspect.stack()[1][3] == "handle_endtag": - self.sanitised += "/" - self.sanitised += tag - if attrs is not None: - for attr, val in attrs: - if tag == "img" and attr == "src" and not self.allow_picture: - val = "" - elif attr == "src" and not self.allow_external_src: - url = urlparse(val) - if url.scheme not in SafeHTMLParser.src_schemes: - val = "" - self.sanitised += " " + quote_plus(attr) - if not (val is None): - self.sanitised += "=\"" + val + "\"" - if inspect.stack()[1][3] == "handle_startendtag": - self.sanitised += "/" - self.sanitised += ">" - - def handle_starttag(self, tag, attrs): - if tag in SafeHTMLParser.acceptable_elements: - self.has_html = True - self.add_if_acceptable(tag, attrs) - - def handle_endtag(self, tag): - self.add_if_acceptable(tag) - - def handle_startendtag(self, tag, attrs): - if tag in SafeHTMLParser.acceptable_elements: - self.has_html = True - self.add_if_acceptable(tag, attrs) - - def handle_data(self, data): - self.sanitised += data - - def handle_charref(self, name): - self.sanitised += "&#" + name + ";" - - def handle_entityref(self, name): - self.sanitised += "&" + name + ";" - - def feed(self, data): - try: - data = unicode(data, 'utf-8') - except UnicodeDecodeError: - data = unicode(data, 'utf-8', errors='replace') - HTMLParser.feed(self, data) - tmp = SafeHTMLParser.replace_pre(data) - tmp = SafeHTMLParser.uriregex1.sub( - r'\1', - tmp) - tmp = SafeHTMLParser.uriregex2.sub(r'\1', tmp) - tmp = SafeHTMLParser.replace_post(tmp) - self.raw += tmp - - def is_html(self, text = None, allow_picture = False): - if text: - self.reset() - self.reset_safe() - self.allow_picture = allow_picture - self.feed(text) - self.close() - return self.has_html diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 4342fd09..6d854773 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -8,8 +8,6 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -from languagebox import LanguageBox -from sys import platform try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -46,26 +44,13 @@ class Ui_settingsDialog(object): self.checkBoxStartOnLogon = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxStartOnLogon.setObjectName(_fromUtf8("checkBoxStartOnLogon")) self.formLayout.setWidget(0, QtGui.QFormLayout.LabelRole, self.checkBoxStartOnLogon) - self.groupBoxTray = QtGui.QGroupBox(self.tabUserInterface) - self.groupBoxTray.setObjectName(_fromUtf8("groupBoxTray")) - self.formLayoutTray = QtGui.QFormLayout(self.groupBoxTray) - self.formLayoutTray.setObjectName(_fromUtf8("formLayoutTray")) - self.checkBoxStartInTray = QtGui.QCheckBox(self.groupBoxTray) + self.checkBoxStartInTray = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxStartInTray.setObjectName(_fromUtf8("checkBoxStartInTray")) - self.formLayoutTray.setWidget(0, QtGui.QFormLayout.SpanningRole, self.checkBoxStartInTray) - self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.groupBoxTray) + self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.checkBoxStartInTray) + self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxMinimizeToTray.setChecked(True) self.checkBoxMinimizeToTray.setObjectName(_fromUtf8("checkBoxMinimizeToTray")) - self.formLayoutTray.setWidget(1, QtGui.QFormLayout.LabelRole, self.checkBoxMinimizeToTray) - self.checkBoxTrayOnClose = QtGui.QCheckBox(self.groupBoxTray) - self.checkBoxTrayOnClose.setChecked(True) - self.checkBoxTrayOnClose.setObjectName(_fromUtf8("checkBoxTrayOnClose")) - self.formLayoutTray.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxTrayOnClose) - self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.groupBoxTray) - self.checkBoxHideTrayConnectionNotifications = QtGui.QCheckBox(self.tabUserInterface) - self.checkBoxHideTrayConnectionNotifications.setChecked(False) - self.checkBoxHideTrayConnectionNotifications.setObjectName(_fromUtf8("checkBoxHideTrayConnectionNotifications")) - self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxHideTrayConnectionNotifications) + self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.checkBoxMinimizeToTray) self.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications")) self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.checkBoxShowTrayNotifications) @@ -94,9 +79,36 @@ class Ui_settingsDialog(object): self.groupBox.setObjectName(_fromUtf8("groupBox")) self.formLayout_2 = QtGui.QFormLayout(self.groupBox) self.formLayout_2.setObjectName(_fromUtf8("formLayout_2")) - self.languageComboBox = LanguageBox(self.groupBox) + self.languageComboBox = QtGui.QComboBox(self.groupBox) self.languageComboBox.setMinimumSize(QtCore.QSize(100, 0)) self.languageComboBox.setObjectName(_fromUtf8("languageComboBox")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(1, _fromUtf8("English")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(2, _fromUtf8("Esperanto")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(3, _fromUtf8("Français")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(4, _fromUtf8("Deutsch")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(5, _fromUtf8("Españl")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(6, _fromUtf8("русский")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(7, _fromUtf8("Norsk")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(8, _fromUtf8("العربية")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(9, _fromUtf8("简体中文")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(10, _fromUtf8("日本語")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(11, _fromUtf8("Nederlands")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.setItemText(12, _fromUtf8("Česky")) + self.languageComboBox.addItem(_fromUtf8("")) + self.languageComboBox.addItem(_fromUtf8("")) self.formLayout_2.setWidget(0, QtGui.QFormLayout.LabelRole, self.languageComboBox) self.formLayout.setWidget(9, QtGui.QFormLayout.FieldRole, self.groupBox) self.tabWidgetSettings.addTab(self.tabUserInterface, _fromUtf8("")) @@ -108,21 +120,15 @@ class Ui_settingsDialog(object): self.groupBox1.setObjectName(_fromUtf8("groupBox1")) self.gridLayout_3 = QtGui.QGridLayout(self.groupBox1) self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - #spacerItem = QtGui.QSpacerItem(125, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - #self.gridLayout_3.addItem(spacerItem, 0, 0, 1, 1) + spacerItem = QtGui.QSpacerItem(125, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_3.addItem(spacerItem, 0, 0, 1, 1) self.label = QtGui.QLabel(self.groupBox1) self.label.setObjectName(_fromUtf8("label")) - self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1, QtCore.Qt.AlignRight) + self.gridLayout_3.addWidget(self.label, 0, 1, 1, 1) self.lineEditTCPPort = QtGui.QLineEdit(self.groupBox1) self.lineEditTCPPort.setMaximumSize(QtCore.QSize(70, 16777215)) self.lineEditTCPPort.setObjectName(_fromUtf8("lineEditTCPPort")) - self.gridLayout_3.addWidget(self.lineEditTCPPort, 0, 1, 1, 1, QtCore.Qt.AlignLeft) - self.labelUPnP = QtGui.QLabel(self.groupBox1) - self.labelUPnP.setObjectName(_fromUtf8("labelUPnP")) - self.gridLayout_3.addWidget(self.labelUPnP, 0, 2, 1, 1, QtCore.Qt.AlignRight) - self.checkBoxUPnP = QtGui.QCheckBox(self.groupBox1) - self.checkBoxUPnP.setObjectName(_fromUtf8("checkBoxUPnP")) - self.gridLayout_3.addWidget(self.checkBoxUPnP, 0, 3, 1, 1, QtCore.Qt.AlignLeft) + self.gridLayout_3.addWidget(self.lineEditTCPPort, 0, 2, 1, 1) self.gridLayout_4.addWidget(self.groupBox1, 0, 0, 1, 1) self.groupBox_3 = QtGui.QGroupBox(self.tabNetworkSettings) self.groupBox_3.setObjectName(_fromUtf8("groupBox_3")) @@ -154,19 +160,6 @@ class Ui_settingsDialog(object): self.lineEditMaxUploadRate.setMaximumSize(QtCore.QSize(60, 16777215)) self.lineEditMaxUploadRate.setObjectName(_fromUtf8("lineEditMaxUploadRate")) self.gridLayout_9.addWidget(self.lineEditMaxUploadRate, 1, 2, 1, 1) - self.label_26 = QtGui.QLabel(self.groupBox_3) - self.label_26.setObjectName(_fromUtf8("label_26")) - self.gridLayout_9.addWidget(self.label_26, 2, 1, 1, 1) - self.lineEditMaxOutboundConnections = QtGui.QLineEdit(self.groupBox_3) - sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lineEditMaxOutboundConnections.sizePolicy().hasHeightForWidth()) - self.lineEditMaxOutboundConnections.setSizePolicy(sizePolicy) - self.lineEditMaxOutboundConnections.setMaximumSize(QtCore.QSize(60, 16777215)) - self.lineEditMaxOutboundConnections.setObjectName(_fromUtf8("lineEditMaxOutboundConnections")) - self.lineEditMaxOutboundConnections.setValidator(QtGui.QIntValidator(0, 8, self.lineEditMaxOutboundConnections)) - self.gridLayout_9.addWidget(self.lineEditMaxOutboundConnections, 2, 2, 1, 1) self.gridLayout_4.addWidget(self.groupBox_3, 2, 0, 1, 1) self.groupBox_2 = QtGui.QGroupBox(self.tabNetworkSettings) self.groupBox_2.setObjectName(_fromUtf8("groupBox_2")) @@ -180,17 +173,12 @@ class Ui_settingsDialog(object): self.gridLayout_2.addWidget(self.label_3, 1, 1, 1, 1) self.lineEditSocksHostname = QtGui.QLineEdit(self.groupBox_2) self.lineEditSocksHostname.setObjectName(_fromUtf8("lineEditSocksHostname")) - self.lineEditSocksHostname.setPlaceholderText(_fromUtf8("127.0.0.1")) self.gridLayout_2.addWidget(self.lineEditSocksHostname, 1, 2, 1, 2) self.label_4 = QtGui.QLabel(self.groupBox_2) self.label_4.setObjectName(_fromUtf8("label_4")) self.gridLayout_2.addWidget(self.label_4, 1, 4, 1, 1) self.lineEditSocksPort = QtGui.QLineEdit(self.groupBox_2) self.lineEditSocksPort.setObjectName(_fromUtf8("lineEditSocksPort")) - if platform in ['darwin', 'win32', 'win64']: - self.lineEditSocksPort.setPlaceholderText(_fromUtf8("9150")) - else: - self.lineEditSocksPort.setPlaceholderText(_fromUtf8("9050")) self.gridLayout_2.addWidget(self.lineEditSocksPort, 1, 5, 1, 1) self.checkBoxAuthentication = QtGui.QCheckBox(self.groupBox_2) self.checkBoxAuthentication.setObjectName(_fromUtf8("checkBoxAuthentication")) @@ -314,12 +302,6 @@ class Ui_settingsDialog(object): self.gridLayout_7.addWidget(self.lineEditMaxAcceptableSmallMessageDifficulty, 2, 2, 1, 1) spacerItem8 = QtGui.QSpacerItem(20, 147, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) self.gridLayout_7.addItem(spacerItem8, 3, 1, 1, 1) - self.labelOpenCL = QtGui.QLabel(self.tabMaxAcceptableDifficulty) - self.labelOpenCL.setObjectName(_fromUtf8("labelOpenCL")) - self.gridLayout_7.addWidget(self.labelOpenCL, 4, 0, 1, 1) - self.comboBoxOpenCL = QtGui.QComboBox(self.tabMaxAcceptableDifficulty) - self.comboBoxOpenCL.setObjectName = (_fromUtf8("comboBoxOpenCL")) - self.gridLayout_7.addWidget(self.comboBoxOpenCL, 4, 1, 1, 1) self.tabWidgetSettings.addTab(self.tabMaxAcceptableDifficulty, _fromUtf8("")) self.tabNamecoin = QtGui.QWidget() self.tabNamecoin.setObjectName(_fromUtf8("tabNamecoin")) @@ -452,11 +434,8 @@ class Ui_settingsDialog(object): def retranslateUi(self, settingsDialog): settingsDialog.setWindowTitle(_translate("settingsDialog", "Settings", None)) self.checkBoxStartOnLogon.setText(_translate("settingsDialog", "Start Bitmessage on user login", None)) - self.groupBoxTray.setTitle(_translate("settingsDialog", "Tray", None)) self.checkBoxStartInTray.setText(_translate("settingsDialog", "Start Bitmessage in the tray (don\'t show main window)", None)) self.checkBoxMinimizeToTray.setText(_translate("settingsDialog", "Minimize to tray", None)) - self.checkBoxTrayOnClose.setText(_translate("settingsDialog", "Close to tray", None)) - self.checkBoxHideTrayConnectionNotifications.setText(_translate("settingsDialog", "Hide connection notifications", None)) self.checkBoxShowTrayNotifications.setText(_translate("settingsDialog", "Show notification when message received", None)) self.checkBoxPortableMode.setText(_translate("settingsDialog", "Run in Portable Mode", None)) self.PortableModeDescription.setText(_translate("settingsDialog", "In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive.", None)) @@ -465,14 +444,14 @@ class Ui_settingsDialog(object): self.checkBoxReplyBelow.setText(_translate("settingsDialog", "Reply below Quote", None)) self.groupBox.setTitle(_translate("settingsDialog", "Interface Language", None)) self.languageComboBox.setItemText(0, _translate("settingsDialog", "System Settings", "system")) + self.languageComboBox.setItemText(13, _translate("settingsDialog", "Pirate English", "en_pirate")) + self.languageComboBox.setItemText(14, _translate("settingsDialog", "Other (set in keys.dat)", "other")) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabUserInterface), _translate("settingsDialog", "User Interface", None)) self.groupBox1.setTitle(_translate("settingsDialog", "Listening port", None)) self.label.setText(_translate("settingsDialog", "Listen for connections on port:", None)) - self.labelUPnP.setText(_translate("settingsDialog", "UPnP:", None)) self.groupBox_3.setTitle(_translate("settingsDialog", "Bandwidth limit", None)) self.label_24.setText(_translate("settingsDialog", "Maximum download rate (kB/s): [0: unlimited]", None)) self.label_25.setText(_translate("settingsDialog", "Maximum upload rate (kB/s): [0: unlimited]", None)) - self.label_26.setText(_translate("settingsDialog", "Maximum outbound connections: [0: none]", None)) self.groupBox_2.setTitle(_translate("settingsDialog", "Proxy server / Tor", None)) self.label_2.setText(_translate("settingsDialog", "Type:", None)) self.label_3.setText(_translate("settingsDialog", "Server hostname:", None)) @@ -495,7 +474,6 @@ class Ui_settingsDialog(object): self.label_13.setText(_translate("settingsDialog", "Maximum acceptable total difficulty:", None)) self.label_14.setText(_translate("settingsDialog", "Maximum acceptable small message difficulty:", None)) self.tabWidgetSettings.setTabText(self.tabWidgetSettings.indexOf(self.tabMaxAcceptableDifficulty), _translate("settingsDialog", "Max acceptable difficulty", None)) - self.labelOpenCL.setText(_translate("settingsDialog", "Hardware GPU acceleration (OpenCL):", None)) self.label_16.setText(_translate("settingsDialog", "

Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to test.

(Getting your own Bitmessage address into Namecoin is still rather difficult).

Bitmessage can use either namecoind directly or a running nmcontrol instance.

", None)) self.label_17.setText(_translate("settingsDialog", "Host:", None)) self.label_18.setText(_translate("settingsDialog", "Port:", None)) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 4aeba3ce..a41d7e4e 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -153,7 +153,7 @@
- Español + Españl @@ -317,29 +317,6 @@ - - - - Maximum outbound connections: [0: none] - - - - - - - - 0 - 0 - - - - - 60 - 16777215 - - - -
diff --git a/src/bitmessageqt/settingsmixin.py b/src/bitmessageqt/settingsmixin.py deleted file mode 100644 index c534d1b5..00000000 --- a/src/bitmessageqt/settingsmixin.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/python2.7 - -from PyQt4 import QtCore, QtGui - -class SettingsMixin(object): - def warnIfNoObjectName(self): - if self.objectName() == "": - # TODO: logger - pass - - def writeState(self, source): - self.warnIfNoObjectName() - settings = QtCore.QSettings() - settings.beginGroup(self.objectName()) - settings.setValue("state", source.saveState()) - settings.endGroup() - - def writeGeometry(self, source): - self.warnIfNoObjectName() - settings = QtCore.QSettings() - settings.beginGroup(self.objectName()) - settings.setValue("geometry", source.saveGeometry()) - settings.endGroup() - - def readGeometry(self, target): - self.warnIfNoObjectName() - settings = QtCore.QSettings() - try: - geom = settings.value("/".join([str(self.objectName()), "geometry"])) - target.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom) - except Exception as e: - pass - - def readState(self, target): - self.warnIfNoObjectName() - settings = QtCore.QSettings() - try: - state = settings.value("/".join([str(self.objectName()), "state"])) - target.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state) - except Exception as e: - pass - - -class SMainWindow(QtGui.QMainWindow, SettingsMixin): - def loadSettings(self): - self.readGeometry(self) - self.readState(self) - - def saveSettings(self): - self.writeState(self) - self.writeGeometry(self) - - -class STableWidget(QtGui.QTableWidget, SettingsMixin): - def loadSettings(self): - self.readState(self.horizontalHeader()) - - def saveSettings(self): - self.writeState(self.horizontalHeader()) - - -class SSplitter(QtGui.QSplitter, SettingsMixin): - def loadSettings(self): - self.readState(self) - - def saveSettings(self): - self.writeState(self) - - -class STreeWidget(QtGui.QTreeWidget, SettingsMixin): - def loadSettings(self): - #recurse children - #self.readState(self) - pass - - def saveSettings(self): - #recurse children - #self.writeState(self) - pass diff --git a/src/bitmessageqt/sound.py b/src/bitmessageqt/sound.py deleted file mode 100644 index 9c86a9a4..00000000 --- a/src/bitmessageqt/sound.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -# sound type constants -SOUND_NONE = 0 -SOUND_KNOWN = 1 -SOUND_UNKNOWN = 2 -SOUND_CONNECTED = 3 -SOUND_DISCONNECTED = 4 -SOUND_CONNECTION_GREEN = 5 - - -# returns true if the given sound category is a connection sound -# rather than a received message sound -def is_connection_sound(category): - return category in ( - SOUND_CONNECTED, - SOUND_DISCONNECTED, - SOUND_CONNECTION_GREEN - ) - -extensions = ('wav', 'mp3', 'oga') diff --git a/src/bitmessageqt/specialaddressbehavior.py b/src/bitmessageqt/specialaddressbehavior.py new file mode 100644 index 00000000..78ff890d --- /dev/null +++ b/src/bitmessageqt/specialaddressbehavior.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'specialaddressbehavior.ui' +# +# Created: Fri Apr 26 17:43:31 2013 +# by: PyQt4 UI code generator 4.9.4 +# +# WARNING! All changes made in this file will be lost! + +from PyQt4 import QtCore, QtGui + +try: + _fromUtf8 = QtCore.QString.fromUtf8 +except AttributeError: + _fromUtf8 = lambda s: s + +class Ui_SpecialAddressBehaviorDialog(object): + def setupUi(self, SpecialAddressBehaviorDialog): + SpecialAddressBehaviorDialog.setObjectName(_fromUtf8("SpecialAddressBehaviorDialog")) + SpecialAddressBehaviorDialog.resize(386, 172) + self.gridLayout = QtGui.QGridLayout(SpecialAddressBehaviorDialog) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.radioButtonBehaveNormalAddress = QtGui.QRadioButton(SpecialAddressBehaviorDialog) + self.radioButtonBehaveNormalAddress.setChecked(True) + self.radioButtonBehaveNormalAddress.setObjectName(_fromUtf8("radioButtonBehaveNormalAddress")) + self.gridLayout.addWidget(self.radioButtonBehaveNormalAddress, 0, 0, 1, 1) + self.radioButtonBehaviorMailingList = QtGui.QRadioButton(SpecialAddressBehaviorDialog) + self.radioButtonBehaviorMailingList.setObjectName(_fromUtf8("radioButtonBehaviorMailingList")) + self.gridLayout.addWidget(self.radioButtonBehaviorMailingList, 1, 0, 1, 1) + self.label = QtGui.QLabel(SpecialAddressBehaviorDialog) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout.addWidget(self.label, 2, 0, 1, 1) + self.label_2 = QtGui.QLabel(SpecialAddressBehaviorDialog) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout.addWidget(self.label_2, 3, 0, 1, 1) + self.lineEditMailingListName = QtGui.QLineEdit(SpecialAddressBehaviorDialog) + self.lineEditMailingListName.setEnabled(False) + self.lineEditMailingListName.setObjectName(_fromUtf8("lineEditMailingListName")) + self.gridLayout.addWidget(self.lineEditMailingListName, 4, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(SpecialAddressBehaviorDialog) + self.buttonBox.setMinimumSize(QtCore.QSize(368, 0)) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName(_fromUtf8("buttonBox")) + self.gridLayout.addWidget(self.buttonBox, 5, 0, 1, 1) + + self.retranslateUi(SpecialAddressBehaviorDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), SpecialAddressBehaviorDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), SpecialAddressBehaviorDialog.reject) + QtCore.QObject.connect(self.radioButtonBehaviorMailingList, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditMailingListName.setEnabled) + QtCore.QObject.connect(self.radioButtonBehaveNormalAddress, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditMailingListName.setDisabled) + QtCore.QMetaObject.connectSlotsByName(SpecialAddressBehaviorDialog) + SpecialAddressBehaviorDialog.setTabOrder(self.radioButtonBehaveNormalAddress, self.radioButtonBehaviorMailingList) + SpecialAddressBehaviorDialog.setTabOrder(self.radioButtonBehaviorMailingList, self.lineEditMailingListName) + SpecialAddressBehaviorDialog.setTabOrder(self.lineEditMailingListName, self.buttonBox) + + def retranslateUi(self, SpecialAddressBehaviorDialog): + SpecialAddressBehaviorDialog.setWindowTitle(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Special Address Behavior", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonBehaveNormalAddress.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Behave as a normal address", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonBehaviorMailingList.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Behave as a pseudo-mailing-list address", None, QtGui.QApplication.UnicodeUTF8)) + 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)) + self.label_2.setText(QtGui.QApplication.translate("SpecialAddressBehaviorDialog", "Name of the pseudo-mailing-list:", None, QtGui.QApplication.UnicodeUTF8)) + diff --git a/src/bitmessageqt/statusbar.py b/src/bitmessageqt/statusbar.py deleted file mode 100644 index 65a5acfb..00000000 --- a/src/bitmessageqt/statusbar.py +++ /dev/null @@ -1,38 +0,0 @@ -from PyQt4 import QtCore, QtGui -from Queue import Queue -from time import time - -class BMStatusBar(QtGui.QStatusBar): - duration = 10000 - deleteAfter = 60 - - def __init__(self, parent=None): - super(BMStatusBar, self).__init__(parent) - self.important = [] - self.timer = self.startTimer(BMStatusBar.duration) - self.iterator = 0 - - def timerEvent(self, event): - while len(self.important) > 0: - self.iterator += 1 - try: - if time() > self.important[self.iterator][1] + BMStatusBar.deleteAfter: - del self.important[self.iterator] - self.iterator -= 1 - continue - except IndexError: - self.iterator = -1 - continue - super(BMStatusBar, self).showMessage(self.important[self.iterator][0], 0) - break - - def addImportant(self, message): - self.important.append([message, time()]) - self.iterator = len(self.important) - 2 - self.timerEvent(None) - - def showMessage(self, message, timeout=0): - super(BMStatusBar, self).showMessage(message, timeout) - - def clearMessage(self): - super(BMStatusBar, self).clearMessage() diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py deleted file mode 100644 index 25c6113d..00000000 --- a/src/bitmessageqt/support.py +++ /dev/null @@ -1,140 +0,0 @@ -import ctypes -from PyQt4 import QtCore, QtGui -import ssl -import sys -import time - -import account -from bmconfigparser import BMConfigParser -from debug import logger -import defaults -from foldertree import AccountMixin -from helper_sql import * -from l10n import getTranslationLanguage -from openclpow import openclAvailable, openclEnabled -import paths -import proofofwork -from pyelliptic.openssl import OpenSSL -import queues -import network.stats -import state -from version import softwareVersion - -# this is BM support address going to Peter Surda -OLD_SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' -SUPPORT_ADDRESS = 'BM-2cUdgkDDAahwPAU6oD2A7DnjqZz3hgY832' -SUPPORT_LABEL = 'PyBitmessage support' -SUPPORT_MY_LABEL = 'My new address' -SUPPORT_SUBJECT = 'Support request' -SUPPORT_MESSAGE = '''You can use this message to send a report to one of the PyBitmessage core developers regarding PyBitmessage or the mailchuck.com email service. If you are using PyBitmessage involuntarily, for example because your computer was infected with ransomware, this is not an appropriate venue for resolving such issues. - -Please describe what you are trying to do: - -Please describe what you expect to happen: - -Please describe what happens instead: - - -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Please write above this line and if possible, keep the information about your environment below intact. - -PyBitmessage version: {} -Operating system: {} -Architecture: {}bit -Python Version: {} -OpenSSL Version: {} -Frozen: {} -Portable mode: {} -C PoW: {} -OpenCL PoW: {} -Locale: {} -SOCKS: {} -UPnP: {} -Connected hosts: {} -''' - -def checkAddressBook(myapp): - sqlExecute('''DELETE from addressbook WHERE address=?''', OLD_SUPPORT_ADDRESS) - queryreturn = sqlQuery('''SELECT * FROM addressbook WHERE address=?''', SUPPORT_ADDRESS) - if queryreturn == []: - sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', str(QtGui.QApplication.translate("Support", SUPPORT_LABEL)), SUPPORT_ADDRESS) - myapp.rerenderAddressBook() - -def checkHasNormalAddress(): - for address in account.getSortedAccounts(): - acct = account.accountClass(address) - if acct.type == AccountMixin.NORMAL and BMConfigParser().safeGetBoolean(address, 'enabled'): - return address - return False - -def createAddressIfNeeded(myapp): - if not checkHasNormalAddress(): - queues.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, defaults.networkDefaultProofOfWorkNonceTrialsPerByte, defaults.networkDefaultPayloadLengthExtraBytes)) - while state.shutdown == 0 and not checkHasNormalAddress(): - time.sleep(.2) - myapp.rerenderComboBoxSendFrom() - return checkHasNormalAddress() - -def createSupportMessage(myapp): - checkAddressBook(myapp) - address = createAddressIfNeeded(myapp) - if state.shutdown: - return - - myapp.ui.lineEditSubject.setText(str(QtGui.QApplication.translate("Support", SUPPORT_SUBJECT))) - addrIndex = myapp.ui.comboBoxSendFrom.findData(address, QtCore.Qt.UserRole, QtCore.Qt.MatchFixedString | QtCore.Qt.MatchCaseSensitive) - if addrIndex == -1: # something is very wrong - return - myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) - myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) - - version = softwareVersion - commit = paths.lastCommit().get('commit') - if commit: - version += " GIT " + commit - - os = sys.platform - if os == "win32": - windowsversion = sys.getwindowsversion() - os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1]) - else: - try: - from os import uname - unixversion = uname() - os = unixversion[0] + " " + unixversion[2] - except: - pass - architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" - pythonversion = sys.version - - opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._version) - - frozen = "N/A" - if paths.frozen: - frozen = paths.frozen - portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False" - cpow = "True" if proofofwork.bmpow else "False" - #cpow = QtGui.QApplication.translate("Support", cpow) - openclpow = str(BMConfigParser().safeGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" - #openclpow = QtGui.QApplication.translate("Support", openclpow) - locale = getTranslationLanguage() - try: - socks = BMConfigParser().get('bitmessagesettings', 'socksproxytype') - except: - socks = "N/A" - try: - upnp = BMConfigParser().get('bitmessagesettings', 'upnp') - except: - upnp = "N/A" - connectedhosts = len(network.stats.connectedHostsList()) - - myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, pythonversion, opensslversion, frozen, portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts)) - - # single msg tab - myapp.ui.tabWidgetSend.setCurrentIndex( - myapp.ui.tabWidgetSend.indexOf(myapp.ui.sendDirect) - ) - # send tab - myapp.ui.tabWidget.setCurrentIndex( - myapp.ui.tabWidget.indexOf(myapp.ui.send) - ) diff --git a/src/bitmessageqt/uisignaler.py b/src/bitmessageqt/uisignaler.py deleted file mode 100644 index 055f9097..00000000 --- a/src/bitmessageqt/uisignaler.py +++ /dev/null @@ -1,79 +0,0 @@ - -from PyQt4.QtCore import QThread, SIGNAL -import sys - -import queues - - -class UISignaler(QThread): - _instance = None - - def __init__(self, parent=None): - QThread.__init__(self, parent) - - @classmethod - def get(cls): - if not cls._instance: - cls._instance = UISignaler() - return cls._instance - - def run(self): - while True: - command, data = queues.UISignalQueue.get() - if command == 'writeNewAddressToTable': - label, address, streamNumber = data - self.emit(SIGNAL( - "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), label, address, str(streamNumber)) - elif command == 'updateStatusBar': - self.emit(SIGNAL("updateStatusBar(PyQt_PyObject)"), data) - elif command == 'updateSentItemStatusByToAddress': - toAddress, message = data - self.emit(SIGNAL( - "updateSentItemStatusByToAddress(PyQt_PyObject,PyQt_PyObject)"), toAddress, message) - elif command == 'updateSentItemStatusByAckdata': - ackData, message = data - self.emit(SIGNAL( - "updateSentItemStatusByAckdata(PyQt_PyObject,PyQt_PyObject)"), ackData, message) - elif command == 'displayNewInboxMessage': - inventoryHash, toAddress, fromAddress, subject, body = data - self.emit(SIGNAL( - "displayNewInboxMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), - inventoryHash, toAddress, fromAddress, subject, body) - elif command == 'displayNewSentMessage': - toAddress, fromLabel, fromAddress, subject, message, ackdata = data - self.emit(SIGNAL( - "displayNewSentMessage(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), - toAddress, fromLabel, fromAddress, subject, message, ackdata) - elif command == 'updateNetworkStatusTab': - outbound, add, destination = data - self.emit(SIGNAL("updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), outbound, add, destination) - elif command == 'updateNumberOfMessagesProcessed': - self.emit(SIGNAL("updateNumberOfMessagesProcessed()")) - elif command == 'updateNumberOfPubkeysProcessed': - self.emit(SIGNAL("updateNumberOfPubkeysProcessed()")) - elif command == 'updateNumberOfBroadcastsProcessed': - self.emit(SIGNAL("updateNumberOfBroadcastsProcessed()")) - elif command == 'setStatusIcon': - self.emit(SIGNAL("setStatusIcon(PyQt_PyObject)"), data) - elif command == 'changedInboxUnread': - self.emit(SIGNAL("changedInboxUnread(PyQt_PyObject)"), data) - elif command == 'rerenderMessagelistFromLabels': - self.emit(SIGNAL("rerenderMessagelistFromLabels()")) - elif command == 'rerenderMessagelistToLabels': - self.emit(SIGNAL("rerenderMessagelistToLabels()")) - elif command == 'rerenderAddressBook': - self.emit(SIGNAL("rerenderAddressBook()")) - elif command == 'rerenderSubscriptions': - self.emit(SIGNAL("rerenderSubscriptions()")) - elif command == 'rerenderBlackWhiteList': - self.emit(SIGNAL("rerenderBlackWhiteList()")) - elif command == 'removeInboxRowByMsgid': - self.emit(SIGNAL("removeInboxRowByMsgid(PyQt_PyObject)"), data) - elif command == 'newVersionAvailable': - self.emit(SIGNAL("newVersionAvailable(PyQt_PyObject)"), data) - elif command == 'alert': - title, text, exitAfterUserClicksOk = data - self.emit(SIGNAL("displayAlert(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), title, text, exitAfterUserClicksOk) - else: - sys.stderr.write( - 'Command sent to UISignaler not recognized: %s\n' % command) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py deleted file mode 100644 index 369d05ef..00000000 --- a/src/bitmessageqt/utils.py +++ /dev/null @@ -1,108 +0,0 @@ -from PyQt4 import QtGui -import hashlib -import os -from addresses import addBMIfNotPresent -from bmconfigparser import BMConfigParser -import state - -str_broadcast_subscribers = '[Broadcast subscribers]' -str_chan = '[chan]' - -def identiconize(address): - size = 48 - - # If you include another identicon library, please generate an - # example identicon with the following md5 hash: - # 3fd4bf901b9d4ea1394f0fb358725b28 - - try: - identicon_lib = BMConfigParser().get('bitmessagesettings', 'identiconlib') - except: - # default to qidenticon_two_x - identicon_lib = 'qidenticon_two_x' - - # As an 'identiconsuffix' you could put "@bitmessge.ch" or "@bm.addr" to make it compatible with other identicon generators. (Note however, that E-Mail programs might convert the BM-address to lowercase first.) - # It can be used as a pseudo-password to salt the generation of the identicons to decrease the risk - # of attacks where someone creates an address to mimic someone else's identicon. - identiconsuffix = BMConfigParser().get('bitmessagesettings', 'identiconsuffix') - - if not BMConfigParser().getboolean('bitmessagesettings', 'useidenticons'): - idcon = QtGui.QIcon() - return idcon - - if (identicon_lib[:len('qidenticon')] == 'qidenticon'): - # print identicon_lib - # originally by: - # :Author:Shin Adachi - # Licesensed under FreeBSD License. - # stripped from PIL and uses QT instead (by sendiulo, same license) - import qidenticon - hash = hashlib.md5(addBMIfNotPresent(address)+identiconsuffix).hexdigest() - use_two_colors = (identicon_lib[:len('qidenticon_two')] == 'qidenticon_two') - opacity = int(not((identicon_lib == 'qidenticon_x') | (identicon_lib == 'qidenticon_two_x') | (identicon_lib == 'qidenticon_b') | (identicon_lib == 'qidenticon_two_b')))*255 - penwidth = 0 - image = qidenticon.render_identicon(int(hash, 16), size, use_two_colors, opacity, penwidth) - # filename = './images/identicons/'+hash+'.png' - # image.save(filename) - idcon = QtGui.QIcon() - idcon.addPixmap(image, QtGui.QIcon.Normal, QtGui.QIcon.Off) - return idcon - elif identicon_lib == 'pydenticon': - # print identicon_lib - # Here you could load pydenticon.py (just put it in the "src" folder of your Bitmessage source) - from pydenticon import Pydenticon - # It is not included in the source, because it is licensed under GPLv3 - # GPLv3 is a copyleft license that would influence our licensing - # Find the source here: http://boottunes.googlecode.com/svn-history/r302/trunk/src/pydenticon.py - # note that it requires PIL to be installed: http://www.pythonware.com/products/pil/ - idcon_render = Pydenticon(addBMIfNotPresent(address)+identiconsuffix, size*3) - rendering = idcon_render._render() - data = rendering.convert("RGBA").tostring("raw", "RGBA") - qim = QtGui.QImage(data, size, size, QtGui.QImage.Format_ARGB32) - pix = QtGui.QPixmap.fromImage(qim) - idcon = QtGui.QIcon() - idcon.addPixmap(pix, QtGui.QIcon.Normal, QtGui.QIcon.Off) - return idcon - -def avatarize(address): - """ - loads a supported image for the given address' hash form 'avatars' folder - falls back to default avatar if 'default.*' file exists - falls back to identiconize(address) - """ - idcon = QtGui.QIcon() - hash = hashlib.md5(addBMIfNotPresent(address)).hexdigest() - str_broadcast_subscribers = '[Broadcast subscribers]' - if address == str_broadcast_subscribers: - # don't hash [Broadcast subscribers] - hash = address - # http://pyqt.sourceforge.net/Docs/PyQt4/qimagereader.html#supportedImageFormats - # print QImageReader.supportedImageFormats () - # QImageReader.supportedImageFormats () - extensions = ['PNG', 'GIF', 'JPG', 'JPEG', 'SVG', 'BMP', 'MNG', 'PBM', 'PGM', 'PPM', 'TIFF', 'XBM', 'XPM', 'TGA'] - # try to find a specific avatar - for ext in extensions: - lower_hash = state.appdata + 'avatars/' + hash + '.' + ext.lower() - upper_hash = state.appdata + 'avatars/' + hash + '.' + ext.upper() - if os.path.isfile(lower_hash): - # print 'found avatar of ', address - idcon.addFile(lower_hash) - return idcon - elif os.path.isfile(upper_hash): - # print 'found avatar of ', address - idcon.addFile(upper_hash) - return idcon - # if we haven't found any, try to find a default avatar - for ext in extensions: - lower_default = state.appdata + 'avatars/' + 'default.' + ext.lower() - upper_default = state.appdata + 'avatars/' + 'default.' + ext.upper() - if os.path.isfile(lower_default): - default = lower_default - idcon.addFile(lower_default) - return idcon - elif os.path.isfile(upper_default): - default = upper_default - idcon.addFile(upper_default) - return idcon - # If no avatar is found - return identiconize(address) diff --git a/src/bitmessageqt/widgets.py b/src/bitmessageqt/widgets.py deleted file mode 100644 index 8ef807f2..00000000 --- a/src/bitmessageqt/widgets.py +++ /dev/null @@ -1,13 +0,0 @@ -from PyQt4 import uic -import os.path -import paths -import sys - -def resource_path(resFile): - baseDir = paths.codePath() - for subDir in ["ui", "bitmessageqt"]: - if os.path.isdir(os.path.join(baseDir, subDir)) and os.path.isfile(os.path.join(baseDir, subDir, resFile)): - return os.path.join(baseDir, subDir, resFile) - -def load(resFile, widget): - uic.loadUi(resource_path(resFile), widget) diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile deleted file mode 100644 index c4fb4ab5..00000000 --- a/src/bitmsghash/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -UNAME_S := $(shell uname -s) -ifeq ($(UNAME_S),Darwin) - CCFLAGS += -I/usr/local/Cellar/openssl/1.0.2d_1/include - LDFLAGS += -L/usr/local/Cellar/openssl/1.0.2d_1/lib -else ifeq ($(UNAME_S),MINGW32_NT-6.1) - CCFLAGS += -IC:\OpenSSL-1.0.2j-mingw\include -D_WIN32 -march=native - LDFLAGS += -static-libgcc -LC:\OpenSSL-1.0.2j-mingw\lib -lwsock32 -o bitmsghash32.dll -Wl,--out-implib,bitmsghash.a -else - LDFLAGS += -lpthread -o bitmsghash.so -endif - -all: bitmsghash.so - -powtest: - ./testpow.py - -bitmsghash.so: bitmsghash.o - ${CXX} bitmsghash.o -shared -fPIC -lcrypto $(LDFLAGS) - -bitmsghash.o: - ${CXX} -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp - -clean: - rm -f bitmsghash.o bitmsghash.so bitmsghash*.dll - diff --git a/src/bitmsghash/Makefile.bsd b/src/bitmsghash/Makefile.bsd deleted file mode 100644 index 6e680c86..00000000 --- a/src/bitmsghash/Makefile.bsd +++ /dev/null @@ -1,14 +0,0 @@ -all: bitmsghash.so - -powtest: - ./testpow.py - -bitmsghash.so: bitmsghash.o - ${CXX} bitmsghash.o -shared -fPIC -lpthread -lcrypto $(LDFLAGS) -o bitmsghash.so - -bitmsghash.o: - ${CXX} -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp - -clean: - rm -f bitmsghash.o bitmsghash.so - diff --git a/src/bitmsghash/Makefile.msvc b/src/bitmsghash/Makefile.msvc deleted file mode 100644 index 63482c34..00000000 --- a/src/bitmsghash/Makefile.msvc +++ /dev/null @@ -1,2 +0,0 @@ -all: - cl /I C:\OpenSSL-1.0.2j\include /INCREMENTAL bitmsghash.cpp /MT /link /DLL /OUT:bitmsghash32.dll /LIBPATH:C:\OpenSSL-1.0.2j\lib\ libeay32.lib ws2_32.lib diff --git a/src/bitmsghash/bitmsghash.cl b/src/bitmsghash/bitmsghash.cl deleted file mode 100644 index 3c8c21a5..00000000 --- a/src/bitmsghash/bitmsghash.cl +++ /dev/null @@ -1,276 +0,0 @@ -/* -* This is based on the John The Ripper SHA512 code, modified for double SHA512 and for use as a miner in Bitmessage. -* This software is originally Copyright (c) 2012 Myrice -* and it is hereby released to the general public under the following terms: -* Redistribution and use in source and binary forms, with or without modification, are permitted. -*/ - -#ifdef cl_khr_byte_addressable_store -#pragma OPENCL EXTENSION cl_khr_byte_addressable_store : disable -#endif - -#define uint8_t unsigned char -#define uint32_t unsigned int -#define uint64_t unsigned long -#define SALT_SIZE 0 - -#define BINARY_SIZE 8 -#define FULL_BINARY_SIZE 64 - - -#define PLAINTEXT_LENGTH 72 - -#define CIPHERTEXT_LENGTH 128 - - -/// Warning: This version of SWAP64(n) is slow and avoid bugs on AMD GPUs(7970) -// #define SWAP64(n) as_ulong(as_uchar8(n).s76543210) - -#define SWAP64(n) \ - (((n) << 56) \ - | (((n) & 0xff00) << 40) \ - | (((n) & 0xff0000) << 24) \ - | (((n) & 0xff000000) << 8) \ - | (((n) >> 8) & 0xff000000) \ - | (((n) >> 24) & 0xff0000) \ - | (((n) >> 40) & 0xff00) \ - | ((n) >> 56)) - - - -#define rol(x,n) ((x << n) | (x >> (64-n))) -#define ror(x,n) ((x >> n) | (x << (64-n))) -#define Ch(x,y,z) ((x & y) ^ ( (~x) & z)) -#define Maj(x,y,z) ((x & y) ^ (x & z) ^ (y & z)) -#define Sigma0(x) ((ror(x,28)) ^ (ror(x,34)) ^ (ror(x,39))) -#define Sigma1(x) ((ror(x,14)) ^ (ror(x,18)) ^ (ror(x,41))) -#define sigma0(x) ((ror(x,1)) ^ (ror(x,8)) ^(x>>7)) -#define sigma1(x) ((ror(x,19)) ^ (ror(x,61)) ^(x>>6)) - - - -typedef struct { // notice memory align problem - uint64_t H[8]; - uint32_t buffer[32]; //1024 bits - uint32_t buflen; -} sha512_ctx; - -typedef struct { - uint64_t target; - char v[PLAINTEXT_LENGTH+1]; -} sha512_key; - - -/* Macros for reading/writing chars from int32's */ -#define PUTCHAR(buf, index, val) (buf)[(index)>>2] = ((buf)[(index)>>2] & ~(0xffU << (((index) & 3) << 3))) + ((val) << (((index) & 3) << 3)) - - -__constant uint64_t k[] = { - 0x428a2f98d728ae22UL, 0x7137449123ef65cdUL, 0xb5c0fbcfec4d3b2fUL, - 0xe9b5dba58189dbbcUL, - 0x3956c25bf348b538UL, 0x59f111f1b605d019UL, 0x923f82a4af194f9bUL, - 0xab1c5ed5da6d8118UL, - 0xd807aa98a3030242UL, 0x12835b0145706fbeUL, 0x243185be4ee4b28cUL, - 0x550c7dc3d5ffb4e2UL, - 0x72be5d74f27b896fUL, 0x80deb1fe3b1696b1UL, 0x9bdc06a725c71235UL, - 0xc19bf174cf692694UL, - 0xe49b69c19ef14ad2UL, 0xefbe4786384f25e3UL, 0x0fc19dc68b8cd5b5UL, - 0x240ca1cc77ac9c65UL, - 0x2de92c6f592b0275UL, 0x4a7484aa6ea6e483UL, 0x5cb0a9dcbd41fbd4UL, - 0x76f988da831153b5UL, - 0x983e5152ee66dfabUL, 0xa831c66d2db43210UL, 0xb00327c898fb213fUL, - 0xbf597fc7beef0ee4UL, - 0xc6e00bf33da88fc2UL, 0xd5a79147930aa725UL, 0x06ca6351e003826fUL, - 0x142929670a0e6e70UL, - 0x27b70a8546d22ffcUL, 0x2e1b21385c26c926UL, 0x4d2c6dfc5ac42aedUL, - 0x53380d139d95b3dfUL, - 0x650a73548baf63deUL, 0x766a0abb3c77b2a8UL, 0x81c2c92e47edaee6UL, - 0x92722c851482353bUL, - 0xa2bfe8a14cf10364UL, 0xa81a664bbc423001UL, 0xc24b8b70d0f89791UL, - 0xc76c51a30654be30UL, - 0xd192e819d6ef5218UL, 0xd69906245565a910UL, 0xf40e35855771202aUL, - 0x106aa07032bbd1b8UL, - 0x19a4c116b8d2d0c8UL, 0x1e376c085141ab53UL, 0x2748774cdf8eeb99UL, - 0x34b0bcb5e19b48a8UL, - 0x391c0cb3c5c95a63UL, 0x4ed8aa4ae3418acbUL, 0x5b9cca4f7763e373UL, - 0x682e6ff3d6b2b8a3UL, - 0x748f82ee5defb2fcUL, 0x78a5636f43172f60UL, 0x84c87814a1f0ab72UL, - 0x8cc702081a6439ecUL, - 0x90befffa23631e28UL, 0xa4506cebde82bde9UL, 0xbef9a3f7b2c67915UL, - 0xc67178f2e372532bUL, - 0xca273eceea26619cUL, 0xd186b8c721c0c207UL, 0xeada7dd6cde0eb1eUL, - 0xf57d4f7fee6ed178UL, - 0x06f067aa72176fbaUL, 0x0a637dc5a2c898a6UL, 0x113f9804bef90daeUL, - 0x1b710b35131c471bUL, - 0x28db77f523047d84UL, 0x32caab7b40c72493UL, 0x3c9ebe0a15c9bebcUL, - 0x431d67c49c100d4cUL, - 0x4cc5d4becb3e42b6UL, 0x597f299cfc657e2aUL, 0x5fcb6fab3ad6faecUL, - 0x6c44198c4a475817UL, -}; - - - -static void setup_ctx(sha512_ctx* ctx, const char * password, uint8_t pass_len) -{ - uint32_t* b32 = ctx->buffer; - - //set password to buffer - for (uint32_t i = 0; i < pass_len; i++) { - PUTCHAR(b32,i,password[i]); - } - ctx->buflen = pass_len; - - //append 1 to ctx buffer - uint32_t length = ctx->buflen; - PUTCHAR(b32, length, 0x80); - while((++length & 3) != 0) { - PUTCHAR(b32, length, 0); - } - - uint32_t* buffer32 = b32+(length>>2); - for(uint32_t i = length; i < 128; i+=4) {// append 0 to 128 - *buffer32++=0; - } - - //append length to buffer - uint64_t *buffer64 = (uint64_t *)ctx->buffer; - buffer64[15] = SWAP64(((uint64_t) ctx->buflen) * 8); -} - -inline uint64_t sha512(char* password) -{ - __private sha512_ctx ctx; - setup_ctx(&ctx, password, 72); - // sha512 main` - int i; - - uint64_t a = 0x6a09e667f3bcc908UL; - uint64_t b = 0xbb67ae8584caa73bUL; - uint64_t c = 0x3c6ef372fe94f82bUL; - uint64_t d = 0xa54ff53a5f1d36f1UL; - uint64_t e = 0x510e527fade682d1UL; - uint64_t f = 0x9b05688c2b3e6c1fUL; - uint64_t g = 0x1f83d9abfb41bd6bUL; - uint64_t h = 0x5be0cd19137e2179UL; - - __private uint64_t w[16]; - - uint64_t *data = (uint64_t *) ctx.buffer; - - for (i = 0; i < 16; i++) - w[i] = SWAP64(data[i]); - - uint64_t t1, t2; - for (i = 0; i < 16; i++) { - t1 = k[i] + w[i] + h + Sigma1(e) + Ch(e, f, g); - t2 = Maj(a, b, c) + Sigma0(a); - - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - for (i = 16; i < 80; i++) { - - w[i & 15] =sigma1(w[(i - 2) & 15]) + sigma0(w[(i - 15) & 15]) + w[(i -16) & 15] + w[(i - 7) & 15]; - t1 = k[i] + w[i & 15] + h + Sigma1(e) + Ch(e, f, g); - t2 = Maj(a, b, c) + Sigma0(a); - - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - uint64_t finalhash[8]; - - finalhash[0] = SWAP64(a + 0x6a09e667f3bcc908UL); - finalhash[1] = SWAP64(b + 0xbb67ae8584caa73bUL); - finalhash[2] = SWAP64(c + 0x3c6ef372fe94f82bUL); - finalhash[3] = SWAP64(d + 0xa54ff53a5f1d36f1UL); - finalhash[4] = SWAP64(e + 0x510e527fade682d1UL); - finalhash[5] = SWAP64(f + 0x9b05688c2b3e6c1fUL); - finalhash[6] = SWAP64(g + 0x1f83d9abfb41bd6bUL); - finalhash[7] = SWAP64(h + 0x5be0cd19137e2179UL); - - setup_ctx(&ctx, (char*) finalhash, 64); - - a = 0x6a09e667f3bcc908UL; - b = 0xbb67ae8584caa73bUL; - c = 0x3c6ef372fe94f82bUL; - d = 0xa54ff53a5f1d36f1UL; - e = 0x510e527fade682d1UL; - f = 0x9b05688c2b3e6c1fUL; - g = 0x1f83d9abfb41bd6bUL; - h = 0x5be0cd19137e2179UL; - - data = (uint64_t *) ctx.buffer; - //((uint64_t*)ctx.buffer)[8] = SWAP64((uint64_t)0x80); - - for (i = 0; i < 16; i++) - w[i] = SWAP64(data[i]); - - for (i = 0; i < 16; i++) { - t1 = k[i] + w[i] + h + Sigma1(e) + Ch(e, f, g); - t2 = Maj(a, b, c) + Sigma0(a); - - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - - for (i = 16; i < 80; i++) { - - w[i & 15] =sigma1(w[(i - 2) & 15]) + sigma0(w[(i - 15) & 15]) + w[(i -16) & 15] + w[(i - 7) & 15]; - t1 = k[i] + w[i & 15] + h + Sigma1(e) + Ch(e, f, g); - t2 = Maj(a, b, c) + Sigma0(a); - - h = g; - g = f; - f = e; - e = d + t1; - d = c; - c = b; - b = a; - a = t1 + t2; - } - return SWAP64(a + 0x6a09e667f3bcc908UL); -} - -__kernel void kernel_sha512(__global const sha512_key *password,__global uint64_t *hash, uint64_t start) -{ - uint64_t idx = get_global_id(0); - if (idx == 0 && start == 0) { - *hash = 0; - } - uint64_t winval; - - uint64_t junk[9]; - - __global uint64_t * source = (__global uint64_t*) password->v; - for (int i = 1; i < 9; i++) { - junk[i] = source[i]; - } - - junk[0] = SWAP64(idx + (start)); - - winval = sha512((char*)junk); - if (SWAP64(winval) < password->target) { - *hash = SWAP64(junk[0]); - } -} - diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp deleted file mode 100644 index 2d0d4b50..00000000 --- a/src/bitmsghash/bitmsghash.cpp +++ /dev/null @@ -1,165 +0,0 @@ -// bitmessage cracker, build with g++ or MSVS to a shared library, use included python code for usage under bitmessage -#ifdef _WIN32 -#include "Winsock.h" -#include "Windows.h" -#define uint64_t unsigned __int64 -#else -#include -#include -#include -#endif -#include -#include -#include -#if defined(__APPLE__) || defined(__FreeBSD__) || defined (__DragonFly__) || defined (__OpenBSD__) || defined (__NetBSD__) -#include -#include -#endif - -#include "openssl/sha.h" - -#define HASH_SIZE 64 -#define BUFLEN 16384 - -#if defined(__GNUC__) - #define EXPORT __attribute__ ((__visibility__("default"))) -#elif defined(_WIN32) - #define EXPORT __declspec(dllexport) -#endif - -#ifndef __APPLE__ -#define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) ) -#endif - -unsigned long long max_val; -unsigned char *initialHash; -unsigned long long successval = 0; -unsigned int numthreads = 0; - -#ifdef _WIN32 -DWORD WINAPI threadfunc(LPVOID param) { -#else -void * threadfunc(void* param) { -#endif - unsigned int incamt = *((unsigned int*)param); - SHA512_CTX sha; - unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 }; - unsigned char output[HASH_SIZE] = { 0 }; - - memcpy(buf + sizeof(uint64_t), initialHash, HASH_SIZE); - - unsigned long long tmpnonce = incamt; - unsigned long long * nonce = (unsigned long long *)buf; - unsigned long long * hash = (unsigned long long *)output; - while (successval == 0) { - tmpnonce += numthreads; - - (*nonce) = ntohll(tmpnonce); /* increment nonce */ - SHA512_Init(&sha); - SHA512_Update(&sha, buf, HASH_SIZE + sizeof(uint64_t)); - SHA512_Final(output, &sha); - SHA512_Init(&sha); - SHA512_Update(&sha, output, HASH_SIZE); - SHA512_Final(output, &sha); - - if (ntohll(*hash) < max_val) { - successval = tmpnonce; - } - } -#ifdef _WIN32 - return 0; -#else - return NULL; -#endif -} - -void getnumthreads() -{ -#ifdef _WIN32 - DWORD_PTR dwProcessAffinity, dwSystemAffinity; -#elif __linux__ - cpu_set_t dwProcessAffinity; -#elif __OpenBSD__ - int mib[2], core_count = 0; - int dwProcessAffinity = 0; - size_t len2; -#else - int dwProcessAffinity = 0; - int32_t core_count = 0; -#endif - size_t len = sizeof(dwProcessAffinity); - if (numthreads > 0) - return; -#ifdef _WIN32 - GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); -#elif __linux__ - sched_getaffinity(0, len, &dwProcessAffinity); -#elif __OpenBSD__ - len2 = sizeof(core_count); - mib[0] = CTL_HW; - mib[1] = HW_NCPU; - if (sysctl(mib, 2, &core_count, &len2, 0, 0) == 0) - numthreads = core_count; -#else - if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0) == 0) - numthreads = core_count; - else if (sysctlbyname("hw.ncpu", &core_count, &len, 0, 0) == 0) - numthreads = core_count; -#endif - for (unsigned int i = 0; i < len * 8; i++) -#if defined(_WIN32) -#if defined(_MSC_VER) - if (dwProcessAffinity & (1i64 << i)) -#else // CYGWIN/MINGW - if (dwProcessAffinity & (1ULL << i)) -#endif -#elif defined __linux__ - if (CPU_ISSET(i, &dwProcessAffinity)) -#else - if (dwProcessAffinity & (1 << i)) -#endif - numthreads++; - if (numthreads == 0) // something failed - numthreads = 1; - printf("Number of threads: %i\n", (int)numthreads); -} - -extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) -{ - successval = 0; - max_val = target; - getnumthreads(); - initialHash = (unsigned char *)starthash; -# ifdef _WIN32 - HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads); -# else - pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads); - struct sched_param schparam; - schparam.sched_priority = 0; -# endif - unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); - for (unsigned int i = 0; i < numthreads; i++) { - threaddata[i] = i; -# ifdef _WIN32 - threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)&threaddata[i], 0, NULL); - SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE); -# else - pthread_create(&threads[i], NULL, threadfunc, (void*)&threaddata[i]); -# ifdef __linux__ - pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); -# else - pthread_setschedparam(threads[i], SCHED_RR, &schparam); -# endif -# endif - } -# ifdef _WIN32 - WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE); -# else - for (unsigned int i = 0; i < numthreads; i++) { - pthread_join(threads[i], NULL); - } -# endif - free(threads); - free(threaddata); - return successval; -} diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py deleted file mode 100644 index 6a598955..00000000 --- a/src/bmconfigparser.py +++ /dev/null @@ -1,129 +0,0 @@ -import ConfigParser -import datetime -import shutil -import os - -from singleton import Singleton -import state - -BMConfigDefaults = { - "bitmessagesettings": { - "maxaddrperstreamsend": 500, - "maxbootstrapconnections": 20, - "maxdownloadrate": 0, - "maxoutboundconnections": 8, - "maxtotalconnections": 200, - "maxuploadrate": 0, - }, - "threads": { - "receive": 3, - }, - "network": { - "bind": '', - "dandelion": 90, - }, - "inventory": { - "storage": "sqlite", - "acceptmismatch": False, - }, - "knownnodes": { - "maxnodes": 20000, - }, - "zlib": { - 'maxsize': 1048576 - } -} - -@Singleton -class BMConfigParser(ConfigParser.SafeConfigParser): - def set(self, section, option, value=None): - if self._optcre is self.OPTCRE or value: - if not isinstance(value, basestring): - raise TypeError("option values must be strings") - if not self.validate(section, option, value): - raise ValueError("Invalid value %s" % str(value)) - return ConfigParser.ConfigParser.set(self, section, option, value) - - def get(self, section, option, raw=False, variables=None): - try: - if section == "bitmessagesettings" and option == "timeformat": - return ConfigParser.ConfigParser.get(self, section, option, raw, variables) - return ConfigParser.ConfigParser.get(self, section, option, True, variables) - except ConfigParser.InterpolationError: - return ConfigParser.ConfigParser.get(self, section, option, True, variables) - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: - try: - return BMConfigDefaults[section][option] - except (KeyError, ValueError, AttributeError): - raise e - - def safeGetBoolean(self, section, field): - try: - return self.getboolean(section, field) - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError, AttributeError): - return False - - def safeGetInt(self, section, field, default=0): - try: - return self.getint(section, field) - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError, AttributeError): - return default - - def safeGet(self, section, option, default = None): - try: - return self.get(section, option) - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError, AttributeError): - return default - - def items(self, section, raw=False, variables=None): - return ConfigParser.ConfigParser.items(self, section, True, variables) - - def addresses(self): - return filter(lambda x: x.startswith('BM-'), BMConfigParser().sections()) - - def read(self, filenames): - ConfigParser.ConfigParser.read(self, filenames) - for section in self.sections(): - for option in self.options(section): - try: - if not self.validate(section, option, ConfigParser.ConfigParser.get(self, section, option)): - try: - newVal = BMConfigDefaults[section][option] - except KeyError: - continue - ConfigParser.ConfigParser.set(self, section, option, newVal) - except ConfigParser.InterpolationError: - continue - - def save(self): - fileName = os.path.join(state.appdata, 'keys.dat') - fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak' - # create a backup copy to prevent the accidental loss due to the disk write failure - try: - shutil.copyfile(fileName, fileNameBak) - # The backup succeeded. - fileNameExisted = True - except (IOError, Exception): - # The backup failed. This can happen if the file didn't exist before. - fileNameExisted = False - # write the file - with open(fileName, 'wb') as configfile: - self.write(configfile) - # delete the backup - if fileNameExisted: - os.remove(fileNameBak) - - def validate(self, section, option, value): - try: - return getattr(self, "validate_%s_%s" % (section, option))(value) - except AttributeError: - return True - - def validate_bitmessagesettings_maxoutboundconnections(self, value): - try: - value = int(value) - except ValueError: - return False - if value < 0 or value > 8: - return False - return True diff --git a/src/build_osx.py b/src/build_osx.py index 1d8f470e..ce70cd54 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,29 +1,17 @@ -from glob import glob -import os -from PyQt4 import QtCore from setuptools import setup name = "Bitmessage" -version = os.getenv("PYBITMESSAGEVERSION", "custom") +version = "0.4.4" mainscript = ["bitmessagemain.py"] -DATA_FILES = [ - ('', ['sslkeys', 'images']), - ('bitmsghash', ['bitmsghash/bitmsghash.cl', 'bitmsghash/bitmsghash.so']), - ('translations', glob('translations/*.qm')), - ('ui', glob('bitmessageqt/*.ui')), - ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??.qm')), - ('translations', glob(str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)) + '/qt_??_??.qm')), -] - setup( name = name, version = version, app = mainscript, - data_files = DATA_FILES, setup_requires = ["py2app"], options = dict( py2app = dict( + resources = ["images", "translations"], includes = ['sip', 'PyQt4._qt'], iconfile = "images/bitmessage.icns" ) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index bd377c1d..af25b210 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -7,43 +7,28 @@ import ctypes import hashlib import highlevelcrypto from addresses import * -from bmconfigparser import BMConfigParser from debug import logger -import defaults -from helper_threading import * from pyelliptic import arithmetic import tr -from binascii import hexlify -import queues -import state -class addressGenerator(threading.Thread, StoppableThread): +class addressGenerator(threading.Thread): def __init__(self): # QThread.__init__(self, parent) - threading.Thread.__init__(self, name="addressGenerator") - self.initStop() - - def stopThread(self): - try: - queues.addressGeneratorQueue.put(("stopThread", "data")) - except: - pass - super(addressGenerator, self).stopThread() + threading.Thread.__init__(self) def run(self): - while state.shutdown == 0: - queueValue = queues.addressGeneratorQueue.get() + while True: + queueValue = shared.addressGeneratorQueue.get() nonceTrialsPerByte = 0 payloadLengthExtraBytes = 0 - live = True if queueValue[0] == 'createChan': - command, addressVersionNumber, streamNumber, label, deterministicPassphrase, live = queueValue + command, addressVersionNumber, streamNumber, label, deterministicPassphrase = queueValue eighteenByteRipe = False numberOfAddressesToMake = 1 numberOfNullBytesDemandedOnFrontOfRipeHash = 1 elif queueValue[0] == 'joinChan': - command, chanAddress, label, deterministicPassphrase, live = queueValue + command, chanAddress, label, deterministicPassphrase = queueValue eighteenByteRipe = False addressVersionNumber = decodeAddress(chanAddress)[1] streamNumber = decodeAddress(chanAddress)[2] @@ -52,7 +37,7 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 7: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: @@ -62,15 +47,13 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 9: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: numberOfNullBytesDemandedOnFrontOfRipeHash = 2 else: numberOfNullBytesDemandedOnFrontOfRipeHash = 1 # the default - elif queueValue[0] == 'stopThread': - break else: sys.stderr.write( 'Programming error: A structure with the wrong number of values was passed into the addressGeneratorQueue. Here is the queueValue: %s\n' % repr(queueValue)) @@ -78,18 +61,18 @@ class addressGenerator(threading.Thread, StoppableThread): sys.stderr.write( 'Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do.\n' % addressVersionNumber) if nonceTrialsPerByte == 0: - nonceTrialsPerByte = BMConfigParser().getint( + nonceTrialsPerByte = shared.config.getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - if nonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte + if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: + nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: - payloadLengthExtraBytes = BMConfigParser().getint( + payloadLengthExtraBytes = shared.config.getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes + if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: + payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow", "Generating one new address"))) + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText("MainWindow", "Generating one new address"))) # This next section is a little bit strange. We're going to generate keys over and over until we # find one that starts with either \x00 or \x00\x00. Then when we pack them into a Bitmessage address, # we won't store the \x00 or \x00\x00 bytes thus making the @@ -110,7 +93,7 @@ class addressGenerator(threading.Thread, StoppableThread): ripe.update(sha.digest()) if ripe.digest()[:numberOfNullBytesDemandedOnFrontOfRipeHash] == '\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash: break - logger.info('Generated address with ripe digest: %s' % hexlify(ripe.digest())) + logger.info('Generated address with ripe digest: %s' % ripe.digest().encode('hex')) try: logger.info('Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix.' % (numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime))) except ZeroDivisionError: @@ -132,34 +115,34 @@ class addressGenerator(threading.Thread, StoppableThread): privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKey + checksum, 256, 58) - BMConfigParser().add_section(address) - BMConfigParser().set(address, 'label', label) - BMConfigParser().set(address, 'enabled', 'true') - BMConfigParser().set(address, 'decoy', 'false') - BMConfigParser().set(address, 'noncetrialsperbyte', str( + shared.config.add_section(address) + shared.config.set(address, 'label', label) + shared.config.set(address, 'enabled', 'true') + shared.config.set(address, 'decoy', 'false') + shared.config.set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - BMConfigParser().set(address, 'payloadlengthextrabytes', str( + shared.config.set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - BMConfigParser().set( + shared.config.set( address, 'privSigningKey', privSigningKeyWIF) - BMConfigParser().set( + shared.config.set( address, 'privEncryptionKey', privEncryptionKeyWIF) - BMConfigParser().save() + shared.writeKeysFile() # The API and the join and create Chan functionality # both need information back from the address generator. - queues.apiAddressGeneratorReturnQueue.put(address) + shared.apiAddressGeneratorReturnQueue.put(address) - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow", "Done generating address. Doing work necessary to broadcast it..."))) - queues.UISignalQueue.put(('writeNewAddressToTable', ( + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText("MainWindow", "Done generating address. Doing work necessary to broadcast it..."))) + shared.UISignalQueue.put(('writeNewAddressToTable', ( label, address, streamNumber))) shared.reloadMyAddressHashes() if addressVersionNumber == 3: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV3Pubkey', ripe.digest())) elif addressVersionNumber == 4: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', address)) elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress' or command == 'createChan' or command == 'joinChan': @@ -167,8 +150,10 @@ class addressGenerator(threading.Thread, StoppableThread): sys.stderr.write( 'WARNING: You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.') if command == 'createDeterministicAddresses': - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow","Generating %1 new addresses.").arg(str(numberOfAddressesToMake)))) + statusbar = 'Generating ' + str( + numberOfAddressesToMake) + ' new addresses.' + shared.UISignalQueue.put(( + 'updateStatusBar', statusbar)) signingKeyNonce = 0 encryptionKeyNonce = 1 listOfNewAddressesToSendOutThroughTheAPI = [ @@ -202,7 +187,7 @@ class addressGenerator(threading.Thread, StoppableThread): break - logger.info('Generated address with ripe digest: %s' % hexlify(ripe.digest())) + logger.info('Generated address with ripe digest: %s' % ripe.digest().encode('hex')) try: logger.info('Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix.' % (numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime))) except ZeroDivisionError: @@ -214,12 +199,12 @@ class addressGenerator(threading.Thread, StoppableThread): # If we are joining an existing chan, let us check to make sure it matches the provided Bitmessage address if command == 'joinChan': if address != chanAddress: - listOfNewAddressesToSendOutThroughTheAPI.append('chan name does not match address') + shared.apiAddressGeneratorReturnQueue.put('chan name does not match address') saveAddressToDisk = False if command == 'getDeterministicAddress': saveAddressToDisk = False - if saveAddressToDisk and live: + if saveAddressToDisk: # An excellent way for us to store our keys is in Wallet Import Format. Let us convert now. # https://en.bitcoin.it/wiki/Wallet_import_format privSigningKey = '\x80' + potentialPrivSigningKey @@ -237,61 +222,60 @@ class addressGenerator(threading.Thread, StoppableThread): try: - BMConfigParser().add_section(address) + shared.config.add_section(address) addressAlreadyExists = False except: addressAlreadyExists = True if addressAlreadyExists: logger.info('%s already exists. Not adding it again.' % address) - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) else: logger.debug('label: %s' % label) - BMConfigParser().set(address, 'label', label) - BMConfigParser().set(address, 'enabled', 'true') - BMConfigParser().set(address, 'decoy', 'false') + shared.config.set(address, 'label', label) + shared.config.set(address, 'enabled', 'true') + shared.config.set(address, 'decoy', 'false') if command == 'joinChan' or command == 'createChan': - BMConfigParser().set(address, 'chan', 'true') - BMConfigParser().set(address, 'noncetrialsperbyte', str( + shared.config.set(address, 'chan', 'true') + shared.config.set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - BMConfigParser().set(address, 'payloadlengthextrabytes', str( + shared.config.set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - BMConfigParser().set( + shared.config.set( address, 'privSigningKey', privSigningKeyWIF) - BMConfigParser().set( + shared.config.set( address, 'privEncryptionKey', privEncryptionKeyWIF) - BMConfigParser().save() + shared.writeKeysFile() - queues.UISignalQueue.put(('writeNewAddressToTable', ( + shared.UISignalQueue.put(('writeNewAddressToTable', ( label, address, str(streamNumber)))) listOfNewAddressesToSendOutThroughTheAPI.append( address) shared.myECCryptorObjects[ripe.digest()] = highlevelcrypto.makeCryptor( - hexlify(potentialPrivEncryptionKey)) + potentialPrivEncryptionKey.encode('hex')) shared.myAddressesByHash[ripe.digest()] = address tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersionNumber) + encodeVarint(streamNumber) + ripe.digest()).digest()).digest()[32:] shared.myAddressesByTag[tag] = address if addressVersionNumber == 3: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV3Pubkey', ripe.digest())) # If this is a chan address, # the worker thread won't send out the pubkey over the network. elif addressVersionNumber == 4: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', address)) - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow", "Done generating address"))) - elif saveAddressToDisk and not live and not BMConfigParser().has_section(address): - listOfNewAddressesToSendOutThroughTheAPI.append(address) + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText("MainWindow", "Done generating address"))) + # Done generating addresses. if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': - queues.apiAddressGeneratorReturnQueue.put( + shared.apiAddressGeneratorReturnQueue.put( listOfNewAddressesToSendOutThroughTheAPI) elif command == 'getDeterministicAddress': - queues.apiAddressGeneratorReturnQueue.put(address) + shared.apiAddressGeneratorReturnQueue.put(address) else: raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) - queues.addressGeneratorQueue.task_done() + diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 2e456d8c..c91b1c23 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -12,16 +12,15 @@ import time import threading class objectHashHolder(threading.Thread): - size = 10 def __init__(self, sendDataThreadMailbox): - threading.Thread.__init__(self, name="objectHashHolder") + threading.Thread.__init__(self) self.shutdown = False self.sendDataThreadMailbox = sendDataThreadMailbox # This queue is used to submit data back to our associated sendDataThread. - self.collectionOfHashLists = [] - self.collectionOfPeerLists = [] - for i in range(objectHashHolder.size): - self.collectionOfHashLists.append([]) - self.collectionOfPeerLists.append([]) + self.collectionOfHashLists = {} + self.collectionOfPeerLists = {} + for i in range(10): + self.collectionOfHashLists[i] = [] + self.collectionOfPeerLists[i] = [] def run(self): iterator = 0 @@ -33,22 +32,14 @@ class objectHashHolder(threading.Thread): self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) self.collectionOfPeerLists[iterator] = [] iterator += 1 - iterator %= objectHashHolder.size + iterator %= 10 time.sleep(1) def holdHash(self,hash): - self.collectionOfHashLists[random.randrange(0, objectHashHolder.size)].append(hash) - - def hasHash(self, hash): - if hash in (hashlist for hashlist in self.collectionOfHashLists): - return True - return False + self.collectionOfHashLists[random.randrange(0, 10)].append(hash) def holdPeer(self,peerDetails): - self.collectionOfPeerLists[random.randrange(0, objectHashHolder.size)].append(peerDetails) - - def hashCount(self): - return sum([len(x) for x in self.collectionOfHashLists if type(x) is list]) + self.collectionOfPeerLists[random.randrange(0, 10)].append(peerDetails) def close(self): - self.shutdown = True + self.shutdown = True \ No newline at end of file diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 181ce30e..f9972fe6 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -8,34 +8,28 @@ import sys import string from subprocess import call # used when the API must execute an outside program import traceback -from binascii import hexlify from pyelliptic.openssl import OpenSSL import highlevelcrypto from addresses import * -from bmconfigparser import BMConfigParser import helper_generic from helper_generic import addDataPadding import helper_bitcoin import helper_inbox -import helper_msgcoding import helper_sent from helper_sql import * -from helper_ackPayload import genAckPayload -import protocol -import queues -import state import tr from debug import logger import l10n + class objectProcessor(threading.Thread): """ The objectProcessor thread, of which there is only one, receives network - objects (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. + objecs (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. """ def __init__(self): - threading.Thread.__init__(self, name="objectProcessor") + threading.Thread.__init__(self) """ It may be the case that the last time Bitmessage was running, the user closed it before it finished processing everything in the @@ -45,18 +39,18 @@ class objectProcessor(threading.Thread): """ queryreturn = sqlQuery( '''SELECT objecttype, data FROM objectprocessorqueue''') - for row in queryreturn: - objectType, data = row - queues.objectProcessorQueue.put((objectType,data)) + with shared.objectProcessorQueueSizeLock: + for row in queryreturn: + objectType, data = row + shared.objectProcessorQueueSize += len(data) + shared.objectProcessorQueue.put((objectType,data)) sqlExecute('''DELETE FROM objectprocessorqueue''') logger.debug('Loaded %s objects from disk into the objectProcessorQueue.' % str(len(queryreturn))) def run(self): while True: - objectType, data = queues.objectProcessorQueue.get() - - self.checkackdata(data) + objectType, data = shared.objectProcessorQueue.get() try: if objectType == 0: # getpubkey @@ -70,54 +64,31 @@ class objectProcessor(threading.Thread): elif objectType == 'checkShutdownVariable': # is more of a command, not an object type. Is used to get this thread past the queue.get() so that it will check the shutdown variable. pass else: - if isinstance(objectType, int): - logger.info('Don\'t know how to handle object type 0x%08X', objectType) - else: - logger.info('Don\'t know how to handle object type %s', objectType) - except helper_msgcoding.DecompressionSizeException as e: - logger.error("The object is too big after decompression (stopped decompressing at %ib, your configured limit %ib). Ignoring", e.size, BMConfigParser().safeGetInt("zlib", "maxsize")) + logger.critical('Error! Bug! The class_objectProcessor was passed an object type it doesn\'t recognize: %s' % str(objectType)) except varintDecodeError as e: logger.debug("There was a problem with a varint while processing an object. Some details: %s" % e) except Exception as e: logger.critical("Critical error within objectProcessorThread: \n%s" % traceback.format_exc()) - if state.shutdown: + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize -= len(data) # We maintain objectProcessorQueueSize so that we will slow down requesting objects if too much data accumulates in the queue. + + if shared.shutdown: time.sleep(.5) # Wait just a moment for most of the connections to close numberOfObjectsThatWereInTheObjectProcessorQueue = 0 with SqlBulkExecute() as sql: - while queues.objectProcessorQueue.curSize > 0: - objectType, data = queues.objectProcessorQueue.get() + while shared.objectProcessorQueueSize > 1: + objectType, data = shared.objectProcessorQueue.get() sql.execute('''INSERT INTO objectprocessorqueue VALUES (?,?)''', objectType,data) + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize -= len(data) # We maintain objectProcessorQueueSize so that we will slow down requesting objects if too much data accumulates in the queue. numberOfObjectsThatWereInTheObjectProcessorQueue += 1 logger.debug('Saved %s objects from the objectProcessorQueue to disk. objectProcessorThread exiting.' % str(numberOfObjectsThatWereInTheObjectProcessorQueue)) - state.shutdown = 2 + shared.shutdown = 2 break - - def checkackdata(self, data): - # Let's check whether this is a message acknowledgement bound for us. - if len(data) < 32: - return - - # bypass nonce and time, retain object type/version/stream + body - readPosition = 16 - - if data[readPosition:] in shared.ackdataForWhichImWatching: - logger.info('This object is an acknowledgement bound for me.') - del shared.ackdataForWhichImWatching[data[readPosition:]] - sqlExecute('UPDATE sent SET status=?, lastactiontime=? WHERE ackdata=?', - 'ackreceived', - int(time.time()), - data[readPosition:]) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[readPosition:], tr._translate("MainWindow",'Acknowledgement of the message received %1').arg(l10n.formatTimestamp())))) - else: - logger.debug('This object is not an acknowledgement bound for me.') - def processgetpubkey(self, data): - if len(data) > 200: - logger.info('getpubkey is abnormally long. Sanity check failed. Ignoring object.') - return readPosition = 20 # bypass the nonce, time, and object type requestedAddressVersionNumber, addressVersionLength = decodeVarint( data[readPosition:readPosition + 10]) @@ -142,7 +113,7 @@ class objectProcessor(threading.Thread): if len(requestedHash) != 20: logger.debug('The length of the requested hash is not 20 bytes. Something is wrong. Ignoring.') return - logger.info('the hash requested in this getpubkey request is: %s' % hexlify(requestedHash)) + logger.info('the hash requested in this getpubkey request is: %s' % requestedHash.encode('hex')) if requestedHash in shared.myAddressesByHash: # if this address hash is one of mine myAddress = shared.myAddressesByHash[requestedHash] elif requestedAddressVersionNumber >= 4: @@ -150,7 +121,7 @@ class objectProcessor(threading.Thread): if len(requestedTag) != 32: logger.debug('The length of the requested tag is not 32 bytes. Something is wrong. Ignoring.') return - logger.debug('the tag requested in this getpubkey request is: %s' % hexlify(requestedTag)) + logger.debug('the tag requested in this getpubkey request is: %s' % requestedTag.encode('hex')) if requestedTag in shared.myAddressesByTag: myAddress = shared.myAddressesByTag[requestedTag] @@ -164,11 +135,11 @@ class objectProcessor(threading.Thread): if decodeAddress(myAddress)[2] != streamNumber: logger.warning('(Within the processgetpubkey function) Someone requested one of my pubkeys but the stream number on which we heard this getpubkey object doesn\'t match this address\' stream number. Ignoring.') return - if BMConfigParser().safeGetBoolean(myAddress, 'chan'): + if shared.safeConfigGetBoolean(myAddress, 'chan'): logger.info('Ignoring getpubkey request because it is for one of my chan addresses. The other party should already have the pubkey.') return try: - lastPubkeySendTime = int(BMConfigParser().get( + lastPubkeySendTime = int(shared.config.get( myAddress, 'lastpubkeysendtime')) except: lastPubkeySendTime = 0 @@ -177,19 +148,19 @@ class objectProcessor(threading.Thread): return logger.info('Found getpubkey-requested-hash in my list of EC hashes. Telling Worker thread to do the POW for a pubkey message and send it out.') if requestedAddressVersionNumber == 2: - queues.workerQueue.put(( + shared.workerQueue.put(( 'doPOWForMyV2Pubkey', requestedHash)) elif requestedAddressVersionNumber == 3: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV3Pubkey', requestedHash)) elif requestedAddressVersionNumber == 4: - queues.workerQueue.put(( + shared.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', myAddress)) def processpubkey(self, data): pubkeyProcessingStartTime = time.time() shared.numberOfPubkeysProcessed += 1 - queues.UISignalQueue.put(( + shared.UISignalQueue.put(( 'updateNumberOfPubkeysProcessed', 'no data')) embeddedTime, = unpack('>Q', data[8:16]) readPosition = 20 # bypass the nonce, time, and object type @@ -235,9 +206,9 @@ class objectProcessor(threading.Thread): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - hexlify(ripe), - hexlify(publicSigningKey), - hexlify(publicEncryptionKey) + ripe.encode('hex'), + publicSigningKey.encode('hex'), + publicEncryptionKey.encode('hex') ) ) @@ -276,7 +247,7 @@ class objectProcessor(threading.Thread): data[readPosition:readPosition + 10]) readPosition += signatureLengthLength signature = data[readPosition:readPosition + signatureLength] - if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, hexlify(publicSigningKey)): + if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, publicSigningKey.encode('hex')): logger.debug('ECDSA verify passed (within processpubkey)') else: logger.warning('ECDSA verify failed (within processpubkey)') @@ -294,9 +265,9 @@ class objectProcessor(threading.Thread): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - hexlify(ripe), - hexlify(publicSigningKey), - hexlify(publicEncryptionKey) + ripe.encode('hex'), + publicSigningKey.encode('hex'), + publicEncryptionKey.encode('hex') ) ) @@ -317,12 +288,12 @@ class objectProcessor(threading.Thread): return tag = data[readPosition:readPosition + 32] - if tag not in state.neededPubkeys: + if tag not in shared.neededPubkeys: logger.info('We don\'t need this v4 pubkey. We didn\'t ask for it.') return # Let us try to decrypt the pubkey - toAddress, cryptorObject = state.neededPubkeys[tag] + toAddress, cryptorObject = shared.neededPubkeys[tag] if shared.decryptAndCheckPubkeyPayload(data, toAddress) == 'successful': # At this point we know that we have been waiting on this pubkey. # This function will command the workerThread to start work on @@ -338,7 +309,7 @@ class objectProcessor(threading.Thread): def processmsg(self, data): messageProcessingStartTime = time.time() shared.numberOfMessagesProcessed += 1 - queues.UISignalQueue.put(( + shared.UISignalQueue.put(( 'updateNumberOfMessagesProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9]) @@ -352,19 +323,30 @@ class objectProcessor(threading.Thread): readPosition += streamNumberAsClaimedByMsgLength inventoryHash = calculateInventoryHash(data) initialDecryptionSuccessful = False + # Let's check whether this is a message acknowledgement bound for us. + if data[-32:] in shared.ackdataForWhichImWatching: + logger.info('This msg IS an acknowledgement bound for me.') + del shared.ackdataForWhichImWatching[data[-32:]] + sqlExecute('UPDATE sent SET status=?, lastactiontime=? WHERE ackdata=?', + 'ackreceived', + int(time.time()), + data[-32:]) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp())))) + return + else: + logger.info('This was NOT an acknowledgement bound for me.') + # This is not an acknowledgement bound for me. See if it is a message # bound for me by trying to decrypt it with my private keys. - for key, cryptorObject in sorted(shared.myECCryptorObjects.items(), key=lambda x: random.random()): + for key, cryptorObject in shared.myECCryptorObjects.items(): try: - if initialDecryptionSuccessful: # continue decryption attempts to avoid timing attacks - cryptorObject.decrypt(data[readPosition:]) - else: - decryptedData = cryptorObject.decrypt(data[readPosition:]) - toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data. - initialDecryptionSuccessful = True - logger.info('EC decryption successful using key associated with ripe hash: %s.' % hexlify(key)) + decryptedData = cryptorObject.decrypt(data[readPosition:]) + toRipe = key # This is the RIPE hash of my pubkeys. We need this below to compare to the destination_ripe included in the encrypted data. + initialDecryptionSuccessful = True + logger.info('EC decryption successful using key associated with ripe hash: %s.' % key.encode('hex')) + break except Exception as err: pass if not initialDecryptionSuccessful: @@ -416,7 +398,7 @@ class objectProcessor(threading.Thread): logger.info('The original sender of this message did not send it to you. Someone is attempting a Surreptitious Forwarding Attack.\n\ See: http://world.std.com/~dtd/sign_encrypt/sign_encrypt7.html \n\ your toRipe: %s\n\ - embedded destination toRipe: %s' % (hexlify(toRipe), hexlify(decryptedData[readPosition:readPosition + 20])) + embedded destination toRipe: %s' % (toRipe.encode('hex'), decryptedData[readPosition:readPosition + 20].encode('hex')) ) return readPosition += 20 @@ -442,7 +424,7 @@ class objectProcessor(threading.Thread): readPosition:readPosition + signatureLength] signedData = data[8:20] + encodeVarint(1) + encodeVarint(streamNumberAsClaimedByMsg) + decryptedData[:positionOfBottomOfAckData] - if not highlevelcrypto.verify(signedData, signature, hexlify(pubSigningKey)): + if not highlevelcrypto.verify(signedData, signature, pubSigningKey.encode('hex')): logger.debug('ECDSA verify failed') return logger.debug('ECDSA verify passed') @@ -479,17 +461,17 @@ class objectProcessor(threading.Thread): # proof of work requirement. If this is bound for one of my chan # addresses then we skip this check; the minimum network POW is # fine. - if decodeAddress(toAddress)[1] >= 3 and not BMConfigParser().safeGetBoolean(toAddress, 'chan'): # If the toAddress version number is 3 or higher and not one of my chan addresses: + if decodeAddress(toAddress)[1] >= 3 and not shared.safeConfigGetBoolean(toAddress, 'chan'): # If the toAddress version number is 3 or higher and not one of my chan addresses: if not shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(fromAddress): # If I'm not friendly with this person: - requiredNonceTrialsPerByte = BMConfigParser().getint( + requiredNonceTrialsPerByte = shared.config.getint( toAddress, 'noncetrialsperbyte') - requiredPayloadLengthExtraBytes = BMConfigParser().getint( + requiredPayloadLengthExtraBytes = shared.config.getint( toAddress, 'payloadlengthextrabytes') - if not protocol.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes): + if not shared.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes): logger.info('Proof of work in msg is insufficient only because it does not meet our higher requirement.') return blockMessage = False # Gets set to True if the user shouldn't see the message according to black or white lists. - if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist queryreturn = sqlQuery( '''SELECT label FROM blacklist where address=? and enabled='1' ''', fromAddress) @@ -504,18 +486,24 @@ class objectProcessor(threading.Thread): if queryreturn == []: logger.info('Message ignored because address not in whitelist.') blockMessage = True - - toLabel = BMConfigParser().get(toAddress, 'label') + + toLabel = shared.config.get(toAddress, 'label') if toLabel == '': toLabel = toAddress - try: - decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) - except helper_msgcoding.MsgDecodeException: - return - subject = decodedMessage.subject - body = decodedMessage.body - + if messageEncodingType == 2: + subject, body = self.decodeType2Message(message) + logger.info('Message subject (first 100 characters): %s' % repr(subject)[:100]) + elif messageEncodingType == 1: + body = message + subject = '' + elif messageEncodingType == 0: + logger.info('messageEncodingType == 0. Doing nothing with the message. They probably just sent it so that we would store their public key or send their ack data for them.') + subject = '' + body = '' + else: + body = 'Unknown encoding type.\n\n' + repr(message) + subject = '' # Let us make sure that we haven't already received this message if helper_inbox.isMessageAlreadyInInbox(sigHash): logger.info('This msg is already in our inbox. Ignoring it.') @@ -526,15 +514,15 @@ class objectProcessor(threading.Thread): time.time()), body, 'inbox', messageEncodingType, 0, sigHash) helper_inbox.insert(t) - queues.UISignalQueue.put(('displayNewInboxMessage', ( + shared.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toAddress, fromAddress, subject, body))) # If we are behaving as an API then we might need to run an # outside command to let some program know that a new message # has arrived. - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = BMConfigParser().get( + apiNotifyPath = shared.config.get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -543,9 +531,9 @@ class objectProcessor(threading.Thread): # Let us now check and see whether our receiving address is # behaving as a mailing list - if BMConfigParser().safeGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: + if shared.safeConfigGetBoolean(toAddress, 'mailinglist'): try: - mailingListName = BMConfigParser().get( + mailingListName = shared.config.get( toAddress, 'mailinglistname') except: mailingListName = '' @@ -556,10 +544,8 @@ class objectProcessor(threading.Thread): message = time.strftime("%a, %Y-%m-%d %H:%M:%S UTC", time.gmtime( )) + ' Message ostensibly from ' + fromAddress + ':\n\n' + body fromAddress = toAddress # The fromAddress for the broadcast that we are about to send is the toAddress (my address) for the msg message we are currently processing. - # We don't actually need the ackdata for acknowledgement since this is a broadcast message but we can use it to update the user interface when the POW is done generating. - streamNumber = decodeAddress(fromAddress)[2] - - ackdata = genAckPayload(streamNumber, 0) + ackdataForBroadcast = OpenSSL.rand( + 32) # We don't actually need the ackdataForBroadcast for acknowledgement since this is a broadcast message but we can use it to update the user interface when the POW is done generating. toAddress = '[Broadcast subscribers]' ripe = '' @@ -573,27 +559,22 @@ class objectProcessor(threading.Thread): fromAddress, subject, message, - ackdata, + ackdataForBroadcast, int(time.time()), # sentTime (this doesn't change) int(time.time()), # lastActionTime 0, 'broadcastqueued', 0, 'sent', - messageEncodingType, + 2, TTL) helper_sent.insert(t) - queues.UISignalQueue.put(('displayNewSentMessage', ( - toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdata))) - queues.workerQueue.put(('sendbroadcast', '')) + shared.UISignalQueue.put(('displayNewSentMessage', ( + toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdataForBroadcast))) + shared.workerQueue.put(('sendbroadcast', '')) - # Don't send ACK if invalid, blacklisted senders, invisible messages, disabled or chan - if self.ackDataHasAValidHeader(ackData) and \ - not blockMessage and \ - messageEncodingType != 0 and \ - not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \ - not BMConfigParser().safeGetBoolean(toAddress, 'chan'): + if self.ackDataHasAVaildHeader(ackData): shared.checkAndShareObjectWithPeers(ackData[24:]) # Display timing data @@ -613,7 +594,7 @@ class objectProcessor(threading.Thread): def processbroadcast(self, data): messageProcessingStartTime = time.time() shared.numberOfBroadcastsProcessed += 1 - queues.UISignalQueue.put(( + shared.UISignalQueue.put(( 'updateNumberOfBroadcastsProcessed', 'no data')) inventoryHash = calculateInventoryHash(data) readPosition = 20 # bypass the nonce, time, and object type @@ -634,15 +615,13 @@ class objectProcessor(threading.Thread): """ signedData = data[8:readPosition] initialDecryptionSuccessful = False - for key, cryptorObject in sorted(shared.MyECSubscriptionCryptorObjects.items(), key=lambda x: random.random()): + for key, cryptorObject in shared.MyECSubscriptionCryptorObjects.items(): try: - if initialDecryptionSuccessful: # continue decryption attempts to avoid timing attacks - cryptorObject.decrypt(data[readPosition:]) - else: - decryptedData = cryptorObject.decrypt(data[readPosition:]) - toRipe = key # This is the RIPE hash of the sender's pubkey. We need this below to compare to the RIPE hash of the sender's address to verify that it was encrypted by with their key rather than some other key. - initialDecryptionSuccessful = True - logger.info('EC decryption successful using key associated with ripe hash: %s' % hexlify(key)) + decryptedData = cryptorObject.decrypt(data[readPosition:]) + toRipe = key # This is the RIPE hash of the sender's pubkey. We need this below to compare to the RIPE hash of the sender's address to verify that it was encrypted by with their key rather than some other key. + initialDecryptionSuccessful = True + logger.info('EC decryption successful using key associated with ripe hash: %s' % key.encode('hex')) + break except Exception as err: pass # print 'cryptorObject.decrypt Exception:', err @@ -737,7 +716,7 @@ class objectProcessor(threading.Thread): signature = decryptedData[ readPosition:readPosition + signatureLength] signedData += decryptedData[:readPositionAtBottomOfMessage] - if not highlevelcrypto.verify(signedData, signature, hexlify(sendersPubSigningKey)): + if not highlevelcrypto.verify(signedData, signature, sendersPubSigningKey.encode('hex')): logger.debug('ECDSA verify failed') return logger.debug('ECDSA verify passed') @@ -762,14 +741,21 @@ class objectProcessor(threading.Thread): fromAddress = encodeAddress( sendersAddressVersion, sendersStream, calculatedRipe) - logger.debug('fromAddress: ' + fromAddress) + with shared.printLock: + print 'fromAddress:', fromAddress - try: - decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) - except helper_msgcoding.MsgDecodeException: + if messageEncodingType == 2: + subject, body = self.decodeType2Message(message) + logger.info('Broadcast subject (first 100 characters): %s' % repr(subject)[:100]) + elif messageEncodingType == 1: + body = message + subject = '' + elif messageEncodingType == 0: + logger.info('messageEncodingType == 0. Doing nothing with the message.') return - subject = decodedMessage.subject - body = decodedMessage.body + else: + body = 'Unknown encoding type.\n\n' + repr(message) + subject = '' toAddress = '[Broadcast subscribers]' if helper_inbox.isMessageAlreadyInInbox(sigHash): @@ -779,15 +765,15 @@ class objectProcessor(threading.Thread): time.time()), body, 'inbox', messageEncodingType, 0, sigHash) helper_inbox.insert(t) - queues.UISignalQueue.put(('displayNewInboxMessage', ( + shared.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toAddress, fromAddress, subject, body))) # If we are behaving as an API then we might need to run an # outside command to let some program know that a new message # has arrived. - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = BMConfigParser().get( + apiNotifyPath = shared.config.get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -809,8 +795,8 @@ class objectProcessor(threading.Thread): # stream number, and RIPE hash. status, addressVersion, streamNumber, ripe = decodeAddress(address) if addressVersion <=3: - if address in state.neededPubkeys: - del state.neededPubkeys[address] + if address in shared.neededPubkeys: + del shared.neededPubkeys[address] self.sendMessages(address) else: logger.debug('We don\'t need this pub key. We didn\'t ask for it. For address: %s' % address) @@ -820,8 +806,8 @@ class objectProcessor(threading.Thread): elif addressVersion >= 4: tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] - if tag in state.neededPubkeys: - del state.neededPubkeys[tag] + if tag in shared.neededPubkeys: + del shared.neededPubkeys[tag] self.sendMessages(address) def sendMessages(self, address): @@ -834,18 +820,18 @@ class objectProcessor(threading.Thread): sqlExecute( '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='awaitingpubkey' or status='doingpubkeypow') AND folder='sent' ''', address) - queues.workerQueue.put(('sendmessage', '')) + shared.workerQueue.put(('sendmessage', '')) - def ackDataHasAValidHeader(self, ackData): - if len(ackData) < protocol.Header.size: + def ackDataHasAVaildHeader(self, ackData): + if len(ackData) < shared.Header.size: logger.info('The length of ackData is unreasonably short. Not sending ackData.') return False - magic,command,payloadLength,checksum = protocol.Header.unpack(ackData[:protocol.Header.size]) + magic,command,payloadLength,checksum = shared.Header.unpack(ackData[:shared.Header.size]) if magic != 0xE9BEB4D9: logger.info('Ackdata magic bytes were wrong. Not sending ackData.') return False - payload = ackData[protocol.Header.size:] + payload = ackData[shared.Header.size:] if len(payload) != payloadLength: logger.info('ackData payload length doesn\'t match the payload length specified in the header. Not sending ackdata.') return False diff --git a/src/class_objectProcessorQueue.py b/src/class_objectProcessorQueue.py deleted file mode 100644 index 6309e994..00000000 --- a/src/class_objectProcessorQueue.py +++ /dev/null @@ -1,27 +0,0 @@ -import Queue -import threading -import time - -class ObjectProcessorQueue(Queue.Queue): - maxSize = 32000000 - - def __init__(self): - Queue.Queue.__init__(self) - self.sizeLock = threading.Lock() - self.curSize = 0 # in Bytes. We maintain this to prevent nodes from flooing us with objects which take up too much memory. If this gets too big we'll sleep before asking for further objects. - - def put(self, item, block = True, timeout = None): - while self.curSize >= self.maxSize: - time.sleep(1) - with self.sizeLock: - self.curSize += len(item[1]) - Queue.Queue.put(self, item, block, timeout) - - def get(self, block = True, timeout = None): - try: - item = Queue.Queue.get(self, block, timeout) - except Queue.Empty as e: - raise Queue.Empty() - with self.sizeLock: - self.curSize -= len(item[1]) - return item diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 9b3eac14..453acfe1 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -1,9 +1,7 @@ -import errno import threading import time import random import shared -import select import socks import socket import sys @@ -11,21 +9,14 @@ import tr from class_sendDataThread import * from class_receiveDataThread import * -from bmconfigparser import BMConfigParser -from helper_threading import * -import knownnodes -import queues -import state # For each stream to which we connect, several outgoingSynSender threads # will exist and will collectively create 8 connections with peers. -class outgoingSynSender(threading.Thread, StoppableThread): +class outgoingSynSender(threading.Thread): def __init__(self): - threading.Thread.__init__(self, name="outgoingSynSender") - self.initStop() - random.seed() + threading.Thread.__init__(self) def setup(self, streamNumber, selfInitiatedConnections): self.streamNumber = streamNumber @@ -35,84 +26,50 @@ class outgoingSynSender(threading.Thread, StoppableThread): # If the user has specified a trusted peer then we'll only # ever connect to that. Otherwise we'll pick a random one from # the known nodes - if state.trustedPeer: - with knownnodes.knownNodesLock: - peer = state.trustedPeer - knownnodes.knownNodes[self.streamNumber][peer] = time.time() + shared.knownNodesLock.acquire() + if shared.trustedPeer: + peer = shared.trustedPeer + shared.knownNodes[self.streamNumber][peer] = time.time() else: - while not self._stopped: - try: - with knownnodes.knownNodesLock: - peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) - priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours - except ValueError: # no known nodes - self.stop.wait(1) - continue - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': - if peer.host.find(".onion") == -1: - priority /= 10 # hidden services have 10x priority over plain net - else: - # don't connect to self - if peer.host == BMConfigParser().get('bitmessagesettings', 'onionhostname') and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport"): - continue - elif peer.host.find(".onion") != -1: # onion address and so proxy - continue - if priority <= 0.001: # everyone has at least this much priority - priority = 0.001 - if (random.random() <= priority): - break - self.stop.wait(0.01) # prevent CPU hogging if something is broken - try: - return peer - except NameError: - return state.Peer('127.0.0.1', 8444) - - def stopThread(self): - super(outgoingSynSender, self).stopThread() - try: - self.sock.shutdown(socket.SHUT_RDWR) - except: - pass + peer, = random.sample(shared.knownNodes[self.streamNumber], 1) + shared.knownNodesLock.release() + + return peer def run(self): - while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: - self.stop.wait(2) - while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: - self.name = "outgoingSynSender" - maximumConnections = 1 if state.trustedPeer else BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') - while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections and not self._stopped: - self.stop.wait(10) - if state.shutdown: + while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + time.sleep(2) + while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): + maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 + while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: + time.sleep(10) + if shared.shutdown: break + random.seed() peer = self._getPeer() + shared.alreadyAttemptedConnectionsListLock.acquire() while peer in shared.alreadyAttemptedConnectionsList or peer.host in shared.connectedHostsList: + shared.alreadyAttemptedConnectionsListLock.release() # print 'choosing new sample' + random.seed() peer = self._getPeer() - self.stop.wait(1) - if self._stopped: - break + time.sleep(1) # Clear out the shared.alreadyAttemptedConnectionsList every half # hour so that this program will again attempt a connection # to any nodes, even ones it has already tried. - with shared.alreadyAttemptedConnectionsListLock: - if (time.time() - shared.alreadyAttemptedConnectionsListResetTime) > 1800: - shared.alreadyAttemptedConnectionsList.clear() - shared.alreadyAttemptedConnectionsListResetTime = int( - time.time()) + if (time.time() - shared.alreadyAttemptedConnectionsListResetTime) > 1800: + shared.alreadyAttemptedConnectionsList.clear() + shared.alreadyAttemptedConnectionsListResetTime = int( + time.time()) + shared.alreadyAttemptedConnectionsListLock.acquire() shared.alreadyAttemptedConnectionsList[peer] = 0 - if self._stopped: - break - self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator - address_family = socket.AF_INET - # Proxy IP is IPv6. Unlikely but possible - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': - if ":" in BMConfigParser().get('bitmessagesettings', 'sockshostname'): - address_family = socket.AF_INET6 - # No proxy, and destination is IPv6 - elif peer.host.find(':') >= 0 : + shared.alreadyAttemptedConnectionsListLock.release() + if peer.host.find(':') == -1: + address_family = socket.AF_INET + else: address_family = socket.AF_INET6 try: - self.sock = socks.socksocket(address_family, socket.SOCK_STREAM) + sock = socks.socksocket(address_family, socket.SOCK_STREAM) except: """ The line can fail on Windows systems which aren't @@ -123,161 +80,154 @@ class outgoingSynSender(threading.Thread, StoppableThread): So let us remove the offending address from our knownNodes file. """ - with knownnodes.knownNodesLock: - try: - del knownnodes.knownNodes[self.streamNumber][peer] - except KeyError: - pass - logger.debug('deleting ' + str(peer) + ' from knownnodes.knownNodes because it caused a socks.socksocket exception. We must not be 64-bit compatible.') + shared.knownNodesLock.acquire() + try: + del shared.knownNodes[self.streamNumber][peer] + except: + pass + shared.knownNodesLock.release() + with shared.printLock: + print 'deleting ', peer, 'from shared.knownNodes because it caused a socks.socksocket exception. We must not be 64-bit compatible.' continue # This option apparently avoids the TIME_WAIT state so that we # can rebind faster - self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.sock.settimeout(20) - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: - logger.debug('Trying an outgoing connection to ' + str(peer)) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.settimeout(20) + if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: + with shared.printLock: + print 'Trying an outgoing connection to', peer # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': + elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': if shared.verbose >= 2: - logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) + with shared.printLock: + print '(Using SOCKS4a) Trying an outgoing connection to', peer proxytype = socks.PROXY_TYPE_SOCKS4 - sockshostname = BMConfigParser().get( + sockshostname = shared.config.get( 'bitmessagesettings', 'sockshostname') - socksport = BMConfigParser().getint( + socksport = shared.config.getint( 'bitmessagesettings', 'socksport') rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = BMConfigParser().get( + if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = shared.config.get( 'bitmessagesettings', 'socksusername') - sockspassword = BMConfigParser().get( + sockspassword = shared.config.get( 'bitmessagesettings', 'sockspassword') - self.sock.setproxy( + sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: - self.sock.setproxy( + sock.setproxy( proxytype, sockshostname, socksport, rdns) - elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': if shared.verbose >= 2: - logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) + with shared.printLock: + print '(Using SOCKS5) Trying an outgoing connection to', peer proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = BMConfigParser().get( + sockshostname = shared.config.get( 'bitmessagesettings', 'sockshostname') - socksport = BMConfigParser().getint( + socksport = shared.config.getint( 'bitmessagesettings', 'socksport') rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = BMConfigParser().get( + if shared.config.getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = shared.config.get( 'bitmessagesettings', 'socksusername') - sockspassword = BMConfigParser().get( + sockspassword = shared.config.get( 'bitmessagesettings', 'sockspassword') - self.sock.setproxy( + sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: - self.sock.setproxy( + sock.setproxy( proxytype, sockshostname, socksport, rdns) try: - self.sock.connect((peer.host, peer.port)) - if self._stopped: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - return - sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. - - sd = sendDataThread(sendDataThreadQueue) - sd.setup(self.sock, peer.host, peer.port, self.streamNumber) - sd.start() - + sock.connect((peer.host, peer.port)) rd = receiveDataThread() rd.daemon = True # close the main program even if there are threads left - rd.setup(self.sock, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. + sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. + rd.setup(sock, peer.host, peer.port, self.streamNumber, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, - sendDataThreadQueue, - sd.objectHashHolderInstance) + sendDataThreadQueue) rd.start() + with shared.printLock: + print self, 'connected to', peer, 'during an outgoing attempt.' + + sd = sendDataThread(sendDataThreadQueue) + sd.setup(sock, peer.host, peer.port, self.streamNumber, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware) + sd.start() sd.sendVersionMessage() - logger.debug(str(self) + ' connected to ' + str(peer) + ' during an outgoing attempt.') except socks.GeneralProxyError as err: - if err[0][0] in [7, 8, 9]: - logger.error('Error communicating with proxy: %s', str(err)) - queues.UISignalQueue.put(( - 'updateStatusBar', - tr._translate( - "MainWindow", "Problem communicating with proxy: %1. Please check your network settings.").arg(str(err[0][1])) - )) - self.stop.wait(1) - continue - elif shared.verbose >= 2: - logger.debug('Could NOT connect to ' + str(peer) + ' during outgoing attempt. ' + str(err)) + if shared.verbose >= 2: + with shared.printLock: + print 'Could NOT connect to', peer, 'during outgoing attempt.', err deletedPeer = None - with knownnodes.knownNodesLock: + with shared.knownNodesLock: """ - It is remotely possible that peer is no longer in knownnodes.knownNodes. + It is remotely possible that peer is no longer in shared.knownNodes. This could happen if two outgoingSynSender threads both try to connect to the same peer, both fail, and then both try to remove - it from knownnodes.knownNodes. This is unlikely because of the + it from shared.knownNodes. This is unlikely because of the alreadyAttemptedConnectionsList but because we clear that list once every half hour, it can happen. """ - if peer in knownnodes.knownNodes[self.streamNumber]: - timeLastSeen = knownnodes.knownNodes[self.streamNumber][peer] - if (int(time.time()) - timeLastSeen) > 172800 and len(knownnodes.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownnodes.knownNodes data-structure. - del knownnodes.knownNodes[self.streamNumber][peer] + if peer in shared.knownNodes[self.streamNumber]: + timeLastSeen = shared.knownNodes[self.streamNumber][peer] + if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure. + del shared.knownNodes[self.streamNumber][peer] deletedPeer = peer if deletedPeer: - str ('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') + with shared.printLock: + print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.' except socks.Socks5AuthError as err: - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate( - "MainWindow", "SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings.").arg(str(err)))) + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText( + "MainWindow", "SOCKS5 Authentication problem: %1").arg(str(err)))) except socks.Socks5Error as err: - if err[0][0] in [3, 4, 5, 6]: - # this is a more bening "error": host unreachable, network unreachable, connection refused, TTL expired - logger.debug('SOCKS5 error: %s', str(err)) - else: - logger.error('SOCKS5 error: %s', str(err)) - if err[0][0] == 4 or err[0][0] == 2: - state.networkProtocolAvailability[protocol.networkType(peer.host)] = False + pass + print 'SOCKS5 error. (It is possible that the server wants authentication).)', str(err) except socks.Socks4Error as err: - logger.error('Socks4Error: ' + str(err)) + print 'Socks4Error:', err except socket.error as err: - if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': - logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) + if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': + print 'Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err) else: - if err[0] == errno.ENETUNREACH: - state.networkProtocolAvailability[protocol.networkType(peer.host)] = False if shared.verbose >= 1: - logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) + with shared.printLock: + print 'Could NOT connect to', peer, 'during outgoing attempt.', err deletedPeer = None - with knownnodes.knownNodesLock: + with shared.knownNodesLock: """ - It is remotely possible that peer is no longer in knownnodes.knownNodes. + It is remotely possible that peer is no longer in shared.knownNodes. This could happen if two outgoingSynSender threads both try to connect to the same peer, both fail, and then both try to remove - it from knownnodes.knownNodes. This is unlikely because of the + it from shared.knownNodes. This is unlikely because of the alreadyAttemptedConnectionsList but because we clear that list once every half hour, it can happen. """ - if peer in knownnodes.knownNodes[self.streamNumber]: - timeLastSeen = knownnodes.knownNodes[self.streamNumber][peer] - if (int(time.time()) - timeLastSeen) > 172800 and len(knownnodes.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the knownnodes.knownNodes data-structure. - del knownnodes.knownNodes[self.streamNumber][peer] + if peer in shared.knownNodes[self.streamNumber]: + timeLastSeen = shared.knownNodes[self.streamNumber][peer] + if (int(time.time()) - timeLastSeen) > 172800 and len(shared.knownNodes[self.streamNumber]) > 1000: # for nodes older than 48 hours old if we have more than 1000 hosts in our list, delete from the shared.knownNodes data-structure. + del shared.knownNodes[self.streamNumber][peer] deletedPeer = peer if deletedPeer: - logger.debug('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') + with shared.printLock: + print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.' except Exception as err: + sys.stderr.write( + 'An exception has occurred in the outgoingSynSender thread that was not caught by other exception types: ') import traceback - logger.exception('An exception has occurred in the outgoingSynSender thread that was not caught by other exception types:') - self.stop.wait(0.1) + traceback.print_exc() + time.sleep(0.1) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 4e86196c..ff5371ad 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,43 +1,23 @@ -doTimingAttackMitigation = False +doTimingAttackMitigation = True -import base64 -import datetime -import errno -import math import time import threading import shared import hashlib -import os -import Queue -import select import socket import random -import ssl from struct import unpack, pack import sys import traceback -from binascii import hexlify #import string #from subprocess import call # used when the API must execute an outside program #from pyelliptic.openssl import OpenSSL #import highlevelcrypto from addresses import * -from bmconfigparser import BMConfigParser -from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery -import knownnodes from debug import logger -import paths -import protocol -from inventory import Inventory, PendingDownloadQueue, PendingUpload -import queues -import state -import throttle -import tr -from version import softwareVersion # This thread is created either by the synSenderThread(for outgoing # connections) or the singleListenerThread(for incoming connections). @@ -45,7 +25,7 @@ from version import softwareVersion class receiveDataThread(threading.Thread): def __init__(self): - threading.Thread.__init__(self, name="receiveData") + threading.Thread.__init__(self) self.data = '' self.verackSent = False self.verackReceived = False @@ -56,139 +36,109 @@ class receiveDataThread(threading.Thread): HOST, port, streamNumber, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware, selfInitiatedConnections, - sendDataThreadQueue, - objectHashHolderInstance): + sendDataThreadQueue): self.sock = sock - self.peer = state.Peer(HOST, port) - self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator - self.streamNumber = state.streamsInWhichIAmParticipating - self.remoteStreams = [] + self.peer = shared.Peer(HOST, port) + self.streamNumber = streamNumber + self.objectsThatWeHaveYetToGetFromThisPeer = {} self.selfInitiatedConnections = selfInitiatedConnections self.sendDataThreadQueue = sendDataThreadQueue # used to send commands and data to the sendDataThread - self.hostIdent = self.peer.port if ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname') and protocol.checkSocksIP(self.peer.host) else self.peer.host shared.connectedHostsList[ - self.hostIdent] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it. + self.peer.host] = 0 # The very fact that this receiveData thread exists shows that we are connected to the remote host. Let's add it to this list so that an outgoingSynSender thread doesn't try to connect to it. self.connectionIsOrWasFullyEstablished = False # set to true after the remote node and I accept each other's version messages. This is needed to allow the user interface to accurately reflect the current number of connections. - self.services = 0 - if streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. + if self.streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. self.initiatedConnection = False else: self.initiatedConnection = True - for stream in self.streamNumber: - self.selfInitiatedConnections[stream][self] = 0 - self.objectHashHolderInstance = objectHashHolderInstance - self.downloadQueue = PendingDownloadQueue() - self.startTime = time.time() + self.selfInitiatedConnections[streamNumber][self] = 0 + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware def run(self): - logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) + with shared.printLock: + print 'receiveDataThread starting. ID', str(id(self)) + '. The size of the shared.connectedHostsList is now', len(shared.connectedHostsList) - while state.shutdown == 0: + while True: + if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0: + downloadRateLimitBytes = float("inf") + else: + downloadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxdownloadrate') * 1000 + with shared.receiveDataLock: + while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes: + if int(time.time()) == shared.lastTimeWeResetBytesReceived: + # If it's still the same second that it was last time then sleep. + time.sleep(0.3) + else: + # It's a new second. Let us clear the shared.numberOfBytesReceivedLastSecond. + shared.lastTimeWeResetBytesReceived = int(time.time()) + shared.numberOfBytesReceivedLastSecond = 0 dataLen = len(self.data) try: - isSSL = False - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - self.connectionIsOrWasFullyEstablished and - protocol.haveSSL(not self.initiatedConnection)): - isSSL = True - dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) - else: - dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) + dataRecv = self.sock.recv(1024) self.data += dataRecv - throttle.ReceiveThrottle().wait(len(dataRecv)) + shared.numberOfBytesReceived += len(dataRecv) # for the 'network status' UI tab. The UI clears this value whenever it updates. + shared.numberOfBytesReceivedLastSecond += len(dataRecv) # for the download rate limit except socket.timeout: - if self.connectionIsOrWasFullyEstablished: - self.sendping("Still around!") - continue - logger.error("Timeout during protocol initialisation") + with shared.printLock: + print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')' break - except ssl.SSLError as err: - if err.errno == ssl.SSL_ERROR_WANT_READ: - select.select([self.sslSock], [], [], 10) - logger.debug('sock.recv retriable SSL error') - continue - if err.errno is None and 'timed out' in str(err): - if self.connectionIsOrWasFullyEstablished: - self.sendping("Still around!") - continue - logger.error ('SSL error: %i/%s', err.errno if err.errno else 0, str(err)) - break - except socket.error as err: - if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ - (sys.platform.startswith('win') and \ - err.errno == errno.WSAEWOULDBLOCK): - select.select([self.sslSock if isSSL else self.sock], [], [], 10) - logger.debug('sock.recv retriable error') - continue - logger.error('sock.recv error. Closing receiveData thread, %s', str(err)) + except Exception as err: + with shared.printLock: + print 'sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID:', str(id(self)) + ').', err break # print 'Received', repr(self.data) if len(self.data) == dataLen: # If self.sock.recv returned no data: - logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread') + with shared.printLock: + print 'Connection to', self.peer, 'closed. Closing receiveData thread. (ID:', str(id(self)) + ')' break else: self.processData() try: - for stream in self.streamNumber: - try: - del self.selfInitiatedConnections[stream][self] - except KeyError: - pass - logger.debug('removed self (a receiveDataThread) from selfInitiatedConnections') + del self.selfInitiatedConnections[self.streamNumber][self] + with shared.printLock: + print 'removed self (a receiveDataThread) from selfInitiatedConnections' except: pass self.sendDataThreadQueue.put((0, 'shutdown','no data')) # commands the corresponding sendDataThread to shut itself down. try: - del shared.connectedHostsList[self.hostIdent] + del shared.connectedHostsList[self.peer.host] except Exception as err: - logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) + with shared.printLock: + print 'Could not delete', self.peer.host, 'from shared.connectedHostsList.', err - queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) - self.checkTimeOffsetNotification() - logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) + try: + del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ + self.peer] + except: + pass + shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + with shared.printLock: + print 'receiveDataThread ending. ID', str(id(self)) + '. The size of the shared.connectedHostsList is now', len(shared.connectedHostsList) - def antiIntersectionDelay(self, initial = False): - # estimated time for a small object to propagate across the whole network - delay = math.ceil(math.log(max(len(knownnodes.knownNodes[x]) for x in knownnodes.knownNodes) + 2, 20)) * (0.2 + objectHashHolder.size/2) - # take the stream with maximum amount of nodes - # +2 is to avoid problems with log(0) and log(1) - # 20 is avg connected nodes count - # 0.2 is avg message transmission time - now = time.time() - if initial and now - delay < self.startTime: - logger.debug("Initial sleeping for %.2fs", delay - (now - self.startTime)) - time.sleep(delay - (now - self.startTime)) - elif not initial: - logger.debug("Sleeping due to missing object for %.2fs", delay) - time.sleep(delay) - - def checkTimeOffsetNotification(self): - if shared.timeOffsetWrongCount >= 4 and not self.connectionIsOrWasFullyEstablished: - queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow", "The time on your computer, %1, may be wrong. Please verify your settings.").arg(datetime.datetime.now().strftime("%H:%M:%S")))) def processData(self): - if len(self.data) < protocol.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data. + if len(self.data) < shared.Header.size: # if so little of the data has arrived that we can't even read the checksum then wait for more data. return - magic,command,payloadLength,checksum = protocol.Header.unpack(self.data[:protocol.Header.size]) + magic,command,payloadLength,checksum = shared.Header.unpack(self.data[:shared.Header.size]) if magic != 0xE9BEB4D9: self.data = "" return if payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. logger.info('The incoming message, which we have not yet download, is too large. Ignoring it. (unfortunately there is no way to tell the other node to stop sending it except to disconnect.) Message size: %s' % payloadLength) - self.data = self.data[payloadLength + protocol.Header.size:] + self.data = self.data[payloadLength + shared.Header.size:] del magic,command,payloadLength,checksum # we don't need these anymore and better to clean them now before the recursive call rather than after self.processData() return - if len(self.data) < payloadLength + protocol.Header.size: # check if the whole message has arrived yet. + if len(self.data) < payloadLength + shared.Header.size: # check if the whole message has arrived yet. return - payload = self.data[protocol.Header.size:payloadLength + protocol.Header.size] + payload = self.data[shared.Header.size:payloadLength + shared.Header.size] if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. - logger.error('Checksum incorrect. Clearing this message.') - self.data = self.data[payloadLength + protocol.Header.size:] + print 'Checksum incorrect. Clearing this message.' + self.data = self.data[payloadLength + shared.Header.size:] del magic,command,payloadLength,checksum,payload # better to clean up before the recursive call self.processData() return @@ -197,13 +147,13 @@ class receiveDataThread(threading.Thread): # just received valid data from it. So update the knownNodes list so # that other peers can be made aware of its existance. if self.initiatedConnection and self.connectionIsOrWasFullyEstablished: # The remote port is only something we should share with others if it is the remote node's incoming port (rather than some random operating-system-assigned outgoing port). - with knownnodes.knownNodesLock: - for stream in self.streamNumber: - knownnodes.knownNodes[stream][self.peer] = int(time.time()) + with shared.knownNodesLock: + shared.knownNodes[self.streamNumber][self.peer] = int(time.time()) #Strip the nulls command = command.rstrip('\x00') - logger.debug('remoteCommand ' + repr(command) + ' from ' + str(self.peer)) + with shared.printLock: + print 'remoteCommand', repr(command), ' from', self.peer try: #TODO: Use a dispatcher here @@ -225,200 +175,130 @@ class receiveDataThread(threading.Thread): self.recobject(payload) elif command == 'ping': self.sendpong(payload) - elif command == 'pong': - pass - else: - logger.info("Unknown command %s, ignoring", command) + #elif command == 'pong': + # pass except varintDecodeError as e: logger.debug("There was a problem with a varint while processing a message from the wire. Some details: %s" % e) except Exception as e: logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc()) del payload - self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message + self.data = self.data[payloadLength + shared.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - toRequest = [] - try: - for i in range(len(self.downloadQueue.pending), 100): - while True: - hashId = self.downloadQueue.get(False) - if not hashId in Inventory(): - toRequest.append(hashId) - break - # don't track download for duplicates - self.downloadQueue.task_done(hashId) - except Queue.Empty: - pass - if len(toRequest) > 0: - self.sendgetdata(toRequest) + while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: + shared.numberOfInventoryLookupsPerformed += 1 + objectHash, = random.sample( + self.objectsThatWeHaveYetToGetFromThisPeer, 1) + if objectHash in shared.inventory: + with shared.printLock: + print 'Inventory (in memory) already has object listed in inv message.' + del self.objectsThatWeHaveYetToGetFromThisPeer[ + objectHash] + elif shared.isInSqlInventory(objectHash): + if shared.verbose >= 3: + with shared.printLock: + print 'Inventory (SQL on disk) already has object listed in inv message.' + del self.objectsThatWeHaveYetToGetFromThisPeer[ + objectHash] + else: + # We don't have the object in our inventory. Let's request it. + self.sendgetdata(objectHash) + del self.objectsThatWeHaveYetToGetFromThisPeer[ + objectHash] # It is possible that the remote node might not respond with the object. In that case, we'll very likely get it from someone else anyway. + if len(self.objectsThatWeHaveYetToGetFromThisPeer) == 0: + with shared.printLock: + print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToGetFromThisPeer is now 0' + try: + del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ + self.peer] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. + except: + pass + break + if len(self.objectsThatWeHaveYetToGetFromThisPeer) == 0: + # We had objectsThatWeHaveYetToGetFromThisPeer but the loop ran, they were all in our inventory, and now we don't have any to get anymore. + with shared.printLock: + print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToGetFromThisPeer is now 0' + try: + del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ + self.peer] # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. + except: + pass + if len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: + with shared.printLock: + print '(concerning', str(self.peer) + ')', 'number of objectsThatWeHaveYetToGetFromThisPeer is now', len(self.objectsThatWeHaveYetToGetFromThisPeer) + + shared.numberOfObjectsThatWeHaveYetToGetPerPeer[self.peer] = len( + self.objectsThatWeHaveYetToGetFromThisPeer) # this data structure is maintained so that we can keep track of how many total objects, across all connections, are currently outstanding. If it goes too high it can indicate that we are under attack by multiple nodes working together. self.processData() - def sendpong(self, payload): - logger.debug('Sending pong') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong', payload))) - def sendping(self, payload): - logger.debug('Sending ping') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('ping', payload))) + def sendpong(self): + with shared.printLock: + print 'Sending pong' + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) + def recverack(self): - logger.debug('verack received') + with shared.printLock: + print 'verack received' self.verackReceived = True if self.verackSent: # We have thus both sent and received a verack. self.connectionFullyEstablished() - def sslHandshake(self): - self.sslSock = self.sock - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - protocol.haveSSL(not self.initiatedConnection)): - logger.debug("Initialising TLS") - if sys.version_info >= (2,7,9): - context = ssl.SSLContext(protocol.sslProtocolVersion) - context.set_ciphers(protocol.sslProtocolCiphers) - context.set_ecdh_curve("secp256k1") - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - # also exclude TLSv1 and TLSv1.1 in the future - context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE - self.sslSock = context.wrap_socket(self.sock, server_side = not self.initiatedConnection, do_handshake_on_connect=False) - else: - self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=protocol.sslProtocolVersion, do_handshake_on_connect=False, ciphers=protocol.sslProtocolCiphers) - self.sendDataThreadQueue.join() - while True: - try: - self.sslSock.do_handshake() - logger.debug("TLS handshake success") - if sys.version_info >= (2, 7, 9): - logger.debug("TLS protocol version: %s", self.sslSock.version()) - break - except ssl.SSLError as e: - if sys.hexversion >= 0x02070900: - if isinstance (e, ssl.SSLWantReadError): - logger.debug("Waiting for SSL socket handhake read") - select.select([self.sslSock], [], [], 10) - continue - elif isinstance (e, ssl.SSLWantWriteError): - logger.debug("Waiting for SSL socket handhake write") - select.select([], [self.sslSock], [], 10) - continue - else: - if e.args[0] == ssl.SSL_ERROR_WANT_READ: - logger.debug("Waiting for SSL socket handhake read") - select.select([self.sslSock], [], [], 10) - continue - elif e.args[0] == ssl.SSL_ERROR_WANT_WRITE: - logger.debug("Waiting for SSL socket handhake write") - select.select([], [self.sslSock], [], 10) - continue - logger.error("SSL socket handhake failed: shutting down connection, %s", str(e)) - self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) - return False - except socket.error as err: - logger.debug('SSL socket handshake failed, shutting down connection, %s', str(err)) - self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) - return False - except Exception: - logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) - self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) - return False - # SSL in the background should be blocking, otherwise the error handling is difficult - self.sslSock.settimeout(None) - return True - # no SSL - return True - - def peerValidityChecks(self): - if self.remoteProtocolVersion < 3: - self.sendDataThreadQueue.put((0, 'sendRawData',protocol.assembleErrorMessage( - fatal=2, errorText="Your is using an old protocol. Closing connection."))) - logger.debug ('Closing connection to old protocol version ' + str(self.remoteProtocolVersion) + ' node: ' + str(self.peer)) - return False - if self.timeOffset > 3600: - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( - fatal=2, errorText="Your time is too far in the future compared to mine. Closing connection."))) - logger.info("%s's time is too far in the future (%s seconds). Closing connection to it.", self.peer, self.timeOffset) - shared.timeOffsetWrongCount += 1 - time.sleep(2) - return False - elif self.timeOffset < -3600: - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( - fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection."))) - logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it.", self.peer, self.timeOffset) - shared.timeOffsetWrongCount += 1 - return False - else: - shared.timeOffsetWrongCount = 0 - if len(self.streamNumber) == 0: - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage( - fatal=2, errorText="We don't have shared stream interests. Closing connection."))) - logger.debug ('Closed connection to ' + str(self.peer) + ' because there is no overlapping interest in streams.') - return False - return True - def connectionFullyEstablished(self): if self.connectionIsOrWasFullyEstablished: # there is no reason to run this function a second time return - - if not self.sslHandshake(): - return - - if self.peerValidityChecks() == False: - time.sleep(2) - self.sendDataThreadQueue.put((0, 'shutdown','no data')) - self.checkTimeOffsetNotification() - return - self.connectionIsOrWasFullyEstablished = True - shared.timeOffsetWrongCount = 0 - # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also - self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) - + self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', 'no data')) if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True - queues.UISignalQueue.put(('setStatusIcon', 'green')) + shared.UISignalQueue.put(('setStatusIcon', 'green')) self.sock.settimeout( - 600) # We'll send out a ping every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately. - queues.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) - logger.debug('Connection fully established with ' + str(self.peer) + "\n" + \ - 'The size of the connectedHostsList is now ' + str(len(shared.connectedHostsList)) + "\n" + \ - 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \ - 'broadcasting addr from within connectionFullyEstablished function.') - - if self.initiatedConnection: - state.networkProtocolAvailability[protocol.networkType(self.peer.host)] = True - - # we need to send our own objects to this node - PendingUpload().add() + 600) # We'll send out a pong every 5 minutes to make sure the connection stays alive if there has been no other traffic to send lately. + shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + with shared.printLock: + print 'Connection fully established with', self.peer + print 'The size of the connectedHostsList is now', len(shared.connectedHostsList) + print 'The length of sendDataQueues is now:', len(shared.sendDataQueues) + print 'broadcasting addr from within connectionFullyEstablished function.' # Let all of our peers know about this new node. - for stream in self.remoteStreams: - dataToSend = (int(time.time()), stream, self.services, self.peer.host, self.remoteNodeIncomingPort) - protocol.broadcastToSendDataQueues(( - stream, 'advertisepeer', dataToSend)) + dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) + shared.broadcastToSendDataQueues(( + self.streamNumber, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. - if len(shared.connectedHostsList) > \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200): - logger.info ('We are connected to too many people. Closing connection.') - if self.initiatedConnection: - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Thank you for providing a listening node."))) - else: - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) + if not self.initiatedConnection and len(shared.connectedHostsList) > 200: + with shared.printLock: + print 'We are connected to too many people. Closing connection.' + self.sendDataThreadQueue.put((0, 'shutdown','no data')) return self.sendBigInv() def sendBigInv(self): # Select all hashes for objects in this stream. + queryreturn = sqlQuery( + '''SELECT hash FROM inventory WHERE expirestime>? and streamnumber=?''', + int(time.time()), + self.streamNumber) bigInvList = {} - for stream in self.streamNumber: - for hash in Inventory().unexpired_hashes_by_stream(stream): - if not self.objectHashHolderInstance.hasHash(hash): - bigInvList[hash] = 0 + for row in queryreturn: + hash, = row + if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: + bigInvList[hash] = 0 + # We also have messages in our inventory in memory (which is a python + # dictionary). Let's fetch those too. + with shared.inventoryLock: + for hash, storedValue in shared.inventory.items(): + if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: + objectType, streamNumber, payload, expiresTime, tag = storedValue + if streamNumber == self.streamNumber and expiresTime > int(time.time()): + bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' # Now let us start appending all of these hashes together. They will be @@ -440,15 +320,17 @@ class receiveDataThread(threading.Thread): # function for broadcasting invs to everyone in our stream. def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): payload = encodeVarint(numberOfObjects) + payload - logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('inv', payload))) + with shared.printLock: + print 'Sending huge inv message with', numberOfObjects, 'objects to just this one peer' + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('inv', payload))) def _sleepForTimingAttackMitigation(self, sleepTime): # We don't need to do the timing attack mitigation if we are # only connected to the trusted peer because we can trust the # peer not to attack - if sleepTime > 0 and doTimingAttackMitigation and state.trustedPeer == None: - logger.debug('Timing attack mitigation: Sleeping for ' + str(sleepTime) + ' seconds.') + if sleepTime > 0 and doTimingAttackMitigation and shared.trustedPeer == None: + with shared.printLock: + print 'Timing attack mitigation: Sleeping for', sleepTime, 'seconds.' time.sleep(sleepTime) def recerror(self, data): @@ -477,7 +359,7 @@ class receiveDataThread(threading.Thread): fatalHumanFriendly = 'Fatal' message = '%s message received from %s: %s.' % (fatalHumanFriendly, self.peer, errorText) if inventoryVector: - message += " This concerns object %s" % hexlify(inventoryVector) + message += " This concerns object %s" % inventoryVector.encode('hex') if banTime > 0: message += " Remote node says that the ban time is %s" % banTime logger.error(message) @@ -486,7 +368,6 @@ class receiveDataThread(threading.Thread): def recobject(self, data): self.messageProcessingStartTime = time.time() lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(data) - self.downloadQueue.task_done(calculateInventoryHash(data)) """ Sleeping will help guarantee that we can process messages faster than a @@ -503,33 +384,64 @@ class receiveDataThread(threading.Thread): # We have received an inv message def recinv(self, data): + totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers = 0 # this counts duplicates separately because they take up memory + if len(shared.numberOfObjectsThatWeHaveYetToGetPerPeer) > 0: + for key, value in shared.numberOfObjectsThatWeHaveYetToGetPerPeer.items(): + totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers += value + with shared.printLock: + print 'number of keys(hosts) in shared.numberOfObjectsThatWeHaveYetToGetPerPeer:', len(shared.numberOfObjectsThatWeHaveYetToGetPerPeer) + print 'totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers = ', totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers + numberOfItemsInInv, lengthOfVarint = decodeVarint(data[:10]) if numberOfItemsInInv > 50000: sys.stderr.write('Too many items in inv message!') return if len(data) < lengthOfVarint + (numberOfItemsInInv * 32): - logger.info('inv message doesn\'t contain enough data. Ignoring.') + print 'inv message doesn\'t contain enough data. Ignoring.' return - - startTime = time.time() - advertisedSet = set() - for i in range(numberOfItemsInInv): - advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) - objectsNewToMe = advertisedSet - for stream in self.streamNumber: - objectsNewToMe -= Inventory().hashes_by_stream(stream) - logger.info('inv message lists %s objects. Of those %s are new to me. It took %s seconds to figure that out.', numberOfItemsInInv, len(objectsNewToMe), time.time()-startTime) - for item in random.sample(objectsNewToMe, len(objectsNewToMe)): - self.downloadQueue.put(item) + if numberOfItemsInInv == 1: # we'll just request this data from the person who advertised the object. + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000: # inv flooding attack mitigation + with shared.printLock: + print 'We already have', totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers, 'items yet to retrieve from peers and over 1000 from this node in particular. Ignoring this inv message.' + return + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ + data[lengthOfVarint:32 + lengthOfVarint]] = 0 + shared.numberOfInventoryLookupsPerformed += 1 + if data[lengthOfVarint:32 + lengthOfVarint] in shared.inventory: + with shared.printLock: + print 'Inventory (in memory) has inventory item already.' + elif shared.isInSqlInventory(data[lengthOfVarint:32 + lengthOfVarint]): + print 'Inventory (SQL on disk) has inventory item already.' + else: + self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) + else: + # There are many items listed in this inv message. Let us create a + # 'set' of objects we are aware of and a set of objects in this inv + # message so that we can diff one from the other cheaply. + startTime = time.time() + advertisedSet = set() + for i in range(numberOfItemsInInv): + advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) + objectsNewToMe = advertisedSet - shared.inventorySets[self.streamNumber] + logger.info('inv message lists %s objects. Of those %s are new to me. It took %s seconds to figure that out.', numberOfItemsInInv, len(objectsNewToMe), time.time()-startTime) + for item in objectsNewToMe: + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000: # inv flooding attack mitigation + with shared.printLock: + print 'We already have', totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers, 'items yet to retrieve from peers and over', len(self.objectsThatWeHaveYetToGetFromThisPeer), 'from this node in particular. Ignoring the rest of this inv message.' + break + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[item] = 0 # helps us keep from sending inv messages to peers that already know about the objects listed therein + self.objectsThatWeHaveYetToGetFromThisPeer[item] = 0 # upon finishing dealing with an incoming message, the receiveDataThread will request a random object of from peer out of this data structure. This way if we get multiple inv messages from multiple peers which list mostly the same objects, we will make getdata requests for different random objects from the various peers. + if len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: + shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ + self.peer] = len(self.objectsThatWeHaveYetToGetFromThisPeer) # Send a getdata message to our peer to request the object with the given # hash - def sendgetdata(self, hashes): - if len(hashes) == 0: - return - logger.debug('sending getdata to retrieve %i objects', len(hashes)) - payload = encodeVarint(len(hashes)) + ''.join(hashes) - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('getdata', payload)), False) + def sendgetdata(self, hash): + with shared.printLock: + print 'sending getdata to retrieve object with hash:', hash.encode('hex') + payload = '\x01' + hash + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) # We have received a getdata request from our peer @@ -537,70 +449,64 @@ class receiveDataThread(threading.Thread): numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( data[:10]) if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): - logger.debug('getdata message does not contain enough data. Ignoring.') + print 'getdata message does not contain enough data. Ignoring.' return - self.antiIntersectionDelay(True) # only handle getdata requests if we have been connected long enough for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + ( i * 32):32 + lengthOfVarint + (i * 32)] - logger.debug('received getdata request for item:' + hexlify(hash)) + with shared.printLock: + print 'received getdata request for item:', hash.encode('hex') - if self.objectHashHolderInstance.hasHash(hash): - self.antiIntersectionDelay() + shared.numberOfInventoryLookupsPerformed += 1 + shared.inventoryLock.acquire() + if hash in shared.inventory: + objectType, streamNumber, payload, expiresTime, tag = shared.inventory[hash] + shared.inventoryLock.release() + self.sendObject(payload) else: - if hash in Inventory(): - self.sendObject(hash, Inventory()[hash].payload) + shared.inventoryLock.release() + queryreturn = sqlQuery( + '''select payload from inventory where hash=? and expirestime>=?''', + hash, + int(time.time())) + if queryreturn != []: + for row in queryreturn: + payload, = row + self.sendObject(payload) else: - self.antiIntersectionDelay() logger.warning('%s asked for an object with a getdata which is not in either our memory inventory or our SQL inventory. We probably cleaned it out after advertising it but before they got around to asking for it.' % (self.peer,)) # Our peer has requested (in a getdata message) that we send an object. - def sendObject(self, hash, payload): - logger.debug('sending an object.') - self.sendDataThreadQueue.put((0, 'sendRawData', (hash, protocol.CreatePacket('object',payload)))) + def sendObject(self, payload): + with shared.printLock: + print 'sending an object.' + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload))) - def _checkIPAddress(self, host): - if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': - hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:]) - return self._checkIPv4Address(host[12:], hostStandardFormat) - elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43': - # Onion, based on BMD/bitcoind - hostStandardFormat = base64.b32encode(host[6:]).lower() + ".onion" - return hostStandardFormat - else: - hostStandardFormat = socket.inet_ntop(socket.AF_INET6, host) - if hostStandardFormat == "": - # This can happen on Windows systems which are not 64-bit compatible - # so let us drop the IPv6 address. - return False - return self._checkIPv6Address(host, hostStandardFormat) def _checkIPv4Address(self, host, hostStandardFormat): - if host[0] == '\x7F': # 127/8 - logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) + # print 'hostStandardFormat', hostStandardFormat + if host[0] == '\x7F': + print 'Ignoring IP address in loopback range:', hostStandardFormat return False - if host[0] == '\x0A': # 10/8 - logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) + if host[0] == '\x0A': + print 'Ignoring IP address in private range:', hostStandardFormat return False - if host[0:2] == '\xC0\xA8': # 192.168/16 - logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) + if host[0:2] == '\xC0\xA8': + print 'Ignoring IP address in private range:', hostStandardFormat return False - if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 - logger.debug('Ignoring IP address in private range:' + hostStandardFormat) - return False - return hostStandardFormat + return True def _checkIPv6Address(self, host, hostStandardFormat): if host == ('\x00' * 15) + '\x01': - logger.debug('Ignoring loopback address: ' + hostStandardFormat) + print 'Ignoring loopback address:', hostStandardFormat return False if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: - logger.debug ('Ignoring local address: ' + hostStandardFormat) + print 'Ignoring local address:', hostStandardFormat return False if (ord(host[0]) & 0xfe) == 0xfc: - logger.debug ('Ignoring unique local address: ' + hostStandardFormat) + print 'Ignoring unique local address:', hostStandardFormat return False - return hostStandardFormat + return True # We have received an addr message. def recaddr(self, data): @@ -608,12 +514,13 @@ class receiveDataThread(threading.Thread): data[:10]) if shared.verbose >= 1: - logger.debug('addr message contains ' + str(numberOfAddressesIncluded) + ' IP addresses.') + with shared.printLock: + print 'addr message contains', numberOfAddressesIncluded, 'IP addresses.' if numberOfAddressesIncluded > 1000 or numberOfAddressesIncluded == 0: return if len(data) != lengthOfNumberOfAddresses + (38 * numberOfAddressesIncluded): - logger.debug('addr message does not contain the correct amount of data. Ignoring.') + print 'addr message does not contain the correct amount of data. Ignoring.' return for i in range(0, numberOfAddressesIncluded): @@ -622,56 +529,53 @@ class receiveDataThread(threading.Thread): 38 * i):12 + lengthOfNumberOfAddresses + (38 * i)]) if recaddrStream == 0: continue - if recaddrStream not in self.streamNumber and (recaddrStream / 2) not in self.streamNumber: # if the embedded stream number and its parent are not in my streams then ignore it. Someone might be trying funny business. + if recaddrStream != self.streamNumber and recaddrStream != (self.streamNumber * 2) and recaddrStream != ((self.streamNumber * 2) + 1): # if the embedded stream number is not in my stream or either of my child streams then ignore it. Someone might be trying funny business. continue recaddrServices, = unpack('>Q', data[12 + lengthOfNumberOfAddresses + ( 38 * i):20 + lengthOfNumberOfAddresses + (38 * i)]) recaddrPort, = unpack('>H', data[36 + lengthOfNumberOfAddresses + ( 38 * i):38 + lengthOfNumberOfAddresses + (38 * i)]) - hostStandardFormat = self._checkIPAddress(fullHost) - if hostStandardFormat is False: - continue - if recaddrPort == 0: - continue + if fullHost[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': + ipv4Host = fullHost[12:] + hostStandardFormat = socket.inet_ntop(socket.AF_INET, ipv4Host) + if not self._checkIPv4Address(ipv4Host, hostStandardFormat): + continue + else: + hostStandardFormat = socket.inet_ntop(socket.AF_INET6, fullHost) + if hostStandardFormat == "": + # This can happen on Windows systems which are not 64-bit compatible + # so let us drop the IPv6 address. + continue + if not self._checkIPv6Address(fullHost, hostStandardFormat): + continue timeSomeoneElseReceivedMessageFromThisNode, = unpack('>Q', data[lengthOfNumberOfAddresses + ( 38 * i):8 + lengthOfNumberOfAddresses + (38 * i)]) # This is the 'time' value in the received addr message. 64-bit. - if recaddrStream not in knownnodes.knownNodes: # knownNodes is a dictionary of dictionaries with one outer dictionary for each stream. If the outer stream dictionary doesn't exist yet then we must make it. - with knownnodes.knownNodesLock: - knownnodes.knownNodes[recaddrStream] = {} - peerFromAddrMessage = state.Peer(hostStandardFormat, recaddrPort) - if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: - # only if recent - if timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): - # bootstrap provider? - if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ - BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): - knownnodes.trimKnownNodes(recaddrStream) - with knownnodes.knownNodesLock: - knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = int(time.time()) - 86400 # penalise initially by 1 day - logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) - shared.needToWriteKnownNodesToDisk = True - # normal mode - elif len(knownnodes.knownNodes[recaddrStream]) < 20000: - with knownnodes.knownNodesLock: - knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode - hostDetails = ( - timeSomeoneElseReceivedMessageFromThisNode, - recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) - protocol.broadcastToSendDataQueues(( - recaddrStream, 'advertisepeer', hostDetails)) - logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) - shared.needToWriteKnownNodesToDisk = True - # only update if normal mode - elif BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') < \ - BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): - timeLastReceivedMessageFromThisNode = knownnodes.knownNodes[recaddrStream][ + if recaddrStream not in shared.knownNodes: # knownNodes is a dictionary of dictionaries with one outer dictionary for each stream. If the outer stream dictionary doesn't exist yet then we must make it. + with shared.knownNodesLock: + shared.knownNodes[recaddrStream] = {} + peerFromAddrMessage = shared.Peer(hostStandardFormat, recaddrPort) + if peerFromAddrMessage not in shared.knownNodes[recaddrStream]: + if len(shared.knownNodes[recaddrStream]) < 20000 and timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): # If we have more than 20000 nodes in our list already then just forget about adding more. Also, make sure that the time that someone else received a message from this node is within three hours from now. + with shared.knownNodesLock: + shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + with shared.printLock: + print 'added new node', peerFromAddrMessage, 'to knownNodes in stream', recaddrStream + + shared.needToWriteKnownNodesToDisk = True + hostDetails = ( + timeSomeoneElseReceivedMessageFromThisNode, + recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) + shared.broadcastToSendDataQueues(( + self.streamNumber, 'advertisepeer', hostDetails)) + else: + timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ peerFromAddrMessage] if (timeLastReceivedMessageFromThisNode < timeSomeoneElseReceivedMessageFromThisNode) and (timeSomeoneElseReceivedMessageFromThisNode < int(time.time())+900): # 900 seconds for wiggle-room in case other nodes' clocks aren't quite right. - with knownnodes.knownNodesLock: - knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + with shared.knownNodesLock: + shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode - for stream in self.streamNumber: - logger.debug('knownNodes currently has %i nodes for stream %i', len(knownnodes.knownNodes[stream]), stream) + with shared.printLock: + print 'knownNodes currently has', len(shared.knownNodes[self.streamNumber]), 'nodes for this stream.' # Send a huge addr message to our peer. This is only used @@ -679,96 +583,78 @@ class receiveDataThread(threading.Thread): # peer (with the full exchange of version and verack # messages). def sendaddr(self): - def sendChunk(): - if numberOfAddressesInAddrMessage == 0: - return - self.sendDataThreadQueue.put((0, 'sendRawData', \ - protocol.CreatePacket('addr', \ - encodeVarint(numberOfAddressesInAddrMessage) + payload))) + addrsInMyStream = {} + addrsInChildStreamLeft = {} + addrsInChildStreamRight = {} + # print 'knownNodes', shared.knownNodes - # We are going to share a maximum number of 1000 addrs (per overlapping - # stream) with our peer. 500 from overlapping streams, 250 from the - # left child stream, and 250 from the right child stream. - maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500) - - # protocol defines this as a maximum in one chunk - protocolAddrLimit = 1000 - - # init + # We are going to share a maximum number of 1000 addrs with our peer. + # 500 from this stream, 250 from the left child stream, and 250 from + # the right child stream. + with shared.knownNodesLock: + if len(shared.knownNodes[self.streamNumber]) > 0: + for i in range(500): + peer, = random.sample(shared.knownNodes[self.streamNumber], 1) + if isHostInPrivateIPRange(peer.host): + continue + addrsInMyStream[peer] = shared.knownNodes[ + self.streamNumber][peer] + if len(shared.knownNodes[self.streamNumber * 2]) > 0: + for i in range(250): + peer, = random.sample(shared.knownNodes[ + self.streamNumber * 2], 1) + if isHostInPrivateIPRange(peer.host): + continue + addrsInChildStreamLeft[peer] = shared.knownNodes[ + self.streamNumber * 2][peer] + if len(shared.knownNodes[(self.streamNumber * 2) + 1]) > 0: + for i in range(250): + peer, = random.sample(shared.knownNodes[ + (self.streamNumber * 2) + 1], 1) + if isHostInPrivateIPRange(peer.host): + continue + addrsInChildStreamRight[peer] = shared.knownNodes[ + (self.streamNumber * 2) + 1][peer] numberOfAddressesInAddrMessage = 0 payload = '' + # print 'addrsInMyStream.items()', addrsInMyStream.items() + for (HOST, PORT), value in addrsInMyStream.items(): + timeLastReceivedMessageFromThisNode = value + if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', self.streamNumber) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += shared.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + for (HOST, PORT), value in addrsInChildStreamLeft.items(): + timeLastReceivedMessageFromThisNode = value + if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', self.streamNumber * 2) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += shared.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + for (HOST, PORT), value in addrsInChildStreamRight.items(): + timeLastReceivedMessageFromThisNode = value + if timeLastReceivedMessageFromThisNode > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers): # If it is younger than 3 hours old.. + numberOfAddressesInAddrMessage += 1 + payload += pack( + '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time + payload += pack('>I', (self.streamNumber * 2) + 1) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += shared.encodeHost(HOST) + payload += pack('>H', PORT) # remote port - for stream in self.streamNumber: - addrsInMyStream = {} - addrsInChildStreamLeft = {} - addrsInChildStreamRight = {} + payload = encodeVarint(numberOfAddressesInAddrMessage) + payload + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('addr', payload))) - with knownnodes.knownNodesLock: - if len(knownnodes.knownNodes[stream]) > 0: - filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() - if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount: - elemCount = maxAddrCount - # only if more recent than 3 hours - addrsInMyStream = random.sample(filtered.items(), elemCount) - # sent 250 only if the remote isn't interested in it - if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber: - filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() - if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount / 2: - elemCount = int(maxAddrCount / 2) - addrsInChildStreamLeft = random.sample(filtered.items(), elemCount) - if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: - filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items() - if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount / 2: - elemCount = int(maxAddrCount / 2) - addrsInChildStreamRight = random.sample(filtered.items(), elemCount) - for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream: - numberOfAddressesInAddrMessage += 1 - payload += pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', stream) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port - if numberOfAddressesInAddrMessage >= protocolAddrLimit: - sendChunk() - payload = '' - numberOfAddressesInAddrMessage = 0 - for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft: - numberOfAddressesInAddrMessage += 1 - payload += pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', stream * 2) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port - if numberOfAddressesInAddrMessage >= protocolAddrLimit: - sendChunk() - payload = '' - numberOfAddressesInAddrMessage = 0 - for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight: - numberOfAddressesInAddrMessage += 1 - payload += pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', (stream * 2) + 1) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port - if numberOfAddressesInAddrMessage >= protocolAddrLimit: - sendChunk() - payload = '' - numberOfAddressesInAddrMessage = 0 - - # flush - sendChunk() # We have received a version message def recversion(self, data): @@ -784,13 +670,26 @@ class receiveDataThread(threading.Thread): ignore this version message """ return - self.remoteProtocolVersion, = unpack('>L', data[:4]) - self.services, = unpack('>q', data[4:12]) - + if self.remoteProtocolVersion < 3: + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + with shared.printLock: + print 'Closing connection to old protocol version', self.remoteProtocolVersion, 'node: ', self.peer + return timestamp, = unpack('>Q', data[12:20]) - self.timeOffset = timestamp - int(time.time()) - + timeOffset = timestamp - int(time.time()) + if timeOffset > 3600: + self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleErrorMessage(fatal=2, errorText="Your time is too far in the future compared to mine. Closing connection."))) + logger.info("%s's time is too far in the future (%s seconds). Closing connection to it." % (self.peer, timeOffset)) + time.sleep(2) + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + return + if timeOffset < -3600: + self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleErrorMessage(fatal=2, errorText="Your time is too far in the past compared to mine. Closing connection."))) + logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it." % (self.peer, timeOffset)) + time.sleep(2) + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + return self.myExternalIP = socket.inet_ntoa(data[40:44]) # print 'myExternalIP', self.myExternalIP self.remoteNodeIncomingPort, = unpack('>H', data[70:72]) @@ -798,67 +697,40 @@ class receiveDataThread(threading.Thread): useragentLength, lengthOfUseragentVarint = decodeVarint( data[80:84]) readPosition = 80 + lengthOfUseragentVarint - self.userAgent = data[readPosition:readPosition + useragentLength] - - # version check - try: - userAgentName, userAgentVersion = self.userAgent[1:-1].split(":", 2) - except: - userAgentName = self.userAgent - userAgentVersion = "0.0.0" - if userAgentName == "PyBitmessage": - myVersion = [int(n) for n in softwareVersion.split(".")] - try: - remoteVersion = [int(n) for n in userAgentVersion.split(".")] - except: - remoteVersion = 0 - # remote is newer, but do not cross between stable and unstable - try: - if cmp(remoteVersion, myVersion) > 0 and \ - (myVersion[1] % 2 == remoteVersion[1] % 2): - queues.UISignalQueue.put(('newVersionAvailable', remoteVersion)) - except: - pass - + useragent = data[readPosition:readPosition + useragentLength] readPosition += useragentLength numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( data[readPosition:]) readPosition += lengthOfNumberOfStreamsInVersionMessage - self.remoteStreams = [] - for i in range(numberOfStreamsInVersionMessage): - newStreamNumber, lengthOfRemoteStreamNumber = decodeVarint(data[readPosition:]) - readPosition += lengthOfRemoteStreamNumber - self.remoteStreams.append(newStreamNumber) - logger.debug('Remote node useragent: %s, streams: (%s), time offset: %is.', - self.userAgent, ', '.join(str(x) for x in self.remoteStreams), self.timeOffset) + self.streamNumber, lengthOfRemoteStreamNumber = decodeVarint( + data[readPosition:]) + with shared.printLock: + print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber, ' time offset:', timeOffset, 'seconds.' - # find shared streams - self.streamNumber = sorted(set(state.streamsInWhichIAmParticipating).intersection(self.remoteStreams)) - - shared.connectedHostsList[ - self.hostIdent] = 1 # We use this data structure to not only keep track of what hosts we are connected to so that we don't try to connect to them again, but also to list the connections count on the Network Status tab. - self.sendDataThreadQueue.put((0, 'setStreamNumber', self.remoteStreams)) - if data[72:80] == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: + if self.streamNumber != 1: self.sendDataThreadQueue.put((0, 'shutdown','no data')) - logger.debug('Closing connection to myself: ' + str(self.peer)) + with shared.printLock: + print 'Closed connection to', self.peer, 'because they are interested in stream', self.streamNumber, '.' + return + shared.connectedHostsList[ + self.peer.host] = 1 # We use this data structure to not only keep track of what hosts we are connected to so that we don't try to connect to them again, but also to list the connections count on the Network Status tab. + # If this was an incoming connection, then the sendDataThread + # doesn't know the stream. We have to set it. + if not self.initiatedConnection: + self.sendDataThreadQueue.put((0, 'setStreamNumber', self.streamNumber)) + if data[72:80] == shared.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: + self.sendDataThreadQueue.put((0, 'shutdown','no data')) + with shared.printLock: + print 'Closing connection to myself: ', self.peer return # The other peer's protocol version is of interest to the sendDataThread but we learn of it # in this version message. Let us inform the sendDataThread. self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion)) - if not isHostInPrivateIPRange(self.peer.host): - with knownnodes.knownNodesLock: - for stream in self.remoteStreams: - knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) - if not self.initiatedConnection: - # bootstrap provider? - if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ - BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): - knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 10800 # penalise inbound, 3 hours - else: - knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 7200 # penalise inbound, 2 hours - shared.needToWriteKnownNodesToDisk = True + with shared.knownNodesLock: + shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) + shared.needToWriteKnownNodesToDisk = True self.sendverack() if self.initiatedConnection == False: @@ -866,14 +738,17 @@ class receiveDataThread(threading.Thread): # Sends a version message def sendversion(self): - logger.debug('Sending version message') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage( - self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection))) + with shared.printLock: + print 'Sending version message' + self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleVersionMessage( + self.peer.host, self.peer.port, self.streamNumber))) + # Sends a verack message def sendverack(self): - logger.debug('Sending verack') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('verack'))) + with shared.printLock: + print 'Sending verack' + self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) self.verackSent = True if self.verackReceived: self.connectionFullyEstablished() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 792fedd0..bb19c9f6 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -1,35 +1,27 @@ -import errno import time import threading +import shared import Queue from struct import unpack, pack import hashlib import random -import select -import socket -from ssl import SSLError, SSL_ERROR_WANT_WRITE import sys +import socket from helper_generic import addDataPadding from class_objectHashHolder import * from addresses import * -from debug import logger -from inventory import PendingUpload -import protocol -import state -import throttle # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). class sendDataThread(threading.Thread): def __init__(self, sendDataThreadQueue): - threading.Thread.__init__(self, name="sendData") + threading.Thread.__init__(self) self.sendDataThreadQueue = sendDataThreadQueue - state.sendDataQueues.append(self.sendDataThreadQueue) + shared.sendDataQueues.append(self.sendDataThreadQueue) self.data = '' self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) - self.objectHashHolderInstance.daemon = True self.objectHashHolderInstance.start() self.connectionIsOrWasFullyEstablished = False @@ -39,88 +31,74 @@ class sendDataThread(threading.Thread): sock, HOST, PORT, - streamNumber - ): + streamNumber, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware): self.sock = sock - self.peer = state.Peer(HOST, PORT) - self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator - self.streamNumber = [] - self.services = 0 - self.buffer = "" - self.initiatedConnection = False + self.peer = shared.Peer(HOST, PORT) + self.streamNumber = streamNumber self.remoteProtocolVersion = - \ 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.sendDataThreadQueue queue. self.lastTimeISentData = int( time.time()) # If this value increases beyond five minutes ago, we'll send a pong message to keep the connection alive. - if streamNumber == -1: # This was an incoming connection. - self.initiatedConnection = False - else: - self.initiatedConnection = True - #logger.debug('The streamNumber of this sendDataThread (ID: ' + str(id(self)) + ') at setup() is' + str(self.streamNumber)) + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware + with shared.printLock: + print 'The streamNumber of this sendDataThread (ID:', str(id(self)) + ') at setup() is', self.streamNumber def sendVersionMessage(self): - datatosend = protocol.assembleVersionMessage( - self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. + datatosend = shared.assembleVersionMessage( + self.peer.host, self.peer.port, self.streamNumber) # the IP and port of the remote host, and my streamNumber. - logger.debug('Sending version packet: ' + repr(datatosend)) + with shared.printLock: + print 'Sending version packet: ', repr(datatosend) try: self.sendBytes(datatosend) except Exception as err: # if not 'Bad file descriptor' in err: - logger.error('sock.sendall error: %s\n' % err) + with shared.printLock: + sys.stderr.write('sock.sendall error: %s\n' % err) self.versionSent = 1 - def sendBytes(self, data = ""): - self.buffer += data - if len(self.buffer) < throttle.SendThrottle().chunkSize and self.sendDataThreadQueue.qsize() > 1: - return True + def sendBytes(self, data): + if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: + uploadRateLimitBytes = 999999999 # float("inf") doesn't work + else: + uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 + with shared.sendDataLock: + while data: + while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes: + if int(time.time()) == shared.lastTimeWeResetBytesSent: + time.sleep(0.3) + else: + # It's a new second. Let us clear the shared.numberOfBytesSentLastSecond + shared.lastTimeWeResetBytesSent = int(time.time()) + shared.numberOfBytesSentLastSecond = 0 + # If the user raises or lowers the uploadRateLimit then we should make use of + # the new setting. If we are hitting the limit then we'll check here about + # once per second. + if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: + uploadRateLimitBytes = 999999999 # float("inf") doesn't work + else: + uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 + amountSent = self.sock.send(data[:1000]) + shared.numberOfBytesSent += amountSent # used for the 'network status' tab in the UI + shared.numberOfBytesSentLastSecond += amountSent + self.lastTimeISentData = int(time.time()) + data = data[amountSent:] - while self.buffer and state.shutdown == 0: - isSSL = False - try: - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - self.connectionIsOrWasFullyEstablished and - protocol.haveSSL(not self.initiatedConnection)): - isSSL = True - amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) - else: - amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) - except socket.timeout: - continue - except SSLError as e: - if e.errno == SSL_ERROR_WANT_WRITE: - select.select([], [self.sslSock], [], 10) - logger.debug('sock.recv retriable SSL error') - continue - logger.debug('Connection error (SSL)') - return False - except socket.error as e: - if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ - (sys.platform.startswith('win') and \ - e.errno == errno.WSAEWOULDBLOCK): - select.select([], [self.sslSock if isSSL else self.sock], [], 10) - logger.debug('sock.recv retriable error') - continue - if e.errno in (errno.EPIPE, errno.ECONNRESET, errno.EHOSTUNREACH, errno.ETIMEDOUT, errno.ECONNREFUSED): - logger.debug('Connection error: %s', str(e)) - return False - raise - throttle.SendThrottle().wait(amountSent) - self.lastTimeISentData = int(time.time()) - self.buffer = self.buffer[amountSent:] - return True def run(self): - logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) - while self.sendBytes(): + with shared.printLock: + print 'sendDataThread starting. ID:', str(id(self))+'. Number of queues in sendDataQueues:', len(shared.sendDataQueues) + while True: deststream, command, data = self.sendDataThreadQueue.get() - if deststream == 0 or deststream in self.streamNumber: + if deststream == self.streamNumber or deststream == 0: if command == 'shutdown': - logger.debug('sendDataThread (associated with ' + str(self.peer) + ') ID: ' + str(id(self)) + ' shutting down now.') + with shared.printLock: + print 'sendDataThread (associated with', self.peer, ') ID:', id(self), 'shutting down now.' break # When you receive an incoming connection, a sendDataThread is # created even though you don't yet know what stream number the @@ -130,10 +108,12 @@ class sendDataThread(threading.Thread): # streamNumber of this send data thread here: elif command == 'setStreamNumber': self.streamNumber = data - logger.debug('setting the stream number to %s', ', '.join(str(x) for x in self.streamNumber)) + with shared.printLock: + print 'setting the stream number in the sendData thread (ID:', id(self), ') to', self.streamNumber elif command == 'setRemoteProtocolVersion': specifiedRemoteProtocolVersion = data - logger.debug('setting the remote node\'s protocol version in the sendDataThread (ID: ' + str(id(self)) + ') to ' + str(specifiedRemoteProtocolVersion)) + with shared.printLock: + print 'setting the remote node\'s protocol version in the sendDataThread (ID:', id(self), ') to', specifiedRemoteProtocolVersion self.remoteProtocolVersion = specifiedRemoteProtocolVersion elif command == 'advertisepeer': self.objectHashHolderInstance.holdPeer(data) @@ -148,15 +128,16 @@ class sendDataThread(threading.Thread): payload += pack('>I', streamNumber) payload += pack( '>q', services) # service bit flags offered by this node - payload += protocol.encodeHost(host) + payload += shared.encodeHost(host) payload += pack('>H', port) payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - packet = protocol.CreatePacket('addr', payload) + packet = shared.CreatePacket('addr', payload) try: self.sendBytes(packet) except: - logger.error('sendaddr: self.sock.sendall failed') + with shared.printLock: + print 'sendaddr: self.sock.sendall failed' break elif command == 'advertiseobject': self.objectHashHolderInstance.holdHash(data) @@ -164,53 +145,49 @@ class sendDataThread(threading.Thread): if self.connectionIsOrWasFullyEstablished: # only send inv messages if we have send and heard a verack from the remote node payload = '' for hash in data: - payload += hash + if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: + payload += hash if payload != '': payload = encodeVarint(len(payload)/32) + payload - packet = protocol.CreatePacket('inv', payload) + packet = shared.CreatePacket('inv', payload) try: self.sendBytes(packet) except: - logger.error('sendinv: self.sock.sendall failed') + with shared.printLock: + print 'sendinv: self.sock.sendall failed' break elif command == 'pong': + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware.clear() # To save memory, let us clear this data structure from time to time. As its function is to help us keep from sending inv messages to peers which sent us the same inv message mere seconds earlier, it will be fine to clear this data structure from time to time. if self.lastTimeISentData < (int(time.time()) - 298): # Send out a pong message to keep the connection alive. - logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.') - packet = protocol.CreatePacket('pong') + with shared.printLock: + print 'Sending pong to', self.peer, 'to keep connection alive.' + packet = shared.CreatePacket('pong') try: self.sendBytes(packet) except: - logger.error('send pong failed') + with shared.printLock: + print 'send pong failed' break elif command == 'sendRawData': - objectHash = None - if type(data) in [list, tuple]: - objectHash, data = data try: self.sendBytes(data) - PendingUpload().delete(objectHash) except: - logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True) + with shared.printLock: + print 'Sending of data to', self.peer, 'failed. sendDataThread thread', self, 'ending now.' break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True - self.services, self.sslSock = data - elif self.connectionIsOrWasFullyEstablished: - logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream ' + str(deststream) + ' but in streams ' + ', '.join(str(x) for x in self.streamNumber)) - self.sendDataThreadQueue.task_done() - # Flush if the cycle ended with break - try: - self.sendDataThreadQueue.task_done() - except ValueError: - pass + else: + with shared.printLock: + print 'sendDataThread ID:', id(self), 'ignoring command', command, 'because the thread is not in stream', deststream try: self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() except: pass - state.sendDataQueues.remove(self.sendDataThreadQueue) - PendingUpload().threadEnd() - logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) + shared.sendDataQueues.remove(self.sendDataThreadQueue) + with shared.printLock: + print 'sendDataThread ending. ID:', str(id(self))+'. Number of queues in sendDataQueues:', len(shared.sendDataQueues) self.objectHashHolderInstance.close() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index ca77881c..b441d11c 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -1,19 +1,13 @@ -import gc import threading import shared import time +import sys import os +import pickle import tr#anslate -from bmconfigparser import BMConfigParser from helper_sql import * -from helper_threading import * -from inventory import Inventory -from network.connectionpool import BMConnectionPool from debug import logger -import knownnodes -import queues -import state """ The singleCleaner class is a timer-driven thread that cleans data structures @@ -26,7 +20,6 @@ inventorySets (clears then reloads data out of sql database) It cleans these tables on the disk: inventory (clears expired objects) pubkeys (clears pubkeys older than 4 weeks old which we have not used personally) -knownNodes (clears addresses which have not been online for over 3 days) It resends messages when there has been no response: resends getpubkey messages in 5 days (then 10 days, then 20 days, etc...) @@ -35,41 +28,49 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) """ -class singleCleaner(threading.Thread, StoppableThread): - cycleLength = 300 - expireDiscoveredPeers = 300 +class singleCleaner(threading.Thread): def __init__(self): - threading.Thread.__init__(self, name="singleCleaner") - self.initStop() + threading.Thread.__init__(self) def run(self): - gc.disable() timeWeLastClearedInventoryAndPubkeysTables = 0 try: - shared.maximumLengthOfTimeToBotherResendingMessages = (float(BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 *365)/12) + shared.maximumLengthOfTimeToBotherResendingMessages = (float(shared.config.get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(shared.config.get('bitmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 *365)/12) except: # Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file. shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') - # initial wait - if state.shutdown == 0: - self.stop.wait(singleCleaner.cycleLength) - - while state.shutdown == 0: - queues.UISignalQueue.put(( + while True: + shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) - Inventory().flush() - queues.UISignalQueue.put(('updateStatusBar', '')) + with shared.inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + with SqlBulkExecute() as sql: + for hash, storedValue in shared.inventory.items(): + objectType, streamNumber, payload, expiresTime, tag = storedValue + sql.execute( + '''INSERT INTO inventory VALUES (?,?,?,?,?,?)''', + hash, + objectType, + streamNumber, + payload, + expiresTime, + tag) + del shared.inventory[hash] + shared.UISignalQueue.put(('updateStatusBar', '')) + shared.broadcastToSendDataQueues(( + 0, 'pong', 'no data')) # commands the sendData threads to send out a pong message if they haven't sent anything else in the last five minutes. The socket timeout-time is 10 minutes. # If we are running as a daemon then we are going to fill up the UI # queue which will never be handled by a UI. We should clear it to # save memory. - if shared.thisapp.daemon: - queues.UISignalQueue.queue.clear() + if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) - Inventory().clean() + sqlExecute( + '''DELETE FROM inventory WHERE expirestime 2419200: # 28 days - shared.needToWriteKnownNodesToDisk = True - del knownnodes.knownNodes[stream][node] - continue - # scrap old nodes with low rating - if now - knownnodes.knownNodes[stream][node]["lastseen"] > 10800 and knownnodes.knownNodes[stream][node]["rating"] <= knownnodes.knownNodesForgetRating: - shared.needToWriteKnownNodesToDisk = True - del knownnodes.knownNodes[stream][node] - continue - except TypeError: - print "Error in %s" % (str(node)) - keys = [] + # Let's also clear and reload shared.inventorySets to keep it from + # taking up an unnecessary amount of memory. + for streamNumber in shared.inventorySets: + shared.inventorySets[streamNumber] = set() + queryData = sqlQuery('''SELECT hash FROM inventory WHERE streamnumber=?''', streamNumber) + for row in queryData: + shared.inventorySets[streamNumber].add(row[0]) + with shared.inventoryLock: + for hash, storedValue in shared.inventory.items(): + objectType, streamNumber, payload, expiresTime, tag = storedValue + if not streamNumber in shared.inventorySets: + shared.inventorySets[streamNumber] = set() + shared.inventorySets[streamNumber].add(hash) # Let us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: + shared.knownNodesLock.acquire() + output = open(shared.appdata + 'knownnodes.dat', 'wb') try: - knownnodes.saveKnownNodes() + pickle.dump(shared.knownNodes, output) + output.close() except Exception as err: if "Errno 28" in str(err): - logger.fatal('(while receiveDataThread knownnodes.needToWriteKnownNodesToDisk) Alert: Your disk or data storage volume is full. ') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - if shared.thisapp.daemon: + logger.fatal('(while receiveDataThread shared.needToWriteKnownNodesToDisk) Alert: Your disk or data storage volume is full. ') + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: os._exit(0) + shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False - -# # clear download queues -# for thread in threading.enumerate(): -# if thread.isAlive() and hasattr(thread, 'downloadQueue'): -# thread.downloadQueue.clear() - - # inv/object tracking - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - connection.clean() - - # discovery tracking - exp = time.time() - singleCleaner.expireDiscoveredPeers - reaper = (k for k, v in state.discoveredPeers.items() if v < exp) - for k in reaper: - try: - del state.discoveredPeers[k] - except KeyError: - pass - # TODO: cleanup pending upload / download - - gc.collect() - - if state.shutdown == 0: - self.stop.wait(singleCleaner.cycleLength) + time.sleep(300) def resendPubkeyRequest(address): logger.debug('It has been a long time and we haven\'t heard a response to our getpubkey request. Sending again.') try: - del state.neededPubkeys[ - address] # We need to take this entry out of the neededPubkeys structure because the queues.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. + del shared.neededPubkeys[ + address] # We need to take this entry out of the shared.neededPubkeys structure because the shared.workerQueue checks to see whether the entry is already present and will not do the POW and send the message because it assumes that it has already done it recently. except: pass - queues.UISignalQueue.put(( + shared.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to request a public key...')) sqlExecute( '''UPDATE sent SET status='msgqueued' WHERE toaddress=?''', address) - queues.workerQueue.put(('sendmessage', '')) + shared.workerQueue.put(('sendmessage', '')) def resendMsg(ackdata): logger.debug('It has been a long time and we haven\'t heard an acknowledgement to our msg. Sending again.') sqlExecute( '''UPDATE sent SET status='msgqueued' WHERE ackdata=?''', ackdata) - queues.workerQueue.put(('sendmessage', '')) - queues.UISignalQueue.put(( + shared.workerQueue.put(('sendmessage', '')) + shared.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 7626542d..a33158a3 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -1,17 +1,12 @@ import threading import shared import socket -from bmconfigparser import BMConfigParser from class_sendDataThread import * from class_receiveDataThread import * import helper_bootstrap -from helper_threading import * -import protocol import errno import re -import state - # Only one singleListener thread will ever exist. It creates the # receiveDataThread and sendDataThread for each incoming connection. Note # that it cannot set the stream number because it is not known yet- the @@ -20,25 +15,17 @@ import state # (within the recversion function of the recieveData thread) -class singleListener(threading.Thread, StoppableThread): +class singleListener(threading.Thread): def __init__(self): - threading.Thread.__init__(self, name="singleListener") - self.initStop() + threading.Thread.__init__(self) def setup(self, selfInitiatedConnections): self.selfInitiatedConnections = selfInitiatedConnections def _createListenSocket(self, family): HOST = '' # Symbolic name meaning all available interfaces - # If not sockslisten, but onionhostname defined, only listen on localhost - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): - if family == socket.AF_INET6 and "." in BMConfigParser().get('bitmessagesettings', 'onionbindip'): - raise socket.error(errno.EINVAL, "Invalid mix of IPv4 and IPv6") - elif family == socket.AF_INET and ":" in BMConfigParser().get('bitmessagesettings', 'onionbindip'): - raise socket.error(errno.EINVAL, "Invalid mix of IPv4 and IPv6") - HOST = BMConfigParser().get('bitmessagesettings', 'onionbindip') - PORT = BMConfigParser().getint('bitmessagesettings', 'port') + PORT = shared.config.getint('bitmessagesettings', 'port') sock = socket.socket(family, socket.SOCK_STREAM) if family == socket.AF_INET6: # Make sure we can accept both IPv4 and IPv6 connections. @@ -50,53 +37,36 @@ class singleListener(threading.Thread, StoppableThread): sock.bind((HOST, PORT)) sock.listen(2) return sock - - def stopThread(self): - super(singleListener, self).stopThread() - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')): - try: - s.connect((ip, BMConfigParser().getint('bitmessagesettings', 'port'))) - s.shutdown(socket.SHUT_RDWR) - s.close() - break - except: - pass def run(self): # If there is a trusted peer then we don't want to accept # incoming connections so we'll just abandon the thread - if state.trustedPeer: + if shared.trustedPeer: return - while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and state.shutdown == 0: - self.stop.wait(1) + while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + time.sleep(1) helper_bootstrap.dns() # We typically don't want to accept incoming connections if the user is using a # SOCKS proxy, unless they have configured otherwise. If they eventually select # proxy 'none' or configure SOCKS listening then this will start listening for - # connections. But if on SOCKS and have an onionhostname, listen - # (socket is then only opened for localhost) - while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ - (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ - ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')) and \ - state.shutdown == 0: - self.stop.wait(5) + # connections. + while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten'): + time.sleep(5) - logger.info('Listening for incoming connections.') + with shared.printLock: + print 'Listening for incoming connections.' # First try listening on an IPv6 socket. This should also be # able to accept connections on IPv4. If that's not available # we'll fall back to IPv4-only. try: sock = self._createListenSocket(socket.AF_INET6) - except socket.error as e: + except socket.error, e: if (isinstance(e.args, tuple) and e.args[0] in (errno.EAFNOSUPPORT, errno.EPFNOSUPPORT, - errno.EADDRNOTAVAIL, - errno.ENOPROTOOPT, - errno.EINVAL)): + errno.ENOPROTOOPT)): sock = self._createListenSocket(socket.AF_INET) else: raise @@ -104,31 +74,21 @@ class singleListener(threading.Thread, StoppableThread): # regexp to match an IPv4-mapped IPv6 address mappedAddressRegexp = re.compile(r'^::ffff:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$') - while state.shutdown == 0: + while True: # We typically don't want to accept incoming connections if the user is using a # SOCKS proxy, unless they have configured otherwise. If they eventually select # proxy 'none' or configure SOCKS listening then this will start listening for # connections. - while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') and state.shutdown == 0: - self.stop.wait(10) - while len(shared.connectedHostsList) > \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200) + \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections", 20) \ - and state.shutdown == 0: - logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') + while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten'): + time.sleep(10) + while len(shared.connectedHostsList) > 220: + with shared.printLock: + print 'We are connected to too many people. Not accepting further incoming connections for ten seconds.' - self.stop.wait(10) - - while state.shutdown == 0: - try: - socketObject, sockaddr = sock.accept() - except socket.error as e: - if isinstance(e.args, tuple) and \ - e.args[0] in (errno.EINTR,): - continue - time.wait(1) - continue + time.sleep(10) + while True: + socketObject, sockaddr = sock.accept() (HOST, PORT) = sockaddr[0:2] # If the address is an IPv4-mapped IPv6 address then @@ -142,27 +102,28 @@ class singleListener(threading.Thread, StoppableThread): # is already connected because the two computers will # share the same external IP. This is here to prevent # connection flooding. - # permit repeated connections from Tor - if HOST in shared.connectedHostsList and \ - (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)): + if HOST in shared.connectedHostsList: socketObject.close() - logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') + with shared.printLock: + print 'We are already connected to', HOST + '. Ignoring connection.' else: break + someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. socketObject.settimeout(20) sd = sendDataThread(sendDataThreadQueue) sd.setup( - socketObject, HOST, PORT, -1) + socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware) sd.start() rd = receiveDataThread() rd.daemon = True # close the main program even if there are threads left rd.setup( - socketObject, HOST, PORT, -1, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) + socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue) rd.start() - logger.info('connected to ' + HOST + ' during INCOMING request.') + with shared.printLock: + print self, 'connected to', HOST, 'during INCOMING request.' diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 322bb20e..327f526a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -11,52 +11,23 @@ import highlevelcrypto import proofofwork import sys import tr -from bmconfigparser import BMConfigParser from debug import logger -import defaults from helper_sql import * import helper_inbox from helper_generic import addDataPadding -import helper_msgcoding -from helper_threading import * -from inventory import Inventory, PendingUpload import l10n -import protocol -import queues -import state -from binascii import hexlify, unhexlify # This thread, of which there is only one, does the heavy lifting: # calculating POWs. -def sizeof_fmt(num, suffix='h/s'): - for unit in ['','k','M','G','T','P','E','Z']: - if abs(num) < 1000.0: - return "%3.1f%s%s" % (num, unit, suffix) - num /= 1024.0 - return "%.1f%s%s" % (num, 'Yi', suffix) -class singleWorker(threading.Thread, StoppableThread): +class singleWorker(threading.Thread): def __init__(self): # QThread.__init__(self, parent) - threading.Thread.__init__(self, name="singleWorker") - self.initStop() - proofofwork.init() - - def stopThread(self): - try: - queues.workerQueue.put(("stopThread", "data")) - except: - pass - super(singleWorker, self).stopThread() + threading.Thread.__init__(self) def run(self): - - while not state.sqlReady and state.shutdown == 0: - self.stop.wait(2) - if state.shutdown > 0: - return # Initialize the neededPubkeys dictionary. queryreturn = sqlQuery( @@ -65,89 +36,60 @@ class singleWorker(threading.Thread, StoppableThread): toAddress, = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) if toAddressVersionNumber <= 3 : - state.neededPubkeys[toAddress] = 0 + shared.neededPubkeys[toAddress] = 0 elif toAddressVersionNumber >= 4: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() privEncryptionKey = doubleHashOfAddressData[:32] # Note that this is the first half of the sha512 hash. tag = doubleHashOfAddressData[32:] - state.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. + shared.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex'))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. # Initialize the shared.ackdataForWhichImWatching data structure queryreturn = sqlQuery( - '''SELECT ackdata FROM sent WHERE status = 'msgsent' ''') + '''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') for row in queryreturn: ackdata, = row - logger.info('Watching for ackdata ' + hexlify(ackdata)) + print 'Watching for ackdata', ackdata.encode('hex') shared.ackdataForWhichImWatching[ackdata] = 0 - # Fix legacy (headerless) watched ackdata to include header - for oldack in shared.ackdataForWhichImWatching.keys(): - if (len(oldack)==32): - # attach legacy header, always constant (msg/1/1) - newack = '\x00\x00\x00\x02\x01\x01' + oldack - shared.ackdataForWhichImWatching[newack] = 0 - sqlExecute('UPDATE sent SET ackdata=? WHERE ackdata=?', - newack, oldack ) - del shared.ackdataForWhichImWatching[oldack] - - self.stop.wait( + time.sleep( 10) # give some time for the GUI to start before we start on existing POW tasks. - if state.shutdown == 0: - # just in case there are any pending tasks for msg - # messages that have yet to be sent. - queues.workerQueue.put(('sendmessage', '')) - # just in case there are any tasks for Broadcasts - # that have yet to be sent. - queues.workerQueue.put(('sendbroadcast', '')) + queryreturn = sqlQuery( + '''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') + for row in queryreturn: + toaddress, = row + self.requestPubKey(toaddress) - while state.shutdown == 0: - self.busy = 0 - command, data = queues.workerQueue.get() - self.busy = 1 + self.sendMsg() + # just in case there are any pending tasks for msg + # messages that have yet to be sent. + self.sendBroadcast() + # just in case there are any tasks for Broadcasts + # that have yet to be sent. + + while True: + command, data = shared.workerQueue.get() if command == 'sendmessage': - try: - self.sendMsg() - except: - pass + self.sendMsg() elif command == 'sendbroadcast': - try: - self.sendBroadcast() - except: - pass + self.sendBroadcast() elif command == 'doPOWForMyV2Pubkey': - try: - self.doPOWForMyV2Pubkey(data) - except: - pass + self.doPOWForMyV2Pubkey(data) elif command == 'sendOutOrStoreMyV3Pubkey': - try: - self.sendOutOrStoreMyV3Pubkey(data) - except: - pass + self.sendOutOrStoreMyV3Pubkey(data) elif command == 'sendOutOrStoreMyV4Pubkey': - try: - self.sendOutOrStoreMyV4Pubkey(data) - except: - pass - elif command == 'resetPoW': - try: - proofofwork.resetPoW() - except: - pass - elif command == 'stopThread': - self.busy = 0 - return + self.sendOutOrStoreMyV4Pubkey(data) else: - logger.error('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) + with shared.printLock: + sys.stderr.write( + 'Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) - queues.workerQueue.task_done() - logger.info("Quitting...") + shared.workerQueue.task_done() def doPOWForMyV2Pubkey(self, hash): # This function also broadcasts out the pubkey message once it is done with the POW # Look up my stream number based on my address hash - """configSections = shared.config.addresses() + """configSections = shared.config.sections() for addressInKeysFile in configSections: if addressInKeysFile <> 'bitmessagesettings': status,addressVersionNumber,streamNumber,hashFromThisParticularAddress = decodeAddress(addressInKeysFile) @@ -164,51 +106,55 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki). + payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). try: - privSigningKeyBase58 = BMConfigParser().get( + privSigningKeyBase58 = shared.config.get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as err: - logger.error('Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) + with shared.printLock: + sys.stderr.write( + 'Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) - pubSigningKey = unhexlify(highlevelcrypto.privToPub( - privSigningKeyHex)) - pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex)) + privSigningKeyHex = shared.decodeWalletImportFormat( + privSigningKeyBase58).encode('hex') + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') + pubSigningKey = highlevelcrypto.privToPub( + privSigningKeyHex).decode('hex') + pubEncryptionKey = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex') payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] # Do the POW for this pubkey message - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For pubkey message) Doing proof of work...') + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + print '(For pubkey message) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For pubkey message) Found proof of work ' + str(trialValue), ' Nonce: ', str(nonce)) + print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') - PendingUpload().add(inventoryHash) + shared.inventorySets[streamNumber].add(inventoryHash) - logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) + with shared.printLock: + print 'broadcasting inv with hash:', inventoryHash.encode('hex') - queues.invQueue.put((streamNumber, inventoryHash)) - queues.UISignalQueue.put(('updateStatusBar', '')) + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) + shared.UISignalQueue.put(('updateStatusBar', '')) try: - BMConfigParser().set( + shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - BMConfigParser().save() + shared.writeKeysFile() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -224,8 +170,9 @@ class singleWorker(threading.Thread, StoppableThread): except: #The address has been deleted. return - if BMConfigParser().safeGetBoolean(myAddress, 'chan'): - logger.info('This is a chan address. Not sending pubkey.') + if shared.safeConfigGetBoolean(myAddress, 'chan'): + with shared.printLock: + print 'This is a chan address. Not sending pubkey.' return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) @@ -244,33 +191,35 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki). + payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). try: - privSigningKeyBase58 = BMConfigParser().get( + privSigningKeyBase58 = shared.config.get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as err: - logger.error('Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) + with shared.printLock: + sys.stderr.write( + 'Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) - pubSigningKey = unhexlify(highlevelcrypto.privToPub( - privSigningKeyHex)) - pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex)) + privSigningKeyHex = shared.decodeWalletImportFormat( + privSigningKeyBase58).encode('hex') + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') + pubSigningKey = highlevelcrypto.privToPub( + privSigningKeyHex).decode('hex') + pubEncryptionKey = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex') payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] - payload += encodeVarint(BMConfigParser().getint( + payload += encodeVarint(shared.config.getint( myAddress, 'noncetrialsperbyte')) - payload += encodeVarint(BMConfigParser().getint( + payload += encodeVarint(shared.config.getint( myAddress, 'payloadlengthextrabytes')) signature = highlevelcrypto.sign(payload, privSigningKeyHex) @@ -278,27 +227,31 @@ class singleWorker(threading.Thread, StoppableThread): payload += signature # Do the POW for this pubkey message - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For pubkey message) Doing proof of work...') + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + with shared.printLock: + print '(For pubkey message) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For pubkey message) Found proof of work. Nonce: ' + str(nonce)) + with shared.printLock: + print '(For pubkey message) Found proof of work. Nonce:', nonce payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') - PendingUpload().add(inventoryHash) + shared.inventorySets[streamNumber].add(inventoryHash) - logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) + with shared.printLock: + print 'broadcasting inv with hash:', inventoryHash.encode('hex') - queues.invQueue.put((streamNumber, inventoryHash)) - queues.UISignalQueue.put(('updateStatusBar', '')) + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) + shared.UISignalQueue.put(('updateStatusBar', '')) try: - BMConfigParser().set( + shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - BMConfigParser().save() + shared.writeKeysFile() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -307,11 +260,12 @@ class singleWorker(threading.Thread, StoppableThread): # If this isn't a chan address, this function assembles the pubkey data, # does the necessary POW and sends it out. def sendOutOrStoreMyV4Pubkey(self, myAddress): - if not BMConfigParser().has_section(myAddress): + if not shared.config.has_section(myAddress): #The address has been deleted. return - if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'): - logger.info('This is a chan address. Not sending pubkey.') + if shared.safeConfigGetBoolean(myAddress, 'chan'): + with shared.printLock: + print 'This is a chan address. Not sending pubkey.' return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) @@ -322,31 +276,34 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - dataToEncrypt = protocol.getBitfield(myAddress) + + dataToEncrypt = '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). try: - privSigningKeyBase58 = BMConfigParser().get( + privSigningKeyBase58 = shared.config.get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as err: - logger.error('Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) + with shared.printLock: + sys.stderr.write( + 'Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) - pubSigningKey = unhexlify(highlevelcrypto.privToPub( - privSigningKeyHex)) - pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex)) + privSigningKeyHex = shared.decodeWalletImportFormat( + privSigningKeyBase58).encode('hex') + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') + pubSigningKey = highlevelcrypto.privToPub( + privSigningKeyHex).decode('hex') + pubEncryptionKey = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex') dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] - dataToEncrypt += encodeVarint(BMConfigParser().getint( + dataToEncrypt += encodeVarint(shared.config.getint( myAddress, 'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(BMConfigParser().getint( + dataToEncrypt += encodeVarint(shared.config.getint( myAddress, 'payloadlengthextrabytes')) # When we encrypt, we'll use a hash of the data @@ -365,72 +322,68 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKey = doubleHashOfAddressData[:32] pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( - dataToEncrypt, hexlify(pubEncryptionKey)) + dataToEncrypt, pubEncryptionKey.encode('hex')) # Do the POW for this pubkey message - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For pubkey message) Doing proof of work...') + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + print '(For pubkey message) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For pubkey message) Found proof of work ' + str(trialValue) + 'Nonce: ' + str(nonce)) + print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) - PendingUpload().add(inventoryHash) + shared.inventorySets[streamNumber].add(inventoryHash) - logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) + with shared.printLock: + print 'broadcasting inv with hash:', inventoryHash.encode('hex') - queues.invQueue.put((streamNumber, inventoryHash)) - queues.UISignalQueue.put(('updateStatusBar', '')) + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) + shared.UISignalQueue.put(('updateStatusBar', '')) try: - BMConfigParser().set( + shared.config.set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - BMConfigParser().save() + shared.writeKeysFile() except Exception as err: logger.error('Error: Couldn\'t add the lastpubkeysendtime to the keys.dat file. Error message: %s' % err) def sendBroadcast(self): - # Reset just in case - sqlExecute( - '''UPDATE sent SET status='broadcastqueued' WHERE status = 'doingbroadcastpow' ''') queryreturn = sqlQuery( - '''SELECT fromaddress, subject, message, ackdata, ttl, encodingtype FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') - + '''SELECT fromaddress, subject, message, ackdata, ttl FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') for row in queryreturn: - fromaddress, subject, body, ackdata, TTL, encoding = row + fromaddress, subject, body, ackdata, TTL = row status, addressVersionNumber, streamNumber, ripe = decodeAddress( fromaddress) if addressVersionNumber <= 1: - logger.error('Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n') + with shared.printLock: + sys.stderr.write( + 'Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n') return # We need to convert our private keys to public keys in order # to include them. try: - privSigningKeyBase58 = BMConfigParser().get( + privSigningKeyBase58 = shared.config.get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( fromaddress, 'privencryptionkey') except: - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue - sqlExecute( - '''UPDATE sent SET status='doingbroadcastpow' WHERE ackdata=? AND status='broadcastqueued' ''', - ackdata) - - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) + privSigningKeyHex = shared.decodeWalletImportFormat( + privSigningKeyBase58).encode('hex') + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') pubSigningKey = highlevelcrypto.privToPub(privSigningKeyHex).decode( 'hex') # At this time these pubkeys are 65 bytes long because they include the encoding byte which we won't be sending in the broadcast message. - pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex)) + pubEncryptionKey = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex') if TTL > 28 * 24 * 60 * 60: TTL = 28 * 24 * 60 * 60 @@ -457,16 +410,15 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt += encodeVarint(streamNumber) - dataToEncrypt += protocol.getBitfield(fromaddress) # behavior bitfield + dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] if addressVersionNumber >= 3: - dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(BMConfigParser().getint(fromaddress,'payloadlengthextrabytes')) - dataToEncrypt += encodeVarint(encoding) # message encoding type - encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": body}, encoding) - dataToEncrypt += encodeVarint(encodedMessage.length) - dataToEncrypt += encodedMessage.data + dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte')) + dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes')) + dataToEncrypt += '\x02' # message encoding type + dataToEncrypt += encodeVarint(len('Subject:' + subject + '\n' + 'Body:' + body)) #Type 2 is simple UTF-8 message encoding per the documentation on the wiki. + dataToEncrypt += 'Subject:' + subject + '\n' + 'Body:' + body dataToSign = payload + dataToEncrypt signature = highlevelcrypto.sign( @@ -487,15 +439,15 @@ class singleWorker(threading.Thread, StoppableThread): pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( - dataToEncrypt, hexlify(pubEncryptionKey)) + dataToEncrypt, pubEncryptionKey.encode('hex')) - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For broadcast message) Doing proof of work...') - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast...")))) + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + print '(For broadcast message) Doing proof of work...' + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Doing work necessary to send broadcast...")))) initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For broadcast message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) + print '(For broadcast message) Found proof of work', trialValue, 'Nonce:', nonce payload = pack('>Q', nonce) + payload @@ -508,13 +460,15 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(payload) objectType = 3 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) - PendingUpload().add(inventoryHash) - logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - queues.invQueue.put((streamNumber, inventoryHash)) + shared.inventorySets[streamNumber].add(inventoryHash) + with shared.printLock: + print 'sending inv (within sendBroadcast function) for object:', inventoryHash.encode('hex') + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) # Update the status of the message in the 'sent' table to have # a 'broadcastsent' status @@ -527,13 +481,16 @@ class singleWorker(threading.Thread, StoppableThread): def sendMsg(self): - # Reset just in case - sqlExecute( - '''UPDATE sent SET status='msgqueued' WHERE status IN ('doingpubkeypow', 'doingmsgpow')''') - queryreturn = sqlQuery( - '''SELECT toaddress, fromaddress, subject, message, ackdata, status, ttl, retrynumber, encodingtype FROM sent WHERE (status='msgqueued' or status='forcepow') and folder='sent' ''') - for row in queryreturn: # while we have a msg that needs some work - toaddress, fromaddress, subject, message, ackdata, status, TTL, retryNumber, encoding = row + while True: # while we have a msg that needs some work + + # Select just one msg that needs work. + queryreturn = sqlQuery( + '''SELECT toaddress, fromaddress, subject, message, ackdata, status, ttl, retrynumber FROM sent WHERE (status='msgqueued' or status='doingmsgpow' or status='forcepow') and folder='sent' LIMIT 1''') + if len(queryreturn) == 0: # if there is no work to do then + break # break out of this sendMsg loop and + # wait for something to get put in the shared.workerQueue. + row = queryreturn[0] + toaddress, fromaddress, subject, message, ackdata, status, TTL, retryNumber = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress( toaddress) fromStatus, fromAddressVersionNumber, fromStreamNumber, fromRipe = decodeAddress( @@ -550,7 +507,7 @@ class singleWorker(threading.Thread, StoppableThread): # so let's assume that we have it. pass # If we are sending a message to ourselves or a chan then we won't need an entry in the pubkeys table; we can calculate the needed pubkey using the private keys in our keys.dat file. - elif BMConfigParser().has_section(toaddress): + elif shared.config.has_section(toaddress): sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) @@ -576,14 +533,14 @@ class singleWorker(threading.Thread, StoppableThread): toTag = '' else: toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:] - if toaddress in state.neededPubkeys or toTag in state.neededPubkeys: + if toaddress in shared.neededPubkeys or toTag in shared.neededPubkeys: # We already sent a request for the pubkey sqlExecute( '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', int(time.time()) + 2.5*24*60*60, toaddress) - queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( - toaddress, tr._translate("MainWindow",'Encryption key was requested earlier.')))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toaddress, tr.translateText("MainWindow",'Encryption key was requested earlier.')))) continue #on with the next msg on which we can do some work else: # We have not yet sent a request for the pubkey @@ -600,44 +557,63 @@ class singleWorker(threading.Thread, StoppableThread): toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() privEncryptionKey = doubleHashOfToAddressData[:32] # The first half of the sha512 hash. tag = doubleHashOfToAddressData[32:] # The second half of the sha512 hash. - state.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) + shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex'))) + + queryreturn = sqlQuery( + '''SELECT payload FROM inventory WHERE objecttype=1 and tag=? ''', toTag) + if queryreturn != []: # if there are any pubkeys in our inventory with the correct tag.. + for row in queryreturn: + payload, = row + if shared.decryptAndCheckPubkeyPayload(payload, toaddress) == 'successful': + needToRequestPubkey = False + sqlExecute( + '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', + toaddress) + del shared.neededPubkeys[tag] + break + #else: # There was something wrong with this pubkey object even + # though it had the correct tag- almost certainly because + # of malicious behavior or a badly programmed client. If + # there are any other pubkeys in our inventory with the correct + # tag then we'll try to decrypt those. - for value in Inventory().by_type_and_tag(1, toTag): - if shared.decryptAndCheckPubkeyPayload(value.payload, toaddress) == 'successful': #if valid, this function also puts it in the pubkeys table. - needToRequestPubkey = False - sqlExecute( - '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', - toaddress) - del state.neededPubkeys[tag] - break - #else: # There was something wrong with this pubkey object even - # though it had the correct tag- almost certainly because - # of malicious behavior or a badly programmed client. If - # there are any other pubkeys in our inventory with the correct - # tag then we'll try to decrypt those. + if needToRequestPubkey: # Obviously we had no success looking in the sql inventory. Let's look through the memory inventory. + with shared.inventoryLock: + for hash, storedValue in shared.inventory.items(): + objectType, streamNumber, payload, expiresTime, tag = storedValue + if objectType == 1 and tag == toTag: + if shared.decryptAndCheckPubkeyPayload(payload, toaddress) == 'successful': #if valid, this function also puts it in the pubkeys table. + needToRequestPubkey = False + sqlExecute( + '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', + toaddress) + del shared.neededPubkeys[tag] + break if needToRequestPubkey: sqlExecute( '''UPDATE sent SET status='doingpubkeypow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) - queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( - toaddress, tr._translate("MainWindow",'Sending a request for the recipient\'s encryption key.')))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toaddress, tr.translateText("MainWindow",'Sending a request for the recipient\'s encryption key.')))) self.requestPubKey(toaddress) continue #on with the next msg on which we can do some work # At this point we know that we have the necessary pubkey in the pubkeys table. - TTL *= 2**retryNumber - if TTL > 28 * 24 * 60 * 60: - TTL = 28 * 24 * 60 * 60 + if retryNumber == 0: + if TTL > 28 * 24 * 60 * 60: + TTL = 28 * 24 * 60 * 60 + else: + TTL = 28 * 24 * 60 * 60 TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL embeddedTime = int(time.time() + TTL) - if not BMConfigParser().has_section(toaddress): # if we aren't sending this to ourselves or a chan + if not shared.config.has_section(toaddress): # if we aren't sending this to ourselves or a chan shared.ackdataForWhichImWatching[ackdata] = 0 - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Looking up the receiver\'s public key")))) - logger.info('Sending a message.') - logger.debug('First 150 characters of message: ' + repr(message[:150])) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Looking up the receiver\'s public key")))) + with shared.printLock: + print 'Sending a message. First 150 characters of message:', repr(message[:150]) # Let us fetch the recipient's public key out of our database. If # the required proof of work difficulty is too hard then we'll @@ -666,9 +642,9 @@ class singleWorker(threading.Thread, StoppableThread): # unencrypted. Before we actually do it the sending human must check a box # in the settings menu to allow it. if shared.isBitSetWithinBitfield(behaviorBitfield,30): # if receiver is a mobile device who expects that their address RIPE is included unencrypted on the front of the message.. - if not shared.BMConfigParser().safeGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. + if not shared.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. logger.info('The receiver is a mobile user but the sender (you) has not selected that you are willing to send to mobiles. Aborting send.') - queues.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1').arg(l10n.formatTimestamp())))) # if the human changes their setting and then sends another message or restarts their client, this one will send at that time. continue readPosition += 4 # to bypass the bitfield of behaviors @@ -680,10 +656,10 @@ class singleWorker(threading.Thread, StoppableThread): # Let us fetch the amount of work required by the recipient. if toAddressVersionNumber == 2: - requiredAverageProofOfWorkNonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) + requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) elif toAddressVersionNumber >= 3: requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint( pubkeyPayload[readPosition:readPosition + 10]) @@ -691,70 +667,72 @@ class singleWorker(threading.Thread, StoppableThread): requiredPayloadLengthExtraBytes, varintLength = decodeVarint( pubkeyPayload[readPosition:readPosition + 10]) readPosition += varintLength - if requiredAverageProofOfWorkNonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network. - requiredAverageProofOfWorkNonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte - if requiredPayloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes: - requiredPayloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes + if requiredAverageProofOfWorkNonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: # We still have to meet a minimum POW difficulty regardless of what they say is allowed in order to get our message to propagate through the network. + requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + if requiredPayloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: + requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes logger.debug('Using averageProofOfWorkNonceTrialsPerByte: %s and payloadLengthExtraBytes: %s.' % (requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes)) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( - requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes))))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( + requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes))))) if status != 'forcepow': - if (requiredAverageProofOfWorkNonceTrialsPerByte > BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): + if (requiredAverageProofOfWorkNonceTrialsPerByte > shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): # The demanded difficulty is more than we are willing # to do. sqlExecute( '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', ackdata) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( - requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3").arg(str(float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( + requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. - logger.info('Sending a message.') - logger.debug('First 150 characters of message: ' + repr(message[:150])) - behaviorBitfield = protocol.getBitfield(fromaddress) + with shared.printLock: + print 'Sending a message. First 150 characters of message:', repr(message[:150]) + behaviorBitfield = '\x00\x00\x00\x01' try: - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( toaddress, 'privencryptionkey') except Exception as err: - queues.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) - logger.error('Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) + with shared.printLock: + sys.stderr.write( + 'Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) continue - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) - pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex))[1:] - requiredAverageProofOfWorkNonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') + pubEncryptionKeyBase256 = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex')[1:] + requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Doing work necessary to send message.")))) # Now we can start to assemble our message. payload = encodeVarint(fromAddressVersionNumber) payload += encodeVarint(fromStreamNumber) - payload += protocol.getBitfield(fromaddress) # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) + payload += '\x00\x00\x00\x01' # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) # We need to convert our private keys to public keys in order # to include them. try: - privSigningKeyBase58 = BMConfigParser().get( + privSigningKeyBase58 = shared.config.get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = BMConfigParser().get( + privEncryptionKeyBase58 = shared.config.get( fromaddress, 'privencryptionkey') except: - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( - ackdata, tr._translate("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue - privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( - privSigningKeyBase58)) - privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( - privEncryptionKeyBase58)) + privSigningKeyHex = shared.decodeWalletImportFormat( + privSigningKeyBase58).encode('hex') + privEncryptionKeyHex = shared.decodeWalletImportFormat( + privEncryptionKeyBase58).encode('hex') - pubSigningKey = unhexlify(highlevelcrypto.privToPub( - privSigningKeyHex)) - pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( - privEncryptionKeyHex)) + pubSigningKey = highlevelcrypto.privToPub( + privSigningKeyHex).decode('hex') + pubEncryptionKey = highlevelcrypto.privToPub( + privEncryptionKeyHex).decode('hex') payload += pubSigningKey[ 1:] # The \x04 on the beginning of the public keys are not sent. This way there is only one acceptable way to encode and send a public key. @@ -767,25 +745,28 @@ class singleWorker(threading.Thread, StoppableThread): # the receiver is in any of those lists. if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress): payload += encodeVarint( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte) + shared.networkDefaultProofOfWorkNonceTrialsPerByte) payload += encodeVarint( - defaults.networkDefaultPayloadLengthExtraBytes) + shared.networkDefaultPayloadLengthExtraBytes) else: - payload += encodeVarint(BMConfigParser().getint( + payload += encodeVarint(shared.config.getint( fromaddress, 'noncetrialsperbyte')) - payload += encodeVarint(BMConfigParser().getint( + payload += encodeVarint(shared.config.getint( fromaddress, 'payloadlengthextrabytes')) payload += toRipe # This hash will be checked by the receiver of the message to verify that toRipe belongs to them. This prevents a Surreptitious Forwarding Attack. - payload += encodeVarint(encoding) # message encoding type - encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding) - payload += encodeVarint(encodedMessage.length) - payload += encodedMessage.data - if BMConfigParser().has_section(toaddress): - logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') + payload += '\x02' # Type 2 is simple UTF-8 message encoding as specified on the Protocol Specification on the Bitmessage Wiki. + messageToTransmit = 'Subject:' + \ + subject + '\n' + 'Body:' + message + payload += encodeVarint(len(messageToTransmit)) + payload += messageToTransmit + if shared.config.has_section(toaddress): + with shared.printLock: + print 'Not bothering to include ackdata because we are sending to ourselves or a chan.' fullAckPayload = '' - elif not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): - logger.info('Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.') + elif not shared.isBitSetWithinBitfield(behaviorBitfield,31): + with shared.printLock: + print 'Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.' fullAckPayload = '' else: fullAckPayload = self.generateFullAckMessage( @@ -799,10 +780,10 @@ class singleWorker(threading.Thread, StoppableThread): # We have assembled the data that will be encrypted. try: - encrypted = highlevelcrypto.encrypt(payload,"04"+hexlify(pubEncryptionKeyBase256)) + encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex')) except: sqlExecute('''UPDATE sent SET status='badkey' WHERE ackdata=?''', ackdata) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr.translateText("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) continue encryptedPayload = pack('>Q', embeddedTime) @@ -810,16 +791,18 @@ class singleWorker(threading.Thread, StoppableThread): encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(toStreamNumber) + encrypted target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For msg message) Doing proof of work. Total required difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / defaults.networkDefaultPayloadLengthExtraBytes) + with shared.printLock: + print '(For msg message) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For msg message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) - try: - logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) - except: - pass + with shared.printLock: + print '(For msg message) Found proof of work', trialValue, 'Nonce:', nonce + try: + print 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.' + except: + pass encryptedPayload = pack('>Q', nonce) + encryptedPayload @@ -832,24 +815,27 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') - PendingUpload().add(inventoryHash) - if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) + shared.inventorySets[toStreamNumber].add(inventoryHash) + if shared.config.has_section(toaddress): + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(l10n.formatTimestamp())))) else: # not sending to a chan or one of my addresses - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) - logger.info('Broadcasting inv for my msg(within sendmsg function):' + hexlify(inventoryHash)) - queues.invQueue.put((toStreamNumber, inventoryHash)) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) + print 'Broadcasting inv for my msg(within sendmsg function):', inventoryHash.encode('hex') + shared.broadcastToSendDataQueues(( + toStreamNumber, 'advertiseobject', inventoryHash)) # Update the sent message in the sent table with the necessary information. - if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): + if shared.config.has_section(toaddress): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' - # wait 10% past expiration - sleepTill = int(time.time() + TTL * 1.1) + if retryNumber == 0: + sleepTill = int(time.time()) + TTL + else: + sleepTill = int(time.time()) + 28*24*60*60 * 2**retryNumber sqlExecute('''UPDATE sent SET msgid=?, status=?, retrynumber=?, sleeptill=?, lastactiontime=? WHERE ackdata=?''', inventoryHash, newStatus, @@ -860,21 +846,21 @@ class singleWorker(threading.Thread, StoppableThread): # If we are sending to ourselves or a chan, let's put the message in # our own inbox. - if BMConfigParser().has_section(toaddress): + if shared.config.has_section(toaddress): sigHash = hashlib.sha512(hashlib.sha512(signature).digest()).digest()[32:] # Used to detect and ignore duplicate messages in our inbox t = (inventoryHash, toaddress, fromaddress, subject, int( - time.time()), message, 'inbox', encoding, 0, sigHash) + time.time()), message, 'inbox', 2, 0, sigHash) helper_inbox.insert(t) - queues.UISignalQueue.put(('displayNewInboxMessage', ( + shared.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toaddress, fromaddress, subject, message))) # If we are behaving as an API then we might need to run an # outside command to let some program know that a new message # has arrived. - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = BMConfigParser().get( + apiNotifyPath = shared.config.get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -885,7 +871,8 @@ class singleWorker(threading.Thread, StoppableThread): toStatus, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if toStatus != 'success': - logger.error('Very abnormal error occurred in requestPubKey. toAddress is: ' + repr( + with shared.printLock: + sys.stderr.write('Very abnormal error occurred in requestPubKey. toAddress is: ' + repr( toAddress) + '. Please report this error to Atheros.') return @@ -898,19 +885,19 @@ class singleWorker(threading.Thread, StoppableThread): retryNumber = queryReturn[0][0] if addressVersionNumber <= 3: - state.neededPubkeys[toAddress] = 0 + shared.neededPubkeys[toAddress] = 0 elif addressVersionNumber >= 4: # If the user just clicked 'send' then the tag (and other information) will already # be in the neededPubkeys dictionary. But if we are recovering from a restart # of the client then we have to put it in now. privEncryptionKey = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[:32] # Note that this is the first half of the sha512 hash. tag = hashlib.sha512(hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+ripe).digest()).digest()[32:] # Note that this is the second half of the sha512 hash. - if tag not in state.neededPubkeys: - state.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. + if tag not in shared.neededPubkeys: + shared.neededPubkeys[tag] = (toAddress, highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex'))) # We'll need this for when we receive a pubkey reply: it will be encrypted and we'll need to decrypt it. - TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. - TTL *= 2**retryNumber - if TTL > 28*24*60*60: + if retryNumber == 0: + TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. + else: TTL = 28*24*60*60 TTL = TTL + random.randrange(-300, 300) # add some randomness to the TTL embeddedTime = int(time.time() + TTL) @@ -920,33 +907,39 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint(streamNumber) if addressVersionNumber <= 3: payload += ripe - logger.info('making request for pubkey with ripe: %s', hexlify(ripe)) + with shared.printLock: + print 'making request for pubkey with ripe:', ripe.encode('hex') else: payload += tag - logger.info('making request for v4 pubkey with tag: %s', hexlify(tag)) + with shared.printLock: + print 'making request for v4 pubkey with tag:', tag.encode('hex') # print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' - queues.UISignalQueue.put(('updateStatusBar', statusbar)) - queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( - toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.')))) + shared.UISignalQueue.put(('updateStatusBar', statusbar)) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + toAddress, tr.translateText("MainWindow",'Doing work necessary to request encryption key.')))) - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) + with shared.printLock: + print 'Found proof of work', trialValue, 'Nonce:', nonce payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - Inventory()[inventoryHash] = ( + shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') - PendingUpload().add(inventoryHash) - logger.info('sending inv (for the getpubkey message)') - queues.invQueue.put((streamNumber, inventoryHash)) + shared.inventorySets[streamNumber].add(inventoryHash) + print 'sending inv (for the getpubkey message)' + shared.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) - # wait 10% past expiration - sleeptill = int(time.time() + TTL * 1.1) + if retryNumber == 0: + sleeptill = int(time.time()) + TTL + else: + sleeptill = int(time.time()) + 28*24*60*60 * 2**retryNumber sqlExecute( '''UPDATE sent SET lastactiontime=?, status='awaitingpubkey', retrynumber=?, sleeptill=? WHERE toaddress=? AND (status='doingpubkeypow' OR status='awaitingpubkey') ''', int(time.time()), @@ -954,9 +947,9 @@ class singleWorker(threading.Thread, StoppableThread): sleeptill, toAddress) - queues.UISignalQueue.put(( - 'updateStatusBar', tr._translate("MainWindow",'Broadcasting the public key request. This program will auto-retry if they are offline.'))) - queues.UISignalQueue.put(('updateSentItemStatusByToAddress', (toAddress, tr._translate("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(( + 'updateStatusBar', tr.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.'))) + shared.UISignalQueue.put(('updateSentItemStatusByToAddress', (toAddress, tr.translateText("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) def generateFullAckMessage(self, ackdata, toStreamNumber, TTL): @@ -977,21 +970,24 @@ class singleWorker(threading.Thread, StoppableThread): TTL = 28*24*60*60 # 4 weeks TTL = int(TTL + random.randrange(-300, 300)) # Add some randomness to the TTL embeddedTime = int(time.time() + TTL) - - # type/version/stream already included - payload = pack('>Q', (embeddedTime)) + ackdata - - target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) - logger.info('(For ack message) Doing proof of work. TTL set to ' + str(TTL)) + payload = pack('>Q', (embeddedTime)) + payload += '\x00\x00\x00\x02' # object type: msg + payload += encodeVarint(1) # msg version + payload += encodeVarint(toStreamNumber) + ackdata + + target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + with shared.printLock: + print '(For ack message) Doing proof of work. TTL set to', TTL powStartTime = time.time() initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - logger.info('(For ack message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) - try: - logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) - except: - pass + with shared.printLock: + print '(For ack message) Found proof of work', trialValue, 'Nonce:', nonce + try: + print 'POW took', int(time.time() - powStartTime), 'seconds.', nonce / (time.time() - powStartTime), 'nonce trials per second.' + except: + pass payload = pack('>Q', nonce) + payload - return protocol.CreatePacket('object', payload) + return shared.CreatePacket('object', payload) diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py deleted file mode 100644 index bb659ebe..00000000 --- a/src/class_smtpDeliver.py +++ /dev/null @@ -1,111 +0,0 @@ -from email.mime.text import MIMEText -from email.header import Header -import smtplib -import sys -import threading -import urlparse - -from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import * -import queues -import state - -SMTPDOMAIN = "bmaddr.lan" - -class smtpDeliver(threading.Thread, StoppableThread): - _instance = None - - def __init__(self, parent=None): - threading.Thread.__init__(self, name="smtpDeliver") - self.initStop() - - def stopThread(self): - try: - queues.UISignallerQueue.put(("stopThread", "data")) - except: - pass - super(smtpDeliver, self).stopThread() - - @classmethod - def get(cls): - if not cls._instance: - cls._instance = smtpDeliver() - return cls._instance - - def run(self): - while state.shutdown == 0: - command, data = queues.UISignalQueue.get() - if command == 'writeNewAddressToTable': - label, address, streamNumber = data - pass - elif command == 'updateStatusBar': - pass - elif command == 'updateSentItemStatusByToAddress': - toAddress, message = data - pass - elif command == 'updateSentItemStatusByAckdata': - ackData, message = data - pass - elif command == 'displayNewInboxMessage': - inventoryHash, toAddress, fromAddress, subject, body = data - dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') - if dest == '': - continue - try: - u = urlparse.urlparse(dest) - to = urlparse.parse_qs(u.query)['to'] - client = smtplib.SMTP(u.hostname, u.port) - msg = MIMEText(body, 'plain', 'utf-8') - msg['Subject'] = Header(subject, 'utf-8') - msg['From'] = fromAddress + '@' + SMTPDOMAIN - toLabel = map (lambda y: BMConfigParser().safeGet(y, "label"), filter(lambda x: x == toAddress, BMConfigParser().addresses())) - if len(toLabel) > 0: - msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN) - else: - msg['To'] = toAddress + '@' + SMTPDOMAIN - client.ehlo() - client.starttls() - client.ehlo() - client.sendmail(msg['From'], [to], msg.as_string()) - logger.info("Delivered via SMTP to %s through %s:%i ...", to, u.hostname, u.port) - client.quit() - except: - logger.error("smtp delivery error", exc_info=True) - elif command == 'displayNewSentMessage': - toAddress, fromLabel, fromAddress, subject, message, ackdata = data - pass - elif command == 'updateNetworkStatusTab': - pass - elif command == 'updateNumberOfMessagesProcessed': - pass - elif command == 'updateNumberOfPubkeysProcessed': - pass - elif command == 'updateNumberOfBroadcastsProcessed': - pass - elif command == 'setStatusIcon': - pass - elif command == 'changedInboxUnread': - pass - elif command == 'rerenderMessagelistFromLabels': - pass - elif command == 'rerenderMessagelistToLabels': - pass - elif command == 'rerenderAddressBook': - pass - elif command == 'rerenderSubscriptions': - pass - elif command == 'rerenderBlackWhiteList': - pass - elif command == 'removeInboxRowByMsgid': - pass - elif command == 'newVersionAvailable': - pass - elif command == 'alert': - title, text, exitAfterUserClicksOk = data - pass - elif command == 'stopThread': - break - else: - sys.stderr.write( - 'Command sent to smtpDeliver not recognized: %s\n' % command) diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py deleted file mode 100644 index b62a7130..00000000 --- a/src/class_smtpServer.py +++ /dev/null @@ -1,201 +0,0 @@ -import asyncore -import base64 -import email -from email.parser import Parser -from email.header import decode_header -import re -import signal -import smtpd -import socket -import threading -import time - -from addresses import decodeAddress -from bmconfigparser import BMConfigParser -from debug import logger -from helper_sql import sqlExecute -from helper_ackPayload import genAckPayload -from helper_threading import StoppableThread -from pyelliptic.openssl import OpenSSL -import queues -from version import softwareVersion - -SMTPDOMAIN = "bmaddr.lan" -LISTENPORT = 8425 - -class smtpServerChannel(smtpd.SMTPChannel): - def smtp_EHLO(self, arg): - if not arg: - self.push('501 Syntax: HELO hostname') - return - self.push('250-PyBitmessage %s' % softwareVersion) - self.push('250 AUTH PLAIN') - - def smtp_AUTH(self, arg): - if not arg or arg[0:5] not in ["PLAIN"]: - self.push('501 Syntax: AUTH PLAIN') - return - authstring = arg[6:] - try: - decoded = base64.b64decode(authstring) - correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \ - "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "") - logger.debug("authstring: %s / %s", correctauth, decoded) - if correctauth == decoded: - self.auth = True - self.push('235 2.7.0 Authentication successful') - else: - raise Exception("Auth fail") - except: - self.push('501 Authentication fail') - - def smtp_DATA(self, arg): - if not hasattr(self, "auth") or not self.auth: - self.push ("530 Authentication required") - return - smtpd.SMTPChannel.smtp_DATA(self, arg) - - -class smtpServerPyBitmessage(smtpd.SMTPServer): - def handle_accept(self): - pair = self.accept() - if pair is not None: - conn, addr = pair -# print >> DEBUGSTREAM, 'Incoming connection from %s' % repr(addr) - self.channel = smtpServerChannel(self, conn, addr) - - def send(self, fromAddress, toAddress, subject, message): - status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) - stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') - ackdata = genAckPayload(streamNumber, stealthLevel) - t = () - sqlExecute( - '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', - '', - toAddress, - ripe, - fromAddress, - subject, - message, - ackdata, - int(time.time()), # sentTime (this will never change) - int(time.time()), # lastActionTime - 0, # sleepTill time. This will get set when the POW gets done. - 'msgqueued', - 0, # retryNumber - 'sent', # folder - 2, # encodingtype - min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days - ) - - queues.workerQueue.put(('sendmessage', toAddress)) - - def decode_header(self, hdr): - ret = [] - for h in decode_header(self.msg_headers[hdr]): - if h[1]: - ret.append(unicode(h[0], h[1])) - else: - ret.append(h[0].decode("utf-8", errors='replace')) - - return ret - - - def process_message(self, peer, mailfrom, rcpttos, data): -# print 'Receiving message from:', peer - p = re.compile(".*<([^>]+)>") - if not hasattr(self.channel, "auth") or not self.channel.auth: - logger.error("Missing or invalid auth") - return - try: - self.msg_headers = Parser().parsestr(data) - except: - logger.error("Invalid headers") - return - - try: - sender, domain = p.sub(r'\1', mailfrom).split("@") - if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) - if sender not in BMConfigParser().addresses(): - raise Exception("Nonexisting user %s", sender) - except Exception as err: - logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) - msg_from = self.decode_header("from") - try: - msg_from = p.sub(r'\1', self.decode_header("from")[0]) - sender, domain = msg_from.split("@") - if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) - if sender not in BMConfigParser().addresses(): - raise Exception("Nonexisting user %s", sender) - except Exception as err: - logger.error("Bad headers from %s: %s", msg_from, repr(err)) - return - - try: - msg_subject = self.decode_header('subject')[0] - except: - msg_subject = "Subject missing..." - - msg_tmp = email.message_from_string(data) - body = u'' - for part in msg_tmp.walk(): - if part and part.get_content_type() == "text/plain": - body += part.get_payload(decode=1).decode(part.get_content_charset('utf-8'), errors='replace') - - for to in rcpttos: - try: - rcpt, domain = p.sub(r'\1', to).split("@") - if domain != SMTPDOMAIN: - raise Exception("Bad domain %s", domain) - logger.debug("Sending %s to %s about %s", sender, rcpt, msg_subject) - self.send(sender, rcpt, msg_subject, body) - logger.info("Relayed %s to %s", sender, rcpt) - except Exception as err: - logger.error( "Bad to %s: %s", to, repr(err)) - continue - return - -class smtpServer(threading.Thread, StoppableThread): - def __init__(self, parent=None): - threading.Thread.__init__(self, name="smtpServerThread") - self.initStop() - self.server = smtpServerPyBitmessage(('127.0.0.1', LISTENPORT), None) - - def stopThread(self): - super(smtpServer, self).stopThread() - self.server.close() - return - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')): - for ip in ('127.0.0.1'): - try: - s.connect((ip, LISTENPORT)) - s.shutdown(socket.SHUT_RDWR) - s.close() - break - except: - pass - - def run(self): - asyncore.loop(1) - -def signals(signal, frame): - print "Got signal, terminating" - for thread in threading.enumerate(): - if thread.isAlive() and isinstance(thread, StoppableThread): - thread.stopThread() - -def runServer(): - print "Running SMTPd thread" - smtpThread = smtpServer() - smtpThread.start() - signal.signal(signal.SIGINT, signals) - signal.signal(signal.SIGTERM, signals) - print "Processing" - smtpThread.join() - print "The end" - -if __name__ == "__main__": - runServer() diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 18606e74..514f772e 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,18 +1,13 @@ import threading -from bmconfigparser import BMConfigParser +import shared import sqlite3 import time import shutil # used for moving the messages.dat file import sys import os from debug import logger -import defaults -import helper_sql from namecoin import ensureNamecoinOptions -import paths -import queues import random -import state import string import tr#anslate @@ -24,14 +19,12 @@ import tr#anslate class sqlThread(threading.Thread): def __init__(self): - threading.Thread.__init__(self, name="SQL") + threading.Thread.__init__(self) def run(self): - self.conn = sqlite3.connect(state.appdata + 'messages.dat') + self.conn = sqlite3.connect(shared.appdata + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() - - self.cur.execute('PRAGMA secure_delete = true') try: self.cur.execute( @@ -70,35 +63,35 @@ class sqlThread(threading.Thread): 'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err)) os._exit(0) - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 1: - BMConfigParser().set('bitmessagesettings', 'settingsversion', '2') + if shared.config.getint('bitmessagesettings', 'settingsversion') == 1: + shared.config.set('bitmessagesettings', 'settingsversion', '2') # If the settings version is equal to 2 or 3 then the # sqlThread will modify the pubkeys table and change # the settings version to 4. - BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') - BMConfigParser().set('bitmessagesettings', 'sockshostname', 'localhost') - BMConfigParser().set('bitmessagesettings', 'socksport', '9050') - BMConfigParser().set('bitmessagesettings', 'socksauthentication', 'false') - BMConfigParser().set('bitmessagesettings', 'socksusername', '') - BMConfigParser().set('bitmessagesettings', 'sockspassword', '') - BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false') - BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false') - BMConfigParser().set('bitmessagesettings', 'messagesencrypted', 'false') + shared.config.set('bitmessagesettings', 'socksproxytype', 'none') + shared.config.set('bitmessagesettings', 'sockshostname', 'localhost') + shared.config.set('bitmessagesettings', 'socksport', '9050') + shared.config.set('bitmessagesettings', 'socksauthentication', 'false') + shared.config.set('bitmessagesettings', 'socksusername', '') + shared.config.set('bitmessagesettings', 'sockspassword', '') + shared.config.set('bitmessagesettings', 'sockslisten', 'false') + shared.config.set('bitmessagesettings', 'keysencrypted', 'false') + shared.config.set('bitmessagesettings', 'messagesencrypted', 'false') # People running earlier versions of PyBitmessage do not have the # usedpersonally field in their pubkeys table. Let's add it. - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 2: + if shared.config.getint('bitmessagesettings', 'settingsversion') == 2: item = '''ALTER TABLE pubkeys ADD usedpersonally text DEFAULT 'no' ''' parameters = '' self.cur.execute(item, parameters) self.conn.commit() - BMConfigParser().set('bitmessagesettings', 'settingsversion', '3') + shared.config.set('bitmessagesettings', 'settingsversion', '3') # People running earlier versions of PyBitmessage do not have the # encodingtype field in their inbox and sent tables or the read field # in the inbox table. Let's add them. - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 3: + if shared.config.getint('bitmessagesettings', 'settingsversion') == 3: item = '''ALTER TABLE inbox ADD encodingtype int DEFAULT '2' ''' parameters = '' self.cur.execute(item, parameters) @@ -112,21 +105,21 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) self.conn.commit() - BMConfigParser().set('bitmessagesettings', 'settingsversion', '4') + shared.config.set('bitmessagesettings', 'settingsversion', '4') - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: - BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - defaults.networkDefaultPayloadLengthExtraBytes)) - BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') + if shared.config.getint('bitmessagesettings', 'settingsversion') == 4: + shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + shared.networkDefaultPayloadLengthExtraBytes)) + shared.config.set('bitmessagesettings', 'settingsversion', '5') - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: - BMConfigParser().set( + if shared.config.getint('bitmessagesettings', 'settingsversion') == 5: + shared.config.set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') - BMConfigParser().set('bitmessagesettings', 'settingsversion', '6') + shared.config.set('bitmessagesettings', 'settingsversion', '6') # From now on, let us keep a 'version' embedded in the messages.dat # file so that when we make changes to the database, the database @@ -179,8 +172,8 @@ class sqlThread(threading.Thread): '''update sent set status='broadcastqueued' where status='broadcastpending' ''') self.conn.commit() - if not BMConfigParser().has_option('bitmessagesettings', 'sockslisten'): - BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false') + if not shared.config.has_option('bitmessagesettings', 'sockslisten'): + shared.config.set('bitmessagesettings', 'sockslisten', 'false') ensureNamecoinOptions() @@ -231,18 +224,18 @@ class sqlThread(threading.Thread): parameters = (4,) self.cur.execute(item, parameters) - if not BMConfigParser().has_option('bitmessagesettings', 'userlocale'): - BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') - if not BMConfigParser().has_option('bitmessagesettings', 'sendoutgoingconnections'): - BMConfigParser().set('bitmessagesettings', 'sendoutgoingconnections', 'True') + if not shared.config.has_option('bitmessagesettings', 'userlocale'): + shared.config.set('bitmessagesettings', 'userlocale', 'system') + if not shared.config.has_option('bitmessagesettings', 'sendoutgoingconnections'): + shared.config.set('bitmessagesettings', 'sendoutgoingconnections', 'True') # Raise the default required difficulty from 1 to 2 # With the change to protocol v3, this is obsolete. - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 6: - """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == defaults.networkDefaultProofOfWorkNonceTrialsPerByte: - shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) + if shared.config.getint('bitmessagesettings', 'settingsversion') == 6: + """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte: + shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) """ - BMConfigParser().set('bitmessagesettings', 'settingsversion', '7') + shared.config.set('bitmessagesettings', 'settingsversion', '7') # Add a new column to the pubkeys table to store the address version. # We're going to trash all of our pubkeys and let them be redownloaded. @@ -260,18 +253,18 @@ class sqlThread(threading.Thread): parameters = (5,) self.cur.execute(item, parameters) - if not BMConfigParser().has_option('bitmessagesettings', 'useidenticons'): - BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') - if not BMConfigParser().has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt - BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons + if not shared.config.has_option('bitmessagesettings', 'useidenticons'): + shared.config.set('bitmessagesettings', 'useidenticons', 'True') + if not shared.config.has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt + shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons #Add settings to support no longer resending messages after a certain period of time even if we never get an ack - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 7: - BMConfigParser().set( + if shared.config.getint('bitmessagesettings', 'settingsversion') == 7: + shared.config.set( 'bitmessagesettings', 'stopresendingafterxdays', '') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - BMConfigParser().set('bitmessagesettings', 'settingsversion', '8') + shared.config.set('bitmessagesettings', 'settingsversion', '8') # Add a new table: objectprocessorqueue with which to hold objects # that have yet to be processed if the user shuts down Bitmessage. @@ -305,39 +298,33 @@ class sqlThread(threading.Thread): logger.debug('Finished dropping and recreating the inventory table.') # With the change to protocol version 3, reset the user-settable difficulties to 1 - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 8: - BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(defaults.networkDefaultPayloadLengthExtraBytes)) - previousTotalDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 - previousSmallMessageDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) - BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) - BMConfigParser().set('bitmessagesettings', 'settingsversion', '9') + if shared.config.getint('bitmessagesettings', 'settingsversion') == 8: + shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + shared.config.set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) + previousTotalDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 + previousSmallMessageDifficulty = int(shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 + shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) + shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(previousSmallMessageDifficulty * 1000)) + shared.config.set('bitmessagesettings', 'settingsversion', '9') # Adjust the required POW values for each of this user's addresses to conform to protocol v3 norms. - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 9: - for addressInKeysFile in BMConfigParser().addressses(): + if shared.config.getint('bitmessagesettings', 'settingsversion') == 9: + for addressInKeysFile in shared.config.sections(): try: - previousTotalDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 - previousSmallMessageDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 + previousTotalDifficulty = float(shared.config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 + previousSmallMessageDifficulty = float(shared.config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 if previousTotalDifficulty <= 2: previousTotalDifficulty = 1 if previousSmallMessageDifficulty < 1: previousSmallMessageDifficulty = 1 - BMConfigParser().set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) - BMConfigParser().set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) + shared.config.set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) + shared.config.set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) except: continue - BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') - BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') - BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') - BMConfigParser().save() - - # sanity check - if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) - if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * defaults.networkDefaultPayloadLengthExtraBytes)) + shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') + shared.config.set('bitmessagesettings', 'maxuploadrate', '0') + shared.config.set('bitmessagesettings', 'settingsversion', '10') + shared.writeKeysFile() # The format of data stored in the pubkeys table has changed. Let's # clear it, and the pubkeys from inventory, so that they'll be re-downloaded. @@ -376,8 +363,8 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) # TTL is now user-specifiable. Let's add an option to save whatever the user selects. - if not BMConfigParser().has_option('bitmessagesettings', 'ttl'): - BMConfigParser().set('bitmessagesettings', 'ttl', '367200') + if not shared.config.has_option('bitmessagesettings', 'ttl'): + shared.config.set('bitmessagesettings', 'ttl', '367200') # We'll also need a `sleeptill` field and a `ttl` field. Also we can combine # the pubkeyretrynumber and msgretrynumber into one. item = '''SELECT value FROM settings WHERE key='version';''' @@ -424,27 +411,6 @@ class sqlThread(threading.Thread): logger.debug('In messages.dat database, done adding address field to the pubkeys table and removing the hash field.') self.cur.execute('''update settings set value=10 WHERE key='version';''') - if not BMConfigParser().has_option('bitmessagesettings', 'onionhostname'): - BMConfigParser().set('bitmessagesettings', 'onionhostname', '') - if not BMConfigParser().has_option('bitmessagesettings', 'onionport'): - BMConfigParser().set('bitmessagesettings', 'onionport', '8444') - if not BMConfigParser().has_option('bitmessagesettings', 'onionbindip'): - BMConfigParser().set('bitmessagesettings', 'onionbindip', '127.0.0.1') - if not BMConfigParser().has_option('bitmessagesettings', 'smtpdeliver'): - BMConfigParser().set('bitmessagesettings', 'smtpdeliver', '') - if not BMConfigParser().has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): - BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') - if BMConfigParser().has_option('bitmessagesettings', 'maxoutboundconnections'): - try: - if BMConfigParser().getint('bitmessagesettings', 'maxoutboundconnections') < 1: raise ValueError - except ValueError as err: - BMConfigParser().remove_option('bitmessagesettings', 'maxoutboundconnections') - logger.error('Your maximum outbound connections must be a number.') - if not BMConfigParser().has_option('bitmessagesettings', 'maxoutboundconnections'): - logger.info('Setting maximum outbound connections to 8.') - BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', '8') - - BMConfigParser().save() # Are you hoping to add a new option to the keys.dat file of existing # Bitmessage users or modify the SQLite database? Add it right above this line! @@ -468,8 +434,11 @@ class sqlThread(threading.Thread): except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(While null value test) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return else: logger.error(err) @@ -481,31 +450,35 @@ class sqlThread(threading.Thread): queryreturn = self.cur.fetchall() for row in queryreturn: value, = row - if int(value) < int(time.time()) - 86400: + if int(value) < int(time.time()) - 2592000: logger.info('It has been a long time since the messages.dat file has been vacuumed. Vacuuming now...') try: self.cur.execute( ''' VACUUM ''') except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(While VACUUM) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return item = '''update settings set value=? WHERE key='lastvacuumtime';''' parameters = (int(time.time()),) self.cur.execute(item, parameters) - state.sqlReady = True - while True: - item = helper_sql.sqlSubmitQueue.get() + item = shared.sqlSubmitQueue.get() if item == 'commit': try: self.conn.commit() except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(While committing) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return elif item == 'exit': self.conn.close() logger.info('sqlThread exiting gracefully.') @@ -519,12 +492,15 @@ class sqlThread(threading.Thread): except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(while movemessagstoprog) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return self.conn.close() shutil.move( - paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat') - self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat') + shared.lookupAppdataFolder() + 'messages.dat', 'messages.dat') + self.conn = sqlite3.connect('messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'movemessagstoappdata': @@ -535,12 +511,15 @@ class sqlThread(threading.Thread): except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(while movemessagstoappdata) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return self.conn.close() shutil.move( - paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat') - self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat') + 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') + self.conn = sqlite3.connect(shared.appdata + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'deleteandvacuume': @@ -552,26 +531,30 @@ class sqlThread(threading.Thread): except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(while deleteandvacuume) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return else: - parameters = helper_sql.sqlSubmitQueue.get() - rowcount = 0 + parameters = shared.sqlSubmitQueue.get() # print 'item', item # print 'parameters', parameters try: self.cur.execute(item, parameters) - rowcount = self.cur.rowcount except Exception as err: if str(err) == 'database or disk is full': logger.fatal('(while cur.execute) Alert: Your disk or data storage volume is full. sqlThread will now exit.') - queues.UISignalQueue.put(('alert', (tr._translate("MainWindow", "Disk full"), tr._translate("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) - os._exit(0) + shared.UISignalQueue.put(('alert', (tr.translateText("MainWindow", "Disk full"), tr.translateText("MainWindow", 'Alert: Your disk or data storage volume is full. Bitmessage will now exit.'), True))) + if shared.daemon: + os._exit(0) + else: + return else: logger.fatal('Major error occurred when trying to execute a SQL statement within the sqlThread. Please tell Atheros about this error message or post it in the forum! Error occurred while trying to execute statement: "%s" Here are the parameters; you might want to censor this data with asterisks (***) as it can contain private information: %s. Here is the actual error message thrown by the sqlThread: %s', str(item), str(repr(parameters)), str(err)) logger.fatal('This program shall now abruptly exit!') os._exit(0) - helper_sql.sqlReturnQueue.put((self.cur.fetchall(), rowcount)) - # helper_sql.sqlSubmitQueue.task_done() + shared.sqlReturnQueue.put(self.cur.fetchall()) + # shared.sqlSubmitQueue.task_done() diff --git a/src/debug.py b/src/debug.py index 79c6e64e..30c64ea4 100644 --- a/src/debug.py +++ b/src/debug.py @@ -18,43 +18,20 @@ Use: `from debug import logger` to import this facility into whatever module you ''' import logging import logging.config -import os +import shared import sys import helper_startup -import state helper_startup.loadConfig() -# Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface -# examples are here: https://bitmessage.org/forum/index.php/topic,4820.msg11163.html#msg11163 -log_level = 'WARNING' - -def log_uncaught_exceptions(ex_cls, ex, tb): - logging.critical('Unhandled exception', exc_info=(ex_cls, ex, tb)) +# TODO(xj9): Get from a config file. +log_level = 'DEBUG' def configureLogging(): - have_logging = False - try: - logging.config.fileConfig(os.path.join (state.appdata, 'logging.dat')) - have_logging = True - print "Loaded logger configuration from %s" % (os.path.join(state.appdata, 'logging.dat')) - except: - if os.path.isfile(os.path.join(state.appdata, 'logging.dat')): - print "Failed to load logger configuration from %s, using default logging config" % (os.path.join(state.appdata, 'logging.dat')) - print sys.exc_info() - else: - # no need to confuse the user if the logger config is missing entirely - print "Using default logger configuration" - - sys.excepthook = log_uncaught_exceptions - - if have_logging: - return False - logging.config.dictConfig({ 'version': 1, 'formatters': { 'default': { - 'format': u'%(asctime)s - %(levelname)s - %(message)s', + 'format': '%(asctime)s - %(levelname)s - %(message)s', }, }, 'handlers': { @@ -62,16 +39,15 @@ def configureLogging(): 'class': 'logging.StreamHandler', 'formatter': 'default', 'level': log_level, - 'stream': 'ext://sys.stderr' + 'stream': 'ext://sys.stdout' }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', 'formatter': 'default', 'level': log_level, - 'filename': state.appdata + 'debug.log', + 'filename': shared.appdata + 'debug.log', 'maxBytes': 2097152, # 2 MiB 'backupCount': 1, - 'encoding': 'UTF-8', } }, 'loggers': { @@ -93,17 +69,13 @@ def configureLogging(): 'handlers': ['console'], }, }) - return True - # TODO (xj9): Get from a config file. #logger = logging.getLogger('console_only') -if configureLogging(): - if '-c' in sys.argv: - logger = logging.getLogger('file_only') - else: - logger = logging.getLogger('both') +configureLogging() +if '-c' in sys.argv: + logger = logging.getLogger('file_only') else: - logger = logging.getLogger('default') + logger = logging.getLogger('both') def restartLoggingInUpdatedAppdataLocation(): global logger @@ -111,11 +83,9 @@ def restartLoggingInUpdatedAppdataLocation(): logger.removeHandler(i) i.flush() i.close() - if configureLogging(): - if '-c' in sys.argv: - logger = logging.getLogger('file_only') - else: - logger = logging.getLogger('both') + configureLogging() + if '-c' in sys.argv: + logger = logging.getLogger('file_only') else: - logger = logging.getLogger('default') + logger = logging.getLogger('both') diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index 05b65014..f91e6fe6 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -5,22 +5,22 @@ import time import random import sys from time import strftime, localtime -import state +import shared def createDefaultKnownNodes(appdata): ############## Stream 1 ################ stream1 = {} - #stream1[state.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) - stream1[state.Peer('5.45.99.75', 8444)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('75.167.159.54', 8444)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('95.165.168.168', 8444)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('85.180.139.241', 8444)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('158.222.217.190', 8080)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('178.62.12.187', 8448)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('24.188.198.204', 8111)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('109.147.204.113', 1195)] = {"lastseen": int(time.time()), "rating": 0, "self": False} - stream1[state.Peer('178.11.46.221', 8444)] = {"lastseen": int(time.time()), "rating": 0, "self": False} + #stream1[shared.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) + stream1[shared.Peer('5.45.99.75', 8444)] = int(time.time()) + stream1[shared.Peer('75.167.159.54', 8444)] = int(time.time()) + stream1[shared.Peer('95.165.168.168', 8444)] = int(time.time()) + stream1[shared.Peer('85.180.139.241', 8444)] = int(time.time()) + stream1[shared.Peer('158.222.211.81', 8080)] = int(time.time()) + stream1[shared.Peer('178.62.12.187', 8448)] = int(time.time()) + stream1[shared.Peer('24.188.198.204', 8111)] = int(time.time()) + stream1[shared.Peer('109.147.204.113', 1195)] = int(time.time()) + stream1[shared.Peer('178.11.46.221', 8444)] = int(time.time()) ############# Stream 2 ################# stream2 = {} diff --git a/src/defaults.py b/src/defaults.py deleted file mode 100644 index 8401bf2e..00000000 --- a/src/defaults.py +++ /dev/null @@ -1,13 +0,0 @@ -# sanity check, prevent doing ridiculous PoW -# 20 million PoWs equals approximately 2 days on dev's dual R9 290 -ridiculousDifficulty = 20000000 - -# Remember here the RPC port read from namecoin.conf so we can restore to -# it as default whenever the user changes the "method" selection for -# namecoin integration to "namecoind". -namecoinDefaultRpcPort = "8336" - -#If changed, these values will cause particularly unexpected behavior: You won't be able to either send or receive messages because the proof of work you do (or demand) won't match that done or demanded by others. Don't change them! -networkDefaultProofOfWorkNonceTrialsPerByte = 1000 #The amount of work that should be performed (and demanded) per byte of the payload. -networkDefaultPayloadLengthExtraBytes = 1000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target. - diff --git a/src/depends.py b/src/depends.py index d66663b1..553a5031 100755 --- a/src/depends.py +++ b/src/depends.py @@ -1,8 +1,6 @@ #! python import sys -import os -import pyelliptic.openssl #Only really old versions of Python don't have sys.hexversion. We don't support #them. The logging module was introduced in Python 2.3 @@ -42,8 +40,6 @@ def check_hashlib(): def check_sqlite(): if sys.hexversion < 0x020500F0: logger.error('The sqlite3 module is not included in this version of Python.') - if sys.platform.startswith('freebsd'): - logger.error('On FreeBSD, try running "pkg install py27-sqlite3" as root.') return False try: import sqlite3 @@ -91,7 +87,7 @@ def check_openssl(): paths = ['libeay32.dll'] if getattr(sys, 'frozen', False): import os.path - paths.insert(0, os.path.join(sys._MEIPASS, 'libeay32.dll')) + paths.append(os.path.join(sys._MEIPASS, 'libeay32.dll')) else: paths = ['libcrypto.so'] if sys.platform == 'darwin': @@ -110,9 +106,8 @@ def check_openssl(): except: pass - openssl_version = None - openssl_hexversion = None - openssl_cflags = None + SSLEAY_VERSION = 0 + SSLEAY_CFLAGS = 2 cflags_regex = re.compile(r'(?:OPENSSL_NO_)(AES|EC|ECDH|ECDSA)(?!\w)') @@ -123,18 +118,23 @@ def check_openssl(): except OSError: continue logger.info('OpenSSL Name: ' + library._name) - openssl_version, openssl_hexversion, openssl_cflags = pyelliptic.openssl.get_version(library) - if not openssl_version: + try: + library.SSLeay.restype = ctypes.c_long + library.SSLeay_version.restype = ctypes.c_char_p + library.SSLeay_version.argtypes = [ctypes.c_int] + except AttributeError: logger.error('Cannot determine version of this OpenSSL library.') return False - logger.info('OpenSSL Version: ' + openssl_version) - logger.info('OpenSSL Compile Options: ' + openssl_cflags) + logger.info('OpenSSL Version: ' + library.SSLeay_version(SSLEAY_VERSION)) + compile_options = library.SSLeay_version(SSLEAY_CFLAGS) + logger.info('OpenSSL Compile Options: ' + compile_options) + openssl_hexversion = library.SSLeay() #PyElliptic uses EVP_CIPHER_CTX_new and EVP_CIPHER_CTX_free which were #introduced in 0.9.8b. if openssl_hexversion < 0x90802F: logger.error('This OpenSSL library is too old. PyBitmessage requires OpenSSL 0.9.8b or later with AES, Elliptic Curves (EC), ECDH, and ECDSA enabled.') return False - matches = cflags_regex.findall(openssl_cflags) + matches = cflags_regex.findall(compile_options) if len(matches) > 0: logger.error('This OpenSSL library is missing the following required features: ' + ', '.join(matches) + '. PyBitmessage requires OpenSSL 0.9.8b or later with AES, Elliptic Curves (EC), ECDH, and ECDSA enabled.') return False @@ -170,24 +170,6 @@ def check_pyqt(): import PyQt4.QtCore except ImportError: logger.error('The PyQt4 package is not available. PyBitmessage requires PyQt 4.8 or later and Qt 4.7 or later.') - if sys.platform.startswith('openbsd'): - logger.error('On OpenBSD, try running "pkg_add py-qt4" as root.') - elif sys.platform.startswith('freebsd'): - logger.error('On FreeBSD, try running "pkg install py27-qt4" as root.') - elif os.path.isfile("/etc/os-release"): - with open("/etc/os-release", 'rt') as osRelease: - for line in osRelease: - if line.startswith("NAME="): - if "fedora" in line.lower(): - logger.error('On Fedora, try running "dnf install PyQt4" as root.') - elif "opensuse" in line.lower(): - logger.error('On openSUSE, try running "zypper install python-qt" as root.') - elif "ubuntu" in line.lower(): - logger.error('On Ubuntu, try running "apt-get install python-qt4" as root.') - elif "debian" in line.lower(): - logger.error('On Debian, try running "apt-get install python-qt4" as root.') - else: - logger.error('If your package manager does not have this package, try running "pip install PyQt4".') return False logger.info('PyQt Version: ' + PyQt4.QtCore.PYQT_VERSION_STR) logger.info('Qt Version: ' + PyQt4.QtCore.QT_VERSION_STR) @@ -200,34 +182,6 @@ def check_pyqt(): passed = False return passed -def check_msgpack(): - try: - import msgpack - except ImportError: - logger.error( - 'The msgpack package is not available.' - 'It is highly recommended for messages coding.') - if sys.platform.startswith('openbsd'): - logger.error('On OpenBSD, try running "pkg_add py-msgpack" as root.') - elif sys.platform.startswith('freebsd'): - logger.error('On FreeBSD, try running "pkg install py27-msgpack-python" as root.') - elif os.path.isfile("/etc/os-release"): - with open("/etc/os-release", 'rt') as osRelease: - for line in osRelease: - if line.startswith("NAME="): - if "fedora" in line.lower(): - logger.error('On Fedora, try running "dnf install python2-msgpack" as root.') - elif "opensuse" in line.lower(): - logger.error('On openSUSE, try running "zypper install python-msgpack-python" as root.') - elif "ubuntu" in line.lower(): - logger.error('On Ubuntu, try running "apt-get install python-msgpack" as root.') - elif "debian" in line.lower(): - logger.error('On Debian, try running "apt-get install python-msgpack" as root.') - else: - logger.error('If your package manager does not have this package, try running "pip install msgpack-python".') - - return True - def check_dependencies(verbose = False, optional = False): if verbose: logger.setLevel(logging.INFO) @@ -244,7 +198,7 @@ def check_dependencies(verbose = False, optional = False): logger.error('PyBitmessage does not support Python 3+. Python 2.7.3 or greater is required.') has_all_dependencies = False - check_functions = [check_hashlib, check_sqlite, check_openssl, check_msgpack] + check_functions = [check_hashlib, check_sqlite, check_openssl] if optional: check_functions.extend([check_pyqt, check_curses]) diff --git a/src/fallback/__init__.py b/src/fallback/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fallback/umsgpack/__init__.py b/src/fallback/umsgpack/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/fallback/umsgpack/umsgpack.py b/src/fallback/umsgpack/umsgpack.py deleted file mode 100644 index cd7a2037..00000000 --- a/src/fallback/umsgpack/umsgpack.py +++ /dev/null @@ -1,1057 +0,0 @@ -# u-msgpack-python v2.4.1 - v at sergeev.io -# https://github.com/vsergeev/u-msgpack-python -# -# u-msgpack-python is a lightweight MessagePack serializer and deserializer -# module, compatible with both Python 2 and 3, as well CPython and PyPy -# implementations of Python. u-msgpack-python is fully compliant with the -# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In -# particular, it supports the new binary, UTF-8 string, and application ext -# types. -# -# MIT License -# -# Copyright (c) 2013-2016 vsergeev / Ivan (Vanya) A. Sergeev -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -# -""" -u-msgpack-python v2.4.1 - v at sergeev.io -https://github.com/vsergeev/u-msgpack-python - -u-msgpack-python is a lightweight MessagePack serializer and deserializer -module, compatible with both Python 2 and 3, as well CPython and PyPy -implementations of Python. u-msgpack-python is fully compliant with the -latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In -particular, it supports the new binary, UTF-8 string, and application ext -types. - -License: MIT -""" -import struct -import collections -import sys -import io - -__version__ = "2.4.1" -"Module version string" - -version = (2, 4, 1) -"Module version tuple" - - -############################################################################## -# Ext Class -############################################################################## - -# Extension type for application-defined types and data -class Ext: - """ - The Ext class facilitates creating a serializable extension object to store - an application-defined type and data byte array. - """ - - def __init__(self, type, data): - """ - Construct a new Ext object. - - Args: - type: application-defined type integer from 0 to 127 - data: application-defined data byte array - - Raises: - TypeError: - Specified ext type is outside of 0 to 127 range. - - Example: - >>> foo = umsgpack.Ext(0x05, b"\x01\x02\x03") - >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) - '\x82\xa7awesome\xc3\xadspecial stuff\xc7\x03\x05\x01\x02\x03' - >>> bar = umsgpack.unpackb(_) - >>> print(bar["special stuff"]) - Ext Object (Type: 0x05, Data: 01 02 03) - >>> - """ - # Application ext type should be 0 <= type <= 127 - if not isinstance(type, int) or not (type >= 0 and type <= 127): - raise TypeError("ext type out of range") - # Check data is type bytes - elif sys.version_info[0] == 3 and not isinstance(data, bytes): - raise TypeError("ext data is not type \'bytes\'") - elif sys.version_info[0] == 2 and not isinstance(data, str): - raise TypeError("ext data is not type \'str\'") - self.type = type - self.data = data - - def __eq__(self, other): - """ - Compare this Ext object with another for equality. - """ - return (isinstance(other, self.__class__) and - self.type == other.type and - self.data == other.data) - - def __ne__(self, other): - """ - Compare this Ext object with another for inequality. - """ - return not self.__eq__(other) - - def __str__(self): - """ - String representation of this Ext object. - """ - s = "Ext Object (Type: 0x%02x, Data: " % self.type - s += " ".join(["0x%02x" % ord(self.data[i:i + 1]) - for i in xrange(min(len(self.data), 8))]) - if len(self.data) > 8: - s += " ..." - s += ")" - return s - - def __hash__(self): - """ - Provide a hash of this Ext object. - """ - return hash((self.type, self.data)) - - -class InvalidString(bytes): - """Subclass of bytes to hold invalid UTF-8 strings.""" - pass - -############################################################################## -# Exceptions -############################################################################## - - -# Base Exception classes -class PackException(Exception): - "Base class for exceptions encountered during packing." - pass - - -class UnpackException(Exception): - "Base class for exceptions encountered during unpacking." - pass - - -# Packing error -class UnsupportedTypeException(PackException): - "Object type not supported for packing." - pass - - -# Unpacking error -class InsufficientDataException(UnpackException): - "Insufficient data to unpack the serialized object." - pass - - -class InvalidStringException(UnpackException): - "Invalid UTF-8 string encountered during unpacking." - pass - - -class ReservedCodeException(UnpackException): - "Reserved code encountered during unpacking." - pass - - -class UnhashableKeyException(UnpackException): - """ - Unhashable key encountered during map unpacking. - The serialized map cannot be deserialized into a Python dictionary. - """ - pass - - -class DuplicateKeyException(UnpackException): - "Duplicate key encountered during map unpacking." - pass - - -# Backwards compatibility -KeyNotPrimitiveException = UnhashableKeyException -KeyDuplicateException = DuplicateKeyException - -############################################################################# -# Exported Functions and Glob -############################################################################# - -# Exported functions and variables, set up in __init() -pack = None -packb = None -unpack = None -unpackb = None -dump = None -dumps = None -load = None -loads = None - -compatibility = False -""" -Compatibility mode boolean. - -When compatibility mode is enabled, u-msgpack-python will serialize both -unicode strings and bytes into the old "raw" msgpack type, and deserialize the -"raw" msgpack type into bytes. This provides backwards compatibility with the -old MessagePack specification. - -Example: ->>> umsgpack.compatibility = True ->>> ->>> umsgpack.packb([u"some string", b"some bytes"]) -b'\x92\xabsome string\xaasome bytes' ->>> umsgpack.unpackb(_) -[b'some string', b'some bytes'] ->>> -""" - -############################################################################## -# Packing -############################################################################## - -# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the -# code below. This is to allow for seamless Python 2 and 3 compatibility, as -# chr(obj) has a str return type instead of bytes in Python 3, and -# struct.pack(...) has the right return type in both versions. - - -def _pack_integer(obj, fp, options): - if obj < 0: - if obj >= -32: - fp.write(struct.pack("b", obj)) - elif obj >= -2**(8 - 1): - fp.write(b"\xd0" + struct.pack("b", obj)) - elif obj >= -2**(16 - 1): - fp.write(b"\xd1" + struct.pack(">h", obj)) - elif obj >= -2**(32 - 1): - fp.write(b"\xd2" + struct.pack(">i", obj)) - elif obj >= -2**(64 - 1): - fp.write(b"\xd3" + struct.pack(">q", obj)) - else: - raise UnsupportedTypeException("huge signed int") - else: - if obj <= 127: - fp.write(struct.pack("B", obj)) - elif obj <= 2**8 - 1: - fp.write(b"\xcc" + struct.pack("B", obj)) - elif obj <= 2**16 - 1: - fp.write(b"\xcd" + struct.pack(">H", obj)) - elif obj <= 2**32 - 1: - fp.write(b"\xce" + struct.pack(">I", obj)) - elif obj <= 2**64 - 1: - fp.write(b"\xcf" + struct.pack(">Q", obj)) - else: - raise UnsupportedTypeException("huge unsigned int") - - -def _pack_nil(obj, fp, options): - fp.write(b"\xc0") - - -def _pack_boolean(obj, fp, options): - fp.write(b"\xc3" if obj else b"\xc2") - - -def _pack_float(obj, fp, options): - float_precision = options.get('force_float_precision', _float_precision) - - if float_precision == "double": - fp.write(b"\xcb" + struct.pack(">d", obj)) - elif float_precision == "single": - fp.write(b"\xca" + struct.pack(">f", obj)) - else: - raise ValueError("invalid float precision") - - -def _pack_string(obj, fp, options): - obj = obj.encode('utf-8') - if len(obj) <= 31: - fp.write(struct.pack("B", 0xa0 | len(obj)) + obj) - elif len(obj) <= 2**8 - 1: - fp.write(b"\xd9" + struct.pack("B", len(obj)) + obj) - elif len(obj) <= 2**16 - 1: - fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj) - elif len(obj) <= 2**32 - 1: - fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj) - else: - raise UnsupportedTypeException("huge string") - - -def _pack_binary(obj, fp, options): - if len(obj) <= 2**8 - 1: - fp.write(b"\xc4" + struct.pack("B", len(obj)) + obj) - elif len(obj) <= 2**16 - 1: - fp.write(b"\xc5" + struct.pack(">H", len(obj)) + obj) - elif len(obj) <= 2**32 - 1: - fp.write(b"\xc6" + struct.pack(">I", len(obj)) + obj) - else: - raise UnsupportedTypeException("huge binary string") - - -def _pack_oldspec_raw(obj, fp, options): - if len(obj) <= 31: - fp.write(struct.pack("B", 0xa0 | len(obj)) + obj) - elif len(obj) <= 2**16 - 1: - fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj) - elif len(obj) <= 2**32 - 1: - fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj) - else: - raise UnsupportedTypeException("huge raw string") - - -def _pack_ext(obj, fp, options): - if len(obj.data) == 1: - fp.write(b"\xd4" + struct.pack("B", obj.type & 0xff) + obj.data) - elif len(obj.data) == 2: - fp.write(b"\xd5" + struct.pack("B", obj.type & 0xff) + obj.data) - elif len(obj.data) == 4: - fp.write(b"\xd6" + struct.pack("B", obj.type & 0xff) + obj.data) - elif len(obj.data) == 8: - fp.write(b"\xd7" + struct.pack("B", obj.type & 0xff) + obj.data) - elif len(obj.data) == 16: - fp.write(b"\xd8" + struct.pack("B", obj.type & 0xff) + obj.data) - elif len(obj.data) <= 2**8 - 1: - fp.write(b"\xc7" + - struct.pack("BB", len(obj.data), obj.type & 0xff) + obj.data) - elif len(obj.data) <= 2**16 - 1: - fp.write(b"\xc8" + - struct.pack(">HB", len(obj.data), obj.type & 0xff) + obj.data) - elif len(obj.data) <= 2**32 - 1: - fp.write(b"\xc9" + - struct.pack(">IB", len(obj.data), obj.type & 0xff) + obj.data) - else: - raise UnsupportedTypeException("huge ext data") - - -def _pack_array(obj, fp, options): - if len(obj) <= 15: - fp.write(struct.pack("B", 0x90 | len(obj))) - elif len(obj) <= 2**16 - 1: - fp.write(b"\xdc" + struct.pack(">H", len(obj))) - elif len(obj) <= 2**32 - 1: - fp.write(b"\xdd" + struct.pack(">I", len(obj))) - else: - raise UnsupportedTypeException("huge array") - - for e in obj: - pack(e, fp, **options) - - -def _pack_map(obj, fp, options): - if len(obj) <= 15: - fp.write(struct.pack("B", 0x80 | len(obj))) - elif len(obj) <= 2**16 - 1: - fp.write(b"\xde" + struct.pack(">H", len(obj))) - elif len(obj) <= 2**32 - 1: - fp.write(b"\xdf" + struct.pack(">I", len(obj))) - else: - raise UnsupportedTypeException("huge array") - - for k, v in obj.items(): - pack(k, fp, **options) - pack(v, fp, **options) - -######################################## - - -# Pack for Python 2, with 'unicode' type, 'str' type, and 'long' type -def _pack2(obj, fp, **options): - """ - Serialize a Python object into MessagePack bytes. - - Args: - obj: a Python object - fp: a .write()-supporting file-like object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping a custom type - to a callable that packs an instance of the type - into an Ext object - force_float_precision (str): "single" to force packing floats as - IEEE-754 single-precision floats, - "double" to force packing floats as - IEEE-754 double-precision floats. - - Returns: - None. - - Raises: - UnsupportedType(PackException): - Object type not supported for packing. - - Example: - >>> f = open('test.bin', 'wb') - >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) - >>> - """ - global compatibility - - ext_handlers = options.get("ext_handlers") - - if obj is None: - _pack_nil(obj, fp, options) - elif ext_handlers and obj.__class__ in ext_handlers: - _pack_ext(ext_handlers[obj.__class__](obj), fp, options) - elif isinstance(obj, bool): - _pack_boolean(obj, fp, options) - elif isinstance(obj, int) or isinstance(obj, long): - _pack_integer(obj, fp, options) - elif isinstance(obj, float): - _pack_float(obj, fp, options) - elif compatibility and isinstance(obj, unicode): - _pack_oldspec_raw(bytes(obj), fp, options) - elif compatibility and isinstance(obj, bytes): - _pack_oldspec_raw(obj, fp, options) - elif isinstance(obj, unicode): - _pack_string(obj, fp, options) - elif isinstance(obj, str): - _pack_binary(obj, fp, options) - elif isinstance(obj, list) or isinstance(obj, tuple): - _pack_array(obj, fp, options) - elif isinstance(obj, dict): - _pack_map(obj, fp, options) - elif isinstance(obj, Ext): - _pack_ext(obj, fp, options) - elif ext_handlers: - # Linear search for superclass - t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) - if t: - _pack_ext(ext_handlers[t](obj), fp, options) - else: - raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) - else: - raise UnsupportedTypeException("unsupported type: %s" % str(type(obj))) - - -# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type -def _pack3(obj, fp, **options): - """ - Serialize a Python object into MessagePack bytes. - - Args: - obj: a Python object - fp: a .write()-supporting file-like object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping a custom type - to a callable that packs an instance of the type - into an Ext object - force_float_precision (str): "single" to force packing floats as - IEEE-754 single-precision floats, - "double" to force packing floats as - IEEE-754 double-precision floats. - - Returns: - None. - - Raises: - UnsupportedType(PackException): - Object type not supported for packing. - - Example: - >>> f = open('test.bin', 'wb') - >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) - >>> - """ - global compatibility - - ext_handlers = options.get("ext_handlers") - - if obj is None: - _pack_nil(obj, fp, options) - elif ext_handlers and obj.__class__ in ext_handlers: - _pack_ext(ext_handlers[obj.__class__](obj), fp, options) - elif isinstance(obj, bool): - _pack_boolean(obj, fp, options) - elif isinstance(obj, int): - _pack_integer(obj, fp, options) - elif isinstance(obj, float): - _pack_float(obj, fp, options) - elif compatibility and isinstance(obj, str): - _pack_oldspec_raw(obj.encode('utf-8'), fp, options) - elif compatibility and isinstance(obj, bytes): - _pack_oldspec_raw(obj, fp, options) - elif isinstance(obj, str): - _pack_string(obj, fp, options) - elif isinstance(obj, bytes): - _pack_binary(obj, fp, options) - elif isinstance(obj, list) or isinstance(obj, tuple): - _pack_array(obj, fp, options) - elif isinstance(obj, dict): - _pack_map(obj, fp, options) - elif isinstance(obj, Ext): - _pack_ext(obj, fp, options) - elif ext_handlers: - # Linear search for superclass - t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) - if t: - _pack_ext(ext_handlers[t](obj), fp, options) - else: - raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) - else: - raise UnsupportedTypeException( - "unsupported type: %s" % str(type(obj))) - - -def _packb2(obj, **options): - """ - Serialize a Python object into MessagePack bytes. - - Args: - obj: a Python object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping a custom type - to a callable that packs an instance of the type - into an Ext object - force_float_precision (str): "single" to force packing floats as - IEEE-754 single-precision floats, - "double" to force packing floats as - IEEE-754 double-precision floats. - - Returns: - A 'str' containing serialized MessagePack bytes. - - Raises: - UnsupportedType(PackException): - Object type not supported for packing. - - Example: - >>> umsgpack.packb({u"compact": True, u"schema": 0}) - '\x82\xa7compact\xc3\xa6schema\x00' - >>> - """ - fp = io.BytesIO() - _pack2(obj, fp, **options) - return fp.getvalue() - - -def _packb3(obj, **options): - """ - Serialize a Python object into MessagePack bytes. - - Args: - obj: a Python object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping a custom type - to a callable that packs an instance of the type - into an Ext object - force_float_precision (str): "single" to force packing floats as - IEEE-754 single-precision floats, - "double" to force packing floats as - IEEE-754 double-precision floats. - - Returns: - A 'bytes' containing serialized MessagePack bytes. - - Raises: - UnsupportedType(PackException): - Object type not supported for packing. - - Example: - >>> umsgpack.packb({u"compact": True, u"schema": 0}) - b'\x82\xa7compact\xc3\xa6schema\x00' - >>> - """ - fp = io.BytesIO() - _pack3(obj, fp, **options) - return fp.getvalue() - -############################################################################# -# Unpacking -############################################################################# - - -def _read_except(fp, n): - data = fp.read(n) - if len(data) < n: - raise InsufficientDataException() - return data - - -def _unpack_integer(code, fp, options): - if (ord(code) & 0xe0) == 0xe0: - return struct.unpack("b", code)[0] - elif code == b'\xd0': - return struct.unpack("b", _read_except(fp, 1))[0] - elif code == b'\xd1': - return struct.unpack(">h", _read_except(fp, 2))[0] - elif code == b'\xd2': - return struct.unpack(">i", _read_except(fp, 4))[0] - elif code == b'\xd3': - return struct.unpack(">q", _read_except(fp, 8))[0] - elif (ord(code) & 0x80) == 0x00: - return struct.unpack("B", code)[0] - elif code == b'\xcc': - return struct.unpack("B", _read_except(fp, 1))[0] - elif code == b'\xcd': - return struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xce': - return struct.unpack(">I", _read_except(fp, 4))[0] - elif code == b'\xcf': - return struct.unpack(">Q", _read_except(fp, 8))[0] - raise Exception("logic error, not int: 0x%02x" % ord(code)) - - -def _unpack_reserved(code, fp, options): - if code == b'\xc1': - raise ReservedCodeException( - "encountered reserved code: 0x%02x" % ord(code)) - raise Exception( - "logic error, not reserved code: 0x%02x" % ord(code)) - - -def _unpack_nil(code, fp, options): - if code == b'\xc0': - return None - raise Exception("logic error, not nil: 0x%02x" % ord(code)) - - -def _unpack_boolean(code, fp, options): - if code == b'\xc2': - return False - elif code == b'\xc3': - return True - raise Exception("logic error, not boolean: 0x%02x" % ord(code)) - - -def _unpack_float(code, fp, options): - if code == b'\xca': - return struct.unpack(">f", _read_except(fp, 4))[0] - elif code == b'\xcb': - return struct.unpack(">d", _read_except(fp, 8))[0] - raise Exception("logic error, not float: 0x%02x" % ord(code)) - - -def _unpack_string(code, fp, options): - if (ord(code) & 0xe0) == 0xa0: - length = ord(code) & ~0xe0 - elif code == b'\xd9': - length = struct.unpack("B", _read_except(fp, 1))[0] - elif code == b'\xda': - length = struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xdb': - length = struct.unpack(">I", _read_except(fp, 4))[0] - else: - raise Exception("logic error, not string: 0x%02x" % ord(code)) - - # Always return raw bytes in compatibility mode - global compatibility - if compatibility: - return _read_except(fp, length) - - data = _read_except(fp, length) - try: - return bytes.decode(data, 'utf-8') - except UnicodeDecodeError: - if options.get("allow_invalid_utf8"): - return InvalidString(data) - raise InvalidStringException("unpacked string is invalid utf-8") - - -def _unpack_binary(code, fp, options): - if code == b'\xc4': - length = struct.unpack("B", _read_except(fp, 1))[0] - elif code == b'\xc5': - length = struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xc6': - length = struct.unpack(">I", _read_except(fp, 4))[0] - else: - raise Exception("logic error, not binary: 0x%02x" % ord(code)) - - return _read_except(fp, length) - - -def _unpack_ext(code, fp, options): - if code == b'\xd4': - length = 1 - elif code == b'\xd5': - length = 2 - elif code == b'\xd6': - length = 4 - elif code == b'\xd7': - length = 8 - elif code == b'\xd8': - length = 16 - elif code == b'\xc7': - length = struct.unpack("B", _read_except(fp, 1))[0] - elif code == b'\xc8': - length = struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xc9': - length = struct.unpack(">I", _read_except(fp, 4))[0] - else: - raise Exception("logic error, not ext: 0x%02x" % ord(code)) - - ext = Ext(ord(_read_except(fp, 1)), _read_except(fp, length)) - - # Unpack with ext handler, if we have one - ext_handlers = options.get("ext_handlers") - if ext_handlers and ext.type in ext_handlers: - ext = ext_handlers[ext.type](ext) - - return ext - - -def _unpack_array(code, fp, options): - if (ord(code) & 0xf0) == 0x90: - length = (ord(code) & ~0xf0) - elif code == b'\xdc': - length = struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xdd': - length = struct.unpack(">I", _read_except(fp, 4))[0] - else: - raise Exception("logic error, not array: 0x%02x" % ord(code)) - - return [_unpack(fp, options) for i in xrange(length)] - - -def _deep_list_to_tuple(obj): - if isinstance(obj, list): - return tuple([_deep_list_to_tuple(e) for e in obj]) - return obj - - -def _unpack_map(code, fp, options): - if (ord(code) & 0xf0) == 0x80: - length = (ord(code) & ~0xf0) - elif code == b'\xde': - length = struct.unpack(">H", _read_except(fp, 2))[0] - elif code == b'\xdf': - length = struct.unpack(">I", _read_except(fp, 4))[0] - else: - raise Exception("logic error, not map: 0x%02x" % ord(code)) - - d = {} if not options.get('use_ordered_dict') \ - else collections.OrderedDict() - for _ in xrange(length): - # Unpack key - k = _unpack(fp, options) - - if isinstance(k, list): - # Attempt to convert list into a hashable tuple - k = _deep_list_to_tuple(k) - elif not isinstance(k, collections.Hashable): - raise UnhashableKeyException( - "encountered unhashable key: %s, %s" % (str(k), str(type(k)))) - elif k in d: - raise DuplicateKeyException( - "encountered duplicate key: %s, %s" % (str(k), str(type(k)))) - - # Unpack value - v = _unpack(fp, options) - - try: - d[k] = v - except TypeError: - raise UnhashableKeyException( - "encountered unhashable key: %s" % str(k)) - return d - - -def _unpack(fp, options): - code = _read_except(fp, 1) - return _unpack_dispatch_table[code](code, fp, options) - -######################################## - - -def _unpack2(fp, **options): - """ - Deserialize MessagePack bytes into a Python object. - - Args: - fp: a .read()-supporting file-like object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext - type to a callable that unpacks an instance of - Ext into an object - use_ordered_dict (bool): unpack maps into OrderedDict, instead of - unordered dict (default False) - allow_invalid_utf8 (bool): unpack invalid strings into instances of - InvalidString, for access to the bytes - (default False) - - Returns: - A Python object. - - Raises: - InsufficientDataException(UnpackException): - Insufficient data to unpack the serialized object. - InvalidStringException(UnpackException): - Invalid UTF-8 string encountered during unpacking. - ReservedCodeException(UnpackException): - Reserved code encountered during unpacking. - UnhashableKeyException(UnpackException): - Unhashable key encountered during map unpacking. - The serialized map cannot be deserialized into a Python dictionary. - DuplicateKeyException(UnpackException): - Duplicate key encountered during map unpacking. - - Example: - >>> f = open('test.bin', 'rb') - >>> umsgpack.unpackb(f) - {u'compact': True, u'schema': 0} - >>> - """ - return _unpack(fp, options) - - -def _unpack3(fp, **options): - """ - Deserialize MessagePack bytes into a Python object. - - Args: - fp: a .read()-supporting file-like object - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext - type to a callable that unpacks an instance of - Ext into an object - use_ordered_dict (bool): unpack maps into OrderedDict, instead of - unordered dict (default False) - allow_invalid_utf8 (bool): unpack invalid strings into instances of - InvalidString, for access to the bytes - (default False) - - Returns: - A Python object. - - Raises: - InsufficientDataException(UnpackException): - Insufficient data to unpack the serialized object. - InvalidStringException(UnpackException): - Invalid UTF-8 string encountered during unpacking. - ReservedCodeException(UnpackException): - Reserved code encountered during unpacking. - UnhashableKeyException(UnpackException): - Unhashable key encountered during map unpacking. - The serialized map cannot be deserialized into a Python dictionary. - DuplicateKeyException(UnpackException): - Duplicate key encountered during map unpacking. - - Example: - >>> f = open('test.bin', 'rb') - >>> umsgpack.unpackb(f) - {'compact': True, 'schema': 0} - >>> - """ - return _unpack(fp, options) - - -# For Python 2, expects a str object -def _unpackb2(s, **options): - """ - Deserialize MessagePack bytes into a Python object. - - Args: - s: a 'str' or 'bytearray' containing serialized MessagePack bytes - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext - type to a callable that unpacks an instance of - Ext into an object - use_ordered_dict (bool): unpack maps into OrderedDict, instead of - unordered dict (default False) - allow_invalid_utf8 (bool): unpack invalid strings into instances of - InvalidString, for access to the bytes - (default False) - - Returns: - A Python object. - - Raises: - TypeError: - Packed data type is neither 'str' nor 'bytearray'. - InsufficientDataException(UnpackException): - Insufficient data to unpack the serialized object. - InvalidStringException(UnpackException): - Invalid UTF-8 string encountered during unpacking. - ReservedCodeException(UnpackException): - Reserved code encountered during unpacking. - UnhashableKeyException(UnpackException): - Unhashable key encountered during map unpacking. - The serialized map cannot be deserialized into a Python dictionary. - DuplicateKeyException(UnpackException): - Duplicate key encountered during map unpacking. - - Example: - >>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00') - {u'compact': True, u'schema': 0} - >>> - """ - if not isinstance(s, (str, bytearray)): - raise TypeError("packed data must be type 'str' or 'bytearray'") - return _unpack(io.BytesIO(s), options) - - -# For Python 3, expects a bytes object -def _unpackb3(s, **options): - """ - Deserialize MessagePack bytes into a Python object. - - Args: - s: a 'bytes' or 'bytearray' containing serialized MessagePack bytes - - Kwargs: - ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext - type to a callable that unpacks an instance of - Ext into an object - use_ordered_dict (bool): unpack maps into OrderedDict, instead of - unordered dict (default False) - allow_invalid_utf8 (bool): unpack invalid strings into instances of - InvalidString, for access to the bytes - (default False) - - Returns: - A Python object. - - Raises: - TypeError: - Packed data type is neither 'bytes' nor 'bytearray'. - InsufficientDataException(UnpackException): - Insufficient data to unpack the serialized object. - InvalidStringException(UnpackException): - Invalid UTF-8 string encountered during unpacking. - ReservedCodeException(UnpackException): - Reserved code encountered during unpacking. - UnhashableKeyException(UnpackException): - Unhashable key encountered during map unpacking. - The serialized map cannot be deserialized into a Python dictionary. - DuplicateKeyException(UnpackException): - Duplicate key encountered during map unpacking. - - Example: - >>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00') - {'compact': True, 'schema': 0} - >>> - """ - if not isinstance(s, (bytes, bytearray)): - raise TypeError("packed data must be type 'bytes' or 'bytearray'") - return _unpack(io.BytesIO(s), options) - -############################################################################# -# Module Initialization -############################################################################# - - -def __init(): - global pack - global packb - global unpack - global unpackb - global dump - global dumps - global load - global loads - global compatibility - global _float_precision - global _unpack_dispatch_table - global xrange - - # Compatibility mode for handling strings/bytes with the old specification - compatibility = False - - # Auto-detect system float precision - if sys.float_info.mant_dig == 53: - _float_precision = "double" - else: - _float_precision = "single" - - # Map packb and unpackb to the appropriate version - if sys.version_info[0] == 3: - pack = _pack3 - packb = _packb3 - dump = _pack3 - dumps = _packb3 - unpack = _unpack3 - unpackb = _unpackb3 - load = _unpack3 - loads = _unpackb3 - xrange = range - else: - pack = _pack2 - packb = _packb2 - dump = _pack2 - dumps = _packb2 - unpack = _unpack2 - unpackb = _unpackb2 - load = _unpack2 - loads = _unpackb2 - - # Build a dispatch table for fast lookup of unpacking function - - _unpack_dispatch_table = {} - # Fix uint - for code in range(0, 0x7f + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer - # Fix map - for code in range(0x80, 0x8f + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map - # Fix array - for code in range(0x90, 0x9f + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array - # Fix str - for code in range(0xa0, 0xbf + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string - # Nil - _unpack_dispatch_table[b'\xc0'] = _unpack_nil - # Reserved - _unpack_dispatch_table[b'\xc1'] = _unpack_reserved - # Boolean - _unpack_dispatch_table[b'\xc2'] = _unpack_boolean - _unpack_dispatch_table[b'\xc3'] = _unpack_boolean - # Bin - for code in range(0xc4, 0xc6 + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary - # Ext - for code in range(0xc7, 0xc9 + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext - # Float - _unpack_dispatch_table[b'\xca'] = _unpack_float - _unpack_dispatch_table[b'\xcb'] = _unpack_float - # Uint - for code in range(0xcc, 0xcf + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer - # Int - for code in range(0xd0, 0xd3 + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer - # Fixext - for code in range(0xd4, 0xd8 + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext - # String - for code in range(0xd9, 0xdb + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string - # Array - _unpack_dispatch_table[b'\xdc'] = _unpack_array - _unpack_dispatch_table[b'\xdd'] = _unpack_array - # Map - _unpack_dispatch_table[b'\xde'] = _unpack_map - _unpack_dispatch_table[b'\xdf'] = _unpack_map - # Negative fixint - for code in range(0xe0, 0xff + 1): - _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer - - -__init() diff --git a/src/helper_ackPayload.py b/src/helper_ackPayload.py deleted file mode 100644 index ef99ec2a..00000000 --- a/src/helper_ackPayload.py +++ /dev/null @@ -1,40 +0,0 @@ -import hashlib -import highlevelcrypto -import random -import helper_random -from binascii import hexlify, unhexlify -from struct import pack, unpack -from addresses import encodeVarint - -# This function generates payload objects for message acknowledgements -# Several stealth levels are available depending on the privacy needs; -# a higher level means better stealth, but also higher cost (size+POW) -# - level 0: a random 32-byte sequence with a message header appended -# - level 1: a getpubkey request for a (random) dummy key hash -# - level 2: a standard message, encrypted to a random pubkey - -def genAckPayload(streamNumber=1, stealthLevel=0): - if (stealthLevel==2): # Generate privacy-enhanced payload - # Generate a dummy privkey and derive the pubkey - dummyPubKeyHex = highlevelcrypto.privToPub(hexlify(helper_random.randomBytes(32))) - # Generate a dummy message of random length - # (the smallest possible standard-formatted message is 234 bytes) - dummyMessage = helper_random.randomBytes(random.randint(234, 800)) - # Encrypt the message using standard BM encryption (ECIES) - ackdata = highlevelcrypto.encrypt(dummyMessage, dummyPubKeyHex) - acktype = 2 # message - version = 1 - - elif (stealthLevel==1): # Basic privacy payload (random getpubkey) - ackdata = helper_random.randomBytes(32) - acktype = 0 # getpubkey - version = 4 - - else: # Minimum viable payload (non stealth) - ackdata = helper_random.randomBytes(32) - acktype = 2 # message - version = 1 - - ackobject = pack('>I', acktype) + encodeVarint(version) + encodeVarint(streamNumber) + ackdata - - return ackobject diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 0ba86348..edeeb984 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -1,110 +1,54 @@ +import shared import socket import defaultKnownNodes import pickle import time -from bmconfigparser import BMConfigParser -from debug import logger -import knownnodes -import socks -import state - - -def addKnownNode(stream, peer, lastseen=None, self=False): - if lastseen is None: - lastseen = time.time() - knownnodes.knownNodes[stream][peer] = { - "lastseen": lastseen, - "rating": 0, - "self": self, - } - - def knownNodes(): try: - with open(state.appdata + 'knownnodes.dat', 'rb') as pickleFile: - with knownnodes.knownNodesLock: - knownnodes.knownNodes = pickle.load(pickleFile) - # the old format was {Peer:lastseen, ...} - # the new format is {Peer:{"lastseen":i, "rating":f}} - for stream in knownnodes.knownNodes.keys(): - for node, params in knownnodes.knownNodes[stream].items(): - if isinstance(params, (float, int)): - addKnownNode(stream, node, params) + # We shouldn't have to use the shared.knownNodesLock because this had + # better be the only thread accessing knownNodes right now. + pickleFile = open(shared.appdata + 'knownnodes.dat', 'rb') + loadedKnownNodes = pickle.load(pickleFile) + pickleFile.close() + # The old format of storing knownNodes was as a 'host: (port, time)' + # mapping. The new format is as 'Peer: time' pairs. If we loaded + # data in the old format, transform it to the new style. + for stream, nodes in loadedKnownNodes.items(): + shared.knownNodes[stream] = {} + for node_tuple in nodes.items(): + try: + host, (port, time) = node_tuple + peer = shared.Peer(host, port) + except: + peer, time = node_tuple + shared.knownNodes[stream][peer] = time except: - knownnodes.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata) - # your own onion address, if setup - if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): - addKnownNode(1, state.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport')), self=True) - if BMConfigParser().getint('bitmessagesettings', 'settingsversion') > 10: - logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.') + shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) + if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: + print 'Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.' raise SystemExit - def dns(): # DNS bootstrap. This could be programmed to use the SOCKS proxy to do the # DNS lookup some day but for now we will just rely on the entries in # defaultKnownNodes.py. Hopefully either they are up to date or the user # has run Bitmessage recently without SOCKS turned on and received good # bootstrap nodes using that method. - def try_add_known_node(stream, addr, port, method=''): - try: - socket.inet_aton(addr) - except (TypeError, socket.error): - return - logger.info( - 'Adding %s to knownNodes based on %s DNS bootstrap method', - addr, method) - addKnownNode(stream, state.Peer(addr, port)) - - proxy_type = BMConfigParser().get('bitmessagesettings', 'socksproxytype') - - if proxy_type == 'none': - for port in [8080, 8444]: + with shared.printLock: + if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': try: - for item in socket.getaddrinfo( - 'bootstrap%s.bitmessage.org' % port, 80): - try_add_known_node(1, item[4][0], port) + for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): + print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' + shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) except: - logger.error( - 'bootstrap%s.bitmessage.org DNS bootstrapping failed.', - port, exc_info=True - ) - elif proxy_type == 'SOCKS5': - addKnownNode(1, state.Peer('quzwelsuziwqgpt2.onion', 8444)) - logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") - for port in [8080, 8444]: - logger.debug("Resolving %i through SOCKS...", port) - address_family = socket.AF_INET - sock = socks.socksocket(address_family, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.settimeout(20) - proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = BMConfigParser().get( - 'bitmessagesettings', 'sockshostname') - socksport = BMConfigParser().getint( - 'bitmessagesettings', 'socksport') - rdns = True # Do domain name lookups through the proxy; though this setting doesn't really matter since we won't be doing any domain name lookups anyway. - if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = BMConfigParser().get( - 'bitmessagesettings', 'socksusername') - sockspassword = BMConfigParser().get( - 'bitmessagesettings', 'sockspassword') - sock.setproxy( - proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) - else: - sock.setproxy( - proxytype, sockshostname, socksport, rdns) + print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.' try: - ip = sock.resolve("bootstrap" + str(port) + ".bitmessage.org") - sock.shutdown(socket.SHUT_RDWR) - sock.close() + for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): + print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' + shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) except: - logger.error("SOCKS DNS resolving failed", exc_info=True) - else: - try_add_known_node(1, ip, port, 'SOCKS') - else: - logger.info( - 'DNS bootstrap skipped because the proxy type does not support' - ' DNS resolution.' - ) + print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.' + else: + print 'DNS bootstrap skipped because SOCKS is used.' + diff --git a/src/helper_generic.py b/src/helper_generic.py index 588ae8f1..f3380b26 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -1,87 +1,36 @@ -import os -import socket -import sys -from binascii import hexlify, unhexlify -from multiprocessing import current_process -from threading import current_thread, enumerate -import traceback - import shared -from debug import logger -import queues -import shutdown - -def powQueueSize(): - curWorkerQueue = queues.workerQueue.qsize() - for thread in enumerate(): - try: - if thread.name == "singleWorker": - curWorkerQueue += thread.busy - except: - pass - return curWorkerQueue +import sys def convertIntToString(n): a = __builtins__.hex(n) if a[-1:] == 'L': a = a[:-1] if (len(a) % 2) == 0: - return unhexlify(a[2:]) + return a[2:].decode('hex') else: - return unhexlify('0' + a[2:]) + return ('0' + a[2:]).decode('hex') + def convertStringToInt(s): - return int(hexlify(s), 16) + return int(s.encode('hex'), 16) -def allThreadTraceback(frame): - id2name = dict([(th.ident, th.name) for th in enumerate()]) - code = [] - for threadId, stack in sys._current_frames().items(): - code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), threadId)) - for filename, lineno, name, line in traceback.extract_stack(stack): - code.append('File: "%s", line %d, in %s' % (filename, lineno, name)) - if line: - code.append(" %s" % (line.strip())) - print "\n".join(code) def signal_handler(signal, frame): - logger.error("Got signal %i in %s/%s", signal, current_process().name, current_thread().name) - if current_process().name == "RegExParser": - # on Windows this isn't triggered, but it's fine, it has its own process termination thing - raise SystemExit - if "PoolWorker" in current_process().name: - raise SystemExit - if current_thread().name not in ("PyBitmessage", "MainThread"): - return - logger.error("Got signal %i", signal) - if shared.thisapp.daemon: - shutdown.doCleanShutdown() + if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + shared.doCleanShutdown() + sys.exit(0) else: - allThreadTraceback(frame) print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' def isHostInPrivateIPRange(host): - if ":" in host: #IPv6 - hostAddr = socket.inet_pton(socket.AF_INET6, host) - if hostAddr == ('\x00' * 15) + '\x01': - return False - if hostAddr[0] == '\xFE' and (ord(hostAddr[1]) & 0xc0) == 0x80: - return False - if (ord(hostAddr[0]) & 0xfe) == 0xfc: - return False - pass - elif ".onion" not in host: - if host[:3] == '10.': - return True - if host[:4] == '172.': - if host[6] == '.': - if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: - return True - if host[:8] == '192.168.': - return True - # Multicast - if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.': - return True + if host[:3] == '10.': + return True + if host[:4] == '172.': + if host[6] == '.': + if int(host[4:6]) >= 16 and int(host[4:6]) <= 31: + return True + if host[:8] == '192.168.': + return True return False def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): diff --git a/src/helper_inbox.py b/src/helper_inbox.py index 3506150a..09c7edbc 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -1,16 +1,15 @@ from helper_sql import * -import queues +import shared def insert(t): sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) - #shouldn't emit changedInboxUnread and displayNewInboxMessage at the same time - #queues.UISignalQueue.put(('changedInboxUnread', None)) + shared.UISignalQueue.put(('changedInboxUnread', None)) def trash(msgid): sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) - queues.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) + shared.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) def isMessageAlreadyInInbox(sigHash): queryReturn = sqlQuery( '''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash) - return queryReturn[0][0] != 0 + return queryReturn[0][0] != 0 \ No newline at end of file diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py deleted file mode 100644 index f8bc95a6..00000000 --- a/src/helper_msgcoding.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/python2.7 - -try: - import msgpack -except ImportError: - try: - import umsgpack as msgpack - except ImportError: - import fallback.umsgpack.umsgpack as msgpack -import string -import zlib - -from bmconfigparser import BMConfigParser -from debug import logger -import messagetypes -from tr import _translate - -BITMESSAGE_ENCODING_IGNORE = 0 -BITMESSAGE_ENCODING_TRIVIAL = 1 -BITMESSAGE_ENCODING_SIMPLE = 2 -BITMESSAGE_ENCODING_EXTENDED = 3 - - -class MsgEncodeException(Exception): - pass - - -class MsgDecodeException(Exception): - pass - - -class DecompressionSizeException(MsgDecodeException): - def __init__(self, size): - self.size = size - - -class MsgEncode(object): - def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): - self.data = None - self.encoding = encoding - self.length = 0 - if self.encoding == BITMESSAGE_ENCODING_EXTENDED: - self.encodeExtended(message) - elif self.encoding == BITMESSAGE_ENCODING_SIMPLE: - self.encodeSimple(message) - elif self.encoding == BITMESSAGE_ENCODING_TRIVIAL: - self.encodeTrivial(message) - else: - raise MsgEncodeException("Unknown encoding %i" % (encoding)) - - def encodeExtended(self, message): - try: - msgObj = messagetypes.message.Message() - self.data = zlib.compress(msgpack.dumps(msgObj.encode(message)), 9) - except zlib.error: - logger.error("Error compressing message") - raise MsgEncodeException("Error compressing message") - except msgpack.exceptions.PackException: - logger.error("Error msgpacking message") - raise MsgEncodeException("Error msgpacking message") - self.length = len(self.data) - - def encodeSimple(self, message): - self.data = 'Subject:' + message['subject'] + '\n' + 'Body:' + message['body'] - self.length = len(self.data) - - def encodeTrivial(self, message): - self.data = message['body'] - self.length = len(self.data) - - -class MsgDecode(object): - def __init__(self, encoding, data): - self.encoding = encoding - if self.encoding == BITMESSAGE_ENCODING_EXTENDED: - self.decodeExtended(data) - elif self.encoding in [BITMESSAGE_ENCODING_SIMPLE, BITMESSAGE_ENCODING_TRIVIAL]: - self.decodeSimple(data) - else: - self.body = _translate("MsgDecode", "The message has an unknown encoding.\nPerhaps you should upgrade Bitmessage.") - self.subject = _translate("MsgDecode", "Unknown encoding") - - def decodeExtended(self, data): - dc = zlib.decompressobj() - tmp = "" - while len(tmp) <= BMConfigParser().safeGetInt("zlib", "maxsize"): - try: - got = dc.decompress(data, BMConfigParser().safeGetInt("zlib", "maxsize") + 1 - len(tmp)) - # EOF - if got == "": - break - tmp += got - data = dc.unconsumed_tail - except zlib.error: - logger.error("Error decompressing message") - raise MsgDecodeException("Error decompressing message") - else: - raise DecompressionSizeException(len(tmp)) - - try: - tmp = msgpack.loads(tmp) - except (msgpack.exceptions.UnpackException, - msgpack.exceptions.ExtraData): - logger.error("Error msgunpacking message") - raise MsgDecodeException("Error msgunpacking message") - - try: - msgType = tmp[""] - except KeyError: - logger.error("Message type missing") - raise MsgDecodeException("Message type missing") - - msgObj = messagetypes.constructObject(tmp) - if msgObj is None: - raise MsgDecodeException("Malformed message") - try: - msgObj.process() - except: - raise MsgDecodeException("Malformed message") - if msgType == "message": - self.subject = msgObj.subject - self.body = msgObj.body - - def decodeSimple(self, data): - bodyPositionIndex = string.find(data, '\nBody:') - if bodyPositionIndex > 1: - subject = data[8:bodyPositionIndex] - # Only save and show the first 500 characters of the subject. - # Any more is probably an attack. - subject = subject[:500] - body = data[bodyPositionIndex + 6:] - else: - subject = '' - body = data - # Throw away any extra lines (headers) after the subject. - if subject: - subject = subject.splitlines()[0] - self.subject = subject - self.body = body - -if __name__ == '__main__': - import random - messageData = { - "subject": ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(40)), - "body": ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10000)) - } - obj1 = MsgEncode(messageData, 1) - obj2 = MsgEncode(messageData, 2) - obj3 = MsgEncode(messageData, 3) - print "1:%i 2:%i 3:%i" %(len(obj1.data), len(obj2.data), len(obj3.data)) - - obj1e = MsgDecode(1, obj1.data) - # no subject in trivial encoding - assert messageData["body"] == obj1e.body - obj2e = MsgDecode(2, obj2.data) - assert messageData["subject"] == obj2e.subject - assert messageData["body"] == obj2e.body - obj3e = MsgDecode(3, obj3.data) - assert messageData["subject"] == obj3e.subject - assert messageData["body"] == obj3e.body diff --git a/src/helper_random.py b/src/helper_random.py deleted file mode 100644 index a0fb08f1..00000000 --- a/src/helper_random.py +++ /dev/null @@ -1,9 +0,0 @@ -import os - -from pyelliptic.openssl import OpenSSL - -def randomBytes(n): - try: - return os.urandom(n) - except NotImplementedError: - return OpenSSL.rand(n) diff --git a/src/helper_search.py b/src/helper_search.py deleted file mode 100644 index 2217974f..00000000 --- a/src/helper_search.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python2.7 - -from helper_sql import * - -try: - from PyQt4 import QtCore, QtGui - haveQt = True -except: - haveQt = False - -def search_translate (context, text): - if haveQt: - return QtGui.QApplication.translate(context, text) - else: - return text.lower() - -def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = None, what = None, unreadOnly = False): - if what is not None and what != "": - what = "%" + what + "%" - if where == search_translate("MainWindow", "To"): - where = "toaddress" - elif where == search_translate("MainWindow", "From"): - where = "fromaddress" - elif where == search_translate("MainWindow", "Subject"): - where = "subject" - elif where == search_translate("MainWindow", "Message"): - where = "message" - else: - where = "toaddress || fromaddress || subject || message" - else: - what = None - - if folder == "sent": - sqlStatementBase = ''' - SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime - FROM sent ''' - else: - sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox ''' - - sqlStatementParts = [] - sqlArguments = [] - if account is not None: - if xAddress == 'both': - sqlStatementParts.append("(fromaddress = ? OR toaddress = ?)") - sqlArguments.append(account) - sqlArguments.append(account) - else: - sqlStatementParts.append(xAddress + " = ? ") - sqlArguments.append(account) - if folder is not None: - if folder == "new": - folder = "inbox" - unreadOnly = True - sqlStatementParts.append("folder = ? ") - sqlArguments.append(folder) - else: - sqlStatementParts.append("folder != ?") - sqlArguments.append("trash") - if what is not None: - sqlStatementParts.append("%s LIKE ?" % (where)) - sqlArguments.append(what) - if unreadOnly: - sqlStatementParts.append("read = 0") - if len(sqlStatementParts) > 0: - sqlStatementBase += "WHERE " + " AND ".join(sqlStatementParts) - if folder == "sent": - sqlStatementBase += " ORDER BY lastactiontime" - return sqlQuery(sqlStatementBase, sqlArguments) - -def check_match(toAddress, fromAddress, subject, message, where = None, what = None): - if what is not None and what != "": - if where in (search_translate("MainWindow", "To"), search_translate("MainWindow", "All")): - if what.lower() not in toAddress.lower(): - return False - elif where in (search_translate("MainWindow", "From"), search_translate("MainWindow", "All")): - if what.lower() not in fromAddress.lower(): - return False - elif where in (search_translate("MainWindow", "Subject"), search_translate("MainWindow", "All")): - if what.lower() not in subject.lower(): - return False - elif where in (search_translate("MainWindow", "Message"), search_translate("MainWindow", "All")): - if what.lower() not in message.lower(): - return False - return True diff --git a/src/helper_sql.py b/src/helper_sql.py index fec67bef..0353f9ae 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -11,47 +11,14 @@ def sqlQuery(sqlStatement, *args): if args == (): sqlSubmitQueue.put('') - elif type(args[0]) in [list, tuple]: - sqlSubmitQueue.put(args[0]) else: sqlSubmitQueue.put(args) - queryreturn, rowcount = sqlReturnQueue.get() + queryreturn = sqlReturnQueue.get() sqlLock.release() return queryreturn - -def sqlExecuteChunked(sqlStatement, idCount, *args): - # SQLITE_MAX_VARIABLE_NUMBER, - # unfortunately getting/setting isn't exposed to python - sqlExecuteChunked.chunkSize = 999 - - if idCount == 0 or idCount > len(args): - return 0 - - totalRowCount = 0 - with sqlLock: - for i in range( - len(args) - idCount, len(args), - sqlExecuteChunked.chunkSize - (len(args) - idCount) - ): - chunk_slice = args[ - i:i+sqlExecuteChunked.chunkSize - (len(args) - idCount) - ] - sqlSubmitQueue.put( - sqlStatement.format(','.join('?' * len(chunk_slice))) - ) - # first static args, and then iterative chunk - sqlSubmitQueue.put( - args[0:len(args)-idCount] + chunk_slice - ) - retVal = sqlReturnQueue.get() - totalRowCount += retVal[1] - sqlSubmitQueue.put('commit') - return totalRowCount - - def sqlExecute(sqlStatement, *args): sqlLock.acquire() sqlSubmitQueue.put(sqlStatement) @@ -61,10 +28,9 @@ def sqlExecute(sqlStatement, *args): else: sqlSubmitQueue.put(args) - queryreturn, rowcount = sqlReturnQueue.get() + sqlReturnQueue.get() sqlSubmitQueue.put('commit') sqlLock.release() - return rowcount def sqlStoredProcedure(procName): sqlLock.acquire() diff --git a/src/helper_startup.py b/src/helper_startup.py index 6402ee89..778fe70a 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,6 +1,5 @@ +import shared import ConfigParser -from bmconfigparser import BMConfigParser -import defaults import sys import os import locale @@ -10,48 +9,46 @@ import platform from distutils.version import StrictVersion from namecoin import ensureNamecoinOptions -import paths -import state storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-select Portable Mode in the settings if they want the config files to stay in the application data folder. def _loadTrustedPeer(): try: - trustedPeer = BMConfigParser().get('bitmessagesettings', 'trustedpeer') + trustedPeer = shared.config.get('bitmessagesettings', 'trustedpeer') except ConfigParser.Error: # This probably means the trusted peer wasn't specified so we # can just leave it as None return host, port = trustedPeer.split(':') - state.trustedPeer = state.Peer(host, int(port)) + shared.trustedPeer = shared.Peer(host, int(port)) def loadConfig(): - if state.appdata: - BMConfigParser().read(state.appdata + 'keys.dat') - #state.appdata must have been specified as a startup option. + if shared.appdata: + shared.config.read(shared.appdata + 'keys.dat') + #shared.appdata must have been specified as a startup option. try: - BMConfigParser().get('bitmessagesettings', 'settingsversion') - print 'Loading config files from directory specified on startup: ' + state.appdata + shared.config.get('bitmessagesettings', 'settingsversion') + print 'Loading config files from directory specified on startup: ' + shared.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True else: - BMConfigParser().read(paths.lookupExeFolder() + 'keys.dat') + shared.config.read('keys.dat') try: - BMConfigParser().get('bitmessagesettings', 'settingsversion') + shared.config.get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False - state.appdata = paths.lookupExeFolder() + shared.appdata = '' except: # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. - state.appdata = paths.lookupAppdataFolder() - BMConfigParser().read(state.appdata + 'keys.dat') + shared.appdata = shared.lookupAppdataFolder() + shared.config.read(shared.appdata + 'keys.dat') try: - BMConfigParser().get('bitmessagesettings', 'settingsversion') - print 'Loading existing config files from', state.appdata + shared.config.get('bitmessagesettings', 'settingsversion') + print 'Loading existing config files from', shared.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True @@ -59,63 +56,62 @@ def loadConfig(): if needToCreateKeysFile: # This appears to be the first time running the program; there is # no config file (or it cannot be accessed). Create config file. - BMConfigParser().add_section('bitmessagesettings') - BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') - BMConfigParser().set('bitmessagesettings', 'port', '8444') - BMConfigParser().set( - 'bitmessagesettings', 'timeformat', '%%c') - BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') - BMConfigParser().set('bitmessagesettings', 'startonlogon', 'false') + shared.config.add_section('bitmessagesettings') + shared.config.set('bitmessagesettings', 'settingsversion', '10') + shared.config.set('bitmessagesettings', 'port', '8444') + shared.config.set( + 'bitmessagesettings', 'timeformat', '%%a, %%d %%b %%Y %%I:%%M %%p') + shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') + shared.config.set('bitmessagesettings', 'startonlogon', 'false') if 'linux' in sys.platform: - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'minimizetotray', 'false') # This isn't implimented yet and when True on # Ubuntu causes Bitmessage to disappear while # running when minimized. else: - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'minimizetotray', 'true') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'showtraynotifications', 'true') - BMConfigParser().set('bitmessagesettings', 'startintray', 'false') - BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') - BMConfigParser().set( + shared.config.set('bitmessagesettings', 'startintray', 'false') + shared.config.set('bitmessagesettings', 'socksproxytype', 'none') + shared.config.set( 'bitmessagesettings', 'sockshostname', 'localhost') - BMConfigParser().set('bitmessagesettings', 'socksport', '9050') - BMConfigParser().set( + shared.config.set('bitmessagesettings', 'socksport', '9050') + shared.config.set( 'bitmessagesettings', 'socksauthentication', 'false') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'sockslisten', 'false') - BMConfigParser().set('bitmessagesettings', 'socksusername', '') - BMConfigParser().set('bitmessagesettings', 'sockspassword', '') - BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false') - BMConfigParser().set( + shared.config.set('bitmessagesettings', 'socksusername', '') + shared.config.set('bitmessagesettings', 'sockspassword', '') + shared.config.set('bitmessagesettings', 'keysencrypted', 'false') + shared.config.set( 'bitmessagesettings', 'messagesencrypted', 'false') - BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - defaults.networkDefaultPayloadLengthExtraBytes)) - BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') - BMConfigParser().set( + shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + shared.networkDefaultPayloadLengthExtraBytes)) + shared.config.set('bitmessagesettings', 'minimizeonclose', 'false') + shared.config.set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') - BMConfigParser().set('bitmessagesettings', 'dontconnect', 'true') - BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') - BMConfigParser().set('bitmessagesettings', 'useidenticons', 'True') - BMConfigParser().set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons - BMConfigParser().set('bitmessagesettings', 'replybelow', 'False') - BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') - BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') - BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', '8') - BMConfigParser().set('bitmessagesettings', 'ttl', '367200') + shared.config.set('bitmessagesettings', 'dontconnect', 'true') + shared.config.set('bitmessagesettings', 'userlocale', 'system') + shared.config.set('bitmessagesettings', 'useidenticons', 'True') + shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons + shared.config.set('bitmessagesettings', 'replybelow', 'False') + shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') + shared.config.set('bitmessagesettings', 'maxuploadrate', '0') + shared.config.set('bitmessagesettings', 'ttl', '367200') #start:UI setting to stop trying to send messages after X days/months - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'stopresendingafterxdays', '') - BMConfigParser().set( + shared.config.set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - #BMConfigParser().set( + #shared.config.set( # 'bitmessagesettings', 'timeperiod', '-1') #end @@ -130,23 +126,24 @@ def loadConfig(): if storeConfigFilesInSameDirectoryAsProgramByDefault: # Just use the same directory as the program and forget about # the appdata folder - state.appdata = '' + shared.appdata = '' print 'Creating new config files in same directory as program.' else: - print 'Creating new config files in', state.appdata - if not os.path.exists(state.appdata): - os.makedirs(state.appdata) + print 'Creating new config files in', shared.appdata + if not os.path.exists(shared.appdata): + os.makedirs(shared.appdata) if not sys.platform.startswith('win'): os.umask(0o077) - BMConfigParser().save() + shared.writeKeysFile() _loadTrustedPeer() def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): try: + VER_THIS=StrictVersion(platform.version()) if sys.platform[0:3]=="win": - VER_THIS=StrictVersion(platform.version()) return StrictVersion("5.1.2600")<=VER_THIS and StrictVersion("6.0.6000")>=VER_THIS return False except Exception as err: + print "Info: we could not tell whether your OS is limited to having very view half open connections because we couldn't interpret the platform version. Don't worry; we'll assume that it is not limited. This tends to occur on Raspberry Pis. :", err return False diff --git a/src/helper_threading.py b/src/helper_threading.py deleted file mode 100644 index 3b7ba378..00000000 --- a/src/helper_threading.py +++ /dev/null @@ -1,37 +0,0 @@ -from contextlib import contextmanager -import threading - -try: - import prctl - def set_thread_name(name): prctl.set_name(name) - - def _thread_name_hack(self): - set_thread_name(self.name) - threading.Thread.__bootstrap_original__(self) - - threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap - threading.Thread._Thread__bootstrap = _thread_name_hack -except ImportError: - def set_thread_name(name): threading.current_thread().name = name - -class StoppableThread(object): - def initStop(self): - self.stop = threading.Event() - self._stopped = False - - def stopThread(self): - self._stopped = True - self.stop.set() - -class BusyError(threading.ThreadError): - pass - -@contextmanager -def nonBlocking(lock): - locked = lock.acquire(False) - if not locked: - raise BusyError - try: - yield - finally: - lock.release() diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 8729ec5c..5a2ae920 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,5 +1,3 @@ -from binascii import hexlify -from bmconfigparser import BMConfigParser import pyelliptic from pyelliptic import arithmetic as a, OpenSSL def makeCryptor(privkey): @@ -20,7 +18,7 @@ def makePubCryptor(pubkey): def privToPub(privkey): private_key = a.changebase(privkey, 16, 256, minlen=32) public_key = pointMult(private_key) - return hexlify(public_key) + return public_key.encode('hex') # Encrypts message with hex public key def encrypt(msg,hexPubkey): return pyelliptic.ECC(curve='secp256k1').encrypt(msg,hexToPubkey(hexPubkey)) @@ -36,15 +34,8 @@ def sign(msg,hexPrivkey): # upgrade PyBitmessage gracefully. # https://github.com/yann2192/pyelliptic/pull/33 # More discussion: https://github.com/yann2192/pyelliptic/issues/32 - digestAlg = BMConfigParser().safeGet('bitmessagesettings', 'digestalg', 'sha1') - if digestAlg == "sha1": - # SHA1, this will eventually be deprecated - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) - elif digestAlg == "sha256": - # SHA256. Eventually this will become the default - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) - else: - raise ValueError("Unknown digest algorithm %s" % (digestAlg)) + return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_ecdsa) # SHA1 + #return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) # SHA256. We should switch to this eventually. # Verifies with hex public key def verify(msg,sig,hexPubkey): # As mentioned above, we must upgrade gracefully to use SHA256. So @@ -52,7 +43,7 @@ def verify(msg,sig,hexPubkey): # of them passes then we will be satisfied. Eventually this can # be simplified and we'll only check with SHA256. try: - sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.digest_ecdsa_sha1) # old SHA1 algorithm. + sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.EVP_ecdsa) # old SHA1 algorithm. except: sigVerifyPassed = False if sigVerifyPassed: diff --git a/src/inventory.py b/src/inventory.py deleted file mode 100644 index 598021fb..00000000 --- a/src/inventory.py +++ /dev/null @@ -1,198 +0,0 @@ -import collections -from importlib import import_module -from threading import current_thread, enumerate as threadingEnumerate, RLock -import Queue -import time -import sys - -from bmconfigparser import BMConfigParser -from helper_sql import * -from singleton import Singleton - -# TODO make this dynamic, and watch out for frozen, like with messagetypes -import storage.sqlite -import storage.filesystem - -@Singleton -class Inventory(): - def __init__(self): - #super(self.__class__, self).__init__() - self._moduleName = BMConfigParser().safeGet("inventory", "storage") - #import_module("." + self._moduleName, "storage") - #import_module("storage." + self._moduleName) - self._className = "storage." + self._moduleName + "." + self._moduleName.title() + "Inventory" - self._inventoryClass = eval(self._className) - self._realInventory = self._inventoryClass() - self.numberOfInventoryLookupsPerformed = 0 - - # cheap inheritance copied from asyncore - def __getattr__(self, attr): - try: - if attr == "__contains__": - self.numberOfInventoryLookupsPerformed += 1 - realRet = getattr(self._realInventory, attr) - except AttributeError: - raise AttributeError("%s instance has no attribute '%s'" %(self.__class__.__name__, attr)) - else: - return realRet - - -class PendingDownloadQueue(Queue.Queue): -# keep a track of objects that have been advertised to us but we haven't downloaded them yet - maxWait = 300 - - def __init__(self, maxsize=0): - Queue.Queue.__init__(self, maxsize) - self.stopped = False - self.pending = {} - self.lock = RLock() - - def task_done(self, hashId): - Queue.Queue.task_done(self) - try: - with self.lock: - del self.pending[hashId] - except KeyError: - pass - - def get(self, block=True, timeout=None): - retval = Queue.Queue.get(self, block, timeout) - # no exception was raised - if not self.stopped: - with self.lock: - self.pending[retval] = time.time() - return retval - - def clear(self): - with self.lock: - newPending = {} - for hashId in self.pending: - if self.pending[hashId] + PendingDownloadQueue.maxWait > time.time(): - newPending[hashId] = self.pending[hashId] - self.pending = newPending - - @staticmethod - def totalSize(): - size = 0 - for thread in threadingEnumerate(): - if thread.isAlive() and hasattr(thread, 'downloadQueue'): - size += thread.downloadQueue.qsize() + len(thread.downloadQueue.pending) - return size - - @staticmethod - def stop(): - for thread in threadingEnumerate(): - if thread.isAlive() and hasattr(thread, 'downloadQueue'): - thread.downloadQueue.stopped = True - with thread.downloadQueue.lock: - thread.downloadQueue.pending = {} - - -class PendingUploadDeadlineException(Exception): - pass - - -@Singleton -class PendingUpload(object): -# keep a track of objects that we have created but haven't distributed yet - def __init__(self): - super(self.__class__, self).__init__() - self.lock = RLock() - self.hashes = {} - # end by this time in any case - self.deadline = 0 - self.maxLen = 0 - # during shutdown, wait up to 20 seconds to finish uploading - self.shutdownWait = 20 - # forget tracking objects after 60 seconds - self.objectWait = 60 - # wait 10 seconds between clears - self.clearDelay = 10 - self.lastCleared = time.time() - - def add(self, objectHash = None): - with self.lock: - # add a new object into existing thread lists - if objectHash: - if objectHash not in self.hashes: - self.hashes[objectHash] = {'created': time.time(), 'sendCount': 0, 'peers': []} - for thread in threadingEnumerate(): - if thread.isAlive() and hasattr(thread, 'peer') and \ - thread.peer not in self.hashes[objectHash]['peers']: - self.hashes[objectHash]['peers'].append(thread.peer) - # add all objects into the current thread - else: - for objectHash in self.hashes: - if current_thread().peer not in self.hashes[objectHash]['peers']: - self.hashes[objectHash]['peers'].append(current_thread().peer) - - def len(self): - self.clearHashes() - with self.lock: - return sum(1 - for x in self.hashes if (self.hashes[x]['created'] + self.objectWait < time.time() or - self.hashes[x]['sendCount'] == 0)) - - def _progress(self): - with self.lock: - return float(sum(len(self.hashes[x]['peers']) - for x in self.hashes if (self.hashes[x]['created'] + self.objectWait < time.time()) or - self.hashes[x]['sendCount'] == 0)) - - def progress(self, raiseDeadline=True): - if self.maxLen < self._progress(): - self.maxLen = self._progress() - if self.deadline < time.time(): - if self.deadline > 0 and raiseDeadline: - raise PendingUploadDeadlineException - self.deadline = time.time() + 20 - try: - return 1.0 - self._progress() / self.maxLen - except ZeroDivisionError: - return 1.0 - - def clearHashes(self, objectHash=None): - if objectHash is None: - if self.lastCleared > time.time() - self.clearDelay: - return - objects = self.hashes.keys() - else: - objects = objectHash, - with self.lock: - for i in objects: - try: - if self.hashes[i]['sendCount'] > 0 and ( - len(self.hashes[i]['peers']) == 0 or - self.hashes[i]['created'] + self.objectWait < time.time()): - del self.hashes[i] - except KeyError: - pass - self.lastCleared = time.time() - - def delete(self, objectHash=None): - if not hasattr(current_thread(), 'peer'): - return - if objectHash is None: - return - with self.lock: - try: - if objectHash in self.hashes and current_thread().peer in self.hashes[objectHash]['peers']: - self.hashes[objectHash]['sendCount'] += 1 - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except KeyError: - pass - self.clearHashes(objectHash) - - def stop(self): - with self.lock: - self.hashes = {} - - def threadEnd(self): - with self.lock: - for objectHash in self.hashes: - try: - if current_thread().peer in self.hashes[objectHash]['peers']: - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except KeyError: - pass - self.clearHashes() diff --git a/src/knownnodes.py b/src/knownnodes.py deleted file mode 100644 index aa080128..00000000 --- a/src/knownnodes.py +++ /dev/null @@ -1,49 +0,0 @@ -import pickle -import os -import threading - -from bmconfigparser import BMConfigParser -import state - -knownNodesLock = threading.Lock() -knownNodes = {} - -knownNodesTrimAmount = 2000 - -# forget a node after rating is this low -knownNodesForgetRating = -0.5 - -def saveKnownNodes(dirName = None): - if dirName is None: - dirName = state.appdata - with knownNodesLock: - with open(os.path.join(dirName, 'knownnodes.dat'), 'wb') as output: - pickle.dump(knownNodes, output) - -def increaseRating(peer): - increaseAmount = 0.1 - maxRating = 1 - with knownNodesLock: - for stream in knownNodes.keys(): - try: - knownNodes[stream][peer]["rating"] = min(knownNodes[stream][peer]["rating"] + increaseAmount, maxRating) - except KeyError: - pass - -def decreaseRating(peer): - decreaseAmount = 0.1 - minRating = -1 - with knownNodesLock: - for stream in knownNodes.keys(): - try: - knownNodes[stream][peer]["rating"] = max(knownNodes[stream][peer]["rating"] - decreaseAmount, minRating) - except KeyError: - pass - -def trimKnownNodes(recAddrStream = 1): - if len(knownNodes[recAddrStream]) < int(BMConfigParser().get("knownnodes", "maxnodes")): - return - with knownNodesLock: - oldestList = sorted(knownNodes[recAddrStream], key=lambda x: x['lastseen'])[:knownNodesTrimAmount] - for oldest in oldestList: - del knownNodes[recAddrStream][oldest] diff --git a/src/l10n.py b/src/l10n.py index b3b16341..f9c9b456 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -1,9 +1,8 @@ import logging -import os import time -from bmconfigparser import BMConfigParser +import shared #logger = logging.getLogger(__name__) @@ -17,29 +16,6 @@ DEFAULT_TIME_FORMAT = '%Y-%m-%d %H:%M:%S' encoding = DEFAULT_ENCODING language = DEFAULT_LANGUAGE -windowsLanguageMap = { - "ar": "arabic", - "cs": "czech", - "da": "danish", - "de": "german", - "en": "english", - "eo": "esperanto", - "fr": "french", - "it": "italian", - "ja": "japanese", - "nl": "dutch", - "no": "norwegian", - "pl": "polish", - "pt": "portuguese", - "ru": "russian", - "sk": "slovak", - "zh": "chinese", - "zh_CN": "chinese-simplified", - "zh_HK": "chinese-traditional", - "zh_SG": "chinese-simplified", - "zh_TW": "chinese-traditional" -} - try: import locale encoding = locale.getpreferredencoding(True) or DEFAULT_ENCODING @@ -48,8 +24,8 @@ except: logger.exception('Could not determine language or encoding') -if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): - time_format = BMConfigParser().get('bitmessagesettings', 'timeformat') +if shared.config.has_option('bitmessagesettings', 'timeformat'): + time_format = shared.config.get('bitmessagesettings', 'timeformat') #Test the format string try: time.strftime(time_format) @@ -79,11 +55,6 @@ if time_format != DEFAULT_TIME_FORMAT: time_format = DEFAULT_TIME_FORMAT encoding = DEFAULT_ENCODING -def setlocale(category, newlocale): - locale.setlocale(category, newlocale) - # it looks like some stuff isn't initialised yet when this is called the - # first time and its init gets the locale settings from the environment - os.environ["LC_ALL"] = newlocale def formatTimestamp(timestamp = None, as_unicode = True): #For some reason some timestamps are strings so we need to sanitize. @@ -112,25 +83,11 @@ def formatTimestamp(timestamp = None, as_unicode = True): def getTranslationLanguage(): userlocale = None - if BMConfigParser().has_option('bitmessagesettings', 'userlocale'): - userlocale = BMConfigParser().get('bitmessagesettings', 'userlocale') + if shared.config.has_option('bitmessagesettings', 'userlocale'): + userlocale = shared.config.get('bitmessagesettings', 'userlocale') if userlocale in [None, '', 'system']: return language return userlocale -def getWindowsLocale(posixLocale): - if posixLocale in windowsLanguageMap: - return windowsLanguageMap[posixLocale] - if "." in posixLocale: - loc = posixLocale.split(".", 1) - if loc[0] in windowsLanguageMap: - return windowsLanguageMap[loc[0]] - if "_" in posixLocale: - loc = posixLocale.split("_", 1) - if loc[0] in windowsLanguageMap: - return windowsLanguageMap[loc[0]] - if posixLocale != DEFAULT_LANGUAGE: - return getWindowsLocale(DEFAULT_LANGUAGE) - return None diff --git a/src/message_data_reader.py b/src/message_data_reader.py index a0659807..250e06a9 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -5,12 +5,10 @@ import sqlite3 from time import strftime, localtime import sys -import paths -import queues -import state -from binascii import hexlify +import shared +import string -appdata = paths.lookupAppdataFolder() +appdata = shared.lookupAppdataFolder() conn = sqlite3.connect( appdata + 'messages.dat' ) conn.text_factory = str @@ -33,7 +31,7 @@ def readSent(): output = cur.fetchall() for row in output: msgid, toaddress, toripe, fromaddress, subject, message, ackdata, lastactiontime, sleeptill, status, retrynumber, folder, encodingtype, ttl = row - print hexlify(msgid), toaddress, 'toripe:', hexlify(toripe), 'fromaddress:', fromaddress, 'ENCODING TYPE:', encodingtype, 'SUBJECT:', repr(subject), 'MESSAGE:', repr(message), 'ACKDATA:', hexlify(ackdata), lastactiontime, status, retrynumber, folder + 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 def readSubscriptions(): print 'Printing everything in subscriptions table:' @@ -52,7 +50,7 @@ def readPubkeys(): output = cur.fetchall() for row in output: address, transmitdata, time, usedpersonally = row - print 'Address:', address, '\tTime first broadcast:', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(time)),'utf-8'), '\tUsed by me personally:', usedpersonally, '\tFull pubkey message:', hexlify(transmitdata) + 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') def readInventory(): print 'Printing everything in inventory table:' @@ -62,7 +60,7 @@ def readInventory(): output = cur.fetchall() for row in output: hash, objecttype, streamnumber, payload, expirestime = row - print 'Hash:', hexlify(hash), objecttype, streamnumber, '\t', hexlify(payload), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(expirestime)),'utf-8') + 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') def takeInboxMessagesOutOfTrash(): @@ -87,7 +85,7 @@ def markAllInboxMessagesAsUnread(): cur.execute(item, parameters) output = cur.fetchall() conn.commit() - queues.UISignalQueue.put(('changedInboxUnread', None)) + shared.UISignalQueue.put(('changedInboxUnread', None)) print 'done' def vacuum(): diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py deleted file mode 100644 index 1a5223df..00000000 --- a/src/messagetypes/__init__.py +++ /dev/null @@ -1,50 +0,0 @@ -from importlib import import_module -from os import path, listdir -from string import lower - -from debug import logger -import paths - -class MsgBase(object): - def encode(self): - self.data = {"": lower(type(self).__name__)} - - -def constructObject(data): - whitelist = ["message"] - if data[""] not in whitelist: - return None - try: - m = import_module("messagetypes." + data[""]) - classBase = getattr(m, data[""].title()) - except (NameError, ImportError): - logger.error("Don't know how to handle message type: \"%s\"", data[""], exc_info=True) - return None - try: - returnObj = classBase() - returnObj.decode(data) - except KeyError as e: - logger.error("Missing mandatory key %s", e) - return None - except: - logger.error("classBase fail", exc_info=True) - return None - else: - return returnObj - -if paths.frozen is not None: - import messagetypes.message - import messagetypes.vote -else: - for mod in listdir(path.dirname(__file__)): - if mod == "__init__.py": - continue - splitted = path.splitext(mod) - if splitted[1] != ".py": - continue - try: - import_module("." + splitted[0], "messagetypes") - except ImportError: - logger.error("Error importing %s", mod, exc_info=True) - else: - logger.debug("Imported message type module %s", mod) diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py deleted file mode 100644 index ab61e375..00000000 --- a/src/messagetypes/message.py +++ /dev/null @@ -1,31 +0,0 @@ -from debug import logger -from messagetypes import MsgBase - - -class Message(MsgBase): - def __init__(self): - return - - def decode(self, data): - # UTF-8 and variable type validator - if type(data["subject"]) is str: - self.subject = unicode(data["subject"], 'utf-8', 'replace') - else: - self.subject = unicode(str(data["subject"]), 'utf-8', 'replace') - if type(data["body"]) is str: - self.body = unicode(data["body"], 'utf-8', 'replace') - else: - self.body = unicode(str(data["body"]), 'utf-8', 'replace') - - def encode(self, data): - super(Message, self).encode() - try: - self.data["subject"] = data["subject"] - self.data["body"] = data["body"] - except KeyError as e: - logger.error("Missing key %s", e.name) - return self.data - - def process(self): - logger.debug("Subject: %i bytes", len(self.subject)) - logger.debug("Body: %i bytes", len(self.body)) diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py deleted file mode 100644 index df8d267f..00000000 --- a/src/messagetypes/vote.py +++ /dev/null @@ -1,23 +0,0 @@ -from debug import logger -from messagetypes import MsgBase - -class Vote(MsgBase): - def __init__(self): - return - - def decode(self, data): - self.msgid = data["msgid"] - self.vote = data["vote"] - - def encode(self, data): - super(Vote, self).encode() - try: - self.data["msgid"] = data["msgid"] - self.data["vote"] = data["vote"] - except KeyError as e: - logger.error("Missing key %s", e.name) - return self.data - - def process(self): - logger.debug("msgid: %s", self.msgid) - logger.debug("vote: %s", self.vote) diff --git a/src/multiqueue.py b/src/multiqueue.py deleted file mode 100644 index 62b0fa87..00000000 --- a/src/multiqueue.py +++ /dev/null @@ -1,37 +0,0 @@ -from collections import deque -import Queue -import random - -class MultiQueue(Queue.Queue): - defaultQueueCount = 10 - def __init__(self, maxsize=0, count=0): - if not count: - self.queueCount = MultiQueue.defaultQueueCount - else: - self.queueCount = count - Queue.Queue.__init__(self, maxsize) - - # Initialize the queue representation - def _init(self, maxsize): - self.iter = 0 - self.queues = [] - for i in range(self.queueCount): - self.queues.append(deque()) - - def _qsize(self, len=len): - return len(self.queues[self.iter]) - - # Put a new item in the queue - def _put(self, item): - #self.queue.append(item) - self.queues[random.randrange(self.queueCount)].append((item)) - - # Get an item from the queue - def _get(self): - return self.queues[self.iter].popleft() - - def iterate(self): - self.iter = (self.iter + 1) % self.queueCount - - def totalSize(self): - return sum(len(x) for x in self.queues) diff --git a/src/namecoin.py b/src/namecoin.py index 9b3c3c3e..03cd3080 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -20,21 +20,14 @@ # SOFTWARE. import base64 -import httplib import json import socket import sys import os -from bmconfigparser import BMConfigParser -import defaults +import shared import tr # translate -# FIXME: from debug import logger crashes PyBitmessage due to a circular -# dependency. The debug module will also override/disable logging.getLogger() -# loggers so module level logging functions are used instead -import logging as logger - configSection = "bitmessagesettings" # Error thrown when the RPC call returns an error. @@ -43,9 +36,6 @@ class RPCError (Exception): def __init__ (self, data): self.error = data - - def __str__(self): - return '{0}: {1}'.format(type(self).__name__, self.error) # This class handles the Namecoin identity integration. class namecoinConnection (object): @@ -56,7 +46,6 @@ class namecoinConnection (object): nmctype = None bufsize = 4096 queryid = 1 - con = None # Initialise. If options are given, take the connection settings from # them instead of loading from the configs. This can be used to test @@ -64,22 +53,20 @@ class namecoinConnection (object): # actually changing the values (yet). def __init__ (self, options = None): if options is None: - self.nmctype = BMConfigParser().get (configSection, "namecoinrpctype") - self.host = BMConfigParser().get (configSection, "namecoinrpchost") - self.port = int(BMConfigParser().get (configSection, "namecoinrpcport")) - self.user = BMConfigParser().get (configSection, "namecoinrpcuser") - self.password = BMConfigParser().get (configSection, + self.nmctype = shared.config.get (configSection, "namecoinrpctype") + self.host = shared.config.get (configSection, "namecoinrpchost") + self.port = shared.config.get (configSection, "namecoinrpcport") + self.user = shared.config.get (configSection, "namecoinrpcuser") + self.password = shared.config.get (configSection, "namecoinrpcpassword") else: self.nmctype = options["type"] self.host = options["host"] - self.port = int(options["port"]) + self.port = options["port"] self.user = options["user"] self.password = options["password"] assert self.nmctype == "namecoind" or self.nmctype == "nmcontrol" - if self.nmctype == "namecoind": - self.con = httplib.HTTPConnection(self.host, self.port, timeout = 3) # Query for the bitmessage address corresponding to the given identity # string. If it doesn't contain a slash, id/ is prepended. We return @@ -98,45 +85,36 @@ class namecoinConnection (object): res = self.callRPC ("data", ["getValue", string]) res = res["reply"] if res == False: - return (tr._translate("MainWindow",'The name %1 was not found.').arg(unicode(string)), None) + raise RPCError ({"code": -4}) else: assert False except RPCError as exc: - logger.exception("Namecoin query RPC exception") - if isinstance(exc.error, dict): - errmsg = exc.error["message"] + if exc.error["code"] == -4: + return (tr.translateText("MainWindow",'The name %1 was not found.').arg(unicode(string)), None) else: - errmsg = exc.error - return (tr._translate("MainWindow",'The namecoin query failed (%1)').arg(unicode(errmsg)), None) + return (tr.translateText("MainWindow",'The namecoin query failed (%1)').arg(unicode(exc.error["message"])), None) except Exception as exc: - logger.exception("Namecoin query exception") - return (tr._translate("MainWindow",'The namecoin query failed.'), None) + print "Namecoin query exception: %s" % str (exc) + return (tr.translateText("MainWindow",'The namecoin query failed.'), None) try: val = json.loads (res) except: - logger.exception("Namecoin query json exception") - return (tr._translate("MainWindow",'The name %1 has no valid JSON data.').arg(unicode(string)), None) + return (tr.translateText("MainWindow",'The name %1 has no valid JSON data.').arg(unicode(string)), None) if "bitmessage" in val: - if "name" in val: - ret = "%s <%s>" % (val["name"], val["bitmessage"]) - else: - ret = val["bitmessage"] - return (None, ret) - return (tr._translate("MainWindow",'The name %1 has no associated Bitmessage address.').arg(unicode(string)), None) + return (None, val["bitmessage"]) + return (tr.translateText("MainWindow",'The name %1 has no associated Bitmessage address.').arg(unicode(string)), None) # Test the connection settings. This routine tries to query a "getinfo" # command, and builds either an error message or a success message with # some info from it. - def test(self): + def test (self): try: if self.nmctype == "namecoind": - try: - vers = self.callRPC("getinfo", [])["version"] - except RPCError: - vers = self.callRPC("getnetworkinfo", [])["version"] - + res = self.callRPC ("getinfo", []) + vers = res["version"] + v3 = vers % 100 vers = vers / 100 v2 = vers % 100 @@ -146,27 +124,23 @@ class namecoinConnection (object): versStr = "0.%d.%d" % (v1, v2) else: versStr = "0.%d.%d.%d" % (v1, v2, v3) - return ('success', tr._translate("MainWindow",'Success! Namecoind version %1 running.').arg(unicode(versStr)) ) + return ('success', tr.translateText("MainWindow",'Success! Namecoind version %1 running.').arg(unicode(versStr)) ) elif self.nmctype == "nmcontrol": res = self.callRPC ("data", ["status"]) prefix = "Plugin data running" if ("reply" in res) and res["reply"][:len(prefix)] == prefix: - return ('success', tr._translate("MainWindow",'Success! NMControll is up and running.')) + return ('success', tr.translateText("MainWindow",'Success! NMControll is up and running.')) - logger.error("Unexpected nmcontrol reply: %s", res) - return ('failed', tr._translate("MainWindow",'Couldn\'t understand NMControl.')) + print "Unexpected nmcontrol reply: %s" % res + return ('failed', tr.translateText("MainWindow",'Couldn\'t understand NMControl.')) else: assert False - except Exception: - logger.info("Namecoin connection test failure") - return ( - 'failed', - tr._translate( - "MainWindow", "The connection to namecoin failed.") - ) + except Exception as exc: + print "Namecoin connection test: %s" % str (exc) + return ('failed', "The connection to namecoin failed.") # Helper routine that actually performs an JSON RPC call. def callRPC (self, method, params): @@ -181,43 +155,35 @@ class namecoinConnection (object): if val["id"] != self.queryid: raise Exception ("ID mismatch in JSON RPC answer.") - - if self.nmctype == "namecoind": - self.queryid = self.queryid + 1 + self.queryid = self.queryid + 1 - error = val["error"] - if error is None: - return val["result"] + if val["error"] is not None: + raise RPCError (val["error"]) - if isinstance(error, bool): - raise RPCError (val["result"]) - raise RPCError (error) + return val["result"] # Query the server via HTTP. def queryHTTP (self, data): - result = None + header = "POST / HTTP/1.1\n" + header += "User-Agent: bitmessage\n" + header += "Host: %s\n" % self.host + header += "Content-Type: application/json\n" + header += "Content-Length: %d\n" % len (data) + header += "Accept: application/json\n" + authstr = "%s:%s" % (self.user, self.password) + header += "Authorization: Basic %s\n" % base64.b64encode (authstr) - try: - self.con.putrequest("POST", "/") - self.con.putheader("Connection", "Keep-Alive") - self.con.putheader("User-Agent", "bitmessage") - self.con.putheader("Host", self.host) - self.con.putheader("Content-Type", "application/json") - self.con.putheader("Content-Length", str(len(data))) - self.con.putheader("Accept", "application/json") - authstr = "%s:%s" % (self.user, self.password) - self.con.putheader("Authorization", "Basic %s" % base64.b64encode (authstr)) - self.con.endheaders() - self.con.send(data) - try: - resp = self.con.getresponse() - result = resp.read() - if resp.status != 200: - raise Exception ("Namecoin returned status %i: %s", resp.status, resp.reason) - except: - logger.info("HTTP receive error") - except: - logger.info("HTTP connection error") + resp = self.queryServer ("%s\n%s" % (header, data)) + lines = resp.split ("\r\n") + result = None + body = False + for line in lines: + if line == "" and not body: + body = True + elif body: + if result is not None: + raise Exception ("Expected a single line in HTTP response.") + result = line return result @@ -227,7 +193,7 @@ class namecoinConnection (object): s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.settimeout(3) - s.connect ((self.host, self.port)) + s.connect ((self.host, int (self.port))) s.sendall (data) result = "" @@ -268,21 +234,21 @@ def lookupNamecoinFolder (): # Ensure all namecoin options are set, by setting those to default values # that aren't there. def ensureNamecoinOptions (): - if not BMConfigParser().has_option (configSection, "namecoinrpctype"): - BMConfigParser().set (configSection, "namecoinrpctype", "namecoind") - if not BMConfigParser().has_option (configSection, "namecoinrpchost"): - BMConfigParser().set (configSection, "namecoinrpchost", "localhost") + if not shared.config.has_option (configSection, "namecoinrpctype"): + shared.config.set (configSection, "namecoinrpctype", "namecoind") + if not shared.config.has_option (configSection, "namecoinrpchost"): + shared.config.set (configSection, "namecoinrpchost", "localhost") - hasUser = BMConfigParser().has_option (configSection, "namecoinrpcuser") - hasPass = BMConfigParser().has_option (configSection, "namecoinrpcpassword") - hasPort = BMConfigParser().has_option (configSection, "namecoinrpcport") + hasUser = shared.config.has_option (configSection, "namecoinrpcuser") + hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") + hasPort = shared.config.has_option (configSection, "namecoinrpcport") # Try to read user/password from .namecoin configuration file. defaultUser = "" defaultPass = "" - nmcFolder = lookupNamecoinFolder () - nmcConfig = nmcFolder + "namecoin.conf" try: + nmcFolder = lookupNamecoinFolder () + nmcConfig = nmcFolder + "namecoin.conf" nmc = open (nmcConfig, "r") while True: @@ -299,21 +265,20 @@ def ensureNamecoinOptions (): if key == "rpcpassword" and not hasPass: defaultPass = val if key == "rpcport": - defaults.namecoinDefaultRpcPort = val + shared.namecoinDefaultRpcPort = val nmc.close () - except IOError: - logger.error("%s unreadable or missing, Namecoin support deactivated", nmcConfig) + except Exception as exc: - logger.warning("Error processing namecoin.conf", exc_info=True) + print "Could not read the Namecoin config file probably because you don't have Namecoin installed. That's ok; we don't really need it. Detailed error message: %s" % str (exc) # If still nothing found, set empty at least. if (not hasUser): - BMConfigParser().set (configSection, "namecoinrpcuser", defaultUser) + shared.config.set (configSection, "namecoinrpcuser", defaultUser) if (not hasPass): - BMConfigParser().set (configSection, "namecoinrpcpassword", defaultPass) + shared.config.set (configSection, "namecoinrpcpassword", defaultPass) # Set default port now, possibly to found value. if (not hasPort): - BMConfigParser().set (configSection, "namecoinrpcport", - defaults.namecoinDefaultRpcPort) + shared.config.set (configSection, "namecoinrpcport", + shared.namecoinDefaultRpcPort) diff --git a/src/network/__init__.py b/src/network/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/network/addrthread.py b/src/network/addrthread.py deleted file mode 100644 index 5b0ea638..00000000 --- a/src/network/addrthread.py +++ /dev/null @@ -1,36 +0,0 @@ -import Queue -import threading - -import addresses -from helper_threading import StoppableThread -from network.connectionpool import BMConnectionPool -from queues import addrQueue -import protocol -import state - -class AddrThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="AddrBroadcaster") - self.initStop() - self.name = "AddrBroadcaster" - - def run(self): - while not state.shutdown: - chunk = [] - while True: - try: - data = addrQueue.get(False) - chunk.append((data[0], data[1])) - if len(data) > 2: - source = BMConnectionPool().getConnectionByAddr(data[2]) - except Queue.Empty: - break - except KeyError: - continue - - #finish - - addrQueue.iterate() - for i in range(len(chunk)): - addrQueue.task_done() - self.stop.wait(1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py deleted file mode 100644 index 6f857398..00000000 --- a/src/network/advanceddispatcher.py +++ /dev/null @@ -1,131 +0,0 @@ -import socket -import threading -import time - -import asyncore_pollchoose as asyncore -from debug import logger -from helper_threading import BusyError, nonBlocking -import state - -class AdvancedDispatcher(asyncore.dispatcher): - _buf_len = 131072 # 128kB - - def __init__(self, sock=None): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self, sock) - self.read_buf = bytearray() - self.write_buf = bytearray() - self.state = "init" - self.lastTx = time.time() - self.sentBytes = 0 - self.receivedBytes = 0 - self.expectBytes = 0 - self.readLock = threading.RLock() - self.writeLock = threading.RLock() - self.processingLock = threading.RLock() - - def append_write_buf(self, data): - if data: - if isinstance(data, list): - with self.writeLock: - for chunk in data: - self.write_buf.extend(chunk) - else: - with self.writeLock: - self.write_buf.extend(data) - - def slice_write_buf(self, length=0): - if length > 0: - with self.writeLock: - if length >= len(self.write_buf): - del self.write_buf[:] - else: - del self.write_buf[0:length] - - def slice_read_buf(self, length=0): - if length > 0: - with self.readLock: - if length >= len(self.read_buf): - del self.read_buf[:] - else: - del self.read_buf[0:length] - - def process(self): - while self.connected and not state.shutdown: - try: - with nonBlocking(self.processingLock): - if not self.connected or state.shutdown: - break - if len(self.read_buf) < self.expectBytes: - return False - if not getattr(self, "state_" + str(self.state))(): - break - except AttributeError: - logger.error("Unknown state %s", self.state, exc_info=True) - raise - except BusyError: - return False - return False - - def set_state(self, state, length=0, expectBytes=0): - self.expectBytes = expectBytes - self.slice_read_buf(length) - self.state = state - - def writable(self): - self.uploadChunk = AdvancedDispatcher._buf_len - if asyncore.maxUploadRate > 0: - self.uploadChunk = int(asyncore.uploadBucket) - self.uploadChunk = min(self.uploadChunk, len(self.write_buf)) - return asyncore.dispatcher.writable(self) and \ - (self.connecting or (self.connected and self.uploadChunk > 0)) - - def readable(self): - self.downloadChunk = AdvancedDispatcher._buf_len - if asyncore.maxDownloadRate > 0: - self.downloadChunk = int(asyncore.downloadBucket) - try: - if self.expectBytes > 0 and not self.fullyEstablished: - self.downloadChunk = min(self.downloadChunk, self.expectBytes - len(self.read_buf)) - if self.downloadChunk < 0: - self.downloadChunk = 0 - except AttributeError: - pass - return asyncore.dispatcher.readable(self) and \ - (self.connecting or self.accepting or (self.connected and self.downloadChunk > 0)) - - def handle_read(self): - self.lastTx = time.time() - newData = self.recv(self.downloadChunk) - self.receivedBytes += len(newData) - asyncore.update_received(len(newData)) - with self.readLock: - self.read_buf.extend(newData) - - def handle_write(self): - self.lastTx = time.time() - written = self.send(self.write_buf[0:self.uploadChunk]) - asyncore.update_sent(written) - self.sentBytes += written - self.slice_write_buf(written) - - def handle_connect_event(self): - try: - asyncore.dispatcher.handle_connect_event(self) - except socket.error as e: - if e.args[0] not in asyncore._DISCONNECTED: - raise - - def handle_connect(self): - self.lastTx = time.time() - - def state_close(self): - return False - - def handle_close(self): - with self.readLock: - self.read_buf = bytearray() - with self.writeLock: - self.write_buf = bytearray() - self.set_state("close") - self.close() diff --git a/src/network/announcethread.py b/src/network/announcethread.py deleted file mode 100644 index a94eeb36..00000000 --- a/src/network/announcethread.py +++ /dev/null @@ -1,35 +0,0 @@ -import threading -import time - -from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import StoppableThread -from network.bmproto import BMProto -from network.connectionpool import BMConnectionPool -from network.udp import UDPSocket -import state - -class AnnounceThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="Announcer") - self.initStop() - self.name = "Announcer" - logger.info("init announce thread") - - def run(self): - lastSelfAnnounced = 0 - while not self._stopped and state.shutdown == 0: - processed = 0 - if lastSelfAnnounced < time.time() - UDPSocket.announceInterval: - self.announceSelf() - lastSelfAnnounced = time.time() - if processed == 0: - self.stop.wait(10) - - def announceSelf(self): - for connection in BMConnectionPool().udpSockets.values(): - if not connection.announcing: - continue - for stream in state.streamsInWhichIAmParticipating: - addr = (stream, state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), time.time()) - connection.append_write_buf(BMProto.assembleAddr([addr])) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py deleted file mode 100644 index cd19063a..00000000 --- a/src/network/asyncore_pollchoose.py +++ /dev/null @@ -1,944 +0,0 @@ -# -*- Mode: Python -*- -# Id: asyncore.py,v 2.51 2000/09/07 22:29:26 rushing Exp -# Author: Sam Rushing - -# ====================================================================== -# Copyright 1996 by Sam Rushing -# -# All Rights Reserved -# -# Permission to use, copy, modify, and distribute this software and -# its documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appear in all -# copies and that both that copyright notice and this permission -# notice appear in supporting documentation, and that the name of Sam -# Rushing not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. -# -# SAM RUSHING DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN -# NO EVENT SHALL SAM RUSHING BE LIABLE FOR ANY SPECIAL, INDIRECT OR -# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS -# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, -# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN -# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -# ====================================================================== - -"""Basic infrastructure for asynchronous socket service clients and servers. - -There are only two ways to have a program on a single processor do "more -than one thing at a time". Multi-threaded programming is the simplest and -most popular way to do it, but there is another very different technique, -that lets you have nearly all the advantages of multi-threading, without -actually using multiple threads. it's really only practical if your program -is largely I/O bound. If your program is CPU bound, then pre-emptive -scheduled threads are probably what you really need. Network servers are -rarely CPU-bound, however. - -If your operating system supports the select() system call in its I/O -library (and nearly all do), then you can use it to juggle multiple -communication channels at once; doing other work while your I/O is taking -place in the "background." Although this strategy can seem strange and -complex, especially at first, it is in many ways easier to understand and -control than multi-threaded programming. The module documented here solves -many of the difficult problems for you, making the task of building -sophisticated high-performance network servers and clients a snap. -""" - -# randomise object order for bandwidth balancing -import random -import select -import socket -import sys -import time -from threading import current_thread -import warnings - -import os -from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ - ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \ - EADDRINUSE, \ - errorcode -try: - from errno import WSAEWOULDBLOCK -except (ImportError, AttributeError): - WSAEWOULDBLOCK = EWOULDBLOCK -try: - from errno import WSAENOTSOCK -except (ImportError, AttributeError): - WSAENOTSOCK = ENOTSOCK -try: - from errno import WSAECONNRESET -except (ImportError, AttributeError): - WSAECONNRESET = ECONNRESET -try: - from errno import WSAEADDRINUSE -except (ImportError, AttributeError): - WSAEADDRINUSE = EADDRINUSE - -_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, - WSAECONNRESET)) - -OP_READ = 1 -OP_WRITE = 2 - -try: - socket_map -except NameError: - socket_map = {} - -def _strerror(err): - try: - return os.strerror(err) - except (ValueError, OverflowError, NameError): - if err in errorcode: - return errorcode[err] - return "Unknown error %s" %err - -class ExitNow(Exception): - pass - -_reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit) - -maxDownloadRate = 0 -downloadTimestamp = 0 -downloadBucket = 0 -receivedBytes = 0 -maxUploadRate = 0 -uploadTimestamp = 0 -uploadBucket = 0 -sentBytes = 0 - -def read(obj): - if not can_receive(): - return - try: - obj.handle_read_event() - except _reraised_exceptions: - raise - except: - obj.handle_error() - -def write(obj): - if not can_send(): - return - try: - obj.handle_write_event() - except _reraised_exceptions: - raise - except: - obj.handle_error() - -def set_rates(download, upload): - global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp - maxDownloadRate = float(download) * 1024 - maxUploadRate = float(upload) * 1024 - downloadBucket = maxDownloadRate - uploadBucket = maxUploadRate - downloadTimestamp = time.time() - uploadTimestamp = time.time() - -def can_receive(): - return maxDownloadRate == 0 or downloadBucket > 0 - -def can_send(): - return maxUploadRate == 0 or uploadBucket > 0 - -def update_received(download=0): - global receivedBytes, downloadBucket, downloadTimestamp - currentTimestamp = time.time() - receivedBytes += download - if maxDownloadRate > 0: - bucketIncrease = maxDownloadRate * (currentTimestamp - downloadTimestamp) - downloadBucket += bucketIncrease - if downloadBucket > maxDownloadRate: - downloadBucket = int(maxDownloadRate) - downloadBucket -= download - downloadTimestamp = currentTimestamp - -def update_sent(upload=0): - global sentBytes, uploadBucket, uploadTimestamp - currentTimestamp = time.time() - sentBytes += upload - if maxUploadRate > 0: - bucketIncrease = maxUploadRate * (currentTimestamp - uploadTimestamp) - uploadBucket += bucketIncrease - if uploadBucket > maxUploadRate: - uploadBucket = int(maxUploadRate) - uploadBucket -= upload - uploadTimestamp = currentTimestamp - -def _exception(obj): - try: - obj.handle_expt_event() - except _reraised_exceptions: - raise - except: - obj.handle_error() - -def readwrite(obj, flags): - try: - if flags & select.POLLIN and can_receive(): - obj.handle_read_event() - if flags & select.POLLOUT and can_send(): - obj.handle_write_event() - if flags & select.POLLPRI: - obj.handle_expt_event() - if flags & (select.POLLHUP | select.POLLERR | select.POLLNVAL): - obj.handle_close() - except socket.error as e: - if e.args[0] not in _DISCONNECTED: - obj.handle_error() - else: - obj.handle_close() - except _reraised_exceptions: - raise - except: - obj.handle_error() - -def select_poller(timeout=0.0, map=None): - """A poller which uses select(), available on most platforms.""" - if map is None: - map = socket_map - if map: - r = []; w = []; e = [] - for fd, obj in list(map.items()): - is_r = obj.readable() - is_w = obj.writable() - if is_r: - r.append(fd) - # accepting sockets should not be writable - if is_w and not obj.accepting: - w.append(fd) - if is_r or is_w: - e.append(fd) - if [] == r == w == e: - time.sleep(timeout) - return - - try: - r, w, e = select.select(r, w, e, timeout) - except KeyboardInterrupt: - return - except socket.error as err: - if err.args[0] in (EBADF, EINTR): - return - except Exception as err: - if err.args[0] in (WSAENOTSOCK, ): - return - - for fd in random.sample(r, len(r)): - obj = map.get(fd) - if obj is None: - continue - read(obj) - - for fd in random.sample(w, len(w)): - obj = map.get(fd) - if obj is None: - continue - write(obj) - - for fd in e: - obj = map.get(fd) - if obj is None: - continue - _exception(obj) - else: - current_thread().stop.wait(timeout) - -def poll_poller(timeout=0.0, map=None): - """A poller which uses poll(), available on most UNIXen.""" - if map is None: - map = socket_map - if timeout is not None: - # timeout is in milliseconds - timeout = int(timeout*1000) - try: - poll_poller.pollster - except AttributeError: - poll_poller.pollster = select.poll() - if map: - for fd, obj in list(map.items()): - flags = newflags = 0 - if obj.readable(): - flags |= select.POLLIN | select.POLLPRI - newflags |= OP_READ - else: - newflags &= ~ OP_READ - # accepting sockets should not be writable - if obj.writable() and not obj.accepting: - flags |= select.POLLOUT - newflags |= OP_WRITE - else: - newflags &= ~ OP_WRITE - if newflags != obj.poller_flags: - obj.poller_flags = newflags - try: - if obj.poller_registered: - poll_poller.pollster.modify(fd, flags) - else: - poll_poller.pollster.register(fd, flags) - obj.poller_registered = True - except IOError: - pass - try: - r = poll_poller.pollster.poll(timeout) - except KeyboardInterrupt: - r = [] - except socket.error as err: - if err.args[0] in (EBADF, WSAENOTSOCK, EINTR): - return - for fd, flags in random.sample(r, len(r)): - obj = map.get(fd) - if obj is None: - continue - readwrite(obj, flags) - else: - current_thread().stop.wait(timeout) - -# Aliases for backward compatibility -poll = select_poller -poll2 = poll3 = poll_poller - -def epoll_poller(timeout=0.0, map=None): - """A poller which uses epoll(), supported on Linux 2.5.44 and newer.""" - if map is None: - map = socket_map - try: - epoll_poller.pollster - except AttributeError: - epoll_poller.pollster = select.epoll() - if map: - for fd, obj in map.items(): - flags = newflags = 0 - if obj.readable(): - flags |= select.POLLIN | select.POLLPRI - newflags |= OP_READ - else: - newflags &= ~ OP_READ - # accepting sockets should not be writable - if obj.writable() and not obj.accepting: - flags |= select.POLLOUT - newflags |= OP_WRITE - else: - newflags &= ~ OP_WRITE - if newflags != obj.poller_flags: - obj.poller_flags = newflags - # Only check for exceptions if object was either readable - # or writable. - flags |= select.POLLERR | select.POLLHUP | select.POLLNVAL - try: - if obj.poller_registered: - epoll_poller.pollster.modify(fd, flags) - else: - epoll_poller.pollster.register(fd, flags) - obj.poller_registered = True - except IOError: - pass - try: - r = epoll_poller.pollster.poll(timeout) - except IOError as e: - if e.errno != EINTR: - raise - r = [] - except select.error, err: - if err.args[0] != EINTR: - raise - r = [] - for fd, flags in random.sample(r, len(r)): - obj = map.get(fd) - if obj is None: - continue - readwrite(obj, flags) - else: - current_thread().stop.wait(timeout) - -def kqueue_poller(timeout=0.0, map=None): - """A poller which uses kqueue(), BSD specific.""" - if map is None: - map = socket_map - try: - kqueue_poller.pollster - except AttributeError: - kqueue_poller.pollster = select.kqueue() - if map: - updates = [] - selectables = 0 - for fd, obj in map.items(): - kq_filter = 0 - if obj.readable(): - kq_filter |= 1 - selectables += 1 - if obj.writable() and not obj.accepting: - kq_filter |= 2 - selectables += 1 - if kq_filter != obj.poller_filter: - # unlike other pollers, READ and WRITE aren't OR able but have - # to be set and checked separately - if kq_filter & 1 != obj.poller_filter & 1: - poller_flags = select.KQ_EV_ADD - if kq_filter & 1: - poller_flags |= select.KQ_EV_ENABLE - else: - poller_flags |= select.KQ_EV_DISABLE - updates.append(select.kevent(fd, filter=select.KQ_FILTER_READ, flags=poller_flags)) - if kq_filter & 2 != obj.poller_filter & 2: - poller_flags = select.KQ_EV_ADD - if kq_filter & 2: - poller_flags |= select.KQ_EV_ENABLE - else: - poller_flags |= select.KQ_EV_DISABLE - updates.append(select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=poller_flags)) - obj.poller_filter = kq_filter - - if not selectables: - # unlike other pollers, kqueue poll does not wait if there are no - # filters setup - current_thread().stop.wait(timeout) - return - - events = kqueue_poller.pollster.control(updates, selectables, timeout) - if len(events) > 1: - events = random.sample(events, len(events)) - - for event in events: - fd = event.ident - obj = map.get(fd) - if obj is None: - continue - if event.flags & select.KQ_EV_ERROR: - _exception(obj) - continue - if event.flags & select.KQ_EV_EOF and event.data and event.fflags: - obj.handle_close() - continue - if event.filter == select.KQ_FILTER_READ: - read(obj) - if event.filter == select.KQ_FILTER_WRITE: - write(obj) - else: - current_thread().stop.wait(timeout) - - -def loop(timeout=30.0, use_poll=False, map=None, count=None, - poller=None): - if map is None: - map = socket_map - if count is None: - count = True - # code which grants backward compatibility with "use_poll" - # argument which should no longer be used in favor of - # "poller" - - if poller is None: - if use_poll: - poller = poll_poller - elif hasattr(select, 'epoll'): - poller = epoll_poller - elif hasattr(select, 'kqueue'): - poller = kqueue_poller - elif hasattr(select, 'poll'): - poller = poll_poller - elif hasattr(select, 'select'): - poller = select_poller - - if timeout == 0: - deadline = 0 - else: - deadline = time.time() + timeout - while count: - # fill buckets first - update_sent() - update_received() - subtimeout = deadline - time.time() - if subtimeout <= 0: - break - # then poll - poller(subtimeout, map) - if type(count) is int: - count = count - 1 - -class dispatcher: - - debug = False - connected = False - accepting = False - connecting = False - closing = False - addr = None - ignore_log_types = frozenset(['warning']) - poller_registered = False - poller_flags = 0 - # don't do network IO with a smaller bucket than this - minTx = 1500 - - def __init__(self, sock=None, map=None): - if map is None: - self._map = socket_map - else: - self._map = map - - self._fileno = None - - if sock: - # Set to nonblocking just to make sure for cases where we - # get a socket from a blocking source. - sock.setblocking(0) - self.set_socket(sock, map) - self.connected = True - # The constructor no longer requires that the socket - # passed be connected. - try: - self.addr = sock.getpeername() - except socket.error as err: - if err.args[0] in (ENOTCONN, EINVAL): - # To handle the case where we got an unconnected - # socket. - self.connected = False - else: - # The socket is broken in some unknown way, alert - # the user and remove it from the map (to prevent - # polling of broken sockets). - self.del_channel(map) - raise - else: - self.socket = None - - def __repr__(self): - status = [self.__class__.__module__+"."+self.__class__.__name__] - if self.accepting and self.addr: - status.append('listening') - elif self.connected: - status.append('connected') - if self.addr is not None: - try: - status.append('%s:%d' % self.addr) - except TypeError: - status.append(repr(self.addr)) - return '<%s at %#x>' % (' '.join(status), id(self)) - - __str__ = __repr__ - - def add_channel(self, map=None): - #self.log_info('adding channel %s' % self) - if map is None: - map = self._map - map[self._fileno] = self - self.poller_flags = 0 - self.poller_filter = 0 - - def del_channel(self, map=None): - fd = self._fileno - if map is None: - map = self._map - if fd in map: - #self.log_info('closing channel %d:%s' % (fd, self)) - del map[fd] - if self._fileno: - try: - kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE)], 0) - except (AttributeError, KeyError, TypeError, IOError, OSError): - pass - try: - kqueue_poller.pollster.control([select.kevent(fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE)], 0) - except (AttributeError, KeyError, TypeError, IOError, OSError): - pass - try: - epoll_poller.pollster.unregister(fd) - except (AttributeError, KeyError, TypeError, IOError): - # no epoll used, or not registered - pass - try: - poll_poller.pollster.unregister(fd) - except (AttributeError, KeyError, TypeError, IOError): - # no poll used, or not registered - pass - self._fileno = None - self.poller_flags = 0 - self.poller_filter = 0 - self.poller_registered = False - - def create_socket(self, family=socket.AF_INET, socket_type=socket.SOCK_STREAM): - self.family_and_type = family, socket_type - sock = socket.socket(family, socket_type) - sock.setblocking(0) - self.set_socket(sock) - - def set_socket(self, sock, map=None): - self.socket = sock -## self.__dict__['socket'] = sock - self._fileno = sock.fileno() - self.add_channel(map) - - def set_reuse_addr(self): - # try to re-use a server port if possible - try: - self.socket.setsockopt( - socket.SOL_SOCKET, socket.SO_REUSEADDR, - self.socket.getsockopt(socket.SOL_SOCKET, - socket.SO_REUSEADDR) | 1 - ) - except socket.error: - pass - - # ================================================== - # predicates for select() - # these are used as filters for the lists of sockets - # to pass to select(). - # ================================================== - - def readable(self): - if maxDownloadRate > 0: - return downloadBucket > dispatcher.minTx - return True - - def writable(self): - if maxUploadRate > 0: - return uploadBucket > dispatcher.minTx - return True - - # ================================================== - # socket object methods. - # ================================================== - - def listen(self, num): - self.accepting = True - if os.name == 'nt' and num > 5: - num = 5 - return self.socket.listen(num) - - def bind(self, addr): - self.addr = addr - return self.socket.bind(addr) - - def connect(self, address): - self.connected = False - self.connecting = True - err = self.socket.connect_ex(address) - if err in (EINPROGRESS, EALREADY, EWOULDBLOCK, WSAEWOULDBLOCK) \ - or err == EINVAL and os.name in ('nt', 'ce'): - self.addr = address - return - if err in (0, EISCONN): - self.addr = address - self.handle_connect_event() - else: - raise socket.error(err, errorcode[err]) - - def accept(self): - # XXX can return either an address pair or None - try: - conn, addr = self.socket.accept() - except TypeError: - return None - except socket.error as why: - if why.args[0] in (EWOULDBLOCK, WSAEWOULDBLOCK, ECONNABORTED, EAGAIN, ENOTCONN): - return None - else: - raise - else: - return conn, addr - - def send(self, data): - try: - result = self.socket.send(data) - return result - except socket.error as why: - if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): - return 0 - elif why.args[0] in _DISCONNECTED: - self.handle_close() - return 0 - else: - raise - - def recv(self, buffer_size): - try: - data = self.socket.recv(buffer_size) - if not data: - # a closed connection is indicated by signaling - # a read condition, and having recv() return 0. - self.handle_close() - return b'' - else: - return data - except socket.error as why: - # winsock sometimes raises ENOTCONN - if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): - return b'' - if why.args[0] in _DISCONNECTED: - self.handle_close() - return b'' - else: - raise - - def close(self): - self.connected = False - self.accepting = False - self.connecting = False - self.del_channel() - try: - self.socket.close() - except socket.error as why: - if why.args[0] not in (ENOTCONN, EBADF): - raise - - # cheap inheritance, used to pass all other attribute - # references to the underlying socket object. - def __getattr__(self, attr): - try: - retattr = getattr(self.socket, attr) - except AttributeError: - raise AttributeError("%s instance has no attribute '%s'" - %(self.__class__.__name__, attr)) - else: - msg = "%(me)s.%(attr)s is deprecated; use %(me)s.socket.%(attr)s " \ - "instead" % {'me' : self.__class__.__name__, 'attr' : attr} - warnings.warn(msg, DeprecationWarning, stacklevel=2) - return retattr - - # log and log_info may be overridden to provide more sophisticated - # logging and warning methods. In general, log is for 'hit' logging - # and 'log_info' is for informational, warning and error logging. - - def log(self, message): - sys.stderr.write('log: %s\n' % str(message)) - - def log_info(self, message, log_type='info'): - if log_type not in self.ignore_log_types: - print('%s: %s' % (log_type, message)) - - def handle_read_event(self): - if self.accepting: - # accepting sockets are never connected, they "spawn" new - # sockets that are connected - self.handle_accept() - elif not self.connected: - if self.connecting: - self.handle_connect_event() - self.handle_read() - else: - self.handle_read() - - def handle_connect_event(self): - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - raise socket.error(err, _strerror(err)) - self.handle_connect() - self.connected = True - self.connecting = False - - def handle_write_event(self): - if self.accepting: - # Accepting sockets shouldn't get a write event. - # We will pretend it didn't happen. - return - - if not self.connected: - if self.connecting: - self.handle_connect_event() - self.handle_write() - - def handle_expt_event(self): - # handle_expt_event() is called if there might be an error on the - # socket, or if there is OOB data - # check for the error condition first - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - if err != 0: - # we can get here when select.select() says that there is an - # exceptional condition on the socket - # since there is an error, we'll go ahead and close the socket - # like we would in a subclassed handle_read() that received no - # data - self.handle_close() - elif sys.platform.startswith("win"): - # async connect failed - self.handle_close() - else: - self.handle_expt() - - def handle_error(self): - nil, t, v, tbinfo = compact_traceback() - - # sometimes a user repr method will crash. - try: - self_repr = repr(self) - except: - self_repr = '<__repr__(self) failed for object at %0x>' % id(self) - - self.log_info( - 'uncaptured python exception, closing channel %s (%s:%s %s)' % ( - self_repr, - t, - v, - tbinfo - ), - 'error' - ) - self.handle_close() - - def handle_expt(self): - self.log_info('unhandled incoming priority event', 'warning') - - def handle_read(self): - self.log_info('unhandled read event', 'warning') - - def handle_write(self): - self.log_info('unhandled write event', 'warning') - - def handle_connect(self): - self.log_info('unhandled connect event', 'warning') - - def handle_accept(self): - pair = self.accept() - if pair is not None: - self.handle_accepted(*pair) - - def handle_accepted(self, sock, addr): - sock.close() - self.log_info('unhandled accepted event on %s' % (addr), 'warning') - - def handle_close(self): - self.log_info('unhandled close event', 'warning') - self.close() - -# --------------------------------------------------------------------------- -# adds simple buffered output capability, useful for simple clients. -# [for more sophisticated usage use asynchat.async_chat] -# --------------------------------------------------------------------------- - -class dispatcher_with_send(dispatcher): - - def __init__(self, sock=None, map=None): - dispatcher.__init__(self, sock, map) - self.out_buffer = b'' - - def initiate_send(self): - num_sent = 0 - num_sent = dispatcher.send(self, self.out_buffer[:512]) - self.out_buffer = self.out_buffer[num_sent:] - - def handle_write(self): - self.initiate_send() - - def writable(self): - return (not self.connected) or len(self.out_buffer) - - def send(self, data): - if self.debug: - self.log_info('sending %s' % repr(data)) - self.out_buffer = self.out_buffer + data - self.initiate_send() - -# --------------------------------------------------------------------------- -# used for debugging. -# --------------------------------------------------------------------------- - -def compact_traceback(): - t, v, tb = sys.exc_info() - tbinfo = [] - if not tb: # Must have a traceback - raise AssertionError("traceback does not exist") - while tb: - tbinfo.append(( - tb.tb_frame.f_code.co_filename, - tb.tb_frame.f_code.co_name, - str(tb.tb_lineno) - )) - tb = tb.tb_next - - # just to be safe - del tb - - file, function, line = tbinfo[-1] - info = ' '.join(['[%s|%s|%s]' % x for x in tbinfo]) - return (file, function, line), t, v, info - -def close_all(map=None, ignore_all=False): - if map is None: - map = socket_map - for x in list(map.values()): - try: - x.close() - except OSError as e: - if e.args[0] == EBADF: - pass - elif not ignore_all: - raise - except _reraised_exceptions: - raise - except: - if not ignore_all: - raise - map.clear() - -# Asynchronous File I/O: -# -# After a little research (reading man pages on various unixen, and -# digging through the linux kernel), I've determined that select() -# isn't meant for doing asynchronous file i/o. -# Heartening, though - reading linux/mm/filemap.c shows that linux -# supports asynchronous read-ahead. So _MOST_ of the time, the data -# will be sitting in memory for us already when we go to read it. -# -# What other OS's (besides NT) support async file i/o? [VMS?] -# -# Regardless, this is useful for pipes, and stdin/stdout... - -if os.name == 'posix': - import fcntl - - class file_wrapper: - # Here we override just enough to make a file - # look like a socket for the purposes of asyncore. - # The passed fd is automatically os.dup()'d - - def __init__(self, fd): - self.fd = os.dup(fd) - - def recv(self, *args): - return os.read(self.fd, *args) - - def send(self, *args): - return os.write(self.fd, *args) - - def getsockopt(self, level, optname, buflen=None): - if (level == socket.SOL_SOCKET and - optname == socket.SO_ERROR and - not buflen): - return 0 - raise NotImplementedError("Only asyncore specific behaviour " - "implemented.") - - read = recv - write = send - - def close(self): - os.close(self.fd) - - def fileno(self): - return self.fd - - class file_dispatcher(dispatcher): - - def __init__(self, fd, map=None): - dispatcher.__init__(self, None, map) - self.connected = True - try: - fd = fd.fileno() - except AttributeError: - pass - self.set_file(fd) - # set it to non-blocking mode - flags = fcntl.fcntl(fd, fcntl.F_GETFL, 0) - flags = flags | os.O_NONBLOCK - fcntl.fcntl(fd, fcntl.F_SETFL, flags) - - def set_file(self, fd): - self.socket = file_wrapper(fd) - self._fileno = self.socket.fileno() - self.add_channel() diff --git a/src/network/bmobject.py b/src/network/bmobject.py deleted file mode 100644 index 2e7dd092..00000000 --- a/src/network/bmobject.py +++ /dev/null @@ -1,113 +0,0 @@ -from binascii import hexlify -import time - -from addresses import calculateInventoryHash -from debug import logger -from inventory import Inventory -from network.dandelion import Dandelion -import protocol -import state - -class BMObjectInsufficientPOWError(Exception): - errorCodes = ("Insufficient proof of work") - - -class BMObjectInvalidDataError(Exception): - errorCodes = ("Data invalid") - - -class BMObjectExpiredError(Exception): - errorCodes = ("Object expired") - - -class BMObjectUnwantedStreamError(Exception): - errorCodes = ("Object in unwanted stream") - - -class BMObjectInvalidError(Exception): - errorCodes = ("Invalid object") - - -class BMObjectAlreadyHaveError(Exception): - errorCodes = ("Already have this object") - - -class BMObject(object): - # max TTL, 28 days and 3 hours - maxTTL = 28 * 24 * 60 * 60 + 10800 - # min TTL, 3 hour (in the past - minTTL = -3600 - - def __init__(self, nonce, expiresTime, objectType, version, streamNumber, data, payloadOffset): - self.nonce = nonce - self.expiresTime = expiresTime - self.objectType = objectType - self.version = version - self.streamNumber = streamNumber - self.inventoryHash = calculateInventoryHash(data) - # copy to avoid memory issues - self.data = bytearray(data) - self.tag = self.data[payloadOffset:payloadOffset+32] - - def checkProofOfWorkSufficient(self): - # Let us check to make sure that the proof of work is sufficient. - if not protocol.isProofOfWorkSufficient(self.data): - logger.info('Proof of work is insufficient.') - raise BMObjectInsufficientPOWError() - - def checkEOLSanity(self): - # EOL sanity check - if self.expiresTime - int(time.time()) > BMObject.maxTTL: - logger.info('This object\'s End of Life time is too far in the future. Ignoring it. Time is %i', self.expiresTime) - # TODO: remove from download queue - raise BMObjectExpiredError() - - if self.expiresTime - int(time.time()) < BMObject.minTTL: - logger.info('This object\'s End of Life time was too long ago. Ignoring the object. Time is %i', self.expiresTime) - # TODO: remove from download queue - raise BMObjectExpiredError() - - def checkStream(self): - if self.streamNumber not in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %i isn\'t one we are interested in.', self.streamNumber) - raise BMObjectUnwantedStreamError() - - def checkAlreadyHave(self): - # if it's a stem duplicate, pretend we don't have it - if Dandelion().hasHash(self.inventoryHash): - return - if self.inventoryHash in Inventory(): - raise BMObjectAlreadyHaveError() - - def checkObjectByType(self): - if self.objectType == protocol.OBJECT_GETPUBKEY: - self.checkGetpubkey() - elif self.objectType == protocol.OBJECT_PUBKEY: - self.checkPubkey() - elif self.objectType == protocol.OBJECT_MSG: - self.checkMessage() - elif self.objectType == protocol.OBJECT_BROADCAST: - self.checkBroadcast() - # other objects don't require other types of tests - - def checkMessage(self): - return - - def checkGetpubkey(self): - if len(self.data) < 42: - logger.info('getpubkey message doesn\'t contain enough data. Ignoring.') - raise BMObjectInvalidError() - - def checkPubkey(self): - if len(self.data) < 146 or len(self.data) > 440: # sanity check - logger.info('pubkey object too short or too long. Ignoring.') - raise BMObjectInvalidError() - - def checkBroadcast(self): - if len(self.data) < 180: - logger.debug('The payload length of this broadcast packet is unreasonably low. Someone is probably trying funny business. Ignoring message.') - raise BMObjectInvalidError() - - # this isn't supported anymore - if self.version < 2: - raise BMObjectInvalidError() diff --git a/src/network/bmproto.py b/src/network/bmproto.py deleted file mode 100644 index 28277f52..00000000 --- a/src/network/bmproto.py +++ /dev/null @@ -1,572 +0,0 @@ -import base64 -import hashlib -import random -import socket -import struct -import time - -from bmconfigparser import BMConfigParser -from debug import logger -from inventory import Inventory -import knownnodes -from network.advanceddispatcher import AdvancedDispatcher -from network.dandelion import Dandelion -from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, \ - BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError -import network.connectionpool -from network.node import Node -from network.objectracker import ObjectTracker -from network.proxy import Proxy, ProxyError, GeneralProxyError - -import addresses -from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue -import shared -import state -import protocol - -class BMProtoError(ProxyError): - errorCodes = ("Protocol error") - - -class BMProtoInsufficientDataError(BMProtoError): - errorCodes = ("Insufficient data") - - -class BMProtoExcessiveDataError(BMProtoError): - errorCodes = ("Too much data") - - -class BMProto(AdvancedDispatcher, ObjectTracker): - # ~1.6 MB which is the maximum possible size of an inv message. - maxMessageSize = 1600100 - # 2**18 = 256kB is the maximum size of an object payload - maxObjectPayloadSize = 2**18 - # protocol specification says max 1000 addresses in one addr command - maxAddrCount = 1000 - # protocol specification says max 50000 objects in one inv command - maxObjectCount = 50000 - # address is online if online less than this many seconds ago - addressAlive = 10800 - # maximum time offset - maxTimeOffset = 3600 - - def __init__(self, address=None, sock=None): - AdvancedDispatcher.__init__(self, sock) - self.isOutbound = False - # packet/connection from a local IP - self.local = False - - def bm_proto_reset(self): - self.magic = None - self.command = None - self.payloadLength = 0 - self.checksum = None - self.payload = None - self.invalid = False - self.payloadOffset = 0 - self.expectBytes = protocol.Header.size - self.object = None - - def state_bm_header(self): - self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size]) - self.command = self.command.rstrip('\x00') - if self.magic != 0xE9BEB4D9: - # skip 1 byte in order to sync - self.set_state("bm_header", length=1) - self.bm_proto_reset() - logger.debug("Bad magic") - if self.socket.type == socket.SOCK_STREAM: - self.close_reason = "Bad magic" - self.set_state("close") - return False - if self.payloadLength > BMProto.maxMessageSize: - self.invalid = True - self.set_state("bm_command", length=protocol.Header.size, expectBytes=self.payloadLength) - return True - - def state_bm_command(self): - self.payload = self.read_buf[:self.payloadLength] - if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: - logger.debug("Bad checksum, ignoring") - self.invalid = True - retval = True - if not self.fullyEstablished and self.command not in ("error", "version", "verack"): - logger.error("Received command %s before connection was fully established, ignoring", self.command) - self.invalid = True - if not self.invalid: - try: - retval = getattr(self, "bm_command_" + str(self.command).lower())() - except AttributeError: - # unimplemented command - logger.debug("unimplemented command %s", self.command) - except BMProtoInsufficientDataError: - logger.debug("packet length too short, skipping") - except BMProtoExcessiveDataError: - logger.debug("too much data, skipping") - except BMObjectInsufficientPOWError: - logger.debug("insufficient PoW, skipping") - except BMObjectInvalidDataError: - logger.debug("object invalid data, skipping") - except BMObjectExpiredError: - logger.debug("object expired, skipping") - except BMObjectUnwantedStreamError: - logger.debug("object not in wanted stream, skipping") - except BMObjectInvalidError: - logger.debug("object invalid, skipping") - except BMObjectAlreadyHaveError: - logger.debug("%s:%i already got object, skipping", self.destination.host, self.destination.port) - except struct.error: - logger.debug("decoding error, skipping") - elif self.socket.type == socket.SOCK_DGRAM: - # broken read, ignore - pass - else: - #print "Skipping command %s due to invalid data" % (self.command) - logger.debug("Closing due to invalid command %s", self.command) - self.close_reason = "Invalid command %s" % (self.command) - self.set_state("close") - return False - if retval: - self.set_state("bm_header", length=self.payloadLength) - self.bm_proto_reset() - # else assume the command requires a different state to follow - return True - - def decode_payload_string(self, length): - value = self.payload[self.payloadOffset:self.payloadOffset+length] - self.payloadOffset += length - return value - - def decode_payload_varint(self): - value, offset = addresses.decodeVarint(self.payload[self.payloadOffset:]) - self.payloadOffset += offset - return value - - def decode_payload_node(self): - services, host, port = self.decode_payload_content("Q16sH") - if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': - host = socket.inet_ntop(socket.AF_INET, str(host[12:16])) - elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43': - # Onion, based on BMD/bitcoind - host = base64.b32encode(host[6:]).lower() + ".onion" - else: - host = socket.inet_ntop(socket.AF_INET6, str(host)) - if host == "": - # This can happen on Windows systems which are not 64-bit compatible - # so let us drop the IPv6 address. - host = socket.inet_ntop(socket.AF_INET, str(host[12:16])) - - return Node(services, host, port) - - def decode_payload_content(self, pattern = "v"): - # L = varint indicating the length of the next array - # l = varint indicating the length of the next item - # v = varint (or array) - # H = uint16 - # I = uint32 - # Q = uint64 - # i = net_addr (without time and stream number) - # s = string - # 0-9 = length of the next item - # , = end of array - - def decode_simple(self, char="v"): - if char == "v": - return self.decode_payload_varint() - if char == "i": - return self.decode_payload_node() - if char == "H": - self.payloadOffset += 2 - return struct.unpack(">H", self.payload[self.payloadOffset-2:self.payloadOffset])[0] - if char == "I": - self.payloadOffset += 4 - return struct.unpack(">I", self.payload[self.payloadOffset-4:self.payloadOffset])[0] - if char == "Q": - self.payloadOffset += 8 - return struct.unpack(">Q", self.payload[self.payloadOffset-8:self.payloadOffset])[0] - - size = None - isArray = False - - # size - # iterator starting from size counting to 0 - # isArray? - # subpattern - # position of parser in subpattern - # retval (array) - parserStack = [[1, 1, False, pattern, 0, []]] - - #try: - # sys._getframe(200) - # logger.error("Stack depth warning, pattern: %s", pattern) - # return - #except ValueError: - # pass - - while True: - i = parserStack[-1][3][parserStack[-1][4]] - if i in "0123456789" and (size is None or parserStack[-1][3][parserStack[-1][4]-1] not in "lL"): - try: - size = size * 10 + int(i) - except TypeError: - size = int(i) - isArray = False - elif i in "Ll" and size is None: - size = self.decode_payload_varint() - if i == "L": - isArray = True - else: - isArray = False - elif size is not None: - if isArray: - parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:], 0, []]) - parserStack[-2][4] = len(parserStack[-2][3]) - else: - for j in range(parserStack[-1][4], len(parserStack[-1][3])): - if parserStack[-1][3][j] not in "lL0123456789": - break - parserStack.append([size, size, isArray, parserStack[-1][3][parserStack[-1][4]:j+1], 0, []]) - parserStack[-2][4] += len(parserStack[-1][3]) - 1 - size = None - continue - elif i == "s": - #if parserStack[-2][2]: - # parserStack[-1][5].append(self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]]) - #else: - parserStack[-1][5] = self.payload[self.payloadOffset:self.payloadOffset + parserStack[-1][0]] - self.payloadOffset += parserStack[-1][0] - parserStack[-1][1] = 0 - parserStack[-1][2] = True - #del parserStack[-1] - size = None - elif i in "viHIQ": - parserStack[-1][5].append(decode_simple(self, parserStack[-1][3][parserStack[-1][4]])) - size = None - else: - size = None - for depth in range(len(parserStack) - 1, -1, -1): - parserStack[depth][4] += 1 - if parserStack[depth][4] >= len(parserStack[depth][3]): - parserStack[depth][1] -= 1 - parserStack[depth][4] = 0 - if depth > 0: - if parserStack[depth][2]: - parserStack[depth - 1][5].append(parserStack[depth][5]) - else: - parserStack[depth - 1][5].extend(parserStack[depth][5]) - parserStack[depth][5] = [] - if parserStack[depth][1] <= 0: - if depth == 0: - # we're done, at depth 0 counter is at 0 and pattern is done parsing - return parserStack[depth][5] - del parserStack[-1] - continue - break - break - if self.payloadOffset > self.payloadLength: - logger.debug("Insufficient data %i/%i", self.payloadOffset, self.payloadLength) - raise BMProtoInsufficientDataError() - - def bm_command_error(self): - fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") - logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText) - return True - - def bm_command_getdata(self): - items = self.decode_payload_content("l32s") - # skip? - if time.time() < self.skipUntil: - return True - #TODO make this more asynchronous - random.shuffle(items) - for i in map(str, items): - if Dandelion().hasHash(i) and \ - self != Dandelion().objectChildStem(i): - self.antiIntersectionDelay() - logger.info('%s asked for a stem object we didn\'t offer to it.', self.destination) - break - else: - try: - self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].payload)) - except KeyError: - self.antiIntersectionDelay() - logger.info('%s asked for an object we don\'t have.', self.destination) - break - # I think that aborting after the first missing/stem object is more secure - # when using random reordering, as the recipient won't know exactly which objects we refuse to deliver - return True - - def _command_inv(self, dandelion=False): - items = self.decode_payload_content("l32s") - - if len(items) >= BMProto.maxObjectCount: - logger.error("Too many items in %sinv message!", "d" if dandelion else "") - raise BMProtoExcessiveDataError() - else: - pass - - # ignore dinv if dandelion turned off - if dandelion and not state.dandelion: - return True - - for i in map(str, items): - if i in Inventory() and not Dandelion().hasHash(i): - continue - if dandelion and not Dandelion().hasHash(i): - Dandelion().addHash(i, self) - self.handleReceivedInventory(i) - - return True - - def bm_command_inv(self): - return self._command_inv(False) - - def bm_command_dinv(self): - """ - Dandelion stem announce - """ - return self._command_inv(True) - - def bm_command_object(self): - objectOffset = self.payloadOffset - nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv") - self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload, self.payloadOffset) - - if len(self.payload) - self.payloadOffset > BMProto.maxObjectPayloadSize: - logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(self.payload) - self.payloadOffset) - raise BMProtoExcessiveDataError() - - try: - self.object.checkProofOfWorkSufficient() - self.object.checkEOLSanity() - self.object.checkAlreadyHave() - except (BMObjectExpiredError, BMObjectAlreadyHaveError, BMObjectInsufficientPOWError) as e: - BMProto.stopDownloadingObject(self.object.inventoryHash) - raise e - try: - self.object.checkStream() - except (BMObjectUnwantedStreamError,) as e: - BMProto.stopDownloadingObject(self.object.inventoryHash, BMConfigParser().get("inventory", "acceptmismatch")) - if not BMConfigParser().get("inventory", "acceptmismatch"): - raise e - - try: - self.object.checkObjectByType() - objectProcessorQueue.put((self.object.objectType, buffer(self.object.data))) - except BMObjectInvalidError as e: - BMProto.stopDownloadingObject(self.object.inventoryHash, True) - else: - try: - del state.missingObjects[self.object.inventoryHash] - except KeyError: - pass - - if self.object.inventoryHash in Inventory() and Dandelion().hasHash(self.object.inventoryHash): - Dandelion().removeHash(self.object.inventoryHash, "cycle detection") - - Inventory()[self.object.inventoryHash] = ( - self.object.objectType, self.object.streamNumber, buffer(self.payload[objectOffset:]), self.object.expiresTime, buffer(self.object.tag)) - self.handleReceivedObject(self.object.streamNumber, self.object.inventoryHash) - invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination)) - return True - - def _decode_addr(self): - return self.decode_payload_content("LQIQ16sH") - - def bm_command_addr(self): - addresses = self._decode_addr() - for i in addresses: - seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(str(ip)) - if stream not in state.streamsInWhichIAmParticipating: - continue - if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: - peer = state.Peer(decodedIP, port) - try: - if knownnodes.knownNodes[stream][peer]["lastseen"] > seenTime: - continue - except KeyError: - pass - if len(knownnodes.knownNodes[stream]) < int(BMConfigParser().get("knownnodes", "maxnodes")): - with knownnodes.knownNodesLock: - try: - knownnodes.knownNodes[stream][peer]["lastseen"] = seenTime - except (TypeError, KeyError): - knownnodes.knownNodes[stream][peer] = { - "lastseen": seenTime, - "rating": 0, - "self": False, - } - addrQueue.put((stream, peer, self.destination)) - return True - - def bm_command_portcheck(self): - portCheckerQueue.put(state.Peer(self.destination, self.peerNode.port)) - return True - - def bm_command_ping(self): - self.append_write_buf(protocol.CreatePacket('pong')) - return True - - def bm_command_pong(self): - # nothing really - return True - - def bm_command_verack(self): - self.verackReceived = True - if self.verackSent: - if self.isSSL: - self.set_state("tls_init", length=self.payloadLength, expectBytes=0) - return False - self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) - return False - return True - - def bm_command_version(self): - self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, \ - self.userAgent, self.streams = self.decode_payload_content("IQQiiQlsLv") - self.nonce = struct.pack('>Q', self.nonce) - self.timeOffset = self.timestamp - int(time.time()) - logger.debug("remoteProtocolVersion: %i", self.remoteProtocolVersion) - logger.debug("services: 0x%08X", self.services) - logger.debug("time offset: %i", self.timestamp - int(time.time())) - logger.debug("my external IP: %s", self.sockNode.host) - logger.debug("remote node incoming address: %s:%i", self.destination.host, self.peerNode.port) - logger.debug("user agent: %s", self.userAgent) - logger.debug("streams: [%s]", ",".join(map(str,self.streams))) - if not self.peerValidityChecks(): - # TODO ABORT - return True - #shared.connectedHostsList[self.destination] = self.streams[0] - self.append_write_buf(protocol.CreatePacket('verack')) - self.verackSent = True - if not self.isOutbound: - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ - network.connectionpool.BMConnectionPool().streams, True, nodeid=self.nodeid)) - #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - protocol.haveSSL(not self.isOutbound)): - self.isSSL = True - if self.verackReceived: - if self.isSSL: - self.set_state("tls_init", length=self.payloadLength, expectBytes=0) - return False - self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) - return False - return True - - def peerValidityChecks(self): - if self.remoteProtocolVersion < 3: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="Your is using an old protocol. Closing connection.")) - logger.debug ('Closing connection to old protocol version %s, node: %s', - str(self.remoteProtocolVersion), str(self.destination)) - return False - if self.timeOffset > BMProto.maxTimeOffset: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="Your time is too far in the future compared to mine. Closing connection.")) - logger.info("%s's time is too far in the future (%s seconds). Closing connection to it.", - self.destination, self.timeOffset) - shared.timeOffsetWrongCount += 1 - return False - elif self.timeOffset < -BMProto.maxTimeOffset: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="Your time is too far in the past compared to mine. Closing connection.")) - logger.info("%s's time is too far in the past (timeOffset %s seconds). Closing connection to it.", - self.destination, self.timeOffset) - shared.timeOffsetWrongCount += 1 - return False - else: - shared.timeOffsetWrongCount = 0 - if not self.streams: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="We don't have shared stream interests. Closing connection.")) - logger.debug ('Closed connection to %s because there is no overlapping interest in streams.', - str(self.destination)) - return False - if self.destination in network.connectionpool.BMConnectionPool().inboundConnections: - try: - if not protocol.checkSocksIP(self.destination.host): - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="Too many connections from your IP. Closing connection.")) - logger.debug ('Closed connection to %s because we are already connected to that IP.', - str(self.destination)) - return False - except: - pass - if not self.isOutbound: - # incoming from a peer we're connected to as outbound, or server full - # report the same error to counter deanonymisation - if state.Peer(self.destination.host, self.peerNode.port) in \ - network.connectionpool.BMConnectionPool().inboundConnections or \ - len(network.connectionpool.BMConnectionPool().inboundConnections) + \ - len(network.connectionpool.BMConnectionPool().outboundConnections) > \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"): - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="Server full, please try again later.")) - logger.debug ("Closed connection to %s due to server full or duplicate inbound/outbound.", - str(self.destination)) - return False - if network.connectionpool.BMConnectionPool().isAlreadyConnected(self.nonce): - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, - errorText="I'm connected to myself. Closing connection.")) - logger.debug ("Closed connection to %s because I'm connected to myself.", - str(self.destination)) - return False - - return True - - @staticmethod - def assembleAddr(peerList): - if isinstance(peerList, state.Peer): - peerList = (peerList) - if not peerList: - return b'' - retval = b'' - for i in range(0, len(peerList), BMProto.maxAddrCount): - payload = addresses.encodeVarint(len(peerList[i:i + BMProto.maxAddrCount])) - for address in peerList[i:i + BMProto.maxAddrCount]: - stream, peer, timestamp = address - payload += struct.pack( - '>Q', timestamp) # 64-bit time - payload += struct.pack('>I', stream) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(peer.host) - payload += struct.pack('>H', peer.port) # remote port - retval += protocol.CreatePacket('addr', payload) - return retval - - @staticmethod - def stopDownloadingObject(hashId, forwardAnyway=False): - for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ - network.connectionpool.BMConnectionPool().outboundConnections.values(): - try: - del connection.objectsNewToMe[hashId] - except KeyError: - pass - if not forwardAnyway: - try: - with connection.objectsNewToThemLock: - del connection.objectsNewToThem[hashId] - except KeyError: - pass - try: - del state.missingObjects[hashId] - except KeyError: - pass - - def handle_close(self): - self.set_state("close") - if not (self.accepting or self.connecting or self.connected): - # already disconnected - return - try: - logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, self.close_reason) - except AttributeError: - try: - logger.debug("%s:%i: closing", self.destination.host, self.destination.port) - except AttributeError: - logger.debug("Disconnected socket closing") - AdvancedDispatcher.handle_close(self) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py deleted file mode 100644 index 819dfeb1..00000000 --- a/src/network/connectionchooser.py +++ /dev/null @@ -1,58 +0,0 @@ -from queues import Queue -import random - -from bmconfigparser import BMConfigParser -import knownnodes -import protocol -from queues import portCheckerQueue -import state - -def getDiscoveredPeer(): - try: - peer = random.choice(state.discoveredPeers.keys()) - except (IndexError, KeyError): - raise ValueError - try: - del state.discoveredPeers[peer] - except KeyError: - pass - return peer - -def chooseConnection(stream): - haveOnion = BMConfigParser().safeGet("bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' - if state.trustedPeer: - return state.trustedPeer - try: - retval = portCheckerQueue.get(False) - portCheckerQueue.task_done() - return retval - except Queue.Empty: - pass - # with a probability of 0.5, connect to a discovered peer - if random.choice((False, True)) and not haveOnion: - # discovered peers are already filtered by allowed streams - return getDiscoveredPeer() - for _ in range(50): - peer = random.choice(knownnodes.knownNodes[stream].keys()) - try: - rating = knownnodes.knownNodes[stream][peer]["rating"] - except TypeError: - print "Error in %s" % (peer) - rating = 0 - if haveOnion: - # onion addresses have a higher priority when SOCKS - if peer.host.endswith('.onion') and rating > 0: - rating = 1 - else: - encodedAddr = protocol.encodeHost(peer.host) - # don't connect to local IPs when using SOCKS - if not protocol.checkIPAddress(encodedAddr, False): - continue - if rating > 1: - rating = 1 - try: - if 0.05/(1.0-rating) > random.random(): - return peer - except ZeroDivisionError: - return peer - raise ValueError diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py deleted file mode 100644 index 408d56e0..00000000 --- a/src/network/connectionpool.py +++ /dev/null @@ -1,259 +0,0 @@ -from ConfigParser import NoOptionError, NoSectionError -import errno -import socket -import time -import random -import re - -from bmconfigparser import BMConfigParser -from debug import logger -import helper_bootstrap -from network.proxy import Proxy -from network.tcp import TCPServer, Socks5BMConnection, Socks4aBMConnection, TCPConnection -from network.udp import UDPSocket -from network.connectionchooser import chooseConnection -import network.asyncore_pollchoose as asyncore -import protocol -from singleton import Singleton -import state - -@Singleton -class BMConnectionPool(object): - def __init__(self): - asyncore.set_rates( - BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"), - BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate")) - self.outboundConnections = {} - self.inboundConnections = {} - self.listeningSockets = {} - self.udpSockets = {} - self.streams = [] - self.lastSpawned = 0 - self.spawnWait = 2 - self.bootstrapped = False - - def connectToStream(self, streamNumber): - self.streams.append(streamNumber) - - def getConnectionByAddr(self, addr): - if addr in self.inboundConnections: - return self.inboundConnections[addr] - try: - if addr.host in self.inboundConnections: - return self.inboundConnections[addr.host] - except AttributeError: - pass - if addr in self.outboundConnections: - return self.outboundConnections[addr] - try: - if addr.host in self.udpSockets: - return self.udpSockets[addr.host] - except AttributeError: - pass - raise KeyError - - def isAlreadyConnected(self, nodeid): - for i in self.inboundConnections.values() + self.outboundConnections.values(): - try: - if nodeid == i.nodeid: - return True - except AttributeError: - pass - return False - - def addConnection(self, connection): - if isinstance(connection, UDPSocket): - return - if connection.isOutbound: - self.outboundConnections[connection.destination] = connection - else: - if connection.destination.host in self.inboundConnections: - self.inboundConnections[connection.destination] = connection - else: - self.inboundConnections[connection.destination.host] = connection - - def removeConnection(self, connection): - if isinstance(connection, UDPSocket): - del self.udpSockets[connection.listening.host] - elif isinstance(connection, TCPServer): - del self.listeningSockets[state.Peer(connection.destination.host, connection.destination.port)] - elif connection.isOutbound: - try: - del self.outboundConnections[connection.destination] - except KeyError: - pass - else: - try: - del self.inboundConnections[connection.destination] - except KeyError: - try: - del self.inboundConnections[connection.destination.host] - except KeyError: - pass - connection.close() - - def getListeningIP(self): - if BMConfigParser().safeGet("bitmessagesettings", "onionhostname").endswith(".onion"): - host = BMConfigParser().safeGet("bitmessagesettings", "onionbindip") - else: - host = '127.0.0.1' - if BMConfigParser().safeGetBoolean("bitmessagesettings", "sockslisten") or \ - BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none": - # python doesn't like bind + INADDR_ANY? - #host = socket.INADDR_ANY - host = BMConfigParser().get("network", "bind") - return host - - def startListening(self, bind=None): - if bind is None: - bind = self.getListeningIP() - port = BMConfigParser().safeGetInt("bitmessagesettings", "port") - # correct port even if it changed - ls = TCPServer(host=bind, port=port) - self.listeningSockets[ls.destination] = ls - - def startUDPSocket(self, bind=None): - if bind is None: - host = self.getListeningIP() - udpSocket = UDPSocket(host=host, announcing=True) - else: - if bind is False: - udpSocket = UDPSocket(announcing=False) - else: - udpSocket = UDPSocket(host=bind, announcing=True) - self.udpSockets[udpSocket.listening.host] = udpSocket - - def loop(self): - # defaults to empty loop if outbound connections are maxed - spawnConnections = False - acceptConnections = True - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): - acceptConnections = False - elif BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): - spawnConnections = True - if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ - (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ - ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')): - acceptConnections = False - - if spawnConnections: - if not self.bootstrapped: - helper_bootstrap.dns() - self.bootstrapped = True - Proxy.proxy = (BMConfigParser().safeGet("bitmessagesettings", "sockshostname"), - BMConfigParser().safeGetInt("bitmessagesettings", "socksport")) - # TODO AUTH - # TODO reset based on GUI settings changes - try: - if not BMConfigParser().get("network", "onionsocksproxytype").startswith("SOCKS"): - raise NoOptionError - Proxy.onionproxy = (BMConfigParser().get("network", "onionsockshostname"), - BMConfigParser().getint("network", "onionsocksport")) - except (NoOptionError, NoSectionError): - Proxy.onionproxy = None - established = sum(1 for c in self.outboundConnections.values() if (c.connected and c.fullyEstablished)) - pending = len(self.outboundConnections) - established - if established < BMConfigParser().safeGetInt("bitmessagesettings", "maxoutboundconnections"): - for i in range(state.maximumNumberOfHalfOpenConnections - pending): - try: - chosen = chooseConnection(random.choice(self.streams)) - except ValueError: - continue - if chosen in self.outboundConnections: - continue - if chosen.host in self.inboundConnections: - continue - # don't connect to self - if chosen in state.ownAddresses: - continue - - #for c in self.outboundConnections: - # if chosen == c.destination: - # continue - #for c in self.inboundConnections: - # if chosen.host == c.destination.host: - # continue - try: - if chosen.host.endswith(".onion") and Proxy.onionproxy is not None: - if BMConfigParser().get("network", "onionsocksproxytype") == "SOCKS5": - self.addConnection(Socks5BMConnection(chosen)) - elif BMConfigParser().get("network", "onionsocksproxytype") == "SOCKS4a": - self.addConnection(Socks4aBMConnection(chosen)) - elif BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5": - self.addConnection(Socks5BMConnection(chosen)) - elif BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a": - self.addConnection(Socks4aBMConnection(chosen)) - else: - self.addConnection(TCPConnection(chosen)) - except socket.error as e: - if e.errno == errno.ENETUNREACH: - continue - except (NoSectionError, NoOptionError): - # shouldn't happen - pass - - self.lastSpawned = time.time() - else: - for i in ( - self.inboundConnections.values() + - self.outboundConnections.values() - ): - i.set_state("close") - # FIXME: rating will be increased after next connection - i.handle_close() - - if acceptConnections: - if not self.listeningSockets: - if BMConfigParser().safeGet("network", "bind") == '': - self.startListening() - else: - for bind in re.sub("[^\w.]+", " ", BMConfigParser().safeGet("network", "bind")).split(): - self.startListening(bind) - logger.info('Listening for incoming connections.') - if not self.udpSockets: - if BMConfigParser().safeGet("network", "bind") == '': - self.startUDPSocket() - else: - for bind in re.sub("[^\w.]+", " ", BMConfigParser().safeGet("network", "bind")).split(): - self.startUDPSocket(bind) - self.startUDPSocket(False) - logger.info('Starting UDP socket(s).') - else: - if self.listeningSockets: - for i in self.listeningSockets.values(): - i.close_reason = "Stopping listening" - i.accepting = i.connecting = i.connected = False - logger.info('Stopped listening for incoming connections.') - if self.udpSockets: - for i in self.udpSockets.values(): - i.close_reason = "Stopping UDP socket" - i.accepting = i.connecting = i.connected = False - logger.info('Stopped udp sockets.') - - loopTime = float(self.spawnWait) - if self.lastSpawned < time.time() - self.spawnWait: - loopTime = 2.0 - asyncore.loop(timeout=loopTime, count=1000) - - reaper = [] - for i in self.inboundConnections.values() + self.outboundConnections.values(): - minTx = time.time() - 20 - if i.fullyEstablished: - minTx -= 300 - 20 - if i.lastTx < minTx: - if i.fullyEstablished: - i.append_write_buf(protocol.CreatePacket('ping')) - else: - i.close_reason = "Timeout (%is)" % (time.time() - i.lastTx) - i.set_state("close") - for i in self.inboundConnections.values() + self.outboundConnections.values() + self.listeningSockets.values() + self.udpSockets.values(): - if not (i.accepting or i.connecting or i.connected): - reaper.append(i) - else: - try: - if i.state == "close": - reaper.append(i) - except AttributeError: - pass - for i in reaper: - self.removeConnection(i) diff --git a/src/network/dandelion.py b/src/network/dandelion.py deleted file mode 100644 index 06ecca24..00000000 --- a/src/network/dandelion.py +++ /dev/null @@ -1,141 +0,0 @@ -from collections import namedtuple -from random import choice, sample, expovariate -from threading import RLock -from time import time - -from bmconfigparser import BMConfigParser -import network.connectionpool -from debug import logging -from queues import invQueue -from singleton import Singleton -import state - -# randomise routes after 600 seconds -REASSIGN_INTERVAL = 600 - -# trigger fluff due to expiration -FLUFF_TRIGGER_FIXED_DELAY = 10 -FLUFF_TRIGGER_MEAN_DELAY = 30 - -MAX_STEMS = 2 - -Stem = namedtuple('Stem', ['child', 'stream', 'timeout']) - -@Singleton -class Dandelion(): - def __init__(self): - # currently assignable child stems - self.stem = [] - # currently assigned parent <-> child mappings - self.nodeMap = {} - # currently existing objects in stem mode - self.hashMap = {} - # when to rerandomise routes - self.refresh = time() + REASSIGN_INTERVAL - self.lock = RLock() - - def poissonTimeout(self, start=None, average=0): - if start is None: - start = time() - if average == 0: - average = FLUFF_TRIGGER_MEAN_DELAY - return start + expovariate(1.0/average) + FLUFF_TRIGGER_FIXED_DELAY - - def addHash(self, hashId, source=None, stream=1): - if not state.dandelion: - return - with self.lock: - self.hashMap[hashId] = Stem( - self.getNodeStem(source), - stream, - self.poissonTimeout()) - - def setHashStream(self, hashId, stream=1): - with self.lock: - if hashId in self.hashMap: - self.hashMap[hashId] = Stem( - self.hashMap[hashId].child, - stream, - self.poissonTimeout()) - - def removeHash(self, hashId, reason="no reason specified"): - logging.debug("%s entering fluff mode due to %s.", ''.join('%02x'%ord(i) for i in hashId), reason) - with self.lock: - try: - del self.hashMap[hashId] - except KeyError: - pass - - def hasHash(self, hashId): - return hashId in self.hashMap - - def objectChildStem(self, hashId): - return self.hashMap[hashId].child - - def maybeAddStem(self, connection): - # fewer than MAX_STEMS outbound connections at last reshuffle? - with self.lock: - if len(self.stem) < MAX_STEMS: - self.stem.append(connection) - for k in (k for k, v in self.nodeMap.iteritems() if v is None): - self.nodeMap[k] = connection - for k, v in {k: v for k, v in self.hashMap.iteritems() if v.child is None}.iteritems(): - self.hashMap[k] = Stem(connection, v.stream, self.poissonTimeout()) - invQueue.put((v.stream, k, v.child)) - - - def maybeRemoveStem(self, connection): - # is the stem active? - with self.lock: - if connection in self.stem: - self.stem.remove(connection) - # active mappings to pointing to the removed node - for k in (k for k, v in self.nodeMap.iteritems() if v == connection): - self.nodeMap[k] = None - for k, v in {k: v for k, v in self.hashMap.iteritems() if v.child == connection}.iteritems(): - self.hashMap[k] = Stem(None, v.stream, self.poissonTimeout()) - - def pickStem(self, parent=None): - try: - # pick a random from available stems - stem = choice(range(len(self.stem))) - if self.stem[stem] == parent: - # one stem available and it's the parent - if len(self.stem) == 1: - return None - # else, pick the other one - return self.stem[1 - stem] - # all ok - return self.stem[stem] - except IndexError: - # no stems available - return None - - def getNodeStem(self, node=None): - with self.lock: - try: - return self.nodeMap[node] - except KeyError: - self.nodeMap[node] = self.pickStem(node) - return self.nodeMap[node] - - def expire(self): - with self.lock: - deadline = time() - # only expire those that have a child node, i.e. those without a child not will stick around - toDelete = [[v.stream, k, v.child] for k, v in self.hashMap.iteritems() if v.timeout < deadline and v.child] - for row in toDelete: - self.removeHash(row[1], 'expiration') - invQueue.put((row[0], row[1], row[2])) - - def reRandomiseStems(self): - with self.lock: - try: - # random two connections - self.stem = sample(network.connectionpool.BMConnectionPool().outboundConnections.values(), MAX_STEMS) - # not enough stems available - except ValueError: - self.stem = network.connectionpool.BMConnectionPool().outboundConnections.values() - self.nodeMap = {} - # hashMap stays to cater for pending stems - self.refresh = time() + REASSIGN_INTERVAL diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py deleted file mode 100644 index 7eee2761..00000000 --- a/src/network/downloadthread.py +++ /dev/null @@ -1,74 +0,0 @@ -import random -import threading -import time - -import addresses -from dandelion import Dandelion -from debug import logger -from helper_threading import StoppableThread -from inventory import Inventory -from network.connectionpool import BMConnectionPool -import protocol -from state import missingObjects - -class DownloadThread(threading.Thread, StoppableThread): - minPending = 200 - maxRequestChunk = 1000 - requestTimeout = 60 - cleanInterval = 60 - requestExpires = 3600 - - def __init__(self): - threading.Thread.__init__(self, name="Downloader") - self.initStop() - self.name = "Downloader" - logger.info("init download thread") - self.lastCleaned = time.time() - - def cleanPending(self): - deadline = time.time() - DownloadThread.requestExpires - try: - toDelete = [k for k, v in missingObjects.iteritems() if v < deadline] - except RuntimeError: - pass - else: - for i in toDelete: - del missingObjects[i] - self.lastCleaned = time.time() - - def run(self): - while not self._stopped: - requested = 0 - # Choose downloading peers randomly - connections = [x for x in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() if x.fullyEstablished] - random.shuffle(connections) - try: - requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) - except ZeroDivisionError: - requestChunk = 1 - for i in connections: - now = time.time() - try: - request = i.objectsNewToMe.randomKeys(requestChunk) - except KeyError: - continue - payload = bytearray() - payload.extend(addresses.encodeVarint(len(request))) - for chunk in request: - if chunk in Inventory() and not Dandelion().hasHash(chunk): - try: - del i.objectsNewToMe[chunk] - except KeyError: - pass - continue - payload.extend(chunk) - missingObjects[chunk] = now - if not payload: - continue - i.append_write_buf(protocol.CreatePacket('getdata', payload)) - logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) - requested += len(request) - if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: - self.cleanPending() - if not requested: - self.stop.wait(1) diff --git a/src/network/http-old.py b/src/network/http-old.py deleted file mode 100644 index 56d24915..00000000 --- a/src/network/http-old.py +++ /dev/null @@ -1,49 +0,0 @@ -import asyncore -import socket -import time - -requestCount = 0 -parallel = 50 -duration = 60 - - -class HTTPClient(asyncore.dispatcher): - port = 12345 - - def __init__(self, host, path, connect=True): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self) - if connect: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.connect((host, HTTPClient.port)) - self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path - - def handle_close(self): - global requestCount - requestCount += 1 - self.close() - - def handle_read(self): -# print self.recv(8192) - self.recv(8192) - - def writable(self): - return (len(self.buffer) > 0) - - def handle_write(self): - sent = self.send(self.buffer) - self.buffer = self.buffer[sent:] - -if __name__ == "__main__": - # initial fill - for i in range(parallel): - HTTPClient('127.0.0.1', '/') - start = time.time() - while (time.time() - start < duration): - if (len(asyncore.socket_map) < parallel): - for i in range(parallel - len(asyncore.socket_map)): - HTTPClient('127.0.0.1', '/') - print "Active connections: %i" % (len(asyncore.socket_map)) - asyncore.loop(count=len(asyncore.socket_map)/2) - if requestCount % 100 == 0: - print "Processed %i total messages" % (requestCount) diff --git a/src/network/http.py b/src/network/http.py deleted file mode 100644 index 55cb81a1..00000000 --- a/src/network/http.py +++ /dev/null @@ -1,86 +0,0 @@ -import socket - -from advanceddispatcher import AdvancedDispatcher -import asyncore_pollchoose as asyncore -from proxy import Proxy, ProxyError, GeneralProxyError -from socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error -from socks4a import Socks4aConnection, Socks4aResolver, Socks4aError - -class HttpError(ProxyError): pass - - -class HttpConnection(AdvancedDispatcher): - def __init__(self, host, path="/"): - AdvancedDispatcher.__init__(self) - self.path = path - self.destination = (host, 80) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.connect(self.destination) - print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) - - def state_init(self): - self.append_write_buf("GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (self.path, self.destination[0])) - print "Sending %ib" % (len(self.write_buf)) - self.set_state("http_request_sent", 0) - return False - - def state_http_request_sent(self): - if len(self.read_buf) > 0: - print "Received %ib" % (len(self.read_buf)) - self.read_buf = b"" - if not self.connected: - self.set_state("close", 0) - return False - - -class Socks5HttpConnection(Socks5Connection, HttpConnection): - def __init__(self, host, path="/"): - self.path = path - Socks5Connection.__init__(self, address=(host, 80)) - - def state_socks_handshake_done(self): - HttpConnection.state_init(self) - return False - - -class Socks4aHttpConnection(Socks4aConnection, HttpConnection): - def __init__(self, host, path="/"): - Socks4aConnection.__init__(self, address=(host, 80)) - self.path = path - - def state_socks_handshake_done(self): - HttpConnection.state_init(self) - return False - - -if __name__ == "__main__": - # initial fill - - for host in ("bootstrap8080.bitmessage.org", "bootstrap8444.bitmessage.org"): - proxy = Socks5Resolver(host=host) - while len(asyncore.socket_map) > 0: - print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) - asyncore.loop(timeout=1, count=1) - proxy.resolved() - - proxy = Socks4aResolver(host=host) - while len(asyncore.socket_map) > 0: - print "loop %s, len %i" % (proxy.state, len(asyncore.socket_map)) - asyncore.loop(timeout=1, count=1) - proxy.resolved() - - for host in ("bitmessage.org",): - direct = HttpConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (direct.state) - asyncore.loop(timeout=1, count=1) - - proxy = Socks5HttpConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=1, count=1) - - proxy = Socks4aHttpConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=1, count=1) diff --git a/src/network/httpd.py b/src/network/httpd.py deleted file mode 100644 index b8b6ba21..00000000 --- a/src/network/httpd.py +++ /dev/null @@ -1,148 +0,0 @@ -import asyncore -import socket - -from tls import TLSHandshake - -class HTTPRequestHandler(asyncore.dispatcher): - response = """HTTP/1.0 200 OK\r -Date: Sun, 23 Oct 2016 18:02:00 GMT\r -Content-Type: text/html; charset=UTF-8\r -Content-Encoding: UTF-8\r -Content-Length: 136\r -Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT\r -Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)\r -ETag: "3f80f-1b6-3e1cb03b"\r -Accept-Ranges: bytes\r -Connection: close\r -\r - - - An Example Page - - - Hello World, this is a very simple HTML document. - -""" - - def __init__(self, sock): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self, sock) - self.inbuf = "" - self.ready = True - self.busy = False - self.respos = 0 - - def handle_close(self): - self.close() - - def readable(self): - return self.ready - - def writable(self): - return self.busy - - def handle_read(self): - self.inbuf += self.recv(8192) - if self.inbuf[-4:] == "\r\n\r\n": - self.busy = True - self.ready = False - self.inbuf = "" - elif self.inbuf == "": - pass - - def handle_write(self): - if self.busy and self.respos < len(HTTPRequestHandler.response): - written = 0 - written = self.send(HTTPRequestHandler.response[self.respos:65536]) - self.respos += written - elif self.busy: - self.busy = False - self.ready = True - self.close() - - -class HTTPSRequestHandler(HTTPRequestHandler, TLSHandshake): - def __init__(self, sock): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self, sock) -# self.tlsDone = False - TLSHandshake.__init__(self, sock=sock, certfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/cert.pem', keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', server_side=True) - HTTPRequestHandler.__init__(self, sock) - - def handle_connect(self): - TLSHandshake.handle_connect(self) - - def handle_close(self): - if self.tlsDone: - HTTPRequestHandler.close(self) - else: - TLSHandshake.close(self) - - def readable(self): - if self.tlsDone: - return HTTPRequestHandler.readable(self) - else: - return TLSHandshake.readable(self) - - def handle_read(self): - if self.tlsDone: - HTTPRequestHandler.handle_read(self) - else: - TLSHandshake.handle_read(self) - - def writable(self): - if self.tlsDone: - return HTTPRequestHandler.writable(self) - else: - return TLSHandshake.writable(self) - - def handle_write(self): - if self.tlsDone: - HTTPRequestHandler.handle_write(self) - else: - TLSHandshake.handle_write(self) - - -class HTTPServer(asyncore.dispatcher): - port = 12345 - - def __init__(self): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.bind(('127.0.0.1', HTTPServer.port)) - self.connections = 0 - self.listen(5) - - def handle_accept(self): - pair = self.accept() - if pair is not None: - sock, addr = pair -# print 'Incoming connection from %s' % repr(addr) - self.connections += 1 -# if self.connections % 1000 == 0: -# print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) - HTTPRequestHandler(sock) - - -class HTTPSServer(HTTPServer): - port = 12345 - - def __init__(self): - if not hasattr(self, '_map'): - HTTPServer.__init__(self) - - def handle_accept(self): - pair = self.accept() - if pair is not None: - sock, addr = pair -# print 'Incoming connection from %s' % repr(addr) - self.connections += 1 -# if self.connections % 1000 == 0: -# print "Processed %i connections, active %i" % (self.connections, len(asyncore.socket_map)) - HTTPSRequestHandler(sock) - -if __name__ == "__main__": - client = HTTPSServer() - asyncore.loop() diff --git a/src/network/https.py b/src/network/https.py deleted file mode 100644 index 151efcb8..00000000 --- a/src/network/https.py +++ /dev/null @@ -1,54 +0,0 @@ -import asyncore - -from http import HTTPClient -import paths -from tls import TLSHandshake - -# self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') - - -class HTTPSClient(HTTPClient, TLSHandshake): - def __init__(self, host, path): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self) - self.tlsDone = False -# TLSHandshake.__init__(self, address=(host, 443), certfile='/home/shurdeek/src/PyBitmessage/sslsrc/keys/cert.pem', keyfile='/home/shurdeek/src/PyBitmessage/src/sslkeys/key.pem', server_side=False, ciphers='AECDH-AES256-SHA') - HTTPClient.__init__(self, host, path, connect=False) - TLSHandshake.__init__(self, address=(host, 443), server_side=False) - - def handle_connect(self): - TLSHandshake.handle_connect(self) - - def handle_close(self): - if self.tlsDone: - HTTPClient.close(self) - else: - TLSHandshake.close(self) - - def readable(self): - if self.tlsDone: - return HTTPClient.readable(self) - else: - return TLSHandshake.readable(self) - - def handle_read(self): - if self.tlsDone: - HTTPClient.handle_read(self) - else: - TLSHandshake.handle_read(self) - - def writable(self): - if self.tlsDone: - return HTTPClient.writable(self) - else: - return TLSHandshake.writable(self) - - def handle_write(self): - if self.tlsDone: - HTTPClient.handle_write(self) - else: - TLSHandshake.handle_write(self) - -if __name__ == "__main__": - client = HTTPSClient('anarchy.economicsofbitcoin.com', '/') - asyncore.loop() diff --git a/src/network/invthread.py b/src/network/invthread.py deleted file mode 100644 index d0d758fb..00000000 --- a/src/network/invthread.py +++ /dev/null @@ -1,87 +0,0 @@ -import Queue -from random import randint, shuffle -import threading -from time import time - -import addresses -from bmconfigparser import BMConfigParser -from helper_threading import StoppableThread -from network.connectionpool import BMConnectionPool -from network.dandelion import Dandelion -from queues import invQueue -import protocol -import state - -class InvThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="InvBroadcaster") - self.initStop() - self.name = "InvBroadcaster" - - def handleLocallyGenerated(self, stream, hashId): - Dandelion().addHash(hashId, stream=stream) - for connection in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): - if state.dandelion and connection != Dandelion().objectChildStem(hashId): - continue - connection.objectsNewToThem[hashId] = time() - - def run(self): - while not state.shutdown: - chunk = [] - while True: - # Dandelion fluff trigger by expiration - Dandelion().expire() - try: - data = invQueue.get(False) - chunk.append((data[0], data[1])) - # locally generated - if len(data) == 2 or data[2] is None: - self.handleLocallyGenerated(data[0], data[1]) - except Queue.Empty: - break - - if chunk: - for connection in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): - fluffs = [] - stems = [] - for inv in chunk: - if inv[0] not in connection.streams: - continue - try: - with connection.objectsNewToThemLock: - del connection.objectsNewToThem[inv[1]] - except KeyError: - continue - try: - if connection == Dandelion().objectChildStem(inv[1]): - # Fluff trigger by RNG - # auto-ignore if config set to 0, i.e. dandelion is off - if randint(1, 100) >= state.dandelion: - fluffs.append(inv[1]) - # send a dinv only if the stem node supports dandelion - elif connection.services & protocol.NODE_DANDELION > 0: - stems.append(inv[1]) - else: - fluffs.append(inv[1]) - except KeyError: - fluffs.append(inv[1]) - - if fluffs: - shuffle(fluffs) - connection.append_write_buf(protocol.CreatePacket('inv', \ - addresses.encodeVarint(len(fluffs)) + "".join(fluffs))) - if stems: - shuffle(stems) - connection.append_write_buf(protocol.CreatePacket('dinv', \ - addresses.encodeVarint(len(stems)) + "".join(stems))) - - invQueue.iterate() - for i in range(len(chunk)): - invQueue.task_done() - - if Dandelion().refresh < time(): - Dandelion().reRandomiseStems() - - self.stop.wait(1) diff --git a/src/network/networkthread.py b/src/network/networkthread.py deleted file mode 100644 index 5a709c8b..00000000 --- a/src/network/networkthread.py +++ /dev/null @@ -1,40 +0,0 @@ -import threading - -from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import StoppableThread -import network.asyncore_pollchoose as asyncore -from network.connectionpool import BMConnectionPool -import state - -class BMNetworkThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="Asyncore") - self.initStop() - self.name = "Asyncore" - logger.info("init asyncore thread") - - def run(self): - while not self._stopped and state.shutdown == 0: - BMConnectionPool().loop() - - def stopThread(self): - super(BMNetworkThread, self).stopThread() - for i in BMConnectionPool().listeningSockets.values(): - try: - i.close() - except: - pass - for i in BMConnectionPool().outboundConnections.values(): - try: - i.close() - except: - pass - for i in BMConnectionPool().inboundConnections.values(): - try: - i.close() - except: - pass - - # just in case - asyncore.close_all() diff --git a/src/network/node.py b/src/network/node.py deleted file mode 100644 index ab9f5fbe..00000000 --- a/src/network/node.py +++ /dev/null @@ -1,3 +0,0 @@ -import collections - -Node = collections.namedtuple('Node', ['services', 'host', 'port']) diff --git a/src/network/objectracker.py b/src/network/objectracker.py deleted file mode 100644 index 66b0685b..00000000 --- a/src/network/objectracker.py +++ /dev/null @@ -1,129 +0,0 @@ -import time -from threading import RLock - -from inventory import Inventory -import network.connectionpool -from network.dandelion import Dandelion -from randomtrackingdict import RandomTrackingDict -from state import missingObjects - -haveBloom = False - -try: - # pybloomfiltermmap - from pybloomfilter import BloomFilter - haveBloom = True -except ImportError: - try: - # pybloom - from pybloom import BloomFilter - haveBloom = True - except ImportError: - pass - -# it isn't actually implemented yet so no point in turning it on -haveBloom = False - -class ObjectTracker(object): - invCleanPeriod = 300 - invInitialCapacity = 50000 - invErrorRate = 0.03 - trackingExpires = 3600 - initialTimeOffset = 60 - - def __init__(self): - self.objectsNewToMe = RandomTrackingDict() - self.objectsNewToThem = {} - self.objectsNewToThemLock = RLock() - self.initInvBloom() - self.initAddrBloom() - self.lastCleaned = time.time() - - def initInvBloom(self): - if haveBloom: - # lock? - self.invBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, - error_rate=ObjectTracker.invErrorRate) - - def initAddrBloom(self): - if haveBloom: - # lock? - self.addrBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, - error_rate=ObjectTracker.invErrorRate) - - def clean(self): - if self.lastCleaned < time.time() - ObjectTracker.invCleanPeriod: - if haveBloom: - # FIXME - if PendingDownloadQueue().size() == 0: - self.initInvBloom() - self.initAddrBloom() - else: - # release memory - deadline = time.time() - ObjectTracker.trackingExpires - with self.objectsNewToThemLock: - self.objectsNewToThem = {k: v for k, v in self.objectsNewToThem.iteritems() if v >= deadline} - self.lastCleaned = time.time() - - def hasObj(self, hashid): - if haveBloom: - return hashid in self.invBloom - else: - return hashid in self.objectsNewToMe - - def handleReceivedInventory(self, hashId): - if haveBloom: - self.invBloom.add(hashId) - try: - with self.objectsNewToThemLock: - del self.objectsNewToThem[hashId] - except KeyError: - pass - if hashId not in missingObjects: - missingObjects[hashId] = time.time() - self.objectsNewToMe[hashId] = True - - def handleReceivedObject(self, streamNumber, hashid): - for i in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): - if not i.fullyEstablished: - continue - try: - del i.objectsNewToMe[hashid] - except KeyError: - if streamNumber in i.streams and \ - (not Dandelion().hasHash(hashid) or \ - Dandelion().objectChildStem(hashid) == i): - with i.objectsNewToThemLock: - i.objectsNewToThem[hashid] = time.time() - # update stream number, which we didn't have when we just received the dinv - # also resets expiration of the stem mode - Dandelion().setHashStream(hashid, streamNumber) - - if i == self: - try: - with i.objectsNewToThemLock: - del i.objectsNewToThem[hashid] - except KeyError: - pass - - def hasAddr(self, addr): - if haveBloom: - return addr in self.invBloom - - def addAddr(self, hashid): - if haveBloom: - self.addrBloom.add(hashid) - -# addr sending -> per node upload queue, and flush every minute or so -# inv sending -> if not in bloom, inv immediately, otherwise put into a per node upload queue and flush every minute or so -# data sending -> a simple queue - -# no bloom -# - if inv arrives -# - if we don't have it, add tracking and download queue -# - if we do have it, remove from tracking -# tracking downloads -# - per node hash of items the node has but we don't -# tracking inv -# - per node hash of items that neither the remote node nor we have -# diff --git a/src/network/proxy.py b/src/network/proxy.py deleted file mode 100644 index 43298f63..00000000 --- a/src/network/proxy.py +++ /dev/null @@ -1,107 +0,0 @@ -import socket -import time - -from advanceddispatcher import AdvancedDispatcher -import asyncore_pollchoose as asyncore -from debug import logger -import network.connectionpool -import state - -class ProxyError(Exception): - errorCodes = ("UnknownError") - - def __init__(self, code=-1): - self.code = code - try: - self.message = self.__class__.errorCodes[self.code] - except IndexError: - self.message = self.__class__.errorCodes[-1] - super(ProxyError, self).__init__(self.message) - - -class GeneralProxyError(ProxyError): - errorCodes = ("Success", - "Invalid data", - "Not connected", - "Not available", - "Bad proxy type", - "Bad input", - "Timed out", - "Network unreachable", - "Connection refused", - "Host unreachable") - - -class Proxy(AdvancedDispatcher): - # these are global, and if you change config during runtime, all active/new - # instances should change too - _proxy = ("127.0.0.1", 9050) - _auth = None - _onion_proxy = None - _onion_auth = None - _remote_dns = True - - @property - def proxy(self): - return self.__class__._proxy - - @proxy.setter - def proxy(self, address): - if not isinstance(address, tuple) or (len(address) < 2) or \ - (not isinstance(address[0], str) or not isinstance(address[1], int)): - raise ValueError - self.__class__._proxy = address - - @property - def auth(self): - return self.__class__._auth - - @auth.setter - def auth(self, authTuple): - self.__class__._auth = authTuple - - @property - def onion_proxy(self): - return self.__class__._onion_proxy - - @onion_proxy.setter - def onion_proxy(self, address): - if address is not None and (not isinstance(address, tuple) or (len(address) < 2) or \ - (not isinstance(address[0], str) or not isinstance(address[1], int))): - raise ValueError - self.__class__._onion_proxy = address - - @property - def onion_auth(self): - return self.__class__._onion_auth - - @onion_auth.setter - def onion_auth(self, authTuple): - self.__class__._onion_auth = authTuple - - def __init__(self, address): - if not isinstance(address, state.Peer): - raise ValueError - AdvancedDispatcher.__init__(self) - self.destination = address - self.isOutbound = True - self.fullyEstablished = False - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - if address.host.endswith(".onion") and self.onion_proxy is not None: - self.connect(self.onion_proxy) - else: - self.connect(self.proxy) - - def handle_connect(self): - self.set_state("init") - try: - AdvancedDispatcher.handle_connect(self) - except socket.error as e: - if e.errno in asyncore._DISCONNECTED: - logger.debug("%s:%i: Connection failed: %s", self.destination.host, self.destination.port, str(e)) - return - self.state_init() - - def state_proxy_handshake_done(self): - self.connectedAt = time.time() - return False diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py deleted file mode 100644 index 5399b972..00000000 --- a/src/network/receivequeuethread.py +++ /dev/null @@ -1,53 +0,0 @@ -import errno -import Queue -import socket -import sys -import threading -import time - -import addresses -from bmconfigparser import BMConfigParser -from debug import logger -from helper_threading import StoppableThread -from inventory import Inventory -from network.connectionpool import BMConnectionPool -from network.bmproto import BMProto -from queues import receiveDataQueue -import protocol -import state - -class ReceiveQueueThread(threading.Thread, StoppableThread): - def __init__(self, num=0): - threading.Thread.__init__(self, name="ReceiveQueue_%i" %(num)) - self.initStop() - self.name = "ReceiveQueue_%i" % (num) - logger.info("init receive queue thread %i", num) - - def run(self): - while not self._stopped and state.shutdown == 0: - try: - dest = receiveDataQueue.get(block=True, timeout=1) - except Queue.Empty: - continue - - if self._stopped or state.shutdown: - break - - # cycle as long as there is data - # methods should return False if there isn't enough data, or the connection is to be aborted - - # state_* methods should return False if there isn't enough data, - # or the connection is to be aborted - - try: - BMConnectionPool().getConnectionByAddr(dest).process() - # KeyError = connection object not found - # AttributeError = state isn't implemented - except (KeyError, AttributeError): - pass - except socket.error as err: - if err.errno == errno.EBADF: - BMConnectionPool().getConnectionByAddr(dest).set_state("close", 0) - else: - logger.error("Socket error: %s", str(err)) - receiveDataQueue.task_done() diff --git a/src/network/socks4a.py b/src/network/socks4a.py deleted file mode 100644 index 978ede04..00000000 --- a/src/network/socks4a.py +++ /dev/null @@ -1,111 +0,0 @@ -import socket -import struct - -from proxy import Proxy, ProxyError, GeneralProxyError - -class Socks4aError(ProxyError): - errorCodes = ("Request granted", - "Request rejected or failed", - "Request rejected because SOCKS server cannot connect to identd on the client", - "Request rejected because the client program and identd report different user-ids", - "Unknown error") - - -class Socks4a(Proxy): - def __init__(self, address=None): - Proxy.__init__(self, address) - self.ipaddr = None - self.destport = address[1] - - def state_init(self): - self.set_state("auth_done", 0) - return True - - def state_pre_connect(self): - # Get the response - if self.read_buf[0:1] != chr(0x00).encode(): - # bad data - self.close() - raise GeneralProxyError(1) - elif self.read_buf[1:2] != chr(0x5A).encode(): - # Connection failed - self.close() - if ord(self.read_buf[1:2]) in (91, 92, 93): - # socks 4 error - raise Socks4aError(ord(self.read_buf[1:2]) - 90) - else: - raise Socks4aError(4) - # Get the bound address/port - self.boundport = struct.unpack(">H", self.read_buf[2:4])[0] - self.boundaddr = self.read_buf[4:] - self.__proxysockname = (self.boundaddr, self.boundport) - if self.ipaddr: - self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) - else: - self.__proxypeername = (self.destination[0], self.destport) - self.set_state("proxy_handshake_done", length=8) - return True - - def proxy_sock_name(self): - return socket.inet_ntoa(self.__proxysockname[0]) - - -class Socks4aConnection(Socks4a): - def __init__(self, address): - Socks4a.__init__(self, address=address) - - def state_auth_done(self): - # Now we can request the actual connection - rmtrslv = False - self.append_write_buf(struct.pack('>BBH', 0x04, 0x01, self.destination[1])) - # If the given destination address is an IP address, we'll - # use the IPv4 address request even if remote resolving was specified. - try: - self.ipaddr = socket.inet_aton(self.destination[0]) - self.append_write_buf(self.ipaddr) - except socket.error: - # Well it's not an IP number, so it's probably a DNS name. - if Proxy._remote_dns: - # Resolve remotely - rmtrslv = True - self.ipaddr = None - self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)) - else: - # Resolve locally - self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) - self.append_write_buf(self.ipaddr) - if self._auth: - self.append_write_buf(self._auth[0]) - self.append_write_buf(chr(0x00).encode()) - if rmtrslv: - self.append_write_buf(self.destination[0] + chr(0x00).encode()) - self.set_state("pre_connect", length=0, expectBytes=8) - return True - - def state_pre_connect(self): - try: - return Socks4a.state_pre_connect(self) - except Socks4aError as e: - self.close_reason = e.message - self.set_state("close") - - -class Socks4aResolver(Socks4a): - def __init__(self, host): - self.host = host - self.port = 8444 - Socks4a.__init__(self, address=(self.host, self.port)) - - def state_auth_done(self): - # Now we can request the actual connection - self.append_write_buf(struct.pack('>BBH', 0x04, 0xF0, self.destination[1])) - self.append_write_buf(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)) - if self._auth: - self.append_write_buf(self._auth[0]) - self.append_write_buf(chr(0x00).encode()) - self.append_write_buf(self.host + chr(0x00).encode()) - self.set_state("pre_connect", length=0, expectBytes=8) - return True - - def resolved(self): - print "Resolved %s as %s" % (self.host, self.proxy_sock_name()) diff --git a/src/network/socks5.py b/src/network/socks5.py deleted file mode 100644 index 52050ec9..00000000 --- a/src/network/socks5.py +++ /dev/null @@ -1,176 +0,0 @@ -import socket -import struct - -from proxy import Proxy, ProxyError, GeneralProxyError - -class Socks5AuthError(ProxyError): - errorCodes = ("Succeeded", - "Authentication is required", - "All offered authentication methods were rejected", - "Unknown username or invalid password", - "Unknown error") - - -class Socks5Error(ProxyError): - errorCodes = ("Succeeded", - "General SOCKS server failure", - "Connection not allowed by ruleset", - "Network unreachable", - "Host unreachable", - "Connection refused", - "TTL expired", - "Command not supported", - "Address type not supported", - "Unknown error") - - -class Socks5(Proxy): - def __init__(self, address=None): - Proxy.__init__(self, address) - self.ipaddr = None - self.destport = address[1] - - def state_init(self): - if self._auth: - self.append_write_buf(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) - else: - self.append_write_buf(struct.pack('BBB', 0x05, 0x01, 0x00)) - self.set_state("auth_1", length=0, expectBytes=2) - return True - - def state_auth_1(self): - ret = struct.unpack('BB', self.read_buf) - if ret[0] != 5: - # general error - raise GeneralProxyError(1) - elif ret[1] == 0: - # no auth required - self.set_state("auth_done", length=2) - elif ret[1] == 2: - # username/password - self.append_write_buf(struct.pack('BB', 1, len(self._auth[0])) + \ - self._auth[0] + struct.pack('B', len(self._auth[1])) + \ - self._auth[1]) - self.set_state("auth_needed", length=2, expectBytes=2) - else: - if ret[1] == 0xff: - # auth error - raise Socks5AuthError(2) - else: - # other error - raise GeneralProxyError(1) - return True - - def state_auth_needed(self): - ret = struct.unpack('BB', self.read_buf[0:2]) - if ret[0] != 1: - # general error - raise GeneralProxyError(1) - if ret[1] != 0: - # auth error - raise Socks5AuthError(3) - # all ok - self.set_state("auth_done", length=2) - return True - - def state_pre_connect(self): - # Get the response - if self.read_buf[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError(1) - elif self.read_buf[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(self.read_buf[1:2])<=8: - raise Socks5Error(ord(self.read_buf[1:2])) - else: - raise Socks5Error(9) - # Get the bound address/port - elif self.read_buf[3:4] == chr(0x01).encode(): - self.set_state("proxy_addr_1", length=4, expectBytes=4) - elif self.read_buf[3:4] == chr(0x03).encode(): - self.set_state("proxy_addr_2_1", length=4, expectBytes=1) - else: - self.close() - raise GeneralProxyError(1) - return True - - def state_proxy_addr_1(self): - self.boundaddr = self.read_buf[0:4] - self.set_state("proxy_port", length=4, expectBytes=2) - return True - - def state_proxy_addr_2_1(self): - self.address_length = ord(self.read_buf[0:1]) - self.set_state("proxy_addr_2_2", length=1, expectBytes=self.address_length) - return True - - def state_proxy_addr_2_2(self): - self.boundaddr = self.read_buf[0:self.address_length] - self.set_state("proxy_port", length=self.address_length, expectBytes=2) - return True - - def state_proxy_port(self): - self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] - self.__proxysockname = (self.boundaddr, self.boundport) - if self.ipaddr is not None: - self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) - else: - self.__proxypeername = (self.destination[0], self.destport) - self.set_state("proxy_handshake_done", length=2) - return True - - def proxy_sock_name(self): - return socket.inet_ntoa(self.__proxysockname[0]) - - -class Socks5Connection(Socks5): - def __init__(self, address): - Socks5.__init__(self, address=address) - - def state_auth_done(self): - # Now we can request the actual connection - self.append_write_buf(struct.pack('BBB', 0x05, 0x01, 0x00)) - # If the given destination address is an IP address, we'll - # use the IPv4 address request even if remote resolving was specified. - try: - self.ipaddr = socket.inet_aton(self.destination[0]) - self.append_write_buf(chr(0x01).encode() + self.ipaddr) - except socket.error: - # Well it's not an IP number, so it's probably a DNS name. - if Proxy._remote_dns: - # Resolve remotely - self.ipaddr = None - self.append_write_buf(chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]) - else: - # Resolve locally - self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) - self.append_write_buf(chr(0x01).encode() + self.ipaddr) - self.append_write_buf(struct.pack(">H", self.destination[1])) - self.set_state("pre_connect", length=0, expectBytes=4) - return True - - def state_pre_connect(self): - try: - return Socks5.state_pre_connect(self) - except Socks5Error as e: - self.close_reason = e.message - self.set_state("close") - - -class Socks5Resolver(Socks5): - def __init__(self, host): - self.host = host - self.port = 8444 - Socks5.__init__(self, address=(self.host, self.port)) - - def state_auth_done(self): - # Now we can request the actual connection - self.append_write_buf(struct.pack('BBB', 0x05, 0xF0, 0x00)) - self.append_write_buf(chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host)) - self.append_write_buf(struct.pack(">H", self.port)) - self.set_state("pre_connect", length=0, expectBytes=4) - return True - - def resolved(self): - print "Resolved %s as %s" % (self.host, self.proxy_sock_name()) diff --git a/src/network/stats.py b/src/network/stats.py deleted file mode 100644 index 80925f7c..00000000 --- a/src/network/stats.py +++ /dev/null @@ -1,70 +0,0 @@ -import time - -from network.connectionpool import BMConnectionPool -import asyncore_pollchoose as asyncore -from state import missingObjects - -lastReceivedTimestamp = time.time() -lastReceivedBytes = 0 -currentReceivedSpeed = 0 -lastSentTimestamp = time.time() -lastSentBytes = 0 -currentSentSpeed = 0 - -def connectedHostsList(): - retval = [] - for i in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): - if not i.fullyEstablished: - continue - try: - retval.append(i) - except AttributeError: - pass - return retval - -def sentBytes(): - return asyncore.sentBytes - -def uploadSpeed(): - global lastSentTimestamp, lastSentBytes, currentSentSpeed - currentTimestamp = time.time() - if int(lastSentTimestamp) < int(currentTimestamp): - currentSentBytes = asyncore.sentBytes - currentSentSpeed = int((currentSentBytes - lastSentBytes) / (currentTimestamp - lastSentTimestamp)) - lastSentBytes = currentSentBytes - lastSentTimestamp = currentTimestamp - return currentSentSpeed - -def receivedBytes(): - return asyncore.receivedBytes - -def downloadSpeed(): - global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed - currentTimestamp = time.time() - if int(lastReceivedTimestamp) < int(currentTimestamp): - currentReceivedBytes = asyncore.receivedBytes - currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / - (currentTimestamp - lastReceivedTimestamp)) - lastReceivedBytes = currentReceivedBytes - lastReceivedTimestamp = currentTimestamp - return currentReceivedSpeed - -def pendingDownload(): - return len(missingObjects) - #tmp = {} - #for connection in BMConnectionPool().inboundConnections.values() + \ - # BMConnectionPool().outboundConnections.values(): - # for k in connection.objectsNewToMe.keys(): - # tmp[k] = True - #return len(tmp) - -def pendingUpload(): - #tmp = {} - #for connection in BMConnectionPool().inboundConnections.values() + \ - # BMConnectionPool().outboundConnections.values(): - # for k in connection.objectsNewToThem.keys(): - # tmp[k] = True - #This probably isn't the correct logic so it's disabled - #return len(tmp) - return 0 diff --git a/src/network/tcp.py b/src/network/tcp.py deleted file mode 100644 index 33c4b6ca..00000000 --- a/src/network/tcp.py +++ /dev/null @@ -1,325 +0,0 @@ -import base64 -from binascii import hexlify -import hashlib -import math -import time -from pprint import pprint -import socket -import struct -import random -import traceback - -from addresses import calculateInventoryHash -from debug import logger -from helper_random import randomBytes -from inventory import Inventory -import knownnodes -from network.advanceddispatcher import AdvancedDispatcher -from network.bmproto import BMProtoError, BMProtoInsufficientDataError, BMProtoExcessiveDataError, BMProto -from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError -import network.connectionpool -from network.dandelion import Dandelion -from network.node import Node -import network.asyncore_pollchoose as asyncore -from network.proxy import Proxy, ProxyError, GeneralProxyError -from network.objectracker import ObjectTracker -from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error -from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError -from network.tls import TLSDispatcher - -import addresses -from bmconfigparser import BMConfigParser -from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue, receiveDataQueue -import shared -import state -import protocol - -class TCPConnection(BMProto, TLSDispatcher): - def __init__(self, address=None, sock=None): - BMProto.__init__(self, address=address, sock=sock) - self.verackReceived = False - self.verackSent = False - self.streams = [0] - self.fullyEstablished = False - self.connectedAt = 0 - self.skipUntil = 0 - if address is None and sock is not None: - self.destination = state.Peer(sock.getpeername()[0], sock.getpeername()[1]) - self.isOutbound = False - TLSDispatcher.__init__(self, sock, server_side=True) - self.connectedAt = time.time() - logger.debug("Received connection from %s:%i", self.destination.host, self.destination.port) - self.nodeid = randomBytes(8) - elif address is not None and sock is not None: - TLSDispatcher.__init__(self, sock, server_side=False) - self.isOutbound = True - logger.debug("Outbound proxy connection to %s:%i", self.destination.host, self.destination.port) - else: - self.destination = address - self.isOutbound = True - if ":" in address.host: - self.create_socket(socket.AF_INET6, socket.SOCK_STREAM) - else: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - TLSDispatcher.__init__(self, sock, server_side=False) - self.connect(self.destination) - logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port) - encodedAddr = protocol.encodeHost(self.destination.host) - if protocol.checkIPAddress(encodedAddr, True) and not protocol.checkSocksIP(self.destination.host): - self.local = True - else: - self.local = False - #shared.connectedHostsList[self.destination] = 0 - ObjectTracker.__init__(self) - self.bm_proto_reset() - self.set_state("bm_header", expectBytes=protocol.Header.size) - - def antiIntersectionDelay(self, initial = False): - # estimated time for a small object to propagate across the whole network - delay = math.ceil(math.log(max(len(knownnodes.knownNodes[x]) for x in knownnodes.knownNodes) + 2, 20)) * (0.2 + invQueue.queueCount/2.0) - # take the stream with maximum amount of nodes - # +2 is to avoid problems with log(0) and log(1) - # 20 is avg connected nodes count - # 0.2 is avg message transmission time - if delay > 0: - if initial: - self.skipUntil = self.connectedAt + delay - if self.skipUntil > time.time(): - logger.debug("Initial skipping processing getdata for %.2fs", self.skipUntil - time.time()) - else: - logger.debug("Skipping processing getdata due to missing object for %.2fs", delay) - self.skipUntil = time.time() + delay - - def state_connection_fully_established(self): - self.set_connection_fully_established() - self.set_state("bm_header") - self.bm_proto_reset() - return True - - def set_connection_fully_established(self): - if not self.isOutbound and not self.local: - shared.clientHasReceivedIncomingConnections = True - UISignalQueue.put(('setStatusIcon', 'green')) - UISignalQueue.put(('updateNetworkStatusTab', (self.isOutbound, True, self.destination))) - self.antiIntersectionDelay(True) - self.fullyEstablished = True - if self.isOutbound: - knownnodes.increaseRating(self.destination) - if self.isOutbound: - Dandelion().maybeAddStem(self) - self.sendAddr() - self.sendBigInv() - - def sendAddr(self): - # We are going to share a maximum number of 1000 addrs (per overlapping - # stream) with our peer. 500 from overlapping streams, 250 from the - # left child stream, and 250 from the right child stream. - maxAddrCount = BMConfigParser().safeGetInt("bitmessagesettings", "maxaddrperstreamsend", 500) - - # init - addressCount = 0 - payload = b'' - - templist = [] - addrs = {} - for stream in self.streams: - with knownnodes.knownNodesLock: - if len(knownnodes.knownNodes[stream]) > 0: - filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() - if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount: - elemCount = maxAddrCount - # only if more recent than 3 hours - addrs[stream] = random.sample(filtered.items(), elemCount) - # sent 250 only if the remote isn't interested in it - if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streams: - filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() - if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount / 2: - elemCount = int(maxAddrCount / 2) - addrs[stream * 2] = random.sample(filtered.items(), elemCount) - if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streams: - filtered = {k: v for k, v in knownnodes.knownNodes[stream*2+1].items() - if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} - elemCount = len(filtered) - if elemCount > maxAddrCount / 2: - elemCount = int(maxAddrCount / 2) - addrs[stream * 2 + 1] = random.sample(filtered.items(), elemCount) - for substream in addrs.keys(): - for peer, params in addrs[substream]: - templist.append((substream, peer, params["lastseen"])) - if len(templist) > 0: - self.append_write_buf(BMProto.assembleAddr(templist)) - - def sendBigInv(self): - def sendChunk(): - if objectCount == 0: - return - logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount) - self.append_write_buf(protocol.CreatePacket('inv', addresses.encodeVarint(objectCount) + payload)) - - # Select all hashes for objects in this stream. - bigInvList = {} - for stream in self.streams: - # may lock for a long time, but I think it's better than thousands of small locks - with self.objectsNewToThemLock: - for objHash in Inventory().unexpired_hashes_by_stream(stream): - # don't advertise stem objects on bigInv - if Dandelion().hasHash(objHash): - continue - bigInvList[objHash] = 0 - self.objectsNewToThem[objHash] = time.time() - objectCount = 0 - payload = b'' - # Now let us start appending all of these hashes together. They will be - # sent out in a big inv message to our new peer. - for hash, storedValue in bigInvList.items(): - payload += hash - objectCount += 1 - if objectCount >= BMProto.maxObjectCount: - sendChunk() - payload = b'' - objectCount = 0 - - # flush - sendChunk() - - def handle_connect(self): - try: - AdvancedDispatcher.handle_connect(self) - except socket.error as e: - if e.errno in asyncore._DISCONNECTED: - logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e))) - return - self.nodeid = randomBytes(8) - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ - network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid)) - #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) - self.connectedAt = time.time() - receiveDataQueue.put(self.destination) - - def handle_read(self): - TLSDispatcher.handle_read(self) - if self.isOutbound and self.fullyEstablished: - for s in self.streams: - try: - with knownnodes.knownNodesLock: - knownnodes.knownNodes[s][self.destination]["lastseen"] = time.time() - except KeyError: - pass - receiveDataQueue.put(self.destination) - - def handle_write(self): - TLSDispatcher.handle_write(self) - - def handle_close(self): - if self.isOutbound and not self.fullyEstablished: - knownnodes.decreaseRating(self.destination) - if self.fullyEstablished: - UISignalQueue.put(('updateNetworkStatusTab', (self.isOutbound, False, self.destination))) - if self.isOutbound: - Dandelion().maybeRemoveStem(self) - BMProto.handle_close(self) - - -class Socks5BMConnection(Socks5Connection, TCPConnection): - def __init__(self, address): - Socks5Connection.__init__(self, address=address) - TCPConnection.__init__(self, address=address, sock=self.socket) - self.set_state("init") - - def state_proxy_handshake_done(self): - Socks5Connection.state_proxy_handshake_done(self) - self.nodeid = randomBytes(8) - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ - network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid)) - self.set_state("bm_header", expectBytes=protocol.Header.size) - return True - - -class Socks4aBMConnection(Socks4aConnection, TCPConnection): - def __init__(self, address): - Socks4aConnection.__init__(self, address=address) - TCPConnection.__init__(self, address=address, sock=self.socket) - self.set_state("init") - - def state_proxy_handshake_done(self): - Socks4aConnection.state_proxy_handshake_done(self) - self.nodeid = randomBytes(8) - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ - network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid)) - self.set_state("bm_header", expectBytes=protocol.Header.size) - return True - - -class TCPServer(AdvancedDispatcher): - def __init__(self, host='127.0.0.1', port=8444): - if not hasattr(self, '_map'): - AdvancedDispatcher.__init__(self) - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - for attempt in range(50): - try: - if attempt > 0: - port = random.randint(32767, 65535) - self.bind((host, port)) - except socket.error as e: - if e.errno in (asyncore.EADDRINUSE, asyncore.WSAEADDRINUSE): - continue - else: - if attempt > 0: - BMConfigParser().set("bitmessagesettings", "port", str(port)) - BMConfigParser().save() - break - self.destination = state.Peer(host, port) - self.bound = True - self.listen(5) - - def is_bound(self): - try: - return self.bound - except AttributeError: - return False - - def handle_accept(self): - pair = self.accept() - if pair is not None: - sock, addr = pair - state.ownAddresses[state.Peer(sock.getsockname()[0], sock.getsockname()[1])] = True - if len(network.connectionpool.BMConnectionPool().inboundConnections) + \ - len(network.connectionpool.BMConnectionPool().outboundConnections) > \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections") + 10: - # 10 is a sort of buffer, in between it will go through the version handshake - # and return an error to the peer - logger.warning("Server full, dropping connection") - sock.close() - return - try: - network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock)) - except socket.error: - pass - - -if __name__ == "__main__": - # initial fill - - for host in (("127.0.0.1", 8448),): - direct = TCPConnection(host) - while len(asyncore.socket_map) > 0: - print "loop, state = %s" % (direct.state) - asyncore.loop(timeout=10, count=1) - continue - - proxy = Socks5BMConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=10, count=1) - - proxy = Socks4aBMConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=10, count=1) diff --git a/src/network/tls.py b/src/network/tls.py deleted file mode 100644 index 379dae99..00000000 --- a/src/network/tls.py +++ /dev/null @@ -1,173 +0,0 @@ -""" -SSL/TLS negotiation. -""" - -import os -import socket -import ssl -import sys - -from debug import logger -from network.advanceddispatcher import AdvancedDispatcher -import network.asyncore_pollchoose as asyncore -from queues import receiveDataQueue -import paths -import protocol - -_DISCONNECTED_SSL = frozenset((ssl.SSL_ERROR_EOF,)) - -class TLSDispatcher(AdvancedDispatcher): - def __init__(self, address=None, sock=None, - certfile=None, keyfile=None, server_side=False, ciphers=protocol.sslProtocolCiphers): - self.want_read = self.want_write = True - if certfile is None: - self.certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem') - else: - self.certfile = certfile - if keyfile is None: - self.keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem') - else: - self.keyfile = keyfile - self.server_side = server_side - self.ciphers = ciphers - self.tlsStarted = False - self.tlsDone = False - self.tlsVersion = "N/A" - self.isSSL = False - - def state_tls_init(self): - self.isSSL = True - self.tlsStarted = True - # Once the connection has been established, it's safe to wrap the - # socket. - if sys.version_info >= (2,7,9): - context = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH) - context.set_ciphers(self.ciphers) - context.set_ecdh_curve("secp256k1") - context.check_hostname = False - context.verify_mode = ssl.CERT_NONE - # also exclude TLSv1 and TLSv1.1 in the future - context.options = ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_SINGLE_ECDH_USE | ssl.OP_CIPHER_SERVER_PREFERENCE - self.sslSocket = context.wrap_socket(self.socket, server_side = self.server_side, do_handshake_on_connect=False) - else: - self.sslSocket = ssl.wrap_socket(self.socket, - server_side=self.server_side, - ssl_version=protocol.sslProtocolVersion, - certfile=self.certfile, - keyfile=self.keyfile, - ciphers=self.ciphers, - do_handshake_on_connect=False) - self.sslSocket.setblocking(0) - self.want_read = self.want_write = True - self.set_state("tls_handshake") - return False -# if hasattr(self.socket, "context"): -# self.socket.context.set_ecdh_curve("secp256k1") - - def state_tls_handshake(self): - return False - - def writable(self): - try: - if self.tlsStarted and not self.tlsDone and not self.write_buf: - return self.want_write - return AdvancedDispatcher.writable(self) - except AttributeError: - return AdvancedDispatcher.writable(self) - - def readable(self): - try: - # during TLS handshake, and after flushing write buffer, return status of last handshake attempt - if self.tlsStarted and not self.tlsDone and not self.write_buf: - #print "tls readable, %r" % (self.want_read) - return self.want_read - # prior to TLS handshake, receiveDataThread should emulate synchronous behaviour - elif not self.fullyEstablished and (self.expectBytes == 0 or not self.write_buf_empty()): - return False - return AdvancedDispatcher.readable(self) - except AttributeError: - return AdvancedDispatcher.readable(self) - - def handle_read(self): - try: - # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and not self.write_buf: - #logger.debug("%s:%i TLS handshaking (read)", self.destination.host, self.destination.port) - self.tls_handshake() - else: - #logger.debug("%s:%i Not TLS handshaking (read)", self.destination.host, self.destination.port) - return AdvancedDispatcher.handle_read(self) - except AttributeError: - return AdvancedDispatcher.handle_read(self) - except ssl.SSLError as err: - if err.errno == ssl.SSL_ERROR_WANT_READ: - return - elif err.errno in _DISCONNECTED_SSL: - self.handle_close() - return - logger.info("SSL Error: %s", str(err)) - self.handle_close() - return - - def handle_write(self): - try: - # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and not self.write_buf: - #logger.debug("%s:%i TLS handshaking (write)", self.destination.host, self.destination.port) - self.tls_handshake() - else: - #logger.debug("%s:%i Not TLS handshaking (write)", self.destination.host, self.destination.port) - return AdvancedDispatcher.handle_write(self) - except AttributeError: - return AdvancedDispatcher.handle_write(self) - except ssl.SSLError as err: - if err.errno == ssl.SSL_ERROR_WANT_WRITE: - return 0 - elif err.errno in _DISCONNECTED_SSL: - self.handle_close() - return 0 - logger.info("SSL Error: %s", str(err)) - self.handle_close() - return - - def tls_handshake(self): - # wait for flush - if self.write_buf: - return False - # Perform the handshake. - try: - #print "handshaking (internal)" - self.sslSocket.do_handshake() - except ssl.SSLError as err: - #print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) - self.want_read = self.want_write = False - if err.args[0] == ssl.SSL_ERROR_WANT_READ: - #print "want read" - self.want_read = True - if err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - #print "want write" - self.want_write = True - if not (self.want_write or self.want_read): - raise - except socket.error as err: - if err.errno in asyncore._DISCONNECTED: - self.handle_close() - else: - raise - else: - if sys.version_info >= (2, 7, 9): - self.tlsVersion = self.sslSocket.version() - logger.debug("%s:%i: TLS handshake success, TLS protocol version: %s", - self.destination.host, self.destination.port, self.sslSocket.version()) - else: - self.tlsVersion = "TLSv1" - logger.debug("%s:%i: TLS handshake success", self.destination.host, self.destination.port) - # The handshake has completed, so remove this channel and... - self.del_channel() - self.set_socket(self.sslSocket) - self.tlsDone = True - - self.bm_proto_reset() - self.set_state("connection_fully_established") - receiveDataQueue.put(self.destination) - return False diff --git a/src/network/udp.py b/src/network/udp.py deleted file mode 100644 index 0dba5a3f..00000000 --- a/src/network/udp.py +++ /dev/null @@ -1,176 +0,0 @@ -import time -import Queue -import socket - -from debug import logger -from network.advanceddispatcher import AdvancedDispatcher -from network.bmproto import BMProtoError, BMProtoInsufficientDataError, BMProto -from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectInvalidError, BMObjectAlreadyHaveError -import network.asyncore_pollchoose as asyncore -from network.objectracker import ObjectTracker - -from queues import objectProcessorQueue, UISignalQueue, receiveDataQueue -import state -import protocol - -class UDPSocket(BMProto): - port = 8444 - announceInterval = 60 - - def __init__(self, host=None, sock=None, announcing=False): - super(BMProto, self).__init__(sock=sock) - self.verackReceived = True - self.verackSent = True - # TODO sort out streams - self.streams = [1] - self.fullyEstablished = True - self.connectedAt = 0 - self.skipUntil = 0 - if sock is None: - if host is None: - host = '' - if ":" in host: - self.create_socket(socket.AF_INET6, socket.SOCK_DGRAM) - else: - self.create_socket(socket.AF_INET, socket.SOCK_DGRAM) - self.set_socket_reuse() - logger.info("Binding UDP socket to %s:%i", host, UDPSocket.port) - self.socket.bind((host, UDPSocket.port)) - #BINDTODEVICE is only available on linux and requires root - #try: - #print "binding to %s" % (host) - #self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, host) - #except AttributeError: - else: - self.socket = sock - self.set_socket_reuse() - self.listening = state.Peer(self.socket.getsockname()[0], self.socket.getsockname()[1]) - self.destination = state.Peer(self.socket.getsockname()[0], self.socket.getsockname()[1]) - ObjectTracker.__init__(self) - self.connecting = False - self.connected = True - self.announcing = announcing - self.set_state("bm_header", expectBytes=protocol.Header.size) - - def set_socket_reuse(self): - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - try: - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - except AttributeError: - pass - - def state_bm_command(self): - return BMProto.state_bm_command(self) - - # disable most commands before doing research / testing - # only addr (peer discovery), error and object are implemented - - def bm_command_error(self): - return BMProto.bm_command_error(self) - - def bm_command_getdata(self): - return True -# return BMProto.bm_command_getdata(self) - - def bm_command_inv(self): - return True -# return BMProto.bm_command_inv(self) - - def bm_command_object(self): - return BMProto.bm_command_object(self) - - def bm_command_addr(self): -# BMProto.bm_command_object(self) - addresses = self._decode_addr() - # only allow peer discovery from private IPs in order to avoid attacks from random IPs on the internet - if not self.local: - return True - remoteport = False - for i in addresses: - seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(str(ip)) - if stream not in state.streamsInWhichIAmParticipating: - continue - if seenTime < time.time() - BMProto.maxTimeOffset or seenTime > time.time() + BMProto.maxTimeOffset: - continue - if decodedIP is False: - # if the address isn't local, interpret it as the hosts' own announcement - remoteport = port - if remoteport is False: - return True - logger.debug("received peer discovery from %s:%i (port %i):", self.destination.host, self.destination.port, remoteport) - if self.local: - state.discoveredPeers[state.Peer(self.destination.host, remoteport)] = time.time() - return True - - def bm_command_portcheck(self): - return True - - def bm_command_ping(self): - return True - - def bm_command_pong(self): - return True - - def bm_command_verack(self): - return True - - def bm_command_version(self): - return True - - def handle_connect(self): - return - - def writable(self): - return self.write_buf - - def readable(self): - return len(self.read_buf) < AdvancedDispatcher._buf_len - - def handle_read(self): - try: - (recdata, addr) = self.socket.recvfrom(AdvancedDispatcher._buf_len) - except socket.error as e: - logger.error("socket error: %s", str(e)) - return - - self.destination = state.Peer(addr[0], addr[1]) - encodedAddr = protocol.encodeHost(addr[0]) - if protocol.checkIPAddress(encodedAddr, True): - self.local = True - else: - self.local = False - # overwrite the old buffer to avoid mixing data and so that self.local works correctly - self.read_buf[0:] = recdata - self.bm_proto_reset() - receiveDataQueue.put(self.listening) - - def handle_write(self): - try: - retval = self.socket.sendto(self.write_buf, ('', UDPSocket.port)) - except socket.error as e: - logger.error("socket error on sendato: %s", str(e)) - retval = 0 - self.slice_write_buf(retval) - - -if __name__ == "__main__": - # initial fill - - for host in (("127.0.0.1", 8448),): - direct = BMConnection(host) - while len(asyncore.socket_map) > 0: - print "loop, state = %s" % (direct.state) - asyncore.loop(timeout=10, count=1) - continue - - proxy = Socks5BMConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=10, count=1) - - proxy = Socks4aBMConnection(host) - while len(asyncore.socket_map) > 0: -# print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=10, count=1) diff --git a/src/openclpow.py b/src/openclpow.py deleted file mode 100644 index 894a5b77..00000000 --- a/src/openclpow.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python2.7 -from struct import pack, unpack -import time -import hashlib -import random -import os - -from bmconfigparser import BMConfigParser -import paths -from state import shutdown -from debug import logger - -libAvailable = True -ctx = False -queue = False -program = False -gpus = [] -enabledGpus = [] -vendors = [] -hash_dt = None - -try: - import numpy - import pyopencl as cl -except: - libAvailable = False - -def initCL(): - global ctx, queue, program, hash_dt, libAvailable - if libAvailable is False: - return - del enabledGpus[:] - del vendors[:] - del gpus[:] - ctx = False - try: - hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) - try: - for platform in cl.get_platforms(): - gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if BMConfigParser().safeGet("bitmessagesettings", "opencl") == platform.vendor: - enabledGpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if platform.vendor not in vendors: - vendors.append(platform.vendor) - except: - pass - if (len(enabledGpus) > 0): - ctx = cl.Context(devices=enabledGpus) - queue = cl.CommandQueue(ctx) - f = open(os.path.join(paths.codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') - fstr = ''.join(f.readlines()) - program = cl.Program(ctx, fstr).build(options="") - logger.info("Loaded OpenCL kernel") - else: - logger.info("No OpenCL GPUs found") - del enabledGpus[:] - except Exception as e: - logger.error("OpenCL fail: ", exc_info=True) - del enabledGpus[:] - -def openclAvailable(): - return (len(gpus) > 0) - -def openclEnabled(): - return (len(enabledGpus) > 0) - -def do_opencl_pow(hash, target): - output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) - if (len(enabledGpus) == 0): - return output[0][0] - - data = numpy.zeros(1, dtype=hash_dt, order='C') - data[0]['v'] = ("0000000000000000" + hash).decode("hex") - data[0]['target'] = target - - hash_buf = cl.Buffer(ctx, cl.mem_flags.READ_ONLY | cl.mem_flags.COPY_HOST_PTR, hostbuf=data) - dest_buf = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, output.nbytes) - - kernel = program.kernel_sha512 - worksize = kernel.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, enabledGpus[0]) - - kernel.set_arg(0, hash_buf) - kernel.set_arg(1, dest_buf) - - start = time.time() - progress = 0 - globamt = worksize*2000 - - while output[0][0] == 0 and shutdown == 0: - kernel.set_arg(2, pack("Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - print "{} - value {} < {}".format(nonce, trialValue, target) - diff --git a/src/paths.py b/src/paths.py deleted file mode 100644 index 325fcd8b..00000000 --- a/src/paths.py +++ /dev/null @@ -1,114 +0,0 @@ -from os import environ, path -import sys -import re -from datetime import datetime - -# When using py2exe or py2app, the variable frozen is added to the sys -# namespace. This can be used to setup a different code path for -# binary distributions vs source distributions. -frozen = getattr(sys,'frozen', None) - -def lookupExeFolder(): - if frozen: - if frozen == "macosx_app": - # targetdir/Bitmessage.app/Contents/MacOS/Bitmessage - exeFolder = path.dirname(path.dirname(path.dirname(path.dirname(sys.executable)))) + path.sep - else: - exeFolder = path.dirname(sys.executable) + path.sep - elif __file__: - exeFolder = path.dirname(__file__) + path.sep - else: - exeFolder = '' - return exeFolder - -def lookupAppdataFolder(): - APPNAME = "PyBitmessage" - if "BITMESSAGE_HOME" in environ: - dataFolder = environ["BITMESSAGE_HOME"] - if dataFolder[-1] not in [path.sep, path.altsep]: - dataFolder += path.sep - elif sys.platform == 'darwin': - if "HOME" in environ: - dataFolder = path.join(environ["HOME"], "Library/Application Support/", APPNAME) + '/' - else: - stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.' - if 'logger' in globals(): - logger.critical(stringToLog) - else: - print stringToLog - sys.exit() - - elif 'win32' in sys.platform or 'win64' in sys.platform: - dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep - else: - from shutil import move - try: - dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME) - except KeyError: - dataFolder = path.join(environ["HOME"], ".config", APPNAME) - - # Migrate existing data to the proper location if this is an existing install - try: - move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder) - stringToLog = "Moving data folder to %s" % (dataFolder) - if 'logger' in globals(): - logger.info(stringToLog) - else: - print stringToLog - except IOError: - # Old directory may not exist. - pass - dataFolder = dataFolder + '/' - return dataFolder - -def codePath(): - if frozen == "macosx_app": - codePath = environ.get("RESOURCEPATH") - elif frozen: # windows - codePath = sys._MEIPASS - else: - codePath = path.dirname(__file__) - return codePath - -def tail(f, lines=20): - total_lines_wanted = lines - - BLOCK_SIZE = 1024 - f.seek(0, 2) - block_end_byte = f.tell() - lines_to_go = total_lines_wanted - block_number = -1 - blocks = [] # blocks of size BLOCK_SIZE, in reverse order starting - # from the end of the file - while lines_to_go > 0 and block_end_byte > 0: - if (block_end_byte - BLOCK_SIZE > 0): - # read the last block we haven't yet read - f.seek(block_number*BLOCK_SIZE, 2) - blocks.append(f.read(BLOCK_SIZE)) - else: - # file too small, start from begining - f.seek(0,0) - # only read what was not read - blocks.append(f.read(block_end_byte)) - lines_found = blocks[-1].count('\n') - lines_to_go -= lines_found - block_end_byte -= BLOCK_SIZE - block_number -= 1 - all_read_text = ''.join(reversed(blocks)) - return '\n'.join(all_read_text.splitlines()[-total_lines_wanted:]) - - -def lastCommit(): - githeadfile = path.join(codePath(), '..', '.git', 'logs', 'HEAD') - result = {} - if path.isfile(githeadfile): - try: - with open(githeadfile, 'rt') as githead: - line = tail(githead, 1) - result['commit'] = line.split()[1] - result['time'] = datetime.fromtimestamp( - float(re.search(r'>\s*(.*?)\s', line).group(1)) - ) - except (IOError, AttributeError, TypeError): - pass - return result diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/plugins/indicator_libmessaging.py b/src/plugins/indicator_libmessaging.py deleted file mode 100644 index 36178663..00000000 --- a/src/plugins/indicator_libmessaging.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- - -import gi -gi.require_version('MessagingMenu', '1.0') # noqa:E402 -from gi.repository import MessagingMenu - -from pybitmessage.bitmessageqt.utils import str_broadcast_subscribers -from pybitmessage.tr import _translate - - -class IndicatorLibmessaging(object): - def __init__(self, form): - try: - self.app = MessagingMenu.App(desktop_id='pybitmessage.desktop') - self.app.register() - self.app.connect('activate-source', self.activate) - except: - self.app = None - return - - self._menu = { - 'send': unicode(_translate('MainWindow', 'Send')), - 'messages': unicode(_translate('MainWindow', 'Messages')), - 'subscriptions': unicode(_translate('MainWindow', 'Subscriptions')) - } - - self.new_message_item = self.new_broadcast_item = None - self.form = form - self.show_unread() - - def __del__(self): - if self.app: - self.app.unregister() - - def activate(self, app, source): - self.form.appIndicatorInbox( - self.new_message_item if source == 'messages' - else self.new_broadcast_item - ) - - # show the number of unread messages and subscriptions - # on the messaging menu - def show_unread(self, draw_attention=False): - for source, count in zip( - ('messages', 'subscriptions'), - self.form.getUnread() - ): - if count > 0: - if self.app.has_source(source): - self.app.set_source_count(source, count) - else: - self.app.append_source_with_count( - source, None, self._menu[source], count) - if draw_attention: - self.app.draw_attention(source) - - # update the Ubuntu messaging menu - def __call__(self, draw_attention, item=None, to_label=None): - if not self.app: - return - # remember this item to that the activate() can find it - if item: - if to_label == str_broadcast_subscribers: - self.new_broadcast_item = item - else: - self.new_message_item = item - - self.show_unread(draw_attention) - - -connect_plugin = IndicatorLibmessaging diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py deleted file mode 100644 index 3fd935c4..00000000 --- a/src/plugins/notification_notify2.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -import gi -gi.require_version('Notify', '0.7') -from gi.repository import Notify - -Notify.init('pybitmessage') - -def connect_plugin(title, subtitle, category, label, icon): - if not icon: - icon = 'mail-message-new' if category == 2 else 'pybitmessage' - connect_plugin.notification.update(title, subtitle, icon) - connect_plugin.notification.show() - -connect_plugin.notification = Notify.Notification.new("Init", "Init") diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py deleted file mode 100644 index 6601adaf..00000000 --- a/src/plugins/plugin.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -import pkg_resources - - -def get_plugins(group, point='', name=None, fallback=None): - """ - Iterate through plugins (`connect_plugin` attribute of entry point) - which name starts with `point` or equals to `name`. - If `fallback` kwarg specified, plugin with that name yield last. - """ - for ep in pkg_resources.iter_entry_points('bitmessage.' + group): - if name and ep.name == name or ep.name.startswith(point): - try: - plugin = ep.load().connect_plugin - if ep.name == fallback: - _fallback = plugin - else: - yield plugin - except (AttributeError, - ImportError, - ValueError, - pkg_resources.DistributionNotFound, - pkg_resources.UnknownExtra): - continue - try: - yield _fallback - except NameError: - pass - - -def get_plugin(*args, **kwargs): - """Returns first available plugin `from get_plugins()` if any.""" - for plugin in get_plugins(*args, **kwargs): - return plugin diff --git a/src/plugins/qrcodeui.py b/src/plugins/qrcodeui.py deleted file mode 100644 index 25b1e0b1..00000000 --- a/src/plugins/qrcodeui.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- - -from PyQt4 import QtGui, QtCore -import qrcode - -from pybitmessage.tr import translateText - -try: - _fromUtf8 = QtCore.QString.fromUtf8 -except AttributeError: - _fromUtf8 = lambda s: s - - -# http://stackoverflow.com/questions/20452486 -class Image(qrcode.image.base.BaseImage): - def __init__(self, border, width, box_size): - self.border = border - self.width = width - self.box_size = box_size - size = (width + border * 2) * box_size - self._image = QtGui.QImage( - size, size, QtGui.QImage.Format_RGB16) - self._image.fill(QtCore.Qt.white) - - def pixmap(self): - return QtGui.QPixmap.fromImage(self._image) - - def drawrect(self, row, col): - painter = QtGui.QPainter(self._image) - painter.fillRect( - (col + self.border) * self.box_size, - (row + self.border) * self.box_size, - self.box_size, self.box_size, - QtCore.Qt.black) - - def save(self, stream, kind=None): - pass - - -class Ui_qrcodeDialog(object): - def setupUi(self, qrcodeDialog): - qrcodeDialog.setObjectName(_fromUtf8("qrcodeDialog")) - self.image = QtGui.QLabel(qrcodeDialog) - self.label = QtGui.QLabel(qrcodeDialog) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label.setFont(font) - self.label.setAlignment( - QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter) - self.buttonBox = QtGui.QDialogButtonBox(qrcodeDialog) - self.buttonBox.setOrientation(QtCore.Qt.Horizontal) - self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok) - layout = QtGui.QVBoxLayout(qrcodeDialog) - layout.addWidget(self.image) - layout.addWidget(self.label) - layout.addWidget(self.buttonBox) - - self.retranslateUi(qrcodeDialog) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL( - _fromUtf8("accepted()")), qrcodeDialog.accept) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL( - _fromUtf8("rejected()")), qrcodeDialog.reject) - QtCore.QMetaObject.connectSlotsByName(qrcodeDialog) - - def retranslateUi(self, qrcodeDialog): - qrcodeDialog.setWindowTitle(QtGui.QApplication.translate( - "qrcodeDialog", "QR-code", - None, QtGui.QApplication.UnicodeUTF8 - )) - - def render(self, text): - self.label.setText(text) - self.image.setPixmap( - qrcode.make(text, image_factory=Image).pixmap()) - - -class qrcodeDialog(QtGui.QDialog): - - def __init__(self, parent): - QtGui.QWidget.__init__(self, parent) - self.ui = Ui_qrcodeDialog() - self.ui.setupUi(self) - self.parent = parent - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - -def connect_plugin(form): - def on_action_ShowQR(): - form.qrcodeDialogInstance = qrcodeDialog(form) - form.qrcodeDialogInstance.ui.render( - str(form.getCurrentAccount()) - ) - form.qrcodeDialogInstance.exec_() - - form.actionShowQRCode = \ - form.ui.addressContextMenuToolbarYourIdentities.addAction( - translateText("MainWindow", "Show QR-code"), - on_action_ShowQR - ) - form.popMenuYourIdentities.addAction(form.actionShowQRCode) diff --git a/src/plugins/sound_canberra.py b/src/plugins/sound_canberra.py deleted file mode 100644 index 094901ed..00000000 --- a/src/plugins/sound_canberra.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- - -from pybitmessage.bitmessageqt import sound - -import pycanberra - -_canberra = pycanberra.Canberra() - -_theme = { - sound.SOUND_UNKNOWN: 'message-new-email', - sound.SOUND_CONNECTED: 'network-connectivity-established', - sound.SOUND_DISCONNECTED: 'network-connectivity-lost', - sound.SOUND_CONNECTION_GREEN: 'network-connectivity-established' -} - - -def connect_plugin(category, label=None): - try: - _canberra.play(0, pycanberra.CA_PROP_EVENT_ID, _theme[category], None) - except (KeyError, pycanberra.CanberraException): - pass diff --git a/src/plugins/sound_gstreamer.py b/src/plugins/sound_gstreamer.py deleted file mode 100644 index 062da3f9..00000000 --- a/src/plugins/sound_gstreamer.py +++ /dev/null @@ -1,14 +0,0 @@ -# -*- coding: utf-8 -*- - -import gi -gi.require_version('Gst', '1.0') -from gi.repository import Gst # noqa: E402 - -Gst.init(None) -_player = Gst.ElementFactory.make("playbin", "player") - - -def connect_plugin(sound_file): - _player.set_state(Gst.State.NULL) - _player.set_property("uri", "file://" + sound_file) - _player.set_state(Gst.State.PLAYING) diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py deleted file mode 100644 index c8216d07..00000000 --- a/src/plugins/sound_playfile.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - - -try: - import winsound - - def connect_plugin(sound_file): - winsound.PlaySound(sound_file, winsound.SND_FILENAME) -except ImportError: - import os - import subprocess - - play_cmd = {} - - def _subprocess(*args): - FNULL = open(os.devnull, 'wb') - subprocess.call( - args, stdout=FNULL, stderr=subprocess.STDOUT, close_fds=True) - - def connect_plugin(sound_file): - global play_cmd - - ext = os.path.splitext(sound_file)[-1] - try: - return _subprocess(play_cmd[ext], sound_file) - except (KeyError, AttributeError): - pass - - programs = ['gst123', 'gst-play-1.0'] - if ext == '.wav': - programs.append('aplay') - elif ext == '.mp3': - programs += ['mpg123', 'mpg321', 'mpg321-mpg123'] - for cmd in programs: - try: - _subprocess(cmd, sound_file) - except OSError: - pass # log here! - else: - play_cmd[ext] = cmd - break diff --git a/src/proofofwork.py b/src/proofofwork.py index df6ed295..4392bc7e 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -3,27 +3,15 @@ #from multiprocessing import Pool, cpu_count import hashlib from struct import unpack, pack -from subprocess import call import sys -import time -from bmconfigparser import BMConfigParser -from debug import logger -import paths -import openclpow -import queues -import tr -import os -import ctypes - -import state - -bitmsglib = 'bitmsghash.so' - -bmpow = None +from shared import config, frozen +import shared +#import os def _set_idle(): if 'linux' in sys.platform: - os.nice(20) + import os + os.nice(20) # @UndefinedVariable else: try: sys.getwindowsversion() @@ -44,252 +32,47 @@ def _pool_worker(nonce, initialHash, target, pool_size): return [trialValue, nonce] def _doSafePoW(target, initialHash): - logger.debug("Safe PoW start") nonce = 0 trialValue = float('inf') - while trialValue > target and state.shutdown == 0: + while trialValue > target: nonce += 1 trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - if state.shutdown != 0: - raise StopIteration("Interrupted") - logger.debug("Safe PoW done") return [trialValue, nonce] def _doFastPoW(target, initialHash): - logger.debug("Fast PoW start") + import time from multiprocessing import Pool, cpu_count try: pool_size = cpu_count() except: pool_size = 4 try: - maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') + maxCores = config.getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if pool_size > maxCores: pool_size = maxCores - pool = Pool(processes=pool_size) result = [] for i in range(pool_size): - result.append(pool.apply_async(_pool_worker, args=(i, initialHash, target, pool_size))) - + result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) while True: - if state.shutdown > 0: - try: - pool.terminate() - pool.join() - except: - pass - raise StopIteration("Interrupted") + if shared.shutdown >= 1: + pool.terminate() + while True: + time.sleep(10) # Don't let this thread return here; it will return nothing and cause an exception in bitmessagemain.py + return for i in range(pool_size): if result[i].ready(): - try: - result[i].successful() - except AssertionError: - pool.terminate() - pool.join() - raise StopIteration("Interrupted") result = result[i].get() pool.terminate() - pool.join() - logger.debug("Fast PoW done") + pool.join() #Wait for the workers to exit... return result[0], result[1] time.sleep(0.2) - -def _doCPoW(target, initialHash): - h = initialHash - m = target - out_h = ctypes.pointer(ctypes.create_string_buffer(h, 64)) - out_m = ctypes.c_ulonglong(m) - logger.debug("C PoW start") - nonce = bmpow(out_h, out_m) - trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - if state.shutdown != 0: - raise StopIteration("Interrupted") - logger.debug("C PoW done") - return [trialValue, nonce] - -def _doGPUPoW(target, initialHash): - logger.debug("GPU PoW start") - nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target) - trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - #print "{} - value {} < {}".format(nonce, trialValue, target) - if trialValue > target: - deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) - queues.UISignalQueue.put(('updateStatusBar', (tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'), 1))) - logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames) - openclpow.enabledGpus = [] - raise Exception("GPU did not calculate correctly.") - if state.shutdown != 0: - raise StopIteration("Interrupted") - logger.debug("GPU PoW done") - return [trialValue, nonce] - -def estimate(difficulty, format = False): - ret = difficulty / 10 - if ret < 1: - ret = 1 - if format: - out = str(int(ret)) + " seconds" - if ret > 60: - ret /= 60 - out = str(int(ret)) + " minutes" - if ret > 60: - ret /= 60 - out = str(int(ret)) + " hours" - if ret > 24: - ret /= 24 - out = str(int(ret)) + " days" - if ret > 7: - out = str(int(ret)) + " weeks" - if ret > 31: - out = str(int(ret)) + " months" - if ret > 366: - ret /= 366 - out = str(int(ret)) + " years" - else: - return ret - -def getPowType(): - if openclpow.openclEnabled(): - return "OpenCL" - if bmpow: - return "C" - return "python" - -def notifyBuild(tried=False): - if bmpow: - queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1))) - elif tried: - queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1))) - else: - queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1))) - -def buildCPoW(): - if bmpow is not None: - return - if paths.frozen is not None: - notifyBuild(False) - return - if sys.platform in ["win32", "win64"]: - notifyBuild(False) - return - try: - if "bsd" in sys.platform: - # BSD make - call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash"), '-f', 'Makefile.bsd']) - else: - # GNU make - call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")]) - if os.path.exists(os.path.join(paths.codePath(), "bitmsghash", "bitmsghash.so")): - init() - notifyBuild(True) - else: - notifyBuild(True) - except: - notifyBuild(True) def run(target, initialHash): - if state.shutdown != 0: - raise target = int(target) - if openclpow.openclEnabled(): -# trialvalue1, nonce1 = _doGPUPoW(target, initialHash) -# trialvalue, nonce = _doFastPoW(target, initialHash) -# print "GPU: %s, %s" % (trialvalue1, nonce1) -# print "Fast: %s, %s" % (trialvalue, nonce) -# return [trialvalue, nonce] - try: - return _doGPUPoW(target, initialHash) - except StopIteration: - raise - except: - pass # fallback - if bmpow: - try: - return _doCPoW(target, initialHash) - except StopIteration: - raise - except: - pass # fallback - if paths.frozen == "macosx_app" or not paths.frozen: - # on my (Peter Surda) Windows 10, Windows Defender - # does not like this and fights with PyBitmessage - # over CPU, resulting in very slow PoW - # added on 2015-11-29: multiprocesing.freeze_support() doesn't help - try: - return _doFastPoW(target, initialHash) - except StopIteration: - logger.error("Fast PoW got StopIteration") - raise - except: - logger.error("Fast PoW got exception:", exc_info=True) - pass #fallback - try: + if frozen == "macosx_app" or not frozen: + return _doFastPoW(target, initialHash) + else: return _doSafePoW(target, initialHash) - except StopIteration: - raise - except: - pass #fallback - -def resetPoW(): - openclpow.initCL() - -# init -def init(): - global bitmsglib, bso, bmpow - - openclpow.initCL() - - if "win32" == sys.platform: - if ctypes.sizeof(ctypes.c_voidp) == 4: - bitmsglib = 'bitmsghash32.dll' - else: - bitmsglib = 'bitmsghash64.dll' - try: - # MSVS - bso = ctypes.WinDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) - bmpow = bso.BitmessagePOW - bmpow.restype = ctypes.c_ulonglong - _doCPoW(2**63, "") - logger.info("Successfully tested C PoW DLL (stdcall) %s", bitmsglib) - except: - logger.error("C PoW test fail.", exc_info=True) - try: - # MinGW - bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) - bmpow = bso.BitmessagePOW - bmpow.restype = ctypes.c_ulonglong - _doCPoW(2**63, "") - logger.info("Successfully tested C PoW DLL (cdecl) %s", bitmsglib) - except: - logger.error("C PoW test fail.", exc_info=True) - bso = None - else: - try: - bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) - except OSError: - import glob - try: - bso = ctypes.CDLL(glob.glob(os.path.join( - paths.codePath(), "bitmsghash", "bitmsghash*.so" - ))[0]) - except (OSError, IndexError): - bso = None - except: - bso = None - else: - logger.info("Loaded C PoW DLL %s", bitmsglib) - if bso: - try: - bmpow = bso.BitmessagePOW - bmpow.restype = ctypes.c_ulonglong - except: - bmpow = None - else: - bmpow = None - if bmpow is None: - buildCPoW() diff --git a/src/protocol.py b/src/protocol.py deleted file mode 100644 index e5b2c5c2..00000000 --- a/src/protocol.py +++ /dev/null @@ -1,593 +0,0 @@ -import base64 -from binascii import hexlify -import hashlib -import random -import socket -import ssl -from struct import pack, unpack, Struct -import sys -import time -import traceback - -from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError -from bmconfigparser import BMConfigParser -from debug import logger -import defaults -from helper_sql import sqlExecute -import highlevelcrypto -from inventory import Inventory -from queues import objectProcessorQueue -import state -from version import softwareVersion - -#Service flags -NODE_NETWORK = 1 -NODE_SSL = 2 -NODE_DANDELION = 8 - -#Bitfield flags -BITFIELD_DOESACK = 1 - -#Error types -STATUS_WARNING = 0 -STATUS_ERROR = 1 -STATUS_FATAL = 2 - -#Object types -OBJECT_GETPUBKEY = 0 -OBJECT_PUBKEY = 1 -OBJECT_MSG = 2 -OBJECT_BROADCAST = 3 -OBJECT_I2P = 0x493250 -OBJECT_ADDR = 0x61646472 - -eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( - '>Q', random.randrange(1, 18446744073709551615)) - -#Compiled struct for packing/unpacking headers -#New code should use CreatePacket instead of Header.pack -Header = Struct('!L12sL4s') - -VersionPacket = Struct('>LqQ20s4s36sH') - -# Bitfield - -def getBitfield(address): - # bitfield of features supported by me (see the wiki). - bitfield = 0 - # send ack - if not BMConfigParser().safeGetBoolean(address, 'dontsendack'): - bitfield |= BITFIELD_DOESACK - return pack('>I', bitfield) - -def checkBitfield(bitfieldBinary, flags): - bitfield, = unpack('>I', bitfieldBinary) - return (bitfield & flags) == flags - -def isBitSetWithinBitfield(fourByteString, n): - # Uses MSB 0 bit numbering across 4 bytes of data - n = 31 - n - x, = unpack('>L', fourByteString) - return x & 2**n != 0 - -# ip addresses - -def encodeHost(host): - if host.find('.onion') > -1: - return '\xfd\x87\xd8\x7e\xeb\x43' + base64.b32decode(host.split(".")[0], True) - elif host.find(':') == -1: - return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ - socket.inet_aton(host) - else: - return socket.inet_pton(socket.AF_INET6, host) - -def networkType(host): - if host.find('.onion') > -1: - return 'onion' - elif host.find(':') == -1: - return 'IPv4' - else: - return 'IPv6' - -def checkIPAddress(host, private=False): - if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': - hostStandardFormat = socket.inet_ntop(socket.AF_INET, host[12:]) - return checkIPv4Address(host[12:], hostStandardFormat, private) - elif host[0:6] == '\xfd\x87\xd8\x7e\xeb\x43': - # Onion, based on BMD/bitcoind - hostStandardFormat = base64.b32encode(host[6:]).lower() + ".onion" - if private: - return False - return hostStandardFormat - else: - hostStandardFormat = socket.inet_ntop(socket.AF_INET6, host) - if hostStandardFormat == "": - # This can happen on Windows systems which are not 64-bit compatible - # so let us drop the IPv6 address. - return False - return checkIPv6Address(host, hostStandardFormat, private) - -def checkIPv4Address(host, hostStandardFormat, private=False): - if host[0] == '\x7F': # 127/8 - if not private: - logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) - return hostStandardFormat if private else False - if host[0] == '\x0A': # 10/8 - if not private: - logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) - return hostStandardFormat if private else False - if host[0:2] == '\xC0\xA8': # 192.168/16 - if not private: - logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) - return hostStandardFormat if private else False - if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 - if not private: - logger.debug('Ignoring IP address in private range:' + hostStandardFormat) - return hostStandardFormat if private else False - return False if private else hostStandardFormat - -def checkIPv6Address(host, hostStandardFormat, private=False): - if host == ('\x00' * 15) + '\x01': - if not private: - logger.debug('Ignoring loopback address: ' + hostStandardFormat) - return False - if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: - if not private: - logger.debug ('Ignoring local address: ' + hostStandardFormat) - return hostStandardFormat if private else False - if (ord(host[0]) & 0xfe) == 0xfc: - if not private: - logger.debug ('Ignoring unique local address: ' + hostStandardFormat) - return hostStandardFormat if private else False - return False if private else hostStandardFormat - -# checks - -def haveSSL(server = False): - # python < 2.7.9's ssl library does not support ECDSA server due to missing initialisation of available curves, but client works ok - if server == False: - return True - elif sys.version_info >= (2,7,9): - return True - return False - -def checkSocksIP(host): - try: - if state.socksIP is None or not state.socksIP: - state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - # uninitialised - except NameError: - state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - # resolving failure - except socket.gaierror: - state.socksIP = BMConfigParser().get("bitmessagesettings", "sockshostname") - return state.socksIP == host - -def isProofOfWorkSufficient(data, - nonceTrialsPerByte=0, - payloadLengthExtraBytes=0): - if nonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte - if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes - endOfLifeTime, = unpack('>Q', data[8:16]) - TTL = endOfLifeTime - int(time.time()) - if TTL < 300: - TTL = 300 - POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[ - :8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8]) - return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16)))) - -# Packet creation - -def CreatePacket(command, payload=''): - payload_length = len(payload) - checksum = hashlib.sha512(payload).digest()[0:4] - - b = bytearray(Header.size + payload_length) - Header.pack_into(b, 0, 0xE9BEB4D9, command, payload_length, checksum) - b[Header.size:] = payload - return bytes(b) - -def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server = False, nodeid = None): - payload = '' - payload += pack('>L', 3) # protocol version. - # bitflags of the services I offer. - payload += pack('>q', - NODE_NETWORK | - (NODE_SSL if haveSSL(server) else 0) | - (NODE_DANDELION if state.dandelion else 0) - ) - payload += pack('>q', int(time.time())) - - payload += pack( - '>q', 1) # boolservices of remote connection; ignored by the remote host. - if checkSocksIP(remoteHost) and server: # prevent leaking of tor outbound IP - payload += encodeHost('127.0.0.1') - payload += pack('>H', 8444) - else: - payload += encodeHost(remoteHost) - payload += pack('>H', remotePort) # remote IPv6 and port - - # bitflags of the services I offer. - payload += pack('>q', - NODE_NETWORK | - (NODE_SSL if haveSSL(server) else 0) | - (NODE_DANDELION if state.dandelion else 0) - ) - payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack( - '>L', 2130706433) # = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used. - # we have a separate extPort and - # incoming over clearnet or - # outgoing through clearnet - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and state.extPort \ - and ((server and not checkSocksIP(remoteHost)) or \ - (BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none" and not server)): - payload += pack('>H', state.extPort) - elif checkSocksIP(remoteHost) and server: # incoming connection over Tor - payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'onionport')) - else: # no extPort and not incoming over Tor - payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'port')) - - random.seed() - if nodeid is not None: - payload += nodeid[0:8] - else: - payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf - userAgent = '/PyBitmessage:' + softwareVersion + '/' - payload += encodeVarint(len(userAgent)) - payload += userAgent - - # Streams - payload += encodeVarint(len(participatingStreams)) - count = 0 - for stream in sorted(participatingStreams): - payload += encodeVarint(stream) - count += 1 - # protocol limit, see specification - if count >= 160000: - break - - return CreatePacket('version', payload) - -def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): - payload = encodeVarint(fatal) - payload += encodeVarint(banTime) - payload += encodeVarint(len(inventoryVector)) - payload += inventoryVector - payload += encodeVarint(len(errorText)) - payload += errorText - return CreatePacket('error', payload) - -# Packet decoding - -def decryptAndCheckPubkeyPayload(data, address): - """ - Version 4 pubkeys are encrypted. This function is run when we already have the - address to which we want to try to send a message. The 'data' may come either - off of the wire or we might have had it already in our inventory when we tried - to send a msg to this particular address. - """ - try: - status, addressVersion, streamNumber, ripe = decodeAddress(address) - - readPosition = 20 # bypass the nonce, time, and object type - embeddedAddressVersion, varintLength = decodeVarint(data[readPosition:readPosition + 10]) - readPosition += varintLength - embeddedStreamNumber, varintLength = decodeVarint(data[readPosition:readPosition + 10]) - readPosition += varintLength - storedData = data[20:readPosition] # We'll store the address version and stream number (and some more) in the pubkeys table. - - if addressVersion != embeddedAddressVersion: - logger.info('Pubkey decryption was UNsuccessful due to address version mismatch.') - return 'failed' - if streamNumber != embeddedStreamNumber: - logger.info('Pubkey decryption was UNsuccessful due to stream number mismatch.') - return 'failed' - - tag = data[readPosition:readPosition + 32] - readPosition += 32 - signedData = data[8:readPosition] # the time through the tag. More data is appended onto signedData below after the decryption. - encryptedData = data[readPosition:] - - # Let us try to decrypt the pubkey - toAddress, cryptorObject = state.neededPubkeys[tag] - if toAddress != address: - logger.critical('decryptAndCheckPubkeyPayload failed due to toAddress mismatch. This is very peculiar. toAddress: %s, address %s', toAddress, address) - # the only way I can think that this could happen is if someone encodes their address data two different ways. - # That sort of address-malleability should have been caught by the UI or API and an error given to the user. - return 'failed' - try: - decryptedData = cryptorObject.decrypt(encryptedData) - except: - # Someone must have encrypted some data with a different key - # but tagged it with a tag for which we are watching. - logger.info('Pubkey decryption was unsuccessful.') - return 'failed' - - readPosition = 0 - bitfieldBehaviors = decryptedData[readPosition:readPosition + 4] - readPosition += 4 - publicSigningKey = '\x04' + decryptedData[readPosition:readPosition + 64] - readPosition += 64 - publicEncryptionKey = '\x04' + decryptedData[readPosition:readPosition + 64] - readPosition += 64 - specifiedNonceTrialsPerByte, specifiedNonceTrialsPerByteLength = decodeVarint( - decryptedData[readPosition:readPosition + 10]) - readPosition += specifiedNonceTrialsPerByteLength - specifiedPayloadLengthExtraBytes, specifiedPayloadLengthExtraBytesLength = decodeVarint( - decryptedData[readPosition:readPosition + 10]) - readPosition += specifiedPayloadLengthExtraBytesLength - storedData += decryptedData[:readPosition] - signedData += decryptedData[:readPosition] - signatureLength, signatureLengthLength = decodeVarint( - decryptedData[readPosition:readPosition + 10]) - readPosition += signatureLengthLength - signature = decryptedData[readPosition:readPosition + signatureLength] - - if highlevelcrypto.verify(signedData, signature, hexlify(publicSigningKey)): - logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)') - else: - logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)') - return 'failed' - - sha = hashlib.new('sha512') - sha.update(publicSigningKey + publicEncryptionKey) - ripeHasher = hashlib.new('ripemd160') - ripeHasher.update(sha.digest()) - embeddedRipe = ripeHasher.digest() - - if embeddedRipe != ripe: - # Although this pubkey object had the tag were were looking for and was - # encrypted with the correct encryption key, it doesn't contain the - # correct pubkeys. Someone is either being malicious or using buggy software. - logger.info('Pubkey decryption was UNsuccessful due to RIPE mismatch.') - return 'failed' - - # Everything checked out. Insert it into the pubkeys table. - - logger.info('within decryptAndCheckPubkeyPayload, addressVersion: %s, streamNumber: %s \n\ - ripe %s\n\ - publicSigningKey in hex: %s\n\ - publicEncryptionKey in hex: %s', addressVersion, - streamNumber, - hexlify(ripe), - hexlify(publicSigningKey), - hexlify(publicEncryptionKey) - ) - - t = (address, addressVersion, storedData, int(time.time()), 'yes') - sqlExecute('''INSERT INTO pubkeys VALUES (?,?,?,?,?)''', *t) - return 'successful' - except varintDecodeError as e: - logger.info('Pubkey decryption was UNsuccessful due to a malformed varint.') - return 'failed' - except Exception as e: - logger.critical('Pubkey decryption was UNsuccessful because of an unhandled exception! This is definitely a bug! \n%s', traceback.format_exc()) - return 'failed' - -def checkAndShareObjectWithPeers(data): - """ - This function is called after either receiving an object off of the wire - or after receiving one as ackdata. - Returns the length of time that we should reserve to process this message - if we are receiving it off of the wire. - """ - if len(data) > 2 ** 18: - logger.info('The payload length of this object is too large (%s bytes). Ignoring it.', len(data)) - return 0 - # Let us check to make sure that the proof of work is sufficient. - if not isProofOfWorkSufficient(data): - logger.info('Proof of work is insufficient.') - return 0 - - endOfLifeTime, = unpack('>Q', data[8:16]) - if endOfLifeTime - int(time.time()) > 28 * 24 * 60 * 60 + 10800: # The TTL may not be larger than 28 days + 3 hours of wiggle room - logger.info('This object\'s End of Life time is too far in the future. Ignoring it. Time is %s', endOfLifeTime) - return 0 - if endOfLifeTime - int(time.time()) < - 3600: # The EOL time was more than an hour ago. That's too much. - logger.info('This object\'s End of Life time was more than an hour ago. Ignoring the object. Time is %s', endOfLifeTime) - return 0 - intObjectType, = unpack('>I', data[16:20]) - try: - if intObjectType == 0: - _checkAndShareGetpubkeyWithPeers(data) - return 0.1 - elif intObjectType == 1: - _checkAndSharePubkeyWithPeers(data) - return 0.1 - elif intObjectType == 2: - _checkAndShareMsgWithPeers(data) - return 0.6 - elif intObjectType == 3: - _checkAndShareBroadcastWithPeers(data) - return 0.6 - else: - _checkAndShareUndefinedObjectWithPeers(data) - return 0.6 - except varintDecodeError as e: - logger.debug("There was a problem with a varint while checking to see whether it was appropriate to share an object with peers. Some details: %s", e) - except Exception as e: - logger.critical('There was a problem while checking to see whether it was appropriate to share an object with peers. This is definitely a bug! \n%s', traceback.format_exc()) - return 0 - - -def _checkAndShareUndefinedObjectWithPeers(data): - embeddedTime, = unpack('>Q', data[8:16]) - readPosition = 20 # bypass nonce, time, and object type - objectVersion, objectVersionLength = decodeVarint( - data[readPosition:readPosition + 9]) - readPosition += objectVersionLength - streamNumber, streamNumberLength = decodeVarint( - data[readPosition:readPosition + 9]) - if not streamNumber in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) - return - - inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): - logger.debug('We have already received this undefined object. Ignoring.') - return - objectType, = unpack('>I', data[16:20]) - Inventory()[inventoryHash] = ( - objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) - - -def _checkAndShareMsgWithPeers(data): - embeddedTime, = unpack('>Q', data[8:16]) - readPosition = 20 # bypass nonce, time, and object type - objectVersion, objectVersionLength = decodeVarint( - data[readPosition:readPosition + 9]) - readPosition += objectVersionLength - streamNumber, streamNumberLength = decodeVarint( - data[readPosition:readPosition + 9]) - if not streamNumber in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) - return - readPosition += streamNumberLength - inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): - logger.debug('We have already received this msg message. Ignoring.') - return - # This msg message is valid. Let's let our peers know about it. - objectType = 2 - Inventory()[inventoryHash] = ( - objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) - - # Now let's enqueue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) - -def _checkAndShareGetpubkeyWithPeers(data): - if len(data) < 42: - logger.info('getpubkey message doesn\'t contain enough data. Ignoring.') - return - if len(data) > 200: - logger.info('getpubkey is abnormally long. Sanity check failed. Ignoring object.') - embeddedTime, = unpack('>Q', data[8:16]) - readPosition = 20 # bypass the nonce, time, and object type - requestedAddressVersionNumber, addressVersionLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += addressVersionLength - streamNumber, streamNumberLength = decodeVarint( - data[readPosition:readPosition + 10]) - if not streamNumber in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) - return - readPosition += streamNumberLength - - inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): - logger.debug('We have already received this getpubkey request. Ignoring it.') - return - - objectType = 0 - Inventory()[inventoryHash] = ( - objectType, streamNumber, data, embeddedTime,'') - # This getpubkey request is valid. Forward to peers. - logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) - - # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) - -def _checkAndSharePubkeyWithPeers(data): - if len(data) < 146 or len(data) > 440: # sanity check - return - embeddedTime, = unpack('>Q', data[8:16]) - readPosition = 20 # bypass the nonce, time, and object type - addressVersion, varintLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += varintLength - streamNumber, varintLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += varintLength - if not streamNumber in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) - return - if addressVersion >= 4: - tag = data[readPosition:readPosition + 32] - logger.debug('tag in received pubkey is: %s', hexlify(tag)) - else: - tag = '' - - inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): - logger.debug('We have already received this pubkey. Ignoring it.') - return - objectType = 1 - Inventory()[inventoryHash] = ( - objectType, streamNumber, data, embeddedTime, tag) - # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) - - - # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) - - -def _checkAndShareBroadcastWithPeers(data): - if len(data) < 180: - logger.debug('The payload length of this broadcast packet is unreasonably low. Someone is probably trying funny business. Ignoring message.') - return - embeddedTime, = unpack('>Q', data[8:16]) - readPosition = 20 # bypass the nonce, time, and object type - broadcastVersion, broadcastVersionLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += broadcastVersionLength - if broadcastVersion >= 2: - streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) - readPosition += streamNumberLength - if not streamNumber in state.streamsInWhichIAmParticipating: - logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) - return - if broadcastVersion >= 3: - tag = data[readPosition:readPosition+32] - else: - tag = '' - inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): - logger.debug('We have already received this broadcast object. Ignoring.') - return - # It is valid. Let's let our peers know about it. - objectType = 3 - Inventory()[inventoryHash] = ( - objectType, streamNumber, data, embeddedTime, tag) - # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) - - # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) - -# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this -# function puts your data into the queues for each of the sendDataThreads. The sendDataThreads are -# responsible for putting their queue into (and out of) the sendDataQueues list. -def broadcastToSendDataQueues(data): - # logger.debug('running broadcastToSendDataQueues') - for q in state.sendDataQueues: - q.put(data) - -# sslProtocolVersion -if sys.version_info >= (2,7,13): - # this means TLSv1 or higher - # in the future change to - # ssl.PROTOCOL_TLS1.2 - sslProtocolVersion = ssl.PROTOCOL_TLS -elif sys.version_info >= (2,7,9): - # this means any SSL/TLS. SSLv2 and 3 are excluded with an option after context is created - sslProtocolVersion = ssl.PROTOCOL_SSLv23 -else: - # this means TLSv1, there is no way to set "TLSv1 or higher" or - # "TLSv1.2" in < 2.7.9 - sslProtocolVersion = ssl.PROTOCOL_TLSv1 - -# ciphers -if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000 and not ssl.OPENSSL_VERSION.startswith("LibreSSL"): - sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0" -else: - sslProtocolCiphers = "AECDH-AES256-SHA" diff --git a/src/pybitmessage b/src/pybitmessage deleted file mode 100644 index decebfff..00000000 --- a/src/pybitmessage +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/python2.7 - -import os -import pkg_resources - -dist = pkg_resources.get_distribution('pybitmessage') -script_file = os.path.join(dist.location, dist.key, 'bitmessagemain.py') -new_globals = globals() -new_globals.update(__file__=script_file) - -execfile(script_file, new_globals) diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index b597cafa..fb8d0d46 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -77,8 +77,5 @@ class Cipher: return buff + self.final() def __del__(self): - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_CIPHER_CTX_reset(self.ctx) - else: - OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) + OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) OpenSSL.EVP_CIPHER_CTX_free(self.ctx) diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index bea645db..269db952 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -223,10 +223,7 @@ class ECC: if (OpenSSL.EC_KEY_set_private_key(own_key, own_priv_key)) == 0: raise Exception("[OpenSSL] EC_KEY_set_private_key FAIL ...") - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EC_KEY_set_method(own_key, OpenSSL.EC_KEY_OpenSSL()) - else: - OpenSSL.ECDH_set_method(own_key, OpenSSL.ECDH_OpenSSL()) + OpenSSL.ECDH_set_method(own_key, OpenSSL.ECDH_OpenSSL()) ecdh_keylen = OpenSSL.ECDH_compute_key( ecdh_keybuffer, 32, other_pub_key, own_key, 0) @@ -302,7 +299,7 @@ class ECC: if privkey is not None: OpenSSL.BN_free(priv_key) - def sign(self, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): + def sign(self, inputb, digest_alg=OpenSSL.EVP_ecdsa): """ Sign the input with ECDSA method and returns the signature """ @@ -310,10 +307,7 @@ class ECC: size = len(inputb) buff = OpenSSL.malloc(inputb, size) digest = OpenSSL.malloc(0, 64) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - md_ctx = OpenSSL.EVP_MD_CTX_new() - else: - md_ctx = OpenSSL.EVP_MD_CTX_create() + md_ctx = OpenSSL.EVP_MD_CTX_create() dgst_len = OpenSSL.pointer(OpenSSL.c_int(0)) siglen = OpenSSL.pointer(OpenSSL.c_int(0)) sig = OpenSSL.malloc(0, 151) @@ -343,10 +337,7 @@ class ECC: if (OpenSSL.EC_KEY_check_key(key)) == 0: raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_new(md_ctx) - else: - OpenSSL.EVP_MD_CTX_init(md_ctx) + OpenSSL.EVP_MD_CTX_init(md_ctx) OpenSSL.EVP_DigestInit_ex(md_ctx, digest_alg(), None) if (OpenSSL.EVP_DigestUpdate(md_ctx, buff, size)) == 0: @@ -365,13 +356,9 @@ class ECC: OpenSSL.BN_free(pub_key_y) OpenSSL.BN_free(priv_key) OpenSSL.EC_POINT_free(pub_key) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_free(md_ctx) - else: - OpenSSL.EVP_MD_CTX_destroy(md_ctx) - pass + OpenSSL.EVP_MD_CTX_destroy(md_ctx) - def verify(self, sig, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): + def verify(self, sig, inputb, digest_alg=OpenSSL.EVP_ecdsa): """ Verify the signature with the input and the local public key. Returns a boolean @@ -381,10 +368,8 @@ class ECC: binputb = OpenSSL.malloc(inputb, len(inputb)) digest = OpenSSL.malloc(0, 64) dgst_len = OpenSSL.pointer(OpenSSL.c_int(0)) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - md_ctx = OpenSSL.EVP_MD_CTX_new() - else: - md_ctx = OpenSSL.EVP_MD_CTX_create() + md_ctx = OpenSSL.EVP_MD_CTX_create() + key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) if key == 0: @@ -405,10 +390,8 @@ class ECC: raise Exception("[OpenSSL] EC_KEY_set_public_key FAIL ...") if (OpenSSL.EC_KEY_check_key(key)) == 0: raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_new(md_ctx) - else: - OpenSSL.EVP_MD_CTX_init(md_ctx) + + OpenSSL.EVP_MD_CTX_init(md_ctx) OpenSSL.EVP_DigestInit_ex(md_ctx, digest_alg(), None) if (OpenSSL.EVP_DigestUpdate(md_ctx, binputb, len(inputb))) == 0: raise Exception("[OpenSSL] EVP_DigestUpdate FAIL ...") @@ -431,10 +414,7 @@ class ECC: OpenSSL.BN_free(pub_key_x) OpenSSL.BN_free(pub_key_y) OpenSSL.EC_POINT_free(pub_key) - if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: - OpenSSL.EVP_MD_CTX_free(md_ctx) - else: - OpenSSL.EVP_MD_CTX_destroy(md_ctx) + OpenSSL.EVP_MD_CTX_destroy(md_ctx) @staticmethod def encrypt(data, pubkey, ephemcurve=None, ciphername='aes-256-cbc'): diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 7af4fd18..c6b72b65 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -31,37 +31,6 @@ class CipherName: return self._blocksize -def get_version(library): - version = None - hexversion = None - cflags = None - try: - #OpenSSL 1.1 - OPENSSL_VERSION = 0 - OPENSSL_CFLAGS = 1 - library.OpenSSL_version.argtypes = [ctypes.c_int] - library.OpenSSL_version.restype = ctypes.c_char_p - version = library.OpenSSL_version(OPENSSL_VERSION) - cflags = library.OpenSSL_version(OPENSSL_CFLAGS) - library.OpenSSL_version_num.restype = ctypes.c_long - hexversion = library.OpenSSL_version_num() - except AttributeError: - try: - #OpenSSL 1.0 - SSLEAY_VERSION = 0 - SSLEAY_CFLAGS = 2 - library.SSLeay.restype = ctypes.c_long - library.SSLeay_version.restype = ctypes.c_char_p - library.SSLeay_version.argtypes = [ctypes.c_int] - version = library.SSLeay_version(SSLEAY_VERSION) - cflags = library.SSLeay_version(SSLEAY_CFLAGS) - hexversion = library.SSLeay() - except AttributeError: - #raise NotImplementedError('Cannot determine version of this OpenSSL library.') - pass - return (version, hexversion, cflags) - - class _OpenSSL: """ Wrapper for OpenSSL using ctypes @@ -71,8 +40,6 @@ class _OpenSSL: Build the wrapper """ self._lib = ctypes.CDLL(library) - self._version, self._hexversion, self._cflags = get_version(self._lib) - self._libreSSL = self._version.startswith("LibreSSL") self.pointer = ctypes.pointer self.c_int = ctypes.c_int @@ -171,27 +138,18 @@ class _OpenSSL: self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EC_KEY_OpenSSL = self._lib.EC_KEY_OpenSSL - self._lib.EC_KEY_OpenSSL.restype = ctypes.c_void_p - self._lib.EC_KEY_OpenSSL.argtypes = [] - - self.EC_KEY_set_method = self._lib.EC_KEY_set_method - self._lib.EC_KEY_set_method.restype = ctypes.c_int - self._lib.EC_KEY_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - else: - self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL - self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p - self._lib.ECDH_OpenSSL.argtypes = [] - - self.ECDH_set_method = self._lib.ECDH_set_method - self._lib.ECDH_set_method.restype = ctypes.c_int - self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL + self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p + self._lib.ECDH_OpenSSL.argtypes = [] self.BN_CTX_new = self._lib.BN_CTX_new self._lib.BN_CTX_new.restype = ctypes.c_void_p self._lib.BN_CTX_new.argtypes = [] + self.ECDH_set_method = self._lib.ECDH_set_method + self._lib.ECDH_set_method.restype = ctypes.c_int + self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] + self.ECDH_compute_key = self._lib.ECDH_compute_key self.ECDH_compute_key.restype = ctypes.c_int self.ECDH_compute_key.argtypes = [ctypes.c_void_p, @@ -250,15 +208,10 @@ class _OpenSSL: self.EVP_rc4 = self._lib.EVP_rc4 self.EVP_rc4.restype = ctypes.c_void_p self.EVP_rc4.argtypes = [] - - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EVP_CIPHER_CTX_reset = self._lib.EVP_CIPHER_CTX_reset - self.EVP_CIPHER_CTX_reset.restype = ctypes.c_int - self.EVP_CIPHER_CTX_reset.argtypes = [ctypes.c_void_p] - else: - self.EVP_CIPHER_CTX_cleanup = self._lib.EVP_CIPHER_CTX_cleanup - self.EVP_CIPHER_CTX_cleanup.restype = ctypes.c_int - self.EVP_CIPHER_CTX_cleanup.argtypes = [ctypes.c_void_p] + + self.EVP_CIPHER_CTX_cleanup = self._lib.EVP_CIPHER_CTX_cleanup + self.EVP_CIPHER_CTX_cleanup.restype = ctypes.c_int + self.EVP_CIPHER_CTX_cleanup.argtypes = [ctypes.c_void_p] self.EVP_CIPHER_CTX_free = self._lib.EVP_CIPHER_CTX_free self.EVP_CIPHER_CTX_free.restype = None @@ -297,6 +250,10 @@ class _OpenSSL: self.EVP_DigestFinal_ex.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] + self.EVP_ecdsa = self._lib.EVP_ecdsa + self._lib.EVP_ecdsa.restype = ctypes.c_void_p + self._lib.EVP_ecdsa.argtypes = [] + self.ECDSA_sign = self._lib.ECDSA_sign self.ECDSA_sign.restype = ctypes.c_int self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, @@ -307,47 +264,23 @@ class _OpenSSL: self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] - if self._hexversion >= 0x10100000 and not self._libreSSL: - self.EVP_MD_CTX_new = self._lib.EVP_MD_CTX_new - self.EVP_MD_CTX_new.restype = ctypes.c_void_p - self.EVP_MD_CTX_new.argtypes = [] - - self.EVP_MD_CTX_reset = self._lib.EVP_MD_CTX_reset - self.EVP_MD_CTX_reset.restype = None - self.EVP_MD_CTX_reset.argtypes = [ctypes.c_void_p] + self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create + self.EVP_MD_CTX_create.restype = ctypes.c_void_p + self.EVP_MD_CTX_create.argtypes = [] - self.EVP_MD_CTX_free = self._lib.EVP_MD_CTX_free - self.EVP_MD_CTX_free.restype = None - self.EVP_MD_CTX_free.argtypes = [ctypes.c_void_p] + self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init + self.EVP_MD_CTX_init.restype = None + self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p] - self.EVP_sha1 = self._lib.EVP_sha1 - self.EVP_sha1.restype = ctypes.c_void_p - self.EVP_sha1.argtypes = [] - - self.digest_ecdsa_sha1 = self.EVP_sha1 - else: - self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create - self.EVP_MD_CTX_create.restype = ctypes.c_void_p - self.EVP_MD_CTX_create.argtypes = [] - - self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init - self.EVP_MD_CTX_init.restype = None - self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p] - - self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy - self.EVP_MD_CTX_destroy.restype = None - self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p] - - self.EVP_ecdsa = self._lib.EVP_ecdsa - self._lib.EVP_ecdsa.restype = ctypes.c_void_p - self._lib.EVP_ecdsa.argtypes = [] - - self.digest_ecdsa_sha1 = self.EVP_ecdsa + self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy + self.EVP_MD_CTX_destroy.restype = None + self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p] self.RAND_bytes = self._lib.RAND_bytes self.RAND_bytes.restype = ctypes.c_int self.RAND_bytes.argtypes = [ctypes.c_void_p, ctypes.c_int] + self.EVP_sha256 = self._lib.EVP_sha256 self.EVP_sha256.restype = ctypes.c_void_p self.EVP_sha256.argtypes = [] @@ -494,56 +427,35 @@ class _OpenSSL: buffer = self.create_string_buffer(size) return buffer -def loadOpenSSL(): - global OpenSSL - from os import path, environ - from ctypes.util import find_library - - libdir = [] - if getattr(sys,'frozen', None): - if 'darwin' in sys.platform: - libdir.extend([ - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.1.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.2.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.1.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.0.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.0.9.8.dylib'), - ]) - elif 'win32' in sys.platform or 'win64' in sys.platform: - libdir.append(path.join(sys._MEIPASS, 'libeay32.dll')) - else: - libdir.extend([ - path.join(sys._MEIPASS, 'libcrypto.so'), - path.join(sys._MEIPASS, 'libssl.so'), - path.join(sys._MEIPASS, 'libcrypto.so.1.1.0'), - path.join(sys._MEIPASS, 'libssl.so.1.1.0'), - path.join(sys._MEIPASS, 'libcrypto.so.1.0.2'), - path.join(sys._MEIPASS, 'libssl.so.1.0.2'), - path.join(sys._MEIPASS, 'libcrypto.so.1.0.1'), - path.join(sys._MEIPASS, 'libssl.so.1.0.1'), - path.join(sys._MEIPASS, 'libcrypto.so.1.0.0'), - path.join(sys._MEIPASS, 'libssl.so.1.0.0'), - path.join(sys._MEIPASS, 'libcrypto.so.0.9.8'), - path.join(sys._MEIPASS, 'libssl.so.0.9.8'), - ]) - if 'darwin' in sys.platform: - libdir.extend(['libcrypto.dylib', '/usr/local/opt/openssl/lib/libcrypto.dylib']) - elif 'win32' in sys.platform or 'win64' in sys.platform: - libdir.append('libeay32.dll') - else: - libdir.append('libcrypto.so') - libdir.append('libssl.so') - if 'linux' in sys.platform or 'darwin' in sys.platform or 'bsd' in sys.platform: - libdir.append(find_library('ssl')) - elif 'win32' in sys.platform or 'win64' in sys.platform: - libdir.append(find_library('libeay32')) - for library in libdir: +try: + OpenSSL = _OpenSSL('libcrypto.so') +except: + try: + OpenSSL = _OpenSSL('libeay32.dll') + except: try: - OpenSSL = _OpenSSL(library) - return + OpenSSL = _OpenSSL('libcrypto.dylib') except: - pass - raise Exception("Couldn't find and load the OpenSSL library. You must install it.") - -loadOpenSSL() + try: + # try homebrew installation + OpenSSL = _OpenSSL('/usr/local/opt/openssl/lib/libcrypto.dylib') + except: + try: + # Load it from an Bitmessage.app on OSX + OpenSSL = _OpenSSL('./../Frameworks/libcrypto.dylib') + except: + try: + from os import path + lib_path = path.join(sys._MEIPASS, "libeay32.dll") + OpenSSL = _OpenSSL(lib_path) + except: + if 'linux' in sys.platform or 'darwin' in sys.platform or 'freebsd' in sys.platform: + try: + from ctypes.util import find_library + OpenSSL = _OpenSSL(find_library('ssl')) + except Exception, err: + sys.stderr.write('(On Linux) Couldn\'t find and load the OpenSSL library. You must install it. If you believe that you already have it installed, this exception information might be of use:\n') + from ctypes.util import find_library + OpenSSL = _OpenSSL(find_library('ssl')) + else: + raise Exception("Couldn't find and load the OpenSSL library. You must install it.") diff --git a/src/queues.py b/src/queues.py deleted file mode 100644 index e8923dbd..00000000 --- a/src/queues.py +++ /dev/null @@ -1,16 +0,0 @@ -import Queue - -from class_objectProcessorQueue import ObjectProcessorQueue -from multiqueue import MultiQueue - -workerQueue = Queue.Queue() -UISignalQueue = Queue.Queue() -addressGeneratorQueue = Queue.Queue() -# receiveDataThreads dump objects they hear on the network into this queue to be processed. -objectProcessorQueue = ObjectProcessorQueue() -invQueue = MultiQueue() -addrQueue = MultiQueue() -portCheckerQueue = Queue.Queue() -receiveDataQueue = Queue.Queue() -apiAddressGeneratorReturnQueue = Queue.Queue( - ) # The address generator thread uses this queue to get information back to the API thread. diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py deleted file mode 100644 index 83d35cdf..00000000 --- a/src/randomtrackingdict.py +++ /dev/null @@ -1,134 +0,0 @@ -import random -from threading import RLock -from time import time - -class RandomTrackingDict(object): - maxPending = 10 - pendingTimeout = 60 - def __init__(self): # O(1) - self.dictionary = {} - self.indexDict = [] - self.len = 0 - self.pendingLen = 0 - self.lastPoll = 0 - self.lock = RLock() - - def __len__(self): - return self.len - - def __contains__(self, key): - return key in self.dictionary - - def __getitem__(self, key): - return self.dictionary[key][1] - - def _swap(self, i1, i2): - with self.lock: - key1 = self.indexDict[i1] - key2 = self.indexDict[i2] - self.indexDict[i1] = key2 - self.indexDict[i2] = key1 - self.dictionary[key1][0] = i2 - self.dictionary[key2][0] = i1 - # for quick reassignment - return i2 - - def __setitem__(self, key, value): - with self.lock: - if key in self.dictionary: - self.dictionary[key][1] = value - else: - self.indexDict.append(key) - self.dictionary[key] = [self.len, value] - self._swap(self.len, self.len - self.pendingLen) - self.len += 1 - - def __delitem__(self, key): - if not key in self.dictionary: - raise KeyError - with self.lock: - index = self.dictionary[key][0] - # not pending - if index < self.len - self.pendingLen: - # left of pending part - index = self._swap(index, self.len - self.pendingLen - 1) - # pending - else: - self.pendingLen -= 1 - # end - self._swap(index, self.len - 1) - # if the following del is batched, performance of this single - # operation can improve 4x, but it's already very fast so we'll - # ignore it for the time being - del self.indexDict[-1] - del self.dictionary[key] - self.len -= 1 - - def setMaxPending(self, maxPending): - self.maxPending = maxPending - - def setPendingTimeout(self, pendingTimeout): - self.pendingTimeout = pendingTimeout - - def randomKeys(self, count=1): - if self.len == 0 or ((self.pendingLen >= self.maxPending or - self.pendingLen == self.len) and self.lastPoll + - self.pendingTimeout > time()): - raise KeyError - # reset if we've requested all - with self.lock: - if self.pendingLen == self.len: - self.pendingLen = 0 - available = self.len - self.pendingLen - if count > available: - count = available - randomIndex = random.sample(range(self.len - self.pendingLen), count) - retval = [self.indexDict[i] for i in randomIndex] - - for i in sorted(randomIndex, reverse=True): - # swap with one below lowest pending - self._swap(i, self.len - self.pendingLen - 1) - self.pendingLen += 1 - self.lastPoll = time() - return retval - -if __name__ == '__main__': - def randString(): - retval = b'' - for _ in range(32): - retval += chr(random.randint(0,255)) - return retval - - a = [] - k = RandomTrackingDict() - d = {} - -# print "populating normal dict" -# a.append(time()) -# for i in range(50000): -# d[randString()] = True -# a.append(time()) - print "populating random tracking dict" - a.append(time()) - for i in range(50000): - k[randString()] = True - a.append(time()) - print "done" - while len(k) > 0: - retval = k.randomKeys(1000) - if not retval: - print "error getting random keys" - #a.append(time()) - try: - k.randomKeys(100) - print "bad" - except KeyError: - pass - #a.append(time()) - for i in retval: - del k[i] - #a.append(time()) - a.append(time()) - - for x in range(len(a) - 1): - print "%i: %.3f" % (x, a[x+1] - a[x]) diff --git a/src/shared.py b/src/shared.py index e2f3c1cc..5351947f 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,5 +1,6 @@ from __future__ import division +softwareVersion = '0.4.4' verbose = 1 maximumAgeOfAnObjectThatIAmWillingToAccept = 216000 # This is obsolete with the change to protocol v3 but the singleCleaner thread still hasn't been updated so we need this a little longer. lengthOfTimeToHoldOnToAllPubkeys = 2419200 # Equals 4 weeks. You could make this longer if you want but making it shorter would not be advisable because there is a very small possibility that it could keep you from obtaining a needed pubkey for a period of time. @@ -8,51 +9,214 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. +import collections +import ConfigParser import os +import pickle +import Queue +import random +import socket import sys import stat import threading import time +import shutil # used for moving the data folder and copying keys.dat +import datetime +from os import path, environ +from struct import Struct import traceback -from binascii import hexlify # Project imports. from addresses import * -from bmconfigparser import BMConfigParser import highlevelcrypto +import shared #import helper_startup from helper_sql import * -from inventory import Inventory -from queues import objectProcessorQueue -import protocol -import state +config = ConfigParser.SafeConfigParser() myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself. myAddressesByTag = {} # The key in this dictionary is the tag generated from the address. broadcastSendersForWhichImWatching = {} +workerQueue = Queue.Queue() +UISignalQueue = Queue.Queue() +addressGeneratorQueue = Queue.Queue() +knownNodesLock = threading.Lock() +knownNodes = {} +sendDataQueues = [] #each sendData thread puts its queue in this list. +inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet). +inventoryLock = threading.Lock() #Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) printLock = threading.Lock() +objectProcessorQueueSizeLock = threading.Lock() +objectProcessorQueueSize = 0 # in Bytes. We maintain this to prevent nodes from flooing us with objects which take up too much memory. If this gets too big we'll sleep before asking for further objects. +appdata = '' #holds the location of the application data storage directory statusIconColor = 'red' connectedHostsList = {} #List of hosts to which we are connected. Used to guarantee that the outgoingSynSender threads won't connect to the same remote node twice. -thisapp = None # singleton lock instance +shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. alreadyAttemptedConnectionsList = { } # This is a list of nodes to which we have already attempted a connection alreadyAttemptedConnectionsListLock = threading.Lock() alreadyAttemptedConnectionsListResetTime = int( time.time()) # used to clear out the alreadyAttemptedConnectionsList periodically so that we will retry connecting to hosts to which we have already tried to connect. +numberOfObjectsThatWeHaveYetToGetPerPeer = {} +neededPubkeys = {} +eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( + '>Q', random.randrange(1, 18446744073709551615)) successfullyDecryptMessageTimings = [ ] # A list of the amounts of time it took to successfully decrypt msg messages +apiAddressGeneratorReturnQueue = Queue.Queue( + ) # The address generator thread uses this queue to get information back to the API thread. ackdataForWhichImWatching = {} clientHasReceivedIncomingConnections = False #used by API command clientStatus numberOfMessagesProcessed = 0 numberOfBroadcastsProcessed = 0 numberOfPubkeysProcessed = 0 - +numberOfInventoryLookupsPerformed = 0 +numberOfBytesReceived = 0 # Used for the 'network status' page +numberOfBytesSent = 0 # Used for the 'network status' page +numberOfBytesReceivedLastSecond = 0 # used for the bandwidth rate limit +numberOfBytesSentLastSecond = 0 # used for the bandwidth rate limit +lastTimeWeResetBytesReceived = 0 # used for the bandwidth rate limit +lastTimeWeResetBytesSent = 0 # used for the bandwidth rate limit +sendDataLock = threading.Lock() # used for the bandwidth rate limit +receiveDataLock = threading.Lock() # used for the bandwidth rate limit +daemon = False +inventorySets = {} # key = streamNumer, value = a set which holds the inventory object hashes that we are aware of. This is used whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it every couple hours. needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 -timeOffsetWrongCount = 0 +objectProcessorQueue = Queue.Queue( + ) # receiveDataThreads dump objects they hear on the network into this queue to be processed. +streamsInWhichIAmParticipating = {} + +#If changed, these values will cause particularly unexpected behavior: You won't be able to either send or receive messages because the proof of work you do (or demand) won't match that done or demanded by others. Don't change them! +networkDefaultProofOfWorkNonceTrialsPerByte = 1000 #The amount of work that should be performed (and demanded) per byte of the payload. +networkDefaultPayloadLengthExtraBytes = 1000 #To make sending short messages a little more difficult, this value is added to the payload length for use in calculating the proof of work target. + +# Remember here the RPC port read from namecoin.conf so we can restore to +# it as default whenever the user changes the "method" selection for +# namecoin integration to "namecoind". +namecoinDefaultRpcPort = "8336" + +# When using py2exe or py2app, the variable frozen is added to the sys +# namespace. This can be used to setup a different code path for +# binary distributions vs source distributions. +frozen = getattr(sys,'frozen', None) + +# If the trustedpeer option is specified in keys.dat then this will +# contain a Peer which will be connected to instead of using the +# addresses advertised by other peers. The client will only connect to +# this peer and the timing attack mitigation will be disabled in order +# to download data faster. The expected use case is where the user has +# a fast connection to a trusted server where they run a BitMessage +# daemon permanently. If they then run a second instance of the client +# on a local machine periodically when they want to check for messages +# it will sync with the network a lot faster without compromising +# security. +trustedPeer = None + +#Compiled struct for packing/unpacking headers +#New code should use CreatePacket instead of Header.pack +Header = Struct('!L12sL4s') + +#Create a packet +def CreatePacket(command, payload=''): + payload_length = len(payload) + checksum = hashlib.sha512(payload).digest()[0:4] + + b = bytearray(Header.size + payload_length) + Header.pack_into(b, 0, 0xE9BEB4D9, command, payload_length, checksum) + b[Header.size:] = payload + return bytes(b) + +def isInSqlInventory(hash): + queryreturn = sqlQuery('''select hash from inventory where hash=?''', hash) + return queryreturn != [] + +def encodeHost(host): + if host.find(':') == -1: + return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ + socket.inet_aton(host) + else: + return socket.inet_pton(socket.AF_INET6, host) + +def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): + payload = '' + payload += pack('>L', 3) # protocol version. + payload += pack('>q', 1) # bitflags of the services I offer. + payload += pack('>q', int(time.time())) + + payload += pack( + '>q', 1) # boolservices of remote connection; ignored by the remote host. + payload += encodeHost(remoteHost) + payload += pack('>H', remotePort) # remote IPv6 and port + + payload += pack('>q', 1) # bitflags of the services I offer. + payload += '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + pack( + '>L', 2130706433) # = 127.0.0.1. This will be ignored by the remote host. The actual remote connected IP will be used. + payload += pack('>H', shared.config.getint( + 'bitmessagesettings', 'port')) + + random.seed() + payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf + userAgent = '/PyBitmessage:' + shared.softwareVersion + '/' + payload += encodeVarint(len(userAgent)) + payload += userAgent + payload += encodeVarint( + 1) # The number of streams about which I care. PyBitmessage currently only supports 1 per connection. + payload += encodeVarint(myStreamNumber) + + return CreatePacket('version', payload) + +def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): + payload = encodeVarint(fatal) + payload += encodeVarint(banTime) + payload += encodeVarint(len(inventoryVector)) + payload += inventoryVector + payload += encodeVarint(len(errorText)) + payload += errorText + return CreatePacket('error', payload) + +def lookupAppdataFolder(): + APPNAME = "PyBitmessage" + if "BITMESSAGE_HOME" in environ: + dataFolder = environ["BITMESSAGE_HOME"] + if dataFolder[-1] not in [os.path.sep, os.path.altsep]: + dataFolder += os.path.sep + elif sys.platform == 'darwin': + if "HOME" in environ: + dataFolder = path.join(os.environ["HOME"], "Library/Application Support/", APPNAME) + '/' + else: + stringToLog = 'Could not find home folder, please report this message and your OS X version to the BitMessage Github.' + if 'logger' in globals(): + logger.critical(stringToLog) + else: + print stringToLog + sys.exit() + + elif 'win32' in sys.platform or 'win64' in sys.platform: + dataFolder = path.join(environ['APPDATA'].decode(sys.getfilesystemencoding(), 'ignore'), APPNAME) + path.sep + else: + from shutil import move + try: + dataFolder = path.join(environ["XDG_CONFIG_HOME"], APPNAME) + except KeyError: + dataFolder = path.join(environ["HOME"], ".config", APPNAME) + + # Migrate existing data to the proper location if this is an existing install + try: + move(path.join(environ["HOME"], ".%s" % APPNAME), dataFolder) + stringToLog = "Moving data folder to %s" % (dataFolder) + if 'logger' in globals(): + logger.info(stringToLog) + else: + print stringToLog + except IOError: + # Old directory may not exist. + pass + dataFolder = dataFolder + '/' + return dataFolder def isAddressInMyAddressBook(address): queryreturn = sqlQuery( @@ -82,6 +246,12 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return True return False +def safeConfigGetBoolean(section,field): + try: + return config.getboolean(section,field) + except Exception, err: + return False + def decodeWalletImportFormat(WIFstring): fullString = arithmetic.changebase(WIFstring,58,256) privkey = fullString[:-4] @@ -109,31 +279,33 @@ def reloadMyAddressHashes(): myAddressesByTag.clear() #myPrivateKeys.clear() - keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') + keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') + configSections = config.sections() hasEnabledKeys = False - for addressInKeysFile in BMConfigParser().addresses(): - isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') - if isEnabled: - hasEnabledKeys = True - status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile) - if addressVersionNumber == 2 or addressVersionNumber == 3 or addressVersionNumber == 4: - # Returns a simple 32 bytes of information encoded in 64 Hex characters, - # or null if there was an error. - privEncryptionKey = hexlify(decodeWalletImportFormat( - BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))) + for addressInKeysFile in configSections: + if addressInKeysFile <> 'bitmessagesettings': + isEnabled = config.getboolean(addressInKeysFile, 'enabled') + if isEnabled: + hasEnabledKeys = True + status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile) + if addressVersionNumber == 2 or addressVersionNumber == 3 or addressVersionNumber == 4: + # Returns a simple 32 bytes of information encoded in 64 Hex characters, + # or null if there was an error. + privEncryptionKey = decodeWalletImportFormat( + config.get(addressInKeysFile, 'privencryptionkey')).encode('hex') - if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters - myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) - myAddressesByHash[hash] = addressInKeysFile - tag = hashlib.sha512(hashlib.sha512(encodeVarint( - addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()[32:] - myAddressesByTag[tag] = addressInKeysFile + if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters + myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) + myAddressesByHash[hash] = addressInKeysFile + tag = hashlib.sha512(hashlib.sha512(encodeVarint( + addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest()[32:] + myAddressesByTag[tag] = addressInKeysFile - else: - logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n') + else: + logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n') if not keyfileSecure: - fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) + fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) def reloadBroadcastSendersForWhichImWatching(): broadcastSendersForWhichImWatching.clear() @@ -149,13 +321,92 @@ def reloadBroadcastSendersForWhichImWatching(): if addressVersionNumber <= 3: privEncryptionKey = hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+hash).digest()[:32] - MyECSubscriptionCryptorObjects[hash] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) + MyECSubscriptionCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex')) else: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() tag = doubleHashOfAddressData[32:] privEncryptionKey = doubleHashOfAddressData[:32] - MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) + MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex')) + +def isProofOfWorkSufficient(data, + nonceTrialsPerByte=0, + payloadLengthExtraBytes=0): + if nonceTrialsPerByte < networkDefaultProofOfWorkNonceTrialsPerByte: + nonceTrialsPerByte = networkDefaultProofOfWorkNonceTrialsPerByte + if payloadLengthExtraBytes < networkDefaultPayloadLengthExtraBytes: + payloadLengthExtraBytes = networkDefaultPayloadLengthExtraBytes + endOfLifeTime, = unpack('>Q', data[8:16]) + TTL = endOfLifeTime - int(time.time()) + if TTL < 300: + TTL = 300 + POW, = unpack('>Q', hashlib.sha512(hashlib.sha512(data[ + :8] + hashlib.sha512(data[8:]).digest()).digest()).digest()[0:8]) + return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16)))) + +def doCleanShutdown(): + global shutdown + shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. + broadcastToSendDataQueues((0, 'shutdown', 'no data')) + with shared.objectProcessorQueueSizeLock: + data = 'no data' + shared.objectProcessorQueueSize += len(data) + objectProcessorQueue.put(('checkShutdownVariable',data)) + + knownNodesLock.acquire() + UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) + output = open(appdata + 'knownnodes.dat', 'wb') + logger.info('finished opening knownnodes.dat. Now pickle.dump') + pickle.dump(knownNodes, output) + logger.info('Completed pickle.dump. Closing output...') + output.close() + knownNodesLock.release() + logger.info('Finished closing knownnodes.dat output file.') + UISignalQueue.put(('updateStatusBar','Done saving the knownNodes list of peers to disk.')) + + logger.info('Flushing inventory in memory out to disk...') + UISignalQueue.put(( + 'updateStatusBar', + 'Flushing inventory in memory out to disk. This should normally only take a second...')) + flushInventory() + + import upnp + upnp.deletePortMapping() + # Verify that the objectProcessor has finished exiting. It should have incremented the + # shutdown variable from 1 to 2. This must finish before we command the sqlThread to exit. + while shutdown == 1: + time.sleep(.1) + + # This one last useless query will guarantee that the previous flush committed and that the + # objectProcessorThread committed before we close the program. + sqlQuery('SELECT address FROM subscriptions') + logger.info('Finished flushing inventory.') + sqlStoredProcedure('exit') + + # Wait long enough to guarantee that any running proof of work worker threads will check the + # shutdown variable and exit. If the main thread closes before they do then they won't stop. + time.sleep(.25) + + if safeConfigGetBoolean('bitmessagesettings','daemon'): + logger.info('Clean shutdown complete.') + os._exit(0) + +# If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this +# function puts your data into the queues for each of the sendDataThreads. The sendDataThreads are +# responsible for putting their queue into (and out of) the sendDataQueues list. +def broadcastToSendDataQueues(data): + # logger.debug('running broadcastToSendDataQueues') + for q in sendDataQueues: + q.put(data) + +def flushInventory(): + #Note that the singleCleanerThread clears out the inventory dictionary from time to time, although it only clears things that have been in the dictionary for a long time. This clears the inventory dictionary Now. + with SqlBulkExecute() as sql: + for hash, storedValue in inventory.items(): + objectType, streamNumber, payload, expiresTime, tag = storedValue + sql.execute('''INSERT INTO inventory VALUES (?,?,?,?,?,?)''', + hash,objectType,streamNumber,payload,expiresTime,tag) + del inventory[hash] def fixPotentiallyInvalidUTF8Data(text): try: @@ -255,7 +506,7 @@ def decryptAndCheckPubkeyPayload(data, address): encryptedData = data[readPosition:] # Let us try to decrypt the pubkey - toAddress, cryptorObject = state.neededPubkeys[tag] + toAddress, cryptorObject = shared.neededPubkeys[tag] if toAddress != address: logger.critical('decryptAndCheckPubkeyPayload failed due to toAddress mismatch. This is very peculiar. toAddress: %s, address %s' % (toAddress, address)) # the only way I can think that this could happen is if someone encodes their address data two different ways. @@ -289,7 +540,7 @@ def decryptAndCheckPubkeyPayload(data, address): readPosition += signatureLengthLength signature = decryptedData[readPosition:readPosition + signatureLength] - if highlevelcrypto.verify(signedData, signature, hexlify(publicSigningKey)): + if highlevelcrypto.verify(signedData, signature, publicSigningKey.encode('hex')): logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)') else: logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)') @@ -315,9 +566,9 @@ def decryptAndCheckPubkeyPayload(data, address): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - hexlify(ripe), - hexlify(publicSigningKey), - hexlify(publicEncryptionKey) + ripe.encode('hex'), + publicSigningKey.encode('hex'), + publicEncryptionKey.encode('hex') ) ) @@ -331,6 +582,8 @@ def decryptAndCheckPubkeyPayload(data, address): logger.critical('Pubkey decryption was UNsuccessful because of an unhandled exception! This is definitely a bug! \n%s' % traceback.format_exc()) return 'failed' +Peer = collections.namedtuple('Peer', ['host', 'port']) + def checkAndShareObjectWithPeers(data): """ This function is called after either receiving an object off of the wire @@ -342,7 +595,7 @@ def checkAndShareObjectWithPeers(data): logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data)) return 0 # Let us check to make sure that the proof of work is sufficient. - if not protocol.isProofOfWorkSufficient(data): + if not isProofOfWorkSufficient(data): logger.info('Proof of work is insufficient.') return 0 @@ -385,19 +638,28 @@ def _checkAndShareUndefinedObjectWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in state.streamsInWhichIAmParticipating: + if not streamNumber in streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): + shared.numberOfInventoryLookupsPerformed += 1 + inventoryLock.acquire() + if inventoryHash in inventory: logger.debug('We have already received this undefined object. Ignoring.') + inventoryLock.release() + return + elif isInSqlInventory(inventoryHash): + logger.debug('We have already received this undefined object (it is stored on disk in the SQL inventory). Ignoring it.') + inventoryLock.release() return objectType, = unpack('>I', data[16:20]) - Inventory()[inventoryHash] = ( + inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + inventorySets[streamNumber].add(inventoryHash) + inventoryLock.release() + logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) def _checkAndShareMsgWithPeers(data): @@ -408,28 +670,44 @@ def _checkAndShareMsgWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in state.streamsInWhichIAmParticipating: + if not streamNumber in streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): + shared.numberOfInventoryLookupsPerformed += 1 + inventoryLock.acquire() + if inventoryHash in inventory: logger.debug('We have already received this msg message. Ignoring.') + inventoryLock.release() + return + elif isInSqlInventory(inventoryHash): + logger.debug('We have already received this msg message (it is stored on disk in the SQL inventory). Ignoring it.') + inventoryLock.release() return # This msg message is valid. Let's let our peers know about it. objectType = 2 - Inventory()[inventoryHash] = ( + inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + inventorySets[streamNumber].add(inventoryHash) + inventoryLock.release() + logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) + # If we already have too much data in the queue to be processed, just sleep for now. + while shared.objectProcessorQueueSize > 120000000: + time.sleep(2) + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize += len(data) + objectProcessorQueue.put((objectType,data)) def _checkAndShareGetpubkeyWithPeers(data): if len(data) < 42: logger.info('getpubkey message doesn\'t contain enough data. Ignoring.') return + if len(data) > 200: + logger.info('getpubkey is abnormally long. Sanity check failed. Ignoring object.') embeddedTime, = unpack('>Q', data[8:16]) readPosition = 20 # bypass the nonce, time, and object type requestedAddressVersionNumber, addressVersionLength = decodeVarint( @@ -437,25 +715,39 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += addressVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 10]) - if not streamNumber in state.streamsInWhichIAmParticipating: + if not streamNumber in streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength + shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): + inventoryLock.acquire() + if inventoryHash in inventory: logger.debug('We have already received this getpubkey request. Ignoring it.') + inventoryLock.release() + return + elif isInSqlInventory(inventoryHash): + logger.debug('We have already received this getpubkey request (it is stored on disk in the SQL inventory). Ignoring it.') + inventoryLock.release() return objectType = 0 - Inventory()[inventoryHash] = ( + inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') + inventorySets[streamNumber].add(inventoryHash) + inventoryLock.release() # This getpubkey request is valid. Forward to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) + # If we already have too much data in the queue to be processed, just sleep for now. + while shared.objectProcessorQueueSize > 120000000: + time.sleep(2) + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize += len(data) + objectProcessorQueue.put((objectType,data)) def _checkAndSharePubkeyWithPeers(data): if len(data) < 146 or len(data) > 440: # sanity check @@ -468,29 +760,43 @@ def _checkAndSharePubkeyWithPeers(data): streamNumber, varintLength = decodeVarint( data[readPosition:readPosition + 10]) readPosition += varintLength - if not streamNumber in state.streamsInWhichIAmParticipating: + if not streamNumber in streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if addressVersion >= 4: tag = data[readPosition:readPosition + 32] - logger.debug('tag in received pubkey is: %s' % hexlify(tag)) + logger.debug('tag in received pubkey is: %s' % tag.encode('hex')) else: tag = '' + shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): + inventoryLock.acquire() + if inventoryHash in inventory: logger.debug('We have already received this pubkey. Ignoring it.') + inventoryLock.release() + return + elif isInSqlInventory(inventoryHash): + logger.debug('We have already received this pubkey (it is stored on disk in the SQL inventory). Ignoring it.') + inventoryLock.release() return objectType = 1 - Inventory()[inventoryHash] = ( + inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) + inventorySets[streamNumber].add(inventoryHash) + inventoryLock.release() # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) + # If we already have too much data in the queue to be processed, just sleep for now. + while shared.objectProcessorQueueSize > 120000000: + time.sleep(2) + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize += len(data) + objectProcessorQueue.put((objectType,data)) def _checkAndShareBroadcastWithPeers(data): @@ -505,33 +811,64 @@ def _checkAndShareBroadcastWithPeers(data): if broadcastVersion >= 2: streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) readPosition += streamNumberLength - if not streamNumber in state.streamsInWhichIAmParticipating: + if not streamNumber in streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if broadcastVersion >= 3: tag = data[readPosition:readPosition+32] else: tag = '' + shared.numberOfInventoryLookupsPerformed += 1 + inventoryLock.acquire() inventoryHash = calculateInventoryHash(data) - if inventoryHash in Inventory(): + if inventoryHash in inventory: logger.debug('We have already received this broadcast object. Ignoring.') + inventoryLock.release() + return + elif isInSqlInventory(inventoryHash): + logger.debug('We have already received this broadcast object (it is stored on disk in the SQL inventory). Ignoring it.') + inventoryLock.release() return # It is valid. Let's let our peers know about it. objectType = 3 - Inventory()[inventoryHash] = ( + inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) + inventorySets[streamNumber].add(inventoryHash) + inventoryLock.release() # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. - objectProcessorQueue.put((objectType,data)) + # If we already have too much data in the queue to be processed, just sleep for now. + while shared.objectProcessorQueueSize > 120000000: + time.sleep(2) + with shared.objectProcessorQueueSizeLock: + shared.objectProcessorQueueSize += len(data) + objectProcessorQueue.put((objectType,data)) def openKeysFile(): if 'linux' in sys.platform: - import subprocess - subprocess.call(["xdg-open", state.appdata + 'keys.dat']) + subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) else: - os.startfile(state.appdata + 'keys.dat') + os.startfile(shared.appdata + 'keys.dat') + +def writeKeysFile(): + fileName = shared.appdata + 'keys.dat' + fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak' + # create a backup copy to prevent the accidental loss due to the disk write failure + try: + shutil.copyfile(fileName, fileNameBak) + # The backup succeeded. + fileNameExisted = True + except: + # The backup failed. This can happen if the file didn't exist before. + fileNameExisted = False + # write the file + with open(fileName, 'wb') as configfile: + shared.config.write(configfile) + # delete the backup + if fileNameExisted: + os.remove(fileNameBak) from debug import logger diff --git a/src/shutdown.py b/src/shutdown.py deleted file mode 100644 index f447148b..00000000 --- a/src/shutdown.py +++ /dev/null @@ -1,69 +0,0 @@ -import os -import Queue -import threading -import time - -from debug import logger -from helper_sql import sqlQuery, sqlStoredProcedure -from helper_threading import StoppableThread -from knownnodes import saveKnownNodes -from inventory import Inventory -from queues import addressGeneratorQueue, objectProcessorQueue, UISignalQueue, workerQueue -import shared -import state - -def doCleanShutdown(): - state.shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. - objectProcessorQueue.put(('checkShutdownVariable', 'no data')) - for thread in threading.enumerate(): - if thread.isAlive() and isinstance(thread, StoppableThread): - thread.stopThread() - - UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) - logger.info('Saving knownNodes list of peers to disk') - saveKnownNodes() - logger.info('Done saving knownNodes list of peers to disk') - UISignalQueue.put(('updateStatusBar','Done saving the knownNodes list of peers to disk.')) - logger.info('Flushing inventory in memory out to disk...') - UISignalQueue.put(( - 'updateStatusBar', - 'Flushing inventory in memory out to disk. This should normally only take a second...')) - Inventory().flush() - - # Verify that the objectProcessor has finished exiting. It should have incremented the - # shutdown variable from 1 to 2. This must finish before we command the sqlThread to exit. - while state.shutdown == 1: - time.sleep(.1) - - # This one last useless query will guarantee that the previous flush committed and that the - # objectProcessorThread committed before we close the program. - sqlQuery('SELECT address FROM subscriptions') - logger.info('Finished flushing inventory.') - sqlStoredProcedure('exit') - - # Wait long enough to guarantee that any running proof of work worker threads will check the - # shutdown variable and exit. If the main thread closes before they do then they won't stop. - time.sleep(.25) - - for thread in threading.enumerate(): - if thread is not threading.currentThread() and isinstance(thread, StoppableThread): - logger.debug("Waiting for thread %s", thread.name) - thread.join() - - # flush queued - for queue in (workerQueue, UISignalQueue, addressGeneratorQueue, objectProcessorQueue): - while True: - try: - queue.get(False) - queue.task_done() - except Queue.Empty: - break - - if shared.thisapp.daemon: - logger.info('Clean shutdown complete.') - shared.thisapp.cleanup() - os._exit(0) - else: - logger.info('Core shutdown complete.') - for thread in threading.enumerate(): - logger.debug("Thread %s still running", thread.name) diff --git a/src/singleinstance.py b/src/singleinstance.py deleted file mode 100644 index ed1048ba..00000000 --- a/src/singleinstance.py +++ /dev/null @@ -1,101 +0,0 @@ -#! /usr/bin/env python - -import atexit -import errno -from multiprocessing import Process -import os -import sys -import state - -try: - import fcntl # @UnresolvedImport -except: - pass - -class singleinstance: - """ - Implements a single instance application by creating a lock file at appdata. - - This is based upon the singleton class from tendo https://github.com/pycontribs/tendo - which is under the Python Software Foundation License version 2 - """ - def __init__(self, flavor_id="", daemon=False): - self.initialized = False - self.counter = 0 - self.daemon = daemon - self.lockPid = None - self.lockfile = os.path.normpath(os.path.join(state.appdata, 'singleton%s.lock' % flavor_id)) - - if not self.daemon and not state.curses: - # Tells the already running (if any) application to get focus. - import bitmessageqt - bitmessageqt.init() - - self.lock() - - self.initialized = True - atexit.register(self.cleanup) - - def lock(self): - if self.lockPid is None: - self.lockPid = os.getpid() - if sys.platform == 'win32': - try: - # file already exists, we try to remove (in case previous execution was interrupted) - if os.path.exists(self.lockfile): - os.unlink(self.lockfile) - self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR | os.O_TRUNC) - except OSError: - type, e, tb = sys.exc_info() - if e.errno == 13: - print 'Another instance of this application is already running' - sys.exit(-1) - print(e.errno) - raise - else: - pidLine = "%i\n" % self.lockPid - os.write(self.fd, pidLine) - else: # non Windows - self.fp = open(self.lockfile, 'a+') - try: - if self.daemon and self.lockPid != os.getpid(): - fcntl.lockf(self.fp, fcntl.LOCK_EX) # wait for parent to finish - else: - fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) - self.lockPid = os.getpid() - except IOError: - print 'Another instance of this application is already running' - sys.exit(-1) - else: - pidLine = "%i\n" % self.lockPid - self.fp.truncate(0) - self.fp.write(pidLine) - self.fp.flush() - - def cleanup(self): - if not self.initialized: - return - if self.daemon and self.lockPid == os.getpid(): - # these are the two initial forks while daemonizing - try: - if sys.platform == 'win32': - if hasattr(self, 'fd'): - os.close(self.fd) - else: - fcntl.lockf(self.fp, fcntl.LOCK_UN) - except Exception, e: - pass - - return - print "Cleaning up lockfile" - try: - if sys.platform == 'win32': - if hasattr(self, 'fd'): - os.close(self.fd) - os.unlink(self.lockfile) - else: - fcntl.lockf(self.fp, fcntl.LOCK_UN) - if os.path.isfile(self.lockfile): - os.unlink(self.lockfile) - except Exception, e: - pass diff --git a/src/singleton.py b/src/singleton.py index 1eef08e1..ee5c3077 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -1,7 +1,61 @@ -def Singleton(cls): - instances = {} - def getinstance(): - if cls not in instances: - instances[cls] = cls() - return instances[cls] - return getinstance +#! /usr/bin/env python + +import sys +import os +import errno +import tempfile +from multiprocessing import Process + + +class singleinstance: + """ + Implements a single instance application by creating a lock file based on the full path to the script file. + + This is based upon the singleton class from tendo https://github.com/pycontribs/tendo + which is under the Python Software Foundation License version 2 + """ + def __init__(self, flavor_id=""): + import sys + self.initialized = False + basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock' + self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename) + + if sys.platform == 'win32': + try: + # file already exists, we try to remove (in case previous execution was interrupted) + if os.path.exists(self.lockfile): + os.unlink(self.lockfile) + self.fd = os.open(self.lockfile, os.O_CREAT | os.O_EXCL | os.O_RDWR) + except OSError: + type, e, tb = sys.exc_info() + if e.errno == 13: + print 'Another instance of this application is already running' + sys.exit(-1) + print(e.errno) + raise + else: # non Windows + import fcntl # @UnresolvedImport + self.fp = open(self.lockfile, 'w') + try: + fcntl.lockf(self.fp, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError: + print 'Another instance of this application is already running' + sys.exit(-1) + self.initialized = True + + def __del__(self): + import sys + if not self.initialized: + return + try: + if sys.platform == 'win32': + if hasattr(self, 'fd'): + os.close(self.fd) + os.unlink(self.lockfile) + else: + import fcntl # @UnresolvedImport + fcntl.lockf(self.fp, fcntl.LOCK_UN) + if os.path.isfile(self.lockfile): + os.unlink(self.lockfile) + except Exception, e: + sys.exit(-1) diff --git a/src/socks/__init__.py b/src/socks/__init__.py index 0bfa18f5..ebb68f45 100644 --- a/src/socks/__init__.py +++ b/src/socks/__init__.py @@ -63,11 +63,7 @@ _generalerrors = ("success", "not connected", "not available", "bad proxy type", - "bad input", - "timed out", - "network unreachable", - "connection refused", - "host unreachable") + "bad input") _socks5errors = ("succeeded", "general SOCKS server failure", @@ -133,10 +129,7 @@ class socksocket(socket.socket): Receive EXACTLY the number of bytes requested from the socket. Blocks until the required number of bytes have been received. """ - try: - data = self.recv(count) - except socket.timeout: - raise GeneralProxyError((6, "timed out")) + data = self.recv(count) while len(data) < count: d = self.recv(count-len(data)) if not d: raise GeneralProxyError((0, "connection closed unexpectedly")) @@ -162,7 +155,7 @@ class socksocket(socket.socket): """ self.__proxy = (proxytype, addr, port, rdns, username, password) - def __negotiatesocks5(self): + def __negotiatesocks5(self, destaddr, destport): """__negotiatesocks5(self,destaddr,destport) Negotiates a connection through a SOCKS5 server. """ @@ -207,8 +200,6 @@ class socksocket(socket.socket): raise Socks5AuthError((2, _socks5autherrors[2])) else: raise GeneralProxyError((1, _generalerrors[1])) - - def __connectsocks5(self, destaddr, destport): # Now we can request the actual connection req = struct.pack('BBB', 0x05, 0x01, 0x00) # If the given destination address is an IP address, we'll @@ -256,37 +247,6 @@ class socksocket(socket.socket): else: self.__proxypeername = (destaddr, destport) - def __resolvesocks5(self, host): - # Now we can request the actual connection - req = struct.pack('BBB', 0x05, 0xF0, 0x00) - req += chr(0x03).encode() + chr(len(host)).encode() + host - req = req + struct.pack(">H", 8444) - self.sendall(req) - # Get the response - ip = "" - resp = self.__recvall(4) - if resp[0:1] != chr(0x05).encode(): - self.close() - raise GeneralProxyError((1, _generalerrors[1])) - elif resp[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(resp[1:2])<=8: - raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) - else: - raise Socks5Error((9, _socks5errors[9])) - # Get the bound address/port - elif resp[3:4] == chr(0x01).encode(): - ip = socket.inet_ntoa(self.__recvall(4)) - elif resp[3:4] == chr(0x03).encode(): - resp = resp + self.recv(1) - ip = self.__recvall(ord(resp[4:5])) - else: - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - boundport = struct.unpack(">H", self.__recvall(2))[0] - return ip - def getproxysockname(self): """getsockname() -> address info Returns the bound IP address and port number at the proxy. @@ -306,9 +266,6 @@ class socksocket(socket.socket): """ return self.__proxypeername - def getproxytype(self): - return self.__proxy[0] - def __negotiatesocks4(self,destaddr,destport): """__negotiatesocks4(self,destaddr,destport) Negotiates a connection through a SOCKS4 server. @@ -403,21 +360,8 @@ class socksocket(socket.socket): portnum = self.__proxy[2] else: portnum = 1080 - try: - _orgsocket.connect(self, (self.__proxy[1], portnum)) - except socket.error as e: - # ENETUNREACH, WSAENETUNREACH - if e[0] in [101, 10051]: - raise GeneralProxyError((7, _generalerrors[7])) - # ECONNREFUSED, WSAECONNREFUSED - if e[0] in [111, 10061]: - raise GeneralProxyError((8, _generalerrors[8])) - # EHOSTUNREACH, WSAEHOSTUNREACH - if e[0] in [113, 10065]: - raise GeneralProxyError((9, _generalerrors[9])) - raise - self.__negotiatesocks5() - self.__connectsocks5(destpair[0], destpair[1]) + _orgsocket.connect(self, (self.__proxy[1], portnum)) + self.__negotiatesocks5(destpair[0], destpair[1]) elif self.__proxy[0] == PROXY_TYPE_SOCKS4: if self.__proxy[2] != None: portnum = self.__proxy[2] @@ -430,33 +374,9 @@ class socksocket(socket.socket): portnum = self.__proxy[2] else: portnum = 8080 - try: - _orgsocket.connect(self,(self.__proxy[1], portnum)) - except socket.error as e: - # ENETUNREACH, WSAENETUNREACH - if e[0] in [101, 10051]: - raise GeneralProxyError((7, _generalerrors[7])) - # ECONNREFUSED, WSAECONNREFUSED - if e[0] in [111, 10061]: - raise GeneralProxyError((8, _generalerrors[8])) - # EHOSTUNREACH, WSAEHOSTUNREACH - if e[0] in [113, 10065]: - raise GeneralProxyError((9, _generalerrors[9])) - raise + _orgsocket.connect(self,(self.__proxy[1], portnum)) self.__negotiatehttp(destpair[0], destpair[1]) elif self.__proxy[0] == None: _orgsocket.connect(self, (destpair[0], destpair[1])) else: raise GeneralProxyError((4, _generalerrors[4])) - - def resolve(self, host): - if self.__proxy[0] == PROXY_TYPE_SOCKS5: - if self.__proxy[2] != None: - portnum = self.__proxy[2] - else: - portnum = 1080 - _orgsocket.connect(self, (self.__proxy[1], portnum)) - self.__negotiatesocks5() - return self.__resolvesocks5(host) - else: - return None diff --git a/src/sslkeys/cert.pem b/src/sslkeys/cert.pem deleted file mode 100644 index a976db75..00000000 --- a/src/sslkeys/cert.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICWDCCAcGgAwIBAgIJAJs5yni/cDh5MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTUxMTEzMDk1NTU3WhcNMTUxMTE0MDk1NTU3WjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQCg8XkFpIAYsTSBealTubvu4dzpMnnAOwANG5K9TJeclG9O65cmKWpH8k3hNDif -xagIAI8UanBsQo6SQrK1Iby2kz6DCKmySO1OwoNOOF0Ok31N+5aWsQvYF1wLbk2m -Ti/CSLWBgL25ywCCiP3Mgr+krapT4TrfvF4gCchUdcxMQQIDAQABo1AwTjAdBgNV -HQ4EFgQUWuFUJQC6zu6OTDgHZzhfZxsgJOMwHwYDVR0jBBgwFoAUWuFUJQC6zu6O -TDgHZzhfZxsgJOMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAT1I/x -GbsYAE4pM4sVQrcuz7jLwr3k5Zve0z4WKR41W17Nc44G3DyLbkTWYESLfAYsivkx -tRRtYTtJm1qmTPtedXQJK+wJGNHCWRfwSB2CYwmO7+C2rYYzkFndN68kB6RJmyOr -eCX+9vkbQqgh7KfiNquJxCfMSDfhA2RszU43jg== ------END CERTIFICATE----- diff --git a/src/sslkeys/key.pem b/src/sslkeys/key.pem deleted file mode 100644 index a47bcc3c..00000000 --- a/src/sslkeys/key.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKDxeQWkgBixNIF5 -qVO5u+7h3OkyecA7AA0bkr1Ml5yUb07rlyYpakfyTeE0OJ/FqAgAjxRqcGxCjpJC -srUhvLaTPoMIqbJI7U7Cg044XQ6TfU37lpaxC9gXXAtuTaZOL8JItYGAvbnLAIKI -/cyCv6StqlPhOt+8XiAJyFR1zExBAgMBAAECgYEAmd2hpQpayMCJgQsOHhRgnoXi -jDOMgIInj2CADmguPi0OqTXEoGBR0ozNdfNV+zGdbmESaSNFbcrHwP7xGQgzABlv -5ANLgBYrHnW/oFCCuw4Lj/CAAHRA4its+2wzf13BYoVitDiYBt3JMRqwLV03aHyy -Oqhvt2nVicz85+HERj0CQQDMJAPUIyOQLO+BPC5MsuxyQFJgie0aB5swumxanOv4 -J8GIvulNEJMG/dq+h/x4paV2LGDlUAOsBUmjXfTPMQAHAkEAydQtYorqYqhFZWWD -3lUMAoa8pGb6BfNXUqxdH0H8fk6B7OxYPpvwm7ce1lD1Oje3/+rMnn8i6A1p9HUy -l9wvdwJAdhxIUs7Z3qsBD8bgCuRixV/NyalDk5HfCnxyAKNWK8fkw9ehaEM0rhDm -JOLNAojkiND4ZvS6iyasCmdsIwx4tQJAAV+eR3NmkPFQN5ZvRU4S3NmJ4xyISw4S -5A8kOxg53aovHCunlhV9l7GxVggLAzBp4iX46oM2+5lLxUwe4gWvlQJBAK0IR8bB -85bKZ+M/O8rbs9kQHjx6GCbbDxH+qbIKkNcvLUvMgwwIFKiwqX+Tedtu2xET0mQM -9tEE5eMBOJ8GrxQ= ------END PRIVATE KEY----- diff --git a/src/state.py b/src/state.py deleted file mode 100644 index 73e4f789..00000000 --- a/src/state.py +++ /dev/null @@ -1,57 +0,0 @@ -import collections - -neededPubkeys = {} -streamsInWhichIAmParticipating = [] -sendDataQueues = [] #each sendData thread puts its queue in this list. - -# For UPnP -extPort = None - -# for Tor hidden service -socksIP = None - -# Network protocols availability, initialised below -networkProtocolAvailability = None - -appdata = '' #holds the location of the application data storage directory - -shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. - -curses = False - -sqlReady = False # set to true by sqlTread when ready for processing - -maximumNumberOfHalfOpenConnections = 0 - -invThread = None -addrThread = None -downloadThread = None - -ownAddresses = {} - -# If the trustedpeer option is specified in keys.dat then this will -# contain a Peer which will be connected to instead of using the -# addresses advertised by other peers. The client will only connect to -# this peer and the timing attack mitigation will be disabled in order -# to download data faster. The expected use case is where the user has -# a fast connection to a trusted server where they run a BitMessage -# daemon permanently. If they then run a second instance of the client -# on a local machine periodically when they want to check for messages -# it will sync with the network a lot faster without compromising -# security. -trustedPeer = None - -discoveredPeers = {} - -# tracking pending downloads globally, for stats -missingObjects = {} - -Peer = collections.namedtuple('Peer', ['host', 'port']) - -def resetNetworkProtocolAvailability(): - global networkProtocolAvailability - networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} - -resetNetworkProtocolAvailability() - -dandelion = 0 diff --git a/src/storage/__init__.py b/src/storage/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py deleted file mode 100644 index d64894a9..00000000 --- a/src/storage/filesystem.py +++ /dev/null @@ -1,175 +0,0 @@ -from binascii import hexlify, unhexlify -from os import listdir, makedirs, path, remove, rmdir -import string -from threading import RLock -import time -import traceback - -from paths import lookupAppdataFolder -from storage import InventoryStorage, InventoryItem - -class FilesystemInventory(InventoryStorage): - topDir = "inventory" - objectDir = "objects" - metadataFilename = "metadata" - dataFilename = "data" - - def __init__(self): - super(self.__class__, self).__init__() - self.baseDir = path.join(lookupAppdataFolder(), FilesystemInventory.topDir) - for createDir in [self.baseDir, path.join(self.baseDir, "objects")]: - if path.exists(createDir): - if not path.isdir(createDir): - raise IOError("%s exists but it's not a directory" % (createDir)) - else: - makedirs(createDir) - self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) - self._inventory = {} - self._load() - - def __contains__(self, hash): - retval = False - for streamDict in self._inventory.values(): - if hash in streamDict: - return True - return False - - def __getitem__(self, hash): - for streamDict in self._inventory.values(): - try: - retval = streamDict[hash] - except KeyError: - continue - if retval.payload is None: - retval = InventoryItem(retval.type, retval.stream, self.getData(hash), retval.expires, retval.tag) - return retval - raise KeyError(hash) - - def __setitem__(self, hash, value): - with self.lock: - value = InventoryItem(*value) - try: - makedirs(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash))) - except OSError: - pass - try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.metadataFilename), 'w') as f: - f.write("%s,%s,%s,%s," % (value.type, value.stream, value.expires, hexlify(value.tag))) - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.dataFilename), 'w') as f: - f.write(value.payload) - except IOError: - raise KeyError - try: - self._inventory[value.stream][hash] = value - except KeyError: - self._inventory[value.stream] = {} - self._inventory[value.stream][hash] = value - - def delHashId(self, hash): - for stream in self._inventory.keys(): - try: - del self._inventory[stream][hash] - except KeyError: - pass - with self.lock: - try: - remove(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.metadataFilename)) - except IOError: - pass - try: - remove(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash), FilesystemInventory.dataFilename)) - except IOError: - pass - try: - rmdir(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hash))) - except IOError: - pass - - def __iter__(self): - elems = [] - for streamDict in self._inventory.values(): - elems.extend (streamDict.keys()) - return elems.__iter__() - - def __len__(self): - retval = 0 - for streamDict in self._inventory.values(): - retval += len(streamDict) - return retval - - def _load(self): - newInventory = {} - for hashId in self.object_list(): - try: - objectType, streamNumber, expiresTime, tag = self.getMetadata(hashId) - try: - newInventory[streamNumber][hashId] = InventoryItem(objectType, streamNumber, None, expiresTime, tag) - except KeyError: - newInventory[streamNumber] = {} - newInventory[streamNumber][hashId] = InventoryItem(objectType, streamNumber, None, expiresTime, tag) - except KeyError: - print "error loading %s" % (hexlify(hashId)) - pass - self._inventory = newInventory -# for i, v in self._inventory.items(): -# print "loaded stream: %s, %i items" % (i, len(v)) - - def stream_list(self): - return self._inventory.keys() - - def object_list(self): - return [unhexlify(x) for x in listdir(path.join(self.baseDir, FilesystemInventory.objectDir))] - - def getData(self, hashId): - try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashId), FilesystemInventory.dataFilename), 'r') as f: - return f.read() - except IOError: - raise AttributeError - - def getMetadata(self, hashId): - try: - with open(path.join(self.baseDir, FilesystemInventory.objectDir, hexlify(hashId), FilesystemInventory.metadataFilename), 'r') as f: - objectType, streamNumber, expiresTime, tag, undef = string.split(f.read(), ",", 4) - return [int(objectType), int(streamNumber), int(expiresTime), unhexlify(tag)] - except IOError: - raise KeyError - - def by_type_and_tag(self, objectType, tag): - retval = [] - for stream, streamDict in self._inventory: - for hashId, item in streamDict: - if item.type == objectType and item.tag == tag: - try: - if item.payload is None: - item.payload = self.getData(hashId) - except IOError: - continue - retval.append(InventoryItem(item.type, item.stream, item.payload, item.expires, item.tag)) - return retval - - def hashes_by_stream(self, stream): - try: - return self._inventory[stream].keys() - except KeyError: - return [] - - def unexpired_hashes_by_stream(self, stream): - t = int(time.time()) - try: - return [x for x, value in self._inventory[stream].items() if value.expires > t] - except KeyError: - return [] - - def flush(self): - self._load() - - def clean(self): - minTime = int(time.time()) - (60 * 60 * 30) - deletes = [] - for stream, streamDict in self._inventory.items(): - for hashId, item in streamDict.items(): - if item.expires < minTime: - deletes.append(hashId) - for hashId in deletes: - self.delHashId(hashId) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py deleted file mode 100644 index 438cbdcb..00000000 --- a/src/storage/sqlite.py +++ /dev/null @@ -1,81 +0,0 @@ -import collections -from threading import current_thread, enumerate as threadingEnumerate, RLock -import Queue -import sqlite3 -import time - -from helper_sql import * -from storage import InventoryStorage, InventoryItem - -class SqliteInventory(InventoryStorage): - def __init__(self): - super(self.__class__, self).__init__() - self._inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet). - self._objects = {} # cache for existing objects, used for quick lookups if we have an object. This is used for example whenever we receive an inv message from a peer to check to see what items are new to us. We don't delete things out of it; instead, the singleCleaner thread clears and refills it. - self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) - - def __contains__(self, hash): - with self.lock: - if hash in self._objects: - return True - rows = sqlQuery('SELECT streamnumber FROM inventory WHERE hash=?', sqlite3.Binary(hash)) - if not rows: - return False - self._objects[hash] = rows[0][0] - return True - - def __getitem__(self, hash): - with self.lock: - if hash in self._inventory: - return self._inventory[hash] - rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', sqlite3.Binary(hash)) - if not rows: - raise KeyError(hash) - return InventoryItem(*rows[0]) - - def __setitem__(self, hash, value): - with self.lock: - value = InventoryItem(*value) - self._inventory[hash] = value - self._objects[hash] = value.stream - - def __delitem__(self, hash): - raise NotImplementedError - - def __iter__(self): - with self.lock: - hashes = self._inventory.keys()[:] - hashes += (x for x, in sqlQuery('SELECT hash FROM inventory')) - return hashes.__iter__() - - def __len__(self): - with self.lock: - return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0] - - def by_type_and_tag(self, objectType, tag): - with self.lock: - values = [value for value in self._inventory.values() if value.type == objectType and value.tag == tag] - values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', objectType, sqlite3.Binary(tag))) - return values - - def unexpired_hashes_by_stream(self, stream): - with self.lock: - t = int(time.time()) - hashes = [x for x, value in self._inventory.items() if value.stream == stream and value.expires > t] - hashes += (str(payload) for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) - return hashes - - def flush(self): - with self.lock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. - with SqlBulkExecute() as sql: - for objectHash, value in self._inventory.items(): - sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', sqlite3.Binary(objectHash), *value) - self._inventory.clear() - - def clean(self): - with self.lock: - sqlExecute('DELETE FROM inventory WHERE expirestime self.txTime: - self.speed = self.txLen / (now - self.txTime) - self.txLen -= self.limit * (now - self.txTime) - self.txTime = now - if self.txLen < 0 or self.limit == 0: - self.txLen = 0 - - def wait(self, dataLen): - with self.lock: - self.txLen += dataLen - self.total += dataLen - while state.shutdown == 0: - self.recalculate() - if self.limit == 0: - break - if self.txLen < self.limit: - break - self.timer.wait(0.2) - - def getSpeed(self): - self.recalculate() - return self.speed - - def resetChunkSize(self): - with self.lock: - # power of two smaller or equal to speed limit - try: - self.chunkSize = int(math.pow(2, int(math.log(self.limit,2)))) - except ValueError: - self.chunkSize = Throttle.maxChunkSize - # range check - if self.chunkSize < Throttle.minChunkSize: - self.chunkSize = Throttle.minChunkSize - elif self.chunkSize > Throttle.maxChunkSize: - self.chunkSize = Throttle.maxChunkSize - -@Singleton -class SendThrottle(Throttle): - def __init__(self): - Throttle.__init__(self, BMConfigParser().safeGetInt('bitmessagesettings', 'maxuploadrate')*1024) - - def resetLimit(self): - with self.lock: - self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxuploadrate')*1024 - Throttle.resetChunkSize(self) - -@Singleton -class ReceiveThrottle(Throttle): - def __init__(self): - Throttle.__init__(self, BMConfigParser().safeGetInt('bitmessagesettings', 'maxdownloadrate')*1024) - - def resetLimit(self): - with self.lock: - self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxdownloadrate')*1024 - Throttle.resetChunkSize(self) diff --git a/src/tr.py b/src/tr.py index cf7f16ac..c11d1f57 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,6 +1,5 @@ -import os - import shared +import os # This is used so that the translateText function can be used when we are in daemon mode and not using any QT functions. class translateClass: @@ -13,27 +12,20 @@ class translateClass: else: return self.text -def _translate(context, text, disambiguation = None, encoding = None, n = None): - return translateText(context, text, n) +def _translate(context, text): + return translateText(context, text) -def translateText(context, text, n = None): - try: - is_daemon = shared.thisapp.daemon - except AttributeError: # inside the plugin - is_daemon = False - if not is_daemon: +def translateText(context, text): + if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): try: from PyQt4 import QtCore, QtGui except Exception as err: 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' print 'Error message:', err os._exit(0) - if n is None: - return QtGui.QApplication.translate(context, text) - else: - return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, n) + return QtGui.QApplication.translate(context, text) else: if '%' in text: return translateClass(context, text.replace('%','',1)) else: - return text + return text \ No newline at end of file diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro deleted file mode 100644 index f5d6b946..00000000 --- a/src/translations/bitmessage.pro +++ /dev/null @@ -1,75 +0,0 @@ -SOURCES = ../addresses.py\ - ../bitmessagemain.py\ - ../class_addressGenerator.py\ - ../class_outgoingSynSender.py\ - ../class_objectProcessor.py\ - ../class_receiveDataThread.py\ - ../class_sendDataThread.py\ - ../class_singleCleaner.py\ - ../class_singleListener.py\ - ../class_singleWorker.py\ - ../class_sqlThread.py\ - ../helper_bitcoin.py\ - ../helper_bootstrap.py\ - ../helper_generic.py\ - ../helper_inbox.py\ - ../helper_msgcoding.py\ - ../helper_sent.py\ - ../helper_startup.py\ - ../namecoin.py\ - ../proofofwork.py\ - ../shared.py\ - ../upnp.py\ - ../bitmessageqt/__init__.py\ - ../bitmessageqt/account.py\ - ../bitmessageqt/address_dialogs.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/blacklist.py\ - ../bitmessageqt/dialogs.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/languagebox.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/networkstatus.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../plugins/qrcodeui.py - -FORMS = \ - ../bitmessageqt/about.ui\ - ../bitmessageqt/addaddressdialog.ui\ - ../bitmessageqt/blacklist.ui\ - ../bitmessageqt/connect.ui\ - ../bitmessageqt/emailgateway.ui\ - ../bitmessageqt/help.ui\ - ../bitmessageqt/iconglossary.ui\ - ../bitmessageqt/networkstatus.ui\ - ../bitmessageqt/newaddressdialog.ui\ - ../bitmessageqt/newchandialog.ui\ - ../bitmessageqt/newsubscriptiondialog.ui\ - ../bitmessageqt/regenerateaddresses.ui\ - ../bitmessageqt/specialaddressbehavior.ui - -TRANSLATIONS = \ - bitmessage_ar.ts \ - bitmessage_cs.ts \ - bitmessage_da.ts \ - bitmessage_de.ts \ - bitmessage_en.ts \ - bitmessage_en_pirate.ts \ - bitmessage_eo.ts \ - bitmessage_fr.ts \ - bitmessage_it.ts \ - bitmessage_ja.ts \ - bitmessage_nl.ts \ - bitmessage_no.ts \ - bitmessage_pl.ts \ - bitmessage_pt.ts \ - bitmessage_sk.ts \ - bitmessage_ru.ts \ - bitmessage_uk.ts \ - bitmessage_zh_cn.ts - -CODECFORTR = UTF-8 -CODECFORSRC = UTF-8 diff --git a/src/translations/bitmessage_ar.pro b/src/translations/bitmessage_ar.pro new file mode 100644 index 00000000..1cd8dd64 --- /dev/null +++ b/src/translations/bitmessage_ar.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_ar.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_ar.qm b/src/translations/bitmessage_ar.qm index 892f6160..477a7586 100644 Binary files a/src/translations/bitmessage_ar.qm and b/src/translations/bitmessage_ar.qm differ diff --git a/src/translations/bitmessage_ar.ts b/src/translations/bitmessage_ar.ts index 6bf906d7..b37dcc0b 100644 --- a/src/translations/bitmessage_ar.ts +++ b/src/translations/bitmessage_ar.ts @@ -1,351 +1,389 @@ - - - AddAddressDialog - - - Add new entry - إضافة مدخل جديد - - - - Label - إسم مستعار - - - - Address - عنوان - - - - EmailGatewayDialog - - - Email gateway - - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - + + MainWindow - - Reply to sender - + + Bitmessage + Bitmessage - - Reply to channel - + + To + إلى - - Add sender to your Address Book - إضافة جهة اتصال لدفتر العناوين + + From + من - - Add sender to your Blacklist - + + Subject + الموضوع - - Move to Trash - حذف إلى سلة المهملات + + Received + تاريخ الإستلام - - Undelete - + + Inbox + البريد الوارد - - View HTML code as formatted text - إظهار نظام تشفير HTML كنص منسق + + Load from Address book + تحميل من دفتر العناوين - - Save message as... - حفظ الرسالة ك + + Message: + الرسالة: - - Mark Unread - وضع علامة غير مقروء + + Subject: + الموضوع: - - New - جديد + + Send to one or more specific people + إرسال لشخص أو عدة أشخاص - - Enable - تفعيل + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + - - Disable - تعطيل + + To: + إلى: - - Set avatar... - تغيير الصورة الرمزية + + From: + من: - - Copy address to clipboard - نسخ العنوان إلى الحافظة + + Broadcast to everyone who is subscribed to your address + إرسال لجميع المتابعين - - Special address behavior... - سلوك عنوان خاص - - - - Email gateway - - - - - Delete - حذف - - - - Send message to this address - أرسل رسالة لهذا العنوان - - - - Subscribe to this address - متابعة هذا العنوان - - - - Add New Address - إضافة جهة إتصال - - - - Copy destination address to clipboard - نسخ عنوان المرسل إليه إلى الحافظة - - - - Force send - إرسال قصري - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - واحد من العناوين، %1، حاصل على رقم إصدار 1، العناوين ذات رقم الإصدار 1 غير مدعومه حالياً، هل باستطاعتنا حذفه الآن؟ - - - - Waiting for their encryption key. Will request it again soon. - - - - - Encryption key request queued. - تم إدراح طلب مفتاح التشفير بقائمة الإنتظار. - - - - Queued. - تم الإدراج بقائمة الانتظار - - - - Message sent. Waiting for acknowledgement. Sent at %1 - - - - - Message sent. Sent at %1 - تم إرسال الرسالة في %1 - - - - Need to do work to send message. Work is queued. - تحتاج لبعض العمل لإرسال الرسالة، تم إدراج العمل بقائمة الانتظار - - - - Acknowledgement of the message received %1 - تم استلام إشعار الاستلام للرسالة %1 - - - - Broadcast queued. - تم إدراج البث في قائمة الانتظار - - - - Broadcast on %1 - البث في %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - مشكلة: العمل المطلوب من قبل المستلم أصعب من ما كنت مستعد للقيام به %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - مشكلة: مفتاح تشفير المرسل إليه غير جيد، لا يمكن تشفير الرسالة. %1 - - - - Forced difficulty override. Send should start soon. - تم تجازو الصعوبة قصراً، ستبدأ الإرسال قريباً - - - - Unknown status: %1 %2 - حالة غير معروفه: %1 %2 - - - - Not Connected - غير متصل - - - - Show Bitmessage - إظهار Bitmessage - - - + Send إرسال - - Subscribe - إشتراك + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + إنتبه أن البث مشفر فقط بعنوانك، و يمكن لأي شخص يعرف عنوانك قراءة البث - - Channel - + + Status + الحالة - + + Sent + البريد المرسل + + + + New + جديد + + + + Label (not shown to anyone) + إسم مستعار خاص - غير مرئي للآخرين + + + + Address + العنوان + + + + Group + المجموعة + + + + Stream + مجرى + + + + Your Identities + هوياتك + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + هنا يمكن التسجيل لمتابعة مشاركات الآخرين، الرسائل ستظهر في البريد الوارد، و العناوين هنا تبطل العناوين في القائمة السوداء. + + + + Add new Subscription + إدخال إشتراك جديدة + + + + Label + إسم مستعار + + + + Subscriptions + الإشتراكات + + + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + دفتر العناوين مفيد لإضافة أسماء أو طوابع بريدية للأشخاص الآخرين مع عناوينهم لكي يسهل تمييزهم بسهولة في البريد الوارد، يمكنك إضافة جهات اتصال جديدة باستخدام زر إضافة أو من البريد الوارد بالضغط الأيمن على الرسالة الواردة. + + + + Add new entry + إضافة جهة اتصال جديدة + + + + Name or Label + إسم مستعار + + + + Address Book + دفتر العناوين + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + إستخدام القائمة السوداء - تسمح وصول كل الرسائل الواردة عدا العناوين المسجلة في القائمة السوداء + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + إستخدام القائمة البيضاء - تمنع وصول كل الرسائل الواردة عدا العناوين المسجلة في القائمة البيضاء + + + + Blacklist + القائمة السوداء + + + + Stream Number + Numéro de flux + + + + Number of Connections + Nombre de connexions + + + + Total connections: 0 + إجمالي الروابط + + + + Since startup at asdf: + منذ بداية التشغيل: + + + + Processed 0 person-to-person message. + تم معالجة 0 رسالة -شخص إلى شخص-. + + + + Processed 0 public key. + تم معالجة 0 مفتاح علني. + + + + Processed 0 broadcast. + تم معالجة 0 بث. + + + + Inventory lookups per second: 0 + معدل البحث ضمن المخزن لكل ثانية: 0 + + + + Network Status + حالة الشبكة + + + + File + ملف + + + + Settings + الضبط + + + + View + إظهار + + + + Hashtags + هاشتاق + + + + Help + مساعدة + + + + Import keys + إدراج المفاتيح + + + + Manage keys + إدارة المفاتيح + + + Quit الخروج - + + About + عن + + + + Regenerate deterministic addresses + إعادة إنتاج عناوين حتمية - غير عشوائية + + + + Delete all trashed messages + حذف سلة المهملات + + + + Total Connections: %1 + إجمالي الروابط %1 + + + + Not Connected + غير متصل + + + + Connected + متصل + + + + Show Bitmessage + إظهار Bitmessage + + + + Subscribe + إشتراك + + + + Processed %1 person-to-person messages. + تم معالجة %1 من رسالة - شخص إلى شخص + + + + Processed %1 broadcast messages. + تم معالجة %1 من رسائل البث + + + + Processed %1 public keys. + تم معالجة %1 من المفاتيح العامة + + + + Since startup on %1 + منذ بداية التشغيل في %1 + + + + Waiting on their encryption key. Will request it again soon. + بانتظار مفتاح التشفير، سيتم طلبه مرة أخرى قريباً + + + + Encryption key request queued. + تم إدراح طلب مفتاح التشفير بقائمة الإنتظار. + + + + Queued. + تم الإدراج بقائمة الانتظار + + + + Need to do work to send message. Work is queued. + تحتاج لبعض العمل لإرسال الرسالة، تم إدراج العمل بقائمة الانتظار + + + + Acknowledgement of the message received %1 + تم استلام إشعار الاستلام للرسالة %1 + + + + Broadcast queued. + تم إدراج البث في قائمة الانتظار + + + + Broadcast on %1 + البث في %1 + + + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + مشكلة: العمل المطلوب من قبل المستلم أصعب من ما كنت مستعد للقيام به %1 + + + + Forced difficulty override. Send should start soon. + تم تجازو الصعوبة قصراً، ستبدأ الإرسال قريباً + + + + Message sent. Waiting on acknowledgement. Sent at %1 + تم إرسال الرسالة، بانتظار إشعار الإستلام، تم الإرسال في %1 + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. يمكنك إدارة مفاتيحك بتعديل ملف keys.dat المحفوظ بنفس المجلد الخاص بالبرنامج، مهم جداً أن تحتفظ بنسخة إضافية للملف المذكور سلفاً. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -354,17 +392,12 @@ It is important that you back up this file. مهم جداً أن تحتفظ بنسخة إضافية من هذا الملف. - - Open keys.dat? - فتح ملف keys.dat؟ - - - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) يمكنك إدارة مفاتيحك بتعديل ملف keys.dat المحفوظ بنفس المجلد الخاص بالبرنامج، مهم جداً أن تحتفظ بنسخة إضافية للملف المذكور سلفاً. هل ترغب بفتح الملف الآن؟ تأكد من إغلاق البرنامج Bitmessage قبل تعديل الملف. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) @@ -373,922 +406,617 @@ It is important that you back up this file. Would you like to open the file now? مهم جداً أن تحتفظ بنسخة إضافية من هذا الملف. هل ترغب بفتح الملف الآن؟ تأكد من إغلاق البرنامج Bitmessage قبل تعديل الملف. - - Delete trash? - حذف سلة المهملات؟ + + Add sender to your Address Book + إضافة جهة اتصال لدفتر العناوين - + + Move to Trash + حذف إلى سلة المهملات + + + + View HTML code as formatted text + إظهار نظام تشفير HTML كنص منسق + + + + Enable + تفعيل + + + + Disable + تعطيل + + + + Copy address to clipboard + نسخ العنوان إلى الحافظة + + + + Special address behavior... + سلوك عنوان خاص + + + + Send message to this address + أرسل رسالة لهذا العنوان + + + + Send message to this group + أرسل رسالة لهذه المجموعة + + + + Set avatar... + تغيير الصورة الرمزية + + + + Add New Address + إضافة جهة إتصال + + + + Delete + حذف + + + + Copy destination address to clipboard + نسخ عنوان المرسل إليه إلى الحافظة + + + + Force send + إرسال قصري + + + Are you sure you want to delete all trashed messages? هل أنت متأكد من رغبتك في حذف كل الرسائل من سلة المهملات؟ - - bad passphrase - عبارة المرور غير جيدة - - - + You must type your passphrase. If you don't have one then this is not the form for you. يجب إدخال عبارة المرور، إن لم تكن لديك عبارة مرور، إذاً هذه ليست الطريقة المناسبة لك - - Bad address version number - + + Delete trash? + حذف سلة المهملات؟ - - Your address version number must be a number: either 3 or 4. - + + Open keys.dat? + فتح ملف keys.dat؟ - - Your address version number must be either 3 or 4. - + + bad passphrase + عبارة المرور غير جيدة - - Chan name needed - مطلوب إسم زمرة - - - - You didn't enter a chan name. - لم تدخل إسم الزمرة - - - - Address already present - العنوان موجود سلفاً - - - - Could not add chan because it appears to already be one of your identities. - لا يمكن إضافة هذه الزمرة لأنها تعتبر أحد هوياتك. - - - - Success - نجاح - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - تم تكوين زمرة بنجاح، لإتاحة الفرصة للأخرين بالإنضمام لمجموعتك أعطهم إسم الزمرة و هذا العنوان %1، هذا العنوان سيظهر ضمن هوياتك. - - - - Address too new - العنوان جديد جداً - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - بالرغم أن العنوان صحيح و لكن رقم إصداره جديد جدًا بحيث لا يمكن التعامل معه، ربما عليك تحديث البرنامج. - - - - Address invalid - العنوان غير صحيح - - - - That Bitmessage address is not valid. - عنوان Bitmessage غير صحيح. - - - - Address does not match chan name - العنوان لا يتوافق مع إسم الزمرة - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - بالرغم أن العنوان صحيح، و لكن لا يتوافق مع إسم الزمرة. - - - - Successfully joined chan. - تم الإنضمام للزمرة بنجاح. - - - - Connection lost - تم فقد الاتصال - - - - Connected - متصل - - - - Message trashed - تم حذف الرسالة - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - خطأ: عناوين ال Bitmessage تبدأ ب BM-، يرجى فحص %1 - - - - Error: The address %1 is not typed or copied correctly. Please check it. - خطأ: لم يتم إدخال أو نسخ العنوان %1 بطريقة صحيحة، يرجى فحصه. - - - - Error: The address %1 contains invalid characters. Please check it. - خطأ: العنوان %1 يحتوي على حروف غير صالحة، يرجى فحصه. - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - خطأ: رقم إصدار العنوان %1 عالي جداً، إما أن تقوم بتحديث برنامج Bitmessage أو أن شريكك ذكي جدأ. - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - بعض البيانات المشفرة ضمن العنوان %1 قصيرة جداً. يمكن أن يكون هناك خطأ في برنامج شريكك. - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - بعض البيانات المشفرة ضمن العنوان %1 طويلة جداً. يمكن أن يكون هناك خطأ في برنامج شريكك. - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - خطأ: هناك خطأ في هذا العنوان %1. - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - خطأ: يجب اختيار عنوان للإرسال منه، إن لم يكن لديك واحد إذهب إلى تبويب "هوياتك". - - - - Address version number - رقم إصدار العنوان - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - بالنظر إلى العنوان %1, Bitmessage لم يستطع فهم رقم إصدار العنوان %2، ربما يجب عليك تحديث برنامج Bitmessage لإصداره الأخير. - - - - Stream number - رقم المجرى - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - بالنظر إلى العنوان %1, Bitmessage لم يستطع فهم رقم إصدار العنوان %2، ربما يجب عليك تحديث برنامج Bitmessage لإصداره الأخير. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - تحذير: أنت غير متصل حالياً، Bitmessage سيقوم بالعمل اللازم لإرسال الرسالة و لكن لن يقوم بالإرسال حتى تصبح متصلاً. - - - - Message queued. - - - - - Your 'To' field is empty. - حقل "إلى" فارغ. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - أنقر يميناً على واحد أو أكثر من جهات الاتصال في دفتر العناوين و اختر "إرسال رسالة لهذا العنوان". - - - - Fetched address from namecoin identity. - تم تحصيل العنوان من هوية namecoin. - - - - New Message - رسالة جديدة - - - - From - من - - - - Sending email gateway registration request - - - - - Address is valid. - العنوان صحيح - - - - The address you entered was invalid. Ignoring it. - العنوان الذي أدخلته غير صالح، سيتم تجاهله. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - خطأ: لا يمكنك إضافة نفس العنوان إلى دفتر العناوين مرتين، يمكنك إعادة تسمية العنوان. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - + Restart إعادة تشغيل - + You must restart Bitmessage for the port number change to take effect. لتفعيل تغيير رقم نقطة العبور (port) يجب عليك إعادة تشغيل برنامج Bitmessage. - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - سيقوم Bitmessage باستخدام البروكسي الخاص بك من الآن فصاعداً و لكن يمكنك إعادة تشغيل Bitmessage يدوياً لإغلاق الروابط الحالية -إن وجدت. + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage utilisera votre proxy à partir de maintenant mais il vous faudra redémarrer Bitmessage pour fermer les connexions existantes. - - Number needed - + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + خطأ: لا يمكنك إضافة نفس العنوان مرتين إلى القائمة، يمكنك إعادة تسمية العنوان. - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - + + The address you entered was invalid. Ignoring it. + العنوان الذي أدخلته غير صالح، سيتم تجاهله. - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - + Passphrase mismatch عبارة المرور غير متطابقه - + The passphrase you entered twice doesn't match. Try again. عبارة المرور التي أدخلتها مرتين غير متطابقه، أعد المحاولة. - + Choose a passphrase اختر عبارة المرور - + You really do need a passphrase. أنت بحاجة لعبارة مرور. - + + All done. Closing user interface... + تم عمل اللازم، سيتم إغلاق واجهة المستخدم + + + Address is gone تم إنتاج العنوان - + Bitmessage cannot find your address %1. Perhaps you removed it? لم يستطع Bitmessage العثور على عنوانك %1, ربما قمت بحذف العنوان؟ - + Address disabled تم تعطيل العنوان - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. خطأ: العنوان المستخدم للإرسال منه معطل، يجب عليك تفعيله في تبويب "هوياتك" قبل استخدامه. - + Entry added to the Address Book. Edit the label to your liking. تم إضافة جهة الاتصال لدفتر العناوين، يمكنك تعديل الإسم المستعار إذا أحببت. - - Entry added to the blacklist. Edit the label to your liking. - + + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + خطأ: لا يمكنك إضافة نفس العنوان إلى دفتر العناوين مرتين، يمكنك إعادة تسمية العنوان. - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + تم نقل المادة لسلة المهملات، لا يتوفر واجهة مستخدم لإظهار سلة المهملات حالياً، و لكن يمكنك إيجاد الرسالة المحذوفة على القرص الصلب إذا أردت استرجاعها. - - Moved items to trash. - تم نقل المادة لسلة المهملات. - - - - Undeleted item. - - - - - Save As... - حفظ بإسم - - - - Write error. - خطأ كتابة. - - - + No addresses selected. لم يتم اختيار عناوين - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - + + Options have been disabled because they either aren't applicable or because they haven't yet been implimented for your operating system. + Certaines options ont été désactivées car elles n'étaient pas applicables ou car elles n'ont pas encore été implémentées pour votre système d'exploitation. - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - اختبار... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - هذا عنوان الزمرة، لا يمكنك إستخدامه كقائمة بريدية مستعاره. - - - + The address should start with ''BM-'' العنوان يجب أن يبدأ ب "BM-". - + The address is not typed or copied correctly (the checksum failed). لم يتم إدخال أو نسخ العنوان بالطريقة الصحيحة - اختبار checksum فشل. - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. رقم إصدار هذا العنوان أعلى من إمكانية هذا البرنامج، قم بتحديث البرنامج. - + The address contains invalid characters. العنوان يحتوي على حروف غير صحيحة - + Some data encoded in the address is too short. بعض البيانات المشفرة ضمن العنوان قصيرة جداً - + Some data encoded in the address is too long. بعض البيانات المشفرة ضمن العنوان طويلة جداً. - - Some data encoded in the address is malformed. - + + Address is valid. + العنوان صحيح - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - + You are using TCP port %1. (This can be changed in the settings). أنت تستخدم نقطة عبور TCP %1 - يمكنك تغييره في قائمة الضبط. - - Bitmessage - Bitmessage + + Error: Bitmessage addresses start with BM- Please check %1 + خطأ: عناوين ال Bitmessage تبدأ ب BM-، يرجى فحص %1 - - Identities - + + Error: The address %1 contains invalid characters. Please check it. + خطأ: العنوان %1 يحتوي على حروف غير صالحة، يرجى فحصه. - - New Identity - + + Error: The address %1 is not typed or copied correctly. Please check it. + خطأ: لم يتم إدخال أو نسخ العنوان %1 بطريقة صحيحة، يرجى فحصه. - + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + خطأ: رقم إصدار العنوان %1 عالي جداً، إما أن تقوم بتحديث برنامج Bitmessage أو أن شريكك ذكي جدأ. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + بعض البيانات المشفرة ضمن العنوان %1 قصيرة جداً. يمكن أن يكون هناك خطأ في برنامج شريكك. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + بعض البيانات المشفرة ضمن العنوان %1 طويلة جداً. يمكن أن يكون هناك خطأ في برنامج شريكك. + + + + Error: Something is wrong with the address %1. + خطأ: هناك خطأ في هذا العنوان %1. + + + + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + خطأ: يجب اختيار عنوان للإرسال منه، إن لم يكن لديك واحد إذهب إلى تبويب "هوياتك". + + + + Sending to your address + يتم الإرسال إلى عنوانك + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + خطأ: عنوان من العناوين المرسل إليها، %1, يكون لك، لسوئ الحظ عميل Bitmessage لا يمكنه معالجة رسالئه، يرجى تشغيل عميل ثاني في حاسوب آخر أو ضمن حاسوب إفتراضي. + + + + Address version number + رقم إصدار العنوان + + + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + بالنظر إلى العنوان %1, Bitmessage لم يستطع فهم رقم إصدار العنوان %2، ربما يجب عليك تحديث برنامج Bitmessage لإصداره الأخير. + + + + Stream number + رقم المجرى + + + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + بالنظر إلى العنوان %1, Bitmessage لم يستطع فهم رقم إصدار العنوان %2، ربما يجب عليك تحديث برنامج Bitmessage لإصداره الأخير. + + + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + تحذير: أنت غير متصل حالياً، Bitmessage سيقوم بالعمل اللازم لإرسال الرسالة و لكن لن يقوم بالإرسال حتى تصبح متصلاً. + + + + Your 'To' field is empty. + حقل "إلى" فارغ. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + أنقر يميناً على واحد أو أكثر من جهات الاتصال في دفتر العناوين و اختر "إرسال رسالة لهذا العنوان". + + + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + خطأ: لا يمكنك إضافة نفس العنوان إلى الإشتراكات مرتين، يمكنك إعادة تسمية العنوان. + + + + Message trashed + تم حذف الرسالة + + + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + واحد من العناوين، %1، حاصل على رقم إصدار 1، العناوين ذات رقم الإصدار 1 غير مدعومه حالياً، هل باستطاعتنا حذفه الآن؟ + + + + Unknown status: %1 %2 + حالة غير معروفه: %1 %2 + + + + Connection lost + تم فقد الاتصال + + + + SOCKS5 Authentication problem: %1 + Problème d'authentification SOCKS5 : %1 + + + + Reply + . + رد + + + + Generating one new address + Génération d'une nouvelle adresse + + + + Done generating address. Doing work necessary to broadcast it... + Génération de l'adresse terminée. Travail pour la diffuser en cours... + + + + Done generating address + Génération de l'adresse terminée + + + + Message sent. Waiting on acknowledgement. Sent on %1 + Message envoyé. En attente de l'accusé de réception. Envoyé le %1 + + + + Error! Could not find sender address (your address) in the keys.dat file. + Erreur ! L'adresse de l'expéditeur (vous) n'a pas pu être trouvée dans le fichier keys.dat. + + + + Doing work necessary to send broadcast... + Travail pour envoyer la diffusion en cours... + + + + Broadcast sent on %1 + Message de diffusion envoyé le %1 + + + + Looking up the receiver's public key + Recherche de la clé publique du destinataire + + + + Doing work necessary to send message. (There is no required difficulty for version 2 addresses like this.) + Travail nécessaire pour envoyer le message en cours. (Il n'y a pas de difficulté requise pour ces adresses de version 2.) + + + + Doing work necessary to send message. +Receiver's required difficulty: %1 and %2 + Travail nécessaire pour envoyer le message. +Difficulté requise par le destinataire : %1 et %2 + + + + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. + Problème : Le travail demandé par le destinataire (%1 et %2) est plus difficile que ce que vous souhaitez faire. + + + + Work is queued. + تم إدراج العمل ضمن قائمة الإنتظار. + + + + Work is queued. %1 + تم إدراج العمل ضمن قائمة الإنتظار. %1 + + + + Doing work necessary to send message. +There is no required difficulty for version 2 addresses like this. + Travail nécessaire pour envoyer le message en cours. +Il n'y a pas de difficulté requise pour ces adresses de version 2. + + + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + مشكلة: مفتاح تشفير المرسل إليه غير جيد، لا يمكن تشفير الرسالة. %1 + + + + Save message as... + حفظ الرسالة ك + + + + Mark Unread + وضع علامة غير مقروء + + + + Subscribe to this address + متابعة هذا العنوان + + + + Message sent. Sent at %1 + تم إرسال الرسالة في %1 + + + + Chan name needed + مطلوب إسم زمرة + + + + You didn't enter a chan name. + لم تدخل إسم الزمرة + + + + Address already present + العنوان موجود سلفاً + + + + Could not add chan because it appears to already be one of your identities. + لا يمكن إضافة هذه الزمرة لأنها تعتبر أحد هوياتك. + + + + Success + نجاح + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + تم تكوين زمرة بنجاح، لإتاحة الفرصة للأخرين بالإنضمام لمجموعتك أعطهم إسم الزمرة و هذا العنوان %1، هذا العنوان سيظهر ضمن هوياتك. + + + + Address too new + العنوان جديد جداً + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + بالرغم أن العنوان صحيح و لكن رقم إصداره جديد جدًا بحيث لا يمكن التعامل معه، ربما عليك تحديث البرنامج. + + + + Address invalid + العنوان غير صحيح + + + + That Bitmessage address is not valid. + عنوان Bitmessage غير صحيح. + + + + Address does not match chan name + العنوان لا يتوافق مع إسم الزمرة + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + بالرغم أن العنوان صحيح، و لكن لا يتوافق مع إسم الزمرة. + + + + Successfully joined chan. + تم الإنضمام للزمرة بنجاح. + + + + Fetched address from namecoin identity. + تم تحصيل العنوان من هوية namecoin. + + + + New Message + رسالة جديدة + + + + From + من + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + سيقوم Bitmessage باستخدام البروكسي الخاص بك من الآن فصاعداً و لكن يمكنك إعادة تشغيل Bitmessage يدوياً لإغلاق الروابط الحالية -إن وجدت. + + + + Save As... + حفظ بإسم + + + + Write error. + خطأ كتابة. + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implemented for your operating system. + تم تعطيل الخيارات لأنه إما أنها غير قابلة للتطبيق أو لم يتم برمجتها لنظام التشغيل الخاص بك. + + + + Testing... + اختبار... + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + هذا عنوان الزمرة، لا يمكنك إستخدامه كقائمة بريدية مستعاره. + + + Search بحث - + All الكل - - To - إلى - - - - From - من - - - - Subject - الموضوع - - - + Message الرسالة - - Received - تاريخ الإستلام - - - - Messages - - - - - Address book - - - - - Address - العنوان - - - - Add Contact - - - - + Fetch Namecoin ID إحضار هوية namecoin - - Subject: - الموضوع: + + Stream # + المجرى # - - From: - من: + + Connections + الروابط - - To: - إلى: - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - Subscriptions - الإشتراكات - - - - Add new Subscription - إدخال إشتراك جديدة - - - - Chans - - - - - Add Chan - - - - - File - ملف - - - - Settings - الضبط - - - - Help - مساعدة - - - - Import keys - إدراج المفاتيح - - - - Manage keys - إدارة المفاتيح - - - + Ctrl+Q Ctrl+Q - + F1 F1 - - Contact support - - - - - About - عن - - - - Regenerate deterministic addresses - إعادة إنتاج عناوين حتمية - غير عشوائية - - - - Delete all trashed messages - حذف سلة المهملات - - - + Join / Create chan إنضمام / تكوين زمرة + + + MainWindows - - All accounts - - - - - Zoom level %1% - - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - إضافة مدخل جديد - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - - - - - %n day(s) - - - - - - - - - - - - Shutting down PyBitmessage... %1% - - - - - Sent - - - - - Generating one new address - - - - - Done generating address. Doing work necessary to broadcast it... - - - - - Generating %1 new addresses. - - - - - %1 is already in 'Your Identities'. Not adding it again. - - - - - Done generating address - - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - - Error! Could not find sender address (your address) in the keys.dat file. - - - - - Doing work necessary to send broadcast... - - - - - Broadcast sent on %1 - - - - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - + + Address is valid. + L'adresse est valide. @@ -1308,7 +1036,7 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - + @@ -1332,8 +1060,8 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 4 - + Address version number: 3 + رقم إصدار العنوان: 3 @@ -1394,25 +1122,20 @@ The 'Random Number' option is selected by default but deterministic ad NewSubscriptionDialog - + Add new entry إضافة مدخل جديد - + Label إسم مستعار - + Address عنوان - - - Enter an address above. - - SpecialAddressBehaviorDialog @@ -1442,81 +1165,39 @@ The 'Random Number' option is selected by default but deterministic ad إسم القائمة البريدية المستعار: - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - - About - عن البرنامج - - - + PyBitmessage PyBitmessage - + version ? الإصدار ؟ - - <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> - + + About + عن البرنامج + + + + Copyright © 2013 Jonathan Warren + حقوق الحفظ © 2013 Warren Jonathan - + + <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> + + + + This is Beta software. هذه نسخة تجريبة للبرنامج - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - إضافة مدخل جديد - - - - Name or Label - - - - - Address - - - - - Blacklist - - - - - Whitelist - - - connectDialog @@ -1549,8 +1230,8 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + @@ -1586,154 +1267,6 @@ The 'Random Number' option is selected by default but deterministic ad أن على اتصال بباقي الأقران (المشاركين) و تم تضبيط الجدار الناري بطريقة صحيحة. - - networkstatus - - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - - - - - Object(s) to be synced: %n - - - - - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - - - - - Processed %n broadcast message(s). - - - - - - - - - - - - Processed %n public key(s). - - - - - - - - - - newChanDialog @@ -1759,7 +1292,7 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + @@ -1833,295 +1366,315 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings الضبط - + Start Bitmessage on user login إبدأ برنامج Bitmessage عند نقطة ولوج المستخدم - - Tray - - - - + Start Bitmessage in the tray (don't show main window) تشغيل البرنامج في شريط المهام - + Minimize to tray تصغير إلى شريط المهام - - Close to tray - - - - + Show notification when message received أظهر التنبيهات عن وصول رسالة - + Run in Portable Mode شغّل بالنظام المتنقل - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. في النظام المتنقل تكون الرسائل و ملفات الضبط محفوظة في مجلد البرنامج نفسه على خلاف بيانات البرنامج العادي، و بذلك يسهل تشغيل البرنامج من USB. - - Willingly include unencrypted destination address when sending to a mobile device - فضلاً أضف عنوان غير مشفر للمرسل إليه عندما ترسل إلى جهاز نقال - - - - Use Identicons - استخدم Identicons - - - - Reply below Quote - - - - - Interface Language - لغة العرض - - - - System Settings - system - - - - + User Interface واجهة المستخدم - + + Use Identicons + استخدم Identicons + + + + Interface Language + لغة العرض + + + Listening port نقطة عبور للإستماع - + Listen for connections on port: استماع للروابط في نقطة عبور: - - UPnP: - - - - - Bandwidth limit - - - - - Maximum download rate (kB/s): [0: unlimited] - - - - - Maximum upload rate (kB/s): [0: unlimited] - - - - + Proxy server / Tor خادم البروكسي / تور - + Type: نوع: - - Server hostname: - إسم الخادم: - - - - Port: - نقطة عبور: - - - - Authentication - إثبات الهوية - - - - Username: - إسم المستخدم: - - - - Pass: - العبور: - - - - Listen for incoming connections when using proxy - أنصت للروابط الوارده عن استخدام البروكسي - - - + none لا يوجد - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + + Server hostname: + إسم الخادم: + + + + Port: + نقطة عبور: + + + + Authentication + إثبات الهوية + + + + Username: + إسم المستخدم: + + + + Pass: + العبور: + + + Network Settings ضبط الشبكة - - Total difficulty: - الصعوبة الإجمالية: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - الصعوبة الكلية تؤثر على الكمية المطلقة للعمل اللازم إكماله من قبل المرسل. تضاعف هذه القيمة يضاعف كمية العمل. - - - - Small message difficulty: - صعوبة الرسالة الصغيرة: - - - + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. عندما يقوم أحد المشاركين بإرسال رسالة لك يقوم حاسوبه بأداء بعض العمل، صعوبة هذا العمل هو 1، يمكنك زيادة هذا الرقم الإفتراضي للعناوين الجديدة بتغيير القيم هنا، لكل عنوان جديد على المرسل أن يصل على صعوبة أعلى، باستثناء المشاركين الذين قمت بإضافتهم إلى دفتر عناوينك، البرنامج سيقوم تلقائياً بتنبيه هؤلاء المشاركين عند قيامك بإرسال رسالة بأن عليهم إكمال أقل كمية من العمل: الصعوبة 1. - + + Total difficulty: + الصعوبة الإجمالية: + + + + Small message difficulty: + صعوبة الرسالة الصغيرة: + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. تقريبا كل صعوبات الرسائل الصغيرة تؤثر فقط على صعوبة إرسال الرسائل الصغيرة، بتضاعف هذه القيمة يجعلها تقريباً مرتين أصعب لإرسال رسالة ضغيرة و لكن لا تؤثر على الرسائل كبيرة الحجم. - + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + الصعوبة الكلية تؤثر على الكمية المطلقة للعمل اللازم إكماله من قبل المرسل. تضاعف هذه القيمة يضاعف كمية العمل. + + + Demanded difficulty الصعوبة المطلوبة - + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. هنا يمكنك تحديد الكمية القصوى من العمل الذي ترغب بأدائه عندما ترسل رسالة لشخص آخر، تصفير هذه القيم يدل على قبولك بأي قيمة. - + Maximum acceptable total difficulty: الصعوبة الكلية القصوى المقبولة: - + Maximum acceptable small message difficulty: صعوبة الرسائل الصغيرة القصوى المقبولة: - + Max acceptable difficulty الصعوبة القصوى المقبولة - - Hardware GPU acceleration (OpenCL) - + + Willingly include unencrypted destination address when sending to a mobile device + فضلاً أضف عنوان غير مشفر للمرسل إليه عندما ترسل إلى جهاز نقال - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - + + Override automatic language localization (use countycode or language code, e.g. 'en_US' or 'en'): + تجاهل تحديد اللغة الآلي - استخدم رمز البلد أو رمز اللغة مثل 'en_US' أو 'en'-: - + + Listen for incoming connections when using proxy + أنصت للروابط الوارده عن استخدام البروكسي + + + + Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to test. (Getting your own Bitmessage address into Namecoin is still rather difficult). Bitmessage can use either namecoind directly or a running nmcontrol instance. + يستطيع برنامج Bitmessage استخدام برنامج مختلف يعتمد على Bitcoin و يسمى Namecoin لإنتاج عناوين سهله التداول بين البشر، على سيبل المثال بدلاً من أن تقوم بإخبار صديقك عن عنوانك Bitmessage الطويل، بإمكانك أن تطلب منه إرسال رسالة للإختبار، إدخال عنوانك الخاص إلى Namecoin يبقى صعب بالمقارنة. برنامج Bitmessage إما أن يستخدم namecoind مباشره أو يقوم بتشغيل طلب nmcontrol. + + + Host: المضيف: - + Password: كلمة العبور: - + Test اختبار - + Connect to: متصل ب: - + Namecoind Namecoind - + NMControl NMControl - + Namecoin integration دمج Namecoin - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - + + By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months. Leave these input fields blank for the default behavior. + إفتراضياً إذا أرسلت رسالة لشخص و هو غير متصل لأكثر من يومين سيقوم البرنامج بإرسال الرسالة مرة أخرى بعد يومين إضافيين، ستستمر عملية إعادة الإرسال بصور متباعده زمنياً، و عليه سيتم إعادة إرسال الرسائل بعد 5، 10، 20 يوم إلخ حتى يقوم المستلم بإرسال إشعار استلام الرسائل، هنا يمكنك تغيير أسلوب إعادة الإرسال و التوقف بعد عدة أيام أو شهور، أترك هذه الخانات فارغة لتفعيل الأسلوب الإفتراضي. - + Give up after توقف بعد - + and و - + days أيام - + months. شهور. - + Resends Expire إنتهاء صلاحية إعادة الإرسال + + hashtagDialog + + + Hashtag + هاشتاق + + + + Trending Hashtags + الهاشتاقات النشطة + + + + Day + يوم + + + + Week + أسبوع + + + + Month + شهر + + + + All Time + كل الأوقات + + + + Popularity + الشعبية + + + + NewGroupDialog + + + Add new entry + إضافة مدخل جديد + + + + Label + الإسم المستعار + + + + Address + العنوان + + + + Group Name + إسم المجموعة + + diff --git a/src/translations/bitmessage_cs.pro b/src/translations/bitmessage_cs.pro new file mode 100755 index 00000000..db58da97 --- /dev/null +++ b/src/translations/bitmessage_cs.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.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\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_cs.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_cs.qm b/src/translations/bitmessage_cs.qm index c25ccafa..6aadf62b 100644 Binary files a/src/translations/bitmessage_cs.qm and b/src/translations/bitmessage_cs.qm differ diff --git a/src/translations/bitmessage_cs.ts b/src/translations/bitmessage_cs.ts old mode 100644 new mode 100755 index 11ab163a..c16012c9 --- a/src/translations/bitmessage_cs.ts +++ b/src/translations/bitmessage_cs.ts @@ -1,5 +1,6 @@ - + + AddAddressDialog @@ -18,334 +19,210 @@ Adresa - - EmailGatewayDialog - - - Email gateway - Email brána - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - MainWindow - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Address Book - Přidat odesilatele do Vašeho adresáře - - - - Add sender to your Blacklist - - - - - Move to Trash - Přesunout do koše - - - - Undelete - - - - - View HTML code as formatted text - Zobrazit HTML kód jako formátovaný text - - - - Save message as... - Uložit zprávu jako... - - - - Mark Unread - Označit jako nepřečtené - - - - New - Nové - - - - Enable - Zapnout - - - - Disable - Vypnout - - - - Set avatar... - Nastavit avatar... - - - - Copy address to clipboard - Zkopírovat adresu do clipboardu - - - - Special address behavior... - Speciální chování adresy... - - - - Email gateway - Email brána - - - - Delete - Odstranit - - - - Send message to this address - Poslat zprávu na tuto adresu - - - - Subscribe to this address - Přihlásit se k odběru této adresy - - - - Add New Address - Přidat novou adresu - - - - Copy destination address to clipboard - Zkopírovat cílovou adresu do clipboardu - - - - Force send - Přesto odeslat - - - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? Jedna z Vašich adres, %1, je stará adresa verze 1. Adresy verze 1 již nejsou podporovány. Můžeme ji nyní smazat? - + + Reply + Odpovědět + + + + Add sender to your Address Book + Přidat odesilatele do Vašeho adresáře + + + + Move to Trash + Přesunout do koše + + + + View HTML code as formatted text + Zobrazit HTML kód jako formátovaný text + + + + Save message as... + Uložit zprávu jako... + + + + Mark Unread + Označit jako nepřečtené + + + + New + Nové + + + + Enable + Zapnout + + + + Disable + Vypnout + + + + Copy address to clipboard + Zkopírovat adresu do clipboardu + + + + Special address behavior... + Speciální chování adresy... + + + + Send message to this address + Poslat zprávu na tuto adresu + + + + Subscribe to this address + Přihlásit se k odběru této adresy + + + + Add New Address + Přidat novou adresu + + + + Delete + Odstranit + + + + Copy destination address to clipboard + Zkopírovat cílovou adresu do clipboardu + + + + Force send + Přesto odeslat + + + + Add new entry + Přidat novou položku + + + + Since startup on %1 + Od spuštění v %1 + + + Waiting for their encryption key. Will request it again soon. Čekám na šifrovací klíč. Požadavek bude brzy vyslán znovu. - + Encryption key request queued. Požadavek na šifrovací klíč zařazen do fronty. - + Queued. Zařazeno do fronty. - + Message sent. Waiting for acknowledgement. Sent at %1 Zpráva odeslána. Čekám na potvrzení. Odesláno v %1 - + Message sent. Sent at %1 Zpráva odeslána. Odesláno v %1 - + Need to do work to send message. Work is queued. Pro poslání zprávy musím provést práci. Práce byla zařazena do fronty. - + Acknowledgement of the message received %1 Potvrzení o přijetí zprávy %1 - + Broadcast queued. Rozeslání zařazeno do fronty. - + Broadcast on %1 Rozesláno v %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 Problém: Obtížnost práce požadovaná adresátem je vyšší než Vámi povolené maximum. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 Problém: Šifrovací klíč adresáta je nepoužitelný. Zprávu nelze zašifrovat. %1 - + Forced difficulty override. Send should start soon. Vyžádáno odeslání navzdory obtížnosti. Zpráva bude brzy odeslána. - + Unknown status: %1 %2 Neznámý stav: %1 %2 - + Not Connected Nepřipojeno - + Show Bitmessage Ukázat Bitmessage - + Send Poslat - + Subscribe Přihlásit se k odběru - - Channel - + + Address Book + Adresář - + Quit Ukončit - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Své klíče můžete spravovat editováním souboru keys.dat, který najdete ve stejném adresáři jako tento program. Je důležité si tento soubor zazálohovat. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -354,17 +231,17 @@ It is important that you back up this file. Je důležité si tento soubor zazálohovat. - + Open keys.dat? Otevřít soubor keys.dat? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) Své klíče můžete spravovat editováním souboru keys.dat, který najdete ve stejném adresáři jako tento program. Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otevřít? (Nezapomeňte zavřít Bitmessage předtím, než provedete jakékoli změny.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) @@ -373,916 +250,787 @@ It is important that you back up this file. Would you like to open the file now? Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otevřít? (Nezapomeňte zavřít Bitmessage předtím, než provedete jakékoli změny.) - + Delete trash? Smazat obsah koše? - + Are you sure you want to delete all trashed messages? Opravdu chcete smazat všechny zprávy v koši? - + bad passphrase špatné heslo - + You must type your passphrase. If you don't have one then this is not the form for you. Musíte napsat své heslo. Pokud žádné nemáte, pak tento formulář není pro Vás. - - Bad address version number - Špatné číslo verze adresy - - - - Your address version number must be a number: either 3 or 4. - Verze Vaší adresy musí být číslo: buď 3 nebo 4. - - - - Your address version number must be either 3 or 4. - Verze Vaší adresy musí být buď 3 nebo 4. - - - + Chan name needed Je třeba zadat jméno kanálu - + You didn't enter a chan name. Nezadal(a) jste jméno kanálu. - + Address already present Adresa je již přítomna - + Could not add chan because it appears to already be one of your identities. Nelze přidat kanál. Zdá se, že ho již máte mezi svými identitami. - + Success Úspěch - + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. Kanál byl úspěšně vytvořen. Když chcete jiným lidem povolit připojit se k Vašemu kanálu, řekněte jim jméno kanálu a tuto adresu Bitmessage: %1. Tuto adresu také najdete v sekci "Vaše identity". - + Address too new Adresa je příliš nová - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. Tato adresa Bitmessage může být platná, je to však adresa vyšší verze, se kterou neumíme pracovat. Možná byste měl(a) aktualizovat Bitmessage. - + Address invalid Adresa je neplatná - + That Bitmessage address is not valid. Toto není platná adresa Bitmessage. - + Address does not match chan name Adresa nepatří ke jménu kanálu - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. Adresa Bitmessage, kterou jste zadal(a), je sice platná, nepatří však ke kanálu s tímto jménem. - + Successfully joined chan. Úspěšně jste se připojil(a) ke kanálu. - + + Processed %1 person-to-person messages. + Zpracováno %1 osobních zpráv. + + + + Processed %1 broadcast messages. + Zpracováno %1 hromadných zpráv. + + + + Processed %1 public keys. + Zpracováno %1 veřejných klíčů. + + + + Total Connections: %1 + Celkový počet připojení: %1 + + + Connection lost Připojení ztraceno - + Connected Připojeno - + Message trashed Zpráva byla vyhozena do koše - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - Zpráva je příliš dlouhá - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Zpráva, kterou se snažíte poslat, je o %1 bajtů delší, než je dovoleno. (Maximum je 261644 bajtů). Zkuste ji prosím před odesláním zkrátit. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - + Error: Bitmessage addresses start with BM- Please check %1 Chyba: Adresy Bitmessage začínají na BM- Zkontroluje prosím %1 - + Error: The address %1 is not typed or copied correctly. Please check it. Chyba: Adresa %1 nebyla správně opsána nebo zkopírována. Zkontrolujte ji prosím. - + Error: The address %1 contains invalid characters. Please check it. Chyba: Adresa %1 obsahuje neplatné znaky. Zkontrolujte ji prosím. - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. Chyba: Verze adresy %1 je příliš vysoká. Buď používáte starou verzi Bitmessage a je čas na aktualizaci, nebo si Váš známý dělá legraci. - + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. Chyba: Některá data zakódovaná v adrese %1 jsou příliš krátká. Možná je to chyba softwaru, který Váš známý používá. - + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. Chyba: Některá data zakódovaná v adrese %1 jsou příliš dlouhá. Možná je to chyba softwaru, který Váš známý používá. - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - Chyba: Některá data zakódovaná v adrese %1 mají neplatný formát. Možná je to chyba softwaru, který Váš známý používá. - - - + Error: Something is wrong with the address %1. Chyba: Nastal problém s adresou %1. - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. Chyba: V poli "Od" musíte uvést adresu. Pokud žádnou nemáte, klikněte na kartu "Vaše identity". - + Address version number Číslo verze adresy - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. Co se týče adresy %1, Bitmessage nerozumí jejímu číslu verze "%2". Možná byste měl(a) aktualizovat Bitmessage na nejnovější verzi. - + Stream number Číslo proudu - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. Co se týče adresy %1, Bitmessage neumí zpracovat její číslo proudu "%2". Možná byste měl(a) aktualizovat Bitmessage na nejnovější verzi. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. Varování: Nyní nejste připojen(a). Bitmessage provede práci potřebnou k pro odeslání zprávy, ale neodešle ji, dokud se nepřipojíte. - - Message queued. - - - - + Your 'To' field is empty. Pole "Komu" je prázdné. - + Right click one or more entries in your address book and select 'Send message to this address'. Klikněte pravým tlačítkem na jeden nebo více záznamů v adresáři, a vyberte "Poslat zprávu na tuto adresu". - + Fetched address from namecoin identity. Adresa načtena z namecoinové identity. - + + Work is queued. %1 + Práce je zařazena ve frontě. %1 + + + New Message Nová zpráva - + From - Od + Od - - Sending email gateway registration request - - - - + Address is valid. Adresa je platná. - + The address you entered was invalid. Ignoring it. Zadaná adresa je neplatná, ignoruji jí. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Chyba: Nemůžete do adresáře přidat adresu, která tam již je. Můžete ale tu existující přejmenovat. - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Chyba: Nemůžete do odběrů přidat adresu, která tam již je. Můžete ale tu existující přejmenovat. - + Restart Restart - + You must restart Bitmessage for the port number change to take effect. Je třeba restartovat Bitmessage, aby se změna portu projevila. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). Bitmessage bude od teď používat Váš proxy server. Bude ale jistější, když nyní Bitmessage restartujete, abyste zavřel(a) všechna aktivní připojení (pokud nějaká jsou). - - Number needed - Je třeba zadat číslo + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + Chyba: Nemůžete na listinu přidat adresu, která tam již je. Můžete ale tu existující přejmenovat. - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Limity pro rychlost stahování a odesílání musejí být čísla. Vámi zadané hodnoty nelze použít. - - - - Will not resend ever - Nikdy nebude nic posláno znovu - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Všimněte si, že časový limit, který jste zadal(a), je menší, než čas po kterém Bitmessage poprvé zkusí opětovné odeslání, proto Vaše zprávy nebudou nikdy poslány znovu. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - + Passphrase mismatch Hesla nejsou stejná - + The passphrase you entered twice doesn't match. Try again. Zadaná hesla nejsou stejná. Zkuste to znovu. - + Choose a passphrase Zvolte heslo - + You really do need a passphrase. Opravdu je nutné zvolit heslo. - + + All done. Closing user interface... + Vše hotovo. Zavírám uživatelské rozhraní... + + + Address is gone Adresa je pryč - + Bitmessage cannot find your address %1. Perhaps you removed it? Bitmessage nemůže najít Vaši adresu %1. Možná jste ji odstranil(a)? - + Address disabled Adresa je vypnutá - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. Chyba: Adresa, ze které se snažíte poslat zprávu, je vypnutá. Před použitím ji musíte zapnout na kartě "Vaše identity". - + Entry added to the Address Book. Edit the label to your liking. Položka byla přidána do adresáře. Popisku můžete upravit dle svého přání. - - Entry added to the blacklist. Edit the label to your liking. - + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Položky byly přesunuty do koše. Koš nemá uživatelské rozhraní, ale jeho obsah je stále na disku, pro případ že ho nutně potřebujete obnovit. - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - Položky byly přesunuty do koše. - - - - Undeleted item. - - - - + Save As... Uložit jako... - + Write error. Chyba zápisu. - + No addresses selected. Není vybrána žádná adresa. - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - Opravdu chcete odstranit tento avatar? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Pro tuto adresu již avatar máte. Opravdu ho chcete přepsat? - - - - Start-on-login not yet supported on your OS. - Spuštění po přihlášení není zatím na Vašem operačním systému podporováno. - - - - Minimize-to-tray not yet supported on your OS. - Minimalizace na lištu není zatím na Vašem operačním systému podporována. - - - - Tray notifications not yet supported on your OS. - Upozornění v liště nejsou zatím na Vašem operačním systému podporována. - - - + Testing... Zkouším... - + This is a chan address. You cannot use it as a pseudo-mailing list. Toto je adresa kanálu. Není možné ji použít jako pseudo-mailing list. - + The address should start with ''BM-'' Adresa by měla začínat "BM-" - + The address is not typed or copied correctly (the checksum failed). Adresa nebyla správně opsána nebo zkopírována (kontrolní součet nesouhlasí). - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. Verze této adresy je vyšší než s jakou tento software umí pracovat. Prosím aktualizujte Bitmessage. - + The address contains invalid characters. Adresa obsahuje neplatné znaky. - + Some data encoded in the address is too short. Některá data zakódovaná v této adrese jsou příliš krátká. - + Some data encoded in the address is too long. Některá data zakódovaná v této adrese jsou příliš dlouhá. - - Some data encoded in the address is malformed. - Některá data zakódovaná v této adrese mají neplatný formát. - - - - Enter an address above. - Zadejte adresu výše. - - - - Address is an old type. We cannot display its past broadcasts. - Toto je starý typ adresy. Neumíme zobrazit její rozesílané zprávy. - - - - There are no recent broadcasts from this address to display. - Z této adresy nebyly v poslední době rozesílány žádné zprávy. - - - + You are using TCP port %1. (This can be changed in the settings). Používáte TCP port %1. (To lze změnit v nastavení). - + Bitmessage Bitmessage - - Identities - - - - - New Identity - - - - + Search Hledej - + All Vše - + To Komu - + From Od - + Subject Předmět - + Message Zpráva - + Received Doručeno - - Messages - + + Inbox + Doručené - - Address book - + + Load from Address book + Vybrat z adresáře - - Address - Adresa - - - - Add Contact - - - - + Fetch Namecoin ID Načíst Namecoin ID - + + Message: + Zpráva: + + + Subject: Předmět: - - From: - Od: + + Send to one or more specific people + Poslat jednomu nebo více konkrétním lidem - + To: Komu: - - Send ordinary Message - + + From: + Od: - - Send Message to your Subscribers - + + Broadcast to everyone who is subscribed to your address + Rozeslat všem, kteří odebírají Vaši adresu - - TTL: - + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Mějte na paměti, že rozesílané zprávy jsou šifrovány jen Vaší adresou. Kdokoli, kdo zná Vaši adresu, je může číst. - - Subscriptions - Odběry + + Status + Stav - + + Sent + Odeslané + + + + Label (not shown to anyone) + Popiska (nikomu se neukazuje) + + + + Address + Adresa + + + + Stream + Proud + + + + Your Identities + Vaše identity + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Zde se můžete přihlásit k odběru veřejných zpráv, rozesílaných jinými uživateli. Zprávy uvidíte ve své doručené poště. Na adresy uvedené zde nemá vliv nastavení černé listiny. + + + Add new Subscription Přidat nový odběr - - Chans - + + Label + Popiska - - Add Chan - + + Subscriptions + Odběry - + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + Adresář umožňuje přidat jména nebo popisky k Bitmessage adresám jiných lidí, takže je ve své doručené poště lépe rozpoznáte. Položky můžete přidávat buď kliknutím na tlačítko přidat, nebo ze své doručené pošty, když kliknete na nějakou zprávu pravým tlačítkem. + + + + Name or Label + Jméno nebo popiska + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Použít černou listinu (povolit všechny příchozí zprávy kromě těch od adres na černé listině) + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Použít bílou listinu (blokovat všechny příchozí zprávy kromě těch od adres na bílé listině) + + + + Blacklist + Černá listina + + + + Stream # + Číslo proudu + + + + Connections + Připojení + + + + Total connections: 0 + Celkový počet připojení: 0 + + + + Since startup at asdf: + Od spuštění v asdf: + + + + Processed 0 person-to-person message. + Zpracováno 0 osobních zpráv. + + + + Processed 0 public key. + Zpracováno 0 veřejných klíčů. + + + + Processed 0 broadcast. + Zpracováno 0 hromadných zpráv. + + + + Network Status + Stav sítě + + + File Soubor - + Settings Nastavení - + Help Nápověda - + Import keys Importovat klíče - + Manage keys Správa klíčů - + Ctrl+Q Ctrl+Q - + F1 F1 - - Contact support - - - - + About O aplikaci - + Regenerate deterministic addresses Obnovit deterministické adresy - + Delete all trashed messages Smazat všechny zprávy v koši - + Join / Create chan Připojit ke kanálu / Vytvořit kanál - - All accounts - + + Set avatar... + Nastavit avatar... - - Zoom level %1% - + + Bad address version number + Špatné číslo verze adresy - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - + + Your address version number must be a number: either 3 or 4. + Verze Vaší adresy musí být číslo: buď 3 nebo 4. - - Add new entry - Přidat novou položku + + Your address version number must be either 3 or 4. + Verze Vaší adresy musí být buď 3 nebo 4. - - Display the %1 recent broadcast(s) from this address. - + + Inventory lookups per second: %1 + Počet kontrol inventáře za sekundu: %1 - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - + + Will not resend ever + Nikdy nebude nic posláno znovu - - Waiting for PoW to finish... %1% - + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + Všimněte si, že časový limit, který jste zadal(a), je menší, než čas po kterém Bitmessage poprvé zkusí opětovné odeslání, proto Vaše zprávy nebudou nikdy poslány znovu. - - Shutting down Pybitmessage... %1% - + + Do you really want to remove this avatar? + Opravdu chcete odstranit tento avatar? - - Waiting for objects to be sent... %1% - + + You have already set an avatar for this address. Do you really want to overwrite it? + Pro tuto adresu již avatar máte. Opravdu ho chcete přepsat? - - Saving settings... %1% - + + Start-on-login not yet supported on your OS. + Spuštění po přihlášení není zatím na Vašem operačním systému podporováno. - - Shutting down core... %1% - + + Minimize-to-tray not yet supported on your OS. + Minimalizace na lištu není zatím na Vašem operačním systému podporována. - - Stopping notifications... %1% - + + Tray notifications not yet supported on your OS. + Upozornění v liště nejsou zatím na Vašem operačním systému podporována. - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - - %n day(s) - - - - - + + Enter an address above. + Zadejte adresu výše. - - Shutting down PyBitmessage... %1% - + + Address is an old type. We cannot display its past broadcasts. + Toto je starý typ adresy. Neumíme zobrazit její rozesílané zprávy. - - Sent - + + There are no recent broadcasts from this address to display. + Z této adresy nebyly v poslední době rozesílány žádné zprávy. - - Generating one new address - + + Display the %1 recent broadcast from this address. + Zobrazit %1 zprávu nedávno rozeslanou z této adresy. - - Done generating address. Doing work necessary to broadcast it... - + + Display the %1 recent broadcasts from this address. + Zobrazit %1 zpráv nedávno rozeslaných z této adresy. - - Generating %1 new addresses. - + + Inventory lookups per second: 0 + Počet kontrol inventáře za sekundu: 0 - - %1 is already in 'Your Identities'. Not adding it again. - + + Down: %1/s Total: %2 + Stahování: %1/s Celkem: %2 - - Done generating address - + + Up: %1/s Total: %2 + Odesílání: %1/s Celkem: %2 - - SOCKS5 Authentication problem: %1 - + + Message too long + Zpráva je příliš dlouhá - - Disk full - + + The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. + Zpráva, kterou se snažíte poslat, je o %1 bajtů delší, než je dovoleno. (Maximum je 261644 bajtů). Zkuste ji prosím před odesláním zkrátit. - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - + + Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + Chyba: Některá data zakódovaná v adrese %1 mají neplatný formát. Možná je to chyba softwaru, který Váš známý používá. - - Error! Could not find sender address (your address) in the keys.dat file. - + + Number needed + Je třeba zadat číslo - - Doing work necessary to send broadcast... - + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + Limity pro rychlost stahování a odesílání musejí být čísla. Vámi zadané hodnoty nelze použít. - - Broadcast sent on %1 - + + Some data encoded in the address is malformed. + Některá data zakódovaná v této adrese mají neplatný formát. - - Encryption key was requested earlier. - + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - Sending a request for the recipient's encryption key. - + + Down: 0 KB/s + Stahování: 0 KB/s - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - + + Up: 0 KB/s + Odesílání: 0 KB/s @@ -1309,11 +1057,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Use a random number generator to make an address Použít generátor náhodných čísel k vytvoření adresy - - - Use a passphrase to make addresses - Použít k vytvoření adres heslo - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter @@ -1324,11 +1067,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Make deterministic addresses Vytvořit deterministické adresy - - - Address version number: 4 - Číslo verze adresy: 4 - In addition to your passphrase, you must remember these numbers: @@ -1384,6 +1122,16 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi (saves you some bandwidth and processing power) (šetří přenesená data a práci procesoru) + + + Use a passphrase to make addresses + Použít k vytvoření adres heslo + + + + Address version number: 4 + Číslo verze adresy: 4 + NewSubscriptionDialog @@ -1404,8 +1152,8 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - Enter an address above. - Zadejte adresu výše. + CheckBox + CheckBox @@ -1436,79 +1184,42 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Jméno pseudo-mailing-listu: - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - - About - O aplikaci - - - + PyBitmessage PyBitmessage - + version ? verze ? - + + About + O aplikaci + + + <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> <html><head/><body><p>Distribuováno pod softwarovou licencí MIT/X11; viz <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> - + This is Beta software. Toto je Beta software. - - - blacklist - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 Vývojáři Bitmessage</p></body></html> - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Přidat novou položku - - - - Name or Label - - - - - Address - Adresa - - - - Blacklist - - - - - Whitelist - + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 Vývojáři Bitmessage</p></body></html> @@ -1543,8 +1254,8 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> @@ -1564,11 +1275,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi You have no connections with other peers. Nemáte žádná připojení k jiným uzlům. - - - 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. - Úspěšně jste se připojil(a) k jednomu či více uzlům pomocí odchozího spojení, ale nepřijal(a) jste žádná příchozí spojení. Váš firewall nebo domácí router pravděpodobně nemá nakonfigurováno přeposílání příchozích TCP připojení na Váš počítač. Bitmessage bude fungovat i bez toho, síti Bitmessage ale můžete pomoci, pokud povolíte příchozí připojení a stanete tak se lépe propojeným uzlem. - You are using TCP port ?. (This can be changed in the settings). @@ -1579,138 +1285,10 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi You do have connections with other peers and your firewall is correctly configured. Máte připojení k jiným uzlům a Váš firewall je správně nastaven. - - - networkstatus - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - - Object(s) to be synced: %n - - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - - Processed %n broadcast message(s). - - - - - - - - - Processed %n public key(s). - - - - - + + 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. + Úspěšně jste se připojil(a) k jednomu či více uzlům pomocí odchozího spojení, ale nepřijal(a) jste žádná příchozí spojení. Váš firewall nebo domácí router pravděpodobně nemá nakonfigurováno přeposílání příchozích TCP připojení na Váš počítač. Bitmessage bude fungovat i bez toho, síti Bitmessage ale můžete pomoci, pokud povolíte příchozí připojení a stanete tak se lépe propojeným uzlem. @@ -1778,11 +1356,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Number of addresses to make based on your passphrase: Počet adres, které mají být odvozeny od Vašeho hesla: - - - Address version number: - Číslo verze adresy: - Stream number: @@ -1808,299 +1381,338 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. Pokud jste dříve vytvořil(a) deterministické adresy, a ztratil(a) jste je při nějaké nehodě (jako třeba selhání harddisku), můžete je zde obnovit. Pokud jste k vytvoření adres použil(a) generátor náhodných čísel, pak Vám tento formulář nijak nepomůže. + + + Address version number: + Číslo verze adresy: + settingsDialog - + Settings Nastavení - + Start Bitmessage on user login Spustit Bitmessage po přihlášení uživatele - - Tray - - - - + Start Bitmessage in the tray (don't show main window) Spustit Bitmessage v liště (neukazovat hlavní okno) - + Minimize to tray Minimalizovat na lištu - - Close to tray - - - - + Show notification when message received Zobrazit upozornění na příchozí zprávu - + Run in Portable Mode Spustit v přenosném režimu - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. V přenosném režimu jsou zprávy a konfigurační soubory ukládány ve stejném adresáři jako program, namísto normálního adresáře pro data aplikací. To se hodí, když chcete Bitmessage spouštět z USB flashdisku. - + + User Interface + Uživatelské rozhraní + + + + Listening port + Port pro naslouchání + + + + Listen for connections on port: + Naslouchat příchozím připojením na portu: + + + + Proxy server / Tor + Proxy server / Tor + + + + Type: + Typ: + + + + none + žádný + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Jméno serveru: + + + + Port: + Port: + + + + Authentication + Přihlášení + + + + Username: + Uživatelské jméno: + + + + Pass: + Heslo: + + + + Network Settings + Nastavení sítě + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + Když Vám někdo pošle zprávu, jeho počítač musí nejprve provést určitou práci. Výchozí obtížnost práce je 1. Tuto hodnotu můžete zvýšit tím, že zvýšíte zde uvedené hodnoty. Všechny nové adresy, které vytvoříte, budou po odesilatelích vyžadovat tuto vyšší obtížnost. Existuje jedna výjimka: když si kamaráda nebo známého přidáte do adresáře, při příští zprávě, kterou mu pošlete, ho Bitmessage upozorní, že mu od teď stačí provést minimální množství práce (obtížnost 1) když Vám chce poslat zprávu. + + + + Total difficulty: + Celková obtížnost: + + + + Small message difficulty: + Obtížnost pro malou zprávu: + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + "Obtížnost pro malou zprávu" ovlivňuje pouze obtížnost posílání malých zpráv. Pokud ji zdvojnásobíte, bude dvakrát obtížnější poslat malou zprávu, ale velké zprávy to nijak neovlivní. + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + "Celková obtížnost" ovlivňuje množství práce, kterou musí odesilatel provést. Zdvojnásobením této hodnoty zdvojnásobíte množství práce. + + + + Demanded difficulty + Požadovaná obtížnost + + + Willingly include unencrypted destination address when sending to a mobile device Přiložit nezašifrovanou cílovou adresu při posílání zprávy na mobilní zařízení - + + Listen for incoming connections when using proxy + Naslouchat příchozím připojením při použití proxy + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + Zde můžete nastavit maximální množství práce, které je pro Vás přijatelné, když posíláte zprávu jiné osobě. Nastavení 0 znamená, že množství není omezeno. + + + + Maximum acceptable total difficulty: + Maximální přijatelná celková obtížnost: + + + + Maximum acceptable small message difficulty: + Maximální přijatelná obtížnost pro malou zprávu: + + + + Max acceptable difficulty + Maximální přijatelná obtížnost + + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + <html><head/><body><p>Bitmessage může použít jiný program založený na technologii Bitcoin, který se jmenuje Namecoin, a nahradit tak adresy lépe čitelnými jmény. Příklad: místo toho, abyste musel(a) kamarádovi diktovat svou dlouhou adresu Bitmessage, můžete mu jednoduše říct, ať pošle zprávu na jméno <span style=" font-style:italic;">test. </span></p><p>(Vložit svou adresu Bitmessage do Namecoin je zatím stále celkem složité).</p><p>Bitmessage může použít buď přímo namecoind, nebo běžící instanci nmcontrol.</p></body></html> + + + + Host: + Server: + + + + Password: + Heslo: + + + + Test + Zkouška + + + + Connect to: + Připojit k: + + + + Namecoind + Namecoind + + + + NMControl + NMControl + + + + Namecoin integration + Integrace s Namecoin + + + Use Identicons Používat identikony - - Reply below Quote - Odpověď pod citací - - - + Interface Language Jazyk pro rozhraní - + System Settings system Dle nastavení systému - - User Interface - Uživatelské rozhraní + + English + en + English + + + + Esperanto + eo + Esperanto + + + + Français + fr + Français + + + + Deutsch + de + Deutsch + + + + Españl + es + Españl + + + + русский язык + ru + русский язык + + + + Norsk + no + Norsk - Listening port - Port pro naslouchání + Pirate English + en_pirate + Pirate English - Listen for connections on port: - Naslouchat příchozím připojením na portu: + Other (set in keys.dat) + other + Jiný (nastavený v keys.dat) - - UPnP: - - - - - Bandwidth limit - Omezení rychlosti - - - - Maximum download rate (kB/s): [0: unlimited] - Maximální rychlost stahování (kB/s): [0: bez omezení] - - - - Maximum upload rate (kB/s): [0: unlimited] - Maximální rychlost odesílání (kB/s): [0: bez omezení] - - - - Proxy server / Tor - Proxy server / Tor - - - - Type: - Typ: - - - - Server hostname: - Jméno serveru: - - - - Port: - Port: - - - - Authentication - Přihlášení - - - - Username: - Uživatelské jméno: - - - - Pass: - Heslo: - - - - Listen for incoming connections when using proxy - Naslouchat příchozím připojením při použití proxy - - - - none - žádný - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Nastavení sítě - - - - Total difficulty: - Celková obtížnost: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - "Celková obtížnost" ovlivňuje množství práce, kterou musí odesilatel provést. Zdvojnásobením této hodnoty zdvojnásobíte množství práce. - - - - Small message difficulty: - Obtížnost pro malou zprávu: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Když Vám někdo pošle zprávu, jeho počítač musí nejprve provést určitou práci. Výchozí obtížnost práce je 1. Tuto hodnotu můžete zvýšit tím, že zvýšíte zde uvedené hodnoty. Všechny nové adresy, které vytvoříte, budou po odesilatelích vyžadovat tuto vyšší obtížnost. Existuje jedna výjimka: když si kamaráda nebo známého přidáte do adresáře, při příští zprávě, kterou mu pošlete, ho Bitmessage upozorní, že mu od teď stačí provést minimální množství práce (obtížnost 1) když Vám chce poslat zprávu. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - "Obtížnost pro malou zprávu" ovlivňuje pouze obtížnost posílání malých zpráv. Pokud ji zdvojnásobíte, bude dvakrát obtížnější poslat malou zprávu, ale velké zprávy to nijak neovlivní. - - - - Demanded difficulty - Požadovaná obtížnost - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Zde můžete nastavit maximální množství práce, které je pro Vás přijatelné, když posíláte zprávu jiné osobě. Nastavení 0 znamená, že množství není omezeno. - - - - Maximum acceptable total difficulty: - Maximální přijatelná celková obtížnost: - - - - Maximum acceptable small message difficulty: - Maximální přijatelná obtížnost pro malou zprávu: - - - - Max acceptable difficulty - Maximální přijatelná obtížnost - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage může použít jiný program založený na technologii Bitcoin, který se jmenuje Namecoin, a nahradit tak adresy lépe čitelnými jmény. Příklad: místo toho, abyste musel(a) kamarádovi diktovat svou dlouhou adresu Bitmessage, můžete mu jednoduše říct, ať pošle zprávu na jméno <span style=" font-style:italic;">test. </span></p><p>(Vložit svou adresu Bitmessage do Namecoin je zatím stále celkem složité).</p><p>Bitmessage může použít buď přímo namecoind, nebo běžící instanci nmcontrol.</p></body></html> - - - - Host: - Server: - - - - Password: - Heslo: - - - - Test - Zkouška - - - - Connect to: - Připojit k: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Integrace s Namecoin - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> <html><head/><body><p>Výchozí nastavení funguje tak, že když pošlete zprávu někomu, kdo je odpojen více než dva dny, Bitmessage tuto zprávu za další dva dny pošle znovu. To bude pokračovat, ale intervaly se budou exponenciálně prodlužovat; zprávy budou znovu poslány za 5, 10, 20 dní atd. dokud adresát nepotvrdí jejich přijetí. Zde můžete toto chování změnit, a nastavit, aby to Bitmessage vzdal, pokud zpráva nebude doručena do určitého počtu dní či měsíců.</p><p>Ponechte tato pole prázdná, pokud chcete použít výchozí chování. </p></body></html> - + Give up after Vzdát to po - + and a - + days dnech - + months. měsících. - + Resends Expire Lhůta pro opětovné poslání + + + Reply below Quote + Odpověď pod citací + + + + Bandwidth limit + Omezení rychlosti + + + + Maximum download rate (kB/s): [0: unlimited] + Maximální rychlost stahování (kB/s): [0: bez omezení] + + + + Maximum upload rate (kB/s): [0: unlimited] + Maximální rychlost odesílání (kB/s): [0: bez omezení] + diff --git a/src/translations/bitmessage_da.qm b/src/translations/bitmessage_da.qm deleted file mode 100644 index e5588987..00000000 Binary files a/src/translations/bitmessage_da.qm and /dev/null differ diff --git a/src/translations/bitmessage_da.ts b/src/translations/bitmessage_da.ts deleted file mode 100644 index fcf80470..00000000 --- a/src/translations/bitmessage_da.ts +++ /dev/null @@ -1,2103 +0,0 @@ - - - - AddAddressDialog - - - Add new entry - Tilføj ny addresse - - - - Label - Navn - - - - Address - Adresse - - - - EmailGatewayDialog - - - Email gateway - Email gateway - - - - Register on email gateway - Registrér hos en email gateway - - - - Account status at email gateway - Status for konto hos email gateway - - - - Change account settings at email gateway - Ændr kontoindstillinger for email gateway - - - - Unregister from email gateway - Annullér registrering hos email gateway - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - Ønskede mailadresse (inklusiv @mailchuck.com) - - - - EmailGatewayRegistrationDialog - - - Registration failed: - Registrering mislykkedes: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - Registrering hos email gateway - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - - - MainWindow - - - Reply to sender - Svar til afsender - - - - Reply to channel - Svar til kanal - - - - Add sender to your Address Book - Tilføj afsender til dn adressebog - - - - Add sender to your Blacklist - Tilføj afsender til din blacklist - - - - Move to Trash - Flyt til papirkurv - - - - Undelete - Gendan - - - - View HTML code as formatted text - Vis HTML-kode som formatteret tekst - - - - Save message as... - Gem besked som... - - - - Mark Unread - Marker som ulæst - - - - New - Ny - - - - Enable - Aktiver - - - - Disable - Deaktiver - - - - Set avatar... - Sæt ikon... - - - - Copy address to clipboard - Kopiér adresse til udklipsholder - - - - Special address behavior... - Speciel addressefunktion... - - - - Email gateway - Email gateway - - - - Delete - Slet - - - - Send message to this address - Send besked til denne adresse - - - - Subscribe to this address - Abonner på denne adresse - - - - Add New Address - Tilføj ny adresse - - - - Copy destination address to clipboard - Kopier modtageraddresse til udklipsholder - - - - Force send - Gennemtving afsendelse - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - En af dine adresser, %1 er en gammel version 1-addresse. Version 1-addresser understøttes ikke længere. Må vi slette den? - - - - Waiting for their encryption key. Will request it again soon. - Venter på krypteringsnøgle. Vil snart efterspørge den igen. - - - - Encryption key request queued. - Efterspørgsel på krypteringsnøgle er sat i kø. - - - - Queued. - Sat i kø. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Besked afsendt. Afventer bekræftelse på modtagelse. Sendt %1 - - - - Message sent. Sent at %1 - Besked sendt. Sendt %1 - - - - Need to do work to send message. Work is queued. - Skal foretage beregning for at sende besked. Beregningen er sat i kø. - - - - Acknowledgement of the message received %1 - Bekræftelse på modtagelse er modtaget %1 - - - - Broadcast queued. - Afsendelse sat i kø. - - - - Broadcast on %1 - Afsendt %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problem: Beregningen som kræves af modtageren er mere besværlig end du accepterer. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problem: Modtagerens krypteringsnøgle virker ikke. Beskeden kunne ikke krypteres. %1 - - - - Forced difficulty override. Send should start soon. - Ændring af sværhedsgrad gennemtvunget. Afsendelse bør starte snart. - - - - Unknown status: %1 %2 - Ukendt status: %1 %2 - - - - Not Connected - Ikke forbundet - - - - Show Bitmessage - Vis Bitmessage - - - - Send - Send - - - - Subscribe - Abonnér - - - - Channel - Kanal - - - - Quit - Afslut - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Du kan administrere dine nøgler ved at redigere keys.dat-filen i samme mappe som dette program. Det er vigtigt at tage backup af denne fil. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Du kan administrere dine nøgler ved at redigere keys.dat-filen i -%1 -Det er vigtigt at tage backup af denne fil. - - - - Open keys.dat? - Åbn keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Du kan administrere dine nøgler ved at redigere keys.dat-filen i samme mappe som dette program. Det er vigtigt at tage backup af denne fil. Vil du åbne denne fil nu? (Sørg for at lukke Bitmessage før du foretager ændringer.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Du kan administrere dine nøgler ved at redigere keys.dat-filen i -%1 -Det er vigtigt at tage backup af denne fil. (Sørg for at lukke Bitmessage før du foretager ændringer.) - - - - Delete trash? - Slet papirkurv? - - - - Are you sure you want to delete all trashed messages? - Er du sikker på at du vil slette alle beskeder i papirkurven? - - - - bad passphrase - ugyldigt kodeord - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Du skal indtaste dit kodeord. Hvis du ikke har et så er dette ikke den rette dialogboks. - - - - Bad address version number - Ugyldig addresse-version - - - - Your address version number must be a number: either 3 or 4. - Din addresse-version skal være enten 3 eller 4. - - - - Your address version number must be either 3 or 4. - Din addresse-version skal være enten 3 eller 4. - - - - Chan name needed - Kanalnavnet er påkrævet - - - - You didn't enter a chan name. - Du indtastede ikke et kanalnavn. - - - - Address already present - Adressen eksisterer allerede - - - - Could not add chan because it appears to already be one of your identities. - Adressen kunne ikke tilføjes da det ser ud tilat den allerede er en af dine identiteter. - - - - Success - Succes - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - Ny kanal oprettet. For at andre kan blive medlem skal du oplyse dem kanalnavnet og denne Bitmessage-adresse: %1. Denne adresse vises også i 'Dine identiteter'. - - - - Address too new - Adressen er for ny - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - Selvom denne Bitmessage-adresse måske er gyldig, er dens versionsnummer for nyt. Måske bør du opgradere Bitmessage. - - - - Address invalid - Adressen er ugyldig - - - - That Bitmessage address is not valid. - Denne Bitmessage-adresse er ikke gyldig. - - - - Address does not match chan name - Adressen stemmer ikke overens med kanalnavnet - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - Selvom denne Bitmessage-adresse er gyldig stemmer den ikke overens med kanalnavnet. - - - - Successfully joined chan. - Du er nu medlem af kanalen - - - - Connection lost - Forbindelse afbrudt - - - - Connected - Forbundet - - - - Message trashed - Beskeden er flyttet til papirkurven - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - Beskeden er for lang - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Beskeden som du prøver at sende er %1 byte for lang. (Den maksimale størrelse er 261644 byte). Prøv at gøre den kortere før afsendelsen. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - Fejl: Bitmessage-adresser starter med BM- Check %1 - - - - Error: The address %1 is not typed or copied correctly. Please check it. - Fejl: Adressen %1 er skrever eller kopieret forkert. Tjek den venligst. - - - - Error: The address %1 contains invalid characters. Please check it. - Fejl: Adressen %1 indeholder ugyldige tegn. Tjek den venligst. - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - Fejl: Der er noget galt med adressen %1. - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Fejl: Du skal angive en afsenderadresse. Hvis du ikke har nogen skal du gå til fanen 'Dine Identiteter'. - - - - Address version number - Adresseversion - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Vedrørende adressen %1, Bitmessage forstår ikke addreseversion %2. Måske bør du opgradere Bitmessage til den nyeste version. - - - - Stream number - Flodversion - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Vedrørende adressen %1, Bitmessage kan ikke håndtere flod nummer %2. Måske bør du opgradere Bitmessage til den nyeste version. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Advarsel: Du har ingen forbindelse. Bitmessage vil foretage nødvendige beregninger for at afsende beskeder, men de vil først blive afsendt når du opretter forbindelse. - - - - Message queued. - Besked sat i kø. - - - - Your 'To' field is empty. - Du har ikke angivet en modtager. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Højreklik på en eller flere adresser i din adressebog og vælg 'Send besked til denne adresse'. - - - - Fetched address from namecoin identity. - Adresse blev hentet fra namecoin-identitet. - - - - New Message - Ny Besked - - - - From - Fra - - - - Sending email gateway registration request - Sender tilmeldelses-forespørgsel til email gateway - - - - Address is valid. - Adressen er gyldig. - - - - The address you entered was invalid. Ignoring it. - Adressen som du har indtastet er ugyldig og vil derfor blive ignoreret. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Fejl: Du kan ikke tilføje den samme adresse til din adressebog flere gange. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - Genstart - - - - You must restart Bitmessage for the port number change to take effect. - Bitmessage skal genstartes før ændringen af portnummeret træder i kraft. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage vil benytte en proxy fra nu af, men hvis du ønsker at afbryde eventuelle eksisterende forbindelser skal du genstarte Bitmessage manuelt. - - - - Number needed - Et tal er nødvendigt - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - De maksimale download- og upload-hastigheder skal være tal. Det du har indtastet vil blive ignoreret. - - - - Will not resend ever - Vil aldrig gensende - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Bemærk at den tidsgrænse du har indtastet er kortere end den tid som Bitmessage venter inden første genafsendelsesforsøg, og dine beskeder vil derfor aldrig blive genafsendt. - - - - Sending email gateway unregistration request - Sender afmeldelses-forespørgsel til email gateway - - - - Sending email gateway status request - Sender status-forespørgsel til email gateway - - - - Passphrase mismatch - Kodeordene stemmer ikke overens - - - - The passphrase you entered twice doesn't match. Try again. - De to kodeord er ikke ens. Prøv igen. - - - - Choose a passphrase - Vælg et kodeord - - - - You really do need a passphrase. - Du kan ikke undlade at indtaste et kodeord. - - - - Address is gone - Adressen er forsvundet - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage kan ikke finde din adresse %1. Måske har du fjernet den? - - - - Address disabled - Addresse slået fra - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Fejl: Adressen som du prøver at sende fra er deaktiveret. Du skal aktivere den fra fanen 'Dine Identiteter'. - - - - Entry added to the Address Book. Edit the label to your liking. - Adresse tilføjet til adressebogen. Rediger navnet som du ønsker. - - - - Entry added to the blacklist. Edit the label to your liking. - Adresse tilføjet til din blacklist. Rediger navnet som du ønsker. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Fejl: Den samme adresse kan ikke tilføjes til din sortliste flere gange. Prøv eventuelt at omdøbe den eksisterende. - - - - Moved items to trash. - Beskeder blev flyttet til papirkurven. - - - - Undeleted item. - Besked gendannet. - - - - Save As... - Gem Som... - - - - Write error. - Skrivefejl. - - - - No addresses selected. - Ingen adresser valgt. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Hvis du sletter dette abonnement, vil beskeder som du allerede har modtaget blive utilgængelige. Måske bør du hellere slå adressen fra. Abonnementer der er slået fra modtager ikke nye beskeder, men du kan stadigvæk se de beskeder du allerede har modtaget. - -Er du sikker på at du vil slette dette abonnement? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Hvis du sletter denne kanal, vil beskeder som du allerede har modtaget blive utilgængelige. Måske bør du hellere slå adressen fra. Kanaler der er slået fra modtager ikke nye beskeder, men du kan stadigvæk se de beskeder du allerede har modtaget. - -Er du sikker på at du vil slette denne kanal? - - - - Do you really want to remove this avatar? - Vil du virkelig fjerne dette ikon? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Du har allerede valgt et ikon for denne adresse. Er du sikker på at du vil erstatte det? - - - - Start-on-login not yet supported on your OS. - Automatisk start er endnu ikke understøttet på din platform. - - - - Minimize-to-tray not yet supported on your OS. - Minimering til systembakken er endnu ikke understøttet på din platform. - - - - Tray notifications not yet supported on your OS. - Systembakkenotifikationer er endnu ikke understøttet på din platform. - - - - Testing... - Tester... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Dette er en kanaladresse. Den kan ikke benyttes som en pseudo-mailing-liste. - - - - The address should start with ''BM-'' - Adressen bør starte med "BM-" - - - - The address is not typed or copied correctly (the checksum failed). - DU har indtastet eller kopieret adressen forkert (checksummen passer ikke) - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Versionsnummeret for denne adresse er højere end hvad der understøttes af denne softwareversion. Opgrader venligst Bitmessage. - - - - The address contains invalid characters. - Adressen indeholder ugyldige tegn. - - - - Some data encoded in the address is too short. - Nogle af dataene som er indkodet i adressen, er for korte. - - - - Some data encoded in the address is too long. - Nogle af dataene som er indkodet i adressen, er for lange. - - - - Some data encoded in the address is malformed. - Nogle af dataene som er indkodet i adressen er ugyldige. - - - - Enter an address above. - Vælg en adresse ovenfor. - - - - Address is an old type. We cannot display its past broadcasts. - Adressen er af en gammel type. Dens broadcast-beskeder kan ikke vises. - - - - There are no recent broadcasts from this address to display. - Der blev ikke fundet nogen broadcast-beskeder fra denne adresse - - - - You are using TCP port %1. (This can be changed in the settings). - Du bruger TCP-port %1. (Dette kan ændres i indstillingerne). - - - - Bitmessage - Bitmessage - - - - Identities - Identiteter - - - - New Identity - Ny identitet - - - - Search - Søg - - - - All - Alle - - - - To - Til - - - - From - Fra - - - - Subject - Emne - - - - Message - Besked - - - - Received - Modtaget - - - - Messages - Beskeder - - - - Address book - Adressebog - - - - Address - Adresse - - - - Add Contact - Tilføj Kontakt - - - - Fetch Namecoin ID - Hent Namecoin ID - - - - Subject: - Emne: - - - - From: - Fra: - - - - To: - Til: - - - - Send ordinary Message - Send almindelig besked - - - - Send Message to your Subscribers - Send besked til dine abonnenter - - - - TTL: - TTL: - - - - Subscriptions - Abonnementer - - - - Add new Subscription - Tilføj nyt abonnement - - - - Chans - Kanaler - - - - Add Chan - TIlføj kanal - - - - File - Filer - - - - Settings - Indstillinger - - - - Help - Hjælp - - - - Import keys - Importer nøgler - - - - Manage keys - Administrér nøgler - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Kontakt support - - - - About - Om - - - - Regenerate deterministic addresses - Regenerér deterministiske addresser - - - - Delete all trashed messages - Tøm papirkurv - - - - Join / Create chan - Opret/bliv medlem af en kanal - - - - All accounts - Alle konti - - - - Zoom level %1% - Zoom %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - Tilføj ny addresse - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - %n day(s) - - - - - - - - Shutting down PyBitmessage... %1% - - - - - Sent - - - - - Generating one new address - - - - - Done generating address. Doing work necessary to broadcast it... - - - - - Generating %1 new addresses. - - - - - %1 is already in 'Your Identities'. Not adding it again. - - - - - Done generating address - - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - - Error! Could not find sender address (your address) in the keys.dat file. - - - - - Doing work necessary to send broadcast... - - - - - Broadcast sent on %1 - - - - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - - - - - NewAddressDialog - - - Create new Address - Opret ny adresse - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Her kan du generere så mange adresser som du vil. Det er helt fint at oprette adresser som kun bruges kortvarigt. Du kan generere adresser enten ud fra tilfældige tal eller ud fra et kodeord. Hvis du bruger et kodeord, kaldes det en "deterministisk" adresse. -Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved at benytte deterministiske adresser i stedet. - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - - Use a random number generator to make an address - Brug en tilfældighedsgenerator til at generere adresser - - - - Use a passphrase to make addresses - Brug et kodeord til at generere adresser - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Brug flere minutters ekstra beregningstid på at gøre adresserne 1-2 tegn kortere - - - - Make deterministic addresses - Opret deterministiske adresser - - - - Address version number: 4 - Adresse-version: 4 - - - - In addition to your passphrase, you must remember these numbers: - Udover dit kodeord skal du også huske disse tal. - - - - Passphrase - Kodeord - - - - Number of addresses to make based on your passphrase: - Antal adresser der skal genereres ud fra kodeordet: - - - - Stream number: 1 - Flod-nummer: 1 - - - - Retype passphrase - Gentag kodeord - - - - Randomly generate address - Generer adresse tilfældigt - - - - Label (not shown to anyone except you) - Navn (ikke vist til andre end dig selv) - - - - Use the most available stream - Brug den mest tilgængelige flod - - - - (best if this is the first of many addresses you will create) - (anbefales hvis dette er den første ud af mange adresser som du ønsker at oprette) - - - - Use the same stream as an existing address - Brug den samme flod som en eksisterende addresse - - - - (saves you some bandwidth and processing power) - (sparer noget båndbredde og nogle beregninger) - - - - NewSubscriptionDialog - - - Add new entry - Tilføj ny addresse - - - - Label - Navn - - - - Address - Adresse - - - - Enter an address above. - Vælg en adresse ovenfor. - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - Speciel adressefunktionalitet - - - - Behave as a normal address - Fungér som en almindelig adresse - - - - Behave as a pseudo-mailing-list address - Fungér som en pseudo-mailing-liste - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Beskeder som modtages af en pseudo-mailing-liste vil automatisk blive videresendt til alle abonnenter (og vil derved være offentlige). - - - - Name of the pseudo-mailing-list: - Navn på pseudo-mailing-listen: - - - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - aboutDialog - - - About - Om - - - - PyBitmessage - PyBitmessage - - - - version ? - version ? - - - - <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> - <html><head/><body><p>Distribueret under MIT/X11-licensen; se <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> - - - - This is Beta software. - Dette er en betaversion. - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Tilføj ny addresse - - - - Name or Label - - - - - Address - Adresse - - - - Blacklist - - - - - Whitelist - - - - - connectDialog - - - Bitmessage - Bitmessage - - - - Bitmessage won't connect to anyone until you let it. - Bitmessage opretter ikke forbindelse til nogen før du beder om det. - - - - Connect now - Opret forbindelse nu - - - - Let me configure special network settings first - Lad mig først konfigurere specielle netværksindstillinger - - - - helpDialog - - - Help - Hjælp - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - Da Bitmessage er et samarbejdsprojekt, kan du finde hjælp online på Bitmessage-wikien: - - - - iconGlossaryDialog - - - Icon Glossary - - - - - You have no connections with other peers. - Du har ingen forbindelser til andre computere. - - - - 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. - - - - - You are using TCP port ?. (This can be changed in the settings). - Du bruger TCP-port ?. (Dette kan ændres i indstillingerne). - - - - You do have connections with other peers and your firewall is correctly configured. - Du har forbindelser til andre computere og din firewall er konfigureret korrekt. - - - - networkstatus - - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - - - - newChanDialog - - - Dialog - Dialogboks - - - - Create a new chan - Opret en ny kanal - - - - Join a chan - Bliv medlem af en kanal - - - - Create a chan - Opret en kanal - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - Kanalnavn: - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - Bitmessage adresse for kanalen: - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - Regenerér Eksisterende Adresser - - - - Regenerate existing addresses - Regenerér eksisterende adresser - - - - Passphrase - Kodeord - - - - Number of addresses to make based on your passphrase: - Antal adresser som skal genereres ud fra dit kodeord: - - - - Address version number: - Adresseversion: - - - - Stream number: - Flodversion: - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Brug flere minutters ekstra beregningstid på at gøre adresserne 1-2 tegn kortere - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Det er vigtigt at du vælger (eller ikke vælger) dette, ligesom du gjorde (eller ikke gjorde) første gang. - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Hvis du tidligere har genereret deterministiske adresser, men du har mistet dem på grund af et uheld (f.eks. harddiskfejl), kan du genskabe dem her. Hvis du brugte tilfældighedsgeneratoren til at lave adresser kan denne dialogboks ikke hjælpe dig. - - - - settingsDialog - - - Settings - Indstillinger - - - - Start Bitmessage on user login - Start Bitmessage når der logges ind - - - - Tray - Systembakke - - - - Start Bitmessage in the tray (don't show main window) - - - - - Minimize to tray - Minimér til systembakken - - - - Close to tray - Minimér til systembakken når hovedvinduet lukkes - - - - Show notification when message received - Vis notifikationer når en besked modtages - - - - Run in Portable Mode - Kør i Portable Mode - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - I Portable Mode gemmes beskeder og konfigurationsfiler i samme mappe som programmet, i stedet for i den almindelige mappe til applikationsdata. Dette gør det nemt at køre Bitmessage fra et USB-stick. - - - - Willingly include unencrypted destination address when sending to a mobile device - Inkludér en ukrypteret destinationsaddresse når der sendes til mobile enheder - - - - Use Identicons - Brud identicons - - - - Reply below Quote - Besvar under citat - - - - Interface Language - Grænsefladesprog - - - - System Settings - system - Systemindstillinger - - - - User Interface - Brugergrænseflade - - - - Listening port - Indgående portnummer - - - - Listen for connections on port: - Tillad indgående forbindelser på port: - - - - UPnP: - UPnP: - - - - Bandwidth limit - Maksimal overførselshastighed - - - - Maximum download rate (kB/s): [0: unlimited] - Maksimal downloadhastighed (kB/s): [0: ubegrænset] - - - - Maximum upload rate (kB/s): [0: unlimited] - Maksimal uploadhastighed (kB/s): [0: ubegrænset] - - - - Proxy server / Tor - Proxyserver / Tor - - - - Type: - Type: - - - - Server hostname: - Servernavn: - - - - Port: - Port: - - - - Authentication - Autentifikation - - - - Username: - Brugernavn: - - - - Pass: - Kodeord: - - - - Listen for incoming connections when using proxy - Accepter indgående forbindelser når der benyttes en proxyserver - - - - none - ingen - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Netværksindstillinger - - - - Total difficulty: - Total sværhedsgrad: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - - Small message difficulty: - Små-beskeds-sværhedsgrad: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Når nogen sender dig en besked skal deres computer først foretage nogen tunge beregninger. Sværhedsgraden er som standard 1. Du kan hæve sværhedsgraden for nye adresser ved at ændre værdierne her. Alle nye adresser vil kræve at afsenderen foretager beregninger med den nye sværhedsgrad. Der er dog en undtagelse: hvis du tilføjer en ven eller bekendt til din adressebog vil Bitmessage automatisk gøre dem opmærksom på at de kun skal foretage beregninger med en sværhedsgrad på 1, så snart du sender dem en besked. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - Krævet sværhedsgrad - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - Maksimal acceptabel total sværhedsgrad - - - - Maximum acceptable small message difficulty: - Maksimal acceptabel småbeskeds-sværhedsgrad - - - - Max acceptable difficulty - Maks. acceptabel sværhedsgrad - - - - Hardware GPU acceleration (OpenCL) - GPU-acceleration (OpenCL) - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage kan benytte et andet Bitcoin-baseret program som hedder Namecoin til at gøre adresserne brugervenlige. For eksempel kan du bede din ven om at sende en besked til <span style=" font-style:italic;">test</span> i stedet for din lange Bitmessage-adresse.</p><p>(At få sin Bitmessage-adresse ind i namecoin er stadig rimelig kompliceret).</p><p>Bitmessage kan enten bruge namecoind direkte, eller bruge nmcontrol.</p></body></html> - - - - Host: - Vært: - - - - Password: - Kodeord: - - - - Test - Test - - - - Connect to: - Forbind til: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Namcoin integration - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - - Give up after - Giv op efter - - - - and - og - - - - days - dage - - - - months. - måneder. - - - - Resends Expire - Forsøg på genafsendelse stopper efter - - - diff --git a/src/translations/bitmessage_de.pro b/src/translations/bitmessage_de.pro new file mode 100644 index 00000000..56e2b4f1 --- /dev/null +++ b/src/translations/bitmessage_de.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_de.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index ef443a61..400ac465 100644 Binary files a/src/translations/bitmessage_de.qm and b/src/translations/bitmessage_de.qm differ diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 69cdd2a8..5d937bf9 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -1,1927 +1,1279 @@ - + + AddAddressDialog - + Add new entry Neuen Eintrag erstellen - + Label Name oder Bezeichnung - + Address Adresse - - EmailGatewayDialog - - - Email gateway - E-Mail Schnittstelle - - - - Register on email gateway - An E-Mail Schnittstelle registrieren - - - - Account status at email gateway - Statusanfrage der E-Mail Schnittstelle - - - - Change account settings at email gateway - Einstellungen der E-Mail Schnittstelle ändern - - - - Unregister from email gateway - Von der E-Mail Schnittstelle abmelden - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Die E-Mail Schnittstelle ermöglicht es, mit anderen E-Mail Nutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mail Schnittstelle (@mailchuck.com) verfügbar. - - - - Desired email address (including @mailchuck.com): - Gewünschte E-Mailaddresse (inkl. @mailchuck.com): - - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - Registrierung fehlgeschlagen: - - - - The requested email address is not available, please try a new one. - Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. - - - - Sending email gateway registration request - Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. - - - - Sending email gateway unregistration request - E-Mail Schnittestellen-Abmeldeantrag wird versandt - - - - Sending email gateway status request - E-Mail Schnittestellen Statusantrag wird versandt - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Diese Nachricht können Sie für die Änderung Ihrer Einstellungen an der -# E-Mail Schnittstelle verwenden. Unkommentieren Sie die Einstellung, die Sie -# ändern möchten. Dies sind die verfügbaren Einstellungen: -# -# pgp: server -# Die E-Mail-Schnittstelle wird für Sie PGP-Schlüssel erzeugen, und die -# Nachrichten für Sie unterschreiben, Unterschriften überprüfen, ver- und -# entschlüsseln. Verwenden Sie diese Option, wenn Sie PGP verwenden möchten -# aber es manuell zu umständig finden. Erfordert Abonnement. -# -# pgp: local -# Die E-Mail-Schnittstelle wird keine PGP-verarbeitung für Sie machen. -# Sie können auf die Verwendung von PGP entweder ganz verzichten, oder es lokal machen. -# -# attachments: yes -# Eingehende Dateianhänge von E-Mails werden zu MEGA.nz hochgeladen, und Sie -# können diese über einen Link in der Nachricht herunterladen. Erfordert -# Abonnement. -# -# attachments: no -# Anhänge werden ignoriert. -# -# archive: yes -# Ihre eingehende E-Mails werden auf dem Server archiviert. Nutzen Sie dies, -# wenn Sie Hilfe bei Debugging benötigen, oder eine Bestätigung von dritter -# Partei über die E-Mails benötigen. Diese Einstellung bedeutet jedoch, dass -# der Betreiber der Dienstleistung Ihre E-Mails auch lesen kann nachdem sie -# diese erhalten haben. -# -# archive: no -# Eingehende E-Mails werden gleich nach dem Übertragen zu Ihnen bei dem -# Schnittstellenbetreiber gelöscht. -# -# masterpubkey_btc: BIP44-xpub-Schlüssel oder electrum v1 Seed -# offset_btc: Ganzzahl (Voreingestellt auf 0) -# feeamount: Zahl mit bis zu 8 Nachkommastellen -# feecurrency: BTC, XBT, USD, EUR oder GBP -# Nutzen Sie diese Variablen, wenn Sie von den Absendern eine Zahlung -# verlangen. Wenn diese Option eingeschaltet ist und Sie eine E-Mail von einer -# noch nicht bekannten E-Mail-Addresse erhalten, wird die E-Mail abgelehnt und -# der Absender erhällt eine Zahlungsaufforderung in der spezifizierten Höhe. Da -# diese Methode deterministische öffentliche Schlüssel verwendet, erhalten Sie -# die Zahlungen direkt. Um die Funktion wieder auszuschalten, ändern Sie die -# "feeamount"-Variable auf 0. Erfordert Abonnement. - - - MainWindow - - Reply to sender - Dem Absender antworten + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + Eine Ihrer Adressen, %1, ist eine alte Version 1 Adresse. Version 1 Adressen werden nicht mehr unterstützt. Soll sie jetzt gelöscht werden? - - Reply to channel - Antworten in den Chan + + Reply + Antworten - + Add sender to your Address Book Absender zum Adressbuch hinzufügen - - Add sender to your Blacklist - Absender in die Blacklist eintragen - - - + Move to Trash In den Papierkorb verschieben - - Undelete - Wiederherstellen - - - + View HTML code as formatted text HTML als formatierten Text anzeigen - + Save message as... Nachricht speichern unter... - - Mark Unread - Als ungelesen markieren - - - + New Neu - + Enable Aktivieren - + Disable Deaktivieren - - Set avatar... - Avatar wählen... - - - + Copy address to clipboard Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - - Email gateway - E-Mail Schnittstelle - - - - Delete - Löschen - - - + Send message to this address Nachricht an diese Adresse senden - + Subscribe to this address Diese Adresse abonnieren - + Add New Address Neue Adresse hinzufügen - + + Delete + Löschen + + + Copy destination address to clipboard Zieladresse in die Zwischenablage kopieren - + Force send Senden erzwingen - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Eine Ihrer Adressen, %1, ist eine alte Adresse der Version 1 und wird nicht mehr unterstützt. Soll sie jetzt gelöscht werden? - - - - Waiting for their encryption key. Will request it again soon. - Warte auf den Verschlüsselungscode. Wird bald erneut angefordert. - - - - Encryption key request queued. - - - - - Queued. - In Warteschlange. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Nachricht gesendet. Warte auf Bestätigung. Zeitpunkt der Sendung: %1 - - - - Message sent. Sent at %1 - Nachricht gesendet. Zeitpunkt der Sendung: %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - Bestätigung der Nachricht erhalten %1 - - - - Broadcast queued. - Rundruf in Warteschlange. - - - - Broadcast on %1 - Rundruf um %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problem: Die vom Empfänger geforderte Arbeit ist schwerer als Sie bereit sind, zu berechnen. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problem: Der Verschlüsselungscode des Empfängers ist nicht in Ordnung. Nachricht konnte nicht verschlüsselt werden. %1 - - - - Forced difficulty override. Send should start soon. - Schwierigkeitslimit überschrieben. Senden sollte bald beginnen. - - - - Unknown status: %1 %2 - Unbekannter Status: %1 %2 - - - - Not Connected - Nicht verbunden - - - - Show Bitmessage - Bitmessage anzeigen - - - - Send - Senden - - - - Subscribe - Abonnieren - - - - Channel - Chan - - - - Quit - Beenden - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat bearbeiten, die im gleichen Ordner wie das Programm liegt. Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat bearbeiten, die im Ordner -%1 liegt. -Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. - - - - Open keys.dat? - Die keys.dat öffnen? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat bearbeiten, die im gleichen Ordner wie das Programm liegt. Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie die Datei jetzt öffnen? (Stellen Sie sicher, dass Sie Bitmessage beendet haben, bevor Sie etwas ändern.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat bearbeiten, -die im Ordner %1 liegt. -Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie die Datei jetzt öffnen? -(Stellen Sie sicher, dass Sie Bitmessage beendet haben, bevor Sie etwas ändern.) - - - - Delete trash? - Papierkorb leeren? - - - - Are you sure you want to delete all trashed messages? - Sind Sie sicher, dass Sie alle Nachrichten im Papierkorb löschen möchten? - - - - bad passphrase - Falsches Passwort - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Sie müssen Ihr Passwort eingeben. Wenn Sie keins haben, ist dies das falsche Formular für Sie. - - - - Bad address version number - Falsche Addressenversionsnummer - - - - Your address version number must be a number: either 3 or 4. - Die Addressenversionsnummer muss eine Zahl sein, entweder 3 oder 4. - - - - Your address version number must be either 3 or 4. - Die Addressenversionnsnummer muss entweder 3 oder 4 sein. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Verbindung verloren - - - - Connected - Verbunden - - - - Message trashed - Nachricht in den Papierkorb verschoben - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - Die Haltbarkeit, oder Time-To-Live, ist die Dauer, für die das Netzwerk die Nachricht speichern wird. Der Empfänger muss sie während dieser Zeit empfangen. Wenn Ihr Bitmessage-Client keine Empfangsbestätigung erhält, wird die Nachricht automatisch erneut verschickt. Je länger die Time-To-Live, desto mehr Arbeit muss Ihr Rechner verrichten, um die Nachricht zu senden. Eine Time-To-Live von vier oder fünf Tagen ist meist ausreichend. - - - - Message too long - Narchricht zu lang - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Die Nachricht, die Sie zu senden versuchen, ist %1 Byte zu lang. (Maximum 261.644 Bytes). Bitte verringern Sie ihre Größe vor dem Senden. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Fehler: Ihr Konto war an keiner E-Mail Schnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Fehler: Sie müssen eine Absenderadresse auswählen. Sollten Sie keine haben, wechseln Sie zum Reiter "Ihre Identitäten". - - - - Address version number - Adressversion - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Aufgrund der Adresse %1 kann Bitmessage Adressen mit der Version %2 nicht verarbeiten. Möglicherweise müssen Sie Bitmessage auf die aktuelle Version aktualisieren. - - - - Stream number - Datenstrom Nummer - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Aufgrund der Adresse %1 kann Bitmessage den Datenstrom mit der Version %2 nicht verarbeiten. Möglicherweise müssen Sie Bitmessage auf die aktuelle Version aktualisieren. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Warnung: Sie sind aktuell nicht verbunden. Bitmessage wird die nötige Arbeit zum versenden verrichten, aber erst senden, wenn Sie verbunden sind. - - - - Message queued. - Nachricht befindet sich in der Warteschleife. - - - - Your 'To' field is empty. - Ihr "Empfänger"-Feld ist leer. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Klicken Sie mit rechts auf einen oder mehrere Einträge aus Ihrem Adressbuch und wählen Sie "Nachricht an diese Adresse senden". - - - - Fetched address from namecoin identity. - Adresse aus Namecoin Identität geholt. - - - - New Message - Neue Nachricht - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - Adresse ist gültig. - - - - The address you entered was invalid. Ignoring it. - Die von Ihnen eingegebene Adresse ist ungültig, sie wird ignoriert. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Fehler: Sie können eine Adresse nicht doppelt im Adressbuch speichern. Sie können jedoch die bereits eingetragene umbenennen. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Fehler: Dieselbe Adresse kann nicht doppelt in die Abonnements eingetragen werden. Sie können jedoch die bereits eingetragene umbenennen. - - - - Restart - Neustart - - - - You must restart Bitmessage for the port number change to take effect. - Sie müssen Bitmessage neu starten, um den geänderten Port zu verwenden. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage wird ab sofort den Proxy-Server verwenden, aber eventuell möchten Sie Bitmessage neu starten um bereits bestehende Verbindungen zu schließen. - - - - Number needed - Zahl erforderlich - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Ihre maximale Herungerlade- und Hochladegeschwindigkeit müssen Zahlen sein. Die eingetragenen Werte werden ignoriert. - - - - Will not resend ever - Wird nie wiederversendet - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Bitte beachten Sie, dass der eingetratene Dauer kürzer ist als die, die Bitmessage auf das erste Wiederversenden wartet. Deswegen werden Ihre Nachrichten nie wiederversendet. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Kennwort stimmt nicht überein - - - - The passphrase you entered twice doesn't match. Try again. - Die von Ihnen eingegebenen Kennwörter sind nicht identisch. Bitte neu versuchen. - - - - Choose a passphrase - Wählen Sie ein Kennwort - - - - You really do need a passphrase. - Sie benötigen unbedingt ein Kennwort. - - - - Address is gone - Adresse ist verloren - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage kann Ihre Adresse %1 nicht finden. Haben Sie sie gelöscht? - - - - Address disabled - Adresse deaktiviert - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Fehler: Die Adresse von der Sie versuchen zu senden ist deaktiviert. Sie müssen sie unter dem Reiter "Ihre Identitäten" aktivieren bevor Sie fortfahren. - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - Eintrag in die Blacklist hinzugefügt. Die Beschriftung können Sie ändern. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Fehler: Dieselbe Addresse kann nicht doppelt in die Blacklist eingetragen werden. Sie können jedoch die bereits eingetragene umbenennen. - - - - Moved items to trash. - Objekt(e) in den Papierkorb verschoben. - - - - Undeleted item. - Nachricht wiederhergestellt. - - - - Save As... - Speichern unter... - - - - Write error. - Fehler beim Speichern. - - - - No addresses selected. - Keine Adresse ausgewählt. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Wenn Sie das Abonnement löschen, werden bereits erhaltene Nachrichten unaufrufbar. Vielleicht deaktivieren Sie das Abonnement lieber? Deaktivierte Abonnements erhalten keine neue Nachrichten, aber Sie können die bereits erhaltene aufrufen. - -Sind Sie sicher, dass Sie das Abonnement löschen möchten? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Wenn Sie das Chan löschen, die bereits erhaltene Nachrichten werden unaufrufbar. Vielleicht deaktivieren Sie den Chan lieber?. Deaktivierte Chans erhalten keine neue Nachrichten, aber Sie können die bereits erhaltene aufrufen. - -Sind Sie sicher, dass Sie das Chan löschen möchten? - - - - Do you really want to remove this avatar? - Wollen Sie diesen Avatar wirklich entfernen? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Sie haben bereits einen Avatar für diese Adresse gewählt. Wollen Sie ihn wirklich überschreiben? - - - - Start-on-login not yet supported on your OS. - Mit Betriebssystem starten, noch nicht von Ihrem Betriebssystem unterstützt - - - - Minimize-to-tray not yet supported on your OS. - Ins System Tray minimieren von Ihrem Betriebssytem noch nicht unterstützt. - - - - Tray notifications not yet supported on your OS. - Trach-Benachrichtigungen von Ihrem Betriebssystem noch nicht unterstützt. - - - - Testing... - teste... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - Die Adresse sollte mit "BM-" beginnen - - - - The address is not typed or copied correctly (the checksum failed). - Die Adresse wurde nicht korrekt getippt oder kopiert (Prüfsumme falsch). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Die Versionsnummer dieser Adresse ist höher als diese Software unterstützt. Bitte installieren Sie die neueste Bitmessage Version. - - - - The address contains invalid characters. - Diese Adresse beinhaltet ungültige Zeichen. - - - - Some data encoded in the address is too short. - Die in der Adresse kodierten Daten sind zu kurz. - - - - Some data encoded in the address is too long. - Die in der Adresse kodierten Daten sind zu lang. - - - - Some data encoded in the address is malformed. - Einige in der Adresse kodierten Daten sind ungültig. - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - Alter Addressentyp. Wir können deren vorige Rundrufe nicht anzeigen. - - - - There are no recent broadcasts from this address to display. - Es gibt keine neuen Rundrufe von dieser Adresse die angezeigt werden können. - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - Identitäten - - - - New Identity - Neue Identität - - - - Search - Suchen - - - - All - Alle - - - - To - An - - - - From - Von - - - - Subject - Betreff - - - - Message - Nachricht - - - - Received - Erhalten - - - - Messages - Nachrichten - - - - Address book - Addressbuch - - - - Address - Adresse - - - - Add Contact - Kontakt hinzufügen - - - - Fetch Namecoin ID - Hole Namecoin ID - - - - Subject: - Betreff: - - - - From: - Von: - - - - To: - An: - - - - Send ordinary Message - Ordentliche Nachricht senden - - - - Send Message to your Subscribers - Rundruf an Ihre Abonnenten senden - - - - TTL: - Lebenszeit: - - - - Subscriptions - Abonnements - - - - Add new Subscription - Neues Abonnement anlegen - - - - Chans - Chans - - - - Add Chan - Chan hinzufügen - - - - File - Datei - - - - Settings - Einstellungen - - - - Help - Hilfe - - - - Import keys - Schlüssel importieren - - - - Manage keys - Schlüssel verwalten - - - - Ctrl+Q - Strg+Q - - - - F1 - F1 - - - - Contact support - Unterstützung anfordern - - - - About - Über - - - - Regenerate deterministic addresses - Deterministische Adressen neu generieren - - - - Delete all trashed messages - Alle Nachrichten im Papierkorb löschen - - - - Join / Create chan - Chan beitreten / erstellen - - - - All accounts - Alle Identitäten - - - - Zoom level %1% - Zoom-Stufe %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Fehler: Sie können eine Adresse nicht doppelt zur Liste hinzufügen. Wenn Sie möchten, benennen Sie den existierenden Eintrag um. - - - + Add new entry Neuen Eintrag erstellen - - Display the %1 recent broadcast(s) from this address. - + + Waiting for their encryption key. Will request it again soon. + Warte auf den Verschlüsselungscode. Wird bald erneut angefordert. - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - Neue Version von PyBitmessage steht zur Verfügung: %1. Sie können sie von https://github.com/Bitmessage/PyBitmessage/releases/latest herunterladen. + + Encryption key request queued. + Verschlüsselungscode-Anforderung steht aus. - - Waiting for PoW to finish... %1% - Warte auf Abschluss von Berechnungen (PoW)... %1% - - - - Shutting down Pybitmessage... %1% - PyBitmessage wird beendet... %1% - - - - Waiting for objects to be sent... %1% - Warte auf Versand von Objekten... %1% - - - - Saving settings... %1% - Einstellungen werden gespeichert... %1% - - - - Shutting down core... %1% - Kern wird beendet... %1% - - - - Stopping notifications... %1% - Beende Benachrichtigungen... %1% - - - - Shutdown imminent... %1% - Unmittelbar vor Beendung... %1% - - - - %n hour(s) - %n Stunde%n Stunden - - - %n day(s) - %n Tag%n Tage + Queued. + In Warteschlange. - - Shutting down PyBitmessage... %1% - PyBitmessage wird beendet... %1% + + Message sent. Waiting for acknowledgement. Sent at %1 + Nachricht gesendet. Warten auf Bestätigung. Gesendet %1 - + + Need to do work to send message. Work is queued. + Es muss Arbeit verrichtet werden um die Nachricht zu versenden. Arbeit ist in Warteschlange. + + + + Acknowledgement of the message received %1 + Bestätigung der Nachricht erhalten %1 + + + + Broadcast queued. + Rundruf in Warteschlange. + + + + Broadcast on %1 + Rundruf um %1 + + + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + Problem: Die vom Empfänger geforderte Arbeit ist schwerer als Sie bereit sind, zu berechnen. %1 + + + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + Problem: Der Verschlüsselungscode des Empfängers ist nicht in Ordnung. Nachricht konnte nicht verschlüsselt werden. %1 + + + + Forced difficulty override. Send should start soon. + Schwierigkeitslimit überschrieben. Senden sollte bald beginnen. + + + + Unknown status: %1 %2 + Unbekannter Status: %1 %2 + + + + Since startup on %1 + Seit Start der Anwendung am %1 + + + + Not Connected + Nicht verbunden + + + + Show Bitmessage + Bitmessage anzeigen + + + + Send + Senden + + + + Subscribe + Abonnieren + + + + Address Book + Adressbuch + + + + Quit + Schließen + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. + Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat Datei bearbeiten, die im gleichen Ordner wie das Programm liegt. Es ist wichtig, dass Sie diese Datei sichern. + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. + Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat Datei bearbeiten, die im Ordner +%1 liegt. +Es ist wichtig, dass Sie diese Datei sichern. + + + + Open keys.dat? + Datei keys.dat öffnen? + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat Datei bearbeiten, die im gleichen Ordner wie das Programm liegt. Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffnen? (Stellen Sie sicher, dass Bitmessage geschlossen ist, bevor Sie etwas ändern.) + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Sie können Ihre Schlüssel verwalten, indem Sie die keys.dat Datei bearbeiten, +die im Ordner %1 liegt. +Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die datei jetzt öffnen? +(Stellen Sie sicher, dass Bitmessage geschlossen ist, bevor Sie etwas ändern.) + + + + Delete trash? + Papierkorb leeren? + + + + Are you sure you want to delete all trashed messages? + Sind Sie sicher, dass Sie alle Nachrichten im Papierkorb löschen möchten? + + + + bad passphrase + Falscher Passwort-Satz + + + + You must type your passphrase. If you don't have one then this is not the form for you. + Sie müssen Ihren Passwort-Satz eingeben. Wenn Sie keinen haben, ist dies das falsche Formular für Sie. + + + + Processed %1 person-to-person messages. + %1 Person-zu-Person-Nachrichten bearbeitet. + + + + Processed %1 broadcast messages. + %1 Rundruf-Nachrichten bearbeitet. + + + + Processed %1 public keys. + %1 öffentliche Schlüssel bearbeitet. + + + + Total Connections: %1 + Verbindungen insgesamt: %1 + + + + Connection lost + Verbindung verloren + + + + Connected + Verbunden + + + + Message trashed + Nachricht in den Papierkorb verschoben + + + + Error: Bitmessage addresses start with BM- Please check %1 + Fehler: Bitmessage Adressen starten mit BM- Bitte überprüfen Sie %1 + + + + Error: The address %1 is not typed or copied correctly. Please check it. + Fehler: Die Adresse %1 wurde nicht korrekt getippt oder kopiert. Bitte überprüfen. + + + + Error: The address %1 contains invalid characters. Please check it. + Fehler: Die Adresse %1 beinhaltet ungültig Zeichen. Bitte überprüfen. + + + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + Fehler: Die Adressversion von %1 ist zu hoch. Entweder Sie müssen Ihre Bitmessage Software aktualisieren oder Ihr Bekannter ist sehr clever. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + Fehler: Einige Daten die in der Adresse %1 codiert sind, sind zu kurz. Es könnte sein, dass etwas mit der Software Ihres Bekannten nicht stimmt. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + Fehler: Einige Daten die in der Adresse %1 codiert sind, sind zu lang. Es könnte sein, dass etwas mit der Software Ihres Bekannten nicht stimmt. + + + + Error: Something is wrong with the address %1. + Fehler: Mit der Adresse %1 stimmt etwas nicht. + + + + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + Fehler: Sie müssen eine Absenderadresse auswählen. Sollten Sie keine haben, wechseln Sie zum Reiter "Ihre Identitäten". + + + + Sending to your address + Sende zu Ihrer Adresse + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + Fehler: Eine der Adressen an die Sie eine Nachricht schreiben (%1) ist Ihre. Leider kann die Bitmessage Software ihre eigenen Nachrichten nicht verarbeiten. Bitte verwenden Sie einen zweite Installation auf einem anderen Computer oder in einer VM. + + + + Address version number + Adressversion + + + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Bezüglich der Adresse %1, Bitmessage kann Adressen mit der Version %2 nicht verarbeiten. Möglicherweise müssen Sie Bitmessage auf die aktuelle Version aktualisieren. + + + + Stream number + Datenstrom Nummer + + + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Bezüglich der Adresse %1, Bitmessage kann den Datenstrom mit der Version %2 nicht verarbeiten. Möglicherweise müssen Sie Bitmessage auf die aktuelle Version aktualisieren. + + + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + Warnung: Sie sind aktuell nicht verbunden. Bitmessage wird die nötige Arbeit zum versenden verrichten, aber erst senden, wenn Sie verbunden sind. + + + + Your 'To' field is empty. + Ihr "Empfänger"-Feld ist leer. + + + + Work is queued. + Arbeit in Warteschlange. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + Klicken Sie mit rechts auf eine oder mehrere Einträge aus Ihrem Adressbuch und wählen Sie "Nachricht an diese Adresse senden". + + + + Work is queued. %1 + Arbeit in Warteschlange. %1 + + + + New Message + Neue Nachricht + + + + From + Von + + + + Address is valid. + Adresse ist gültig. + + + + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + Fehler: Sie können eine Adresse nicht doppelt im Adressbuch speichern. Wenn Sie möchten, benennen Sie den existierenden Eintrag um. + + + + The address you entered was invalid. Ignoring it. + Die von Ihnen eingegebene Adresse ist ungültig, sie wird ignoriert. + + + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Fehler: Sie können eine Adresse nicht doppelt abonnieren. Wenn Sie möchten, benennen Sie den existierenden Eintrag um. + + + + Restart + Neustart + + + + You must restart Bitmessage for the port number change to take effect. + Sie müssen Bitmessage neu starten, um den geänderten Port zu verwenden. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage wird den Proxy-Server ab jetzt verwenden, möglicherweise möchten Sie Bitmessage neu starten um bestehende Verbindungen zu schließen. + + + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + Fehler: Sie können eine Adresse nicht doppelt zur Liste hinzufügen. Wenn Sie möchten, benennen Sie den existierenden Eintrag um. + + + + Passphrase mismatch + Kennwortsatz nicht identisch + + + + The passphrase you entered twice doesn't match. Try again. + Die von Ihnen eingegebenen Kennwortsätze sind nicht identisch. Bitte neu versuchen. + + + + Choose a passphrase + Wählen Sie einen Kennwortsatz + + + + You really do need a passphrase. + Sie benötigen wirklich einen Kennwortsatz. + + + + All done. Closing user interface... + Alles fertig. Benutzer interface wird geschlossen... + + + + Address is gone + Adresse ist verloren + + + + Bitmessage cannot find your address %1. Perhaps you removed it? + Bitmassage kann Ihre Adresse %1 nicht finden. Haben Sie sie gelöscht? + + + + Address disabled + Adresse deaktiviert + + + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + Fehler: Die Adresse von der Sie versuchen zu senden ist deaktiviert. Sie müssen sie unter dem Reiter "Ihre Identitäten" aktivieren bevor Sie fortfahren. + + + + Entry added to the Address Book. Edit the label to your liking. + Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Objekt in den Papierkorb verschoben. Es gibt kein Benutzerinterface für den Papierkorb, aber die Daten sind noch auf Ihrer Festplatte wenn Sie sie wirklich benötigen. + + + + Save As... + Speichern unter... + + + + Write error. + Fehler beim speichern. + + + + No addresses selected. + Keine Adresse ausgewählt. + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implemented for your operating system. + +Optionen wurden deaktiviert, da sie für Ihr Betriebssystem nicht relevant, oder noch nicht implementiert sind. + + + + The address should start with ''BM-'' + Die Adresse sollte mit "BM-" beginnen + + + + The address is not typed or copied correctly (the checksum failed). + Die Adresse wurde nicht korrekt getippt oder kopiert (Prüfsumme falsch). + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + Die Versionsnummer dieser Adresse ist höher als diese Software unterstützt. Bitte installieren Sie die neuste Bitmessage Version. + + + + The address contains invalid characters. + Diese Adresse beinhaltet ungültige Zeichen. + + + + Some data encoded in the address is too short. + Die in der Adresse codierten Daten sind zu kurz. + + + + Some data encoded in the address is too long. + Die in der Adresse codierten Daten sind zu lang. + + + + You are using TCP port %1. (This can be changed in the settings). + Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). + + + + Bitmessage + Bitmessage + + + + To + An + + + + From + Von + + + + Subject + Betreff + + + + Received + Erhalten + + + + Inbox + Posteingang + + + + Load from Address book + Aus Adressbuch wählen + + + + Message: + Nachricht: + + + + Subject: + Betreff: + + + + Send to one or more specific people + Nachricht an eine oder mehrere spezifische Personen + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + To: + An: + + + + From: + Von: + + + + Broadcast to everyone who is subscribed to your address + Rundruf an jeden, der Ihre Adresse abonniert hat + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Beachten Sie, dass Rundrufe nur mit Ihrer Adresse verschlüsselt werden. Jeder, der Ihre Adresse kennt, kann diese Nachrichten lesen. + + + + Status + Status + + + Sent Gesendet - - Generating one new address - Neue Addresse wird erstellt + + Label (not shown to anyone) + Bezeichnung (wird niemandem gezeigt) - - Done generating address. Doing work necessary to broadcast it... - Die Addresse wurde erstellt. Arbeit wird verrichtet, um sie zu versenden... + + Address + Adresse - - Generating %1 new addresses. - Erzeuge %1 neue Addressen. + + Stream + Datenstrom - - %1 is already in 'Your Identities'. Not adding it again. - %1 befindet sich bereits unter Ihren Identitäten, wird nicht doppelt hinzugefügt. + + Your Identities + Ihre Identitäten - - Done generating address - Addresse fertiggestellt. + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Hier können Sie "Rundruf Nachrichten" abonnieren, die von anderen Benutzern versendet werden. Die Nachrichten tauchen in Ihrem Posteingang auf. (Die Adressen hier überschreiben die auf der Blacklist). - - SOCKS5 Authentication problem: %1 - + + Add new Subscription + Neues Abonnement anlegen - - Disk full - Datenträger voll + + Label + Bezeichnung - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. + + Subscriptions + Abonnements - - Error! Could not find sender address (your address) in the keys.dat file. - Fehler! Konnte die Absenderadresse (Ihre Adresse) in der keys.dat-Datei nicht finden. + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + Das Adressbuch ist nützlich, um die Bitmessage-Adressen anderer Personen Namen oder Beschreibungen zuzuordnen, sodass Sie sie einfacher im Posteingang erkennen können. Sie können Adressen über "Neuen Eintrag erstellen" hinzufügen, oder über einen Rechtsklick auf eine Nachricht im Posteingang. - - Doing work necessary to send broadcast... - Arbeit wird verrichtet, um Rundruf zu verschicken... + + Name or Label + Name oder Bezeichnung - - Broadcast sent on %1 - Rundruf verschickt um %1 + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Liste als Blacklist verwenden (Erlaubt alle eingehenden Nachrichten, außer von Adressen auf der Blacklist) - + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Liste als Whitelist verwenden (Erlaubt keine eingehenden Nachrichten, außer von Adressen auf der Whitelist) + + + + Blacklist + Blacklist + + + + Stream # + Datenstrom # + + + + Connections + Verbindungen + + + + Total connections: 0 + Verbindungen insgesamt: 0 + + + + Since startup at asdf: + Seit start um asdf: + + + + Processed 0 person-to-person message. + 0 Person-zu-Person-Nachrichten verarbeitet. + + + + Processed 0 public key. + 0 öffentliche Schlüssel verarbeitet. + + + + Processed 0 broadcast. + 0 Rundrufe verarbeitet. + + + + Network Status + Netzwerk status + + + + File + Datei + + + + Settings + Einstellungen + + + + Help + Hilfe + + + + Import keys + Schlüssel importieren + + + + Manage keys + Schlüssel verwalten + + + + About + Über + + + + Regenerate deterministic addresses + Deterministische Adressen neu generieren + + + + Delete all trashed messages + Alle Nachrichten im Papierkorb löschen + + + + Message sent. Sent at %1 + Nachricht gesendet. gesendet am %1 + + + + Chan name needed + Chan name benötigt + + + + You didn't enter a chan name. + Sie haben keinen Chan-Namen eingegeben. + + + + Address already present + Adresse bereits vorhanden + + + + Could not add chan because it appears to already be one of your identities. + Chan konnte nicht erstellt werden, da es sich bereits um eine Ihrer Identitäten handelt. + + + + Success + Erfolgreich + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + Chan erfolgreich erstellt. Um andere diesem Chan beitreten zu lassen, geben Sie ihnen den Chan-Namen und die Bitmessage-Adresse: %1. Diese Adresse befindet sich auch unter "Ihre Identitäten". + + + + Address too new + Adresse zu neu + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + Obwohl diese Bitmessage-Adresse gültig ist, ist ihre Versionsnummer zu hoch um verarbeitet zu werden. Vermutlich müssen Sie eine neuere Version von Bitmessage installieren. + + + + Address invalid + Adresse ungültig + + + + That Bitmessage address is not valid. + Diese Bitmessage-Adresse ist nicht gültig. + + + + Address does not match chan name + Adresse stimmt nicht mit dem Chan-Namen überein + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + Obwohl die Bitmessage-Adresse die Sie eingegeben haben gültig ist, stimmt diese nicht mit dem Chan-Namen überein. + + + + Successfully joined chan. + Chan erfolgreich beigetreten. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + Bitmessage wird ab sofort den Proxy-Server verwenden, aber eventuell möchten Sie Bitmessage neu starten um bereits bestehende Verbindungen zu schließen. + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. + + + + Search + Suchen + + + + All + Alle + + + + Message + Nachricht + + + + Join / Create chan + Chan beitreten / erstellen + + + Encryption key was requested earlier. - Verschlüsselungscode wurde früher angefordert. + Verschlüsselungscode wurde bereits angefragt. - + Sending a request for the recipient's encryption key. - Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. + Sende eine Anfrage für den Verschlüsselungscode des Empfängers. - - Looking up the receiver's public key - Suche nach dem öffentlichen Schlüssel des Empfängers - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Problem: Der Empfänger benutzt ein mobiles Gerät und erfordert eine unverschlüsselte Empfängeraddresse. Dies ist in Ihren Einstellungen jedoch nicht zulässig. 1% - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Arbeit für Nachrichtenversand wird verrichtet. -Version-2-Addressen wie die des Empfängers haben keine Schweirigkeitserforderungen. - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Arbeit für Nachrichtenversand wird errichtet. Vom Empfänger geforderte Schwierigkeit: %1 und %2 - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Problem: Die vom Empfänger verlangte Arbeit (%1 und %2) ist schwieriger, als Sie in den Einstellungen erlaubt haben. %3 - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Problem: Sie versuchen, eine Nachricht an sich zu versenden, aber Ihr Schlüssel befindet sich nicht in der keys.dat-Datei. Die Nachricht kann nicht verschlüsselt werden. 1% - - - - Doing work necessary to send message. - Arbeit wird verrichtet, um die Nachricht zu verschicken. - - - - Message sent. Waiting for acknowledgement. Sent on %1 - Nachricht gesendet. Auf Bestätigung wird gewartet. Zeitpunkt der Sendung: %1 - - - + Doing work necessary to request encryption key. - Arbeit wird verrichtet, um den Schlüssel nachzufragen... + Verrichte die benötigte Arbeit um den Verschlüsselungscode anzufragen. - - Broadcasting the public key request. This program will auto-retry if they are offline. - Anfrage nach dem öffentlichen Schlüssel läuft. Wenn der Besitzer nicht mit dem Netzwerk verbunden ist, wird ein Wiederholungsversuch unternommen. + + Broacasting the public key request. This program will auto-retry if they are offline. + Anfrage für den Verschlüsselungscode versendet (wird automatisch periodisch neu verschickt). - + Sending public key request. Waiting for reply. Requested at %1 - Nachfrage nach dem öffentlichen Schlüssel läuft, auf Antwort wird gewartet. Nachgefragt am %1 + Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - - UPnP port mapping established on port %1 - UPnP Port-Mapping eingerichtet auf Port %1 + + Mark Unread + Als ungelesen markieren - - UPnP port mapping removed - UPnP Port-Mapping entfernt + + Fetched address from namecoin identity. + Adresse aus Namecoin Identität geholt. - - Mark all messages as read - Alle Nachrichten als gelesen markieren + + Testing... + teste... - - Are you sure you would like to mark all messages read? - Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? + + Fetch Namecoin ID + Hole Namecoin ID - - Doing work necessary to send broadcast. - Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. + + Ctrl+Q + Strg+Q - - Proof of work pending - Arbeitsbeweis wird berechnet - - - - %n object(s) pending proof of work - %n Objekt wartet auf Berechnungen%n Objekte warten auf Berechnungen - - - - %n object(s) waiting to be distributed - %n Objekt wartet darauf, verteilt zu werden%n Objekte warten darauf, verteilt zu werden + + F1 + F1 - - Wait until these tasks finish? - Warten bis diese Aufgaben erledigt sind? + + Set avatar... + Avatar wählen... - - Problem communicating with proxy: %1. Please check your network settings. - Kommunikationsfehler mit dem Proxy: %1. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. + + Bad address version number + - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. + + Your address version number must be a number: either 3 or 4. + - - The time on your computer, %1, may be wrong. Please verify your settings. - Die Uhrzeit ihres Computers, %1, ist möglicherweise falsch. Bitte überprüfen Sie Ihre einstellungen. + + Your address version number must be either 3 or 4. + - - The name %1 was not found. - Der Name %1 wurde nicht gefunden. + + Inventory lookups per second: %1 + Inventory lookups pro Sekunde: %1 - - The namecoin query failed (%1) - Namecoin-abfrage fehlgeschlagen (%1) + + Will not resend ever + - - The namecoin query failed. - Namecoin-abfrage fehlgeschlagen. + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + - - The name %1 has no valid JSON data. - Der Name %1 beinhaltet keine gültige JSON-Daten. + + Do you really want to remove this avatar? + Wollen Sie diesen Avatar wirklich entfernen? - - The name %1 has no associated Bitmessage address. - Der Name %1 hat keine zugewiesene Bitmessageaddresse. + + You have already set an avatar for this address. Do you really want to overwrite it? + Sie haben bereits einen Avatar für diese Adresse gewählt. Wollen Sie ihn wirklich überschreiben? - - Success! Namecoind version %1 running. - Erfolg! Namecoind Version %1 läuft. + + Start-on-login not yet supported on your OS. + Mit Betriebssystem starten, noch nicht unterstützt - - Success! NMControll is up and running. - Erfolg! NMControl läuft. + + Minimize-to-tray not yet supported on your OS. + - - Couldn't understand NMControl. - Kann NMControl nicht verstehen. + + Tray notifications not yet supported on your OS. + - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Ihre Grafikkarte hat inkorrekt berechnet, OpenCL wird deaktiviert. Bitte benachrichtigen Sie die Entwickler. + + Enter an address above. + - - Set notification sound... - Benachrichtigungsklang einstellen ... + + Address is an old type. We cannot display its past broadcasts. + - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Willkommen zu einfachem und sicherem Bitmessage -* senden Sie Nachrichten an andere Leute -* senden Sie Rundrufe wie bei Twitter oder -* diskutieren Sie mit anderen Leuten in Chans + + There are no recent broadcasts from this address to display. + - - not recommended for chans - für Chans nicht empfohlen + + Display the %1 recent broadcast from this address. + - - Quiet Mode - stiller Modus + + Display the %1 recent broadcasts from this address. + - - Problems connecting? Try enabling UPnP in the Network Settings - Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Sie versuchen, eine E-Mail anstelle einer Bitmessage zu senden. Dies erfordert eine Registrierung bei einer Schnittstelle. Registrierung versuchen? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Fehler: Bitmessage Adressen starten mit BM- Bitte überprüfen Sie die Empfängeradresse %1 - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Fehler: Die Empfängeradresse %1 wurde nicht korrekt getippt oder kopiert. Bitte überprüfen. - - - - Error: The recipient address %1 contains invalid characters. Please check it. - Fehler: Die Empfängeradresse %1 beinhaltet ungültig Zeichen. Bitte überprüfen. - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Fehler: Die Empfängerdresseversion von %1 ist zu hoch. Entweder Sie müssen Ihre Bitmessage Software aktualisieren oder Ihr Bekannter ist sehr clever. - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Fehler: Einige Daten die in der Empfängerdresse %1 codiert sind, sind zu kurz. Es könnte sein, dass etwas mit der Software Ihres Bekannten nicht stimmt. - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Fehler: Einige Daten die in der Empfängeradresse %1 codiert sind, sind zu lang. Es könnte sein, dass etwas mit der Software Ihres Bekannten nicht stimmt. - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Fehler: Einige codierte Daten in der Empfängeradresse %1 sind ungültig. Es könnte etwas mit der Software Ihres Bekannten sein. - - - - Error: Something is wrong with the recipient address %1. - Fehler: Mit der Empfängeradresse %1 stimmt etwas nicht. - - - - Error: %1 - Fehler: %1 - - - - From %1 - Von %1 - - - - Synchronisation pending - Synchronisierung läuft - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage ist nicht synchronisiert, %n Objekt wurde noch nicht heruntergeladen. Wenn Sie das Programm jetzt beenden, kann es zu Zustellverzögerungen kommen. Warten bis die Synchronisierung abgeschlossen ist?Bitmessage ist nicht synchronisiert, %n Objekte wurden noch nicht heruntergeladen. Wenn Sie das Programm jetzt beenden, kann es zu Zustellverzögerungen kommen. Warten bis die Synchronisierung abgeschlossen ist? - - - - Not connected - Nicht verbunden - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage ist nicht mit dem Netzwerk verbunden. Wenn Sie das Programm jetzt beenden, kann es zu Zustellverzögerungen kommen. Warten bis eine Verbindung besteht und die Synchronisierung abgeschlossen ist? - - - - Waiting for network connection... - Warte auf Netzwerkverbindung... - - - - Waiting for finishing synchronisation... - Warte auf Synchronisationsabschluss... - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - Sie haben bereits einen Benachrichtigungsklang für diesen Adressbucheintrag gesetzt. Möchten Sie ihn wirklich überschreiben? - - - - Error occurred: could not load message from disk. - Fehler: Nachricht konnte nicht geladen werden. - - - - Display the %n recent broadcast(s) from this address. - Den letzten %1 Rundruf von dieser Addresse anzeigen.Die letzten %1 Rundrufe von dieser Addresse anzeigen. - - - - Go online - Mit dem Netzwerk verbinden - - - - Go offline - Trennen vom Netzwerk - - - - Clear - Löschen - - - - inbox - Eingang - - - - new - Neu - - - - sent - - - - - trash - - - - - MessageView - - - Follow external link - Externen Link folgen - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - Der Link "%1" wird in Browser geöffnet. Es kann ein Sicherheitsrisiko darstellen, es könnte Sie de-anonymisieren oder schädliche Aktivitäten durchführen. Sind Sie sicher? - - - - HTML detected, click here to display - HTML gefunden, klicken Sie hier um anzuzeigen - - - - Click here to disable HTML - Klicken Sie hier um HTML-Anzeige zu deaktivieren - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - Diese Bitmessage verwendtet eine unbekannte codierung. -Womöglich sollten Sie Bitmessage upgraden. - - - - Unknown encoding - Codierung unbekannt + + Inventory lookups per second: 0 + Inventory lookups pro Sekunde: 0 NewAddressDialog - + Create new Address Neue Adresse erstellen - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: Sie können so viele Adressen generieren wie Sie möchten. Es ist sogar empfohlen neue Adressen zu verwenden und alte fallen zu lassen. Sie können Adressen durch Zufallszahlen erstellen lassen, oder unter Verwendung eines Kennwortsatzes. Wenn Sie einen Kennwortsatz verwenden, nennt man dies eine "deterministische" Adresse. -Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministische Adressen einige Vor- und Nachteile: +Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen einige Vor- und Nachteile: - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Vorteile:<br/></span>Sie können ihre Adresse an jedem Computer aus dem Gedächtnis regenerieren. <br/>Sie brauchen sich keine Sorgen um das Sichern ihrer Schlüssel machen solange Sie sich den Kennwortsatz merken. <br/><span style=" font-weight:600;">Nachteile:<br/></span>Sie müssen sich den Kennwortsatz merken (oder aufschreiben) wenn Sie in der Lage sein wollen ihre Schlüssel wiederherzustellen. <br/>Sie müssen sich die Adressversion und die Datenstrom Nummer zusammen mit dem Kennwortsatz merken. <br/>Wenn Sie einen schwachen Kennwortsatz wählen und jemand kann ihn erraten oder durch ausprobieren herausbekommen, kann dieser Ihre Nachrichten lesen, oder in ihrem Namen Nachrichten senden..</p></body></html> - + Use a random number generator to make an address Lassen Sie eine Adresse mittels Zufallsgenerator erstellen - + Use a passphrase to make addresses Benutzen Sie einen Kennwortsatz um eine Adresse erstellen zu lassen - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter Verwenden Sie einige Minuten extra Rechenleistung um die Adresse(n) ein bis zwei Zeichen kürzer zu machen - + Make deterministic addresses Deterministische Adresse erzeugen - - Address version number: 4 - Adress-Versionsnummer: 4 + + Address version number: 3 + Adress-Versionsnummer: 3 - + In addition to your passphrase, you must remember these numbers: Zusätzlich zu Ihrem Kennwortsatz müssen Sie sich diese Zahlen merken: - + Passphrase Kennwortsatz - + Number of addresses to make based on your passphrase: Anzahl Adressen die basierend auf diesem Kennwortsatz erzeugt werden sollen: - + Stream number: 1 Datenstrom Nummer: 1 - + Retype passphrase Kennwortsatz erneut eingeben - + Randomly generate address Zufällig generierte Adresse - + Label (not shown to anyone except you) Bezeichnung (Wird niemandem außer Ihnen gezeigt) - + Use the most available stream Verwendung des am besten verfügbaren Datenstroms - + (best if this is the first of many addresses you will create) (Zum Generieren der ersten Adresse empfohlen) - + Use the same stream as an existing address Verwendung des gleichen Datenstroms wie eine bestehende Adresse - + (saves you some bandwidth and processing power) (Dies erspart Ihnen etwas an Bandbreite und Rechenleistung) + + + Address version number: 4 + Adress-Versionsnummer: 4 + NewSubscriptionDialog - + Add new entry Neuen Eintrag erstellen - + Label Name oder Bezeichnung - + Address Adresse - - Enter an address above. - Bitte geben Sie oben eine Adresse ein. + + CheckBox + SpecialAddressBehaviorDialog - + Special Address Behavior Spezielles Adressverhalten - + Behave as a normal address Wie eine normale Adresse verhalten - + Behave as a pseudo-mailing-list address Wie eine Pseudo-Mailinglistenadresse verhalten - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Nachrichten an eine Pseudo-Mailinglistenadresse werden automatisch an alle Abonnenten weitergeleitet (Der Inhalt ist dann öffentlich). + Nachrichten an eine Pseudo-Mailinglistenadresse werden automatisch zu allen Abbonenten weitergeleitet (Der Inhalt ist dann öffentlich). - + Name of the pseudo-mailing-list: Name der Pseudo-Mailingliste: - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - aboutDialog - + About Über - + PyBitmessage - + PyBitmessage - + version ? - + Version ? + + + + Copyright © 2013 Jonathan Warren + Copyright © 2013 Jonathan Warren - + <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> - <html><head/><body><p>Veröffentlicht unter der MIT/X11 Software-Lizenz, siehe unter <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> + <html><head/><body><p>Veröffentlicht unter der MIT/X11 Software-Lizenz; 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> - + This is Beta software. Dies ist Beta-Software. - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Liste als Blacklist verwenden (Erlaubt alle eingehenden Nachrichten, außer von Adressen auf der Blacklist) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Liste als Whitelist verwenden (Erlaubt keine eingehenden Nachrichten, außer von Adressen auf der Whitelist) - - - - Add new entry - Neuen Eintrag erstellen - - - - Name or Label - Name oder Bezeichnung - - - - Address - Adresse - - - - Blacklist - Blacklist (Liste gesperrter Adressen) - - - - Whitelist - Whitelist (Liste zugelassener Adressen) + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + connectDialog - + Bitmessage - Bitmessage + Internetverbindung - + Bitmessage won't connect to anyone until you let it. Bitmessage wird sich nicht verbinden, wenn Sie es nicht möchten. - + Connect now Jetzt verbinden - + Let me configure special network settings first - Zunächst spezielle Netzwerkeinstellungen vornehmen - - - - Work offline - Nicht verbinden + Zunächst spezielle Nertzwerkeinstellungen vornehmen helpDialog - + Help Hilfe - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Bitmessage ist ein kollaboratives Projekt. Hilfe finden Sie online im Bitmessage-Wiki: @@ -1929,671 +1281,468 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi iconGlossaryDialog - + Icon Glossary Icon Glossar - + You have no connections with other peers. Sie haben keine Verbindung mit anderen Netzwerkteilnehmern. - + 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. - Sie haben mindestes eine Verbindung mit einem Netzwerkteilnehmer über eine ausgehende Verbindung, aber Sie haben noch keine eingehende Verbindung. Ihre Firewall oder Ihr Router ist vermutlich nicht richtig konfiguriert, um eingehende TCP-Verbindungen an Ihren Computer weiterzuleiten. Bitmessage wird gut funktionieren, jedoch helfen Sie dem Netzwerk, wenn Sie eingehende Verbindungen erlauben. Es hilft auch Ihnen, schneller und mehr Verbindungen ins Netzwerk aufzubauen. + Sie haben mindestes eine Verbindung mit einem Netzwerkteilnehmer über eine ausgehende Verbindung, aber Sie haben noch keine eingehende Verbindung. Ihre Firewall oder Ihr Router ist vermutlich nicht richtig konfiguriert, um eingehende TCP-Verbindungen an Ihren Computer weiterzuleiten. Bitmessage wird gut funktionieren, jedoch helfen Sie dem Netzwerk, wenn Sie eingehende Verbindungen erlauben. Es hilft auch Ihnen schneller und mehr Verbindungen ins Netzwerk aufzubauen. You are using TCP port ?. (This can be changed in the settings). - + Sie benutzen TCP-Port ?. (Dies kann in den Einstellungen verändert werden). - + You do have connections with other peers and your firewall is correctly configured. Sie haben Verbindungen mit anderen Netzwerkteilnehmern und Ihre Firewall ist richtig konfiguriert. - - - You are using TCP port %1. (This can be changed in the settings). - Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). - - - - networkstatus - - - Total connections: - Verbindungen insgesamt: - - - - Since startup: - Seit Start: - - - - Processed 0 person-to-person messages. - 0 Person-zu-Person-Nachrichten verarbeitet. - - - - Processed 0 public keys. - 0 öffentliche Schlüssel verarbeitet. - - - - Processed 0 broadcasts. - 0 Rundrufe verarbeitet. - - - - Inventory lookups per second: 0 - Inventory lookups pro Sekunde: 0 - - - - Objects to be synced: - Zu synchronisierende Objektanzahl: - - - - Stream # - Datenstrom # - - - - Connections - - - - - Since startup on %1 - Seit Start der Anwendung am %1 - - - - Down: %1/s Total: %2 - Herunter: %1/s Insg.: %2 - - - - Up: %1/s Total: %2 - Hoch: %1/s Insg.: %2 - - - - Total Connections: %1 - Verbindungen insgesamt: %1 - - - - Inventory lookups per second: %1 - Inventory lookups pro Sekunde: %1 - - - - Up: 0 kB/s - Hoch: 0 kB/s - - - - Down: 0 kB/s - Herunter: 0 kB/s - - - - Network Status - Netzwerkstatus - - - - byte(s) - ByteBytes - - - - Object(s) to be synced: %n - %n Objekt zu synchronisieren.%n Objekte zu synchronisieren. - - - - Processed %n person-to-person message(s). - %n Person-zu-Person-Nachricht bearbeitet.%n Person-zu-Person-Nachrichten bearbeitet. - - - - Processed %n broadcast message(s). - %n Rundruf-Nachricht bearbeitet.%n Rundruf-Nachrichten bearbeitet. - - - - Processed %n public key(s). - %n öffentlicher Schlüssel verarbeitet.%n öffentliche Schlüssel verarbeitet. - - - - Peer - Peer - - - - IP address or hostname - IP-Adresse oder Hostname - - - - Rating - Bewertung - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage verfolgt die Erfolgsrate von Verbindungsversuchen zu einzelnen Knoten. Die Bewertung reicht von -1 bis 1 und beeinflusst die Wahrscheinlichkeit, den Knoten zukünftig auszuwählen - - - - User agent - Benutzer-Agent - - - - Peer's self-reported software - Peer's selbstberichtete Software - - - - TLS - TLS - - - - Connection encryption - Verbindungsverschlüsselung - - - - List of streams negotiated between you and the peer - Liste der zwischen Ihnen und dem Peer ausgehandelter Datenströme - newChanDialog Dialog - + Chan beitreten / erstellen Create a new chan - + Neuen Chan erstellen Join a chan - + Einem Chan beitreten Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + Chan erstellen Chan name: - + Chan-Name: <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + <html><head/><body><p>Ein Chan existiert, wenn eine Gruppe von Leuten sich den gleichen Entschlüsselungscode teilen. Die Schlüssel und Bitmessage-Adressen werden basierend auf einem lesbaren Wort oder Satz generiert (dem Chan-Namen). Um eine Nachricht an den Chan zu senden, senden Sie eine normale Person-zu-Person-Nachricht an die Chan-Adresse.</p><p>Chans sind experimentell und völlig unmoderierbar.</p><br></body></html> Chan bitmessage address: - + Chan-Bitmessage-Adresse: - - Create or join a chan - Chan erstellen oder beitreten - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Wenn eine Gruppe von Leuten sich den gleichen Entschlüsselungscode teilen, bilden sie einen "chan". Die Schlüssel und Bitmessage-Adressen werden basierend auf einem lesbaren Wort oder Satz generiert (dem Chan-Namen). Um eine Nachricht an den Chan zu senden, senden Sie eine Nachricht an die Chan-Adresse.</p><p>Chans sind experimentell und völlig zentral unmoderierbar.</p><p>Geben Sie einen Namen für Ihren Chan ein. Wenn Sie einen ausreichend komplexen Chan-Namen wählen (wie einen starken, einzigartigen Kennwortsatz) und keiner Ihrer Freunde ihn öffentlich weitergibt, wird der Chan sicher und privat bleiben. Wenn eine andere Person einen Chan mit dem gleichen Namen erzeugt, repräsentieren diese denselben Chan, bzw. der Chan für beide Personen verwendbar.</p></body></html> - - - - Chan passphrase/name: - Chan-Name - - - - Optional, for advanced usage - Optional, für Fortgeschrittene - - - - Chan address - Chan-Adresse - - - - Please input chan name/passphrase: - Bitte Chan-Namen eingeben: - - - - newchandialog - - - Successfully created / joined chan %1 - Chan %1 erfolgreich erstellt/beigetreten - - - - Chan creation / joining failed - Chan-erstellung/-beitritt fehlgeschlagen - - - - Chan creation / joining cancelled - Chan-erstellung/-beitritt abgebrochen - - - - proofofwork - - - C PoW module built successfully. - C-PoW-Modul erfolgreich erstellt. - - - - Failed to build C PoW module. Please build it manually. - Erstellung vom C-PoW-Modul fehlgeschlagen. Bitte erstellen Sie es manuell. - - - - C PoW module unavailable. Please build it. - C-PoW-Modul nicht verfügbar. Bitte erstellen Sie es. - - - - qrcodeDialog - - - QR-code - QR-Code + + <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> + <html><head/><body><p>Geben Sie einen Namen für Ihren Chan ein. Wenn Sie einen ausreichend komplexen Chan-Namen wählen (wie einen starken, einzigartigen Kennwortsatz) und keiner Ihrer Freunde ihn öffentlich weitergibt, wird der Chan sicher und privat bleiben. Wenn eine andere Person einen Chan mit dem gleichen Namen erzeugt, werden diese zu einem Chan.</p><br></body></html> regenerateAddressesDialog - + Regenerate Existing Addresses Bestehende Adresse regenerieren - + Regenerate existing addresses Bestehende Adresse regenerieren - + Passphrase Kennwortsatz - + Number of addresses to make based on your passphrase: - Anzahl Adressen die basierend auf diesem Kennwortsatz erzeugt werden sollen: + Anzahl der Adressen, die basierend auf diesem Kennwortsatz erzeugt werden sollen: - - Address version number: - Adress-Versionsnummer: + + Address version Number: + Adress-Versionsnummer: - + + 3 + 3 + + + Stream number: Stream-Nummer: - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Verwenden Sie einige Minuten extra Rechenleistung um die Adresse(n) ein bis zwei Zeichen kürzer zu machen + Verwenden Sie einige Minuten extra Rechenleistung, um die Adresse(n) ein bis zwei Zeichen kürzer zu machen - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Sie müssen diese Option auswählen (oder nicht auswählen) wie Sie es gemacht haben, als Sie Ihre Adresse das erste Mal erstellt haben. + Sie müssen diese Option auswählen (oder nicht auswählen) wie Sie es gemacht haben, als Sie Ihre Adresse das erste mal erstellt haben. - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. Wenn Sie bereits deterministische Adressen erstellt haben, aber diese durch einen Unfall (zum Beispiel durch eine defekte Festplatte) verloren haben, können Sie sie hier regenerieren. Dies funktioniert nur dann, wenn Sie bei der erstmaligen Erstellung Ihrer Adressen nicht den Zufallsgenerator verwendet haben. + + + Address version number: + Adress-Versionsnummer: + settingsDialog - + Settings Einstellungen - + Start Bitmessage on user login Bitmessage nach dem Hochfahren automatisch starten - - Tray - Infobereich (Taskleiste) - - - + Start Bitmessage in the tray (don't show main window) Bitmessage minimiert starten (zeigt das Hauptfenster nicht an) - + Minimize to tray - In den Infobereich (Tray) minimieren + In den Systemtray minimieren - - Close to tray - Schliessen in den Infobereich (Tray) - - - + Show notification when message received Benachrichtigung anzeigen, wenn eine Nachricht eintrifft - + Run in Portable Mode Im portablen Modus arbeiten - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. Im portablen Modus werden Nachrichten und Konfigurationen im gleichen Ordner abgelegt, in dem sich das Programm selbst befindet (anstatt im normalen Anwendungsdaten-Ordner). Das macht es möglich, Bitmessage auf einem USB-Stick zu betreiben. - - Willingly include unencrypted destination address when sending to a mobile device - Willentlich die unverschlüsselte Adresse des Empfängers übertragen, wenn an ein mobiles Gerät gesendet wird - - - - Use Identicons - Benutze Identicons (Automatisch generierte Icons zu einer Bitmessageadresse) - - - - Reply below Quote - Antworte unter zitierter Nachricht - - - - Interface Language - Sprachauswahl - - - - System Settings - system - Systemeinstellungen - - - + User Interface Benutzerinterface - + Listening port - Empfangender TCP-Port + TCP-Port - + Listen for connections on port: Wartet auf Verbindungen auf Port: - - UPnP: - UPnP: - - - - Bandwidth limit - Bandbreite begrenzen - - - - Maximum download rate (kB/s): [0: unlimited] - Maximale Downloadrate in kB/s, 0 bedeutet kein Limit - - - - Maximum upload rate (kB/s): [0: unlimited] - Maximale Uploadrate in kB/s, 0 bedeutet kein Limit - - - + Proxy server / Tor Proxy-Server / Tor - + Type: Typ: - - Server hostname: - Servername: - - - - Port: - Port: - - - - Authentication - Authentifizierung - - - - Username: - Benutzername: - - - - Pass: - Kennwort: - - - - Listen for incoming connections when using proxy - Auf eingehende Verbindungen warten, auch wenn ein Proxy-Server verwendet wird - - - + none keiner - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + + Server hostname: + Servername: + + + + Port: + Port: + + + + Authentication + Authentifizierung + + + + Username: + Benutzername: + + + + Pass: + Kennwort: + + + Network Settings Netzwerkeinstellungen - - Total difficulty: - Gesamtschwierigkeit: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - Die "Gesamtschwierigkeit" beeinflusst die absolute Menge Arbeit, die ein Sender verrichten muss. Verdoppelung dieses Wertes verdoppelt die Menge der Arbeit. - - - - Small message difficulty: - Schwierigkeit für kurze Nachrichten: - - - + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. Wenn jemand Ihnen eine Nachricht schickt, muss der absendende Computer erst einige Arbeit verrichten. Die Schwierigkeit dieser Arbeit ist standardmäßig 1. Sie können diesen Wert für alle neuen Adressen, die Sie generieren, hier ändern. Es gibt eine Ausnahme: Wenn Sie einen Freund oder Bekannten in Ihr Adressbuch übernehmen, wird Bitmessage ihn mit der nächsten Nachricht automatisch informieren, dass er nur noch die minimale Arbeit verrichten muss: Schwierigkeit 1. - + + Total difficulty: + Gesamtschwierigkeit: + + + + Small message difficulty: + Schwierigkeit für kurze Nachrichten: + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. Die "Schwierigkeit für kurze Nachrichten" trifft nur auf das Senden kurzer Nachrichten zu. Verdoppelung dieses Wertes macht es fast doppelt so schwer, kurze Nachrichten zu senden, aber hat keinen Effekt bei langen Nachrichten. - + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + Die "Gesamtschwierigkeit" beeinflusst die absolute Menge Arbeit, die ein Sender verrichten muss. Verdoppelung dieses Wertes verdoppelt die Menge der Arbeit. + + + Demanded difficulty Geforderte Schwierigkeit - + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. Hier setzen Sie die maximale Arbeit, die Sie bereit sind zu verrichten, um eine Nachricht an eine andere Person zu versenden. Ein Wert von 0 bedeutet, dass Sie jede Arbeit akzeptieren. - + Maximum acceptable total difficulty: Maximale akzeptierte Gesamtschwierigkeit: - + Maximum acceptable small message difficulty: Maximale akzeptierte Schwierigkeit für kurze Nachrichten: - + Max acceptable difficulty Maximale akzeptierte Schwierigkeit - - Hardware GPU acceleration (OpenCL) - + + Listen for incoming connections when using proxy + Auf eingehende Verbindungen warten, auch wenn ein Proxy-Server verwendet wird - + + Willingly include unencrypted destination address when sending to a mobile device + Willentlich die unverschlüsselte Adresse des Empfängers übertragen, wenn an ein mobiles Gerät gesendet wird + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> <html><head/><body><p>Bitmessage kann ein anderes Bitcoin basiertes Programm namens Namecoin nutzen, um Adressen leserlicher zu machen. Zum Beispiel: Anstelle Ihrem Bekannten Ihre lange Bitmessage-Adresse vorzulesen, können Sie ihm einfach sagen, er soll eine Nachricht an <span style=" font-style:italic;">test </span>senden.</p><p> (Ihre Bitmessage-Adresse in Namecoin zu speichern ist noch sehr umständlich)</p><p>Bitmessage kann direkt namecoind verwenden, oder eine nmcontrol Instanz.</p></body></html> - + Host: Server: - + Password: Kennwort: - + Test Verbindung testen - + Connect to: Verbinde mit: - + Namecoind Namecoind - + NMControl NMControl - + Namecoin integration Namecoin Integration - + + Override automatic language localization (use countycode or language code, e.g. 'en_US' or 'en'): + Automatische Sprachauswahl überschreiben (verwenden Sie den Landescode oder Sprachcode, z.B. "de_DE" oder "de"): + + + + Use Identicons + Benutze Identicons (Automatisch generierte Icons zu einer Bitcoinadresse) + + + + Interface Language + Sprachauswahl + + + + System Settings + system + + + + + English + en + + + + + Esperanto + eo + + + + + Français + fr + + + + + Deutsch + de + + + + + Españl + es + + + + + русский язык + ru + + + + + Norsk + no + + + + + Pirate English + en_pirate + + + + + Other (set in keys.dat) + other + + + + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Wenn der Empfänger eine Nachricht nicht bis zum Verfallsdatum herunterlädt, zum Beispiel weil er für längere Zeit nicht mit dem Netz verbunden ist, wird die Nachricht erneut versendet. Dies passiert solange, bis eine Empfangsbestätigung erhalten wird. Hier können Sie dieses Verhalten ändern, indem Sie Bitmessage die Wiederversandversuche nach einer bestimmten Anzahl von Tagen oder Monaten aufgeben lassen.</p><p>Für die Standardeinstellung (ohne zeitliche Einschränkung) lassen Sie diese Eingabefelder leer.</p></body></html> + <html><head/><body><p>Wurde eine Nachricht innerhalb von zwei Tagen nicht bestätigt, wird sie in zwei Tagen noch einmal gesendet. Schlägt dies wieder fehl, wird es in 5, dann in 10, dann in 20 usw. Tagen wieder versucht. Sendet der Empfänger keine Bestätigung, geht dies unendlich so weiter.</p><p>Dieses Verhalten kann hier begrenzt werden.</p></body></html> - + Give up after - Gib auf nach + Gib auf nach - + and - und + und - + days - Tagen + Tagen - + months. - Monaten. + Monaten - + Resends Expire - Verfall der erneuten Sendungen + Neusendung - - Hide connection notifications - Verbindungsbenachrichtigungen nicht anzeigen + + Reply below Quote + Antworte unter zitierter Nachricht - - Maximum outbound connections: [0: none] - Maximale Anzahl der ausgehenden Verbindungen, 0 bedeutet keine + + Bandwidth limit + Bandbreite begrenzen - - Hardware GPU acceleration (OpenCL): - Hardwaregrafikkartenbeschleunigung (OpenCL): + + Maximum download rate (kB/s): [0: unlimited] + Maximale Downloadrate in kB/s, 0 bedeutet kein Limit + + + + Maximum upload rate (kB/s): [0: unlimited] + Maximale Uploadrate in kB/s, 0 bedeutet kein Limit - \ No newline at end of file + diff --git a/src/translations/bitmessage_en.qm b/src/translations/bitmessage_en.qm deleted file mode 100644 index 4751f4ca..00000000 Binary files a/src/translations/bitmessage_en.qm and /dev/null differ diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts deleted file mode 100644 index 05e9cc4b..00000000 --- a/src/translations/bitmessage_en.ts +++ /dev/null @@ -1,2175 +0,0 @@ - - - - AddAddressDialog - - - Add new entry - Add new entry - - - - Label - Label - - - - Address - Address - - - - EmailGatewayDialog - - - Email gateway - Email gateway - - - - Register on email gateway - Register on email gateway - - - - Account status at email gateway - Account status at email gateway - - - - Change account settings at email gateway - Change account settings at email gateway - - - - Unregister from email gateway - Unregister from email gateway - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - Desired email address (including @mailchuck.com): - Desired email address (including @mailchuck.com): - - - - EmailGatewayRegistrationDialog - - - Registration failed: - Registration failed: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - Email gateway registration - Email gateway registration - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - - MainWindow - - - Reply to sender - Reply to sender - - - - Reply to channel - Reply to channel - - - - Add sender to your Address Book - Add sender to your Address Book - - - - Add sender to your Blacklist - Add sender to your Blacklist - - - - Move to Trash - Move to Trash - - - - Undelete - Undelete - - - - View HTML code as formatted text - View HTML code as formatted text - - - - Save message as... - Save message as... - - - - Mark Unread - Mark Unread - - - - New - New - - - - Enable - Enable - - - - Disable - Disable - - - - Set avatar... - Set avatar... - - - - Copy address to clipboard - Copy address to clipboard - - - - Special address behavior... - Special address behavior... - - - - Email gateway - Email gateway - - - - Delete - Delete - - - - Send message to this address - Send message to this address - - - - Subscribe to this address - Subscribe to this address - - - - Add New Address - Add New Address - - - - Copy destination address to clipboard - Copy destination address to clipboard - - - - Force send - Force send - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - - - - Waiting for their encryption key. Will request it again soon. - Waiting for their encryption key. Will request it again soon. - - - - Encryption key request queued. - Encryption key request queued. - - - - Queued. - Queued. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Message sent. Waiting for acknowledgement. Sent at %1 - - - - Message sent. Sent at %1 - Message sent. Sent at %1 - - - - Need to do work to send message. Work is queued. - Need to do work to send message. Work is queued. - - - - Acknowledgement of the message received %1 - Acknowledgement of the message received %1 - - - - Broadcast queued. - Broadcast queued. - - - - Broadcast on %1 - Broadcast on %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - - - - Forced difficulty override. Send should start soon. - Forced difficulty override. Send should start soon. - - - - Unknown status: %1 %2 - Unknown status: %1 %2 - - - - Not Connected - Not Connected - - - - Show Bitmessage - Show Bitmessage - - - - Send - Send - - - - Subscribe - Subscribe - - - - Channel - Channel - - - - Quit - Quit - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - - - - Open keys.dat? - Open keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - Delete trash? - Delete trash? - - - - Are you sure you want to delete all trashed messages? - Are you sure you want to delete all trashed messages? - - - - bad passphrase - bad passphrase - - - - You must type your passphrase. If you don't have one then this is not the form for you. - You must type your passphrase. If you don't have one then this is not the form for you. - - - - Bad address version number - Bad address version number - - - - Your address version number must be a number: either 3 or 4. - Your address version number must be a number: either 3 or 4. - - - - Your address version number must be either 3 or 4. - Your address version number must be either 3 or 4. - - - - Chan name needed - Chan name needed - - - - You didn't enter a chan name. - You didn't enter a chan name. - - - - Address already present - Address already present - - - - Could not add chan because it appears to already be one of your identities. - Could not add chan because it appears to already be one of your identities. - - - - Success - Success - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - Address too new - Address too new - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - Address invalid - Address invalid - - - - That Bitmessage address is not valid. - That Bitmessage address is not valid. - - - - Address does not match chan name - Address does not match chan name - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - Successfully joined chan. - Successfully joined chan. - - - - Connection lost - Connection lost - - - - Connected - Connected - - - - Message trashed - Message trashed - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - Message too long - Message too long - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - Error: Bitmessage addresses start with BM- Please check %1 - Error: Bitmessage addresses start with BM- Please check %1 - - - - Error: The address %1 is not typed or copied correctly. Please check it. - Error: The address %1 is not typed or copied correctly. Please check it. - - - - Error: The address %1 contains invalid characters. Please check it. - Error: The address %1 contains invalid characters. Please check it. - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - Error: Something is wrong with the address %1. - Error: Something is wrong with the address %1. - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - - - - Address version number - Address version number - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - Stream number - Stream number - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - - - Message queued. - Message queued. - - - - Your 'To' field is empty. - Your 'To' field is empty. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Right click one or more entries in your address book and select 'Send message to this address'. - - - - Fetched address from namecoin identity. - Fetched address from namecoin identity. - - - - New Message - New Message - - - - From - From - - - - Sending email gateway registration request - Sending email gateway registration request - - - - Address is valid. - Address is valid. - - - - The address you entered was invalid. Ignoring it. - The address you entered was invalid. Ignoring it. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - Restart - Restart - - - - You must restart Bitmessage for the port number change to take effect. - You must restart Bitmessage for the port number change to take effect. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - - - Number needed - Number needed - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - Will not resend ever - Will not resend ever - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - Sending email gateway unregistration request - Sending email gateway unregistration request - - - - Sending email gateway status request - Sending email gateway status request - - - - Passphrase mismatch - Passphrase mismatch - - - - The passphrase you entered twice doesn't match. Try again. - The passphrase you entered twice doesn't match. Try again. - - - - Choose a passphrase - Choose a passphrase - - - - You really do need a passphrase. - You really do need a passphrase. - - - - Address is gone - Address is gone - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - Address disabled - Address disabled - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - Entry added to the Address Book. Edit the label to your liking. - Entry added to the Address Book. Edit the label to your liking. - - - - Entry added to the blacklist. Edit the label to your liking. - Entry added to the blacklist. Edit the label to your liking. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - Moved items to trash. - Moved items to trash. - - - - Undeleted item. - Undeleted item. - - - - Save As... - Save As... - - - - Write error. - Write error. - - - - No addresses selected. - No addresses selected. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - Do you really want to remove this avatar? - Do you really want to remove this avatar? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - You have already set an avatar for this address. Do you really want to overwrite it? - - - - Start-on-login not yet supported on your OS. - Start-on-login not yet supported on your OS. - - - - Minimize-to-tray not yet supported on your OS. - Minimize-to-tray not yet supported on your OS. - - - - Tray notifications not yet supported on your OS. - Tray notifications not yet supported on your OS. - - - - Testing... - Testing... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - The address should start with ''BM-'' - The address should start with ''BM-'' - - - - The address is not typed or copied correctly (the checksum failed). - The address is not typed or copied correctly (the checksum failed). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - The address contains invalid characters. - The address contains invalid characters. - - - - Some data encoded in the address is too short. - Some data encoded in the address is too short. - - - - Some data encoded in the address is too long. - Some data encoded in the address is too long. - - - - Some data encoded in the address is malformed. - Some data encoded in the address is malformed. - - - - Enter an address above. - Enter an address above. - - - - Address is an old type. We cannot display its past broadcasts. - Address is an old type. We cannot display its past broadcasts. - - - - There are no recent broadcasts from this address to display. - There are no recent broadcasts from this address to display. - - - - You are using TCP port %1. (This can be changed in the settings). - You are using TCP port %1. (This can be changed in the settings). - - - - Bitmessage - Bitmessage - - - - Identities - Identities - - - - New Identity - New Identity - - - - Search - Search - - - - All - All - - - - To - To - - - - From - From - - - - Subject - Subject - - - - Message - Message - - - - Received - Received - - - - Messages - Messages - - - - Address book - Address book - - - - Address - Address - - - - Add Contact - Add Contact - - - - Fetch Namecoin ID - Fetch Namecoin ID - - - - Subject: - Subject: - - - - From: - From: - - - - To: - To: - - - - Send ordinary Message - Send ordinary Message - - - - Send Message to your Subscribers - Send Message to your Subscribers - - - - TTL: - TTL: - - - - Subscriptions - Subscriptions - - - - Add new Subscription - Add new Subscription - - - - Chans - Chans - - - - Add Chan - Add Chan - - - - File - File - - - - Settings - Settings - - - - Help - Help - - - - Import keys - Import keys - - - - Manage keys - Manage keys - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Contact support - - - - About - About - - - - Regenerate deterministic addresses - Regenerate deterministic addresses - - - - Delete all trashed messages - Delete all trashed messages - - - - Join / Create chan - Join / Create chan - - - - All accounts - All accounts - - - - Zoom level %1% - Zoom level %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - Add new entry - Add new entry - - - - Display the %1 recent broadcast(s) from this address. - Display the %1 recent broadcast(s) from this address. - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - Waiting for PoW to finish... %1% - Waiting for PoW to finish... %1% - - - - Shutting down Pybitmessage... %1% - Shutting down Pybitmessage... %1% - - - - Waiting for objects to be sent... %1% - Waiting for objects to be sent... %1% - - - - Saving settings... %1% - Saving settings... %1% - - - - Shutting down core... %1% - Shutting down core... %1% - - - - Stopping notifications... %1% - Stopping notifications... %1% - - - - Shutdown imminent... %1% - Shutdown imminent... %1% - - - - %n hour(s) - - %n hour - %n hours - - - - - %n day(s) - - %n day - %n days - - - - - Shutting down PyBitmessage... %1% - Shutting down PyBitmessage... %1% - - - - Sent - Sent - - - - Generating one new address - Generating one new address - - - - Done generating address. Doing work necessary to broadcast it... - Done generating address. Doing work necessary to broadcast it... - - - - Generating %1 new addresses. - Generating %1 new addresses. - - - - %1 is already in 'Your Identities'. Not adding it again. - %1 is already in 'Your Identities'. Not adding it again. - - - - Done generating address - Done generating address - - - - SOCKS5 Authentication problem: %1 - SOCKS5 Authentication problem: %1 - - - - Disk full - Disk full - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - Error! Could not find sender address (your address) in the keys.dat file. - Error! Could not find sender address (your address) in the keys.dat file. - - - - Doing work necessary to send broadcast... - Doing work necessary to send broadcast... - - - - Broadcast sent on %1 - Broadcast sent on %1 - - - - Encryption key was requested earlier. - Encryption key was requested earlier. - - - - Sending a request for the recipient's encryption key. - Sending a request for the recipient's encryption key. - - - - Looking up the receiver's public key - Looking up the receiver's public key - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - Doing work necessary to send message. - Doing work necessary to send message. - - - - Message sent. Waiting for acknowledgement. Sent on %1 - Message sent. Waiting for acknowledgement. Sent on %1 - - - - Doing work necessary to request encryption key. - Doing work necessary to request encryption key. - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - Sending public key request. Waiting for reply. Requested at %1 - Sending public key request. Waiting for reply. Requested at %1 - - - - UPnP port mapping established on port %1 - UPnP port mapping established on port %1 - - - - UPnP port mapping removed - UPnP port mapping removed - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - - - - - Doing work necessary to send broadcast. - - - - - Proof of work pending - - - - - %n object(s) pending proof of work - - - - - - - - %n object(s) waiting to be distributed - - - - - - - - Wait until these tasks finish? - - - - - NewAddressDialog - - - Create new Address - Create new Address - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - Use a random number generator to make an address - Use a random number generator to make an address - - - - Use a passphrase to make addresses - Use a passphrase to make addresses - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - Make deterministic addresses - Make deterministic addresses - - - - Address version number: 4 - Address version number: 4 - - - - In addition to your passphrase, you must remember these numbers: - In addition to your passphrase, you must remember these numbers: - - - - Passphrase - Passphrase - - - - Number of addresses to make based on your passphrase: - Number of addresses to make based on your passphrase: - - - - Stream number: 1 - Stream number: 1 - - - - Retype passphrase - Retype passphrase - - - - Randomly generate address - Randomly generate address - - - - Label (not shown to anyone except you) - Label (not shown to anyone except you) - - - - Use the most available stream - Use the most available stream - - - - (best if this is the first of many addresses you will create) - (best if this is the first of many addresses you will create) - - - - Use the same stream as an existing address - Use the same stream as an existing address - - - - (saves you some bandwidth and processing power) - (saves you some bandwidth and processing power) - - - - NewSubscriptionDialog - - - Add new entry - Add new entry - - - - Label - Label - - - - Address - Address - - - - Enter an address above. - Enter an address above. - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - Special Address Behavior - - - - Behave as a normal address - Behave as a normal address - - - - Behave as a pseudo-mailing-list address - Behave as a pseudo-mailing-list address - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - - - - Name of the pseudo-mailing-list: - Name of the pseudo-mailing-list: - - - - aboutDialog - - - About - About - - - - PyBitmessage - PyBitmessage - - - - version ? - version ? - - - - <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> - <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> - - - - This is Beta software. - This is Beta software. - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - Add new entry - Add new entry - - - - Name or Label - Name or Label - - - - Address - Address - - - - Blacklist - Blacklist - - - - Whitelist - Whitelist - - - - connectDialog - - - Bitmessage - Bitmessage - - - - Bitmessage won't connect to anyone until you let it. - Bitmessage won't connect to anyone until you let it. - - - - Connect now - Connect now - - - - Let me configure special network settings first - Let me configure special network settings first - - - - helpDialog - - - Help - Help - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - - - - iconGlossaryDialog - - - Icon Glossary - Icon Glossary - - - - You have no connections with other peers. - You have no connections with other peers. - - - - 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. - 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. - - - - You are using TCP port ?. (This can be changed in the settings). - You are using TCP port ?. (This can be changed in the settings). - - - - You do have connections with other peers and your firewall is correctly configured. - You do have connections with other peers and your firewall is correctly configured. - - - - networkstatus - - - Total connections: - Total connections: - - - - Since startup: - Since startup: - - - - Processed 0 person-to-person messages. - Processed 0 person-to-person messages. - - - - Processed 0 public keys. - Processed 0 public keys. - - - - Processed 0 broadcasts. - Processed 0 broadcasts. - - - - Inventory lookups per second: 0 - Inventory lookups per second: 0 - - - - Objects to be synced: - Objects to be synced: - - - - Stream # - Stream # - - - - Connections - Connections - - - - Since startup on %1 - Since startup on %1 - - - - Down: %1/s Total: %2 - Down: %1/s Total: %2 - - - - Up: %1/s Total: %2 - Up: %1/s Total: %2 - - - - Total Connections: %1 - Total Connections: %1 - - - - Inventory lookups per second: %1 - Inventory lookups per second: %1 - - - - Up: 0 kB/s - Up: 0 kB/s - - - - Down: 0 kB/s - Down: 0 kB/s - - - - Network Status - Network Status - - - - byte(s) - - byte - bytes - - - - - Object(s) to be synced: %n - - Object to be synced: %n - Objects to be synced: %n - - - - - Processed %n person-to-person message(s). - - Processed %n person-to-person message. - Processed %n person-to-person messages. - - - - - Processed %n broadcast message(s). - - Processed %n broadcast message. - Processed %n broadcast messages. - - - - - Processed %n public key(s). - - Processed %n public key. - Processed %n public keys. - - - - - newChanDialog - - - Dialog - Dialog - - - - Create a new chan - Create a new chan - - - - Join a chan - Join a chan - - - - Create a chan - Create a chan - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - Chan name: - Chan name: - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - Chan bitmessage address: - Chan bitmessage address: - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - Regenerate Existing Addresses - - - - Regenerate existing addresses - Regenerate existing addresses - - - - Passphrase - Passphrase - - - - Number of addresses to make based on your passphrase: - Number of addresses to make based on your passphrase: - - - - Address version number: - Address version number: - - - - Stream number: - Stream number: - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - - - - settingsDialog - - - Settings - Settings - - - - Start Bitmessage on user login - Start Bitmessage on user login - - - - Tray - Tray - - - - Start Bitmessage in the tray (don't show main window) - Start Bitmessage in the tray (don't show main window) - - - - Minimize to tray - Minimize to tray - - - - Close to tray - Close to tray - - - - Show notification when message received - Show notification when message received - - - - Run in Portable Mode - Run in Portable Mode - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - - - - Willingly include unencrypted destination address when sending to a mobile device - Willingly include unencrypted destination address when sending to a mobile device - - - - Use Identicons - Use Identicons - - - - Reply below Quote - Reply below Quote - - - - Interface Language - Interface Language - - - - System Settings - system - System Settings - - - - User Interface - User Interface - - - - Listening port - Listening port - - - - Listen for connections on port: - Listen for connections on port: - - - - UPnP: - UPnP: - - - - Bandwidth limit - Bandwidth limit - - - - Maximum download rate (kB/s): [0: unlimited] - Maximum download rate (kB/s): [0: unlimited] - - - - Maximum upload rate (kB/s): [0: unlimited] - Maximum upload rate (kB/s): [0: unlimited] - - - - Proxy server / Tor - Proxy server / Tor - - - - Type: - Type: - - - - Server hostname: - Server hostname: - - - - Port: - Port: - - - - Authentication - Authentication - - - - Username: - Username: - - - - Pass: - Pass: - - - - Listen for incoming connections when using proxy - Listen for incoming connections when using proxy - - - - none - none - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Network Settings - - - - Total difficulty: - Total difficulty: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - Small message difficulty: - Small message difficulty: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - Demanded difficulty - Demanded difficulty - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - Maximum acceptable total difficulty: - Maximum acceptable total difficulty: - - - - Maximum acceptable small message difficulty: - Maximum acceptable small message difficulty: - - - - Max acceptable difficulty - Max acceptable difficulty - - - - Hardware GPU acceleration (OpenCL) - Hardware GPU acceleration (OpenCL) - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - Host: - Host: - - - - Password: - Password: - - - - Test - Test - - - - Connect to: - Connect to: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Namecoin integration - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - Give up after - Give up after - - - - and - and - - - - days - days - - - - months. - months. - - - - Resends Expire - Resends Expire - - - diff --git a/src/translations/bitmessage_en_pirate.pro b/src/translations/bitmessage_en_pirate.pro new file mode 100644 index 00000000..acc712ee --- /dev/null +++ b/src/translations/bitmessage_en_pirate.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_en_pirate.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_en_pirate.qm b/src/translations/bitmessage_en_pirate.qm index 69e6bde8..24feb4b9 100644 Binary files a/src/translations/bitmessage_en_pirate.qm and b/src/translations/bitmessage_en_pirate.qm differ diff --git a/src/translations/bitmessage_en_pirate.ts b/src/translations/bitmessage_en_pirate.ts index 69642a96..ba97978a 100644 --- a/src/translations/bitmessage_en_pirate.ts +++ b/src/translations/bitmessage_en_pirate.ts @@ -1,1281 +1,976 @@ - + AddAddressDialog Add new entry - Add yee new entry + Add yee new entry Label - Label + Label Address - Address - - - - EmailGatewayDialog - - - Email gateway - - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - + Address MainWindow - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Address Book - - - - - Add sender to your Blacklist - - - - - Move to Trash - - - - - Undelete - - - - - View HTML code as formatted text - - - - - Save message as... - - - - - Mark Unread - - - - - New - - - - - Enable - - - - - Disable - - - - - Set avatar... - - - - - Copy address to clipboard - - - - - Special address behavior... - - - - - Email gateway - - - - - Delete - - - - - Send message to this address - - - - - Subscribe to this address - - - - - Add New Address - - - - - Copy destination address to clipboard - - - - - Force send - - - - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - + + Reply + + + + + Add sender to your Address Book + + + + + Move to Trash + + + + + View HTML code as formatted text + + + + + Save message as... + + + + + Mark Unread + + + + + New + + + + + Enable + + + + + Disable + + + + + Copy address to clipboard + + + + + Special address behavior... + + + + + Send message to this address + + + + + Subscribe to this address + + + + + Add New Address + + + + + Delete + + + + + Copy destination address to clipboard + + + + + Force send + + + + + Add new entry + Add yee new entry + + + + Since startup on %1 + + + + Waiting for their encryption key. Will request it again soon. - + Encryption key request queued. - + Queued. - + Message sent. Waiting for acknowledgement. Sent at %1 - + Message sent. Sent at %1 - + Need to do work to send message. Work is queued. - + Acknowledgement of the message received %1 - + Broadcast queued. - + Broadcast on %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - + Forced difficulty override. Send should start soon. - + Unknown status: %1 %2 - + Not Connected - + Show Bitmessage - + Send - + Subscribe - - Channel + + Address Book - + Quit - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. - + Open keys.dat? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - + Delete trash? - + Are you sure you want to delete all trashed messages? - + bad passphrase - + You must type your passphrase. If you don't have one then this is not the form for you. - - Bad address version number - - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - + Chan name needed - + You didn't enter a chan name. - + Address already present - + Could not add chan because it appears to already be one of your identities. - + Success - + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - + Address too new - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - + Address invalid - + That Bitmessage address is not valid. - + Address does not match chan name - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. - + Successfully joined chan. - + + Processed %1 person-to-person messages. + + + + + Processed %1 broadcast messages. + + + + + Processed %1 public keys. + + + + + Total Connections: %1 + + + + Connection lost - + Connected - + Message trashed - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - + Error: Bitmessage addresses start with BM- Please check %1 - + Error: The address %1 is not typed or copied correctly. Please check it. - + Error: The address %1 contains invalid characters. Please check it. - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - + Error: Something is wrong with the address %1. - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - + Address version number - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - + Stream number - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - Message queued. - - - - + Your 'To' field is empty. - + Right click one or more entries in your address book and select 'Send message to this address'. - + Fetched address from namecoin identity. - + + Work is queued. %1 + + + + New Message - + From - - Sending email gateway registration request - - - - + Address is valid. - + The address you entered was invalid. Ignoring it. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. - + Restart - + You must restart Bitmessage for the port number change to take effect. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - - - - - Write error. - - - - - No addresses selected. - - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - - - - - Identities - - - - - New Identity - - - - - Search - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - Received - - - - - Messages - - - - - Address book - - - - - Address - Address - - - - Add Contact - - - - - Fetch Namecoin ID - - - - - Subject: - - - - - From: - - - - - To: - - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - File - - - - - Settings - Settings - - - - Help - Help - - - - Import keys - - - - - Manage keys - - - - - Ctrl+Q - - - - - F1 - - - - - Contact support - - - - - About - - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - - - - - Zoom level %1% - - - - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - Add new entry - Add yee new entry - - - - Display the %1 recent broadcast(s) from this address. + + Passphrase mismatch - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest + + The passphrase you entered twice doesn't match. Try again. - - Waiting for PoW to finish... %1% + + Choose a passphrase - - Shutting down Pybitmessage... %1% + + You really do need a passphrase. - - Waiting for objects to be sent... %1% + + All done. Closing user interface... - - Saving settings... %1% + + Address is gone - - Shutting down core... %1% + + Bitmessage cannot find your address %1. Perhaps you removed it? - - Stopping notifications... %1% + + Address disabled - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - %n day(s) - - - - - - - - Shutting down PyBitmessage... %1% + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - + + Entry added to the Address Book. Edit the label to your liking. + + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + + + + + Save As... + + + + + Write error. + + + + + No addresses selected. + + + + + Testing... + + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + + + + + The address should start with ''BM-'' + + + + + The address is not typed or copied correctly (the checksum failed). + + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + + + + + The address contains invalid characters. + + + + + Some data encoded in the address is too short. + + + + + Some data encoded in the address is too long. + + + + + You are using TCP port %1. (This can be changed in the settings). + + + + + Bitmessage + + + + + Search + + + + + All + + + + + To + + + + + From + + + + + Subject + + + + + Message + + + + + Received + + + + + Inbox + + + + + Load from Address book + + + + + Fetch Namecoin ID + + + + + Message: + + + + + Subject: + + + + + Send to one or more specific people + + + + + To: + + + + + From: + + + + + Broadcast to everyone who is subscribed to your address + + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + + + + + Status + + + + Sent - - Generating one new address + + Label (not shown to anyone) - - Done generating address. Doing work necessary to broadcast it... + + Address + Address + + + + Stream - - Generating %1 new addresses. + + Your Identities - - %1 is already in 'Your Identities'. Not adding it again. + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. - - Done generating address + + Add new Subscription - - SOCKS5 Authentication problem: %1 + + Label + Label + + + + Subscriptions - - Disk full + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. + + Name or Label - - Error! Could not find sender address (your address) in the keys.dat file. + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - Doing work necessary to send broadcast... + + Use a Whitelist (Block all incoming messages except those on the Whitelist) - - Broadcast sent on %1 + + Blacklist - - Encryption key was requested earlier. + + Stream # - - Sending a request for the recipient's encryption key. + + Connections - - Looking up the receiver's public key + + Total connections: 0 - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 + + Since startup at asdf: - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. + + Processed 0 person-to-person message. - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 + + Processed 0 public key. - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 + + Processed 0 broadcast. - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 + + Network Status - - Doing work necessary to send message. + + File - - Message sent. Waiting for acknowledgement. Sent on %1 + + Settings + Settings + + + + Help + Help + + + + Import keys - - Doing work necessary to request encryption key. + + Manage keys - - Broadcasting the public key request. This program will auto-retry if they are offline. + + Ctrl+Q + Ctrrl+Q + + + + F1 - - Sending public key request. Waiting for reply. Requested at %1 + + About - - UPnP port mapping established on port %1 + + Regenerate deterministic addresses - - UPnP port mapping removed + + Delete all trashed messages - - Mark all messages as read + + Join / Create chan - - Are you sure you would like to mark all messages read? + + Set avatar... + + + + + Bad address version number + + + + + Your address version number must be a number: either 3 or 4. + + + + + Your address version number must be either 3 or 4. + + + + + Inventory lookups per second: %1 + + + + + Will not resend ever + + + + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + + + + + Do you really want to remove this avatar? + + + + + You have already set an avatar for this address. Do you really want to overwrite it? + + + + + Start-on-login not yet supported on your OS. + + + + + Minimize-to-tray not yet supported on your OS. + + + + + Tray notifications not yet supported on your OS. + + + + + Enter an address above. + + + + + Address is an old type. We cannot display its past broadcasts. + + + + + There are no recent broadcasts from this address to display. + + + + + Display the %1 recent broadcast from this address. + + + + + Display the %1 recent broadcasts from this address. + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + + Inventory lookups per second: 0 @@ -1304,9 +999,9 @@ T' 'Random Number' option be selected by default but deterministi Use yee random number generator to make an arrddress - - Use a passphrase to make addresses - + + Use a passpharase to make addresses + Use yee passpharase to make arrddresses @@ -1320,8 +1015,8 @@ T' 'Random Number' option be selected by default but deterministi - Address version number: 4 - + Address version number: 3 + Arrddress version number: 3 @@ -1378,6 +1073,16 @@ T' 'Random Number' option be selected by default but deterministi (saves you some bandwidth and processing power) (saves yee some bandwidth and processing powerrr) + + + Use a passphrase to make addresses + + + + + Address version number: 4 + Arrddress version number: 4 + NewSubscriptionDialog @@ -1398,7 +1103,7 @@ T' 'Random Number' option be selected by default but deterministi - Enter an address above. + CheckBox @@ -1430,78 +1135,36 @@ T' 'Random Number' option be selected by default but deterministi Name yee pseudo-mailing-list: - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - - About - - - - + PyBitmessage PyBitmessage - + version ? Version ? - + + About + + + + <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> - + This is Beta software. - - - blacklist - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Add yee new entry - - - - Name or Label - - - - - Address - Address - - - - Blacklist - - - - - Whitelist + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> @@ -1537,8 +1200,8 @@ T' 'Random Number' option be selected by default but deterministi - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> @@ -1559,9 +1222,9 @@ T' 'Random Number' option be selected by default but deterministi Sie haben keine Verbindung zu anderen Teilnehmern. - - 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. - + + 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 foward 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. + Yee have made least one connection to a peer pirate usin' outgoing connection but yee not yet received any incoming connections. Yee firewall, witches nest, or home router probably shant configured to foward incoming TCP connections to yee computer. Bitmessage be workin' just fine but it help fellow pirates if yee allowed for incoming connections and will help yee be a better-connected node matey. @@ -1573,134 +1236,11 @@ T' 'Random Number' option be selected by default but deterministi You do have connections with other peers and your firewall is correctly configured. Yee have connections with other peers and pirates,yee firewall is correctly configured. - - - networkstatus - - Total connections: + + 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. - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - newChanDialog @@ -1768,9 +1308,14 @@ T' 'Random Number' option be selected by default but deterministi Number of arrddresses to make based on yee passphrase: - - Address version number: - + + Address version Number: + Arrddress version Number: + + + + 3 + 3 @@ -1797,297 +1342,316 @@ T' 'Random Number' option be selected by default but deterministi If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. If yee have previously made deterministic arrddresses but yee lost them due to an accident (like losin' yee pirate ship), yee can regenerate them here. If yee used t' random number generator to make yee addresses then this form be of no use to you. + + + Address version number: + + settingsDialog - + Settings Settings - + Start Bitmessage on user login Start yee Bitmessage on userrr login - - Tray - - - - + Start Bitmessage in the tray (don't show main window) Start yee Bitmessage in t' tray (don't show main window) - + Minimize to tray Minimize to yee tray - - Close to tray - - - - + Show notification when message received Show yee a notification when message received - + Run in Portable Mode Run in yee Portable Mode - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. In Portable Mode, messages and config files are stored in t' same directory as yee program rather than t' normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive or wooden leg. - + + User Interface + User Interface + + + + Listening port + Listenin' port + + + + Listen for connections on port: + Listen for connections on yee port: + + + + Proxy server / Tor + Proxy server / Tor + + + + Type: + Type: + + + + none + none + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Server hostname: + + + + Port: + Port: + + + + Authentication + Authentication + + + + Username: + Username: + + + + Pass: + Pass: + + + + Network Settings + Network Settings + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + When a pirate sends yee a message, their computer must first complete a load of work. T' difficulty of t' work, by default, is 1. Yee may raise this default for new arrddresses yee create by changin' the values here. Any new arrddresses you be createin' will require senders to meet t' higher difficulty. There be one exception: if yee add a friend or pirate to yee arrddress book, Bitmessage be automatically notifyin' them when yee next send a message that they needin' be only complete t' minimum amount of work: difficulty 1. + + + + Total difficulty: + Total difficulty: + + + + Small message difficulty: + Small message difficulty: + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + T' 'Small message difficulty' mostly only affects t' difficulty of sending small messages. Doubling this value be makin' it almost twice as difficult to send a small message but doesn't really affect large messages. + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + T' 'Total difficulty' affects the absolute amount of work yee sender must complete. Doubling this value be doublin' t' amount of work. + + + + Demanded difficulty + Demanded difficulty + + + Willingly include unencrypted destination address when sending to a mobile device - + + Listen for incoming connections when using proxy + + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + + + + + Maximum acceptable total difficulty: + + + + + Maximum acceptable small message difficulty: + + + + + Max acceptable difficulty + + + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + + + + + Host: + + + + + Password: + + + + + Test + + + + + Connect to: + + + + + Namecoind + + + + + NMControl + + + + + Namecoin integration + + + + Use Identicons - - Reply below Quote - - - - + Interface Language - + System Settings system - - User Interface - User Interface - - - - Listening port - Listenin' port - - - - Listen for connections on port: - Listen for connections on yee port: - - - - UPnP: + + English + en - - Bandwidth limit + + Esperanto + eo - - Maximum download rate (kB/s): [0: unlimited] + + Français + fr - - Maximum upload rate (kB/s): [0: unlimited] + + Deutsch + de - - Proxy server / Tor - Proxy server / Tor - - - - Type: - Type: - - - - Server hostname: - Server hostname: - - - - Port: - Port: - - - - Authentication - Authentication - - - - Username: - Username: - - - - Pass: - Pass: - - - - Listen for incoming connections when using proxy + + Españl + es - - none - none - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Network Settings - - - - Total difficulty: - Total difficulty: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - T' 'Total difficulty' affects the absolute amount of work yee sender must complete. Doubling this value be doublin' t' amount of work. - - - - Small message difficulty: - Small message difficulty: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - When a pirate sends yee a message, their computer must first complete a load of work. T' difficulty of t' work, by default, is 1. Yee may raise this default for new arrddresses yee create by changin' the values here. Any new arrddresses you be createin' will require senders to meet t' higher difficulty. There be one exception: if yee add a friend or pirate to yee arrddress book, Bitmessage be automatically notifyin' them when yee next send a message that they needin' be only complete t' minimum amount of work: difficulty 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - T' 'Small message difficulty' mostly only affects t' difficulty of sending small messages. Doubling this value be makin' it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - Demanded difficulty - Demanded difficulty - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + + русский язык + ru - - Maximum acceptable total difficulty: + + Norsk + no - - Maximum acceptable small message difficulty: + + Pirate English + en_pirate - - Max acceptable difficulty + + Other (set in keys.dat) + other - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - - - - - Password: - - - - - Test - - - - - Connect to: - - - - - Namecoind - - - - - NMControl - - - - - Namecoin integration - - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - + Give up after - + and - + days - + months. - + Resends Expire diff --git a/src/translations/bitmessage_eo.pro b/src/translations/bitmessage_eo.pro new file mode 100644 index 00000000..1e9492cd --- /dev/null +++ b/src/translations/bitmessage_eo.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.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\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_eo.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index ea03b1b5..cfa0a6dc 100644 Binary files a/src/translations/bitmessage_eo.qm and b/src/translations/bitmessage_eo.qm differ diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index beff4aca..2f09691d 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -1,1884 +1,1267 @@ - + + AddAddressDialog - + Add new entry - Aldoni novan elementon + Aldoni novan elementon - + Label - Etikedo + Etikedo - + Address - Adreso - - - - EmailGatewayDialog - - - Email gateway - Retpoŝta kluzo - - - - Register on email gateway - Registri ĉe retpoŝta kluzo - - - - Account status at email gateway - Stato de retpoŝt-kluza konto - - - - Change account settings at email gateway - Ŝanĝu agordojn de konto ĉe retpoŝta kluzo - - - - Unregister from email gateway - Malregistri de retpoŝta kluzo - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Retpoŝta kluzo ebligas al vi komunikadi kun retpoŝtaj uzantoj. Nuntempe, nur la retpoŝta kluzo de Mailchuck (@mailchuck.com) estas disponebla. - - - - Desired email address (including @mailchuck.com): - Dezirata retpoŝta adreso (kune kun @mailchuck.com): - - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - Registrado malsukcesis: - - - - The requested email address is not available, please try a new one. - La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. - - - - Sending email gateway registration request - Sendado de peto pri registrado ĉe retpoŝta kluzo - - - - Sending email gateway unregistration request - Sendado de peto pri malregistrado de retpoŝta kluzo - - - - Sending email gateway status request - Sendado de peto pri stato de retpoŝta kluzo - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Tie ĉi vi povas agordi vian konton ĉe retpoŝta kluzo -# Malkomenti agordojn kiujn vi volas uzi -# Jenaj agordoj: -# -# pgp: server -# La retpoŝta kluzo kreos kaj prizorgos PGP-ŝlosilojn por vi por subskribi, -# verigi, ĉifri kaj deĉifri kiel vi. Se vi volas uzi PGP-on, sed vi estas laca, -# uzu tion. Postulas abonon. -# -# pgp: local -# La retpoŝta kluzo ne faros PGP-operaciojn kiel vi. Vi povas aŭ ne uzi PGP-on -# ĝenerale aŭ uzi ĝin loke. -# -# attachments: yes -# Alvenaj kunsendaĵoj en retmesaĝoj estos alŝutitaj al MEGA.nz, kaj vi povos -# elŝuti ilin de tie per alklaki ligilon. Postulas abonon. -# -# attachments: no -# Kunsendaĵoj estos ignorataj. -# -# archive: yes -# Viaj alvenontaj retmesaĝoj estos arĥivitaj en la servilo. Uzu tion, se vi -# bezonas helpon kun senerarigado aŭ vi bezonas eksterliveritan pruvon de -# retmesaĝoj. Tamen tio signifas, ke la manipulisto de servo eblos legi viajn -# retmesaĝojn eĉ kiam, tiam oni estos liverinta ilin al vi. -# -# archive: no -# Alvenaj mesaĝoj estos forigitaj de la servilo tuj post ili estos liveritaj al vi. -# -# masterpubkey_btc: BIP44 xpub ŝlosilo aŭ electrum v1 publika fontsendo (seed) -# offset_btc: entjera (integer) datumtipo (implicite 0) -# feeamount: nombro kun maksimume 8 decimalaj lokoj -# feecurrency: BTC, XBT, USD, EUR aŭ GBP -# Uzu tiujn se vi volas pagoŝarĝi homojn kiuj sendos al vi retmesaĝojn. Se tiu -# agordo estas ŝaltita kaj iu ajn sendos al vi retmesaĝon, li devos pagi difinan -# sendokoston. Por remalaktivigi ĝin, agordu ‘feeamount’ al 0. Postulas abonon. - + Adreso MainWindow - - Reply to sender - Respondi al sendinto + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + Iu de viaj adresoj, %1, estas malnova versio 1 adreso. Ĉu ni povas forviŝi ĝin? - - Reply to channel - Respondi al kanalo + + Reply + Respondi - + Add sender to your Address Book Aldoni sendinton al via adresaro - - Add sender to your Blacklist - Aldoni sendinton al via nigra listo - - - + Move to Trash Movi al rubujo - - Undelete - Malforigi - - - + View HTML code as formatted text - Montri HTML-n kiel aranĝitan tekston + Montri HTML-n kiel aranĝita teksto - + Save message as... - Konservi mesaĝon kiel… + Konservi mesaĝon kiel... - - Mark Unread - Marki kiel nelegitan - - - + New Nova - + Enable Ŝalti - + Disable Malŝalti - - Set avatar... - Agordi avataron… - - - + Copy address to clipboard Kopii adreson al tondejo - + Special address behavior... - Speciala sinteno de adreso… + Speciala sinteno de adreso... - - Email gateway - Retpoŝta kluzo - - - - Delete - Forigi - - - + Send message to this address Sendi mesaĝon al tiu adreso - + Subscribe to this address Aboni tiun adreson - + Add New Address Aldoni novan adreson - + + Delete + Forviŝi + + + Copy destination address to clipboard Kopii cel-adreson al tondejo - + Force send Devigi sendadon - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Iu de viaj adresoj, %1, estas malnova versio 1 adreso. Versioj 1 adresoj ne estas jam subtenataj. Ĉu ni povas forigi ĝin? - - - - Waiting for their encryption key. Will request it again soon. - Atendado je ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. - - - - Encryption key request queued. - - - - - Queued. - En atendovico. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - - - - Message sent. Sent at %1 - Mesaĝo sendita. Sendita je %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - Ricevis konfirmon de la mesaĝo je %1 - - - - Broadcast queued. - Elsendo en atendovico. - - - - Broadcast on %1 - Elsendo je %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problemo: la demandita laboro de la ricevonto estas pli malfacila ol vi pretas fari. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problemo: la ĉifroŝlosilo de la ricevonto estas rompita. Ne povis ĉifri la mesaĝon. %1 - - - - Forced difficulty override. Send should start soon. - Devigita superado de limito de malfacilaĵo. Sendado devus baldaŭ komenci. - - - - Unknown status: %1 %2 - Nekonata stato: %1 %2 - - - - Not Connected - Ne konektita - - - - Show Bitmessage - Montri Bitmesaĝon - - - - Send - Sendi - - - - Subscribe - Aboni - - - - Channel - Kanalo - - - - Quit - Eliri - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava, ke vi faru sekurkopion de tiu dosiero. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la dosierujo -%1. -Estas grava, ke vi faru sekurkopion de tiu dosiero. - - - - Open keys.dat? - Ĉu malfermi keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Vi povas administri viajn ŝlosilojn per redakti la dosieron keys.dat en la dosierujo -%1. -Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) - - - - Delete trash? - Ĉu malplenigi rubujon? - - - - Are you sure you want to delete all trashed messages? - Ĉu vi certe volas forviŝi ĉiujn mesaĝojn el la rubujo? - - - - bad passphrase - malprava pasvorto - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Vi devas tajpi vian pasvorton. Se vi ne havas pasvorton, tiu ĉi ne estas la prava formularo por vi. - - - - Bad address version number - Erara numero de adresversio - - - - Your address version number must be a number: either 3 or 4. - Via numero de adresversio devas esti: aŭ 3 aŭ 4. - - - - Your address version number must be either 3 or 4. - Via numero de adresversio devas esti: aŭ 3 aŭ 4. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Perdis konekton - - - - Connected - Konektita - - - - Message trashed - Movis mesaĝon al rubujo - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - La vivdaŭro signifas ĝis kiam la reto tenos la mesaĝon. La ricevonto devos elŝuti ĝin dum tiu tempo. Se via bitmesaĝa kliento ne ricevos konfirmon, ĝi resendos mesaĝon aŭtomate. Ju pli longa vivdaŭro, des pli laboron via komputilo bezonos fari por sendi mesaĝon. Vivdaŭro proksimume kvin aŭ kvar horoj estas ofte konvena. - - - - Message too long - Mesaĝo tro longa - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - La mesaĝon kiun vi provis sendi estas tro longa je %1 bitokoj. (La maksimumo estas 261644 bitokoj.) Bonvolu mallongigi ĝin antaŭ sendado. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Eraro: Via konto ne estas registrita je retpoŝta kluzo. Registranta nun kiel %1, bonvolu atendi ĝis la registrado finos antaŭ vi reprovos sendi iun ajn. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Eraro: Vi devas elekti sendontan adreson. Se vi ne havas iun, iru al langeto 'Viaj identigoj'. - - - - Address version number - Numero de adresversio - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Dum prilaborado de adreso adreso %1, Bitmesaĝo ne povas kompreni numerojn %2 de adresversioj. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. - - - - Stream number - Fluo numero - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Dum prilaborado de adreso %1, Bitmesaĝo ne povas priservi %2 fluojn numerojn. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Atentu: Vi ne estas nun konektita. Bitmesaĝo faros necesan laboron por sendi mesaĝon, tamen ĝi ne sendos ĝin antaŭ vi konektos. - - - - Message queued. - Mesaĝo envicigita. - - - - Your 'To' field is empty. - Via "Ricevonto"-kampo malplenas. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Dekstre alklaku kelka(j)n elemento(j)n en via adresaro kaj elektu 'Sendi mesaĝon al tiu adreso'. - - - - Fetched address from namecoin identity. - Venigis adreson de namecoin-a identigo. - - - - New Message - Nova mesaĝo - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - Adreso estas ĝusta. - - - - The address you entered was invalid. Ignoring it. - La adreso kiun vi enmetis estas malĝusta. Ignoras ĝin. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Eraro: Vi ne povas duoble aldoni la saman adreson al via adresaro. Provu renomi la ekzistan se vi volas. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Eraro: Vi ne povas aldoni duoble la saman adreson al viaj abonoj. Eble renomi la ekzistan se vi volas. - - - - Restart - Restartigi - - - - You must restart Bitmessage for the port number change to take effect. - Vi devas restartigi Bitmesaĝon por ke la ŝanĝo de la numero de pordo (Port Number) efektivigu. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmesaĝo uzos retperanton (proxy) ekde nun, sed eble vi volas permane restartigi Bitmesaĝon nun, por ke ĝi fermu eblajn ekzistajn konektojn. - - - - Number needed - Numero bezonata - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Maksimumaj elŝutrapido kaj alŝutrapido devas esti numeroj. Ignoras kion vi enmetis. - - - - Will not resend ever - Resendos neniam - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Rigardu, ke la templimon vi enmetis estas pli malgrandan ol tempo dum kiu Bitmesaĝo atendas por resendi unuafoje, do viaj mesaĝoj estos senditaj neniam. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Pasfrazoj malsamas - - - - The passphrase you entered twice doesn't match. Try again. - Entajpitaj pasfrazoj malsamas. Provu denove. - - - - Choose a passphrase - Elektu pasfrazon - - - - You really do need a passphrase. - Vi ja vere bezonas pasfrazon. - - - - Address is gone - Adreso foriris - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmesaĝo ne povas trovi vian adreson %1. Ĉu eble vi forviŝis ĝin? - - - - Address disabled - Adreso malŝaltita - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Eraro: La adreso kun kiu vi provas sendi estas malŝaltita. Vi devos ĝin ŝalti en la langeto 'Viaj identigoj' antaŭ uzi ĝin. - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - Aldonis elementon al la nigra listo. Redaktu la etikedon laŭvole. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Eraro: Vi ne povas duoble aldoni la saman adreson al via nigra listo. Provu renomi la jaman se vi volas. - - - - Moved items to trash. - Movis elementojn al rubujo. - - - - Undeleted item. - Malforigis elementon. - - - - Save As... - Konservi kiel… - - - - Write error. - Skriberaro. - - - - No addresses selected. - Neniu adreso elektita. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Se vi forigos abonon, mesaĝojn kiujn vi jam ricevis, igos neatingeblajn. Eble vi devus anstataŭ malaktivigi abonon. Malaktivaj abonoj ne ricevos novajn mesaĝojn, tamen vi plu povos legi mesaĝojn kiujn ci jam ricevis. - -Ĉu vi certe volas forigi la abonon? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Se vi forigos kanalon, mesaĝojn kiujn vi jam ricevis, igos neatingeblajn. Eble vi devus anstataŭ malaktivigi kanalon. Malaktivaj kanaloj ne ricevos novajn mesaĝojn, tamen vi plu povos legi mesaĝojn kiujn ci jam ricevis. - -Ĉu vi certe volas forigi la kanalon? - - - - Do you really want to remove this avatar? - Ĉu vi certe volas forviŝi tiun ĉi avataron? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Vi jam agordis avataron por tiu ĉi adreso. Ĉu vi vere volas superskribi ĝin? - - - - Start-on-login not yet supported on your OS. - Starto-dum-ensaluto ne estas ankoraŭ ebla en via operaciumo. - - - - Minimize-to-tray not yet supported on your OS. - Plejetigo al taskopleto ne estas ankoraŭ ebla en via operaciumo. - - - - Tray notifications not yet supported on your OS. - Taskopletaj sciigoj ne estas ankoraŭ eblaj en via operaciumo. - - - - Testing... - Testado… - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - La adreso komencu kun “BM-” - - - - The address is not typed or copied correctly (the checksum failed). - La adreso ne estis ĝuste tajpita aŭ kopiita (kontrolsumo malsukcesis). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - La numero de adresversio estas pli alta ol tiu, kiun la programo poveblas subteni. Bonvolu ĝisdatigi Bitmesaĝon. - - - - The address contains invalid characters. - La adreso enhavas malpermesitajn simbolojn. - - - - Some data encoded in the address is too short. - Iuj datumoj koditaj en la adreso estas tro mallongaj. - - - - Some data encoded in the address is too long. - Iuj datumoj koditaj en la adreso estas tro longaj. - - - - Some data encoded in the address is malformed. - Iuj datumoj koditaj en la adreso estas misformitaj. - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - Malnova tipo de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. - - - - There are no recent broadcasts from this address to display. - Neniaj lastatempaj elsendoj de tiu ĉi adreso por montri. - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmesaĝo - - - - Identities - Identigoj - - - - New Identity - Nova identigo - - - - Search - Serĉi - - - - All - Ĉio - - - - To - Al - - - - From - De - - - - Subject - Temo - - - - Message - Mesaĝo - - - - Received - Ricevita je - - - - Messages - Mesaĝoj - - - - Address book - Etikedo - - - - Address - Adreso - - - - Add Contact - Aldoni kontakton - - - - Fetch Namecoin ID - Venigi Namecoin ID - - - - Subject: - Temo: - - - - From: - De: - - - - To: - Al: - - - - Send ordinary Message - Sendi ordinaran mesaĝon - - - - Send Message to your Subscribers - Sendi mesaĝon al viaj abonantoj - - - - TTL: - Vivdaŭro: - - - - Subscriptions - Abonoj - - - - Add new Subscription - Aldoni novan abonon - - - - Chans - Kanaloj - - - - Add Chan - Aldoni kanalon - - - - File - Dosiero - - - - Settings - Agordoj - - - - Help - Helpo - - - - Import keys - Enporti ŝlosilojn - - - - Manage keys - Administri ŝlosilojn - - - - Ctrl+Q - Stir+Q - - - - F1 - F1 - - - - Contact support - Peti pri helpo - - - - About - Pri - - - - Regenerate deterministic addresses - Regeneri antaŭkalkuleblan adreson - - - - Delete all trashed messages - Forviŝi ĉiujn mesaĝojn el rubujo - - - - Join / Create chan - Aniĝi / Krei kanalon - - - - All accounts - Ĉiuj kontoj - - - - Zoom level %1% - Pligrandigo: %1 - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Eraro: Vi ne povas aldoni duoble la saman adreson al via listo. Eble renomi la jaman se vi volas. - - - + Add new entry Aldoni novan elementon - - Display the %1 recent broadcast(s) from this address. - Montri %1 lasta(j)n elsendo(j)n de tiu ĉi adreso. + + Waiting for their encryption key. Will request it again soon. + mi ne certas kiel traduki "their" ĉi tie. Sonas strange al mi. + Atendante al ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - La nova versio de PyBitmessage estas disponebla: %1. Elŝutu ĝin de https://github.com/Bitmessage/PyBitmessage/releases/latest + + Encryption key request queued. + Peto por ĉifroŝlosilo envicigita. - - Waiting for PoW to finish... %1% - Atendado ĝis laborpruvo finiĝos… %1% + + Queued. + En atendovico. - - Shutting down Pybitmessage... %1% - Fermado de PyBitmessage… %1% + + Message sent. Waiting for acknowledgement. Sent at %1 + Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - - Waiting for objects to be sent... %1% - Atendado ĝis objektoj estos senditaj… %1% + + Need to do work to send message. Work is queued. + Devas labori por sendi mesaĝon. Laboro en atendovico. - - Saving settings... %1% - Konservado de agordoj… %1% + + Acknowledgement of the message received %1 + Ricevis konfirmon de la mesaĝo je %1 - - Shutting down core... %1% - Fermado de kerno… %1% + + Broadcast queued. + Elsendo en atendovico. + + + + Broadcast on %1 + Elsendo je %1 + + + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + Problemo: la demandita laboro de la ricevonto estas pli malfacila ol vi pretas fari. %1 + + + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + Problemo: la ĉifroŝlosilo de la ricevonto estas rompita. Ne povis ĉifri la mesaĝon. %1 + + + + Forced difficulty override. Send should start soon. + Devigita superado de limito de malfacilaĵo. Sendado devus baldaŭ komenci. + + + + Unknown status: %1 %2 + Nekonata stato: %1 %2 + + + + Since startup on %1 + Ekde lanĉo de la programo je %1 + + + + Not Connected + Ne konektita + + + + Show Bitmessage + Montri Bitmesaĝon + + + + Send + Sendi + + + + Subscribe + Aboni + + + + Address Book + Adresaro + + + + Quit + Eliri + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. + Vi povas administri viajn ŝlosilojn redaktante la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava ke vi faru savkopion de tiu dosiero. + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. + Vi povas administri viajn ŝlosilojn redaktante la dosieron keys.dat en la dosierujo +%1. +Estas grava ke vi faru savkopion de tiu dosiero. + + + + Open keys.dat? + Ĉu malfermi keys.dat? + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Vi povas administri viajn ŝlosilojn redaktante la dosieron keys.dat en la sama dosierujo kiel tiu programo. Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Vi povas administri viajn ŝlosilojn redaktante la dosieron keys.dat en la dosierujo +%1. +Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosieron nun? (Bonvolu certigi ke Bitmesaĝo estas fermita antaŭ fari ŝanĝojn.) + + + + Delete trash? + Malplenigi rubujon? + + + + Are you sure you want to delete all trashed messages? + Ĉu vi certas ke vi volas forviŝi ĉiujn mesaĝojn el la rubojo? + + + + bad passphrase + malprava pasvorto + + + + You must type your passphrase. If you don't have one then this is not the form for you. + Vi devas tajpi vian pasvorton. Se vi ne havas pasvorton tiu ne estas la prava formularo por vi. + + + + Processed %1 person-to-person messages. + Pritraktis %1 inter-personajn mesaĝojn. + + + + Processed %1 broadcast messages. + Pritraktis %1 elsendojn. + + + + Processed %1 public keys. + Pritraktis %1 publikajn ŝlosilojn. + + + + Total Connections: %1 + Totalaj Konektoj: %1 + + + + Connection lost + Perdis konekton + + + + Connected + Konektita + + + + Message trashed + Movis mesaĝon al rubujo + + + + Error: Bitmessage addresses start with BM- Please check %1 + Eraro: en Bitmesaĝa adresoj komencas kun BM- Bonvolu kontroli %1 + + + + Error: The address %1 is not typed or copied correctly. Please check it. + Eraro: La adreso %1 ne estis prave tajpita aŭ kopiita. Bonvolu kontroli ĝin. + + + + Error: The address %1 contains invalid characters. Please check it. + Eraro: La adreso %1 enhavas malpermesitajn simbolojn. Bonvolu kontroli ĝin. + + + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + Eraro: La adres-versio %1 estas tro alta. Eble vi devas promocii vian Bitmesaĝo programon aŭ via konato uzas alian programon. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + Eraro: Kelkaj datumoj kodita en la adreso %1 estas tro mallongaj. Povus esti ke io en la programo de via konato malfunkcias. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + Eraro: Kelkaj datumoj kodita en la adreso %1 estas tro longaj. Povus esti ke io en la programo de via konato malfunkcias. + + + + Error: Something is wrong with the address %1. + Eraro: Io malĝustas kun la adreso %1. + + + + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + Eraro: Vi devas elekti sendontan adreson. Se vi ne havas iun, iru al langeto "Viaj identigoj". + + + + Sending to your address + Sendante al via adreso + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + Eraro: Unu el la adresoj al kiuj vi sendas mesaĝon (%1) apartenas al vi. Bedaŭrinde, la kliento de Bitmesaĝo ne povas pritrakti siajn proprajn mesaĝojn. Bonvolu uzi duan klienton ĉe alia komputilo aŭ en virtuala maŝino (VM). + + + + Address version number + Numero de adresversio + + + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + + + + + Stream number + Fluo numero + + + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + + + + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + + + + + Your 'To' field is empty. + Via "Ricevonto"-kampo malplenas. + + + + Work is queued. + Laboro en atendovico. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + + + + + Work is queued. %1 + Laboro en atendovico. %1 + + + + New Message + Nova mesaĝo + + + + From + De + + + + Address is valid. + Adreso estas ĝusta. + + + + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + Eraro: Vi ne povas duoble aldoni la saman adreson al via adresaro. Provu renomi la jaman se vi volas. + + + + The address you entered was invalid. Ignoring it. + La adreso kiun vi enmetis estas malĝusta. Ignoras ĝin. - Stopping notifications... %1% - Haltigado de sciigoj… %1% + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Eraro: Vi ne povas duoble aboni la saman adreson. Provu renomi la jaman se vi volas. - - Shutdown imminent... %1% - Fermado tuj… %1% - - - - %n hour(s) - %n horo%n horoj - - - - %n day(s) - %n tago%n tagoj + + Restart + Restartigi - - Shutting down PyBitmessage... %1% - Fermado de PyBitmessage… %1% + + You must restart Bitmessage for the port number change to take effect. + Vi devas restartigi Bitmesaĝon por ke la ŝanĝo de la numero de pordo (Port Number) efektivigu. - + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage wird den Proxy-Server ab jetzt verwenden, möglicherweise möchten Sie Bitmessage neu starten um bestehende Verbindungen zu schließen. + + + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + + + + + Passphrase mismatch + Pasfrazoj malsamas + + + + The passphrase you entered twice doesn't match. Try again. + La pasfrazo kiun vi duoble enmetis malsamas. Provu denove. + + + + Choose a passphrase + Elektu pasfrazon + + + + You really do need a passphrase. + Vi ja vere bezonas pasfrazon. + + + + All done. Closing user interface... + Ĉiu preta. Fermante fasadon... + + + + Address is gone + Adreso foriris + + + + Bitmessage cannot find your address %1. Perhaps you removed it? + Bitmesaĝo ne povas trovi vian adreson %1. Ĉu eble vi forviŝis ĝin? + + + + Address disabled + Adreso malŝaltita + + + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + Eraro: La adreso kun kiu vi provas sendi estas malŝaltita. Vi devos ĝin ŝalti en la langeto 'Viaj identigoj' antaŭ uzi ĝin. + + + + Entry added to the Address Book. Edit the label to your liking. + Aldonis elementon al adresaro. Redaktu la etikedo laŭvole. + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Movis elementojn al rubujo. Ne estas fasado por rigardi vian rubujon, sed ankoraŭ estas sur disko se vi esperas ĝin retrovi. + + + + Save As... + Konservi kiel... + + + + Write error. + Skriberaro. + + + + No addresses selected. + Neniu adreso elektita. + + + + The address should start with ''BM-'' + La adreso komencu kun "BM-" + + + + The address is not typed or copied correctly (the checksum failed). + La adreso ne estis prave tajpita aŭ kopiita (kontrolsumo malsukcesis). + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + + + + + The address contains invalid characters. + La adreso enhavas malpermesitajn simbolojn. + + + + Some data encoded in the address is too short. + Kelkaj datumoj kodita en la adreso estas tro mallongaj. + + + + Some data encoded in the address is too long. + Kelkaj datumoj kodita en la adreso estas tro longaj. + + + + You are using TCP port %1. (This can be changed in the settings). + Vi estas uzanta TCP pordo %1 (Tio estas ŝanĝebla en la agordoj). + + + + Bitmessage + Bitmesaĝo + + + + To + Al + + + + From + De + + + + Subject + Temo + + + + Received + Ricevita + + + + Inbox + Ricevujo + + + + Load from Address book + Ŝarĝi el adresaro + + + + Message: + Mesaĝo: + + + + Subject: + Temo: + + + + Send to one or more specific people + Sendi al unu aŭ pli specifaj personoj + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + To: + Al: + + + + From: + De: + + + + Broadcast to everyone who is subscribed to your address + Elsendi al ĉiu kiu subskribis al via adreso + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Sciu ke elsendoj estas sole ĉifrita kun via adreso. Iu ajn povas legi ĝin se tiu scias vian adreson. + + + + Status + Stato + + + Sent - Senditaj + Sendita - - Generating one new address - Kreado de unu nova adreso + + Label (not shown to anyone) + Etikdeo (ne montrita al iu ajn) - - Done generating address. Doing work necessary to broadcast it... - Adreso kreita. Kalkulado de laborpruvo, kiu endas por elsendi ĝin… + + Address + Adreso - - Generating %1 new addresses. - Kreado de %1 novaj adresoj. + + Stream + Fluo - - %1 is already in 'Your Identities'. Not adding it again. - %1 jam estas en ‘Viaj Identigoj’. Ĝi ne estos aldonita ree. + + Your Identities + Via identigoj - - Done generating address - Ĉiuj adresoj estas kreitaj + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Ĉi tie vi povas aboni "elsendajn mesaĝojn" elsendita de aliaj uzantoj. Adresoj ĉi tie transpasas tiujn sur la langeto "Nigara listo". - - SOCKS5 Authentication problem: %1 - + + Add new Subscription + Aldoni novan Abonon - - Disk full - Disko plenplena + + Label + Etikedo - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. + + Subscriptions + Abonoj - - Error! Could not find sender address (your address) in the keys.dat file. - Eraro! Ne povas trovi adreson de sendanto (vian adreson) en la dosiero keys.dat. + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + La Adresaro estas utila por aldoni nomojn aŭ etikedojn al la Bitmesaĝa adresoj de aliaj persono por ke vi povu rekoni ilin pli facile en via ricevujo. Vi povas aldoni elementojn ĉi tie uzante la butonon 'Aldoni', aŭ en la ricevujo per dekstra klako al mesaĝo. - - Doing work necessary to send broadcast... - Kalkulado de laborpruvo, kiu endas por sendi elsendon… + + Name or Label + Nomo aŭ Etikedo - - Broadcast sent on %1 - Elsendo sendita je %1 + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Uzi Nigran Liston (permesi ĉiujn alvenintajn mesaĝojn escepte tiuj en la Nigra Listo) - + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Uzi Blankan Liston (bloki ĉiujn alvenintajn mesaĝojn escepte tiuj en la Blanka Listo) + + + + Blacklist + Nigra Listo + + + + Stream # + Fluo # + + + + Connections + Konetkoj + + + + Total connections: 0 + Totalaj konektoj: 0 + + + + Since startup at asdf: + Ekde lanĉo de la programo je asdf: + + + + Processed 0 person-to-person message. + Pritraktis 0 inter-personajn mesaĝojn. + + + + Processed 0 public key. + Pritraktis 0 publikajn ŝlosilojn. + + + + Processed 0 broadcast. + Pritraktis 0 elsendojn. + + + + Network Status + Reta Stato + + + + File + Dosiero + + + + Settings + Agordoj + + + + Help + Helpo + + + + Import keys + Importi ŝlosilojn + + + + Manage keys + Administri ŝlosilojn + + + + About + Pri + + + + Regenerate deterministic addresses + Regeneri determinisman adreson + + + + Delete all trashed messages + Forviŝi ĉiujn mesaĝojn el rubujo + + + + Message sent. Sent at %1 + Mesaĝo sendita. Sendita je %1 + + + + Chan name needed + Bezonas nomon de kanalo + + + + You didn't enter a chan name. + Vi ne enmetis nonon de kanalo. + + + + Address already present + Adreso jam ĉi tie + + + + Could not add chan because it appears to already be one of your identities. + Ne povis aldoni kanalon ĉar ŝajne jam estas unu el viaj indentigoj. + + + + Success + Sukceso + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + Sukcese kreis kanalon. Por ebligi al aliaj aniĝi vian kanalon, sciigu al ili la nomon de la kanalo kaj ties Bitmesaĝa adreso: %1. Tiu adreso ankaŭ aperas en 'Viaj identigoj'. + + + + Address too new + Adreso tro nova + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + Kvankam tiu Bitmesaĝa adreso povus esti ĝusta, ĝia versionumero estas tro nova por pritrakti ĝin. Eble vi devas promocii vian Bitmesaĝon. + + + + Address invalid + Adreso estas malĝusta + + + + That Bitmessage address is not valid. + Tiu Bitmesaĝa adreso ne estas ĝusta. + + + + Address does not match chan name + Adreso ne kongruas kun kanalonomo + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + Kvankam la Bitmesaĝa adreso kiun vi enigis estas ĝusta, ĝi ne kongruas kun la kanalonomo. + + + + Successfully joined chan. + Sukcese aniĝis al kanalo. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + Bitmesaĝo uzos vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn konektojn. + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + Tio estas kanaladreso. Vi ne povas ĝin uzi kiel pseŭdo-dissendolisto. + + + + Search + Serĉi + + + + All + Ĉio + + + + Message + Mesaĝo + + + + Join / Create chan + Aniĝi / Krei kanalon + + + Encryption key was requested earlier. - Peto pri ĉifroŝlosilo jam sendita. + Verschlüsselungscode wurde bereits angefragt. - + Sending a request for the recipient's encryption key. - Sendado de peto pri ĉifroŝlosilo de ricevonto. + Sende eine Anfrage für den Verschlüsselungscode des Empfängers. - - Looking up the receiver's public key - Serĉado de publika ĉifroŝlosilo de ricevonto - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Eraro: celadreso estas portebla aparato kiu necesas, ke la celadreso estu enhavita en la mesaĝo, sed tio estas malpermesita ne viaj agordoj. %1 - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Kalkulado de laborpruvo, kiu endas por sendi mesaĝon. -Malfacilaĵo ne estas bezonata por adresoj versioj 2, kiel tiu ĉi adreso. - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Kalkulado de laborpruvo, kiu endas por sendi mesaĝon. -Ricevonto postulas malfacilaĵon: %1 kaj %2 - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Eraro: la demandita laboro de la ricevonto (%1 kaj %2) estas pli malfacila ol vi pretas fari. %3 - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Eraro: Vi provis sendi mesaĝon al vi mem aŭ al kanalo, tamen via ĉifroŝlosilo ne estas trovebla en la dosiero keys.dat. Mesaĝo ne povis esti ĉifrita. %1 - - - - Doing work necessary to send message. - Kalkulado de laborpruvo, kiu endas por sendi mesaĝon. - - - - Message sent. Waiting for acknowledgement. Sent on %1 - Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - - - + Doing work necessary to request encryption key. - Kalkulado de laborpruvo, kiu endas por peti pri ĉifroŝlosilo. + Verrichte die benötigte Arbeit um den Verschlüsselungscode anzufragen. - - Broadcasting the public key request. This program will auto-retry if they are offline. - Elsendado de peto pri publika ĉifroŝlosilo. La programo reprovos se ili estas eksterrete. + + Broacasting the public key request. This program will auto-retry if they are offline. + Anfrage für den Verschlüsselungscode versendet (wird automatisch periodisch neu verschickt). - + Sending public key request. Waiting for reply. Requested at %1 - Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 + Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - - UPnP port mapping established on port %1 - UPnP pord-mapigo farita je pordo %1 + + Mark Unread + Marki nelegita - - UPnP port mapping removed - UPnP pord-mapigo forigita + + Fetched address from namecoin identity. + Venigis adreson de Namecoin identigo. - - Mark all messages as read - Marki ĉiujn mesaĝojn kiel legitajn + + Testing... + Testante... - - Are you sure you would like to mark all messages read? - Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? + + Fetch Namecoin ID + Venigu Namecoin ID - - Doing work necessary to send broadcast. - Kalkulado de laborpruvo, kiu endas por sendi elsendon. + + Ctrl+Q + Stir+Q - - Proof of work pending - Laborpruvo haltigita - - - - %n object(s) pending proof of work - Haltigis laborpruvon por %n objektoHaltigis laborpruvon por %n objektoj - - - - %n object(s) waiting to be distributed - %n objekto atendas je sendato%n objektoj atendas je sendato + + F1 + F1 - - Wait until these tasks finish? - Ĉu atendi ĝis tiujn taskojn finos? + + Set avatar... + - - Problem communicating with proxy: %1. Please check your network settings. - Eraro dum komunikado kun retperanto: %1. Bonvolu kontroli viajn retajn agordojn. + + Bad address version number + - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. + + Your address version number must be a number: either 3 or 4. + - - The time on your computer, %1, may be wrong. Please verify your settings. - La horloĝo de via komputilo, %1, eble eraras. Bonvolu kontroli viajn agordojn. + + Your address version number must be either 3 or 4. + - - The name %1 was not found. - La nomo %1 ne trovita. + + Inventory lookups per second: %1 + - - The namecoin query failed (%1) - La namecoin-peto fiaskis (%1) + + Will not resend ever + - - The namecoin query failed. - La namecoin-peto fiaskis. + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + - - The name %1 has no valid JSON data. - La nomo %1 ne havas ĝustajn JSON-datumojn. + + Do you really want to remove this avatar? + - - The name %1 has no associated Bitmessage address. - La nomo %1 ne estas atribuita kun bitmesaĝa adreso. + + You have already set an avatar for this address. Do you really want to overwrite it? + - - Success! Namecoind version %1 running. - Sukceso! Namecoind versio %1 funkcias. + + Start-on-login not yet supported on your OS. + - - Success! NMControll is up and running. - Sukceso! NMControl funkcias ĝuste. + + Minimize-to-tray not yet supported on your OS. + - - Couldn't understand NMControl. - Ne povis kompreni NMControl. + + Tray notifications not yet supported on your OS. + - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. + + Enter an address above. + - - Set notification sound... - Agordi sciigan sonon… + + Address is an old type. We cannot display its past broadcasts. + - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Bonvenon al facila kaj sekura Bitmesaĝo -* sendi mesaĝojn al aliaj homoj -* sendi elsendajn mesaĝojn (kiel per Tvitero) -* babili kun aliaj uloj en mesaĝ-kanaloj + + There are no recent broadcasts from this address to display. + - - not recommended for chans - malkonsilinda por kanaloj + + Display the %1 recent broadcast from this address. + - - Quiet Mode - Silenta reĝimo + + Display the %1 recent broadcasts from this address. + - - Problems connecting? Try enabling UPnP in the Network Settings - Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Vi provas sendi retmesaĝon anstataŭ bitmesaĝ-mesaĝon. Tio ĉi postulas registri ĉe retpoŝta kluzo. Ĉu provi registri? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Eraro: bitmesaĝaj adresoj komenciĝas kun BM-. Bonvolu kontroli la adreson de ricevonto %1 - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Eraro: la adreso de ricevonto %1 estas malprave tajpita aŭ kopiita. Bonvolu kontroli ĝin. - - - - Error: The recipient address %1 contains invalid characters. Please check it. - Eraro: la adreso de ricevonto %1 enhavas malpermesatajn simbolojn. Bonvolu kontroli ĝin. - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Eraro: la versio de adreso de ricevonto %1 estas tro alta. Eble vi devas ĝisdatigi vian bitmesaĝan programon aŭ via sagaca konato uzas alian programon. - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas tro mallongaj. Povus esti ke io en la programo de via konato malfunkcias. - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas tro longaj. Povus esti ke io en la programo de via konato malfunkcias. - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Eraro: kelkaj datumoj koditaj en la adreso de ricevonto %1 estas misformitaj. Povus esti ke io en la programo de via konato malfunkcias. - - - - Error: Something is wrong with the recipient address %1. - Eraro: io malĝustas kun la adreso de ricevonto %1. - - - - Error: %1 - Eraro: %1 - - - - From %1 - De %1 - - - - Synchronisation pending - Samtempigado haltigita - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmesaĝo ne estas samtempigita kun la reto, %n objekto elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis la samtempigado finiĝos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis la samtempigado finiĝos? - - - - Not connected - Nekonektita - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmesaĝo ne estas konektita al la reto. Se vi eliros nun, tio povas igi malfruiĝojn de liveradoj. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finiĝos? - - - - Waiting for network connection... - Atendado je retkonekto… - - - - Waiting for finishing synchronisation... - Atendado ĝis samtempigado finiĝos… - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - Vi jam agordis sciigan sonon por tiu ĉi adreso. Ĉu vi volas anstataŭigi ĝin? - - - - Go online - Konekti - - - - Go offline - Malkonekti - - - - MessageView - - - Follow external link - Sekvi la eksteran ligilon - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - La ligilo "%1" estos malfermita per foliumilo. Tio povas esti malsekura, ĝi povos malanonimigi vin aŭ elŝuti malicajn datumojn. Ĉu vi certas? - - - - HTML detected, click here to display - HTML detektita, alklaku ĉi tie por montri - - - - Click here to disable HTML - Alklaku ĉi tie por malaktivigi HTML - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - La mesaĝo enhavas nekonatan kodoprezenton. -Eble vi devas ĝisdatigi Bitmesaĝon. - - - - Unknown encoding - Nekonata kodoprezento + + Inventory lookups per second: 0 + NewAddressDialog - + Create new Address - Krei novan adreson + Krei novan Adreson - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Tie ĉi vi povas generi tiom da adresoj, kiom vi volas. Ververe krei kaj forlasi adresojn estas konsilinda. Vi povas krei adresojn uzante hazardajn nombrojn aŭ pasfrazon. Se vi uzos pasfrazon, la adreso estas nomita kiel “antaŭkalkulebla” (determinisma) adreso. -La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj havas kelkajn bonaĵojn kaj malbonaĵojn: + - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Bonaĵoj:<br/></span>Vi poveblas rekrei viajn adresojn per iu ajn komputilo elkape.<br/>Vi ne devas klopodi fari sekurkopion de la dosiero keys.dat tiel longe, dum vi memoras vian pasfrazon.<br/><span style=" font-weight:600;">Malbonaĵoj:<br/></span>Vi devas memori (aŭ konservi) vian pasfrazon se vi volas rekrei viajn ŝlosilojn kiam vi perdos ilin.<br/>Vi devas memori nombron de adresversio kaj de fluo kune kun vian pasfrazon.<br/>Se vi elektos malfortan pasfrazon kaj iu ajn Interrete eblos brutforti ĝin, li povos legi ĉiujn viajn mesaĝojn kaj sendi mesaĝojn kiel vi.</p></body></html> + - + Use a random number generator to make an address - Uzi hazardnombran generilon por krei adreson + - + Use a passphrase to make addresses - Uzi pasfrazon por krei adreson + - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Pasigi kelkajn minutojn aldone kompute por krei adreso(j)n mallongaj je 1 aŭ 2 signoj + - + Make deterministic addresses - Fari antaŭkalkuleblan adreson + - - Address version number: 4 - Numero de adresversio: 4 - - - + In addition to your passphrase, you must remember these numbers: - Kune kun vian pasfrazon vi devas memori jenajn numerojn: + - + Passphrase - Pasfrazo + Pasfrazo - + Number of addresses to make based on your passphrase: - Nombro da farotaj adresoj bazante sur via pasfrazo: + Kvanto de farotaj adresoj bazante sur via pasfrazo: - + Stream number: 1 - Numero de fluo: 1 + - + Retype passphrase - Pasfrazo ree + - + Randomly generate address - Hazardnombra adreso + - + Label (not shown to anyone except you) - Etikedo (ne montrata al iu ajn escepte de vi) + - + Use the most available stream - Uzi la plej disponeblan fluon + - + (best if this is the first of many addresses you will create) - (plej bone se ĝi estas la unua de ĉiuj adresojn vi kreos) + - + Use the same stream as an existing address - Uzi la saman fluon kiel ekzistan adreson + - + (saves you some bandwidth and processing power) - (konservas iomete da ret-trafiko kaj komput-povo) + + + + + Address version number: 4 + NewSubscriptionDialog - + Add new entry - Aldoni novan elementon + Aldoni novan elementon - + Label - Etikedo + Etikedo - + Address - Adreso + Adreso - - Enter an address above. - Entajpu adreson supre. + + CheckBox + SpecialAddressBehaviorDialog - + Special Address Behavior - Speciala sinteno de adreso + - + Behave as a normal address - Sintenadi kiel normala adreso + - + Behave as a pseudo-mailing-list address - Sintenadi kiel kvazaŭ-elsendlista adreso + - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Mesaĝoj alvenintaj al kvazaŭ-dissendlisto estos aŭtomate dissenditaj al abonantoj (do ili estos publikaj). + - + Name of the pseudo-mailing-list: - Nomo de kvazaŭ-dissendlisto: - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. + aboutDialog - + About Pri - + PyBitmessage - + PyBitmessage - + version ? - + Veriso ? - - - <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> - <html><head/><body><p>Distribuata laŭ la permesilo “MIT/X11 software license”; legu <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> - - - - This is Beta software. - Tio ĉi estas beta-eldono. + + + Copyright © 2013 Jonathan Warren + Kopirajto © 2013 Jonathan Warren - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Kopirajto © 2012-2016 Jonathan WARREN<br/>Kopirajto © 2013-2017 La Programistoj de Bitmesaĝo</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Uzi nigran liston (permesas ĉiujn alvenajn mesaĝojn escepte tiujn en la nigra listo) + <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> + <html><head/><body><p>Distribuita sub la permesilo "MIT/X11 software license"; vidu <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> - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Uzi blankan liston (blokas ĉiujn alvenajn mesaĝojn escepte tiujn en la blanka listo) + + This is Beta software. + Tio estas beta-eldono. - - Add new entry - Aldoni novan elementon - - - - Name or Label - Nomo aŭ etikedo - - - - Address - Adreso - - - - Blacklist - Nigra listo - - - - Whitelist - Blanka listo + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + connectDialog - + Bitmessage Bitmesaĝo - + Bitmessage won't connect to anyone until you let it. - Bitmesaĝo ne konektos antaŭ vi permesos al ĝi. + Bitmesaĝo ne konektos antaŭ vi permesas al ĝi. - + Connect now - Konekti nun + Kenekti nun - + Let me configure special network settings first - Ebligi al mi unue alĝustigi specialajn agordojn de reto - - - - Work offline - Funkcii eksterrete + Lasu min unue fari specialajn retajn agordojn helpDialog - + Help Helpo - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help (angle)</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Ĉar Bitmesaĝo estas kunlabora projekto, vi povas trovi helpon enrete ĉe la vikio de Bitmesaĝo: @@ -1886,671 +1269,448 @@ La “hazardnombra” adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj iconGlossaryDialog - + Icon Glossary Piktograma Glosaro - + You have no connections with other peers. - Vi havas neniujn konektojn al aliaj samtavolanoj. + Vi havas neniun konekton al aliaj samtavolano. - + 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. - Vi konektis almenaŭ al unu samtavolano uzante elirantan konekton, sed vi ankoraŭ ne ricevis enirantajn konektojn. Via fajroŝirmilo (firewall) aŭ hejma enkursigilo (router) verŝajne estas agordita por ne plusendi enirantajn TCP-konektojn al via komputilo. Bitmesaĝo funkcios sufiĉe bone, sed helpus al la bitmesaĝa reto se vi permesus enirantajn konektojn kaj tiel estus pli bone konektita nodo. + Vi konektis almenaŭ al unu smtavolano uzante eliranta konekto, sed vi ankoraŭ ne ricevis enirantajn konetkojn. Via fajroŝirmilo (firewall) aŭ hejma enkursigilo (router) verŝajne estas agordita ne plusendi enirantajn TCP konektojn al via komputilo. Bitmesaĝo funkcios sufiĉe bone sed helpus al la Bitmesaĝa reto se vi permesus enirantajn konektojn kaj tiel estus pli bone konektita nodo. You are using TCP port ?. (This can be changed in the settings). - + Vi estas uzanta TCP pordo ?. (Tio estas ŝanĝebla en la agordoj). - + You do have connections with other peers and your firewall is correctly configured. Vi havas konektojn al aliaj samtavolanoj kaj via fajroŝirmilo estas ĝuste agordita. - - - You are using TCP port %1. (This can be changed in the settings). - Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). - - - - networkstatus - - - Total connections: - Ĉiuj konektoj: - - - - Since startup: - Ekde starto: - - - - Processed 0 person-to-person messages. - Pritraktis 0 inter-personajn mesaĝojn. - - - - Processed 0 public keys. - Pritraktis 0 publikajn ŝlosilojn. - - - - Processed 0 broadcasts. - Pritraktis 0 elsendojn. - - - - Inventory lookups per second: 0 - Petoj pri inventaro en sekundo: 0 - - - - Objects to be synced: - Samtempigotaj eroj: - - - - Stream # - Fluo # - - - - Connections - - - - - Since startup on %1 - Ekde lanĉo de la programo je %1 - - - - Down: %1/s Total: %2 - Elŝuto: %1/s Sume: %2 - - - - Up: %1/s Total: %2 - Alŝuto: %1/s Sume: %2 - - - - Total Connections: %1 - Ĉiuj konektoj: %1 - - - - Inventory lookups per second: %1 - Petoj pri inventaro en sekundo: %1 - - - - Up: 0 kB/s - Alŝuto: 0 kB/s - - - - Down: 0 kB/s - Elŝuto: 0 kB/s - - - - Network Status - Reta stato - - - - byte(s) - bitokobitokoj - - - - Object(s) to be synced: %n - Objekto por samtempigi: %nObjektoj por samtempigi: %n - - - - Processed %n person-to-person message(s). - Pritraktis %n inter-personan mesaĝon.Pritraktis %n inter-personajn mesaĝojn. - - - - Processed %n broadcast message(s). - Pritraktis %n elsendon.Pritraktis %n elsendojn. - - - - Processed %n public key(s). - Pritraktis %n publikan ŝlosilon.Pritraktis %n publikajn ŝlosilojn. - - - - Peer - Samtavolano - - - - IP address or hostname - IP-adreso aŭ gastiga nomo - - - - Rating - Takso - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage registras frekvencon de sukcesaj konekt-provoj al aliaj nodoj. Takso varias de -1 ĝis 1 kaj influas probablon por elekti nodon estontece. - - - - User agent - Klienta aplikaĵo - - - - Peer's self-reported software - Anoncata klienta aplikaĵo - - - - TLS - TLS - - - - Connection encryption - Konekta ĉifrado - - - - List of streams negotiated between you and the peer - Listo de interŝanĝataj fluoj inter vi kaj la samtavolano - newChanDialog Dialog - + Dialogo Create a new chan - + Krei novan kanalon Join a chan - + Aniĝi al kanalo Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + Krei kanalon Chan name: - + Nomo de kanalo: <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + <html><head/><body><p>Kanalo ekzistas kiam grupo de personoj havas komunajn malĉifrajn ŝlosilojn. La ŝlosiloj kaj Bitmesaĝa adreso uzita de kanalo estas generita el homlegebla vorto aŭ frazo (la nomo de la kanalo). Por sendi mesaĝon al ĉiu en la kanalo, sendu normalan person-al-persona mesaĝon al la adreso de la kanalo.</p><p>Kanaloj estas eksperimentaj kaj tute malkontroleblaj.</p></body></html> Chan bitmessage address: - + Bitmesaĝa adreso de kanalo: - - Create or join a chan - Krei aŭ aniĝi kanalon - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Kanalo ekzistas kiam grupo da personoj kunhavas la komunajn malĉifrajn ŝlosilojn. La ŝlosiloj kaj bitmesaĝa adreso uzataj de kanalo estas generitaj el hom-legebla vorto aŭ frazo (la kanala nomo). Por sendi mesaĝon al ĉiuj en la kanalo, sendu mesaĝon al la kanala adreso.</p><p>Kanaloj estas eksperimentaj kaj tute neadministreblaj.</p><p>Entajpu nomon por via kanalo. Se vi elektos sufiĉe ampleksan kanalan nomon (kiel fortan kaj unikan pasfrazon) kaj neniu de viaj amikoj komunikos ĝin publike, la kanalo estos sekura kaj privata. Tamen se vi kaj iu ajn kreos kanalon kun la sama nomo, tiam ili iĝos tre verŝajne la saman kanalon.</p></body></html> - - - - Chan passphrase/name: - Kanala pasfrazo/nomo: - - - - Optional, for advanced usage - Malnepra, por sperta uzado - - - - Chan address - Kanala adreso - - - - Please input chan name/passphrase: - Bonvolu entajpu kanalan nomon/pasfrazon: - - - - newchandialog - - - Successfully created / joined chan %1 - Sukcese kreis / aniĝis al la kanalo %1 - - - - Chan creation / joining failed - Kreado / aniĝado al kanalo malsukcesis - - - - Chan creation / joining cancelled - Kreado / aniĝado al kanalo nuligita - - - - proofofwork - - - C PoW module built successfully. - C PoW modulo konstruita sukcese. - - - - Failed to build C PoW module. Please build it manually. - Malsukcesis konstrui C PoW modulon. Bonvolu konstrui ĝin permane. - - - - C PoW module unavailable. Please build it. - C PoW modulo nedisponebla. Bonvolu konstrui ĝin. - - - - qrcodeDialog - - - QR-code - QR-kodo + + <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> + <html><head/><body><p>Enmetu nomon por via kanalo. Se vi elektas sufiĉe ampleksan kanalnomon (kiel fortan kaj unikan pasfrazon) kaj neniu el viaj amikoj komunikas ĝin publike la kanalo estos sekura kaj privata. Se vi kaj iu ajn kreas kanalon kun la sama nomo tiam en la momento estas tre verŝajne ke estos la sama kanalo.</p></body></html> regenerateAddressesDialog - + Regenerate Existing Addresses Regeneri ekzistantajn adresojn - + Regenerate existing addresses - Regeneri ekzistantajn adresojn + Regeneri ekzistantajn Adresojn - + Passphrase Pasfrazo - + Number of addresses to make based on your passphrase: - Nombro da farotaj adresoj bazante sur via pasfrazo: + Kvanto de farotaj adresoj bazante sur via pasfrazo: - - Address version number: - Numero de adresversio: + + Address version Number: + Adresa versio numero: - + + 3 + 3 + + + Stream number: - Numero de fluo: + Fluo numero: - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Pasigi kelkajn minutojn aldone kompute por krei adreso(j)n mallongaj je 1 aŭ 2 signoj + Elspezi kelkajn minutojn per aldona tempo de komputila kalkulado por fari adreso(j)n 1 aŭ 2 simbolojn pli mallonge - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Vi devas marki (aŭ ne marki) tiun ĉi mark-butonon samkiel vi faris kiam vi generis vian adresojn unuafoje. + Vi devas marki (aŭ ne marki) tiun markobutono samkiel vi faris kiam vi generis vian adreson la unuan fojon. - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Se vi antaŭe kreis antaŭkalkuleblajn (determinismajn) adresojn sed perdis ilin akcidente (ekz. en diska paneo), vi povas regeneri ilin tie ĉi. Se vi uzis la hazardnombran generilon por krei viajn adresojn, tiu ĉi formularo ne taŭgos por vi. + Se vi antaŭe kreis determinismajn adresojn sed perdis ĝin akcidente (ekz. en diska paneo), vi povas regeneri ilin ĉi tie. Se vi uzis la generilo de hazardaj numeroj por krei vian adreson tiu formularo ne taŭgos por vi. + + + + Address version number: + settingsDialog - + Settings - Agordoj + Agordoj - + Start Bitmessage on user login - Startigi Bitmesaĝon dum ensaluto de uzanto + Startigi Bitmesaĝon dum ensaluto de uzanto - - Tray - Taskopleto - - - + Start Bitmessage in the tray (don't show main window) - Startigi Bitmesaĝon en la taskopleto (tray) ne montrante tiun fenestron + Startigi Bitmesaĝon en la taskopleto (tray) ne montrante tiun fenestron - + Minimize to tray - Plejetigi al taskopleto + Plejetigi al taskopleto - - Close to tray - Fermi al taskopleto - - - + Show notification when message received - Montri sciigon kiam mesaĝo alvenas + Montri sciigon kiam mesaĝo alvenas - + Run in Portable Mode - Ekzekucii en Portebla Reĝimo + Ekzekucii en Portebla Reĝimo - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - En Portebla Reĝimo, mesaĝoj kaj agordoj estas enmemorigitaj en la sama dosierujo kiel la programo mem anstataŭ en la dosierujo por datumoj de aplikaĵoj. Tio igas ĝin komforta ekzekucii Bitmesaĝon el USB poŝmemorilo. + En Portebla Reĝimo, mesaĝoj kaj agordoj estas enmemorigitaj en la sama dosierujo kiel la programo mem anstataŭ en la dosierujo por datumoj de aplikaĵoj. Tio igas ĝin komforta ekzekucii Bitmesaĝon el USB poŝmemorilo. - + + User Interface + Fasado + + + + Listening port + Aŭskultanta pordo (port) + + + + Listen for connections on port: + Aŭskultu pri konektoj ĉe pordo: + + + + Proxy server / Tor + Prokurila (proxy) servilo / Tor + + + + Type: + Tipo: + + + + none + Neniu + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Servilo gastiga nomo (hostname): + + + + Port: + Pordo (port): + + + + Authentication + Aŭtentigo + + + + Username: + Uzantnomo: + + + + Pass: + Pas: + + + + Network Settings + Retaj agordoj + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + + + + + Total difficulty: + + + + + Small message difficulty: + + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + + + + + Demanded difficulty + + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + + + + + Maximum acceptable total difficulty: + + + + + Maximum acceptable small message difficulty: + + + + + Max acceptable difficulty + + + + + Listen for incoming connections when using proxy + + + + Willingly include unencrypted destination address when sending to a mobile device - Volonte inkluzivi malĉifritan cel-adreson dum sendado al portebla aparato. + - + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + + + + + Host: + Gastiga servilo: + + + + Password: + Pasvorto: + + + + Test + Testo + + + + Connect to: + Kenekti al: + + + + Namecoind + Namecoind + + + + NMControl + NMControl + + + + Namecoin integration + Integrigo de Namecoin + + + + Override automatic language localization (use countycode or language code, e.g. 'en_US' or 'en'): + Transpasi la automatan reconon de locala lingvo (uzu landokodon aŭ lingvokodon, ekz. 'en_US' aŭ 'en'): + + + Use Identicons - Uzi ID-avatarojn + - - Reply below Quote - Respondi sub citaĵo - - - + Interface Language - Fasada lingvo + - + System Settings system - Sistemaj agordoj + - - User Interface - Fasado + + English + en + - - Listening port - Aŭskultanta pordo (port) + + Esperanto + eo + - - Listen for connections on port: - Aŭskulti pri konektoj ĉe pordo: + + Français + fr + - - UPnP: - UPnP: + + Deutsch + de + - - Bandwidth limit - Rettrafika limo + + Españl + es + - - Maximum download rate (kB/s): [0: unlimited] - Maksimuma rapido de elŝuto (kB/s): [0: senlima] + + русский язык + ru + - - Maximum upload rate (kB/s): [0: unlimited] - Maksimuma rapido de alŝuto (kB/s): [0: senlima] + + Norsk + no + - - Proxy server / Tor - Retperanta (proxy) servilo / Tor + + Pirate English + en_pirate + - - Type: - Speco: + + Other (set in keys.dat) + other + - - Server hostname: - Servilo gastiga nomo (hostname): - - - - Port: - Pordo (port): - - - - Authentication - Aŭtentigo - - - - Username: - Uzantnomo: - - - - Pass: - Pasvorto: - - - - Listen for incoming connections when using proxy - Aŭskulti pri alvenaj konektoj kiam dum uzado de retperanto - - - - none - neniu - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Retaj agordoj - - - - Total difficulty: - Tuta malfacilaĵo: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - La 'Tuta malfacilaĵo' efikas sur la tuta kvalito da laboro, kiun la sendonto devos fari. Duobligo de tiu valoro, duobligas la kvanton de laboro. - - - - Small message difficulty: - Et-mesaĝa malfacilaĵo: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Kiam iu ajn sendas al vi mesaĝon, lia komputilo devas unue fari iom da laboro. La malfacilaĵo de tiu laboro implicite estas 1. Vi povas pligrandigi tiun valoron por novaj adresoj, kiujn vi generos per ŝanĝo de ĉi-tiaj valoroj. Ĉiuj novaj adresoj kreotaj de vi bezonos por ke sendontoj akceptu pli altan malfacilaĵon. Estas unu escepto: se vi aldonos kolegon al vi adresaro, Bitmesaĝo aŭtomate sciigos lin kiam vi sendos mesaĝon, ke li bezonos fari nur minimuman kvaliton da laboro: malfacilaĵo 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - La 'Et-mesaĝa malfacilaĵo' ĉefe efikas malfacilaĵon por sendi malgrandajn mesaĝojn. Duobligo de tiu valoro, preskaŭ duobligas malfacilaĵon por sendi malgrandajn mesaĝojn, sed preskaŭ ne efikas grandajn mesaĝojn. - - - - Demanded difficulty - Postulata malfacilaĵo - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Tie ĉi vi povas agordi maksimuman kvanton da laboro kiun vi faru por sendi mesaĝon al alian persono. Se vi agordos ilin al 0, ĉiuj valoroj estos akceptitaj. - - - - Maximum acceptable total difficulty: - Maksimuma akceptata tuta malfacilaĵo: - - - - Maximum acceptable small message difficulty: - Maksimuma akceptata malfacilaĵo por et-mesaĝoj: - - - - Max acceptable difficulty - Maksimuma akcepta malfacilaĵo - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmesaĝo povas apliki alian Bitmono-bazitan programon - Namecoin - por fari adresojn hom-legeblajn. Ekzemple anstataŭ diri al via amiko longan Bitmesaĝan adreson, vi povas simple peti lin pri sendi mesaĝon al <span style=" font-style:italic;">id/kashnomo. </span></p><p>(Kreado de sia propra Bitmesaĝa adreso en Namecoin-on estas ankoraŭ ete malfacila).</p><p>Bitmesaĝo eblas uzi aŭ na namecoind rekte aŭ jaman aktivan aperon de nmcontrol.</p></body></html> - - - - Host: - Gastiga servilo: - - - - Password: - Pasvorto: - - - - Test - Testi - - - - Connect to: - Konekti al: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Integrigo kun Namecoin - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Implicite se vi sendas mesaĝon al iu kaj li estos eksterrete por iomete da tempo, Bitmesaĝo provos resendi mesaĝon iam poste, kaj iam pli poste. La programo pluigos resendi mesaĝon ĝis sendonto konfirmos liveron. Tie ĉi vi povas ŝanĝi kiam Bitmesaĝo devos rezigni je sendado.</p><p>Lasu tiujn kampojn malplenaj por antaŭagordita sinteno.</p></body></html> + - + Give up after - Rezigni post + - + and - kaj + - + days - tagoj + - + months. - monatoj. + - + Resends Expire - Resenda fortempiĝo - - - - Hide connection notifications - Ne montri sciigojn pri konekto - - - - Maximum outbound connections: [0: none] - Maksimumo de eligaj konektoj: [0: senlima] - - - - Hardware GPU acceleration (OpenCL): - Aparatara GPU-a plirapidigo (OpenCL): + - \ No newline at end of file + diff --git a/src/translations/bitmessage_fr.pro b/src/translations/bitmessage_fr.pro new file mode 100644 index 00000000..0e56c016 --- /dev/null +++ b/src/translations/bitmessage_fr.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.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\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_fr.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 742e62d8..12247227 100644 Binary files a/src/translations/bitmessage_fr.qm and b/src/translations/bitmessage_fr.qm differ diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index 3e64d657..e32eb5ef 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -1,1565 +1,1106 @@ - + + AddAddressDialog Add new entry - Ajouter une nouvelle entrée + Ajouter une nouvelle entrée Label - Étiquette + Label Address - Adresse - - - - EmailGatewayDialog - - - Email gateway - Passerelle de courriel - - - - Register on email gateway - S’inscrire sur la passerelle de courriel - - - - Account status at email gateway - Statut du compte sur la passerelle de courriel - - - - Change account settings at email gateway - Changer les paramètres de compte sur la passerelle de courriel - - - - Unregister from email gateway - Se désabonner de la passerelle de courriel - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - La passerelle de courriel vous permet de communiquer avec des utilisateurs de courriel. Actuellement, seulement la passerelle de courriel de Mailchuck (@mailchuck.com) est disponible. - - - - Desired email address (including @mailchuck.com): - Adresse de courriel désirée (incluant @mailchuck.com) : - - - - EmailGatewayRegistrationDialog - - - Registration failed: - L’inscription a échoué : - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - L’adresse de courriel demandée n’est pas disponible, veuillez en essayer une nouvelle. Saisissez ci-dessous la nouvelle adresse de courriel désirée (incluant @mailchuck.com) : - - - - Email gateway registration - Inscription à la passerelle de courriel - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - La passerelle de courriel vous permet de communiquer avec des utilisateurs de courriels. Actuellement, seule la passerelle de courriel de Mailchuck (@mailchuck.com) est disponible. -Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Vous pouvez utiliser ceci pour configurer votre compte de passerelle de -# messagerie. -# Décommentez les paramètres que vous souhaitez utiliser. -# Les options se trouvent ci-dessous : -# -# pgp: server -# La passerelle de messagerie va créer et conserver pour vous les clefs PGP, -# et va signer, vérifier, chiffrer et déchiffrer en votre nom. Choisissez cela si -# vous voulez utilisez PGP mais que vous êtes paresseux. Exige une inscription. -# -# pgp: local -# La passerelle de messagerie ne va pas exécuter les commandes PGP en -# votre nom. Vous pouvez soit ne pas utiliser PGP du tout, soit l’utiliser -# localement. -# -# attachments: yes -# Les pièces-jointes reçues dans le courriel seront téléversées sur MEGA.nz, -# d’où vous pourrez les télécharger en cliquant sur le lien. Exige une -# inscription. -# -# attachments: no -# Les pièces jointes seront ignorées. -# -# archive: yes -# Les courriels que vous recevrez seront archivés sur le serveur. Utilisez -# ceci si vous avez besoin d’aide pour des problèmes de déboguage ou -# si vous avez besoin d’une preuve par un tiers des courriels. Cela signifie -# cependant que le fournisseur du service pourra lire vos courriels même -# après leur réception. -# -# archive: no -# Les courriels reçus seront supprimés du serveur dès qu’ils vous auront été -# transmis. -# -# masterpubkey_btc: clef xpub BIP44 ou graine publique electrum v1 -# offset_btc: entier (par défaut à 0) -# feeamount: nombre avec jusqu’à 8 décimales -# feecurrency: BTC, XBT, USD, EUR ou GBP -# Utilisez ceci si vous voulez faire payer ceux qui vous envoient des courriels. -# Si ceci est activé et qu’une personne inconnue vous envoie un courriel, il -# devra payer le tarif indiqué. Comme ce mécanisme emploie des clefs -# publiques déterministes, vous recevrez l’argent directement. Pour désactiver -# à nouveau ceci, réglez "feeamount" à 0. Exige une inscription. - + Adresse MainWindow - - Reply to sender - Répondre à l’expéditeur - - - - Reply to channel - Répondre au canal - - - - Add sender to your Address Book - Ajouter l’expéditeur au carnet d’adresses - - - - Add sender to your Blacklist - Ajouter l’expéditeur à votre liste noire - - - - Move to Trash - Envoyer à la Corbeille - - - - Undelete - Restaurer - - - - View HTML code as formatted text - Voir le code HTML comme du texte formaté - - - - Save message as... - Enregistrer le message sous… - - - - Mark Unread - Marquer comme non-lu - - - - New - Nouvelle - - - - Enable - Activer - - - - Disable - Désactiver - - - - Set avatar... - Configurer l’avatar - - - - Copy address to clipboard - Copier l’adresse dans le presse-papier - - - - Special address behavior... - Comportement spécial de l’adresse… - - - - Email gateway - Passerelle de courriel - - - - Delete - Effacer - - - - Send message to this address - Envoyer un message à cette adresse - - - - Subscribe to this address - S’abonner à cette adresse - - - - Add New Address - Ajouter une nouvelle adresse - - - - Copy destination address to clipboard - Copier l’adresse de destination dans le presse-papier - - - - Force send - Forcer l’envoi - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Une de vos adresses, %1, est une vieille adresse de la version 1. Les adresses de la version 1 ne sont plus supportées. Nous pourrions la supprimer maintenant? - - - - Waiting for their encryption key. Will request it again soon. - En attente de la clé de chiffrement. Une nouvelle requête sera bientôt lancée. - - - - Encryption key request queued. - - - - - Queued. - En attente. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Message envoyé. En attente de l’accusé de réception. Envoyé %1 - - - - Message sent. Sent at %1 - Message envoyé. Envoyé %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - Accusé de réception reçu %1 - - - - Broadcast queued. - Message de diffusion en attente. - - - - Broadcast on %1 - Message de diffusion du %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problème : Le travail demandé par le destinataire est plus difficile que ce que vous avez paramétré. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problème : la clé de chiffrement du destinataire n’est pas bonne. Il n’a pas été possible de chiffrer le message. %1 - - - - Forced difficulty override. Send should start soon. - Neutralisation forcée de la difficulté. L’envoi devrait bientôt commencer. - - - - Unknown status: %1 %2 - Statut inconnu : %1 %2 - - - - Not Connected - Déconnecté - - - - Show Bitmessage - Afficher Bitmessage - - - - Send - Envoyer - - - - Subscribe - S’abonner - - - - Channel - Canal - - - - Quit - Quitter - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le répertoire %1. -Il est important de faire des sauvegardes de ce fichier. - - - - Open keys.dat? - Ouvrir keys.dat ? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l’ouvrir maintenant ? (Assurez-vous de fermer Bitmessage avant d’effectuer des changements.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le répertoire %1. Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l’ouvrir maintenant? (Assurez-vous de fermer Bitmessage avant d’effectuer des changements.) - - - - Delete trash? - Supprimer la corbeille ? - - - - Are you sure you want to delete all trashed messages? - Êtes-vous sûr de vouloir supprimer tous les messages dans la corbeille ? - - - - bad passphrase - Mauvaise phrase secrète - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Vous devez taper votre phrase secrète. Si vous n’en avez pas, ce formulaire n’est pas pour vous. - - - - Bad address version number - Mauvais numéro de version d’adresse - - - - Your address version number must be a number: either 3 or 4. - Votre numéro de version d’adresse doit être un nombre : soit 3 soit 4. - - - - Your address version number must be either 3 or 4. - Votre numéro de version d’adresse doit être soit 3 soit 4. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Connexion perdue - - - - Connected - Connecté - - - - Message trashed - Message envoyé à la corbeille - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - Le TTL, ou Time-To-Live (temps à vivre) est la durée de temps durant laquelle le réseau va détenir le message. -Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne reçoit pas de confirmation de réception, il va le ré-envoyer automatiquement. Plus le Time-To-Live est long, plus grand est le travail que votre ordinateur doit effectuer pour envoyer le message. Un Time-To-Live de quatre ou cinq jours est souvent approprié. - - - - Message too long - Message trop long - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Le message que vous essayez d’envoyer est trop long de %1 octets (le maximum est 261644 octets). Veuillez le réduire avant de l’envoyer. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Erreur : votre compte n’a pas été inscrit à une passerelle de courrier électronique. Envoi de l’inscription maintenant en tant que %1, veuillez patienter tandis que l’inscription est en cours de traitement, avant de retenter l’envoi. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Erreur : Vous devez spécifier une adresse d’expéditeur. Si vous n’en avez pas, rendez-vous dans l’onglet 'Vos identités'. - - - - Address version number - Numéro de version de l’adresse - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Concernant l’adresse %1, Bitmessage ne peut pas comprendre les numéros de version de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - - - - Stream number - Numéro de flux - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Concernant l’adresse %1, Bitmessage ne peut pas supporter les nombres de flux de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Avertissement : Vous êtes actuellement déconnecté. Bitmessage fera le travail nécessaire pour envoyer le message mais il ne sera pas envoyé tant que vous ne vous connecterez pas. - - - - Message queued. - Message mis en file d’attente. - - - - Your 'To' field is empty. - Votre champ 'Vers' est vide. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Cliquez droit sur une ou plusieurs entrées dans votre carnet d’adresses et sélectionnez 'Envoyer un message à ces adresses'. - - - - Fetched address from namecoin identity. - Récupération avec succès de l’adresse de l’identité Namecoin. - - - - New Message - Nouveau message - - - - From - - - - - Sending email gateway registration request - Envoi de la demande d’inscription de la passerelle de courriel - - - - Address is valid. - L’adresse est valide. - - - - The address you entered was invalid. Ignoring it. - L’adresse que vous avez entrée est invalide. Adresse ignorée. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Erreur : Vous ne pouvez pas ajouter une adresse déjà présente dans votre carnet d’adresses. Essayez de renommer l’adresse existante. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Erreur : vous ne pouvez pas ajouter la même adresse deux fois à vos abonnements. Peut-être que vous pouvez renommer celle qui existe si vous le souhaitez. - - - - Restart - Redémarrer - - - - You must restart Bitmessage for the port number change to take effect. - Vous devez redémarrer Bitmessage pour que le changement de port prenne effet. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage utilisera votre proxy dorénavant, mais vous pouvez redémarrer manuellement Bitmessage maintenant afin de fermer des connexions existantes (si il y en existe). - - - - Number needed - Nombre requis - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Vos taux maximum de téléchargement et de téléversement doivent être des nombres. Ce que vous avez tapé est ignoré. - - - - Will not resend ever - Ne renverra jamais - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Notez que la limite de temps que vous avez entrée est plus courte que le temps d’attente respecté par Bitmessage avant le premier essai de renvoi, par conséquent votre message ne sera jamais renvoyé. - - - - Sending email gateway unregistration request - Envoi de la demande de désinscription de la passerelle de courriel - - - - Sending email gateway status request - Envoi à la passerelle de courriel d’une demande de statut - - - - Passphrase mismatch - Phrases secrètes différentes - - - - The passphrase you entered twice doesn't match. Try again. - Les phrases secrètes entrées sont différentes. Réessayez. - - - - Choose a passphrase - Choisissez une phrase secrète - - - - You really do need a passphrase. - Vous devez vraiment utiliser une phrase secrète. - - - - Address is gone - L’adresse a disparu - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage ne peut pas trouver votre adresse %1. Peut-être l’avez-vous supprimée? - - - - Address disabled - Adresse désactivée - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Erreur : L’adresse avec laquelle vous essayez de communiquer est désactivée. Vous devez d’abord l’activer dans l’onglet 'Vos identités' avant de l’utiliser. - - - - Entry added to the Address Book. Edit the label to your liking. - Entrée ajoutée au carnet d’adresse. Éditez l’étiquette à votre convenance. - - - - Entry added to the blacklist. Edit the label to your liking. - Entrée ajoutée à la liste noire. Éditez l’étiquette à votre convenance. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Erreur : vous ne pouvez pas ajouter la même adresse deux fois à votre liste noire. Essayez de renommer celle qui existe si vous le souhaitez. - - - - Moved items to trash. - Messages déplacés dans la corbeille. - - - - Undeleted item. - Articles restaurés. - - - - Save As... - Enregistrer sous… - - - - Write error. - Erreur d’écriture. - - - - No addresses selected. - Aucune adresse sélectionnée. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Si vous supprimez cet abonnement, les messages que vous avez déjà reçus deviendront inaccessibles. Peut-être que vous devriez considérez d’abord de désactiver l’abonnement. Les abonnements désactivés ne reçoivent pas de nouveaux messages, mais vous pouvez encore voir ceux que vous avez déjà reçus. - -Êtes-vous sur de vouloir supprimer cet abonnement ? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Si vous supprimez ce canal, les messages que vous avez déjà reçus deviendront inaccessibles. Peut-être que vous devriez considérez d’abord de désactiver le canal. Les canaux désactivés ne reçoivent pas de nouveaux messages, mais vous pouvez encore voir ceux que vous avez déjà reçus. - -Êtes-vous sûr de vouloir supprimer ce canal ? - - - - Do you really want to remove this avatar? - Voulez-vous vraiment enlever cet avatar ? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Vous avez déjà mis un avatar pour cette adresse. Voulez-vous vraiment l’écraser ? - - - - Start-on-login not yet supported on your OS. - Le démarrage dès l’ouverture de session n’est pas encore supporté sur votre OS. - - - - Minimize-to-tray not yet supported on your OS. - La minimisation en zone système n’est pas encore supportée sur votre OS. - - - - Tray notifications not yet supported on your OS. - Les notifications en zone système ne sont pas encore supportées sur votre OS. - - - - Testing... - Tester… - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Ceci est une adresse de canal. Vous ne pouvez pas l’utiliser en tant que pseudo liste de diffusion. - - - - The address should start with ''BM-'' - L’adresse devrait commencer avec "BM-" - - - - The address is not typed or copied correctly (the checksum failed). - L’adresse n’est pas correcte (la somme de contrôle a échoué). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Le numéro de version de cette adresse est supérieur à celui que le programme peut supporter. Veuiller mettre Bitmessage à jour. - - - - The address contains invalid characters. - L’adresse contient des caractères invalides. - - - - Some data encoded in the address is too short. - Certaines données encodées dans l’adresse sont trop courtes. - - - - Some data encoded in the address is too long. - Certaines données encodées dans l’adresse sont trop longues. - - - - Some data encoded in the address is malformed. - Quelques données codées dans l’adresse sont mal formées. - - - - Enter an address above. - Entrez ci-dessus une adresse. - - - - Address is an old type. We cannot display its past broadcasts. - L’adresse est d’ancien type. Nous ne pouvons pas montrer ses messages de diffusion passés. - - - - There are no recent broadcasts from this address to display. - Il n’y a aucun message de diffusion récent de cette adresse à afficher. - - - - You are using TCP port %1. (This can be changed in the settings). - Vous utilisez le port TCP %1. (Ceci peut être changé dans les paramètres). - - - + Bitmessage Bitmessage - - Identities - Identités - - - - New Identity - Nouvelle identité - - - - Search - Chercher - - - - All - Tous - - - + To Vers - + From De - + Subject Sujet - - Message - Message - - - + Received Reçu - - Messages - Messages + + Inbox + Boîte de réception - - Address book - Carnet d’adresses + + Load from Address book + Charger depuis carnet d'adresses - - Address - Adresse + + Message: + Message : - - Add Contact - Ajouter un contact - - - - Fetch Namecoin ID - Récupère l’ID Namecoin - - - + Subject: - Sujet : + Sujet : - - From: - De : + + Send to one or more specific people + Envoyer à une ou plusieurs personne(s) - + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + To: - Vers : + Vers : - - Send ordinary Message - Envoyer un message ordinaire + + From: + De : - - Send Message to your Subscribers - Envoyer un message à vos abonnés + + Broadcast to everyone who is subscribed to your address + Diffuser à chaque abonné de cette adresse - - TTL: - TTL : + + Send + Envoyer - - Subscriptions - Abonnements + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Gardez en tête que les diffusions sont seulement chiffrées avec votre adresse. Quiconque disposant de votre adresse peut les lire. - - Add new Subscription - Ajouter un nouvel abonnement + + Status + Statut - - Chans - Canaux - - - - Add Chan - Ajouter un canal - - - - File - Fichier - - - - Settings - Paramètres - - - - Help - Aide - - - - Import keys - Importer les clés - - - - Manage keys - Gérer les clés - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Contacter le support - - - - About - À propos - - - - Regenerate deterministic addresses - Regénérer les clés déterministes - - - - Delete all trashed messages - Supprimer tous les messages dans la corbeille - - - - Join / Create chan - Rejoindre / créer un canal - - - - All accounts - Tous les comptes - - - - Zoom level %1% - Niveau de zoom %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Erreur : vous ne pouvez pas ajouter la même adresse deux fois à votre liste. Vous pouvez peut-être, si vous le souhaitez, renommer celle qui existe déjà. - - - - Add new entry - Ajouter une nouvelle entrée - - - - Display the %1 recent broadcast(s) from this address. - Montre le(s) %1 plus récent(s) message(s) de diffusion issu(s) de cette adresse. - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - Une nouvelle version de PyBitmessage est disponible : %1. Veuillez la télécharger depuis https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - Waiting for PoW to finish... %1% - En attente de la fin de la PoW… %1% - - - - Shutting down Pybitmessage... %1% - Pybitmessage en cours d’arrêt… %1% - - - - Waiting for objects to be sent... %1% - En attente de l’envoi des objets… %1% - - - - Saving settings... %1% - Enregistrement des paramètres… %1% - - - - Shutting down core... %1% - Cœur en cours d’arrêt… %1% - - - - Stopping notifications... %1% - Arrêt des notifications… %1% - - - - Shutdown imminent... %1% - Arrêt imminent… %1% - - - - %n hour(s) - %n heure%n heures - - - - %n day(s) - %n jour%n jours - - - - Shutting down PyBitmessage... %1% - PyBitmessage en cours d’arrêt… %1% - - - + Sent Envoyé - - Generating one new address - Production d’une nouvelle adresse + + New + Nouveau - - Done generating address. Doing work necessary to broadcast it... - La production de l’adresse a été effectuée. Travail en cours afin de l’émettre… + + Label (not shown to anyone) + Label (seulement visible par vous) - - Generating %1 new addresses. - Production de %1 nouvelles adresses. + + Address + Adresse - - %1 is already in 'Your Identities'. Not adding it again. - %1 est déjà dans "Vos identités". Il ne sera pas ajouté de nouveau. + + Stream + Flux - - Done generating address - La production d’une adresse a été effectuée + + Your Identities + Vos identités - - SOCKS5 Authentication problem: %1 - + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Vous pouvez ici souscrire aux 'messages de diffusion' envoyés par d'autres utilisateurs. Les messages apparaîtront dans votre boîte de récption. Les adresses placées ici outrepassent la liste noire. - - Disk full - Disque plein + + Add new Subscription + Ajouter un nouvel abonnement - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Alerte : votre disque ou le volume de stockage de données est plein. Bitmessage va maintenant se fermer. + + Label + Label - - Error! Could not find sender address (your address) in the keys.dat file. - Erreur ! Il n’a pas été possible de trouver l’adresse d’expéditeur (votre adresse) dans le fichier keys.dat. + + Subscriptions + Abonnements - - Doing work necessary to send broadcast... - Travail en cours afin d’envoyer le message de diffusion… + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + Le carnet d'adresses est utile pour mettre un nom sur une adresse Bitmessage et ainsi faciliter la gestion de votre boîte de réception. Vous pouvez ajouter des entrées ici en utilisant le bouton 'Ajouter', ou depuis votre boîte de réception en faisant un clic-droit sur un message. - - Broadcast sent on %1 - Message de diffusion envoyé %1 + + Add new entry + Ajouter une nouvelle entrée - - Encryption key was requested earlier. - La clé de chiffrement a été demandée plus tôt. + + Name or Label + Nom ou Label - - Sending a request for the recipient's encryption key. - Envoi d’une demande de la clé de chiffrement du destinataire. + + Address Book + Carnet d'adresses - - Looking up the receiver's public key - Recherche de la clé publique du récepteur + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Utiliser une liste noire (autoriser tous les messages entrants exceptés ceux sur la liste noire) - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Problème : la destination est un dispositif mobile qui nécessite que la destination soit incluse dans le message mais ceci n’est pas autorisé dans vos paramètres. %1 + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Utiliser une liste blanche (refuser tous les messages entrants exceptés ceux sur la liste blanche) - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Travail en cours afin d’envoyer le message. -Il n’y a pas de difficulté requise pour les adresses version 2 comme celle-ci. + + Blacklist + Liste noire - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Travail en cours afin d’envoyer le message. -Difficulté requise du destinataire : %1 et %2 + + Stream Number + Numéro de flux - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Problème : Le travail demandé par le destinataire (%1 and %2) est plus difficile que ce que vous avez paramétré. %3 + + Number of Connections + Nombre de connexions - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Problème : Vous essayez d’envoyer un message à un canal ou à vous-même mais votre clef de chiffrement n’a pas été trouvée dans le fichier keys.dat. Le message ne peut pas être chiffré. %1 + + Total connections: 0 + Nombre de connexions total : 0 - - Doing work necessary to send message. - Travail en cours afin d’envoyer le message. + + Since startup at asdf: + Depuis le lancement à asdf : - - Message sent. Waiting for acknowledgement. Sent on %1 - Message envoyé. En attente de l’accusé de réception. Envoyé %1 + + Processed 0 person-to-person message. + 0 message de pair à pair traité. - - Doing work necessary to request encryption key. - Travail en cours afin d’obtenir la clé de chiffrement. + + Processed 0 public key. + 0 clé publique traitée. - - Broadcasting the public key request. This program will auto-retry if they are offline. - Diffusion de la demande de clef publique. Ce programme réessaiera automatiquement si ils sont déconnectés. + + Processed 0 broadcast. + 0 message de diffusion traité. - - Sending public key request. Waiting for reply. Requested at %1 - Envoi d’une demande de clef publique. En attente d’une réponse. Demandée à %1 + + Network Status + État du réseau - - UPnP port mapping established on port %1 - Transfert de port UPnP établi sur le port %1 + + File + Fichier - - UPnP port mapping removed - Transfert de port UPnP retiré + + Settings + Paramètres - - Mark all messages as read - Marquer tous les messages comme lus + + Help + Aide - - Are you sure you would like to mark all messages read? - Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? + + Import keys + Importer les clés - - Doing work necessary to send broadcast. - Travail en cours afin d’envoyer la diffusion. + + Manage keys + Gérer les clés - - Proof of work pending - En attente de preuve de fonctionnement - - - - %n object(s) pending proof of work - %n objet en attente de preuve de fonctionnement%n objet(s) en attente de preuve de fonctionnement - - - - %n object(s) waiting to be distributed - %n objet en attente d'être distribué%n objet(s) en attente d'être distribués + + Quit + Quitter - - Wait until these tasks finish? - Attendre jusqu'à ce que ces tâches se terminent ? + + About + À propos - - Problem communicating with proxy: %1. Please check your network settings. - Problème de communication avec le proxy : %1. Veuillez vérifier vos réglages réseau. + + Regenerate deterministic addresses + Regénérer les clés déterministes - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - Problème d’authentification SOCKS5 : %1. Veuillez vérifier vos réglages SOCKS5. + + Delete all trashed messages + Supprimer tous les messages dans la corbeille - - The time on your computer, %1, may be wrong. Please verify your settings. - L'heure sur votre ordinateur, %1, pourrait être faussse. Veuillez vérifier vos paramètres. + + Total Connections: %1 + Nombre total de connexions : %1 - - The name %1 was not found. - Le nom %1 n'a pas été trouvé. + + Not Connected + Déconnecté - - The namecoin query failed (%1) - La requête Namecoin a échouée (%1) + + Connected + Connecté - - The namecoin query failed. - La requête Namecoin a échouée. + + Show Bitmessage + Afficher Bitmessage - - The name %1 has no valid JSON data. - Le nom %1 n'a aucune donnée JSON valide. + + Subscribe + S'abonner - - The name %1 has no associated Bitmessage address. - Le nom %1 n'a aucune adresse Bitmessage d'associée. + + Processed %1 person-to-person messages. + %1 messages de pair à pair traités. - - Success! Namecoind version %1 running. - Succès ! Namecoind version %1 en cours d'exécution. + + Processed %1 broadcast messages. + %1 messages de diffusion traités. - - Success! NMControll is up and running. - Succès ! NMControll est debout et en cours d'exécution. + + Processed %1 public keys. + %1 clés publiques traitées. - - Couldn't understand NMControl. - Ne pouvait pas comprendre NMControl. + + Since startup on %1 + Depuis lancement le %1 - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Votre GPU(s) n'a pas calculé correctement, mettant OpenCL hors service. Veuillez remonter ceci aux développeurs s'il vous plaît. - - - - Set notification sound... - Mettre un son de notification ... - - - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Bienvenue dans le facile et sécurisé Bitmessage -* envoyer des messages à d'autres personnes -* envoyer des messages par diffusion (broadcast) à la manière de Twitter ou -* discuter dans des canaux (channels) avec d'autres personnes - + + Waiting for their encryption key. Will request it again soon. + En attente de la clé de chiffrement. Une nouvelle requête sera bientôt lancée. - not recommended for chans - pas recommandé pour les canaux + Encryption key request queued. + Demande de clé de chiffrement en attente. - - Problems connecting? Try enabling UPnP in the Network Settings - Des difficultés à se connecter ? Essayez de permettre UPnP dans les "Paramètres réseau" + + Queued. + En attente. - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Vous essayez d'envoyer un courrier électronique au lieu d'un bitmessage. Ceci exige votre inscription à une passerelle. Essayer de vous inscrire ? + + Need to do work to send message. Work is queued. + Travail nécessaire pour envoyer le message. Travail en attente. - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Erreur : Les adresses Bitmessage commencent par BM- Veuillez vérifier l'adresse du destinataire %1 + + Acknowledgement of the message received %1 + Accusé de réception reçu le %1 - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Erreur : L’adresse du destinataire %1 n’est pas correctement tapée ou recopiée. Veuillez la vérifier. + + Broadcast queued. + Message de diffusion en attente. - - Error: The recipient address %1 contains invalid characters. Please check it. - Erreur : L’adresse du destinataire %1 contient des caractères invalides. Veuillez la vérifier. + + Broadcast on %1 + Message de diffusion à %1 - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Erreur : la version de l’adresse destinataire %1 est trop élevée. Vous devez mettre à niveau votre logiciel Bitmessage ou alors celui de votre connaissance est plus intelligent. + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + Problème : Le travail demandé par le destinataire est plus difficile que ce que vous avez paramétré. %1 - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Erreur : quelques données codées dans l’adresse destinataire %1 sont trop courtes. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. + + Forced difficulty override. Send should start soon. + Neutralisation forcée de la difficulté. L'envoi devrait bientôt commencer. - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Erreur : quelques données codées dans l’adresse destinataire %1 sont trop longues. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. + + Message sent. Waiting for acknowledgement. Sent at %1 + Message envoyé. En attente de l'accusé de réception. Envoyé le %1 + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. + Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. + Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le répertoire + %1. +Il est important de faire des sauvegardes de ce fichier. + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le même répertoire que ce programme. Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'ouvrir maintenant ? (Assurez-vous de fermer Bitmessage avant d'effectuer des changements.) + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Vous pouvez éditer vos clés en éditant le fichier keys.dat stocké dans le répertoire + %1. +Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'ouvrir maintenant ? (Assurez-vous de fermer Bitmessage avant d'effectuer des changements.) + + + + Add sender to your Address Book + Ajouter l'expéditeur au carnet d'adresses + + + + Move to Trash + Envoyer à la Corbeille + + + + View HTML code as formatted text + Voir le code HTML comme du texte formaté + + + + Enable + Activer + + + + Disable + Désactiver + + + + Copy address to clipboard + Copier l'adresse dans le presse-papier + + + + Special address behavior... + Comportement spécial de l'adresse... + + + + Send message to this address + Envoyer un message à cette adresse + + + + Add New Address + Ajouter nouvelle adresse + + + + Delete + Supprimer + + + + Copy destination address to clipboard + Copier l'adresse de destination dans le presse-papier + + + + Force send + Forcer l'envoi + + + + Are you sure you want to delete all trashed messages? + Êtes-vous sûr de vouloir supprimer tous les messages dans la corbeille ? + + + + You must type your passphrase. If you don't have one then this is not the form for you. + Vous devez taper votre phrase secrète. Si vous n'en avez pas, ce formulaire n'est pas pour vous. + + + + Delete trash? + Supprimer la corbeille ? + + + + Open keys.dat? + Ouvrir keys.dat ? + + + + bad passphrase + Mauvaise phrase secrète + + + + Restart + Redémarrer + + + + You must restart Bitmessage for the port number change to take effect. + Vous devez redémarrer Bitmessage pour que le changement de port prenne effet. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage utilisera votre proxy à partir de maintenant mais il vous faudra redémarrer Bitmessage pour fermer les connexions existantes. + + + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + Erreur : Vous ne pouvez pas ajouter une adresse déjà présente dans votre liste. Essayez de renommer l'adresse existante. + + + + The address you entered was invalid. Ignoring it. + L'adresse que vous avez entrée est invalide. Adresse ignorée. + + + + Passphrase mismatch + Phrases secrètes différentes + + + + The passphrase you entered twice doesn't match. Try again. + Les phrases secrètes entrées sont différentes. Réessayez. + + + + Choose a passphrase + Choisissez une phrase secrète + + + + You really do need a passphrase. + Vous devez vraiment utiliser une phrase secrète. + + + + All done. Closing user interface... + Terminé. Fermeture de l'interface... + + + + Address is gone + L'adresse a disparu + + + + Bitmessage cannot find your address %1. Perhaps you removed it? + Bitmessage ne peut pas trouver votre adresse %1. Peut-être l'avez-vous supprimée ? + + + + Address disabled + Adresse désactivée + + + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + Erreur : L'adresse avec laquelle vous essayez de communiquer est désactivée. Vous devez d'abord l'activer dans l'onglet 'Vos identités' avant de l'utiliser. + + + + Entry added to the Address Book. Edit the label to your liking. + Entrée ajoutée au carnet d'adresses. Éditez le label selon votre souhait. + + + + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + Erreur : Vous ne pouvez pas ajouter une adresse déjà présente dans votre carnet d'adresses. Essayez de renommer l'adresse existante. + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Messages déplacés dans la corbeille. Il n'y a pas d'interface utilisateur pour voir votre corbeille, mais ils sont toujours présents sur le disque si vous souhaitez les récupérer. + + + + No addresses selected. + Aucune adresse sélectionnée. + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implimented for your operating system. + Certaines options ont été désactivées car elles n'étaient pas applicables ou car elles n'ont pas encore été implémentées pour votre système d'exploitation. + + + + The address should start with ''BM-'' + L'adresse devrait commencer avec "BM-" + + + + The address is not typed or copied correctly (the checksum failed). + L'adresse n'est pas correcte (la somme de contrôle a échoué). + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + Le numéro de version de cette adresse est supérieur à celui que le programme peut supporter. Veuiller mettre Bitmessage à jour. + + + + The address contains invalid characters. + L'adresse contient des caractères invalides. + + + + Some data encoded in the address is too short. + Certaines données encodées dans l'adresse sont trop courtes. + + + + Some data encoded in the address is too long. + Certaines données encodées dans l'adresse sont trop longues. + + + + Address is valid. + L'adresse est valide. + + + + You are using TCP port %1. (This can be changed in the settings). + Vous utilisez le port TCP %1. (Ceci peut être changé dans les paramètres). + + + + Error: Bitmessage addresses start with BM- Please check %1 + Erreur : Les adresses Bitmessage commencent avec BM- Merci de vérifier %1 + + + + Error: The address %1 contains invalid characters. Please check it. + Erreur : L'adresse %1 contient des caractères invalides. Veuillez la vérifier. + + + + Error: The address %1 is not typed or copied correctly. Please check it. + Erreur : L'adresse %1 n'est pas correctement recopiée. Veuillez la vérifier. + + + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + Erreur : La version de l'adresse %1 est trop grande. Pensez à mettre à jour Bitmessage. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + Erreur : Certaines données encodées dans l'adresse %1 sont trop courtes. Il peut y avoir un problème avec le logiciel ou votre connaissance. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + Erreur : Certaines données encodées dans l'adresse %1 sont trop longues. Il peut y avoir un problème avec le logiciel ou votre connaissance. + + + + Error: Something is wrong with the address %1. + Erreur : Problème avec l'adresse %1. - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Erreur : quelques données codées dans l’adresse destinataire %1 sont mal formées. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + Erreur : Vous devez spécifier une adresse d'expéditeur. Si vous n'en avez pas, rendez-vous dans l'onglet 'Vos identités'. - - Error: Something is wrong with the recipient address %1. - Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. + + Sending to your address + Envoi vers votre adresse - - From %1 - De %1 + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + Erreur : Une des adresses vers lesquelles vous envoyez un message, %1, est vôtre. Malheureusement, Bitmessage ne peut pas traiter ses propres messages. Essayez de lancer un second client sur une machine différente. - - Synchronisation pending - En attente de synchronisation - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage ne s'est pas synchronisé avec le réseau, %n objet(s) à télécharger. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce que la synchronisation aboutisse ?Bitmessage ne s'est pas synchronisé avec le réseau, %n objet(s) à télécharger. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce que la synchronisation aboutisse ? + + Address version number + Numéro de version de l'adresse - - Not connected - Non connecté + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Concernant l'adresse %1, Bitmessage ne peut pas comprendre les numéros de version de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage n'est pas connecté au réseau. Si vous quittez maintenant, cela pourrait causer des retards de livraison. Attendre jusqu'à ce qu'il soit connecté et que la synchronisation se termine ? + + Stream number + Numéro de flux - - Waiting for network connection... - En attente de connexion réseau... + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Concernant l'adresse %1, Bitmessage ne peut pas supporter les nombres de flux de %2. Essayez de mettre à jour Bitmessage vers la dernière version. - - Waiting for finishing synchronisation... - En attente d'achèvement de la synchronisation... + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + Avertissement : Vous êtes actuellement déconnecté. Bitmessage fera le travail nécessaire pour envoyer le message mais il ne sera pas envoyé tant que vous ne vous connecterez pas. - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - Vous avez déjà mis un son de notification pour cette adresse. Voulez-vous vraiment l’écraser ? + + Your 'To' field is empty. + Votre champ 'Vers' est vide. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + Cliquez droit sur une ou plusieurs entrées dans votre carnet d'adresses et sélectionnez 'Envoyer un message à ces adresses'. + + + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Erreur : Vous ne pouvez pas ajouter une même adresse à vos abonnements deux fois. Essayez de renommer l'adresse existante. + + + + Message trashed + Message envoyé à la corbeille + + + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + Une de vos adresses, %1, est une vieille adresse de la version 1. Les adresses de la version 1 ne sont plus supportées. Nous pourrions la supprimer maintenant ? + + + + Unknown status: %1 %2 + Statut inconnu : %1 %2 + + + + Connection lost + Connexion perdue + + + + SOCKS5 Authentication problem: %1 + Problème d'authentification SOCKS5 : %1 + + + + Reply + Répondre + + + + Generating one new address + Génération d'une nouvelle adresse + + + + Done generating address. Doing work necessary to broadcast it... + Génération de l'adresse terminée. Travail pour la diffuser en cours... + + + + Done generating address + Génération de l'adresse terminée + + + + Message sent. Waiting for acknowledgement. Sent on %1 + Message envoyé. En attente de l'accusé de réception. Envoyé le %1 + + + + Error! Could not find sender address (your address) in the keys.dat file. + Erreur ! L'adresse de l'expéditeur (vous) n'a pas pu être trouvée dans le fichier keys.dat. + + + + Doing work necessary to send broadcast... + Travail pour envoyer la diffusion en cours... + + + + Broadcast sent on %1 + Message de diffusion envoyé le %1 + + + + Looking up the receiver's public key + Recherche de la clé publique du destinataire + + + + Doing work necessary to send message. (There is no required difficulty for version 2 addresses like this.) + Travail nécessaire pour envoyer le message en cours. (Il n'y a pas de difficulté requise pour ces adresses de version 2.) + + + + Doing work necessary to send message. +Receiver's required difficulty: %1 and %2 + Travail nécessaire pour envoyer le message. +Difficulté requise par le destinataire : %1 et %2 + + + + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. + Problème : Le travail demandé par le destinataire (%1 et %2) est plus difficile que ce que vous souhaitez faire. + + + + Work is queued. + Travail en attente. + + + + Work is queued. %1 + Travail en attente. %1 + + + + Doing work necessary to send message. +There is no required difficulty for version 2 addresses like this. + Travail nécessaire pour envoyer le message en cours. +Il n'y a pas de difficulté requise pour ces adresses de version 2. + + + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + + + + + Save message as... + + + + + Mark Unread + + + + + Subscribe to this address + + + + + Message sent. Sent at %1 + + + + + Chan name needed + + + + + You didn't enter a chan name. + + + + + Address already present + + + + + Could not add chan because it appears to already be one of your identities. + + + + + Success + + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + + + + + Address too new + + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + + + + + Address invalid + + + + + That Bitmessage address is not valid. + + + + + Address does not match chan name + + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + + + + + Successfully joined chan. + + + + + Fetched address from namecoin identity. + + + + + New Message + + + + + From + + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + + + + + Save As... + + + + + Write error. + + + + + Testing... + + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + + + + + Search + + + + + All + + + + + Message + + + + + Fetch Namecoin ID + + + + + Stream # + + + + + Connections + + + + + Ctrl+Q + Ctrl+Q + + + + F1 + + + + + Join / Create chan + + + + + Set avatar... + + + + + Bad address version number + + + + + Your address version number must be a number: either 3 or 4. + + + + + Your address version number must be either 3 or 4. + + + + + Inventory lookups per second: %1 + + + + + Will not resend ever + + + + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + + + + + Do you really want to remove this avatar? + + + + + You have already set an avatar for this address. Do you really want to overwrite it? + + + + + Start-on-login not yet supported on your OS. + + + + + Minimize-to-tray not yet supported on your OS. + + + + + Tray notifications not yet supported on your OS. + + + + + Enter an address above. + + + + + Address is an old type. We cannot display its past broadcasts. + + + + + There are no recent broadcasts from this address to display. + + + + + Display the %1 recent broadcast from this address. + + + + + Display the %1 recent broadcasts from this address. + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + + Inventory lookups per second: 0 + - MessageView + MainWindows - - Follow external link - Suivre lien externe - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - Le lien "%1" s'ouvrira dans un navigateur. Cela pourrait être un risque de sécurité, cela pourrait vous désanonymiser ou télécharger des données malveillantes. Êtes-vous sûr(e) ? - - - - HTML detected, click here to display - HTML détecté, cliquer ici pour l'afficher - - - - Click here to disable HTML - Cliquer ici pour mettre hors de service le HTML - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - Le message est codé de façon inconnue. -Peut-être que vous devriez mettre à niveau Bitmessage. - - - - Unknown encoding - Encodage inconnu + + Address is valid. + L'adresse est valide. @@ -1573,12 +1114,13 @@ Peut-être que vous devriez mettre à niveau Bitmessage. Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Vous pouvez générer autant d’adresses que vous le souhaitez. En effet, nous vous encourageons à créer et à délaisser vos adresses. Vous pouvez générer des adresses en utilisant des nombres aléatoires ou en utilisant une phrase secrète. Si vous utilisez une phrase secrète, l’adresse sera une adresse "déterministe". L’option 'Nombre Aléatoire' est sélectionnée par défaut mais les adresses déterministes ont certains avantages et inconvénients : + Vous pouvez générer autant d'adresses que vous le souhaitez. En effet, nous vous encourageons à créer et à délaisser vos adresses. Vous pouvez générer des adresses en utilisant des nombres aléatoires ou en utilisant une phrase secrète. Si vous utilisez une phrase secrète, l'adresse sera une adresse "déterministe". +L'option 'Nombre Aléatoire' est sélectionnée par défaut mais les adresses déterministes ont certains avantages et inconvénients : <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Avantages :<br/></span>Vous pouvez recréer vos adresses sur n’importe quel ordinateur. <br/>Vous n’avez pas à vous inquiéter à propos de la sauvegarde de votre fichier keys.dat tant que vous vous rappelez de votre phrase secrète. <br/><span style=" font-weight:600;">Inconvénients :<br/></span>Vous devez vous rappeler (ou noter) votre phrase secrète si vous souhaitez être capable de récréer vos clés si vous les perdez. <br/>Vous devez vous rappeler du numéro de version de l’adresse et du numéro de flux en plus de votre phrase secrète. <br/>Si vous choisissez une phrase secrète faible et que quelqu’un sur Internet parvient à la brute-forcer, il pourra lire vos messages et vous en envoyer.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Avantages :<br/></span>Vous pouvez recréer vos adresses sur n'importe quel ordinateur. <br/>Vous n'avez pas à vous inquiéter à propos de la sauvegarde de votre fichier keys.dat tant que vous vous rappelez de votre phrase secrète. <br/><span style=" font-weight:600;">Inconvénients :<br/></span>Vous devez vous rappeler (ou noter) votre phrase secrète si vous souhaitez être capable de récréer vos clés si vous les perdez. <br/>Vous devez vous rappeler du numéro de version de l'adresse et du numéro de flux en plus de votre phrase secrète. <br/>Si vous choisissez une phrase secrète faible et que quelqu'un sur Internet parvient à la brute-forcer, il pourra lire vos messages et vous en envoyer.</p></body></html> @@ -1593,7 +1135,7 @@ The 'Random Number' option is selected by default but deterministic ad Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Créer une adresse plus courte d’un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) + Créer une adresse plus courte d'un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) @@ -1602,13 +1144,13 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 4 - Numéro de version de l’adresse : 4 + Address version number: 3 + Numéro de version de l'adresse : 3 In addition to your passphrase, you must remember these numbers: - En plus de votre phrase secrète, vous devez vous rappeler ces numéros: + En plus de votre phrase secrète, vous devez vous rappeler ces numéros : @@ -1618,7 +1160,7 @@ The 'Random Number' option is selected by default but deterministic ad Number of addresses to make based on your passphrase: - Nombre d’adresses à créer sur base de votre phrase secrète: + Nombre d'adresses à créer sur base de votre phrase secrète : @@ -1638,7 +1180,7 @@ The 'Random Number' option is selected by default but deterministic ad Label (not shown to anyone except you) - Étiquette (seulement visible par vous) + Label (seulement visible par vous) @@ -1648,18 +1190,23 @@ The 'Random Number' option is selected by default but deterministic ad (best if this is the first of many addresses you will create) - (préférable si vous générez votre première adresse) + (préférable si vous générez votre première adresse) Use the same stream as an existing address - Utiliser le même flux qu’une adresse existante + Utiliser le même flux qu'une adresse existante (saves you some bandwidth and processing power) (économise de la bande passante et de la puissance de calcul) + + + Address version number: 4 + Numéro de version de l'adresse : 4 + NewSubscriptionDialog @@ -1671,7 +1218,7 @@ The 'Random Number' option is selected by default but deterministic ad Label - Étiquette + Label @@ -1680,8 +1227,8 @@ The 'Random Number' option is selected by default but deterministic ad - Enter an address above. - Entrez ci-dessus une adresse. + CheckBox + @@ -1689,7 +1236,7 @@ The 'Random Number' option is selected by default but deterministic ad Special Address Behavior - Comportement spécial de l’adresse + Comportement spécial de l'adresse @@ -1699,93 +1246,55 @@ The 'Random Number' option is selected by default but deterministic ad Behave as a pseudo-mailing-list address - Se comporter comme une adresse d’une pseudo liste de diffusion + Se comporter comme une adresse d'une pseudo liste de diffusion Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Un mail reçu sur une adresse d’une pseudo liste de diffusion sera automatiquement diffusé aux abonnés (et sera donc public). + Un mail reçu sur une adresse d'une pseudo liste de diffusion sera automatiquement diffusé aux abonnés (et sera donc public). Name of the pseudo-mailing-list: - Nom de la pseudo liste de diffusion : + Nom de la pseudo liste de diffusion : aboutDialog - - About - À propos - - - + PyBitmessage PyBitmessage - + version ? version ? - + + About + À propos + + + + Copyright © 2013 Jonathan Warren + Copyright © 2013 Jonathan Warren + + + <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> <html><head/><body><p>Distribué sous la licence logicielle MIT/X11; voir <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> - + This is Beta software. Version bêta. - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 Les développeurs de Bitmessage</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Utiliser une liste noire (Blacklist. Cela autorise tous les messages entrants sauf ceux présents sur la liste noire) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Utiliser une liste blanche (Whitelist. Bloque tous les messages entrants sauf ceux présents sur cette liste blanche) - - - - Add new entry - Ajouter une nouvelle entrée - - - - Name or Label - Nom ou Étiquette - - - - Address - Adresse - - - - Blacklist - Liste noire - - - - Whitelist - Liste blanche + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + @@ -1793,22 +1302,22 @@ The 'Random Number' option is selected by default but deterministic ad Bitmessage - Bitmessage + Bitmessage Bitmessage won't connect to anyone until you let it. - Bitmessage ne connectera à personne avant que vous ne le laissiez faire. + Connect now - Connexion maintenant + Let me configure special network settings first - Me laisser d’abord configurer des paramètres spéciaux de réseau + @@ -1820,13 +1329,13 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">Wiki d'aide de PyBitmessage</a> As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - Bitmessage étant un projet collaboratif, une aide peut être trouvée en ligne sur le Wiki de Bitmessage: + Bitmessage étant un projet collaboratif, une aide peut être trouvée en ligne sur le Wiki de Bitmessage : @@ -1839,12 +1348,12 @@ The 'Random Number' option is selected by default but deterministic ad You have no connections with other peers. - Vous n’avez aucune connexion avec d’autres pairs. + Vous n'avez aucune connexion avec d'autres pairs. 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. - Vous avez au moins une connexion sortante avec un pair mais vous n’avez encore reçu aucune connexion entrante. Votre pare-feu ou routeur n’est probablement pas configuré pour transmettre les connexions TCP vers votre ordinateur. Bitmessage fonctionnera correctement, mais le réseau Bitmessage se portera mieux si vous autorisez les connexions entrantes. Cela vous permettra d’être un nœud mieux connecté. + Vous avez au moins une connexion sortante avec un pair mais vous n'avez encore reçu aucune connexion entrante. Votre pare-feu ou routeur n'est probablement pas configuré pour transmettre les connexions TCP vers votre ordinateur. Bitmessage fonctionnera correctement, mais le réseau Bitmessage se portera mieux si vous autorisez les connexions entrantes. Cela vous permettra d'être un nœud mieux connecté. @@ -1854,165 +1363,7 @@ The 'Random Number' option is selected by default but deterministic ad You do have connections with other peers and your firewall is correctly configured. - Vous avez des connexions avec d’autres pairs et votre pare-feu est configuré correctement. - - - - networkstatus - - - Total connections: - Total de connexions: - - - - Since startup: - Depuis le démarrage : - - - - Processed 0 person-to-person messages. - Traité 0 messages de personne à personne. - - - - Processed 0 public keys. - Traité 0 clés publiques. - - - - Processed 0 broadcasts. - Traité 0 message de diffusion. - - - - Inventory lookups per second: 0 - Consultations d’inventaire par seconde : 0 - - - - Objects to be synced: - Objets à synchroniser : - - - - Stream # - Flux N° - - - - Connections - - - - - Since startup on %1 - Démarré depuis le %1 - - - - Down: %1/s Total: %2 - Téléchargées : %1/s Total : %2 - - - - Up: %1/s Total: %2 - Téléversées : %1/s Total : %2 - - - - Total Connections: %1 - Total des connexions : %1 - - - - Inventory lookups per second: %1 - Consultations d’inventaire par seconde : %1 - - - - Up: 0 kB/s - Téléversement : 0 kO/s - - - - Down: 0 kB/s - Téléchargement : 0 kO/s - - - - Network Status - Statut du réseau - - - - byte(s) - octetoctets - - - - Object(s) to be synced: %n - Objet à synchroniser : %nObjets à synchroniser : %n - - - - Processed %n person-to-person message(s). - Traité %n message de personne à personne.Traité %n messages de personne à personne. - - - - Processed %n broadcast message(s). - Traité %n message de diffusion.Traité %n messages de diffusion. - - - - Processed %n public key(s). - Traité %n clé publique.Traité %n clés publiques. - - - - Peer - Pair - - - - IP address or hostname - Adresse IP ou nom d'hôte - - - - Rating - Évaluation - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage suit à la trace le taux de réussites de connexions tentées vers les noeuds individuels. L'évaluation s'étend de -1 à 1 et affecte la probabilité de choisir ce noeud dans l'avenir - - - - User agent - Agent utilisateur - - - - Peer's self-reported software - Logiciel, auto-rapporté par le pair - - - - TLS - TLS - - - - Connection encryption - - - - - List of streams negotiated between you and the peer - + Vous avez des connexions avec d'autres pairs et votre pare-feu est configuré correctement. @@ -2020,116 +1371,42 @@ The 'Random Number' option is selected by default but deterministic ad Dialog - + Create a new chan - + Join a chan - + Create a chan - + <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + Chan name: - + <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + Chan bitmessage address: - - - - - Create or join a chan - Créer ou rejoindre un canal - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Un canal existe lorsqu'un groupe de personnes partage les mêmes clés de décryptage. Les clés et l'adresse bitmessage utilisées par un canal sont produites à partir d'un mot ou d'une phrase faciles à mémoriser par des hommes. Pour envoyer un message à tout le monde dans le canal, envoyez un message à l'adresse du canal.</p><p>Les canaux sont expérimentaux et complètement sans modération.</p><p>Entrez un nom pour votre canal. Si vous le choisissez un nom de canal suffisamment complexe (comme par exemple une phrase mot de passe qui soit forte et unique) et qu'aucun de vos amis ne le partage publiquement, alors le canal sera sécurisé et privé. Cependant si vous et quelqu'un d'autre créez tous les deux un canal ayant le même nom, ces canaux identiques seront partagés.</p></body></html> - - - - Chan passhphrase/name: - Nom ou phrase mot de passe du canal : - - - - Optional, for advanced usage - Facultatif, pour une utilisation avancée - - - - Chan address - Adresse de canal - - - - Please input chan name/passphrase: - Veuillez saisir le nom du canal ou la phrase mot de passe : - - - - newchandialog - - - Successfully created / joined chan %1 - Le canal %1 a été rejoint ou créé avec succès. - - - - Chan creation / joining failed - Échec lors de la création du canal ou de la tentative de le rejoindre - - - - Chan creation / joining cancelled - Annulation de la création du canal ou de la tentative de le rejoindre - - - - proofofwork - - - C PoW module built successfully. - Module PoW C construit avec succès. - - - - Failed to build C PoW module. Please build it manually. - Échec à construire le module PoW C. Veuillez le construire manuellement. - - - - C PoW module unavailable. Please build it. - Module PoW C non disponible. Veuillez le construire. - - - - qrcodeDialog - - - QR-code - QR-code + @@ -2152,17 +1429,22 @@ The 'Random Number' option is selected by default but deterministic ad Number of addresses to make based on your passphrase: - Nombre d’adresses basées sur votre phrase secrète à créer : + Nombre d'adresses basées sur votre phrase secrète à créer : - - Address version number: - Numéro de version de l’adresse : + + Address version Number: + Numéro de version de l'adresse : + + + + 3 + 3 Stream number: - Numéro du flux : + Numéro du flux : @@ -2172,326 +1454,330 @@ The 'Random Number' option is selected by default but deterministic ad Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Créer une adresse plus courte d’un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) + Créer une adresse plus courte d'un ou deux caractères (nécessite plusieurs minutes de temps de calcul supplémentaires) You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Vous devez cocher (ou décocher) cette case comme vous l’aviez fait (ou non) lors de la création de vos adresses la première fois. + Vous devez cocher (ou décocher) cette case comme vous l'aviez fait (ou non) lors de la création de vos adresses la première fois. If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Si vous aviez généré des adresses déterministes mais les avez perdues à cause d’un accident (comme une panne de disque dur), vous pouvez les régénérer ici. Si vous aviez utilisé le générateur de nombres aléatoires pour créer vos adresses, ce formulaire ne vous sera d’aucune utilité. + Si vous aviez généré des adresses déterministes mais les avez perdues à cause d'un accident, vous pouvez les regénérer ici. Si vous aviez utilisé le générateur de nombres aléatoires pour créer vos adresses, ce formulaire ne vous sera d'aucune utilité. + + + + Address version number: + settingsDialog - + Settings Paramètres - + Start Bitmessage on user login - Démarrer Bitmessage à la connexion de l’utilisateur + Démarrer Bitmessage à la connexion de l'utilisateur - - Tray - Zone de notification - - - + Start Bitmessage in the tray (don't show main window) Démarrer Bitmessage dans la barre des tâches (ne pas montrer la fenêtre principale) - + Minimize to tray Minimiser dans la barre des tâches - - Close to tray - Fermer vers la zone de notification - - - + Show notification when message received - Montrer une notification lorsqu’un message est reçu + Montrer une notification lorsqu'un message est reçu - + Run in Portable Mode Lancer en Mode Portable - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - En Mode Portable, les messages et les fichiers de configuration sont stockés dans le même dossier que le programme plutôt que le dossier de l’application. Cela rend l’utilisation de Bitmessage plus facile depuis une clé USB. + En Mode Portable, les messages et les fichiers de configuration sont stockés dans le même dossier que le programme plutôt que le dossier de l'application. Cela rend l'utilisation de Bitmessage plus facile depuis une clé USB. - - Willingly include unencrypted destination address when sending to a mobile device - Inclure volontairement l’adresse de destination non chiffrée lors de l’envoi vers un dispositif mobile - - - - Use Identicons - Utilise des Identicônes. - - - - Reply below Quote - Réponse en dessous de la citation - - - - Interface Language - Langue de l’interface - - - - System Settings - system - Paramètres système - - - + User Interface Interface utilisateur - + Listening port - Port d’écoute + Port d'écoute - + Listen for connections on port: - Écouter les connexions sur le port : + Écouter les connexions sur le port : - - UPnP: - UPnP : - - - - Bandwidth limit - Limite de bande passante - - - - Maximum download rate (kB/s): [0: unlimited] - Taux de téléchargement maximal (kO/s) : [0 : illimité] - - - - Maximum upload rate (kB/s): [0: unlimited] - Taux de téléversement maximal (kO/s) : [0 : illimité] - - - + Proxy server / Tor Serveur proxy / Tor - + Type: - Type : + Type : - - Server hostname: - Nom du serveur: - - - - Port: - Port : - - - - Authentication - Authentification - - - - Username: - Utilisateur : - - - - Pass: - Mot de passe : - - - - Listen for incoming connections when using proxy - Écoute les connexions entrantes lors de l’utilisation du proxy - - - + none aucun - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + + Server hostname: + Nom du serveur : + + + + Port: + Port : + + + + Authentication + Authentification + + + + Username: + Utilisateur : + + + + Pass: + Mot de passe : + + + Network Settings Paramètres réseau - - Total difficulty: - Difficulté totale : - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - La 'difficulté totale' affecte le montant total de travail que l’envoyeur devra compléter. Doubler cette valeur double la charge de travail. - - - - Small message difficulty: - Difficulté d’un message court : - - - + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Lorsque quelqu’un vous envoie un message, son ordinateur doit d’abord effectuer un travail. La difficulté de ce travail, par défaut, est de 1. Vous pouvez augmenter cette valeur pour les adresses que vous créez en changeant la valeur ici. Chaque nouvelle adresse que vous créez requerra à l’envoyeur de faire face à une difficulté supérieure. Il existe une exception : si vous ajoutez un ami ou une connaissance à votre carnet d’adresses, Bitmessage les notifiera automatiquement lors du prochain message que vous leur envoyez qu’ils ne doivent compléter que la charge de travail minimale : difficulté 1. + Lorsque quelqu'un vous envoie un message, son ordinateur doit d'abord effectuer un travail. La difficulté de ce travail, par défaut, est de 1. Vous pouvez augmenter cette valeur pour les adresses que vous créez en changeant la valeur ici. Chaque nouvelle adresse que vous créez requerra à l'envoyeur de faire face à une difficulté supérieure. Il existe une exception : si vous ajoutez un ami ou une connaissance à votre carnet d'adresses, Bitmessage les notifiera automatiquement lors du prochain message que vous leur envoyez qu'ils ne doivent compléter que la charge de travail minimale : difficulté 1. - + + Total difficulty: + Difficulté totale : + + + + Small message difficulty: + Difficulté d'un message court : + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - La 'difficulté d’un message court' affecte principalement la difficulté d’envoyer des messages courts. Doubler cette valeur rend la difficulté à envoyer un court message presque double, tandis qu’un message plus long ne sera pas réellement affecté. + La 'difficulté d'un message court' affecte principalement la difficulté d'envoyer des messages courts. Doubler cette valeur rend la difficulté à envoyer un court message presque double, tandis qu'un message plus long ne sera pas réellement affecté. - + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + La 'difficulté totale' affecte le montant total de travail que l'envoyeur devra compléter. Doubler cette valeur double la charge de travail. + + + Demanded difficulty - Difficulté exigée + Difficulté demandée - + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Vous pouvez préciser quelle charge de travail vous êtes prêt à effectuer afin d’envoyer un message à une personne. Placer cette valeur à 0 signifie que n’importe quelle valeur est acceptée. + Vous pouvez préciser quelle charge de travail vous êtes prêt à effectuer afin d'envoyer un message à une personne. Placer cette valeur à 0 signifie que n'importe quelle valeur est acceptée. - + Maximum acceptable total difficulty: - Difficulté maximale acceptée : + Difficulté maximale acceptée : - + Maximum acceptable small message difficulty: - Difficulté maximale acceptée pour les messages courts : + Difficulté maximale pour les messages courts acceptée : - + Max acceptable difficulty - Difficulté maximale acceptée + Difficulté acceptée max - - Hardware GPU acceleration (OpenCL) - + + Willingly include unencrypted destination address when sending to a mobile device + - + + Listen for incoming connections when using proxy + + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage peut utiliser Namecoin, un autre programme basé sur Bitcoin, pour avoir des adresses plus parlantes. Par exemple, plutôt que de donner à votre ami votre longue adresse Bitmessage, vous pouvez simplement lui dire d’envoyer un message à <span style=" font-style:italic;">test. </span></p><p>(Obtenir votre propre adresse Bitmessage au sein de Namecoin est encore assez difficile).</p><p>Bitmessage peut soit utiliser directement namecoind soit exécuter une instance de nmcontrol.</p></body></html> + - + Host: - Hôte : + - + Password: - Mot de passe : + - + Test - Test + - + Connect to: - Connexion à : + - + Namecoind - Namecoind + - + NMControl - NMControl + - + Namecoin integration - Intégration avec Namecoin + - + + Use Identicons + + + + + Interface Language + + + + + System Settings + system + + + + + English + en + + + + + Esperanto + eo + + + + + Français + fr + + + + + Deutsch + de + + + + + Españl + es + + + + + русский язык + ru + + + + + Norsk + no + + + + + Pirate English + en_pirate + + + + + Other (set in keys.dat) + other + + + + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Par défaut, si vous envoyez un message à quelqu’un et que cette personne est hors connexion pendant plus de deux jours, Bitmessage enverra le message de nouveau après des deux jours supplémentaires. Ceci sera continué avec reculement (backoff) exponentiel pour toujours; les messages seront réenvoyés après 5, 10, 20 jours etc. jusqu’à ce que le récepteur accuse leur réception. Ici vous pouvez changer ce comportement en faisant en sorte que Bitmessage renonce après un certain nombre de jours ou de mois.</p> <p>Si vous souhaitez obtenir le comportement par défaut alors laissez vides ces champs de saisie. </p></body></html> + - + Give up after - Abandonner après + - + and - et + - + days - jours + - + months. - mois. + - + Resends Expire - Expiration des renvois automatiques - - - - Hide connection notifications - Cacher les notifications de connexion - - - - Maximum outbound connections: [0: none] - Connexions sortantes maximum: [0: aucune] - - - - Hardware GPU acceleration (OpenCL): - Accélération matérielle GPU (OpenCL) : + - \ No newline at end of file + diff --git a/src/translations/bitmessage_it.qm b/src/translations/bitmessage_it.qm deleted file mode 100644 index d38e68bc..00000000 Binary files a/src/translations/bitmessage_it.qm and /dev/null differ diff --git a/src/translations/bitmessage_it.ts b/src/translations/bitmessage_it.ts deleted file mode 100644 index dbefce30..00000000 --- a/src/translations/bitmessage_it.ts +++ /dev/null @@ -1,2132 +0,0 @@ - - - - AddAddressDialog - - - Add new entry - Aggiungi una nuova voce - - - - Label - Etichetta - - - - Address - Indirizzo - - - - EmailGatewayDialog - - - Email gateway - Gateway di posta - - - - Register on email gateway - Registrati sul gateway di posta - - - - Account status at email gateway - Stato dell'account rispetto al gateway di posta - - - - Change account settings at email gateway - Modifica i settaggi dell'account rispetto al gateway di posta - - - - Unregister from email gateway - Rimuovi registrazione dal gateway di posta - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Il gateway di posta permette di comunicare con gli utenti email. Per ora, solo il gateway di posta Mailchuck (@mailchuck.com) è disponibile. - - - - Desired email address (including @mailchuck.com): - Indirizzo email desiderato (incluso @mailchuck.com): - - - - EmailGatewayRegistrationDialog - - - Registration failed: - Registrazione fallita: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - L'email richiesto non è disponibile, si prega di provarne uno nuovo. Inserisci il nuovo indirizzo email desiderato (incluso @mailchuck.com) qui sotto: - - - - Email gateway registration - Registrazione gateway email - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # È possibile utilizzare questo per configurare il tuo gateway account di posta elettronica -# Decommentare l'impostazione che si desidera utilizzare -# Ecco le opzioni: -# -# PGP: server -# Il gateway e-mail creerà e manterrà le chiavi PGP per voi e firmerà, verificherà, -# cifrarà e decifrerà a vostro nome. Quando si desidera usare PGP, ma siete pigri, -# utilizzate questo. Richiede abbonamento. -# -# PGP: locale # -Il gateway email non condurrà operazioni PGP a vostro nome. È possibile -# o non usare PGP affatto, o utilizzarlo in locale. -# -# Allegati: sì -# gli allegati in entrata nella e-mail verranno caricati su MEGA.nz, e si può -# scaricarli da qui seguendo il link. Richiede un abbonamento. -# -# Allegati: no -# gli allegati saranno ignorati. -# -# Archivio: sì -# i vostri messaggi di posta elettronica in arrivo verranno archiviati sul server. Utilizzare questo se avete bisogno di -# aiuto per problemi di debug o avete necessità di un controllo di terze parti. -# Questo però significa che l'operatore del servizio sarà in grado di leggere i vostri messaggi di posta elettronica -# anche dopo che sono stati consegnati a voi. -# -# Archivio: no -# i messaggi di posta elettronica in arrivo verranno eliminati dal server non appena vengono inoltrati a te. -# -# masterpubkey_btc: BIP44 xpub key oppure seme electrum v1 pubblico -# offset_btc: intero (il default è 0) -# feeamount: numero con un massimo di 8 cifre decimali -# feecurrency: BTC, XBT, USD, EUR o GBP -# utilizzare questi se si vuole far pagare le persone che inviano messaggi di posta elettronica. -# Se questo è attivato una persona sconosciuta che ti invia una e-mail, sarà tenuta a pagare una commissione specificata. -# Dato che questo schema utilizza chiavi pubbliche deterministiche, si riceverà la commissione direttamente. -# Per disattivarla, impostare "feeamount" a 0. -# Richiede un abbonamento. - - - - - MainWindow - - - Reply to sender - Rispondi al mittente - - - - Reply to channel - Rispondi sul canale - - - - Add sender to your Address Book - Aggiungi mittente alla rubrica - - - - Add sender to your Blacklist - Aggiungi mittente alla blacklist - - - - Move to Trash - Sposta nel cestino - - - - Undelete - Ripristina l'eliminato - - - - View HTML code as formatted text - Vedi codice HTML come testo formattato - - - - Save message as... - Salva messaggio con nome... - - - - Mark Unread - Segna come non letto - - - - New - Nuovo - - - - Enable - Abilita - - - - Disable - Disabilita - - - - Set avatar... - Inserisci l'avatar - - - - Copy address to clipboard - Copia indirizzo negli appunti - - - - Special address behavior... - Comportamento indirizzo speciale - - - - Email gateway - Gateway di posta - - - - Delete - Cancella - - - - Send message to this address - Manda un messaggio a questo indirizzo - - - - Subscribe to this address - Sottoscrivi questo indirizzo - - - - Add New Address - Aggiungi Nuovo Indirizzo - - - - Copy destination address to clipboard - Copia indirizzo di destinazione negli appunti - - - - Force send - Forza invio - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Uno dei tuoi indirizzi, %1, è un indirizzo vecchio versione 1. Gli indirizzi versione 1 non sono più supportati. Posso eliminarlo ora? - - - - Waiting for their encryption key. Will request it again soon. - In attesa della chiave di criptazione. Sarà presto richiesta successivamente. - - - - Encryption key request queued. - Chiave di criptazione richiesta, in coda. - - - - Queued. - In coda. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - - - - - Message sent. Sent at %1 - Messaggio inviato. Inviato a %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - - - - - Broadcast queued. - - - - - Broadcast on %1 - - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - - - - - Forced difficulty override. Send should start soon. - - - - - Unknown status: %1 %2 - - - - - Not Connected - Non connesso - - - - Show Bitmessage - Mostra Bitmessage - - - - Send - Invia - - - - Subscribe - Sottoscrivi - - - - Channel - Canale - - - - Quit - Chiudi - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - - - - - Open keys.dat? - Aprire keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - Delete trash? - Svuotare il cestino? - - - - Are you sure you want to delete all trashed messages? - Sei sicuro di voler eliminare tutti i messaggi cestinati? - - - - bad passphrase - - - - - You must type your passphrase. If you don't have one then this is not the form for you. - - - - - Bad address version number - - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - Indirizzo troppo nuovo - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - Indirizzo non valido - - - - That Bitmessage address is not valid. - L'indirizzo Bitmessage non è valido. - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Connessione persa - - - - Connected - Connesso - - - - Message trashed - Messaggio cestinato - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - Messaggio troppo lungo - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - - - - - Address version number - - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Stream number - - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - - - - Message queued. - - - - - Your 'To' field is empty. - - - - - Right click one or more entries in your address book and select 'Send message to this address'. - - - - - Fetched address from namecoin identity. - - - - - New Message - Nuovo Messaggio - - - - From - Da - - - - Sending email gateway registration request - - - - - Address is valid. - Indirizzo valido - - - - The address you entered was invalid. Ignoring it. - - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - Riavvia - - - - You must restart Bitmessage for the port number change to take effect. - - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - - - - Number needed - Numero richiesto - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - Indirizzo disabilitato - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - Salva come... - - - - Write error. - Errore di scrittura. - - - - No addresses selected. - Nessun indirizzo selezionato. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - Identità - - - - New Identity - Nuova identità - - - - Search - Cerca - - - - All - - - - - To - A - - - - From - Da - - - - Subject - Soggetto - - - - Message - Messaggio - - - - Received - Ricevuto - - - - Messages - Messaggi - - - - Address book - - - - - Address - Indirizzo - - - - Add Contact - Aggiungere Contatto - - - - Fetch Namecoin ID - - - - - Subject: - Soggetto: - - - - From: - Da: - - - - To: - A: - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - TTL: - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - File - File - - - - Settings - Impostazioni - - - - Help - Aiuto - - - - Import keys - Importa chiavi - - - - Manage keys - Gestisci chiavi - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - - - - - About - - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - Tutti gli account - - - - Zoom level %1% - - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - Aggiungi una nuova voce - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - %n day(s) - - - - - - - - Shutting down PyBitmessage... %1% - - - - - Sent - - - - - Generating one new address - - - - - Done generating address. Doing work necessary to broadcast it... - - - - - Generating %1 new addresses. - - - - - %1 is already in 'Your Identities'. Not adding it again. - - - - - Done generating address - - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - - Error! Could not find sender address (your address) in the keys.dat file. - - - - - Doing work necessary to send broadcast... - - - - - Broadcast sent on %1 - - - - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - - - - - NewAddressDialog - - - Create new Address - Crea nuovo Indirizzo - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - - Use a random number generator to make an address - - - - - Use a passphrase to make addresses - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - Make deterministic addresses - - - - - Address version number: 4 - - - - - In addition to your passphrase, you must remember these numbers: - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Stream number: 1 - - - - - Retype passphrase - - - - - Randomly generate address - - - - - Label (not shown to anyone except you) - - - - - Use the most available stream - - - - - (best if this is the first of many addresses you will create) - - - - - Use the same stream as an existing address - - - - - (saves you some bandwidth and processing power) - - - - - NewSubscriptionDialog - - - Add new entry - Aggiungi una nuova voce - - - - Label - Etichetta - - - - Address - Indirizzo - - - - Enter an address above. - - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - - - - - Behave as a normal address - - - - - Behave as a pseudo-mailing-list address - - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - - - - - Name of the pseudo-mailing-list: - - - - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - aboutDialog - - - About - - - - - PyBitmessage - PyBitmessage - - - - version ? - versione ? - - - - <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> - - - - - This is Beta software. - - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Aggiungi una nuova voce - - - - Name or Label - Nome o Etichetta - - - - Address - Indirizzo - - - - Blacklist - - - - - Whitelist - - - - - connectDialog - - - Bitmessage - Bitmessage - - - - Bitmessage won't connect to anyone until you let it. - - - - - Connect now - Connetti ora - - - - Let me configure special network settings first - - - - - helpDialog - - - Help - Aiuto - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - - - - - iconGlossaryDialog - - - Icon Glossary - - - - - You have no connections with other peers. - Non sei connesso ad altri peer. - - - - 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. - - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - - - - - networkstatus - - - Total connections: - Connessioni totali: - - - - Since startup: - Dall'avvio: - - - - Processed 0 person-to-person messages. - Processati 0 messaggi da persona a persona - - - - Processed 0 public keys. - Processate 0 chiavi pubbliche - - - - Processed 0 broadcasts. - Processati 0 broadcast - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - Oggetti da sincronizzare: - - - - Stream # - - - - - Connections - Connessioni - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - Connessioni totali: %1 - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - Stato di Rete - - - - byte(s) - - byte - byte - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - - - - newChanDialog - - - Dialog - Dialogo - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - Rigenera Indirizzi Esistenti - - - - Regenerate existing addresses - Rigenera indirizzi esistenti - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Address version number: - - - - - Stream number: - - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - - - - - settingsDialog - - - Settings - Impostazioni - - - - Start Bitmessage on user login - - - - - Tray - - - - - Start Bitmessage in the tray (don't show main window) - - - - - Minimize to tray - - - - - Close to tray - - - - - Show notification when message received - - - - - Run in Portable Mode - Esegui in Modalità Portabile - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - - - - - Willingly include unencrypted destination address when sending to a mobile device - - - - - Use Identicons - - - - - Reply below Quote - - - - - Interface Language - - - - - System Settings - system - Impostazioni di sistema - - - - User Interface - Interfaccia Utente - - - - Listening port - Porta in ascolto - - - - Listen for connections on port: - - - - - UPnP: - UPnP: - - - - Bandwidth limit - Limite banda - - - - Maximum download rate (kB/s): [0: unlimited] - - - - - Maximum upload rate (kB/s): [0: unlimited] - - - - - Proxy server / Tor - Server proxy / Tor - - - - Type: - - - - - Server hostname: - - - - - Port: - Porta: - - - - Authentication - Autenticazione - - - - Username: - Nome utente: - - - - Pass: - - - - - Listen for incoming connections when using proxy - - - - - none - - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Impostazioni di rete - - - - Total difficulty: - Difficoltà totale: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - - Small message difficulty: - - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - Difficoltà richiesta - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - Massima difficoltà totale accettabile: - - - - Maximum acceptable small message difficulty: - - - - - Max acceptable difficulty - Massima difficoltà accettabile - - - - Hardware GPU acceleration (OpenCL) - Accelerazione hardware GPU (OpenCL) - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - Host: - - - - Password: - Password: - - - - Test - Test - - - - Connect to: - Connetti a: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Integrazione Namecoin - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - - Give up after - - - - - and - e - - - - days - giorni - - - - months. - mesi. - - - - Resends Expire - - - - diff --git a/src/translations/bitmessage_ja.pro b/src/translations/bitmessage_ja.pro new file mode 100644 index 00000000..f6e5ad63 --- /dev/null +++ b/src/translations/bitmessage_ja.pro @@ -0,0 +1,33 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_ja.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 3756d6d3..0d78d13d 100644 Binary files a/src/translations/bitmessage_ja.qm and b/src/translations/bitmessage_ja.qm differ diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 90e49dc2..da9edc69 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -1,1571 +1,892 @@ - - - AddAddressDialog - - - Add new entry - 新しい項目を追加 - - - - Label - ラベル - - - - Address - アドレス - - - - EmailGatewayDialog - - - Email gateway - メールゲートウェイ - - - - Register on email gateway - メールゲートウェイで登録 - - - - Account status at email gateway - メールゲートウェイのアカウント状態 - - - - Change account settings at email gateway - メールゲートウェイでアカウントの設定を変更 - - - - Unregister from email gateway - メールゲートウェイから登録抹消 - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - メールゲートウェイを使用すると、メールユーザーと通信できます。 現在、Mailchuck メールゲートウェイ (@mailchuck.com) のみが利用可能です。 - - - - Desired email address (including @mailchuck.com): - 希望のメールアドレス (@mailchuck.com を含む): - - - - EmailGatewayRegistrationDialog - - - Registration failed: - 登録に失敗しました: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - リクエストしたメールアドレスは利用できません。新しいメールアドレスをお試しください。 新しい希望メールアドレス (@mailchuck.com を含む) を次のように記入してください: - - - - Email gateway registration - メールゲートウェイの登録 - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - メールゲートウェイを使用すると、メールユーザーと通信できます。 現在、Mailchuck メールゲートウェイ (@mailchuck.com) のみが利用可能です。 -希望のメールアドレス (@mailchuck.com を含む) を以下に入力してください: - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # これを使用して、メールゲートウェイアカウントを設定できます -# 使用する設定のコメントを外してください -# オプションは次のとおりです: -# -# pgp: server -# メールゲートウェイは、あなたのために PGP 鍵を作成および管理し、 -# あなたに代わって署名、検証、暗号化と復号化を行います。 PGPを使用したいが、 -# 面倒なときは、これを使用してください。 サブスクリプションが必要です。 -# -# pgp: local -# メールゲートウェイは、あなたに代わって PGP 操作を行いません。 -# PGP をまったく使用しないか、ローカルで使用することができます。 -# -# attachments: yes -# 受信メールの添付ファイルは MEGA.nz にアップロードされ、リンクをフォローして -# そこからダウンロードすることができます。 サブスクリプションが必要です。 -# -# attachments: no -# 添付ファイルは無視されます。 -# -# archive: yes -# 受信メールはサーバーにアーカイブされます。 問題のデバッグで支援が必要な場合や、 -# メールの第三者証明が必要な場合に、これを使用してください。 しかし、これは、 -# メールがあなたに配信された後でも、サービスの運営者があなたのメールを -# 読むことができるということを意味します。 -# -# archive: no -# 受信メールは、あなたに中継されるとすぐにサーバーから削除されます。 -# -# masterpubkey_btc: BIP44 xpub key または electrum v1 public seed -# offset_btc: 整数 (デフォルトは 0) -# feeamount: 小数点以下 8 桁までの数字 -# feecurrency: BTC, XBT, USD, EUR または GBP -# メールを送信した人に請求したい場合に、これらを使用します。 これがオンで、 -# 未知の人があなたにメールを送信した場合、指定された料金を支払うように要求されます。 -# この方式は決定的な公開鍵を使用するため、直接お金を受け取ることになります。 -# もう一度オフにするには、「feeamount」を 0 に設定します。 -# サブスクリプションが必要です。 - - - + + + MainWindow - - Reply to sender - 送信元に返信 - - - - Reply to channel - チャンネルに返信 - - - - Add sender to your Address Book - 送信元をアドレス帳に追加 - - - - Add sender to your Blacklist - 送信元をブラックリストに追加 - - - - Move to Trash - ゴミ箱へ移動 - - - - Undelete - 削除を元に戻す - - - - View HTML code as formatted text - HTMLコードを整形したテキストで表示 - - - - Save message as... - 形式を選択してメッセージを保存 - - - - Mark Unread - 未読にする - - - - New - 新規 - - - - Enable - 有効 - - - - Disable - 無効 - - - - Set avatar... - アバターを設定... - - - - Copy address to clipboard - アドレスをコピー - - - - Special address behavior... - アドレスの特別な動作 - - - - Email gateway - メールゲートウェイ - - - - Delete - 削除 - - - - Send message to this address - このアドレスへ送信 - - - - Subscribe to this address - このアドレスを購読 - - - - Add New Address - アドレスを追加 - - - - Copy destination address to clipboard - 宛先アドレスをコピー - - - - Force send - 強制的に送信 - - - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? %1は古いバージョン1のアドレスです。バージョン1のアドレスはサポートが終了しています。すぐに削除しますか? - - Waiting for their encryption key. Will request it again soon. - 暗号鍵を待っています。 すぐにもう一度リクエストします。 + + Reply + . + 返信 - + + Add sender to your Address Book + 送信元をアドレス帳に追加 + + + + Move to Trash + ゴミ箱へ移動 + + + + View HTML code as formatted text + HTMLコードを整形したテキストで表示 + + + + Save message as... + 形式を選択してメッセージを保存 + + + + Mark Unread + 未読にする + + + + New + 新規 + + + + Enable + 有効 + + + + Disable + 無効 + + + + Copy address to clipboard + アドレスをコピー + + + + Special address behavior... + アドレスの特別な動作 + + + + Send message to this address + このアドレスへ送信 + + + + Subscribe to this address + このアドレスを購読 + + + + Add New Address + アドレスを追加 + + + + Delete + 削除 + + + + Copy destination address to clipboard + 宛先アドレスをコピー + + + + Force send + 強制的に送信 + + + + Add new entry + 新しい項目を追加 + + + + Since startup on %1 + 起動日時 %1 + + + + Waiting on their encryption key. Will request it again soon. + 暗号化キーを待っています。再度リクエストします。 + + + Encryption key request queued. - + 暗号鍵のリクエストはキューに入りました。 - + Queued. キューに入りました。 - - Message sent. Waiting for acknowledgement. Sent at %1 - メッセージを送信しました。 確認応答を待っています。 %1 で送信されました + + Message sent. Waiting on acknowledgement. Sent at %1 + メッセージは送信されました。確認街です。送信先: %1 - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 - + Need to do work to send message. Work is queued. - + 送信のために処理を行う必要があります。処理はキューに入りました。 - + Acknowledgement of the message received %1 メッセージの確認を受け取りました %1 - + Broadcast queued. - 配信がキューに入りました。 + Broadcastがキューに入りました。 - + Broadcast on %1 - 配信: %1 + Broadcast: %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 問題: 受信者が要求している処理は現在あなたが設定しているよりも高い難易度です。 %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 問題: 受信者の暗号鍵は正当でない物です。メッセージを暗号化できません。 %1 - + Forced difficulty override. Send should start soon. 難易度を強制上書きしました。まもなく送信されます。 - + Unknown status: %1 %2 不明なステータス: %1 %2 - + Not Connected 未接続 - + Show Bitmessage Bitmessageを表示 - + Send 送る - + Subscribe 購読 - - Channel - チャンネル + + Address Book + アドレス帳 - + Quit 終了 - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. プログラムを同じディレクトリに保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。 - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. %1に保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。 - + Open keys.dat? keys.datを開きますか? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) プログラムを同じディレクトリに保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。すぐにファイルを開きますか?(必ず編集する前にBitmessageを終了してください) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) %1に保存されているkeys.datファイルを編集することで鍵を管理できます。ファイルをバックアップしておくことも重要です。すぐにファイルを開きますか?(必ず編集する前にBitmessageを終了してください) - + Delete trash? ゴミ箱を空にしますか? - + Are you sure you want to delete all trashed messages? ゴミ箱内のメッセージを全て削除してもよろしいですか? - + bad passphrase 不正なパスフレーズ - + You must type your passphrase. If you don't have one then this is not the form for you. パスフレーズを入力してください。パスフレーズがない場合は入力する必要はありません。 - - Bad address version number - 不正なアドレスのバージョン番号 - - - - Your address version number must be a number: either 3 or 4. - アドレスのバージョン番号は数字にする必要があります: 3 または 4。 - - - - Your address version number must be either 3 or 4. - アドレスのバージョン番号は、3 または 4 のどちらかにする必要があります。 - - - + Chan name needed - + Chan名が必要です - + You didn't enter a chan name. - + chan名が入力されていません。 - + Address already present - + アドレスは既に表示されています - + Could not add chan because it appears to already be one of your identities. - + chanを追加できません。既にアドレス一覧に含まれています。 - + Success - + 成功 - + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - + chanの作成に成功しました。他の人がchanに参加できるようにするには、chanの名前とBitmessageアドレスを伝えてください: %1 アドレスは「アドレス一覧」に表示されます。 - + Address too new - + アドレスが新しすぎます - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - + このBitmessageアドレスは正当ですが、バージョン番号が現在使用中の物より新しいです。Bitmessageをアップデートしてください。 - + Address invalid - + アドレスが不正です - + That Bitmessage address is not valid. - + このBitmessageアドレスは不正です。 - + Address does not match chan name - + アドレスがchan名と一致しません - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. - + このBitmessageアドレスは正当ですが、chan名と一致していません。 - + Successfully joined chan. - + chanに参加しました。 - + + Processed %1 person-to-person messages. + %1 通の1対1のメッセージを処理しました。 + + + + Processed %1 broadcast messages. + %1 件のBroadcastメッセージを処理しました。 + + + + Processed %1 public keys. + %1 件の公開鍵を処理しました。 + + + + Total Connections: %1 + 接続数: %1 + + + Connection lost 接続が切断されました - + Connected 接続済み - + Message trashed メッセージが削除されました - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - TTL または Time-To-Live は、ネットワークがメッセージを保持する時間の長さです。 -受信者は、この時間の間に取得する必要があります。 Bitmessage クライアントが確認応答を受け取らないと、 -自動的にメッセージが再送信されます。 TTL(Time-To-Live)が長くなるほど、 -コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 4〜5 日のTTL(Time-To-Live)が適切です。 - - - - Message too long - メッセージが長すぎます - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - 送信しようとしているメッセージが %1 バイト長すぎます。 (最大は261644バイトです)。 送信する前に短くしてください。 - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - エラー: アカウントがメールゲートウェイに登録されていません。 今 %1 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 - - - + Error: Bitmessage addresses start with BM- Please check %1 - + エラー: Bitmessageアドレスは「BM-」で始まります。確認してください %1 - + Error: The address %1 is not typed or copied correctly. Please check it. - + エラー: アドレス %1 は正しく入力、またはコピーされていません。確認して下さい。 - + Error: The address %1 contains invalid characters. Please check it. - + エラー: アドレス %1 は不正な文字を含んでいます。確認して下さい。 - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - + エラー: アドレスのバージョン %1 は現在使用中の物より新しいです。Bitmessageをアップデートする必要があるか、連絡先がより賢いです。 - + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - + エラー: アドレス %1 でエンコードされたデータが短すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - + エラー: アドレス %1 でエンコードされたデータが長すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - + Error: Something is wrong with the address %1. - + エラー: アドレス %1 には何かしら誤りがあります。 - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. エラー: 送信元アドレスを指定してください。まだ作成していない場合には「アドレス一覧」のタブを開いてください。 - + + Sending to your address + アドレスへ送信中 + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + エラー: 送信先アドレス %1 は自分自身のアドレスです。Bitmessageクライアントは自分自身へのメッセージを処理できません。別のPCか仮想マシン上でクライアントを立ち上げてください。 + + + Address version number アドレスのバージョン番号 - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. アドレス %1 に接続。%2 のバージョン番号は処理できません。Bitmessageを最新のバージョンへアップデートしてください。 - + Stream number ストリーム番号 - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. アドレス %1 に接続。%2 のストリーム番号は処理できません。Bitmessageを最新のバージョンへアップデートしてください。 - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. 警告: 接続されていません。Bitmessageはメッセージの処理を行いますが、ネットワークに接続するまで送信はされません。 - - Message queued. - メッセージがキューに入りました。 - - - + Your 'To' field is empty. 宛先が指定されていません。 - + + Work is queued. + 処理がキューに入りました。 + + + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + + Work is queued. %1 + 処理がキューに入りました。 %1 + + + New Message 新規メッセージ - + From - + 送信元 - - Sending email gateway registration request - メールゲートウェイの登録リクエストを送信しています - - - + Address is valid. アドレスが不正です。 - + The address you entered was invalid. Ignoring it. 入力されたアドレスは不正です。無視されました。 - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. エラー: 同じアドレスを複数アドレス帳に追加する事はできません。既存の項目をリネームしてください。 - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - エラー: 購読に、同じアドレスを2回追加することはできません。 必要に応じて、既存の名前を変更してください。 + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + エラー: 同じアドレスを複数購読リストに追加する事はできません。既存の項目をリネームしてください。 - + Restart 再開 - + You must restart Bitmessage for the port number change to take effect. ポート番号の変更を有効にするにはBitmessageを再起動してください。 - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). プロキシの設定を有効にするには手動でBitmessageを再起動してください。既に接続がある場合は切断されます。 - - Number needed - 数字が必要です - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - 最大ダウンロード数とアップロード数は数字にする必要があります。 入力されたものを無視します。 - - - - Will not resend ever - 今後再送信されません - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - 入力した時間制限は、Bitmessageが最初の再送試行を待つ時間よりも短いため、メッセージは再送信されないことにご注意ください。 - - - - Sending email gateway unregistration request - メールゲートウェイの登録抹消リクエストを送信しています - - - - Sending email gateway status request - メールゲートウェイの状態リクエストを送信しています - - - - Passphrase mismatch - パスフレーズが一致しません - - - - The passphrase you entered twice doesn't match. Try again. - 再度入力されたパスフレーズが一致しません。再入力してください。 - - - - Choose a passphrase - パスフレーズを選択してください - - - - You really do need a passphrase. - パスフレーズが必要です。 - - - - Address is gone - アドレスが無効になりました - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - アドレス %1 が見つかりません。既に削除していませんか? - - - - Address disabled - アドレスが無効になりました - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - エラー: 送信しようとしたアドレスは無効になっています。使用する前に「アドレス一覧」で有効にしてください。 - - - - Entry added to the Address Book. Edit the label to your liking. - アドレス帳に項目が追加されました。ラベルは自由に編集できます。 - - - - Entry added to the blacklist. Edit the label to your liking. - ブラックリストに項目が追加されました。ラベルは自由に編集できます。 - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - エラー: ブラックリストに同じアドレスを2回追加することはできません。 必要に応じて既存の名前を変更してみてください。 - - - - Moved items to trash. - アイテムをゴミ箱へ移動。 - - - - Undeleted item. - アイテムの削除を元に戻します。 - - - - Save As... - 形式を選択して保存 - - - - Write error. - 書き込みエラー。 - - - - No addresses selected. - アドレスが未選択です。 - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - 購読を削除すると、すでに受信したメッセージにアクセスできなくなります。 代わりに、購読を無効にすることもできます。 無効になった購読は新しいメッセージを受信しませんが、受信したメッセージは表示できます。 - -購読を削除してもよろしいですか? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - チャンネルを削除すると、すでに受信したメッセージにアクセスできなくなります。 代わりに、チャンネルを無効にすることもできます。 無効になったチャンネルは新しいメッセージを受信しませんが、受信したメッセージは表示できます。 - -チャンネルを削除してもよろしいですか? - - - - Do you really want to remove this avatar? - このアバターを削除してもよろしいですか? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - すでにこのアドレスのアバターを設定しています。 上書きしてもよろしいですか? - - - - Start-on-login not yet supported on your OS. - ログイン時に開始は、まだお使いのOSでサポートされていません。 - - - - Minimize-to-tray not yet supported on your OS. - トレイに最小化は、まだお使いのOSでサポートされていません。 - - - - Tray notifications not yet supported on your OS. - トレイ通知は、まだお使いのOSでサポートされていません。 - - - - Testing... - テスト中 - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - chanアドレスは仮想メーリングリストのアドレスには使用できません。 - - - - The address should start with ''BM-'' - アドレスは「BM-」から始まります - - - - The address is not typed or copied correctly (the checksum failed). - このアドレスは正しく入力、またはコピーされていません。(チェックサムが一致しません)。 - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - このアドレスのバージョン番号はこのプログラムのサポート範囲外です。Bitmessageをアップデートしてください。 - - - - The address contains invalid characters. - 入力されたアドレスは不正な文字を含んでいます。 - - - - Some data encoded in the address is too short. - このアドレスでエンコードされたデータが短すぎます。 - - - - Some data encoded in the address is too long. - このアドレスでエンコードされたデータが長過ぎます。 - - - - Some data encoded in the address is malformed. - このアドレスでエンコードされた一部のデータが不正です。 - - - - Enter an address above. - 上にアドレスを入力してください。 - - - - Address is an old type. We cannot display its past broadcasts. - アドレスが古い形式です。 過去の配信は表示できません。 - - - - There are no recent broadcasts from this address to display. - このアドレスから表示する最近の配信はありません。 - - - - You are using TCP port %1. (This can be changed in the settings). - 使用中のポート %1 (設定で変更できます)。 - - - - Bitmessage - Bitmessage - - - - Identities - アドレス一覧 - - - - New Identity - 新しいアドレス - - - - Search - 検索 - - - - All - 全て - - - - To - 宛先 - - - - From - 送信元 - - - - Subject - 題名 - - - - Message - メッセージ - - - - Received - 受信日時 - - - - Messages - メッセージ - - - - Address book - アドレス帳 - - - - Address - アドレス - - - - Add Contact - 連絡先を追加 - - - - Fetch Namecoin ID - namecoin IDを取得 - - - - Subject: - 題名: - - - - From: - 送信元: - - - - To: - 宛先: - - - - Send ordinary Message - 通常のメッセージを送信 - - - - Send Message to your Subscribers - 購読者にメッセージを送信 - - - - TTL: - TTL: - - - - Subscriptions - 購読リスト - - - - Add new Subscription - 購読先を追加 - - - - Chans - チャンネル - - - - Add Chan - チャンネルを追加 - - - - File - ファイル - - - - Settings - 設定 - - - - Help - ヘルプ - - - - Import keys - 鍵をインポート - - - - Manage keys - 鍵を管理 - - - - Ctrl+Q - Ctrrl+Q - - - - F1 - F1 - - - - Contact support - お問い合わせサポート - - - - About - 概要 - - - - Regenerate deterministic addresses - deterministicアドレスを再生成 - - - - Delete all trashed messages - ゴミ箱のメッセージを全て削除する - - - - Join / Create chan - チャンネルに参加 / 作成 - - - - All accounts - すべてのアカウント - - - - Zoom level %1% - ズーム レベル %1% - - - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. エラー: 同じアドレスを複数リストに追加する事はできません。既存の項目をリネームしてください。 - - Add new entry - 新しい項目を追加 + + Passphrase mismatch + パスフレーズが一致しません - - Display the %1 recent broadcast(s) from this address. - このアドレスから%1の最新の配信を表示します。 + + The passphrase you entered twice doesn't match. Try again. + 再度入力されたパスフレーズが一致しません。再入力してください。 - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - 新しいバージョンの PyBitmessage が利用可能です: %1。 https://github.com/Bitmessage/PyBitmessage/releases/latest からダウンロードしてください + + Choose a passphrase + パスフレーズを選択してください - - Waiting for PoW to finish... %1% - PoW(証明)が完了するのを待っています... %1% + + You really do need a passphrase. + パスフレーズが必要です。 - - Shutting down Pybitmessage... %1% - Pybitmessageをシャットダウンしています... %1% + + All done. Closing user interface... + 完了しました。ユーザーインターフェースを閉じています。 - - Waiting for objects to be sent... %1% - オブジェクトの送信待ち... %1% + + Address is gone + アドレスが無効になりました - - Saving settings... %1% - 設定を保存しています... %1% + + Bitmessage cannot find your address %1. Perhaps you removed it? + アドレス %1 が見つかりません。既に削除していませんか? - - Shutting down core... %1% - コアをシャットダウンしています... %1% + + Address disabled + アドレスが無効になりました - - Stopping notifications... %1% - 通知を停止しています... %1% + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + エラー: 送信しようとしたアドレスは無効になっています。使用する前に「アドレス一覧」で有効にしてください。 - - Shutdown imminent... %1% - すぐにシャットダウンします... %1% - - - - %n hour(s) - %n 時間 - - - - %n day(s) - %n 日 + + Entry added to the Address Book. Edit the label to your liking. + アドレス帳に項目が追加されました。ラベルは自由に編集できます。 - - Shutting down PyBitmessage... %1% - PyBitmessageをシャットダウンしています... %1% + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + アイテムをゴミ箱へ移動。ゴミ箱の内容を表示する画面はありませんが、もし元に戻したくなった場合に備えてディスク上に残されます。 - + + Save As... + 形式を選択して保存 + + + + Write error. + 書き込みエラー。 + + + + No addresses selected. + アドレスが未選択です。 + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implemented for your operating system. + 現在のOS上で未実装、または実装できないためオプションは無効化されました。 + + + + Testing... + テスト中 + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + chanアドレスは仮想メーリングリストのアドレスには使用できません。 + + + + The address should start with ''BM-'' + アドレスは「BM-」から始まります + + + + The address is not typed or copied correctly (the checksum failed). + このアドレスは正しく入力、またはコピーされていません。(チェックサムが一致しません)。 + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + このアドレスのバージョン番号はこのプログラムのサポート範囲外です。Bitmessageをアップデートしてください。 + + + + The address contains invalid characters. + 入力されたアドレスは不正な文字を含んでいます。 + + + + Some data encoded in the address is too short. + このアドレスでエンコードされたデータが短すぎます。 + + + + Some data encoded in the address is too long. + このアドレスでエンコードされたデータが長過ぎます。 + + + + You are using TCP port %1. (This can be changed in the settings). + 使用中のポート %1 (設定で変更できます)。 + + + + Bitmessage + + + + + Search + 検索 + + + + All + 全て + + + + To + 宛先 + + + + From + 送信元 + + + + Subject + 題名 + + + + Message + メッセージ + + + + Received + 受信日時 + + + + Inbox + 受信箱 + + + + Load from Address book + アドレス帳から読み込み + + + + Fetch Namecoin ID + namecoin IDを取得 + + + + Message: + メッセージ: + + + + Subject: + 題名: + + + + Send to one or more specific people + 一人、または複数のユーザーへ送信 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + + To: + 宛先: + + + + From: + 送信元: + + + + Broadcast to everyone who is subscribed to your address + 自分のアドレスを購読しているユーザー全員へ配信する + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + broadcastはあなたのアドレスのみで暗号化されます。あなたのアドレスを知っている人は全て読むことができます。 + + + + Status + 状態 + + + Sent - 送信済 + 送信済み - - Generating one new address - 新しいアドレスを生成しています + + Label (not shown to anyone) + ラベル(他の人からは見えません) - - Done generating address. Doing work necessary to broadcast it... - アドレスの生成を完了しました。 配信に必要な処理を行っています... + + Address + アドレス - - Generating %1 new addresses. - %1 の新しいアドレスを生成しています。 + + Stream + ストリーム - - %1 is already in 'Your Identities'. Not adding it again. - %1はすでに「アドレス一覧」にあります。 もう一度追加できません。 + + Your Identities + アドレス一覧 - - Done generating address - アドレスの生成を完了しました + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + 他のユーザが送信した「broadcastメッセージ」を購読できます。メッセージは受信箱に表示されます。このリストのアドレスはブラックリストより優先されます。 - - SOCKS5 Authentication problem: %1 - + + Add new Subscription + 購読先を追加 - - Disk full - ディスクがいっぱいです + + Label + ラベル - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 + + Subscriptions + 購読リスト - - Error! Could not find sender address (your address) in the keys.dat file. - エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + アドレス帳は他のユーザのBitmessageアドレスにラベルや名前をつけることで受信箱を見やすくします。「追加」ボタンを押すか受信箱でメッセージを右クリックしてください。 - - Doing work necessary to send broadcast... - 配信に必要な処理を行っています... + + Name or Label + 名前、ラベル - - Broadcast sent on %1 - 配信が送信されました %1 + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + ブラックリストを使用(全てのメッセージを受信してブラックリストと一致する物だけ除外) - - Encryption key was requested earlier. - 暗号鍵は以前にリクエストされました。 + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + ホワイトリストを使用(全てのメッセージを受信拒否してホワイトリストと一致する物だけ許可) - - Sending a request for the recipient's encryption key. - 受信者の暗号鍵のリクエストを送信します。 + + Blacklist + ブラックリスト - - Looking up the receiver's public key - 受信者の公開鍵を探しています + + Stream # + ストリーム # - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - 問題: メッセージに含まれた宛先のリクエストはモバイルデバイスですが、設定では許可されていません。 %1 + + Connections + 接続 - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - メッセージの送信に必要な処理を行っています。 -このようなバージョン2のアドレスには、必要な難易度はありません。 + + Total connections: 0 + 接続数: 0 - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - メッセージの送信に必要な処理を行っています。 -受信者の必要な難易度: %1 および %2 + + Since startup at asdf: + 起動してから asdf: - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - 問題: 受信者が要求している処理 (%1 および %2) は、現在あなたが設定しているよりも高い難易度です。 %3 + + Processed 0 person-to-person message. + 0 通の1対1のメッセージを処理しました。 - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 + + Processed 0 public key. + 0 件の公開鍵を処理しました。 - - Doing work necessary to send message. - メッセージの送信に必要な処理を行っています。 + + Processed 0 broadcast. + 0 件のBroadcastメッセージを処理しました。 - - Message sent. Waiting for acknowledgement. Sent on %1 - メッセージを送信しました。 確認応答を待っています。 %1 で送信しました + + Network Status + ネットワークの状態 - - Doing work necessary to request encryption key. - 暗号鍵のリクエストに必要な処理を行っています。 + + File + ファイル - - Broadcasting the public key request. This program will auto-retry if they are offline. - 公開鍵のリクエストを配信しています。 このプログラムがオフラインの場合、自動的に再試行されます。 + + Settings + 設定 - - Sending public key request. Waiting for reply. Requested at %1 - 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました + + Help + ヘルプ - - UPnP port mapping established on port %1 - ポート%1でUPnPポートマッピングが確立しました + + Import keys + 鍵をインポート - - UPnP port mapping removed - UPnPポートマッピングを削除しました + + Manage keys + 鍵を管理 - - Mark all messages as read - すべてのメッセージを既読にする + + Ctrl+Q + Ctrrl+Q - - Are you sure you would like to mark all messages read? - すべてのメッセージを既読にしてもよろしいですか? + + F1 + - - Doing work necessary to send broadcast. - 配信に必要な処理を行っています。 + + About + 概要 - - Proof of work pending - PoW(証明)を待っています + + Regenerate deterministic addresses + 「決定論的アドレス」ともヤクセルが + deterministicアドレスを再生成 - - - %n object(s) pending proof of work - %n オブジェクトが証明待ち (PoW) - - - - %n object(s) waiting to be distributed - %n オブジェクトが配布待ち - - - - Wait until these tasks finish? - これらのタスクが完了するまで待ちますか? - - - - Problem communicating with proxy: %1. Please check your network settings. - プロキシとの通信に問題があります: %1。 ネットワーク設定を確認してください。 - - - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - SOCKS5認証に問題があります: %1。 SOCKS5の設定を確認してください。 - - - - The time on your computer, %1, may be wrong. Please verify your settings. - お使いのコンピュータの時間 %1 は間違っている可能性があります。 設定を確認してください。 - - - - The name %1 was not found. - 名前 %1 が見つかりませんでした。 - - - - The namecoin query failed (%1) - namecoin のクエリに失敗しました (%1) - - - - The namecoin query failed. - namecoin のクエリに失敗しました。 - - - - The name %1 has no valid JSON data. - 名前 %1 は有効な JSON データがありません。 - - - - The name %1 has no associated Bitmessage address. - 名前 %1 は関連付けられた Bitmessage アドレスがありません。 - - - - Success! Namecoind version %1 running. - 成功! Namecoind バージョン %1 が実行中。 - - - - Success! NMControll is up and running. - 成功! NMControll が開始して実行中です。 - - - - Couldn't understand NMControl. - NMControl を理解できませんでした。 - - - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - - - - Set notification sound... - 通知音を設定... - - - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -簡単で安全な Bitmessage へようこそ -* 他の人にメッセージを送ります -* Twitter のようなブロードキャストメッセージを送信します -* 他の人と一緒にチャン(ネル)で議論します - - - - - not recommended for chans - チャンネルにはお勧めしません - - - - Quiet Mode - マナーモード - - - - Problems connecting? Try enabling UPnP in the Network Settings - 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください - - - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Bitmessage の代わりにメールを送信しようとしています。 これは、ゲートウェイに登録する必要があります。 登録しますか? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - エラー: BitmessageのアドレスはBM-で始まります。 受信者のアドレス %1 を確認してください - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - エラー: 受信者のアドレス %1 は正しく入力、またはコピーされていません。確認して下さい。 - - - - Error: The recipient address %1 contains invalid characters. Please check it. - エラー: 受信者のアドレス %1 は不正な文字を含んでいます。確認して下さい。 - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - エラー: 受信者アドレスのバージョン %1 は高すぎます。 Bitmessageソフトウェアをアップグレードする必要があるか、連絡先が賢明になっているかのいずれかです。 - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - エラー: アドレス %1 でエンコードされたデータが短すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - エラー: 受信者のアドレス %1 でエンコードされたデータが短すぎます。連絡先のソフトウェアが何かしら誤っている可能性があります。 - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - エラー: 受信者のアドレス %1 でエンコードされたデータの一部が不正です。連絡先のソフトウェアが何かしら誤っている可能性があります。 - - - - Error: Something is wrong with the recipient address %1. - エラー: 受信者のアドレス %1 には何かしら誤りがあります。 - - - - Error: %1 - - - - - From %1 - 送信元 %1 - - - - Synchronisation pending - 同期を保留しています - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessageはネットワークと同期していません。%n のオブジェクトをダウンロードする必要があります。 今、終了すると、配送が遅れることがあります。 同期が完了するまで待ちますか? - - - - Not connected - 未接続 - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessageはネットワークに接続していません。 今、終了すると、配送が遅れることがあります。 接続して、同期が完了するまで待ちますか? - - - - Waiting for network connection... - ネットワーク接続を待っています... - - - - Waiting for finishing synchronisation... - 同期の完了を待っています... - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - すでにこのアドレス帳エントリの通知音を設定しています。 上書きしてもよろしいですか? - - - - MessageView - - - Follow external link - 外部リンクをフォロー - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - リンク "%1" はブラウザで開きます。 セキュリティリスクの可能性があります。匿名性がなくなったり、悪意のあるデータをダウンロードする可能性があります。 よろしいですか? - - - - HTML detected, click here to display - HTMLが検出されました。ここをクリックすると表示します - - - - Click here to disable HTML - ここをクリックするとHTMLを無効にします - - - - MsgDecode - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - メッセージのエンコードが不明です。 -Bitmessageをアップグレードする必要があるかもしれません。 + + Delete all trashed messages + ゴミ箱のメッセージを全て削除する - - Unknown encoding - 不明なエンコード + + Join / Create chan + chanに参加 / 作成 @@ -1592,9 +913,9 @@ The 'Random Number' option is selected by default but deterministic ad アドレスの生成に乱数ジェネレーターを使う - - Use a passphrase to make addresses - アドレスの作成にパスフレーズを使う + + Use a passpharase to make addresses + Use yee passpharase to make arrddresses @@ -1608,8 +929,8 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 4 - アドレスのバージョン番号: 4 + Address version number: 3 + アドレスのバージョン番号: 3 @@ -1666,29 +987,29 @@ The 'Random Number' option is selected by default but deterministic ad (saves you some bandwidth and processing power) (帯域と処理能力を節約する) + + + Use a passphrase to make addresses + アドレスの作成にパスフレーズを使う + NewSubscriptionDialog - + Add new entry 新しい項目を追加 - + Label ラベル - + Address アドレス - - - Enter an address above. - 上にアドレスを入力してください。 - SpecialAddressBehaviorDialog @@ -1721,85 +1042,42 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog - + + PyBitmessage + + + + + version ? + Version ? + + + About 概要 - - PyBitmessage - PyBitmessage + + Copyright © 2013 Jonathan Warren + - - version ? - バージョン? - - - + <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> - <html><head/><body><p>MIT/X11 ソフトウェアライセンスに基づいて配布されます。 <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> + - + This is Beta software. このソフトウェアはベータ版です。 - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage 開発者</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - ブラックリストを使用(全てのメッセージを受信してブラックリストと一致する物だけ除外) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - ホワイトリストを使用(全てのメッセージを受信拒否してホワイトリストと一致する物だけ許可) - - - - Add new entry - 新しい項目を追加 - - - - Name or Label - 名前、ラベル - - - - Address - アドレス - - - - Blacklist - ブラックリスト - - - - Whitelist - ホワイトリスト - connectDialog Bitmessage - Bitmessage + @@ -1826,8 +1104,8 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> @@ -1848,9 +1126,9 @@ The 'Random Number' option is selected by default but deterministic ad 他のpeerへ接続されていません。 - - 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. - 発信接続のために1つ以上のピアへ接続を行っていますが、まだ着信接続を受け取っていません。ファイアーウォールかホームルーターが外部からこのコンピューターへのTCP接続を受け取れるように設定されていないかも知れません。Bitmessageは正常に動作しますが、外部からの接続を許可してより良く接続されたノードになることはBitmessageネットワークへの助けになります。 + + 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 foward 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. + Yee have made least one connection to a peer pirate usin' outgoing connection but yee not yet received any incoming connections. Yee firewall, witches nest, or home router probably shant configured to foward incoming TCP connections to yee computer. Bitmessage be workin' just fine but it help fellow pirates if yee allowed for incoming connections and will help yee be a better-connected node matey. @@ -1862,163 +1140,10 @@ The 'Random Number' option is selected by default but deterministic ad You do have connections with other peers and your firewall is correctly configured. ファイアーウォールを適切に設定し、他のpeerへ接続してください。 - - - networkstatus - - Total connections: - 接続数: - - - - Since startup: - 起動日時: - - - - Processed 0 person-to-person messages. - 0 通の1対1のメッセージを処理しました。 - - - - Processed 0 public keys. - 0 件の公開鍵を処理しました。 - - - - Processed 0 broadcasts. - 0 件の配信を処理しました。 - - - - Inventory lookups per second: 0 - 毎秒のインベントリ検索: 0 - - - - Objects to be synced: - 同期する必要のあるオブジェクト: - - - - Stream # - ストリーム # - - - - Connections - - - - - Since startup on %1 - 起動日時 %1 - - - - Down: %1/s Total: %2 - ダウン: %1/秒 合計: %2 - - - - Up: %1/s Total: %2 - アップ: %1/秒 合計: %2 - - - - Total Connections: %1 - 接続数: %1 - - - - Inventory lookups per second: %1 - 毎秒のインベントリ検索: %1 - - - - Up: 0 kB/s - アップ: 0 kB/秒 - - - - Down: 0 kB/s - ダウン: 0 kB/秒 - - - - Network Status - ネットワークの状態 - - - - byte(s) - バイト - - - - Object(s) to be synced: %n - 同期する必要のあるオブジェクト: %n - - - - Processed %n person-to-person message(s). - %n 通の1対1のメッセージを処理しました。 - - - - Processed %n broadcast message(s). - %n 件の配信を処理しました。 - - - - Processed %n public key(s). - %n 件の公開鍵を処理しました。 - - - - Peer - ピア - - - - IP address or hostname - IP アドレスまたはホスト名 - - - - Rating - 評価 - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage は、個々のノードへの接続試行の成功率を追跡します。 率は -1 から 1 の範囲で、将来ノードを選択する可能性に影響します - - - - User agent - ユーザーエージェント - - - - Peer's self-reported software - ピアの自己報告ソフトウェア - - - - TLS - TLS - - - - Connection encryption - 接続暗号化 - - - - List of streams negotiated between you and the peer - あなたとピアの間でネゴシエーションしたストリームのリスト + + 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. + 発信接続のために1つ以上のピアへ接続を行っていますが、まだ着信接続を受け取っていません。ファイアーウォールかホームルーターが外部からこのコンピューターへのTCP接続を受け取れるように設定されていないかも知れません。Bitmessageは正常に動作しますが、外部からの接続を許可してより良く接続されたノードになることはBitmessageネットワークへの助けになります。 @@ -2026,167 +1151,98 @@ The 'Random Number' option is selected by default but deterministic ad Dialog - + ダイアログ Create a new chan - + 新しいchanを作成 Join a chan - + chanに参加 Create a chan - + chanを作成 <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + <html><head/><body><p>chan名を入力してください。(強くて一意のパスフレーズのように)十分に複雑なchan名を選び、あなたの友人たちがそれを他人に教えない限りchanはセキュアでプライベートです。あなたと他の誰かが同じ名前のchanを作成した場合、現状では同じchanになる可能性が非常に高い。</p></body></html> Chan name: - + Chan名: <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + <html><head/><body><p>chanは人々のグループに復号鍵を共有されることで存在します。chanで使われる鍵とBitmessageアドレスは読みやすい単語、またはフレーズ(chan名)から生成されます。chanに居る人たちへメッセージを送るには、通常の一対一のメッセージをchanアドレスへ送ります。</p><p>chansは実験的機能で、内容を管理するモデレーターを設けることはできません。</p></body></html> Chan bitmessage address: - - - - - Create or join a chan - チャンネルを作成または参加 - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>グループの人が同じ復号鍵を共有するときに、チャンネルが存在します。 チャンネルによって使用される鍵と bitmessage アドレスは、人にやさしい単語や語句 (チャンネル名) から生成されます。 チャンネルの全員にメッセージを送信するには、チャンネルのアドレスにメッセージを送信します。</p><p>チャンネルは実験的で完全に調整不能です。</p><p>あなたのチャンネルの名前を入力してください。 (強くて固有のパスフレーズのような) 十分に複雑なチャンネルの名前を選んで、友人の誰もそれを公に共有しない場合に、そのチャンネルは安全でプライベートになります。 しかし、あなたと他の誰かの両方で同じ名前のチャンネルを作成すると、同じチャンネルが共有されます。</p></body></html> - - - - Chan passphrase/name: - - - - - Optional, for advanced usage - オプション、高度な使い方 - - - - Chan address - チャンネル アドレス - - - - Please input chan name/passphrase: - チャンネル名/パスフレーズを入力してください: - - - - newchandialog - - - Successfully created / joined chan %1 - チャンネル %1 を正常に作成 / 参加しました - - - - Chan creation / joining failed - チャンネルの作成 / 参加に失敗しました - - - - Chan creation / joining cancelled - チャンネルの作成 / 参加をキャンセルしました - - - - proofofwork - - - C PoW module built successfully. - C PoW モジュールのビルドに成功しました。 - - - - Failed to build C PoW module. Please build it manually. - C PoW モジュールのビルドに失敗しました。手動でビルドしてください。 - - - - C PoW module unavailable. Please build it. - C PoW モジュールが利用できません。ビルドしてください。 - - - - qrcodeDialog - - - QR-code - QR コード + chanのbitmessageアドレス: regenerateAddressesDialog - + Regenerate Existing Addresses 既存のアドレスを再生成する - + Regenerate existing addresses 既存のアドレスを再生成する - + Passphrase パスフレーズ - + Number of addresses to make based on your passphrase: パスフレーズから生成されたアドレスの数: - - Address version number: + + Address version Number: アドレスのバージョン番号: - + + 3 + + + + Stream number: ストリーム数: - + 1 - 1 + - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter アドレスを1、2文字短くするために数分間追加の計算処理を行う - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. もしあなたが初めてアドレスを作ったのであればこのボックスをチェックする必要があります。(そうでない場合はしないでください)。 - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. もし以前にdeterministicアドレスを作ったことがあり、何かしらのトラブル(ハードディスクの故障のような)でそれを紛失していた場合、ここで再生成することができます。もし乱数でアドレスを作っていたのであればこのフォームは再生成には使えません。 @@ -2194,310 +1250,214 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings 設定 - + Start Bitmessage on user login ユーザのログイン時にBitmessageを起動 - - Tray - トレイ - - - + Start Bitmessage in the tray (don't show main window) Bitmessageをトレイ内で起動する(メインウィンドウを表示しない) - + Minimize to tray タスクトレイへ最小化 - - Close to tray - トレイに閉じる - - - + Show notification when message received メッセージの受信時に通知する - + Run in Portable Mode ポータブルモードで実行 - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. ポータブルモード時、メッセージと設定ファイルは通常のアプリケーションデータのフォルダではなく同じディレクトリに保存されます。これによりBitmessageをUSBドライブから実行できます。 - - Willingly include unencrypted destination address when sending to a mobile device - 携帯端末にメッセージを送る時は暗号化されていないアドレスを許可する - - - - Use Identicons - Identiconsを使用する - - - - Reply below Quote - 下に返信 - - - - Interface Language - インターフェイス言語 - - - - System Settings - system - システム設定 - - - + User Interface ユーザインターフェース - + Listening port リスニングポート - + Listen for connections on port: 接続を待つポート: - - UPnP: - UPnP: - - - - Bandwidth limit - 帯域幅の制限 - - - - Maximum download rate (kB/s): [0: unlimited] - 最大ダウンロード速度 (kB/秒): [0: 無制限] - - - - Maximum upload rate (kB/s): [0: unlimited] - 最大アップロード速度 (kB/秒): [0: 無制限] - - - + Proxy server / Tor プロキシサーバー/Tor - + Type: タイプ: - - Server hostname: - サーバーホスト名: - - - - Port: - ポート: - - - - Authentication - 認証 - - - - Username: - ユーザー名: - - - - Pass: - パス: - - - - Listen for incoming connections when using proxy - プロキシ使用時に外部からの接続を待機する - - - + none 無し - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + + Server hostname: + サーバーホスト名: + + + + Port: + ポート: + + + + Authentication + 認証 + + + + Username: + ユーザー名: + + + + Pass: + パス: + + + Network Settings ネットワーク設定 - - Total difficulty: - 全体の難易度: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - 「全体の難易度」は完全に全てのメッセージに影響します。この値を二倍にすると処理量も二倍になります。 - - - - Small message difficulty: - 小さいメッセージの難易度: - - - + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. 誰かがあなたにメッセージを送る時、相手のコンピューターはいくらか計算処理を行います。処理の難易度はデフォルトでは1です。この値を変更すると新しいアドレスではこのデフォルト値を引き上げることができます。その場合、新しいアドレスはメッセージの送信者により高い難易度を要求します。例外もあります: 友人や知り合いをアドレス帳に登録すると、Bitmessageは次にメッセージを送る際、自動的に要求される処理の難易度を最低限の1で済むように通知します。 - + + Total difficulty: + 全体の難易度: + + + + Small message difficulty: + 小さいメッセージの難易度: + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. 「小さいメッセージの難易度」は小さいメッセージを行う時にだけ影響します。この値を二倍にすれば小さなメッセージに必要な処理の難易度は二倍になりますが、実際にはデータ量の多いメッセージには影響しません。 - + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + 「全体の難易度」は完全に全てのメッセージに影響します。この値を二倍にすると処理量も二倍になります。 + + + Demanded difficulty 要求される難易度 - + + Willingly include unencrypted destination address when sending to a mobile device + 携帯端末にメッセージを送る時は暗号化されていないアドレスを許可する + + + + Override automatic language localization (use countycode or language code, e.g. 'en_US' or 'en'): + 自動的に設定された言語・地域を上書きする(国コード、または言語コードを入力。例:「en_US」または「en」): + + + + Listen for incoming connections when using proxy + プロキシ使用時に外部からの接続を待機する + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. ここでは他のユーザーへメッセージを送る際に行うことを許可する処理量の上限を設定します。0を設定するとどんな量でも許容します。 - + Maximum acceptable total difficulty: 許可する難易度の上限: - + Maximum acceptable small message difficulty: 小さなメッセージに許可する難易度の上限: - + Max acceptable difficulty 許可する最大の難易度 - - Hardware GPU acceleration (OpenCL) - - - - + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> <html><head/><body><p>Bitmessageはアドレスを読みやすくするため、NamecoinというBitcoinベースの別のプログラムを利用できます。例えば、あなたの友人に長いBitmessageアドレスを伝える代わりに、単純に<span style=" font-style:italic;">テスト</span>でメッセージを送るよう伝えることができます。</p><p>(Bitmessageアドレスを独自にNamecoinにするのはかなり難しいです)。</p><p>Bitmessageは直接namecoindを使うか、nmcontrolインスタンスを使うことができます。</p></body></html> - + Host: ホスト: - + Password: パスワード: - + Test テスト - + Connect to: 接続先: - + Namecoind Namecoind - + NMControl NMControl - + Namecoin integration Namecoin連携 - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>デフォルトでは、あなたが誰かにメッセージを送信して、相手が 2 日以上オフラインになっている場合、 Bitmessage はさらに 2 日後にメッセージを再送信します。 これは指数関数的後退で永遠に続きます。 受信者がそれらを確認するまで、メッセージは 5、10、20 日後に再送信されます。 ここで Bitmessage が一定の日数または月数後に諦める数を入力して、その動作を変更することができます。</p><p>デフォルトの動作は、この入力フィールドを空白のままにします。 </p></body></html> - - - - Give up after - 次の期間後に諦める - - - - and - - - - - days - - - - - months. - ヶ月。 - - - - Resends Expire - 再送信の期限 - - - - Hide connection notifications - 接続通知を非表示 - - - - Maximum outbound connections: [0: none] - 最大アウトバウンド接続: [0: なし] - - - - Hardware GPU acceleration (OpenCL): - ハードウェア GPU アクセラレーション (OpenCL): - - \ No newline at end of file + diff --git a/src/translations/bitmessage_nb.ts b/src/translations/bitmessage_nb.ts deleted file mode 100644 index 21f641c0..00000000 --- a/src/translations/bitmessage_nb.ts +++ /dev/null @@ -1,1898 +0,0 @@ - - - AddAddressDialog - - - Add new entry - - - - - Label - - - - - Address - - - - - EmailGatewayDialog - - - Email gateway - - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - - - MainWindow - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Address Book - - - - - Add sender to your Blacklist - - - - - Move to Trash - - - - - Undelete - - - - - View HTML code as formatted text - - - - - Save message as... - - - - - Mark Unread - - - - - New - - - - - Enable - - - - - Disable - - - - - Set avatar... - - - - - Copy address to clipboard - - - - - Special address behavior... - - - - - Email gateway - - - - - Delete - - - - - Send message to this address - - - - - Subscribe to this address - - - - - Add New Address - - - - - Copy destination address to clipboard - - - - - Force send - - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - - - - - 1 hour - - - - - %1 hours - - - - - %1 days - - - - - Waiting for their encryption key. Will request it again soon. - - - - - Encryption key request queued. - - - - - Queued. - - - - - Message sent. Waiting for acknowledgement. Sent at %1 - - - - - Message sent. Sent at %1 - - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - - - - - Broadcast queued. - - - - - Broadcast on %1 - - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - - - - - Forced difficulty override. Send should start soon. - - - - - Unknown status: %1 %2 - - - - - Not Connected - - - - - Show Bitmessage - - - - - Send - - - - - Subscribe - - - - - Channel - - - - - Quit - - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - - - - - Open keys.dat? - - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - Delete trash? - - - - - Are you sure you want to delete all trashed messages? - - - - - bad passphrase - - - - - You must type your passphrase. If you don't have one then this is not the form for you. - - - - - Bad address version number - - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - - - - - Connected - - - - - Message trashed - - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - - - - - Address version number - - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Stream number - - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - - - - Message queued. - - - - - Your 'To' field is empty. - - - - - Right click one or more entries in your address book and select 'Send message to this address'. - - - - - Fetched address from namecoin identity. - - - - - New Message - - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - - - - - The address you entered was invalid. Ignoring it. - - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - - - - - You must restart Bitmessage for the port number change to take effect. - - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - - - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - All done. Closing user interface... - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - - - - - Write error. - - - - - No addresses selected. - - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - - - - - Identities - - - - - New Identity - - - - - Search - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - Received - - - - - Messages - - - - - Address book - - - - - Address - - - - - Add Contact - - - - - Fetch Namecoin ID - - - - - Subject: - - - - - From: - - - - - To: - - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - X days - - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - Network Status - - - - - File - - - - - Settings - - - - - Help - - - - - Import keys - - - - - Manage keys - - - - - Ctrl+Q - - - - - F1 - - - - - Contact support - - - - - About - - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - - - - - Zoom level %1% - - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - - - - - Display the %1 recent broadcast(s) from this address. - - - - - NewAddressDialog - - - Create new Address - - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - - Use a random number generator to make an address - - - - - Use a passphrase to make addresses - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - Make deterministic addresses - - - - - Address version number: 4 - - - - - In addition to your passphrase, you must remember these numbers: - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Stream number: 1 - - - - - Retype passphrase - - - - - Randomly generate address - - - - - Label (not shown to anyone except you) - - - - - Use the most available stream - - - - - (best if this is the first of many addresses you will create) - - - - - Use the same stream as an existing address - - - - - (saves you some bandwidth and processing power) - - - - - NewSubscriptionDialog - - - Add new entry - - - - - Label - - - - - Address - - - - - Enter an address above. - - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - - - - - Behave as a normal address - - - - - Behave as a pseudo-mailing-list address - - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - - - - - Name of the pseudo-mailing-list: - - - - - aboutDialog - - - About - - - - - PyBitmessage - - - - - version ? - - - - - <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> - - - - - <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> - - - - - This is Beta software. - - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - - - - - Name or Label - - - - - Address - - - - - Blacklist - - - - - Whitelist - - - - - connectDialog - - - Bitmessage - - - - - Bitmessage won't connect to anyone until you let it. - - - - - Connect now - - - - - Let me configure special network settings first - - - - - helpDialog - - - Help - - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - - - - - iconGlossaryDialog - - - Icon Glossary - - - - - You have no connections with other peers. - - - - - 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. - - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - - - - - networkstatus - - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Objects to be synced: %1 - - - - - Processed %1 person-to-person messages. - - - - - Processed %1 broadcast messages. - - - - - Processed %1 public keys. - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - newChanDialog - - - Dialog - - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - - - - - Regenerate existing addresses - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Address version number: - - - - - Stream number: - - - - - 1 - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - - - - - settingsDialog - - - Settings - - - - - Start Bitmessage on user login - - - - - Tray - - - - - Start Bitmessage in the tray (don't show main window) - - - - - Minimize to tray - - - - - Close to tray - - - - - Show notification when message received - - - - - Run in Portable Mode - - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - - - - - Willingly include unencrypted destination address when sending to a mobile device - - - - - Use Identicons - - - - - Reply below Quote - - - - - Interface Language - - - - - System Settings - system - - - - - Pirate English - en_pirate - - - - - Other (set in keys.dat) - other - - - - - User Interface - - - - - Listening port - - - - - Listen for connections on port: - - - - - UPnP: - - - - - Bandwidth limit - - - - - Maximum download rate (kB/s): [0: unlimited] - - - - - Maximum upload rate (kB/s): [0: unlimited] - - - - - Proxy server / Tor - - - - - Type: - - - - - Server hostname: - - - - - Port: - - - - - Authentication - - - - - Username: - - - - - Pass: - - - - - Listen for incoming connections when using proxy - - - - - none - - - - - SOCKS4a - - - - - SOCKS5 - - - - - Network Settings - - - - - Total difficulty: - - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - - Small message difficulty: - - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - - - - - Maximum acceptable small message difficulty: - - - - - Max acceptable difficulty - - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - - - - - Password: - - - - - Test - - - - - Connect to: - - - - - Namecoind - - - - - NMControl - - - - - Namecoin integration - - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - - Give up after - - - - - and - - - - - days - - - - - months. - - - - - Resends Expire - - - - \ No newline at end of file diff --git a/src/translations/bitmessage_nl.pro b/src/translations/bitmessage_nl.pro new file mode 100644 index 00000000..950eefba --- /dev/null +++ b/src/translations/bitmessage_nl.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_nl.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_nl.qm b/src/translations/bitmessage_nl.qm index 72a7ade2..aefebc30 100644 Binary files a/src/translations/bitmessage_nl.qm and b/src/translations/bitmessage_nl.qm differ diff --git a/src/translations/bitmessage_nl.ts b/src/translations/bitmessage_nl.ts index 3e7c1640..54237fdd 100644 --- a/src/translations/bitmessage_nl.ts +++ b/src/translations/bitmessage_nl.ts @@ -1,11 +1,12 @@ - + + AddAddressDialog Add new entry - Nieuw adres toevoegen + @@ -18,1265 +19,959 @@ Adres - - EmailGatewayDialog - - - Email gateway - E-mail gateway - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Een e-mail gateway maakt het mogelijk te communiceren met e-mail gebruikers. Momenteel is enkel de Mailchuck e-mail gateway (@mailchuck.com) beschikbaar. - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - Registratie mislukt - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - Het opgegeven e-mail adres is niet beschikbaar, probeer een ander adres. Vul hieronder het nieuwe adres (inclusief @mailchuck.com) in: - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - Een e-mail gateway maakt het mogelijk te communiceren met e-mail gebruikers. Momenteel is enkel de Mailchuck e-mail gateway (@mailchuck.com) beschikbaar. -Voer het gewenste e-mail adres (inclusief @mailchuck.com) hieronder in: - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - MainWindow - - Reply to sender - Afzender beantwoordenjavascript:; - - - - Reply to channel - - - - - Add sender to your Address Book - Afzender aan uw adresboek toevoegen - - - - Add sender to your Blacklist - Afzender blokkeren - - - - Move to Trash - Verplaats naar Prullenbak - - - - Undelete - - - - - View HTML code as formatted text - Bekijk HTML als geformatteerde tekst - - - - Save message as... - Bewaar bericht als - - - - Mark Unread - Markeer Ongelezen - - - - New - Nieuw - - - - Enable - Inschakelen - - - - Disable - Uitschakelen - - - - Set avatar... - Avatar instellen - - - - Copy address to clipboard - Kopieer adres naar klembord - - - - Special address behavior... - - - - - Email gateway - E-mail gateway - - - - Delete - Verwijder - - - - Send message to this address - Stuur bericht naar dit adres - - - - Subscribe to this address - Abonneren op dit adres - - - - Add New Address - Nieuw adres toevoegen - - - - Copy destination address to clipboard - Kopieer bestemmingsadres naar klembord - - - - Force send - Forceer zenden - - - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - + + Reply + Reageer + + + + Add sender to your Address Book + + + + + Move to Trash + Verplaats naar Prullenbak + + + + View HTML code as formatted text + Bekijk HTML als geformatteerde tekst + + + + Save message as... + Bewaar bericht als + + + + Mark Unread + Markeer Ongelezen + + + + New + Nieuw + + + + Enable + Inschakelen + + + + Disable + Uitschakelen + + + + Copy address to clipboard + Kopieer adres naar klembord + + + + Special address behavior... + + + + + Send message to this address + Stuur bericht naar dit adres + + + + Subscribe to this address + + + + + Add New Address + Nieuw adres toevoegen + + + + Delete + Verwijder + + + + Copy destination address to clipboard + Kopieer bestemmingsadres naar klembord + + + + Force send + Forceer zenden + + + + Add new entry + + + + + Since startup on %1 + + + + Waiting for their encryption key. Will request it again soon. - Aan het wachten up hun encryptie sleutel. Zal binnenkort opnieuw proberen. + - + Encryption key request queued. - Encryptie sleutel aanvraag toegevoegd aan de wachtrij + - + Queued. In wachtrij. - + Message sent. Waiting for acknowledgement. Sent at %1 Bericht verzonden. Wachten op bevestiging. Verzonden op %1 - + Message sent. Sent at %1 Bericht verzonden. Verzonden op %1 - + Need to do work to send message. Work is queued. - + Acknowledgement of the message received %1 Bevestiging van het bericht ontvangen op %1 - + Broadcast queued. - + Broadcast on %1 - + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - + Forced difficulty override. Send should start soon. - + Unknown status: %1 %2 Status onbekend: %1 %2 - + Not Connected Niet Verbonden - + Show Bitmessage Toon Bitmessage - + Send Verzend - + Subscribe Abonneer - - Channel - + + Address Book + Adresboek - + Quit Sluiten - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. - + Open keys.dat? keys.dat openen? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - + Delete trash? Prullenbak legen? - + Are you sure you want to delete all trashed messages? - + bad passphrase verkeerd wachtwoord - + You must type your passphrase. If you don't have one then this is not the form for you. - - Bad address version number - Slechte adres versienummer - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - + Chan name needed - + You didn't enter a chan name. - + Address already present - + Could not add chan because it appears to already be one of your identities. - + Success Gelukt - + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - + Address too new Adres te nieuw - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - + Address invalid Adres ongeldig - + That Bitmessage address is not valid. Dat Bitmessage adres is niet geldig. - + Address does not match chan name - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. - + Successfully joined chan. - + + Processed %1 person-to-person messages. + Verwerkt %1 peer-to-peer-bericht(en). + + + + Processed %1 broadcast messages. + Verwerkt %1 broadcast-bericht(en). + + + + Processed %1 public keys. + Verwerkt %1 publieke sleutel(s). + + + + Total Connections: %1 + Aantal Connecties: %1 + + + Connection lost Verbinding verloren - + Connected Verbonden - + Message trashed Bericht weggegooit - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - Bericht te lang - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - + Error: Bitmessage addresses start with BM- Please check %1 - + Error: The address %1 is not typed or copied correctly. Please check it. - + Error: The address %1 contains invalid characters. Please check it. - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - + Error: Something is wrong with the address %1. - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - + Address version number Adres versienummer - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - + Stream number - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - Message queued. - - - - + Your 'To' field is empty. - + Right click one or more entries in your address book and select 'Send message to this address'. - + Fetched address from namecoin identity. - + + Work is queued. %1 + + + + New Message Nieuw Bericht - + From Van - - Sending email gateway registration request - - - - + Address is valid. Adres is geldig. - + The address you entered was invalid. Ignoring it. Het ingevoerd adres is ongeldig. Worden genegeerd. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. - + Restart Herstarten - + You must restart Bitmessage for the port number change to take effect. - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - Opslaan als... - - - - Write error. - Schrijffout. - - - - No addresses selected. - Geen adressen geselecteerd. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - Testen... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - - - - - New Identity - - - - - Search - Zoeken - - - - All - Alle - - - - To - Naar - - - - From - Van - - - - Subject - Onderwerp - - - - Message - Bericht - - - - Received - Ontvangen - - - - Messages - - - - - Address book - - - - - Address - Adres - - - - Add Contact - - - - - Fetch Namecoin ID - Ophalen Namecoin ID - - - - Subject: - Onderwerp: - - - - From: - Van: - - - - To: - Naar: - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - File - Bestand - - - - Settings - Instellingen - - - - Help - Help - - - - Import keys - Importeer sleutels - - - - Manage keys - - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - - - - - About - Over - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - - - - - Zoom level %1% - - - - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - Add new entry - Nieuw adres toevoegen - - - - Display the %1 recent broadcast(s) from this address. + + Passphrase mismatch - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest + + The passphrase you entered twice doesn't match. Try again. - - Waiting for PoW to finish... %1% + + Choose a passphrase - - Shutting down Pybitmessage... %1% + + You really do need a passphrase. - - Waiting for objects to be sent... %1% + + All done. Closing user interface... - - Saving settings... %1% + + Address is gone - - Shutting down core... %1% + + Bitmessage cannot find your address %1. Perhaps you removed it? - - Stopping notifications... %1% + + Address disabled - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - %n day(s) - - - - - - - - Shutting down PyBitmessage... %1% + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - + + Entry added to the Address Book. Edit the label to your liking. + + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + + + + + Save As... + Opslaan als... + + + + Write error. + Schrijffout. + + + + No addresses selected. + Geen adressen geselecteerd. + + + + Testing... + Testen... + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + + + + + The address should start with ''BM-'' + + + + + The address is not typed or copied correctly (the checksum failed). + + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + + + + + The address contains invalid characters. + + + + + Some data encoded in the address is too short. + + + + + Some data encoded in the address is too long. + + + + + You are using TCP port %1. (This can be changed in the settings). + + + + + Bitmessage + Bitmessage + + + + Search + Zoeken + + + + All + Alle + + + + To + Naar + + + + From + Van + + + + Subject + Onderwerp + + + + Message + Bericht + + + + Received + Ontvangen + + + + Inbox + Postvak IN + + + + Load from Address book + Laden uit adresboek + + + + Fetch Namecoin ID + Ophalen Namecoin ID + + + + Message: + Bericht: + + + + Subject: + Onderwerp: + + + + Send to one or more specific people + + + + + To: + Naar: + + + + From: + Van: + + + + Broadcast to everyone who is subscribed to your address + + + + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + + + + + Status + Status + + + Sent + Verzonden + + + + Label (not shown to anyone) - - Generating one new address + + Address + Adres + + + + Stream - - Done generating address. Doing work necessary to broadcast it... + + Your Identities + Uw identiteiten + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. - - Generating %1 new addresses. + + Add new Subscription - - %1 is already in 'Your Identities'. Not adding it again. + + Label + Label + + + + Subscriptions - - Done generating address + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. - - SOCKS5 Authentication problem: %1 + + Name or Label - - Disk full + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. + + Use a Whitelist (Block all incoming messages except those on the Whitelist) - - Error! Could not find sender address (your address) in the keys.dat file. + + Blacklist + Zwarte lijst + + + + Stream # - - Doing work necessary to send broadcast... + + Connections + Verbindingen + + + + Total connections: 0 + Aantal Connecties: 0 + + + + Since startup at asdf: - - Broadcast sent on %1 + + Processed 0 person-to-person message. + Verwerkt 0 peer-to-peer-bericht. + + + + Processed 0 public key. + Verwerkt 0 broadcast-bericht. + + + + Processed 0 broadcast. + Verwerkt 0 publieke sleutel. + + + + Network Status + netwerkstatus + + + + File + Bestand + + + + Settings + Instellingen + + + + Help + Help + + + + Import keys + Importeer sleutels + + + + Manage keys - - Encryption key was requested earlier. + + Ctrl+Q + Ctrl+Q + + + + F1 + F1 + + + + About + Over + + + + Regenerate deterministic addresses - - Sending a request for the recipient's encryption key. + + Delete all trashed messages - - Looking up the receiver's public key + + Join / Create chan - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 + + Set avatar... - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. + + Bad address version number + Slechte adres versienummer + + + + Your address version number must be a number: either 3 or 4. - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 + + Your address version number must be either 3 or 4. - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 + + Inventory lookups per second: %1 - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 + + Will not resend ever - - Doing work necessary to send message. + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - Message sent. Waiting for acknowledgement. Sent on %1 + + Do you really want to remove this avatar? - - Doing work necessary to request encryption key. + + You have already set an avatar for this address. Do you really want to overwrite it? - - Broadcasting the public key request. This program will auto-retry if they are offline. + + Start-on-login not yet supported on your OS. - - Sending public key request. Waiting for reply. Requested at %1 + + Minimize-to-tray not yet supported on your OS. - - UPnP port mapping established on port %1 + + Tray notifications not yet supported on your OS. - - UPnP port mapping removed + + Enter an address above. - - Mark all messages as read + + Address is an old type. We cannot display its past broadcasts. - - Are you sure you would like to mark all messages read? + + There are no recent broadcasts from this address to display. + + + + + Display the %1 recent broadcast from this address. + + + + + Display the %1 recent broadcasts from this address. + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + + Inventory lookups per second: 0 @@ -1304,9 +999,9 @@ The 'Random Number' option is selected by default but deterministic ad Gebruik een willekeurige nummer generator om een adres te maken - - Use a passphrase to make addresses - + + Use a passpharase to make addresses + Use yee passpharase to make arrddresses @@ -1320,8 +1015,8 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 4 - Adres versienummer: 4 + Address version number: 3 + Arrddress version number: 3 @@ -1378,13 +1073,23 @@ The 'Random Number' option is selected by default but deterministic ad (saves you some bandwidth and processing power) + + + Use a passphrase to make addresses + + + + + Address version number: 4 + Adres versienummer: 4 + NewSubscriptionDialog Add new entry - Nieuw adres toevoegen + @@ -1398,7 +1103,7 @@ The 'Random Number' option is selected by default but deterministic ad - Enter an address above. + CheckBox @@ -1430,78 +1135,36 @@ The 'Random Number' option is selected by default but deterministic ad - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - - About - Over - - - + PyBitmessage PyBitmessage - + version ? - + Versie ? - + + About + Over + + + <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> - + This is Beta software. - - - blacklist - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Nieuw adres toevoegen - - - - Name or Label - - - - - Address - Adres - - - - Blacklist - - - - - Whitelist + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> @@ -1537,8 +1200,8 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> @@ -1559,9 +1222,9 @@ The 'Random Number' option is selected by default but deterministic ad - - 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. - + + 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 foward 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. + Yee have made least one connection to a peer pirate usin' outgoing connection but yee not yet received any incoming connections. Yee firewall, witches nest, or home router probably shant configured to foward incoming TCP connections to yee computer. Bitmessage be workin' just fine but it help fellow pirates if yee allowed for incoming connections and will help yee be a better-connected node matey. @@ -1573,134 +1236,11 @@ The 'Random Number' option is selected by default but deterministic ad You do have connections with other peers and your firewall is correctly configured. - - - networkstatus - - Total connections: + + 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. - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - newChanDialog @@ -1768,9 +1308,14 @@ The 'Random Number' option is selected by default but deterministic ad - - Address version number: - + + Address version Number: + Arrddress version Number: + + + + 3 + 3 @@ -1797,297 +1342,316 @@ The 'Random Number' option is selected by default but deterministic ad If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. + + + Address version number: + + settingsDialog - + Settings Instellingen - + Start Bitmessage on user login Start Bitmessage bij user login - - Tray - - - - + Start Bitmessage in the tray (don't show main window) - + Minimize to tray - - Close to tray - - - - + Show notification when message received - + Run in Portable Mode - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - + + User Interface + Gebruikersinterface + + + + Listening port + Luisterpoort + + + + Listen for connections on port: + Luister voor connecties op poort: + + + + Proxy server / Tor + Proxy server / Tor + + + + Type: + Type: + + + + none + geen + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Server hostnaam: + + + + Port: + Poort: + + + + Authentication + Authenticatie + + + + Username: + Gebruikersnaam: + + + + Pass: + Wachtwoord: + + + + Network Settings + Netwerkinstellingen + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + + + + + Total difficulty: + + + + + Small message difficulty: + + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + + + + + Demanded difficulty + + + + Willingly include unencrypted destination address when sending to a mobile device - + + Listen for incoming connections when using proxy + + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + + + + + Maximum acceptable total difficulty: + + + + + Maximum acceptable small message difficulty: + + + + + Max acceptable difficulty + + + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + + + + + Host: + + + + + Password: + Wachtwoord + + + + Test + + + + + Connect to: + + + + + Namecoind + + + + + NMControl + + + + + Namecoin integration + + + + Use Identicons - - Reply below Quote - - - - + Interface Language Interface Taal - + System Settings system - - User Interface - Gebruikersinterface - - - - Listening port - Luisterpoort - - - - Listen for connections on port: - Luister voor connecties op poort: - - - - UPnP: + + English + en - - Bandwidth limit + + Esperanto + eo - - Maximum download rate (kB/s): [0: unlimited] + + Français + fr - - Maximum upload rate (kB/s): [0: unlimited] + + Deutsch + de - - Proxy server / Tor - Proxy server / Tor - - - - Type: - Type: - - - - Server hostname: - Server hostnaam: - - - - Port: - Poort: - - - - Authentication - Authenticatie - - - - Username: - Gebruikersnaam: - - - - Pass: - Wachtwoord: - - - - Listen for incoming connections when using proxy + + Españl + es - - none - geen - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Netwerkinstellingen - - - - Total difficulty: + + русский язык + ru - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + + Norsk + no - - Small message difficulty: + + Pirate English + en_pirate - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + + Other (set in keys.dat) + other - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - - - - - Maximum acceptable small message difficulty: - - - - - Max acceptable difficulty - - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - - - - - Password: - Wachtwoord - - - - Test - - - - - Connect to: - - - - - Namecoind - - - - - NMControl - - - - - Namecoin integration - - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - + Give up after Opgeven na - + and en - + days dagen - + months. maanden. - + Resends Expire diff --git a/src/translations/bitmessage_no.pro b/src/translations/bitmessage_no.pro new file mode 100644 index 00000000..d34ad2f9 --- /dev/null +++ b/src/translations/bitmessage_no.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.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\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_no.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_no.qm b/src/translations/bitmessage_no.qm index 493d09ef..e0b248c6 100644 Binary files a/src/translations/bitmessage_no.qm and b/src/translations/bitmessage_no.qm differ diff --git a/src/translations/bitmessage_no.ts b/src/translations/bitmessage_no.ts index bb1d5278..72ce1f4f 100644 --- a/src/translations/bitmessage_no.ts +++ b/src/translations/bitmessage_no.ts @@ -5,7 +5,7 @@ Add new entry - Legg til ny oppføring + Legg til ny oppføring @@ -18,1269 +18,1107 @@ Adresse - - EmailGatewayDialog - - - Email gateway - Epost portal - - - - Register on email gateway - Registrer på epost portal - - - - Account status at email gateway - Kontoinnstillinger på epost portal - - - - Change account settings at email gateway - Endre kontoinnstillinger på epost portal - - - - Unregister from email gateway - Avregistrer fra epost portal - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - Ønsket epost adresse (inkludert @mailchuck.com): - - - - EmailGatewayRegistrationDialog - - - Registration failed: - Registrering feilet: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - Epost portal registrering - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - MainWindow - - Reply to sender - Svar til avsender - - - - Reply to channel - Svar til kanal - - - - Add sender to your Address Book - Legg til avsender i adresseboka - - - - Add sender to your Blacklist - Legg til avsender i svartelisten - - - - Move to Trash - Kast - - - - Undelete - Angre sletting - - - - View HTML code as formatted text - Vis HTML-koden som formatert tekst - - - - Save message as... - Lagre beskjed som ... - - - - Mark Unread - Merk som ulest - - - - New - Ny - - - - Enable - Aktiver - - - - Disable - Deaktiver - - - - Set avatar... - Sett ett avatar... - - - - Copy address to clipboard - Kopier adressen til utklippstavlen - - - - Special address behavior... - Spesieladressebehandling ... - - - - Email gateway - Epost portal - - - - Delete - Slett - - - - Send message to this address - Send beskjed til denne adressen - - - - Subscribe to this address - Abonner på denne adressen - - - - Add New Address - Legg til ny adresse - - - - Copy destination address to clipboard - Kopier destinasjonsadresse til utklippstavlen - - - - Force send - Tving sending - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - En av dine gamle adresser er av den første typen og derfor ikke lenger støttet: %1. Derfor kan den vel slettes? - - - - Waiting for their encryption key. Will request it again soon. - Venter på krypteringsnøkkel. Sender straks en ny forespørsel. - - - - Encryption key request queued. - Forespørsel for å finne krypteringsnøkkel er satt i kø. - - - - Queued. - Satt i kø. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Beskjed sendt. Venter på bekreftelse. Sendt %1 - - - - Message sent. Sent at %1 - Beskjed sendt. Sendt %1 - - - - Need to do work to send message. Work is queued. - Trenger å utføre arbeidsoppgave for sende beskjed. Denne er satt i kø. - - - - Acknowledgement of the message received %1 - Bekreftelse på beskjeden mottatt %1 - - - - Broadcast queued. - Kringkasting satt i kø. - - - - Broadcast on %1 - Kringkasting på %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problem: Det nødvendige arbeidet som kreves utført av mottaker er mer krevende enn det som er satt som akseptabelt. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problem: Mottakerens nøkkel kunne ikke brukes til å kryptere beskjeden. %1 - - - - Forced difficulty override. Send should start soon. - Tvunget vanskelighet overstyrt. Sender snart. - - - - Unknown status: %1 %2 - Ukjent status: %1 %2 - - - - Not Connected - Ikke tilkoblet - - - - Show Bitmessage - Vis Bitmessage - - - - Send - Send - - - - Subscribe - Abonner - - - - Channel - Kanal - - - - Quit - Avslutt - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Du kan administrere nøklene dine ved å endre filen keys.dat i samme katalog som dette programmet. Det er viktig at du tar en sikkerhetskopi av denne filen. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Du kan administrere nøklene dine ved å endre filen keys.dat lagret i - %1 -Det er viktig at du tar en sikkerhetskopi av denne filen. - - - - Open keys.dat? - Åpne keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Du kan administrere nøklene dine ved å endre filen keys.dat i samme katalog som dette programmet. Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne filen nå? (Pass på å lukke Bitmessage før du gjør endringer.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Du kan administrere dine nøkler ved å endre på filen keys.dat lagret i - %1 -Det er viktig at du tar sikkerhetskopi av denne filen. Vil du åpne denne filen nå? (Vær sikker på å få avsluttet Bitmessage før du gjør endringer.) - - - - Delete trash? - Vil du slette kastet innhold? - - - - Are you sure you want to delete all trashed messages? - Er du sikker på at du vil slette alle kastede beskjeder? - - - - bad passphrase - Dårlig passordfrase - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Du må skrive inn passordfrasen din. Hvis du ikke har en kan du ikke bruke dette skjemaet. - - - - Bad address version number - Feil adresseversjonsnummer - - - - Your address version number must be a number: either 3 or 4. - Ditt adressetypenummer må være et nummer: Enten 3 eller 4. - - - - Your address version number must be either 3 or 4. - Ditt adressetypenummer må enten være 3 eller 4. - - - - Chan name needed - Kanalnavn nødvendig - - - - You didn't enter a chan name. - Du oppga ikke noe kanalnavn. - - - - Address already present - Adressen eksisterer allerede - - - - Could not add chan because it appears to already be one of your identities. - Kunne ikke legge til kanal siden den ser ut til å allerede være lagret som en av dine identiteter. - - - - Success - Suksess - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - Opprettet ny kanal. For å la andre delta i din nye kanal gir du dem dem kanalnavnet og denne Bitmessage-adressen: %1. Denne adressen vises også i 'Dine identiteter'. - - - - Address too new - Adressen er for ny - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - Selv om Bitmessage-adressen kanskje er gyldig så er tilhørende typenummer for nytt til å håndteres. Kanskje du trenger å oppgradere Bitmessage. - - - - Address invalid - Ugyldig adresse - - - - That Bitmessage address is not valid. - Bitmessage-adressen er ikke gyldig. - - - - Address does not match chan name - Adresse stemmer ikke med kanalnavnet - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - Selv om Bitmessage-adressen du oppga var gyldig stemmer den ikke med kanalnavnet. - - - - Successfully joined chan. - Deltar nå i kanal. - - - - Connection lost - Mistet tilkobling - - - - Connected - Tilkoblet - - - - Message trashed - Beskjed kastet - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - Meldingen er for lang - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - Feil: Bitmessage-adresser begynner med BM-. Vennligst sjekk %1 - - - - Error: The address %1 is not typed or copied correctly. Please check it. - Feil: Adressen %1 er skrevet eller kopiert inn feil. Vennligst sjekk den. - - - - Error: The address %1 contains invalid characters. Please check it. - Feil: Adressen %1 innerholder ugyldige tegn. Vennligst sjekk den. - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Feil: Typenummeret for adressen %1 er for høy. Enten trenger du å oppgradere Bitmessaage-programvaren eller så er det fordi kontakten din har funnet på noe smart. - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - Feil: Noen av de kodede dataene i adressen %1 er for korte. Det kan hende det er noe galt med programvaren til kontakten din. - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - Feil: Noen av de kodede dataene i adressen %1 er for lange. Det kan hende det er noe galt med programvaren til kontakten din. - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - Feil: Noe er galt med adressen %1. - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Feil: Du må oppgi en avsenderadresse. Hvis du ikke har en gå til 'Dine identiteter'-fanen. - - - - Address version number - Adressetypenummer - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Angående adressen %1, Bitmessage forstår ikke adressetypenumre for %2. Oppdater Bitmessage til siste versjon. - - - - Stream number - Strømnummer - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Angående adressen %1, Bitmessage kan ikke håndtere strømnumre for %2. Oppdater Bitmessage til siste utgivelse. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Advarsel: Du er ikke tilkoblet. Bitmessage vil utføre nødvendige arbeidsoppgaver for å sende beskjeder, men ingen vil bli sendt før du kobler til igjen. - - - - Message queued. - Meldingen er lagt i kø. - - - - Your 'To' field is empty. - Ditt 'Til'-felt er tomt. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Høyreklikk på en eller flere oppføringer i adresseboka og velg 'Send beskjed til denne adressen'. - - - - Fetched address from namecoin identity. - Hentet adresse fra Namecoin-identitet. - - - - New Message - Ny beskjed - - - - From - Fra - - - - Sending email gateway registration request - - - - - Address is valid. - Adressen er gyldig. - - - - The address you entered was invalid. Ignoring it. - Adressen du oppga var ugyldig og vil derfor bli ignorert. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Feil: Du kan ikke legge til samme adresse i adresseboka flere ganger. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - Omstart - - - - You must restart Bitmessage for the port number change to take effect. - Du må ta omstart av Bitmessage for at endringen av portnummer skal tre i kraft. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage vil bruke proxy fra nå av. Hvis du vil kan du omstart av programmet for å lukke eksisterende tilkoblinger (hvis det finnes noen). - - - - Number needed - Trenger nummer - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - Vil ikke igjensende noensinne - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Legg merke til at utløpstiden du oppga er kortere enn det Bitmessage venter for første igjensendingsforsøk, dine beskjeder vil derfor aldri bli igjensendt. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Passordfrase stemmer ikke - - - - The passphrase you entered twice doesn't match. Try again. - Passordfrasene er ikke like. Vennligst prøv igjen. - - - - Choose a passphrase - Velg en passordfrase - - - - You really do need a passphrase. - Du trenger sårt en passordfrase. - - - - Address is gone - Adressen er borte - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage kan ikke finne adressen %1. Kanskje du fjernet den? - - - - Address disabled - Adressen er deaktivert - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Feil: Adressen du prøver å sende med er deaktivert. Du må aktivere den fra 'Dine identiteter' før du kan bruke den. - - - - Entry added to the Address Book. Edit the label to your liking. - Ny oppføring lagt til i adresseboka. Du kan forandre etiketten til det du måtte ønske. - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - Kastet innholdet. - - - - Undeleted item. - Gjenopprettet innhold. - - - - Save As... - Lagre som ... - - - - Write error. - Skrivefeil. - - - - No addresses selected. - Ingen adresse valgt. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - Vil du virkelig fjerne dette avataret? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Du har allerede satt ett avatar for denne adressen. Vil du virkelig overskrive det? - - - - Start-on-login not yet supported on your OS. - Start ved innlogging er ikke støttet enda for ditt OS. - - - - Minimize-to-tray not yet supported on your OS. - Minimering til systemkurv er ikke støttet enda for ditt OS. - - - - Tray notifications not yet supported on your OS. - Varslinger via systemkurv er ikke støttet enda for ditt OS. - - - - Testing... - Tester ... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Dette er en kanaladresse. Du kan ikke bruke den som en pseudo-epostliste. - - - - The address should start with ''BM-'' - Adressen bør starte med ''BM-'' - - - - The address is not typed or copied correctly (the checksum failed). - Adressen er ikke skrevet eller kopiert inn riktig (sjekksummen feilet). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Typenummeret for denne adressen er høyere enn det programvaren støtter. Vennligst oppgrader Bitmessage. - - - - The address contains invalid characters. - Adressen inneholder ugyldige tegn. - - - - Some data encoded in the address is too short. - Noen av de kodede dataene i adressen er for korte. - - - - Some data encoded in the address is too long. - Noen av de kodede dataene i adressen er for lange. - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - Oppgi inn en adresse over. - - - - Address is an old type. We cannot display its past broadcasts. - Adressen er av gammel type. Vi kan ikke vise dens tidligere kringkastninger. - - - - There are no recent broadcasts from this address to display. - Det er ingen nylige kringkastninger fra denne adressen å vise frem. - - - - You are using TCP port %1. (This can be changed in the settings). - Du benytter TCP-port %1. (Dette kan endres på i innstillingene). - - - + Bitmessage Bitmessage - - Identities - Identiteter - - - - New Identity - Ny identitet - - - - Search - Søk - - - - All - Alle - - - + To Til - + From Fra - + Subject Emne - - Message - Beskjed - - - + Received Mottatt - - Messages - Meldinger + + Inbox + Innboks - - Address book - Adressebok + + Load from Address book + Velg fra adresseboka - - Address - Adresse + + Message: + Beskjed: - - Add Contact - Legg til kontakt - - - - Fetch Namecoin ID - Hent Namecoin-id - - - + Subject: Emne: - - From: - Fra: + + Send to one or more specific people + Send til en eller flere bestemte kontakter - + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + To: Til: - - Send ordinary Message - Send vanlig melding + + From: + Fra: - - Send Message to your Subscribers - Send melding til dine abonnementer + + Broadcast to everyone who is subscribed to your address + Kringkast til alle som abonnerer på din adresse - - TTL: - TTL: + + Send + Send - - Subscriptions - Abonnement + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Vær klar over at når du kringkaster noe er beskjeden kun kryptert med adressen din. Alle som har denne kan derfor få med seg innholdet. - - Add new Subscription - Legg til nytt abonnement + + Status + Status - - Chans - Kanaler - - - - Add Chan - Legg til kanal - - - - File - Fil - - - - Settings - Innstillinger - - - - Help - Hjelp - - - - Import keys - Importer inn nøkler - - - - Manage keys - Administrer nøkler - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Kontakt support - - - - About - Om - - - - Regenerate deterministic addresses - Regenerer deterministiske adresser - - - - Delete all trashed messages - Slett alle kastede meldinger - - - - Join / Create chan - Delta i / opprett kanal - - - - All accounts - Alle kontoer - - - - Zoom level %1% - Zoom nivå %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - Legg til ny oppføring - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - %n time - %n timer - - - - - %n day(s) - - %n dag - %n dager - - - - - Shutting down PyBitmessage... %1% - - - - + Sent Sendt - - Generating one new address - + + New + Ny - - Done generating address. Doing work necessary to broadcast it... - + + Label (not shown to anyone) + Etikett (ikke vist til noen) - - Generating %1 new addresses. - + + Address + Adresse - - %1 is already in 'Your Identities'. Not adding it again. - + + Stream + Strøm - - Done generating address - + + Your Identities + Dine identiteter - + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Her kan du abonnere på 'kringkastede beskjeder' sendt av andre brukere. Beskjedene vil vises i din innboks. Adressene her vil overstyre de under svartelistefanen. + + + + Add new Subscription + Legg til nytt abonnement + + + + Label + Etikett + + + + Subscriptions + Abonnement + + + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + Adresseboka er nyttig for å knytte navn eller etiketter mot andres BitMessage-adresser så du enklere kan gjenkjenne dem i innboksen. Du kan legge til nye oppføringer her ved å bruke 'Legg til'-knappen, eller fra innboksen din ved å høyreklikke på en beskjed. + + + + Add new entry + Legg til ny oppføring + + + + Name or Label + Navn eller etikett + + + + Address Book + Adressebok + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Bruk svarteliste (tillat beskjeder fra alle adresser unntatt de på svartelisten) + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Bruk hviteliste (blokker beskjeder fra alle adresser unntatt de på hvitelisten) + + + + Blacklist + Svarteliste + + + + Stream Number + Strømnummer + + + + Number of Connections + Antall tilkoblinger + + + + Total connections: 0 + Totalt antall tilkoblinger: 0 + + + + Since startup at asdf: + Siden oppstart på asdf: + + + + Processed 0 person-to-person message. + Har bearbeidet 0 beskjeder for person-til-person. + + + + Processed 0 public key. + Har bearbeidet 0 offentlige nøkler. + + + + Processed 0 broadcast. + Har bearbeidet 0 kringkastninger. + + + + Network Status + Nettverksstatus + + + + File + Fil + + + + Settings + Innstillinger + + + + Help + Hjelp + + + + Import keys + Importer inn nøkler + + + + Manage keys + Administrer nøkler + + + + Quit + Avslutt + + + + About + Om + + + + Regenerate deterministic addresses + Regenerer deterministiske adresser + + + + Delete all trashed messages + Slett alle kastede meldinger + + + + Total Connections: %1 + Totalt antall forbindelser: %1 + + + + Not Connected + Ikke tilkoblet + + + + Connected + Tilkoblet + + + + Show Bitmessage + Vis Bitmessage + + + + Subscribe + Abonner + + + + Processed %1 person-to-person messages. + Bearbeidet %1 beskjeder for person-til-person. + + + + Processed %1 broadcast messages. + Bearbeidet %1 kringkastede beskjeder. + + + + Processed %1 public keys. + Bearbeidet %1 offentlige nøkler. + + + + Since startup on %1 + Siden oppstart %1 + + + + Waiting for their encryption key. Will request it again soon. + Venter på krypteringsnøkkel. Sender straks en ny forespørsel. + + + + Encryption key request queued. + Forespørsel for å finne krypteringsnøkkel er satt i kø. + + + + Queued. + Satt i kø. + + + + Need to do work to send message. Work is queued. + Trenger å utføre arbeidsoppgave for sende beskjed. Denne er satt i kø. + + + + Acknowledgement of the message received %1 + Bekreftelse på beskjeden mottatt %1 + + + + Broadcast queued. + Kringkasting satt i kø. + + + + Broadcast on %1 + Kringkasting på %1 + + + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + Problem: Det nødvendige arbeidet som kreves utført av mottaker er mer krevende enn det som er satt som akseptabelt. %1 + + + + Forced difficulty override. Send should start soon. + Tvunget vanskelighet overstyrt. Sender snart. + + + + Message sent. Waiting for acknowledgement. Sent at %1 + Beskjed sendt. Venter på bekreftelse. Sendt %1 + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. + Du kan administrere nøklene dine ved å endre filen keys.dat i samme katalog som dette programmet. Det er viktig at du tar en sikkerhetskopi av denne filen. + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. + Du kan administrere nøklene dine ved å endre filen keys.dat lagret i + %1 +Det er viktig at du tar en sikkerhetskopi av denne filen. + + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Du kan administrere nøklene dine ved å endre filen keys.dat i samme katalog som dette programmet. Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne filen nå? (Pass på å lukke Bitmessage før du gjør endringer.) + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Du kan administrere nøklene dine ved å endre filen keys.dat i + %1 +Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne filen nå? (Pass på å lukke Bitmessage før du gjør endringer.) + + + + Add sender to your Address Book + Legg til sender i adresseboka + + + + Move to Trash + Kast + + + + View HTML code as formatted text + Vis HTML-koden som formatert tekst + + + + Enable + Aktiver + + + + Disable + Deaktiver + + + + Copy address to clipboard + Kopier adressen til utklippstavlen + + + + Special address behavior... + Spesieladressebehandling ... + + + + Send message to this address + Send beskjed til denne adressen + + + + Add New Address + Legg til ny adresse + + + + Delete + Slett + + + + Copy destination address to clipboard + Kopier destinasjonsadresse til utklippstavlen + + + + Force send + Tving sending + + + + Are you sure you want to delete all trashed messages? + Er du sikker på at du vil slette alle kastede beskjeder? + + + + You must type your passphrase. If you don't have one then this is not the form for you. + Du må skrive inn passordfrasen din. Hvis du ikke har en kan du ikke bruke dette skjemaet. + + + + Delete trash? + Vil du slette kastet innhold? + + + + Open keys.dat? + Åpne keys.dat? + + + + bad passphrase + Dårlig passordfrase + + + + Restart + Omstart + + + + You must restart Bitmessage for the port number change to take effect. + Du må ta omstart av Bitmessage for at endringen av portnummer skal tre i kraft. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage vil bruke proxy fra nå av, ta en omstart hvis du vil lukke alle eksisterende tilkoblinger. + + + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + Feil: Du kan ikke legge til samme adresse flere ganger. + + + + The address you entered was invalid. Ignoring it. + Adressen du oppga var ugyldig og vil derfor bli ignorert. + + + + Passphrase mismatch + Passordfrase stemmer ikke + + + + The passphrase you entered twice doesn't match. Try again. + Passordfrasene er ikke like. Vennligst prøv igjen. + + + + Choose a passphrase + Velg en passordfrase + + + + You really do need a passphrase. + Du trenger sårt en passordfrase. + + + + All done. Closing user interface... + Ferdig. Lukker brukergrensesnittet... + + + + Address is gone + Adressen er borte + + + + Bitmessage cannot find your address %1. Perhaps you removed it? + Bitmessage kan ikke finne adressen %1. Kanskje du fjernet den? + + + + Address disabled + Adressen er deaktivert + + + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + Feil: Adressen du prøver å sende med er deaktivert. Du må aktivere den fra 'Dine identiteter' før du kan bruke den. + + + + Entry added to the Address Book. Edit the label to your liking. + Ny oppføring lagt til i adresseboka. Du kan forandre etiketten til det du måtte ønske. + + + + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + Feil: Du kan ikke legge til samme adresse i adresseboka flere ganger. + + + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Kastet innholdet. Det finnes ikke noe brukergrensesnitt enda for kastet innhold, men ingenting er slettet enda. Alt ligger fortsatt på disken hvis du er interessert i å få det tilbake. + + + + No addresses selected. + Ingen adresse valgt. + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implimented for your operating system. + Alternativer har blitt deaktivert fordi de enten ikke er gjeldende eller fordi de ikke har blitt implementert for ditt operativsystem. + + + + The address should start with ''BM-'' + Adressen bør starte med ''BM-'' + + + + The address is not typed or copied correctly (the checksum failed). + Adressen er ikke skrevet eller kopiert inn riktig (sjekksummen feilet). + + + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + Typenummeret for denne adressen er høyere enn det programvaren støtter. Vennligst oppgrader Bitmessage. + + + + The address contains invalid characters. + Adressen inneholder ugyldige tegn. + + + + Some data encoded in the address is too short. + Noen av de kodede dataene i adressen er for korte. + + + + Some data encoded in the address is too long. + Noen av de kodede dataene i adressen er for lange. + + + + Address is valid. + Adressen er gyldig. + + + + You are using TCP port %1. (This can be changed in the settings). + Du benytter TCP-port %1. (Dette kan endres på i innstillingene). + + + + Error: Bitmessage addresses start with BM- Please check %1 + Feil: Bitmessage-adresser begynner med BM-. Vennligst sjekk %1 + + + + Error: The address %1 contains invalid characters. Please check it. + Feil: Adressen %1 innerholder ugyldige tegn. Vennligst sjekk den. + + + + Error: The address %1 is not typed or copied correctly. Please check it. + Feil: Adressen %1 er skrevet eller kopiert inn feil. Vennligst sjekk den. + + + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + Feil: Typenummeret for adressen %1 er for høy. Enten trenger du å oppgradere Bitmessaage-programvaren eller så er det fordi kontakten din har funnet på noe smart. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + Feil: Noen av de kodede dataene i adressen %1 er for korte. Det kan hende det er noe galt med programvaren til kontakten din. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + Feil: Noen av de kodede dataene i adressen %1 er for lange. Det kan hende det er noe galt med programvaren til kontakten din. + + + + Error: Something is wrong with the address %1. + Feil: Noe er galt med adressen %1. + + + + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + Feil: Du må oppgi en avsenderadresse. Hvis du ikke har en gå til 'Dine identiteter'-fanen. + + + + Sending to your address + Sender til din adresse + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + Feil: En av adressene du sender en beskjed til er dine: %1. Dessverre kan ikke Bitmessage-klienten bearbeide sine egne beskjeder. Du kan benytte Bitmessage-klienten på en annen datamaskin eller kjøre den i en virtuell datamaskin. + + + + Address version number + Adressetypenummer + + + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Angående adressen %1, Bitmessage forstår ikke adressetypenumre for %2. Oppdater Bitmessage til siste versjon. + + + + Stream number + Strømnummer + + + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + Angående adressen %1, Bitmessage kan ikke håndtere strømnumre for %2. Oppdater Bitmessage til siste utgivelse. + + + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + Advarsel: Du er ikke tilkoblet. Bitmessage vil utføre nødvendige arbeidsoppgaver for å sende beskjeder, men ingen vil bli sendt før du kobler til igjen. + + + + Your 'To' field is empty. + Ditt 'Til'-felt er tomt. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + Høyreklikk på en eller flere oppføringer i adresseboka og velg 'Send beskjed til denne adressen'. + + + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Feil: Du kan ikke legge til samme adresse flere ganger i abonnementlista. + + + + Message trashed + Beskjed kastet + + + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + En av dine gamle adresser er av den første typen og derfor ikke lenger støttet: %1. Derfor kan den vel slettes? + + + + Unknown status: %1 %2 + Ukjent status: %1 %2 + + + + Connection lost + Mistet tilkobling + + + SOCKS5 Authentication problem: %1 - + Autentiseringsproblem med SOCKS5: %1 - - Disk full - + + Reply + Svar - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - + + Generating one new address + Genererer en ny adresse - + + Done generating address. Doing work necessary to broadcast it... + Ferdig med å generere adresse. Utfører nødvendig arbeidsoppgave for å kringkaste den ... + + + + Done generating address + Ferdig med å generere adresse + + + + Message sent. Waiting on acknowledgement. Sent on %1 + Beskjed sendt, venter på bekreftelse. Sendt %1 + + + Error! Could not find sender address (your address) in the keys.dat file. - + Feil! Kunne ikke finne avsenderadresse (din adresse) i nøkkelfilen som er keys.dat. - + Doing work necessary to send broadcast... - + Utfører nødvendig arbeidsoppgave for å kringkaste ... - + Broadcast sent on %1 - + Kringkastet på %1 - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - + Looking up the receiver's public key - + Gjør oppslag for å finne mottakers offentlige nøkkel - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - + + Doing work necessary to send message. (There is no required difficulty for version 2 addresses like this.) + Utfører nødvendig arbeidsoppgave for å sende beskjeden. (Det er ikke noe krav til vanskelighet for adresser av type to som benyttet her.) - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. + + Doing work necessary to send message. Receiver's required difficulty: %1 and %2 - + Utfører nødvendig arbeidsoppgave for å sende beskjeden. +Mottakernes krav til vanskelighet: %1 og %2 - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - + + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. + Problem: Arbeidsoppgaven som kreves utført av mottaker (%1 og %2) er mer krevende enn det du har satt som akseptabelt. - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - + + Work is queued. + Arbeidsoppgave er satt i kø. - - Doing work necessary to send message. - + + Work is queued. %1 + Arbeidsoppgave er satt i kø. %1 - - Message sent. Waiting for acknowledgement. Sent on %1 - + + Doing work necessary to send message. +There is no required difficulty for version 2 addresses like this. + Utfører nødvendig arbeidsoppgave for å sende beskjeden. +Det er ingen krevd vanskelighet for adresser av type to som benyttet her. - - Doing work necessary to request encryption key. - + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + Problem: Mottakerens nøkkel kunne ikke brukes til å kryptere beskjeden. %1 - - Broadcasting the public key request. This program will auto-retry if they are offline. - + + Save message as... + Lagre beskjed som ... - - Sending public key request. Waiting for reply. Requested at %1 - + + Mark Unread + Merk som ulest - - UPnP port mapping established on port %1 - + + Subscribe to this address + Abonner på denne adressen - - UPnP port mapping removed - + + Message sent. Sent at %1 + Beskjed sendt. Sendt %1 - - Mark all messages as read - + + Chan name needed + Kanalnavn nødvendig - - Are you sure you would like to mark all messages read? - + + You didn't enter a chan name. + Du oppga ikke noe kanalnavn. + + + + Address already present + Adressen eksisterer allerede + + + + Could not add chan because it appears to already be one of your identities. + Kunne ikke legge til kanal siden den ser ut til å allerede være lagret som en av dine identiteter. + + + + Success + Suksess + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + Opprettet ny kanal. For å la andre delta i din nye kanal gir du dem dem kanalnavnet og denne Bitmessage-adressen: %1. Denne adressen vises også i 'Dine identiteter'. + + + + Address too new + Adressen er for ny + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + Selv om Bitmessage-adressen kanskje er gyldig så er tilhørende typenummer for nytt til å håndteres. Kanskje du trenger å oppgradere Bitmessage. + + + + Address invalid + Ugyldig adresse + + + + That Bitmessage address is not valid. + Bitmessage-adressen er ikke gyldig. + + + + Address does not match chan name + Adresse stemmer ikke med kanalnavnet + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + Selv om Bitmessage-adressen du oppga var gyldig stemmer den ikke med kanalnavnet. + + + + Successfully joined chan. + Deltar nå i kanal. + + + + Fetched address from namecoin identity. + Hentet adresse fra Namecoin-identitet. + + + + New Message + Ny beskjed + + + + From + Fra + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + Bitmessage vil bruke proxy fra nå av. Hvis du vil kan du omstart av programmet for å lukke eksisterende tilkoblinger (hvis det finnes noen). + + + + Save As... + Lagre som ... + + + + Write error. + Skrivefeil. + + + + Options have been disabled because they either aren't applicable or because they haven't yet been implemented for your operating system. + Alternativer har blitt deaktivert fordi de enten ikke er gjeldende eller fordi de ikke har blitt implementert for ditt operativsystem. + + + + Testing... + Tester ... + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + Dette er en kanaladresse. Du kan ikke bruke den som en pseudo-epostliste. + + + + Search + Søk + + + + All + Alle + + + + Message + Beskjed + + + + Fetch Namecoin ID + Hent Namecoin-id + + + + Stream # + Strøm # + + + + Connections + Tilkoblinger + + + + Ctrl+Q + Ctrl+Q + + + + F1 + F1 + + + + Join / Create chan + Delta i / opprett kanal + + + + Set avatar... + Sett ett avatar... + + + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Du kan administrere dine nøkler ved å endre på filen keys.dat lagret i + %1 +Det er viktig at du tar sikkerhetskopi av denne filen. Vil du åpne denne filen nå? (Vær sikker på å få avsluttet Bitmessage før du gjør endringer.) + + + + Bad address version number + Feil adresseversjonsnummer + + + + Your address version number must be a number: either 3 or 4. + Ditt adressetypenummer må være et nummer: Enten 3 eller 4. + + + + Your address version number must be either 3 or 4. + Ditt adressetypenummer må enten være 3 eller 4. + + + + Inventory lookups per second: %1 + Inventaroppslag per sekund: %1 + + + + Will not resend ever + Vil ikke igjensende noensinne + + + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + Legg merke til at utløpstiden du oppga er kortere enn det Bitmessage venter for første igjensendingsforsøk, dine beskjeder vil derfor aldri bli igjensendt. + + + + Do you really want to remove this avatar? + Vil du virkelig fjerne dette avataret? + + + + You have already set an avatar for this address. Do you really want to overwrite it? + Du har allerede satt ett avatar for denne adressen. Vil du virkelig overskrive det? + + + + Start-on-login not yet supported on your OS. + Start ved innlogging er ikke støttet enda for ditt OS. + + + + Minimize-to-tray not yet supported on your OS. + Minimering til systemstatusfeltet er ikke støttet enda for ditt OS. + + + + Tray notifications not yet supported on your OS. + Varslinger via systemstatusfeltet er ikke støttet enda for ditt OS. + + + + Enter an address above. + Oppgi inn en adresse over. + + + + Address is an old type. We cannot display its past broadcasts. + Adressen er av gammel type. Vi kan ikke vise dens tidligere kringkastninger. + + + + There are no recent broadcasts from this address to display. + Det er ingen nylige kringkastninger fra denne adressen å vise frem. + + + + Display the %1 recent broadcast from this address. + Vis den %1 nyligste kringkastningen fra denne adressen. + + + + Display the %1 recent broadcasts from this address. + Vis de %1 nyligste kringkastningene fra denne adressen. + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + Inventory lookups per second: 0 + Inventaroppslag per sekund: 0 + + + + MainWindows + + + Address is valid. + Adressen er gyldig. @@ -1294,28 +1132,28 @@ Receiver's required difficulty: %1 and %2 Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Her kan du generere så mange adresser du vil. Du oppfordres til å ta i bruk nye adresser med jevne mellomrom. Du kan generere nye adresser enten ved å bruke tilfeldige numre eller en passordfrase. Hvis du bruker passordfrase får du en såkalt 'deterministisk' adresse. -'Tilfeldig nummer'-valget er valgt som standard. En deterministisk adresse har både fordeler og ulemper: + Her kan du generere så mange adresser du vil. Du oppfordres til å ta i bruk nye adresser med jevne mellomrom. Du kan generere nye adresser enten ved å bruke tilfeldige numre eller en passordfrase. Hvis du bruker passordfrase får du en såkalt 'deterministisk' adresse. +'Tilfeldig nummer'-valget er valgt som standard. En deterministisk adresse har både fordeler og ulemper: <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Fordeler:<br/></span>Du kan gjenskape adressene dine på hvilken som helst datamaskin ved hjelp av hukommelsen. <br/>Du trenger ikke ta noen sikkerhetskopi av keys.dat-filen så lenge du husker passordfrasen din. <br/><span style=" font-weight:600;">Ulemper:<br/></span>Du må huske (eller skrive ned) din passordfrase hvis du forventer å måtte gjenopprette nøklene dine fordi de går tapt. <br/>Du må huske adresseversjonsnummeret og strømnummeret i tillegg til passordfrasen. <br/>Hvis du velger en svak passordfrase og noen andre på Internett klarer å knekke den kan de lese beskjedene dine og sende nye beskjeder på vegne av deg.</p></body></html> + <html><head/><body><p><span style=" font-weight:600;">Fordeler:<br/></span>Du kan gjenskape adressene dine på hvilken som helst datamaskin ved hjelp av hukommelsen. <br/>Du trenger ikke ta noen sikkerhetskopi av keys.dat-filen så lenge du husker passordfrasen din. <br/><span style=" font-weight:600;">Ulemper:<br/></span>Du må huske (eller skrive ned) din passordfrase hvis du forventer å måtte gjenopprette nøklene dine fordi de går tapt. <br/>Du må huske adresseversjonsnummeret og strømnummeret i tillegg til passordfrasen. <br/>Hvis du velger en svak passordfrase og noen andre på Internett klarer å knekke den kan de lese beskjedene dine og sende nye beskjeder på vegne av deg.</p></body></html> Use a random number generator to make an address - Opprett en adresse ved å bruke generatoren som lager tilfeldige tall + Opprett en adresse ved å bruke generatoren som lager tilfeldige tall Use a passphrase to make addresses - Bruk en passordfrase for å opprette adresser + Bruk en passordfrase for å opprette adresser Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Bruk ekstra tid på å få adressen(e) en eller to tegn kortere + Bruk ekstra tid på å få adressen(e) en eller to tegn kortere @@ -1324,13 +1162,13 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 4 - Adressetypenummer: 4 + Address version number: 3 + Adressetypenummer: 3 In addition to your passphrase, you must remember these numbers: - I tillegg til passordfrasen må du huske disse numrene: + I tillegg til passordfrasen må du huske disse numrene: @@ -1340,12 +1178,12 @@ The 'Random Number' option is selected by default but deterministic ad Number of addresses to make based on your passphrase: - Antall adresser som skal opprettes basert på din passordfrase: + Antall adresser som skal opprettes basert på din passordfrase: Stream number: 1 - Strømnummer: 1 + Strømnummer: 1 @@ -1365,22 +1203,27 @@ The 'Random Number' option is selected by default but deterministic ad Use the most available stream - Bruk den mest tilgjengelige strømmen + Bruk den mest tilgjengelige strømmen (best if this is the first of many addresses you will create) - (best hvis dette er de første av mange adresser du kommer til å opprette) + (best hvis dette er de første av mange adresser du kommer til å opprette) Use the same stream as an existing address - Bruk samme strøm som en eksisterende adresse + Bruk samme strøm som en eksisterende adresse (saves you some bandwidth and processing power) - (sparer deg for litt båndbredde og prosesseringskraft) + (sparer deg for litt båndbredde og prosesseringskraft) + + + + Address version number: 4 + Adressetypenummer: 4 @@ -1388,7 +1231,7 @@ The 'Random Number' option is selected by default but deterministic ad Add new entry - Legg til ny oppføring + Legg til ny oppføring @@ -1402,8 +1245,8 @@ The 'Random Number' option is selected by default but deterministic ad - Enter an address above. - Oppgi inn en adresse ovenfor. + CheckBox + Avkryssningsboks @@ -1411,102 +1254,65 @@ The 'Random Number' option is selected by default but deterministic ad Special Address Behavior - Spesiell adresseoppførsel + Spesiell adresseoppførsel Behave as a normal address - Oppførsel som vanlig adresse + Oppførsel som vanlig adresse Behave as a pseudo-mailing-list address - Oppførsel som adresse på pseudo-epostliste + Oppførsel som adresse på pseudo-epostliste Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - E-post mottatt med en adresse oppført på en pseudo-epostliste vil automatisk bli kringkastet til abonnenter (og vil derfor bli offentlig tilgjengelig). + E-post mottatt med en adresse oppført på en pseudo-epostliste vil automatisk bli kringkastet til abonnenter (og vil derfor bli offentlig tilgjengelig). Name of the pseudo-mailing-list: - Navnet på pseudo-epostlista: - - - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - + Navnet på pseudo-epostlista: aboutDialog - - About - Om - - - + PyBitmessage PyBitmessage - + version ? versjon ? - + + About + Om + + + + Copyright © 2013 Jonathan Warren + Kopirett © 2013 Jonathan Warren + + + <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> <html><head/><body><p>Distribuert under MIT/X11-programvarelisens, se <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> - + This is Beta software. Dette er betaprogramvare. - - - blacklist - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Legg til ny oppføring - - - - Name or Label - Navn eller Etikett - - - - Address - Adresse - - - - Blacklist - Svarteliste - - - - Whitelist - Hviteliste + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Kopirett © 2012-2014 Jonathan Warren<br/>Kopirett © 2013-2014 Bitmessage-utviklerne</p></body></html> @@ -1519,17 +1325,17 @@ The 'Random Number' option is selected by default but deterministic ad Bitmessage won't connect to anyone until you let it. - Bitmessage kobler ikke til noen før du lar den. + Bitmessage kobler ikke til noen før du lar den. Connect now - Koble til nå + Koble til nå Let me configure special network settings first - La meg konfigurere spesielle nettverksinnstillinger først + La meg konfigurere spesielle nettverksinnstillinger først @@ -1541,13 +1347,13 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">PyBitmessage-hjelp</a> As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - Bitmessage er et samarbeidsprosjekt, hjelp kan bli funnet på nettet i Bitmessage-wikien: + Bitmessage er et samarbeidsprosjekt, hjelp kan bli funnet på nettet i Bitmessage-wikien: @@ -1565,12 +1371,12 @@ The 'Random Number' option is selected by default but deterministic ad 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. - Du har opprettet minst en utgående tilkobling til andre, men ikke mottatt noen innkommende tilkoblinger enda. Din brannmur eller ruter er antagelig ikke konfigurert til å videreformidle innkommende TCP-tilkoblinger frem til datamaskinen din. Bitmessage vil fungere helt fint, men det ville hjelpe Bitmessage-nettverket hvis du tillot innkommende tilkoblinger. Det vil også hjelpe deg å bli en bedre tilkoblet node. + Du har opprettet minst en utgående tilkobling til andre, men ikke mottatt noen innkommende tilkoblinger enda. Din brannmur eller ruter er antagelig ikke konfigurert til å videreformidle innkommende TCP-tilkoblinger frem til datamaskinen din. Bitmessage vil fungere helt fint, men det ville hjelpe Bitmessage-nettverket hvis du tillot innkommende tilkoblinger. Det vil også hjelpe deg å bli en bedre tilkoblet node. You are using TCP port ?. (This can be changed in the settings). - Du bruker TCP port ?. (Dette kan endres på fra innstillingene). + Du bruker TCP port ?. (Dette kan endres på fra innstillingene). @@ -1578,140 +1384,12 @@ The 'Random Number' option is selected by default but deterministic ad Du har aktive tilkoblinger til andre og riktig konfigurert brannmur. - - networkstatus - - - Total connections: - Antall tilkoblinger: - - - - Since startup: - Siden oppstart: - - - - Processed 0 person-to-person messages. - Behandlet 0 person-til-person meldinger. - - - - Processed 0 public keys. - Behandlet 0 offentlige nøkler. - - - - Processed 0 broadcasts. - Behandlet 0 meldinger. - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - Objekter som skal synkroniseres: - - - - Stream # - - - - - Connections - Tilkoblinger - - - - Since startup on %1 - Siden oppstart på %1 - - - - Down: %1/s Total: %2 - Ned: %1/s Totalt: %2 - - - - Up: %1/s Total: %2 - Opp: %1/s Totalt: %2 - - - - Total Connections: %1 - Antall tilkoblinger: %1 - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - Opp: 0 kB/s - - - - Down: 0 kB/s - Ned: 0 kB/s - - - - Network Status - Nettverksstatus - - - - byte(s) - - byte - byte - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - - newChanDialog Dialog - Dialog + Opprett ny kanal @@ -1731,7 +1409,7 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - <html><head/><body><p>Skriv inn et navn for kanalen din. Hvis du velger et komplisert nok kanalnavn (et som er langt nok og unikt som passfrase) og ingen av dine kontakter deler det offentlig vil kanalen være sikker og privat. Hvis du og noen andre begge oppretter en kanal med samme kanalnavnet vil dette bli samme kanalen</p></body></html> + <html><head/><body><p>Skriv inn et navn for kanalen din. Hvis du velger et komplisert nok kanalnavn (et som er langt nok og unikt som passfrase) og ingen av dine kontakter deler det offentlig vil kanalen være sikker og privat. Hvis du og noen andre begge oppretter en kanal med samme kanalnavnet vil dette bli samme kanalen</p></body></html> @@ -1741,7 +1419,7 @@ The 'Random Number' option is selected by default but deterministic ad <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - <html><head/><body><p>En kanal eksisterer når en gruppe personer deler de samme dekrypteringsnøklene. Nøklene og Bitmessage-adressen brukt av kanalen er generert fra et menneskevennlig ord eller en frase (kanalnavnet). For å sende en beskjed til alle som er i kanalen sender man en vanlig beskjed av typen person-til-person til kanaladressen.</p><p>Kanaler er fullstendig umodererbare og eksperimentelle.</p></body></html> + <html><head/><body><p>En kanal eksisterer når en gruppe personer deler de samme dekrypteringsnøklene. Nøklene og Bitmessage-adressen brukt av kanalen er generert fra et menneskevennlig ord eller en frase (kanalnavnet). For å sende en beskjed til alle som er i kanalen sender man en vanlig beskjed av typen person-til-person til kanaladressen.</p><p>Kanaler er fullstendig umodererbare og eksperimentelle.</p></body></html> @@ -1769,17 +1447,22 @@ The 'Random Number' option is selected by default but deterministic ad Number of addresses to make based on your passphrase: - Antall adresser som skal opprettes basert på din passordfrase: + Antall adresser som skal opprettes basert på din passordfrase: - - Address version number: - Adressetypenummer: + + Address version Number: + Adressetypenummer: + + + + 3 + 3 Stream number: - Strømnummer: + Strømnummer: @@ -1789,309 +1472,333 @@ The 'Random Number' option is selected by default but deterministic ad Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Bruk ekstra tid på å få adressen(e) en eller to tegn kortere + Bruk ekstra tid på å få adressen(e) en eller to tegn kortere You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Du må krysse av for (eller ikke krysse av for) i denne boksen slik du gjorde når du opprettet adressene dine første gangen. + Du må krysse av for (eller ikke krysse av for) i denne boksen slik du gjorde når du opprettet adressene dine første gangen. If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Hvis du tidligere har opprettet deterministiske adresser, men mistet dem p.g.a. et uhell (f.eks. harddiskkræsj) så kan de regenereres her. Hvis du derimot brukte generatoren for generering av tilfeldige tall vil ikke dette skjemaet være til hjelp for deg. + Hvis du tidligere har opprettet deterministiske adresser, men mistet dem p.g.a. et uhell (f.eks. harddiskkræsj) så kan de regenereres her. Hvis du derimot brukte generatoren for generering av tilfeldige tall vil ikke dette skjemaet være til hjelp for deg. + + + + Address version number: + Adressetypenummer: settingsDialog - + Settings Innstillinger - + Start Bitmessage on user login - Start Bitmessage ved brukerpålogging + Start Bitmessage ved brukerpålogging + + + + Start Bitmessage in the tray (don't show main window) + Start Bitmessage i systemstatusfeltet (ikke vis hovedvinduet) + + + + Minimize to tray + Minimiser til systemstatusfeltet + + + + Show notification when message received + Vis varsel når beskjed mottas + + + + Run in Portable Mode + Kjør i flyttbar modus + + + + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. + I flyttbar modus blir beskjeder og konfigurasjonsfiler oppbevart i samme katalog som programmet istedet for den vanlige applikasjonsdatamappen. Dette gjør Bitmessage enkel å kjøre fra f.eks. minnepinne. + + + + User Interface + Brukergrensesnitt + + + + Listening port + Lyttende port + + + + Listen for connections on port: + Lytt etter tilkoblinger på port: + + + + Proxy server / Tor + Proxytjener / Tor + + + + Type: + Type: + + + + none + ingen + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Tjenernavn: + + + + Port: + Port: + + + + Authentication + Autentisering - Tray - Systemkurv + Username: + Brukernavn: + + + + Pass: + Passord: + + + + Network Settings + Nettverksinnstillinger + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + Når noen sender deg en beskjed må først datamaskin deres fullføre en arbeidsoppgave. Vanskelighetsgraden for denne oppgaven er satt til 1 som standard. Du kan heve denne grensen for nye adresser du oppretter ved å endre på verdiene her. Alle nye adresser du oppretter vil kreve av avsender å løse enda vanskeligere oppgaver. Det finnes èt unntak: Hvis du legger til en kontakt i din adressebok vil de bli varslet neste gang du sender en beskjed om at de kun trenger å utføre enkleste form for arbeidsoppgave, denne har vanskelighetsgrad 1. + + + + Total difficulty: + Total vanskelighet: + + + + Small message difficulty: + Vanskelighet for kort beskjed: + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + 'Vanskelighet for kort beskjed' vil kun påvirke sending av korte beskjeder. Dobling av denne verdien vil også doble vanskeligheten for å sende en kort beskjed. + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + 'Total vanskelighet' påvirker den absolutte mengden av arbeid som avsender må fullføre. Dobling av denne verdien dobler også arbeidsmengden. + + + + Demanded difficulty + Krevd vanskelighet + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + Her kan du sette den maksimale mengden med arbeid som du er villig til å gjennomføre for å sende en beskjed til en annen person. Om disse verdiene settes til null vil alle verdier bli akseptert. + + + + Maximum acceptable total difficulty: + Maks akseptabel total vanskelighet: + + + + Maximum acceptable small message difficulty: + Maks akseptabel vanskelighet for korte beskjeder: + + + + Max acceptable difficulty + Maks akseptabel vanskelighet + + + + Willingly include unencrypted destination address when sending to a mobile device + Inkluder med vilje ukrypterte destinasjonadresser når mobil enhet er mottaker + + + + Override automatic language localization (use countycode or language code, e.g. 'en_US' or 'en'): + Overstyr automatisk språklokalisering (bruk land- eller språkkode, f.eks. 'en_US' eller 'en'):) + + + + Listen for incoming connections when using proxy + Lytt etter innkommende tilkoblinger når proxy benyttes + + + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + <html><head/><body><p>Bitmessage kan benytte et annet Bitcoin-basert program ved navn Namecoin for å lage menneskevennlige adresser. For eksempel, istedet for å fortelle din kontakt din lange Bitmessage-adresse så kan du enkelt fortelle vedkommende at beskjeden skal sendes til <span style=" font-style:italic;">test. </span></p><p>(å få din egen adresse inn Namecoin er fortsatt ganske vanskelig).</p><p>Bitmessage kan bruke enten namecoind direkte eller en kjørende instans av nmcontrol.</p></body></html> + + + + Host: + Vert: - Start Bitmessage in the tray (don't show main window) - Start Bitmessage i systemkurv (ikke vis hovedvinduet) + Password: + Passord: - Minimize to tray - Minimiser til systemkurv + Test + Test - Close to tray - Lukk til systemkurv + Connect to: + Koble til: - Show notification when message received - Vis varsel når beskjed mottas + Namecoind + Namecoind - Run in Portable Mode - Kjør i flyttbar modus + NMControl + NMControl - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - I flyttbar modus blir beskjeder og konfigurasjonsfiler oppbevart i samme katalog som programmet istedet for den vanlige applikasjonsdatamappen. Dette gjør Bitmessage enkel å kjøre fra f.eks. minnepinne. + Namecoin integration + Namecoin-integrasjon - - Willingly include unencrypted destination address when sending to a mobile device - Inkluder med vilje ukrypterte destinasjonadresser når mobil enhet er mottaker - - - + Use Identicons Bruk identikoner - - Reply below Quote - Svar under sitat - - - + Interface Language - Grensesnittspråk + Grensesnittspråk - + System Settings system Systeminnstillinger - - User Interface - Brukergrensesnitt + + English + en + Engelsk - - Listening port - Lyttende port + + Esperanto + eo + Esperanto - - Listen for connections on port: - Lytt etter tilkoblinger på port: + + Français + fr + Fransk - - UPnP: - UPnP: + + Deutsch + de + Tysk - - Bandwidth limit - Båndbredde grense + + Españl + es + Spansk - - Maximum download rate (kB/s): [0: unlimited] - + + русский язык + ru + Russisk - - Maximum upload rate (kB/s): [0: unlimited] - + + Norwegian + no + Norsk - - Proxy server / Tor - Proxytjener / Tor + + Pirate English + en_pirate + Piratengelsk - - Type: - Type: + + Other (set in keys.dat) + other + Annet (sett inn keys.dat) - - Server hostname: - Tjenernavn: - - - - Port: - Port: - - - - Authentication - Autentisering - - - - Username: - Brukernavn: - - - - Pass: - Passord: - - - - Listen for incoming connections when using proxy - Lytt etter innkommende tilkoblinger når proxy benyttes - - - - none - ingen - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Nettverksinnstillinger - - - - Total difficulty: - Total vanskelighet: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - 'Total vanskelighet' påvirker den absolutte mengden av arbeid som avsender må fullføre. Dobling av denne verdien dobler også arbeidsmengden. - - - - Small message difficulty: - Vanskelighet for kort beskjed: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Når noen sender deg en beskjed må først datamaskin deres fullføre en arbeidsoppgave. Vanskelighetsgraden for denne oppgaven er satt til 1 som standard. Du kan heve denne grensen for nye adresser du oppretter ved å endre på verdiene her. Alle nye adresser du oppretter vil kreve av avsender å løse enda vanskeligere oppgaver. Det finnes èt unntak: Hvis du legger til en kontakt i din adressebok vil de bli varslet neste gang du sender en beskjed om at de kun trenger å utføre enkleste form for arbeidsoppgave, denne har vanskelighetsgrad 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - 'Vanskelighet for kort beskjed' vil kun påvirke sending av korte beskjeder. Dobling av denne verdien vil også doble vanskeligheten for å sende en kort beskjed. - - - - Demanded difficulty - Krevd vanskelighet - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Her kan du sette den maksimale mengden med arbeid som du er villig til å gjennomføre for å sende en beskjed til en annen person. Om disse verdiene settes til null vil alle verdier bli akseptert. - - - - Maximum acceptable total difficulty: - Maks akseptabel total vanskelighet: - - - - Maximum acceptable small message difficulty: - Maks akseptabel vanskelighet for korte beskjeder: - - - - Max acceptable difficulty - Maks akseptabel vanskelighet - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage kan benytte et annet Bitcoin-basert program ved navn Namecoin for å lage menneskevennlige adresser. For eksempel, istedet for å fortelle din kontakt din lange Bitmessage-adresse så kan du enkelt fortelle vedkommende at beskjeden skal sendes til <span style=" font-style:italic;">test. </span></p><p>(å få din egen adresse inn Namecoin er fortsatt ganske vanskelig).</p><p>Bitmessage kan bruke enten namecoind direkte eller en kjørende instans av nmcontrol.</p></body></html> - - - - Host: - Vert: - - - - Password: - Passord: - - - - Test - Test - - - - Connect to: - Koble til: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Namecoin-integrasjon - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Som standard er det slik at hvis du sender en beskjed til noen og de er frakoblet i mer enn to dager så vil Bitmessage sende beskjeden på nytt igjen etter at det er gått to ekstra dager. Sånn vil det holde på fremover med eksponentiell vekst; beskjeder sendes på nytt etter 8, 16, 32 dager o.s.v., helt til mottakeren erkjenner dem. Her kan du endre på denne oppførselen ved å få Bitmessage til å gi opp etter et bestemt antall dager eller måneder.</p><p>La disse feltene stå tomme for å få standard oppsettet. </p></body></html> + <html><head/><body><p>Som standard er det slik at hvis du sender en beskjed til noen og de er frakoblet i mer enn to dager så vil Bitmessage sende beskjeden på nytt igjen etter at det er gått to ekstra dager. Sånn vil det holde på fremover med eksponentiell vekst; beskjeder sendes på nytt etter 8, 16, 32 dager o.s.v., helt til mottakeren erkjenner dem. Her kan du endre på denne oppførselen ved å få Bitmessage til å gi opp etter et bestemt antall dager eller måneder.</p><p>La disse feltene stå tomme for å få standard oppsettet. </p></body></html> - + Give up after Gi opp etter - + and og - + days dager - + months. - måneder. + måneder. - + Resends Expire Igjensending diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm deleted file mode 100644 index 3b9a0dcc..00000000 Binary files a/src/translations/bitmessage_pl.qm and /dev/null differ diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts deleted file mode 100644 index c97cb4bb..00000000 --- a/src/translations/bitmessage_pl.ts +++ /dev/null @@ -1,2563 +0,0 @@ - - - AddAddressDialog - - - Add new entry - Dodaj nowy wpis - - - - Label - Etykieta - - - - Address - Adres - - - - EmailGatewayDialog - - - Email gateway - Przekaźnik e-mail - - - - Register on email gateway - Zarejestruj u przekaźnika e-mail - - - - Account status at email gateway - Status konta u przekaźnika e-mail - - - - Change account settings at email gateway - Zmień ustawienia konta u przekaźnika e-mail - - - - Unregister from email gateway - Wyrejestruj od przekaźnika e-mail - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Przekaźnik e-mail umożliwia komunikację z użytkownikami poczty elektronicznej. Obecnie usługa ta oferowana jest tylko przez Mailchuck (@mailchuck.com). - - - - Desired email address (including @mailchuck.com): - Wybrany adres e-mail (razem a końcówką @mailchuck.com): - - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - Rejestracja nie powiodła się: - - - - The requested email address is not available, please try a new one. - Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. - - - - Sending email gateway registration request - Wysyłanie zapytania o rejestrację na bramce poczty - - - - Sending email gateway unregistration request - Wysyłanie zapytania o wyrejestrowanie z bramki poczty - - - - Sending email gateway status request - Wysyłanie zapytania o stan bramki poczty - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Tutaj możesz skonfigurować ustawienia bramki poczty e-mail -# Odkomentuj (usuń znak '#') opcje których chcesz użyć -# Ustawienia: -# -# pgp: server -# Bramka poczty utworzy i będzie zarządzać kluczami PGP za Ciebie - -# podpisywać, weryfikować, szyfrować i deszyfrować. Jeżeli chcesz -# używać PGP, ale jesteś leniwy, użyj tej opcji. Wymaga subskrypcji. -# -# pgp: local -# Bramka poczty nie będzie wykonywała operacji PGP za Ciebie. Możesz -# albo wcale nie korzystać z PGP, albo używać go lokalnie. -# -# attachments: yes -# Przychodzące załączniki w wiadomościach będą wrzucane na MEGA.nz i -# będziesz mógł je pobrać z podanego łącza. Wymaga subskrypcji. -# -# attachments: no -# Załączniki zostaną zignorowane. -# -# archive: yes -# Przychodzące wiadomości zostaną zarchiwizowane na serwerze. Użyj tej -# opcji przy diagnozowaniu problemów, lub jeżeli potrzebujesz dowodu -# przesyłani wiadomości na zewnętrznym serwerze. Włączenie tej opcji -# spowoduje, że operator usługi będzie mógł czytać Twoje listy nawet po -# przesłaniu ich do Ciebie. -# -# archive: no -# Przychodzące listy zostaną niezwłocznie usunięte z serwera po -# przekierowaniu ich do Ciebie. -# -# masterpubkey_btc: publiczny klucz BIP44 xpub lub electrum v1 publiczny seed -# offset_btc: integer (domyślnie 0) -# feeamount: liczba, maksymalnie 8 cyfr po przecinku -# feecurrency: BTC, XBT, USD, EUR lub GBP -# Użyj tych opcji, jeżeli chcesz pobierać opłaty od osób, które wyślą -# Tobie wiadomość. Jeżeli ta opcja jest włączona i nieznana osoba wyśle -# Ci wiadomość, będzie poproszona o wniesienie opłaty. Ta funkcja używa -# deterministycznych kluczy publicznych, dostaniesz pieniądze -# bezpośrednio. Aby ją ponownie wyłączyć, ustaw 'feeamount' na 0. -# Wymaga subskrypcji. - - - - MainWindow - - - Reply to sender - Odpowiedz do nadawcy - - - - Reply to channel - Odpowiedz do kanału - - - - Add sender to your Address Book - Dodaj nadawcę do Książki Adresowej - - - - Add sender to your Blacklist - Dodaj nadawcę do Listy Blokowanych - - - - Move to Trash - Przenieś do kosza - - - - Undelete - Przywróć - - - - View HTML code as formatted text - Wyświetl kod HTML w postaci sformatowanej - - - - Save message as... - Zapisz wiadomość jako… - - - - Mark Unread - Oznacz jako nieprzeczytane - - - - New - Nowe - - - - Enable - Aktywuj - - - - Disable - Deaktywuj - - - - Set avatar... - Ustaw awatar… - - - - Copy address to clipboard - Kopiuj adres do schowka - - - - Special address behavior... - Specjalne zachowanie adresu… - - - - Email gateway - Przekaźnik e-mail - - - - Delete - Usuń - - - - Send message to this address - Wyślij wiadomość pod ten adres - - - - Subscribe to this address - Subskrybuj ten adres - - - - Add New Address - Dodaj nowy adres - - - - Copy destination address to clipboard - Kopiuj adres odbiorcy do schowka - - - - Force send - Wymuś wysłanie - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Jeden z adresów, %1, jest starym adresem wersji 1. Adresy tej wersji nie są już wspierane. Usunąć go? - - - - Waiting for their encryption key. Will request it again soon. - Oczekiwanie na klucz szyfrujący odbiorcy. Niedługo nastąpi ponowne wysłanie o niego prośby. - - - - Encryption key request queued. - - - - - Queued. - W kolejce do wysłania. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Wiadomość wysłana. Oczekiwanie na potwierdzenie odbioru. Wysłano o %1 - - - - Message sent. Sent at %1 - Wiadomość wysłana. Wysłano o %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - Otrzymano potwierdzenie odbioru wiadomości %1 - - - - Broadcast queued. - Przekaz w kolejce do wysłania. - - - - Broadcast on %1 - Wysłana o %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problem: dowód pracy wymagany przez odbiorcę jest trudniejszy niż zaakceptowany przez Ciebie. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problem: klucz szyfrujący odbiorcy jest nieprawidłowy. Nie można zaszyfrować wiadomości. %1 - - - - Forced difficulty override. Send should start soon. - Wymuszono ominięcie trudności. Wysłanie zostanie wkrótce rozpoczęte. - - - - Unknown status: %1 %2 - Nieznany status: %1 %2 - - - - Not Connected - Brak połączenia - - - - Show Bitmessage - Pokaż Bitmessage - - - - Send - Wyślij - - - - Subscribe - Subskrybuj - - - - Channel - Kanał - - - - Quit - Zamknij - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się w tym samym katalogu co program. Zaleca się zrobienie kopii zapasowej tego pliku. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się -%1 -Zaleca się zrobienie kopii zapasowej tego pliku. - - - - Open keys.dat? - Otworzyć plik keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się w tym samym katalogu co program. Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik teraz? (Zamknij Bitmessage, przed wprowadzeniem jakichkolwiek zmian.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Możesz zarządzać swoimi kluczami edytując plik keys.dat znajdujący się -%1 -Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik teraz? (Zamknij Bitmessage przed wprowadzeniem jakichkolwiek zmian.) - - - - Delete trash? - Opróżnić kosz? - - - - Are you sure you want to delete all trashed messages? - Czy na pewno usunąć wszystkie wiadomości z kosza? - - - - bad passphrase - nieprawidłowe hasło - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Musisz wpisać swoje hasło. Jeżeli go nie posiadasz, to ten formularz nie jest dla Ciebie. - - - - Bad address version number - Nieprawidłowy numer wersji adresu - - - - Your address version number must be a number: either 3 or 4. - Twój numer wersji adresu powinien wynosić: 3 lub 4. - - - - Your address version number must be either 3 or 4. - Twój numer wersji adresu powinien wynosić: 3 lub 4. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Połączenie utracone - - - - Connected - Połączono - - - - Message trashed - Wiadomość usunięta - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - TTL (ang. Time-To-Live -- czas życia) to czas przez jaki wiadomość będzie przechowywana przez węzły sieci, po jego upływie odbiorca nie będzie juz mógł jej odebrać. -Jeżeli adresat nie otrzyma w tym czasie potwierdzenia odbioru wiadomości, zostanie ona wysłana ponownie. -Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłający wiadomość. -Zwykle 4-5 dniowy TTL jest odpowiedni. - - - - Message too long - Wiadomość zbyt długa - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Wiadomość jest za długa o %1 bajtów (maksymalna długość wynosi 261644 bajty). Przed wysłaniem należy ją skrócić. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Błąd: Twoje konto nie było zarejestrowane w bramce poczty. Rejestrowanie jako %1, proszę poczekać na zakończenie procesu przed ponowną próbą wysłania wiadomości. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Błąd: musisz wybrać adres wysyłania. Jeżeli go nie posiadasz, przejdź do zakładki 'Twoje tożsamości'. - - - - Address version number - Numer wersji adresu - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Odnośnie adresu %1, Bitmessage nie potrafi odczytać wersji adresu %2. Może uaktualnij Bitmessage do najnowszej wersji. - - - - Stream number - Numer strumienia - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Odnośnie adresu %1, Bitmessage nie potrafi operować na strumieniu adresu %2. Może uaktualnij Bitmessage do najnowszej wersji. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Uwaga: nie jesteś obecnie połączony. Bitmessage wykona niezbędną pracę do wysłania wiadomości, ale nie wyśle jej póki się nie połączysz. - - - - Message queued. - W kolejce do wysłania - - - - Your 'To' field is empty. - Pole 'Do' jest puste - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Użyj prawego przycisku myszy na adresie z książki adresowej i wybierz opcję "Wyślij wiadomość do tego adresu". - - - - Fetched address from namecoin identity. - Pobrano adres z identyfikatora Namecoin. - - - - New Message - Nowa wiadomość - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - Adres jest prawidłowy. - - - - The address you entered was invalid. Ignoring it. - Wprowadzono niewłaściwy adres, który został zignorowany. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Błąd: Adres znajduje się już w książce adresowej. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Błąd: Adres znajduje się już na liście subskrybcji. - - - - Restart - Uruchom ponownie - - - - You must restart Bitmessage for the port number change to take effect. - Musisz zrestartować Bitmessage, aby zmiana numeru portu weszła w życie. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage będzie of teraz korzystał z serwera proxy, ale możesz ręcznie zrestartować Bitmessage, aby zamknąć obecne połączenia (jeżeli występują). - - - - Number needed - Wymagany numer - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Maksymalne prędkości wysyłania i pobierania powinny być liczbami. Zignorowano zmiany. - - - - Will not resend ever - Nigdy nie wysyłaj ponownie - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Zauważ, że wpisany limit czasu wynosi mniej niż czas, który Bitmessage czeka przed pierwszą ponowną próbą wysłania wiadomości, więc Twoje wiadomości nie zostaną nigdy wysłane ponownie. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Hasła różnią się - - - - The passphrase you entered twice doesn't match. Try again. - Hasła, które wpisałeś nie pasują. Spróbuj ponownie. - - - - Choose a passphrase - Wpisz hasło - - - - You really do need a passphrase. - Naprawdę musisz wpisać hasło. - - - - Address is gone - Adres zniknął - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage nie może odnaleźć Twojego adresu %1. Może go usunąłeś? - - - - Address disabled - Adres nieaktywny - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Błąd: adres, z którego próbowałeś wysłać wiadomość jest nieaktywny. Włącz go w zakładce 'Twoje tożsamości' zanim go użyjesz. - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - Dodano wpis do listy blokowanych. Można teraz zmienić jego nazwę. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Błąd: Adres znajduje się już na liście blokowanych. - - - - Moved items to trash. - Przeniesiono wiadomości do kosza. - - - - Undeleted item. - Przywrócono wiadomość. - - - - Save As... - Zapisz jako… - - - - Write error. - Błąd zapisu. - - - - No addresses selected. - Nie wybrano adresu. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Jeżeli usuniesz subskrypcję, wiadomości które już dostałeś staną się niedostępne. Może powinieneś rozważyć wyłączenie subskrypcji. Dezaktywowane subskrypcje nie będą odbierać nowych wiadomości, ale ciągle będziesz mógł odczytać obecnie pobrane. - -Czy na pewno chcesz usunąć tę subskrypcję? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Jeżeli usuniesz kanał, wiadomości które już dostałeś staną się niedostępne. Może powinieneś rozważyć wyłączenie kanału. Dezaktywowane kanały nie będą odbierać nowych wiadomości, ale ciągle będziesz mógł odczytać obecnie pobrane. - -Czy na pewno chcesz usunąć ten kanał? - - - - Do you really want to remove this avatar? - Czy na pewno chcesz usunąć ten awatar? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Już ustawiłeś awatar dla tego adresu. Czy na pewno chcesz go nadpisać? - - - - Start-on-login not yet supported on your OS. - Start po zalogowaniu jeszcze nie jest wspierany pod Twoim systemem. - - - - Minimize-to-tray not yet supported on your OS. - Minimalizacja do zasobnika nie jest jeszcze wspierana pod Twoim systemem. - - - - Tray notifications not yet supported on your OS. - Powiadomienia w zasobniku nie są jeszcze wspierane pod Twoim systemem. - - - - Testing... - Testowanie… - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - Adres powinien zaczynać się od „BM-” - - - - The address is not typed or copied correctly (the checksum failed). - Adres nie został skopiowany lub przepisany poprawnie (błąd sumy kontrolnej). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Numer wersji tego adresu jest wyższy niż ten program może obsłużyć. Proszę zaktualizować Bitmessage. - - - - The address contains invalid characters. - Adres zawiera nieprawidłowe znaki. - - - - Some data encoded in the address is too short. - Niektóre dane zakodowane w adresie są za krótkie. - - - - Some data encoded in the address is too long. - Niektóre dane zakodowane w adresie są za długie. - - - - Some data encoded in the address is malformed. - Niektóre dane zakodowane w adresie są uszkodzone. - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - Adres starego typu. Nie można wyświetlić jego wiadomości subskrypcji. - - - - There are no recent broadcasts from this address to display. - Brak niedawnych wiadomości subskrypcji do wyświetlenia. - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - Tożsamości - - - - New Identity - Nowa tożsamość - - - - Search - Szukaj - - - - All - Wszystkie - - - - To - Do - - - - From - Od - - - - Subject - Temat - - - - Message - Wiadomość - - - - Received - Odebrana - - - - Messages - Wiadomości - - - - Address book - Książka adresowa - - - - Address - Adres - - - - Add Contact - Dodaj kontakt - - - - Fetch Namecoin ID - Pobierz Namecoin ID - - - - Subject: - Temat: - - - - From: - Od: - - - - To: - Do: - - - - Send ordinary Message - Wyślij zwykłą wiadomość - - - - Send Message to your Subscribers - Wyślij wiadomość broadcast - - - - TTL: - Czas życia: - - - - Subscriptions - Subskrypcje - - - - Add new Subscription - Dodaj subskrypcję - - - - Chans - Kanały - - - - Add Chan - Dodaj kanał - - - - File - Plik - - - - Settings - Ustawienia - - - - Help - Pomoc - - - - Import keys - Importuj klucze - - - - Manage keys - Zarządzaj kluczami - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Kontakt z twórcami - - - - About - O programie - - - - Regenerate deterministic addresses - Odtwórz adres deterministyczny - - - - Delete all trashed messages - Usuń wiadomości z kosza - - - - Join / Create chan - Dołącz / Utwórz kanał - - - - All accounts - Wszystkie konta - - - - Zoom level %1% - Poziom powiększenia %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Błąd: Adres znajduje sie już na liście. - - - - Add new entry - Dodaj nowy wpis - - - - Display the %1 recent broadcast(s) from this address. - Wyświetl %1 ostatnich wiadomości subskrypcji z tego adresu. - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - Nowa wersja Bitmessage jest dostępna: %1. Pobierz ją z https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - Waiting for PoW to finish... %1% - Oczekiwanie na wykonanie dowodu pracy… %1% - - - - Shutting down Pybitmessage... %1% - Zamykanie PyBitmessage… %1% - - - - Waiting for objects to be sent... %1% - Oczekiwanie na wysłanie obiektów… %1% - - - - Saving settings... %1% - Zapisywanie ustawień… %1% - - - - Shutting down core... %1% - Zamykanie rdzenia programu… %1% - - - - Stopping notifications... %1% - Zatrzymywanie powiadomień… %1% - - - - Shutdown imminent... %1% - Zaraz zamknę… %1% - - - - %n hour(s) - %n godzina%n godziny%n godzin%n godzin - - - - %n day(s) - %n dzień%n dni%n dni%n dni - - - - Shutting down PyBitmessage... %1% - Zamykanie PyBitmessage… %1% - - - - Sent - Wysłane - - - - Generating one new address - Generowanie jednego nowego adresu - - - - Done generating address. Doing work necessary to broadcast it... - Adresy wygenerowany. Wykonywanie dowodu pracy niezbędnego na jego rozesłanie… - - - - Generating %1 new addresses. - Generowanie %1 nowych adresów. - - - - %1 is already in 'Your Identities'. Not adding it again. - %1 jest już w 'Twoich tożsamościach'. Nie zostanie tu dodany. - - - - Done generating address - Ukończono generowanie adresów - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - Dysk pełny - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Uwaga: Twój dysk lub partycja jest pełny. Bitmessage zamknie się. - - - - Error! Could not find sender address (your address) in the keys.dat file. - Błąd! Nie można odnaleźć adresu nadawcy (Twojego adresu) w pliku keys.dat. - - - - Doing work necessary to send broadcast... - Wykonywanie dowodu pracy niezbędnego do wysłania przekazu… - - - - Broadcast sent on %1 - Wysłano: %1 - - - - Encryption key was requested earlier. - Prośba o klucz szyfrujący została już wysłana. - - - - Sending a request for the recipient's encryption key. - Wysyłanie zapytania o klucz szyfrujący odbiorcy. - - - - Looking up the receiver's public key - Wyszukiwanie klucza publicznego odbiorcy - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Problem: adres docelowy jest urządzeniem przenośnym, które wymaga, aby adres docelowy był zawarty w wiadomości, ale jest to zabronione w Twoich ustawieniach. %1 - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Wykonywanie dowodu pracy niezbędnego do wysłania wiadomości. -Nie ma wymaganej trudności dla adresów w wersji 2, takich jak ten adres. - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Wykonywanie dowodu pracy niezbędnego do wysłania wiadomości. -Odbiorca wymaga trudności: %1 i %2 - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Problem: dowód pracy wymagany przez odbiorcę (%1 i %2) jest trudniejszy niż chciałbyś wykonać. %3 - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Problem: próbujesz wysłać wiadomość do siebie lub na kanał, ale Twój klucz szyfrujący nie został znaleziony w pliku keys.dat. Nie można zaszyfrować wiadomości. %1 - - - - Doing work necessary to send message. - Wykonywanie pracy potrzebnej do wysłania wiadomości. - - - - Message sent. Waiting for acknowledgement. Sent on %1 - Wiadomość wysłana. Oczekiwanie na potwierdzenie odbioru. Wysłano o %1 - - - - Doing work necessary to request encryption key. - Wykonywanie pracy niezbędnej do prośby o klucz szyfrujący. - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - Rozsyłanie prośby o klucz publiczny. Program spróbuje ponownie, jeżeli jest on niepołączony. - - - - Sending public key request. Waiting for reply. Requested at %1 - Wysyłanie prośby o klucz publiczny. Oczekiwanie na odpowiedź. Zapytano o %1 - - - - UPnP port mapping established on port %1 - Mapowanie portów UPnP wykonano na porcie %1 - - - - UPnP port mapping removed - Usunięto mapowanie portów UPnP - - - - Mark all messages as read - Oznacz wszystkie jako przeczytane - - - - Are you sure you would like to mark all messages read? - Czy na pewno chcesz oznaczyć wszystkie wiadomości jako przeczytane? - - - - Doing work necessary to send broadcast. - Wykonywanie dowodu pracy niezbędnego do wysłania przekazu. - - - - Proof of work pending - Dowód pracy zawieszony - - - - %n object(s) pending proof of work - Zawieszony dowód pracy %n obiektuZawieszony dowód pracy %n obiektówZawieszony dowód pracy %n obiektówZawieszony dowód pracy %n obiektów - - - - %n object(s) waiting to be distributed - %n obiekt oczekuje na wysłanie%n obiektów oczekuje na wysłanie%n obiektów oczekuje na wysłanie%n obiektów oczekuje na wysłanie - - - - Wait until these tasks finish? - Czy poczekać aż te zadania zostaną zakończone? - - - - Problem communicating with proxy: %1. Please check your network settings. - Błąd podczas komunikacji z proxy: %1. Proszę sprawdź swoje ustawienia sieci. - - - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - Problem z autoryzacją SOCKS5: %1. Proszę sprawdź swoje ustawienia SOCKS5. - - - - The time on your computer, %1, may be wrong. Please verify your settings. - Czas na Twoim komputerze, %1, może być błędny. Proszę sprawdź swoje ustawienia. - - - - The name %1 was not found. - Ksywka %1 nie została znaleziona. - - - - The namecoin query failed (%1) - Zapytanie namecoin nie powiodło się (%1) - - - - The namecoin query failed. - Zapytanie namecoin nie powiodło się. - - - - The name %1 has no valid JSON data. - Ksywka %1 nie zawiera prawidłowych danych JSON. - - - - The name %1 has no associated Bitmessage address. - Ksywka %1 nie ma powiązanego adresu Bitmessage. - - - - Success! Namecoind version %1 running. - Namecoind wersja %1 działa poprawnie! - - - - Success! NMControll is up and running. - NMControl działa poprawnie! - - - - Couldn't understand NMControl. - Nie można zrozumieć NMControl. - - - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Twoje procesory graficzne nie obliczyły poprawnie, wyłączam OpenCL. Prosimy zaraportować przypadek twórcom programu. - - - - Set notification sound... - Ustaw dźwięk powiadomień… - - - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Witamy w przyjaznym i bezpiecznym Bitmessage -* wysyłaj wiadomości do innych użytkowników -* wysyłaj wiadomości subskrypcji (jak na Twitterze) -* dyskutuj na kanałach (chany) z innymi ludźmi - - - - not recommended for chans - niezalecany dla kanałów - - - - Quiet Mode - Tryb cichy - - - - Problems connecting? Try enabling UPnP in the Network Settings - Problem z połączeniem? Spróbuj włączyć UPnP w ustawieniach sieci. - - - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Próbujesz wysłać e-mail zamiast wiadomość bitmessage. To wymaga zarejestrowania się na bramce. Czy zarejestrować? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Błąd: adresy Bitmessage zaczynają się od BM-. Proszę sprawdzić adres odbiorcy %1. - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Błąd: adres odbiorcy %1 nie został skopiowany lub przepisany poprawnie. Proszę go sprawdzić. - - - - Error: The recipient address %1 contains invalid characters. Please check it. - Błąd: adres odbiorcy %1 zawiera nieprawidłowe znaki. Proszę go sprawdzić. - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Błąd: wersja adresu odbiorcy %1 jest za wysoka. Musisz albo zaktualizować Twoje oprogramowanie Bitmessage, albo twój znajomy Cię trolluje. - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są zbyt krótkie. Być może coś nie działa należycie w programie Twojego znajomego. - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są zbyt długie. Być może coś nie działa należycie w programie Twojego znajomego. - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Błąd: niektóre dane zakodowane w adresie odbiorcy %1 są uszkodzone. Być może coś nie działa należycie w programie Twojego znajomego. - - - - Error: Something is wrong with the recipient address %1. - Błąd: coś jest nie tak z adresem odbiorcy %1. - - - - Error: %1 - Błąd: %1 - - - - From %1 - Od %1 - - - - Synchronisation pending - Synchronizacja zawieszona - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage nie zsynchronizował się z siecią, %n obiekt oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiekty oczekują na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiektów oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji?Bitmessage nie zsynchronizował się z siecią, %n obiektów oczekuje na pobranie. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na zakończenie synchronizacji? - - - - Not connected - Niepołączony - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage nie połączył się z siecią. Jeżeli zamkniesz go teraz, może to spowodować opóźnienia dostarczeń. Czy poczekać na połączenie i zakończenie synchronizacji? - - - - Waiting for network connection... - Oczekiwanie na połączenie sieciowe… - - - - Waiting for finishing synchronisation... - Oczekiwanie na zakończenie synchronizacji… - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - Już ustawiłeś dźwięk powiadomienia dla tego kontaktu. Czy chcesz go zastąpić? - - - - Go online - Połącz - - - - Go offline - Rozłącz - - - - MessageView - - - Follow external link - Otwórz zewnętrzne łącze - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - Odnośnik "%1" zostanie otwarty w przeglądarce. Może to spowodować zagrożenie bezpieczeństwa, może on ujawnić Twoją anonimowość lub pobrać złośliwe dane. Czy jesteś pewien? - - - - HTML detected, click here to display - Wykryto HTML, kliknij tu, aby go wyświetlić - - - - Click here to disable HTML - Kliknij tutaj aby wyłączyć HTML - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - Wiadomość zawiera nierozpoznane kodowanie. -Prawdopodobnie powinieneś zaktualizować Bitmessage. - - - - Unknown encoding - Nierozpoznane kodowanie - - - - NewAddressDialog - - - Create new Address - Generuj nowy adres - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Tutaj możesz utworzyć tyle adresów, ile tylko potrzebujesz. W istocie, tworzenie nowych i porzucanie adresów jest zalecane. Możesz wygenerować adres używając albo losowych liczb albo hasła. Jeżeli użyjesz hasła, adres taki jest nazywany adresem „deterministycznym”. -Generowanie adresów „losowych” jest wybrane domyślnie, jednak deterministyczne adresy mają swoje wady i zalety: - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p><span style=" font-weight:600;">Zalety:<br/></span>Możesz wygenerować swój adres na każdym komputerze z głowy.<br/>Nie musisz się martwić o tworzenie kopii zapasowej pliku keys.dat tak długo jak pamiętasz hasło.</br><span style=" font-weight:600;">Wady:<br/></span>Musisz zapamiętać (bądź zapisać) swoje hasło, jeżeli chcesz odzyskać swój adres po utracie kluczy.</br>Musisz zapamiętać numer wersji adresu i numer strumienia razem z hasłem.</br>Jeżeli użyjesz słabego hasła, ktoś z Internetu może je odgadnąć i przeczytać wszystkie Twoje wiadomości i wysyłać wiadomości jako Ty.</p></body></html> - - - - Use a random number generator to make an address - Użyj generatora liczb losowych do utworzenia adresu - - - - Use a passphrase to make addresses - Użyj hasła do utworzenia adresu - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Dołóż kilka minut dodatkowych obliczeń aby wygenerować adres(y) krótsze o 1 lub 2 znaki - - - - Make deterministic addresses - Utwórz adres deterministyczny - - - - Address version number: 4 - Numer wersji adresu: 4 - - - - In addition to your passphrase, you must remember these numbers: - Razem ze swoim hasłem musisz zapamiętać te liczby: - - - - Passphrase - Hasło - - - - Number of addresses to make based on your passphrase: - Liczba adresów do wygenerowanie na podstawie hasła: - - - - Stream number: 1 - Numer strumienia: 1 - - - - Retype passphrase - Hasło ponownie - - - - Randomly generate address - Adres losowy - - - - Label (not shown to anyone except you) - Etykieta (nie wyświetlana komukolwiek oprócz Ciebie) - - - - Use the most available stream - Użyj najbardziej dostępnego strumienia - - - - (best if this is the first of many addresses you will create) - (zalecane, jeżeli jest to pierwszy z adresów który chcesz utworzyć) - - - - Use the same stream as an existing address - Użyj tego samego strumienia co istniejący adres - - - - (saves you some bandwidth and processing power) - (oszczędza trochę transferu i mocy procesora) - - - - NewSubscriptionDialog - - - Add new entry - Dodaj nowy wpis - - - - Label - Etykieta - - - - Address - Adres - - - - Enter an address above. - Wprowadź adres powyżej. - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - Specjalne zachowanie adresu - - - - Behave as a normal address - Zachowuj się jak normalny adres - - - - Behave as a pseudo-mailing-list address - Zachowuj się jak pseudo-lista-dyskusyjna - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Wiadomości wysłane na pseudo-listę-dyskusyjną zostaną automatycznie rozesłane do abonentów (i w ten sposób będą publiczne). - - - - Name of the pseudo-mailing-list: - Nazwa pseudo-listy-dyskusyjnej: - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - - - - aboutDialog - - - About - O programie - - - - PyBitmessage - - - - - version ? - - - - - <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> - <html><head/><body><p>Rozpowszechniane na licencji MIT/X11 software license; zobacz <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> - - - - This is Beta software. - To jest wersja Beta. - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Prawa autorskie © 2012-2016 Jonathan Warren<br/>Prawa autorskie © 2013-2017 Programiści Bitmessage</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Użyj czarnej listy (zezwala na wszystkie przychodzące wiadomości, z wyjątkiem tych na czarnej liście) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Użyj białej listy (blokuje wszystkie wiadomości, z wyjątkiem o tych na białej liście) - - - - Add new entry - Dodaj wpis - - - - Name or Label - Nazwa lub etykieta - - - - Address - Adres - - - - Blacklist - Czarna lista - - - - Whitelist - Biała lista - - - - connectDialog - - - Bitmessage - Bitmessage - - - - Bitmessage won't connect to anyone until you let it. - Bitmessage nie połączy się, zanim mu na to nie pozwolisz. - - - - Connect now - Połącz teraz - - - - Let me configure special network settings first - Pozwól mi najpierw ustawić specjalne opcje konfiguracji sieci - - - - Work offline - Działaj bez sieci - - - - helpDialog - - - Help - Pomoc - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - Ponieważ Bitmessage jest tworzone przez społeczność, możesz uzyskać pomoc w sieci na wiki Bitmessage: - - - - iconGlossaryDialog - - - Icon Glossary - Opis ikon - - - - You have no connections with other peers. - Nie masz żadnych połączeń z innymi użytkownikami. - - - - 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. - Masz co najmniej jedno połączenie wychodzące z innymi użytkownikami, ale nie masz jeszcze żadnych połączeń przychodzących. Twoja zapora sieciowa lub domowy ruter prawdopodobnie nie są poprawnie skonfigurowane aby przekazywać połączenia przychodzące TCP na Twój komputer. Bitmessage będzie działał dobrze, ale byłoby fajnie, gdybyś pomógł sieci Bitmessage i zezwolił na połączenia przychodzące. - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - Masz połączenia z innymi użytkownikami i twoja zapora sieciowa jest skonfigurowana poprawnie. - - - - You are using TCP port %1. (This can be changed in the settings). - Btimessage używa portu TCP %1. (Można go zmienić w ustawieniach). - - - - networkstatus - - - Total connections: - Wszystkich połączeń: - - - - Since startup: - Od startu: - - - - Processed 0 person-to-person messages. - Przetworzono 0 wiadomości zwykłych. - - - - Processed 0 public keys. - Przetworzono 0 kluczy publicznych. - - - - Processed 0 broadcasts. - Przetworzono 0 wiadomości subskrypcji. - - - - Inventory lookups per second: 0 - Zapytań o elementy na sekundę: 0 - - - - Objects to be synced: - Obiektów do zsynchronizowania: - - - - Stream # - Strumień # - - - - Connections - - - - - Since startup on %1 - Od startu programu o %1 - - - - Down: %1/s Total: %2 - Pobieranie: %1/s W całości: %2 - - - - Up: %1/s Total: %2 - Wysyłanie: %1/s W całości: %2 - - - - Total Connections: %1 - Wszystkich połączeń: %1 - - - - Inventory lookups per second: %1 - Zapytań o elementy na sekundę: %1 - - - - Up: 0 kB/s - Wysyłanie: 0 kB/s - - - - Down: 0 kB/s - Pobieranie: 0 kB/s - - - - Network Status - Stan sieci - - - - byte(s) - bajtbajtówbajtówbajtów - - - - Object(s) to be synced: %n - Jeden obiekt do zsynchronizowaniaObieków do zsynchronizowania: %nObieków do zsynchronizowania: %nObieków do zsynchronizowania: %n - - - - Processed %n person-to-person message(s). - Przetworzono %n wiadomość zwykłą.Przetworzono %n wiadomości zwykłych.Przetworzono %n wiadomości zwykłych.Przetworzono %n wiadomości zwykłych. - - - - Processed %n broadcast message(s). - Przetworzono %n wiadomość subskrypcji.Przetworzono %n wiadomości subskrypcji.Przetworzono %n wiadomości subskrypcji.Przetworzono %n wiadomości subskrypcji. - - - - Processed %n public key(s). - Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. - - - - Peer - Użytkownik - - - - IP address or hostname - IP lub nazwa hosta - - - - Rating - Ocena - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage rejestruje pomyślność prób połączeń z indywidualnymi węzłami. Ocena przyjmuje wartości od -1 do 1 i ma wpływ na prawdopodobieństwo wybrania węzła w przyszłości. - - - - User agent - Klient - - - - Peer's self-reported software - Ogłaszana aplikacja kliencka - - - - TLS - TLS - - - - Connection encryption - Szyfrowanie połączenia - - - - List of streams negotiated between you and the peer - Lista strumieni negocjowanych pomiędzy Tobą i użytkownikiem - - - - newChanDialog - - - Dialog - - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - Create or join a chan - Utwórz lub dołącz do kanału - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Kanał powstałe wtedy, jeżeli grupa ludzi dzieli się tymi samymi kluczami szyfrującymi. Klucze i adres używane przez kanał są generowane z łatwego do zapamiętania słowa bądź hasła (nazwa kanału). Aby wysłać wiadomość do każdego na kanale, wyślij zwykłą wiadomość na adres kanału.</p><p>Kanały są eksperymentem i są poza wszelką kontrolą.</p><p>Wpisz nazwę swojego kanału. Jeżeli wybierzesz wystarczająco złożoną nazwę kanału (tak jak mocne i unikalne hasło) i nikt z Twoich przyjaciół nie ujawni go publicznie, wtedy Twój kanał będzie bezpieczny i prywatny. Jeżeli Ty i ktoś inny utworzy kanał o tej samej nazwie, wtedy prawdopodobnie będzie to ten sam kanał.</p></body></html> - - - - Chan passphrase/name: - Nazwa/hasło kanału: - - - - Optional, for advanced usage - Opcjonalne, dla zaawansowanych - - - - Chan address - Adres kanału - - - - Please input chan name/passphrase: - Proszę wpisz nazwę/hasło kanału: - - - - newchandialog - - - Successfully created / joined chan %1 - Pomyślnie utworzono / dołączono do kanału %1 - - - - Chan creation / joining failed - Utworzenie / dołączenie do kanału nie powiodło się - - - - Chan creation / joining cancelled - Utworzenie / dołączenie do kanału przerwane - - - - proofofwork - - - C PoW module built successfully. - Moduł C PoW zbudowany poprawnie. - - - - Failed to build C PoW module. Please build it manually. - Nie można zbudować modułu C PoW. Prosimy zbudować go ręcznie. - - - - C PoW module unavailable. Please build it. - Moduł C PoW niedostępny. Prosimy zbudować go. - - - - qrcodeDialog - - - QR-code - Kod QR - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - Odtwórz istniejące adresy - - - - Regenerate existing addresses - Odtwórz istniejące adresy - - - - Passphrase - Hasło - - - - Number of addresses to make based on your passphrase: - Liczba adresów do wygenerowanie na podstawie hasła: - - - - Address version number: - Numer wersji adresu: - - - - Stream number: - Numer strumienia: - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Dołóż kilka minut dodatkowych obliczeń aby wygenerować adres(y) krótsze o 1 lub 2 znaki - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Musisz to zaznaczyć (albo nie zaznaczyć) jeżeli zaznaczyłeś (bądź nie zaznaczyłeś) to podczas tworzenia adresu po raz pierwszy. - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Jeżeli poprzednio wygenerowałeś deterministyczne adresy, ale je straciłeś przez przypadek (jak np. awaria dysku), możesz je tutaj odtworzyć. Jeżeli użyłeś generatora liczb losowych do utworzenia adresu, wtedy ten formularz jest dla Ciebie bezużyteczny. - - - - settingsDialog - - - Settings - Ustawienia - - - - Start Bitmessage on user login - Uruchom Bitmessage po zalogowaniu - - - - Tray - Zasobnik systemowy - - - - Start Bitmessage in the tray (don't show main window) - Uruchom Bitmessage w zasobniku (nie pokazuj głównego okna) - - - - Minimize to tray - Minimalizuj do zasobnika - - - - Close to tray - Zamknij do zasobnika - - - - Show notification when message received - Wyświetl powiadomienia o przychodzących wiadomościach - - - - Run in Portable Mode - Uruchom w trybie przenośnym - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - W trybie przenośnym, wiadomości i pliki konfiguracyjne są przechowywane w tym samym katalogu co program, zamiast w osobistym katalogu danych użytkownika. To sprawia, że wygodnie można uruchamiać Bitmessage z pamięci przenośnych. - - - - Willingly include unencrypted destination address when sending to a mobile device - Chętnie umieść niezaszyfrowany adres docelowy podczas wysyłania na urządzenia przenośne. - - - - Use Identicons - Użyj graficznych awatarów - - - - Reply below Quote - Odpowiedź pod cytatem - - - - Interface Language - Język interfejsu - - - - System Settings - system - Język systemu - - - - User Interface - Interfejs - - - - Listening port - Port nasłuchujący - - - - Listen for connections on port: - Nasłuchuj połaczeń na porcie: - - - - UPnP: - UPnP: - - - - Bandwidth limit - Limity przepustowości - - - - Maximum download rate (kB/s): [0: unlimited] - Maksymalna prędkość pobierania (w kB/s): [0: bez limitu] - - - - Maximum upload rate (kB/s): [0: unlimited] - Maksymalna prędkość wysyłania (w kB/s): [0: bez limitu] - - - - Proxy server / Tor - Serwer proxy / Tor - - - - Type: - Typ: - - - - Server hostname: - Adres serwera: - - - - Port: - Port: - - - - Authentication - Uwierzytelnienie - - - - Username: - Użytkownik: - - - - Pass: - Hasło: - - - - Listen for incoming connections when using proxy - Nasłuchuj przychodzących połączeń podczas używania proxy - - - - none - brak - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Sieć - - - - Total difficulty: - Całkowita trudność: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - 'Całkowita trudność' ma wpływ na całkowitą ilość pracy jaką nadawca musi wykonać. Podwojenie tej wartości, podwaja ilość pracy do wykonania. - - - - Small message difficulty: - Trudność małej wiadomości: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Kiedy ktoś wysyła Ci wiadomość, jego komputer musi najpierw wykonać dowód pracy. Trudność tej pracy domyślnie wynosi 1. Możesz podwyższyć tę wartość dla nowo-utworzonych adresów podwyższając wartości tutaj. Każdy nowy adres będzie wymagał przez nadawców wyższej trudności. Jest jeden wyjątek: jeżeli dodasz kolegę do swojej książki adresowej, Bitmessage automatycznie powiadomi go kiedy następnym razem wyślesz do niego wiadomość, że musi tylko wykonać minimalną ilość pracy: trudność 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - 'Trudność małej wiadomości' głównie ma wpływ na trudność wysyłania małych wiadomości. Podwojenie tej wartości, prawie podwaja pracę potrzebną do wysłania małej wiadomości, ale w rzeczywistości nie ma wpływu na większe wiadomości. - - - - Demanded difficulty - Wymagana trudność - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Tutaj możesz ustawić maksymalną ilość pracy jaką zamierzasz wykonać aby wysłać wiadomość innej osobie. Ustawienie tych wartości na 0 oznacza, że każda wartość jest akceptowana. - - - - Maximum acceptable total difficulty: - Maksymalna akceptowalna całkowita trudność: - - - - Maximum acceptable small message difficulty: - Maksymalna akceptowalna trudność dla małych wiadomości: - - - - Max acceptable difficulty - Maksymalna akceptowalna trudność - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage potrafi wykorzystać inny program oparty na Bitcoinie - Namecoin - aby sprawić adresy czytelnymi dla ludzi. Na przykład, zamiast podawać koledze swój długi adres Bitmessage, możesz po prostu powiedzieć mu aby wysłał wiadomość pod <span style=" font-style:italic;">id/ksywka</span>.</p><p>(Utworzenie swojego adresu Bitmessage w Namecoinie jest ciągle racze trudne).</p><p>Bitmessage może skorzystać albo bezpośrednio z namecoind, albo z działającego wątku nmcontrol.</p></body></html> - - - - Host: - Host: - - - - Password: - Hasło: - - - - Test - Test - - - - Connect to: - Połącz z: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Połączenie z Namecoin - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Domyślnie jeżeli wyślesz wiadomość do kogoś i ta osoba będzie poza siecią przez jakiś czas, Bitmessage spróbuje ponownie wysłać wiadomość trochę później, i potem ponownie. Program będzie próbował wysyłać wiadomość do czasu aż odbiorca potwierdzi odbiór. Tutaj możesz zmienić kiedy Bitmessage ma zaprzestać próby wysyłania.</p><p>Pozostaw te poza puste, aby ustawić domyślne zachowanie.</p></body></html> - - - - Give up after - Poddaj się po - - - - and - i - - - - days - dniach - - - - months. - miesiącach. - - - - Resends Expire - Niedoręczone wiadomości - - - - Hide connection notifications - Nie pokazuj powiadomień o połączeniu - - - - Maximum outbound connections: [0: none] - Maksymalnych połączeń wychodzących: [0: brak] - - - - Hardware GPU acceleration (OpenCL): - Przyspieszenie sprzętowe GPU (OpenCL): - - - \ No newline at end of file diff --git a/src/translations/bitmessage_pt.qm b/src/translations/bitmessage_pt.qm deleted file mode 100644 index 9c6b3402..00000000 Binary files a/src/translations/bitmessage_pt.qm and /dev/null differ diff --git a/src/translations/bitmessage_pt.ts b/src/translations/bitmessage_pt.ts deleted file mode 100644 index 8c43b926..00000000 --- a/src/translations/bitmessage_pt.ts +++ /dev/null @@ -1,2094 +0,0 @@ - - - - AddAddressDialog - - - Add new entry - Adiciona nova entrada - - - - Label - Rótulo - - - - Address - Morada - - - - EmailGatewayDialog - - - Email gateway - Email gateway - - - - Register on email gateway - Registar na email gateway - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - - - MainWindow - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Address Book - - - - - Add sender to your Blacklist - - - - - Move to Trash - - - - - Undelete - - - - - View HTML code as formatted text - - - - - Save message as... - - - - - Mark Unread - - - - - New - - - - - Enable - - - - - Disable - - - - - Set avatar... - - - - - Copy address to clipboard - - - - - Special address behavior... - - - - - Email gateway - Email gateway - - - - Delete - Apagar - - - - Send message to this address - Enviar mensagem para esta morada - - - - Subscribe to this address - Subscrever esta morada - - - - Add New Address - Adiciona nova morada - - - - Copy destination address to clipboard - Copia morada de destino para o clipboard - - - - Force send - - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - - - - - Waiting for their encryption key. Will request it again soon. - Aguardando chave de encriptação. Novo pedido em breve. - - - - Encryption key request queued. - - - - - Queued. - Em fila - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Mensagem enviada. Aguardando confirmação. Enviada a %1 - - - - Message sent. Sent at %1 - Mensagem enviada. Enviada a 1% - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - - - - - Broadcast queued. - - - - - Broadcast on %1 - - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - - - - - Forced difficulty override. Send should start soon. - - - - - Unknown status: %1 %2 - - - - - Not Connected - Não está ligado - - - - Show Bitmessage - Mostra Bitmessage - - - - Send - Enviar - - - - Subscribe - Subscrever - - - - Channel - Canal - - - - Quit - Desligar - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - - - - - Open keys.dat? - - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - Delete trash? - Esvaziar lixo? - - - - Are you sure you want to delete all trashed messages? - - - - - bad passphrase - - - - - You must type your passphrase. If you don't have one then this is not the form for you. - - - - - Bad address version number - - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - - - - - Connected - - - - - Message trashed - - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - - - - - Address version number - - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Stream number - - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - - - - Message queued. - - - - - Your 'To' field is empty. - - - - - Right click one or more entries in your address book and select 'Send message to this address'. - - - - - Fetched address from namecoin identity. - - - - - New Message - - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - - - - - The address you entered was invalid. Ignoring it. - - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - - - - - You must restart Bitmessage for the port number change to take effect. - - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - - - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - - - - - Write error. - - - - - No addresses selected. - - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - - - - - Identities - - - - - New Identity - - - - - Search - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - Received - - - - - Messages - - - - - Address book - - - - - Address - Morada - - - - Add Contact - - - - - Fetch Namecoin ID - - - - - Subject: - - - - - From: - - - - - To: - - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - File - - - - - Settings - Configurações - - - - Help - - - - - Import keys - Importar chaves - - - - Manage keys - Gerir chaves - - - - Ctrl+Q - Ctrl+Q - - - - F1 - - - - - Contact support - - - - - About - Acerca - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - - - - - Zoom level %1% - - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - Adiciona nova entrada - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - - - - %n day(s) - - - - - - - - Shutting down PyBitmessage... %1% - - - - - Sent - - - - - Generating one new address - - - - - Done generating address. Doing work necessary to broadcast it... - - - - - Generating %1 new addresses. - - - - - %1 is already in 'Your Identities'. Not adding it again. - - - - - Done generating address - - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - - Error! Could not find sender address (your address) in the keys.dat file. - - - - - Doing work necessary to send broadcast... - - - - - Broadcast sent on %1 - - - - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - Mark all messages as read - - - - - Are you sure you would like to mark all messages read? - - - - - NewAddressDialog - - - Create new Address - - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - - Use a random number generator to make an address - - - - - Use a passphrase to make addresses - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - Make deterministic addresses - - - - - Address version number: 4 - - - - - In addition to your passphrase, you must remember these numbers: - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Stream number: 1 - - - - - Retype passphrase - - - - - Randomly generate address - - - - - Label (not shown to anyone except you) - - - - - Use the most available stream - - - - - (best if this is the first of many addresses you will create) - - - - - Use the same stream as an existing address - - - - - (saves you some bandwidth and processing power) - - - - - NewSubscriptionDialog - - - Add new entry - Adiciona nova entrada - - - - Label - Rótulo - - - - Address - Morada - - - - Enter an address above. - - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - - - - - Behave as a normal address - - - - - Behave as a pseudo-mailing-list address - - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - - - - - Name of the pseudo-mailing-list: - - - - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - aboutDialog - - - About - Acerca - - - - PyBitmessage - - - - - version ? - versão? - - - - <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> - - - - - This is Beta software. - Este software é Beta. - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - Adiciona nova entrada - - - - Name or Label - - - - - Address - Morada - - - - Blacklist - - - - - Whitelist - - - - - connectDialog - - - Bitmessage - - - - - Bitmessage won't connect to anyone until you let it. - - - - - Connect now - Ligar agora - - - - Let me configure special network settings first - - - - - helpDialog - - - Help - - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - - - - - iconGlossaryDialog - - - Icon Glossary - - - - - You have no connections with other peers. - - - - - 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. - - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - - - - - networkstatus - - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - - - - Object(s) to be synced: %n - - - - - - - - Processed %n person-to-person message(s). - - - - - - - - Processed %n broadcast message(s). - - - - - - - - Processed %n public key(s). - - - - - - - - newChanDialog - - - Dialog - - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - - - - - Regenerate existing addresses - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Address version number: - - - - - Stream number: - - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - - - - - settingsDialog - - - Settings - Configurações - - - - Start Bitmessage on user login - - - - - Tray - - - - - Start Bitmessage in the tray (don't show main window) - - - - - Minimize to tray - - - - - Close to tray - - - - - Show notification when message received - - - - - Run in Portable Mode - - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - - - - - Willingly include unencrypted destination address when sending to a mobile device - - - - - Use Identicons - - - - - Reply below Quote - - - - - Interface Language - - - - - System Settings - system - - - - - User Interface - - - - - Listening port - - - - - Listen for connections on port: - - - - - UPnP: - - - - - Bandwidth limit - - - - - Maximum download rate (kB/s): [0: unlimited] - - - - - Maximum upload rate (kB/s): [0: unlimited] - - - - - Proxy server / Tor - - - - - Type: - - - - - Server hostname: - - - - - Port: - Porta: - - - - Authentication - Autenticação - - - - Username: - Nome de utilizador: - - - - Pass: - - - - - Listen for incoming connections when using proxy - - - - - none - nenhum - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Configurações de Rede - - - - Total difficulty: - Dificuldade Máxima: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - - Small message difficulty: - - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - - - - - Maximum acceptable small message difficulty: - - - - - Max acceptable difficulty - - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - - - - - Password: - Palavra-passe: - - - - Test - Teste - - - - Connect to: - Ligar a: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Integração Namecoin - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - - Give up after - - - - - and - e - - - - days - dias - - - - months. - meses - - - - Resends Expire - - - - diff --git a/src/translations/bitmessage_ru.pro b/src/translations/bitmessage_ru.pro new file mode 100644 index 00000000..5d74581c --- /dev/null +++ b/src/translations/bitmessage_ru.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.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\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_ru.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 53d58f01..f0bd6342 100644 Binary files a/src/translations/bitmessage_ru.qm and b/src/translations/bitmessage_ru.qm differ diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index ffb2eac9..e72011ca 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -1,1927 +1,1303 @@ - + + + AddAddressDialog - + Add new entry Добавить новую запись - + Label - Имя + Имя - + Address - Адрес - - - - EmailGatewayDialog - - - Email gateway - Email-шлюз - - - - Register on email gateway - Зарегистрироваться на Email-шлюзе - - - - Account status at email gateway - Статус аккаунта Email-шлюза - - - - Change account settings at email gateway - Изменить настройки аккаунта Email-шлюза - - - - Unregister from email gateway - Отменить регистрацию на Email-шлюзе - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - Email-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только шлюз Mailchuck (@mailchuck.com). - - - - Desired email address (including @mailchuck.com): - Желаемый email-адрес (включая @mailchuck.com) - - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - Регистрация не удалась: - - - - The requested email address is not available, please try a new one. - Запрашиваемый адрес email недоступен, попробуйте ввести другой. - - - - Sending email gateway registration request - Отправка запроса на регистрацию на Email-шлюзе - - - - Sending email gateway unregistration request - Отправка запроса на отмену регистрации на Email-шлюзе - - - - Sending email gateway status request - Отправка запроса статуса аккаунта на Email-шлюзе - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Эти параметры можно использовать для настройки аккаунта email-шлюза -# Раскомментируйте (уберите символ #) те параметры, которые хотите использовать -# Параметры: -# -# pgp: server -# Email-шлюз будет создавать и управлять PGP-ключами за вас, а также подписывать, проверять, -# шифровать и дешифровать от вашего имени. Используйте это, если вы желаете использовать PGP, но очень ленивы. -# Этот настройка требует подписки. -# -# pgp: local -# Шлюз электронной почты не будет проводить операции PGP от вашего имени. -# Вы можете не использовать PGP, или использовать его локально. -# -# attachments: yes -# Вложения во входящий email-сообщениях будут загружены на MEGA.nz, -# вы сможете скачать из оттуда по ссылке. Требуется подписка. -# -# attachments: no -# Вложения будут проигнорированы. -# -# archive: yes -# Входящие email-сообщения будут заархивированы на сервере. Используйте эту настройку -# в целях отладки, или если вам нужно подтверждение email третьей стороной. -# Конечно, это означает, что оператор сервиса будет иметь возможность читать ваши email -# даже после доставки их вам. -# -# archive: no -# Входящие email-сообщения будут удалены с сервера после доставки их вам. -# -# masterpubkey_btc: BIP44 xpub key или electrum v1 public seed -# offset_btc: целое число (по умолчанию 0) -# feeamount: число, содержащее до 8 десятичных цифр -# feecurrency: BTC, XBT, USD, EUR или GBP -# Используйте эту настроку, если хотите чтобы отправитель уплатил вознаграждение за отправку email вам. -# Если настройка включена, и неизвестный отправитель посылает вам email, -# то отправителю будет предложено уплатить указанное вознаграждение. -# Схема использует детерминистические открытые ключи, вы получите деньги напрямую. -# Чтобы выключить уплату вознаграждения, установите "feeamount" равным 0. -# Требует подписки. + Адрес MainWindow - - Reply to sender - Ответить отправителю - - - - Reply to channel - Ответить в канал - - - - Add sender to your Address Book - Добавить отправителя в адресную книгу - - - - Add sender to your Blacklist - Добавить отправителя в чёрный список - - - - Move to Trash - Поместить в корзину - - - - Undelete - Отменить удаление - - - - View HTML code as formatted text - Просмотреть HTML код как отформатированный текст - - - - Save message as... - Сохранить сообщение как ... - - - - Mark Unread - Отметить как непрочитанное - - - - New - Новый адрес - - - - Enable - Включить - - - - Disable - Выключить - - - - Set avatar... - Установить аватар... - - - - Copy address to clipboard - Скопировать адрес в буфер обмена - - - - Special address behavior... - Особое поведение адресов... - - - - Email gateway - Email-шлюз - - - - Delete - Удалить - - - - Send message to this address - Отправить сообщение на этот адрес - - - - Subscribe to this address - Подписаться на рассылку с этого адреса - - - - Add New Address - Добавить новый адрес - - - - Copy destination address to clipboard - Скопировать адрес отправки в буфер обмена - - - - Force send - Форсировать отправку - - - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? Один из Ваших адресов, %1, является устаревшим адресом версии 1. Адреса версии 1 больше не поддерживаются. Хотите ли Вы удалить его сейчас? - - Waiting for their encryption key. Will request it again soon. - Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. + + Reply + Ответить - - Encryption key request queued. - + + Add sender to your Address Book + Добавить отправителя в адресную книгу - - Queued. - В очереди. + + Move to Trash + Поместить в корзину - - Message sent. Waiting for acknowledgement. Sent at %1 - Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 + + View HTML code as formatted text + Просмотреть HTML код как отформатированный текст - - Message sent. Sent at %1 - Сообщение отправлено в %1 + + Save message as... + Сохранить сообщение как ... - - Need to do work to send message. Work is queued. - + + New + Новый адрес - - Acknowledgement of the message received %1 - Доставлено в %1 + + Enable + Включить - - Broadcast queued. - Рассылка ожидает очереди. + + Disable + Выключить - - Broadcast on %1 - Рассылка на %1 + + Copy address to clipboard + Скопировать адрес в буфер обмена - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Проблема: Ваш получатель требует более сложных вычислений, чем максимум, указанный в Ваших настройках. %1 + + Special address behavior... + Особое поведение адресов... - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Проблема: ключ получателя неправильный. Невозможно зашифровать сообщение. %1 + + Send message to this address + Отправить сообщение на этот адрес - - Forced difficulty override. Send should start soon. - Форсирована смена сложности. Отправляем через некоторое время. + + Subscribe to this address + Подписаться на рассылку с этого адреса - - Unknown status: %1 %2 - Неизвестный статус: %1 %2 + + Add New Address + Добавить новый адрес - - Not Connected - Не соединено + + Delete + Удалить - - Show Bitmessage - Показать Bitmessage + + Copy destination address to clipboard + Скопировать адрес отправки в буфер обмена - - Send - Отправить + + Force send + Форсировать отправку - - Subscribe - Подписки - - - - Channel - Канал - - - - Quit - Выйти - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в той же папке, что и эта программа. -Создайте резервную копию этого файла перед тем как будете его редактировать. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в - %1 -Создайте резервную копию этого файла перед тем как будете его редактировать. - - - - Open keys.dat? - Открыть файл keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в той же папке, что и эта программа. -Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? -(пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в - %1 -Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? -(пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) - - - - Delete trash? - Очистить корзину? - - - - Are you sure you want to delete all trashed messages? - Вы уверены что хотите очистить корзину? - - - - bad passphrase - Неподходящая секретная фраза - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Вы должны ввести секретную фразу. Если Вы не хотите этого делать, то Вы выбрали неправильную опцию. - - - - Bad address version number - Неверный номер версии адреса - - - - Your address version number must be a number: either 3 or 4. - Адрес номера версии должен быть числом: либо 3, либо 4. - - - - Your address version number must be either 3 or 4. - Адрес номера версии должен быть либо 3, либо 4. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Соединение потеряно - - - - Connected - Соединено - - - - Message trashed - Сообщение удалено - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - TTL или Time-To-Live (время жизни) это время, в течение которого сеть хранит ваше сообщение. -Получатель должен получить сообщение в течение этого времени. Если ваш клиент Bitmessage не получит подтверждение доставки, -он переотправит сообщение автоматически. Чем больше TTL, тем больше расчётов ваш компьютер должен сделать, чтобы отправить -сообщение. Часто разумным вариантом будет установка TTL на 4 или 5 дней. - - - - Message too long - Сообщение слишком длинное - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Сообщение, которое вы пытаетесь отправить, длиннее максимально допустимого на %1 байт. (Максимально допустимое значение 261644 байта). Пожалуйста, сократите сообщение перед отправкой. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Ошибка: ваш аккаунт не зарегистрирован на Email-шлюзе. Отправка регистрации %1, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Вы должны указать адрес в поле "От кого". Вы можете найти Ваш адрес во вкладке "Ваши Адреса". - - - - Address version number - Версия адреса - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - По поводу адреса %1: Bitmessage не поддерживаем адреса версии %2. Возможно, Вам нужно обновить клиент Bitmessage. - - - - Stream number - Номер потока - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - По поводу адреса %1: Bitmessage не поддерживаем стрим номер %2. Возможно, Вам нужно обновить клиент Bitmessage. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Внимание: Вы не подключены к сети. Bitmessage выполнит работу, требуемую для отправки сообщения, но не отправит его до тех пор, пока Вы не подключитесь. - - - - Message queued. - Сообщение в очереди. - - - - Your 'To' field is empty. - Вы не заполнили поле 'Кому'. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Нажмите правую кнопку мыши на каком-либо адресе и выберите "Отправить сообщение на этот адрес". - - - - Fetched address from namecoin identity. - Получить адрес через Namecoin. - - - - New Message - Новое сообщение - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - Адрес введен правильно. - - - - The address you entered was invalid. Ignoring it. - Вы ввели неправильный адрес. Это адрес проигнорирован. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Ошибка: Вы не можете добавлять один и тот же адрес в Адресную Книгу несколько раз. Попробуйте переименовать существующий адрес. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Ошибка: вы не можете добавить один и тот же адрес в ваши подписки дважды. Пожалуйста, переименуйте имеющийся адрес, если хотите. - - - - Restart - Перезапустить - - - - You must restart Bitmessage for the port number change to take effect. - Вы должны перезапустить Bitmessage, чтобы смена номера порта имела эффект. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage будет использовать Ваш прокси, начиная прямо сейчас. Тем не менее Вам имеет смысл перезапустить Bitmessage, чтобы закрыть уже существующие соединения. - - - - Number needed - Требуется число - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Скорости загрузки и выгрузки должны быть числами. Игнорирую то, что вы набрали. - - - - Will not resend ever - Не пересылать никогда - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Обратите внимание, что лимит времени, который вы ввели, меньше чем время, которое Bitmessage ждет перед первой попыткой переотправки сообщения, поэтому ваши сообщения никогда не будут переотправлены. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Секретная фраза не подходит - - - - The passphrase you entered twice doesn't match. Try again. - Вы ввели две разные секретные фразы. Пожалуйста, повторите заново. - - - - Choose a passphrase - Придумайте секретную фразу - - - - You really do need a passphrase. - Вы действительно должны ввести секретную фразу. - - - - Address is gone - Адрес утерян - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage не может найти Ваш адрес %1. Возможно Вы удалили его? - - - - Address disabled - Адрес выключен - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Ошибка: адрес, с которого Вы пытаетесь отправить, выключен. Вам нужно будет включить этот адрес во вкладке "Ваши адреса". - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - Запись добавлена в чёрный список. Измените название по своему вкусу. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Ошибка: вы не можете добавить один и тот же адрес в чёрный список дважды. Попробуйте переименовать существующий адрес. - - - - Moved items to trash. - Удалено в корзину. - - - - Undeleted item. - Элемент восстановлен. - - - - Save As... - Сохранить как ... - - - - Write error. - Ошибка записи. - - - - No addresses selected. - Вы не выбрали адрес. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Если вы отмените подписку, уже принятые сообщения станут недоступны! Возможно, вам стоит выключить подписку вместо ее отмены. Сообщения не приходят в отключенные подписки, но вы можете читать сообщения, которые уже приняты. - -Вы уверены, что хотите отменить подписку? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Если вы удалите канал, уже принятые сообщения станут недоступны! Возможно, вам стоит выключить канал вместо его удаления. Сообщения не приходят в отключенные каналы, но вы можете читать сообщения, которые уже были приняты. - -Вы уверены, что хотите удалить канал? - - - - Do you really want to remove this avatar? - Вы уверены, что хотите удалить этот аватар? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - У вас уже есть аватар для этого адреса. Вы уверены, что хотите перезаписать аватар? - - - - Start-on-login not yet supported on your OS. - Запуск программы при входе в систему ещё не поддерживается в вашей операционной системе. - - - - Minimize-to-tray not yet supported on your OS. - Сворачивание в трей ещё не поддерживается в вашей операционной системе. - - - - Tray notifications not yet supported on your OS. - Уведомления в трее ещё не поддерживаеются в вашей операционной системе. - - - - Testing... - Проверяем... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - Адрес должен начинаться с "BM-" - - - - The address is not typed or copied correctly (the checksum failed). - Адрес введен или скопирован неверно (контрольная сумма не сходится). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Версия этого адреса более поздняя, чем те, что поддерживает программа. Пожалуйста, обновите Bitmessage. - - - - The address contains invalid characters. - Адрес содержит запрещённые символы. - - - - Some data encoded in the address is too short. - Данные, закодированные в адресе, слишком короткие. - - - - Some data encoded in the address is too long. - Данные, закодированные в адресе, слишком длинные. - - - - Some data encoded in the address is malformed. - Данные, закодированные в адресе, имеют неверный формат. - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - Адрес старого типа. Мы не можем отобразить его прошлые рассылки. - - - - There are no recent broadcasts from this address to display. - Нет недавних рассылок с этого адреса для отображения. - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - Адреса - - - - New Identity - Создать новый адрес - - - - Search - Поиск - - - - All - По всем полям - - - - To - Кому - - - - From - От кого - - - - Subject - Тема - - - - Message - Текст сообщения - - - - Received - Получено - - - - Messages - Сообщения - - - - Address book - Адресная книга - - - - Address - Адрес - - - - Add Contact - Добавить контакт - - - - Fetch Namecoin ID - Получить Namecoin ID - - - - Subject: - Тема: - - - - From: - От: - - - - To: - Кому: - - - - Send ordinary Message - Отправить обычное сообщение - - - - Send Message to your Subscribers - Отправить сообщение для ваших подписчиков - - - - TTL: - TTL: - - - - Subscriptions - Подписки - - - - Add new Subscription - Добавить новую подписку - - - - Chans - Чаны - - - - Add Chan - Добавить чан - - - - File - Файл - - - - Settings - Настройки - - - - Help - Помощь - - - - Import keys - Импортировать ключи - - - - Manage keys - Управлять ключами - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Связаться с поддержкой - - - - About - О программе - - - - Regenerate deterministic addresses - Сгенерировать заново все адреса - - - - Delete all trashed messages - Стереть все сообщения из корзины - - - - Join / Create chan - Подключить или создать чан - - - - All accounts - Все аккаунты - - - - Zoom level %1% - Увеличение %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Ошибка: вы не можете добавить один и тот же адрес в ваш лист дважды. Попробуйте переименовать существующий адрес. - - - + Add new entry Добавить новую запись - - Display the %1 recent broadcast(s) from this address. - + + Waiting for their encryption key. Will request it again soon. + Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - Доступна новая версия PyBitmessage: %1. Загрузите её: https://github.com/Bitmessage/PyBitmessage/releases/latest + + Encryption key request queued. + Запрос ключа шифрования поставлен в очередь. - - Waiting for PoW to finish... %1% - Ожидание окончания PoW... %1% - - - - Shutting down Pybitmessage... %1% - Завершение PyBitmessage... %1% - - - - Waiting for objects to be sent... %1% - Ожидание отправки объектов... %1% - - - - Saving settings... %1% - Сохранение настроек... %1% - - - - Shutting down core... %1% - Завершение работы ядра... %1% - - - - Stopping notifications... %1% - Остановка сервиса уведомлений... %1% - - - - Shutdown imminent... %1% - Завершение вот-вот произойдет... %1% - - - - %n hour(s) - %n час%n часа%n часов%n час(а/ов) - - - %n day(s) - %n день%n дня%n дней%n дней + Queued. + В очереди. - - Shutting down PyBitmessage... %1% - Завершение PyBitmessage... %1% + + Message sent. Waiting for acknowledgement. Sent at %1 + Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - - Sent - Отправлено + + Need to do work to send message. Work is queued. + Нужно провести требуемые вычисления, чтобы отправить сообщение. Вычисления ожидают очереди. - - Generating one new address - Создание одного нового адреса + + Acknowledgement of the message received %1 + Сообщение доставлено в %1 - - Done generating address. Doing work necessary to broadcast it... - Создание адреса завершено. Выполнение работы, требуемой для его рассылки... + + Broadcast queued. + Рассылка ожидает очереди. - - Generating %1 new addresses. - Создание %1 новых адресов. + + Broadcast on %1 + Рассылка на %1 - - %1 is already in 'Your Identities'. Not adding it again. - %1 уже имеется в ваших адресах. Не добавляю его снова. + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + Проблема: Ваш получатель требует более сложных вычислений, чем максимум, указанный в Ваших настройках. %1 - - Done generating address - Создание адресов завершено. + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + Проблема: ключ получателя неправильный. Невозможно зашифровать сообщение. %1 - - SOCKS5 Authentication problem: %1 - + + Forced difficulty override. Send should start soon. + Форсирована смена сложности. Отправляем через некоторое время. - - Disk full - Диск переполнен + + Unknown status: %1 %2 + Неизвестный статус: %1 %2 - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. + + Since startup on %1 + С начала работы в %1 - - Error! Could not find sender address (your address) in the keys.dat file. - Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat + + Not Connected + Не соединено - - Doing work necessary to send broadcast... - Выполнение работы, требуемой для рассылки... + + Show Bitmessage + Показать Bitmessage - - Broadcast sent on %1 - Рассылка отправлена на %1 + + Send + Отправить - - Encryption key was requested earlier. - Ключ шифрования запрошен ранее. + + Subscribe + Подписки - - Sending a request for the recipient's encryption key. - Отправка запроса ключа шифрования получателя. + + Address Book + Адресная книга - - Looking up the receiver's public key - Поиск открытого ключа получателя + + Quit + Выйти - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Проблема: адресат является мобильным устройством, которое требует, чтобы адрес назначения был включен в сообщение, однако, это запрещено в ваших настройках. %1 + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. + Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в той же папке, что и эта программа. +Создайте резервную копию этого файла перед тем как будете его редактировать. - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Выполнение работы, требуемой для отправки сообщения. -Для адреса версии 2 (как этот), не требуется указание сложности. + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. + Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в + %1 +Создайте резервную копию этого файла перед тем как будете его редактировать. - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Выполнение работы, требуемой для отправки сообщения. -Получатель запросил сложность: %1 и %2 + + Open keys.dat? + Открыть файл keys.dat? - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Проблема: сложность, затребованная получателем (%1 и %2) гораздо больше, чем вы готовы сделать. %3 + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в той же папке, что и эта программа. +Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? +(пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 + + You may manage your keys by editing the keys.dat file stored in + %1 +It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) + Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в + %1 +Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? +(пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) - - Doing work necessary to send message. - Выполнение работы, требуемой для отправки сообщения. + + Delete trash? + Очистить корзину? - - Message sent. Waiting for acknowledgement. Sent on %1 - Отправлено. Ожидаем подтверждения. Отправлено в %1 + + Are you sure you want to delete all trashed messages? + Вы уверены что хотите очистить корзину? - - Doing work necessary to request encryption key. - Выполнение работы, требуемой для запроса ключа шифрования. + + bad passphrase + Неподходящая секретная фраза - - Broadcasting the public key request. This program will auto-retry if they are offline. - Рассылка запросов открытого ключа шифрования. Программа будет повторять попытки, если они оффлайн. + + You must type your passphrase. If you don't have one then this is not the form for you. + Вы должны ввести секретную фразу. Если Вы не хотите этого делать, то Вы выбрали неправильную опцию. - - Sending public key request. Waiting for reply. Requested at %1 - Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %1 + + Processed %1 person-to-person messages. + Обработано %1 сообщений. - - UPnP port mapping established on port %1 - Распределение портов UPnP завершилось выделением порта %1 + + Processed %1 broadcast messages. + Обработано %1 рассылок. - - UPnP port mapping removed - Распределение портов UPnP отменено + + Processed %1 public keys. + Обработано %1 открытых ключей. - - Mark all messages as read - Отметить все сообщения как прочтенные + + Total Connections: %1 + Всего соединений: %1 + + + + Connection lost + Соединение потеряно + + + + Connected + Соединено + + + + Message trashed + Сообщение удалено + + + + Error: Bitmessage addresses start with BM- Please check %1 + Ошибка: Bitmessage адреса начинаются с BM- Пожалуйста, проверьте %1 + + + + Error: The address %1 is not typed or copied correctly. Please check it. + Ошибка: адрес %1 внесен или скопирован неправильно. Пожалуйста, перепроверьте. + + + + Error: The address %1 contains invalid characters. Please check it. + Ошибка: адрес %1 содержит запрещённые символы. Пожалуйста, перепроверьте. + + + + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. + Ошибка: версия адреса в %1 слишком новая. Либо Вам нужно обновить Bitmessage, либо Ваш собеседник дал неправильный адрес. + + + + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. + Ошибка: некоторые данные, закодированные в адресе %1, слишком короткие. Возможно, что-то не так с программой Вашего собеседника. + + + + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. + Ошибка: некоторые данные, закодированные в адресе %1, слишком длинные. Возможно, что-то не так с программой Вашего собеседника. + + + + Error: Something is wrong with the address %1. + Ошибка: что-то не так с адресом %1. + + + + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. + Вы должны указать адрес в поле "От кого". Вы можете найти Ваш адрес во вкладе "Ваши Адреса". + + + + Sending to your address + Отправка на Ваш собственный адрес + + + + Error: One of the addresses to which you are sending a message, %1, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM. + Ошибка: Один из адресов, на который Вы отправляете сообщение, %1, принадлежит Вам. К сожалению, Bitmessage не может отправлять сообщения самому себе. Попробуйте запустить второго клиента на другом компьютере или на виртуальной машине. + + + + Address version number + Версия адреса + + + + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. + По поводу адреса %1: Bitmessage не поддерживаем адреса версии %2. Возможно, Вам нужно обновить клиент Bitmessage. + + + + Stream number + Номер потока + + + + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. + По поводу адреса %1: Bitmessage не поддерживаем стрим номер %2. Возможно, Вам нужно обновить клиент Bitmessage. + + + + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. + Внимание: Вы не подключены к сети. Bitmessage проделает необходимые вычисления, чтобы отправить сообщение, но не отправит его до тех пор, пока Вы не подсоединитесь к сети. + + + + Your 'To' field is empty. + Вы не заполнили поле 'Кому'. + + + + Work is queued. + Вычисления поставлены в очередь. + + + + Right click one or more entries in your address book and select 'Send message to this address'. + Нажмите правую кнопку мыши на каком-либо адресе и выберите "Отправить сообщение на этот адрес". + + + + Work is queued. %1 + Вычисления поставлены в очередь. %1 + + + + New Message + Новое сообщение + + + + From + От + + + + Address is valid. + Адрес введен правильно. - Are you sure you would like to mark all messages read? - Вы уверены, что хотите отметить все сообщения как прочтенные? + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. + Ошибка: Вы не можете добавлять один и тот же адрес в Адресную Книгу несколько раз. Попробуйте переименовать существующий адрес. - - Doing work necessary to send broadcast. - Выполнение работы, требуемой для отправки рассылки. + + The address you entered was invalid. Ignoring it. + Вы ввели неправильный адрес. Это адрес проигнорирован. - - Proof of work pending - Ожидается доказательство работы - - - - %n object(s) pending proof of work - %n объект в ожидании доказательства работы%n объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - - - - %n object(s) waiting to be distributed - %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + Ошибка: Вы не можете добавлять один и тот же адрес в подписку несколько раз. Просто переименуйте существующую подписку. - - Wait until these tasks finish? - Подождать завершения этих задач? + + Restart + Перезапустить - - Problem communicating with proxy: %1. Please check your network settings. - Проблема коммуникации с прокси: %1. Пожалуйста, проверьте ваши сетевые настройки. + + You must restart Bitmessage for the port number change to take effect. + Вы должны перезапустить Bitmessage, чтобы смена номера порта имела эффект. - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - Проблема аутентификации SOCKS5: %1. Пожалуйста, проверьте настройки SOCKS5. + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections. + Bitmessage будет использовать Ваш прокси в дальнейшем, тем не менее, мы рекомендуем перезапустить Bitmessage вручную, чтобы закрыть уже существующие соединения. - - The time on your computer, %1, may be wrong. Please verify your settings. - Время на компьютере, %1, возможно неправильное. Пожалуйста, проверьте ваши настройки. + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + Ошибка: Вы не можете добавлять один и тот же адрес в список несколько раз. Просто переименуйте существующий адрес. - - The name %1 was not found. - Имя %1 не найдено. + + Passphrase mismatch + Секретная фраза не подходит - - The namecoin query failed (%1) - Запрос к namecoin не удался (%1). + + The passphrase you entered twice doesn't match. Try again. + Вы ввели две разные секретные фразы. Пожалуйста, повторите заново. - - The namecoin query failed. - Запрос к namecoin не удался. + + Choose a passphrase + Придумайте секретную фразу - - The name %1 has no valid JSON data. - Имя %1 не содержит корректных данных JSON. + + You really do need a passphrase. + Вы действительно должны ввести секретную фразу. - - The name %1 has no associated Bitmessage address. - Имя %1 не имеет связанного адреса Bitmessage. + + All done. Closing user interface... + Программа завершена. Закрываем пользовательский интерфейс... - - Success! Namecoind version %1 running. - Успех! Namecoind версии %1 работает. + + Address is gone + Адрес утерян - - Success! NMControll is up and running. - Успех! NMControl запущен и работает. + + Bitmessage cannot find your address %1. Perhaps you removed it? + Bitmessage не может найти Ваш адрес %1. Возможно Вы удалили его? - - Couldn't understand NMControl. - Не удалось разобрать ответ NMControl. + + Address disabled + Адрес выключен - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. + + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. + Ошибка: адрес, с которого Вы пытаетесь отправить, выключен. Вам нужно будет включить этот адрес во вкладке "Ваши адреса". - - Set notification sound... - Установить звук уведомления... + + Entry added to the Address Book. Edit the label to your liking. + Запись добавлена в Адресную Книгу. Вы можете её отредактировать. - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Добро пожаловать в простой и безопасный Bitmessage -* отправляйте сообщения другим людям -* вещайте, как в twitter или -* участвуйте в обсуждениях в чанах + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + Удалено в корзину. Чтобы попасть в корзину, Вам нужно будет найти файл корзины на диске. - - not recommended for chans - не рекомендовано для чанов + + Save As... + Сохранить как ... - - Quiet Mode - Тихий режим + + Write error. + Ошибка записи. - - Problems connecting? Try enabling UPnP in the Network Settings - Проблемы подключения? Попробуйте включить UPnP в сетевых настройках. + + No addresses selected. + Вы не выбрали адрес. - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Вы пытаетесь отправить email вместо bitmessage. Для этого нужно зарегистрироваться на шлюзе. Попробовать зарегистрироваться? + + Options have been disabled because they either aren't applicable or because they haven't yet been implemented for your operating system. + Опции были отключены, потому что они либо не подходят, либо еще не выполнены под Вашу операционную систему. - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Ошибка: адреса Bitmessage начинаются с "BM-". Пожалуйста, проверьте адрес получателя %1. + + The address should start with ''BM-'' + Адрес должен начинаться с "BM-" - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Ошибка: адрес получателя %1 набран или скопирован неправильно. Пожалуйста, проверьте его. + + The address is not typed or copied correctly (the checksum failed). + Адрес введен или скопирован неверно (контрольная сумма не сходится). - - Error: The recipient address %1 contains invalid characters. Please check it. - Ошибка: адрес получателя %1 содержит недопустимые символы. Пожалуйста, проверьте его. + + The version number of this address is higher than this software can support. Please upgrade Bitmessage. + Версия этого адреса более поздняя, чем Ваша программа. Пожалуйста, обновите программу Bitmessage. - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Ошибка: версия адреса получателя %1 слишком высокая. Либо вам нужно обновить программу Bitmessage, либо ваш знакомый - умник. + + The address contains invalid characters. + Адрес содержит запрещённые символы. - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Ошибка: часть данных, закодированных в адресе получателя %1 слишком короткая. Видимо, что-то не так с программой, используемой вашим знакомым. + + Some data encoded in the address is too short. + Данные, закодированные в адресе, слишком короткие. - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Ошибка: часть данных, закодированных в адресе получателя %1 слишком длинная. Видимо, что-то не так с программой, используемой вашим знакомым. + + Some data encoded in the address is too long. + Данные, закодированные в адресе, слишком длинные. - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Ошибка: часть данных, закодированных в адресе получателя %1 сформирована неправильно. Видимо, что-то не так с программой, используемой вашим знакомым. + + You are using TCP port %1. (This can be changed in the settings). + Вы используете TCP порт %1. (Его можно поменять в настройках). - - Error: Something is wrong with the recipient address %1. - Ошибка: что-то не так с адресом получателя %1. + + Bitmessage + Bitmessage - - Error: %1 - Ошибка: %1 + + To + Кому - - From %1 - От %1 + + From + От кого - - Synchronisation pending - Ожидается синхронизация - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? + + Subject + Тема - - Not connected - Не подключено + + Received + Получено - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage не подключен к сети. Выход сейчас может привести к задержкам доставки. Подождать подключения и завершения синхронизации? + + Inbox + Входящие - - Waiting for network connection... - Ожидание сетевого подключения... + + Load from Address book + Взять из адресной книги - - Waiting for finishing synchronisation... - Ожидание окончания синхронизации... + + Message: + Сообщение: - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - У вас уже есть звук уведомления для этого адресата. Вы уверены, что хотите перезаписать звук уведомления? + + Subject: + Тема: - - Error occurred: could not load message from disk. - Произошла ошибка: не удалось загрузить сообщение с диска. - - - - Display the %n recent broadcast(s) from this address. - + + Send to one or more specific people + Отправить одному или нескольким указанным получателям - - Go online - Подключиться к сети + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> - - Go offline - Отключиться от сети + + To: + Кому: - - Clear - Очистить + + From: + От: - - inbox - входящие + + Broadcast to everyone who is subscribed to your address + Рассылка всем, кто подписался на Ваш адрес - - new - новые + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + Пожалуйста, учитывайте, что рассылки шифруются лишь Вашим адресом. Любой человек, который знает Ваш адрес, сможет прочитать Вашу рассылку. - - sent - отправленные + + Status + Статус - - trash - - - - - MessageView - - - Follow external link - Перейти по внешней ссылке + + Sent + Отправленные - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - Ссылка "%1" откроется в браузере. Это может быть угрозой безопасности, например деанонимизировать вас или привести к скачиванию вредоносных данных. Вы уверены? + + Label (not shown to anyone) + Имя (не показывается никому) - - HTML detected, click here to display - Обнаружен HTML, нажмите здесь чтоб отобразить + + Address + Адрес - - Click here to disable HTML - Нажмите здесь для отключения - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - Сообщение в неизвестной кодировке. -Возможно, вам следует обновить Bitmessage. + + Stream + Поток - - Unknown encoding - Неизвестная кодировка + + Your Identities + Ваши Адреса + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + Здесь Вы можете подписаться на рассылки от других пользователей. Все рассылки будут появляться у Вас во Входящих. Вы будете следить за всеми адресами, указанными здесь, даже если они в чёрном списке. + + + + Add new Subscription + Добавить новую подписку + + + + Label + Имя + + + + Subscriptions + Подписки + + + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + Адресная книга удобна для присвоения осмысленных имен Bitmessage адресам Ваших друзей. Вы можете добавлять новые записи с помощью кнопки "Добавить новую запись", или же правым кликом мыши на сообщения. + + + + Name or Label + Имя + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Использовать чёрный список (Разрешить все входящие сообщения, кроме указанных в чёрном списке) + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Использовать белый список (блокировать все входящие сообщения, кроме указанных в белом списке) + + + + Blacklist + Чёрный список + + + + Stream # + № потока + + + + Connections + Соединений + + + + Total connections: 0 + Всего соединений: 0 + + + + Since startup at asdf: + С начала работы программы в asdf: + + + + Processed 0 person-to-person message. + Обработано 0 сообщений. + + + + Processed 0 public key. + Обработано 0 открытых ключей. + + + + Processed 0 broadcast. + Обработано 0 рассылок. + + + + Network Status + Статус сети + + + + File + Файл + + + + Settings + Настройки + + + + Help + Помощь + + + + Import keys + Импортировать ключи + + + + Manage keys + Управлять ключами + + + + About + О программе + + + + Regenerate deterministic addresses + Сгенерировать заново все адреса + + + + Delete all trashed messages + Стереть все сообщения из корзины + + + + Message sent. Sent at %1 + Сообщение отправлено в %1 + + + + Chan name needed + Требуется имя chan-а + + + + You didn't enter a chan name. + Вы не ввели имя chan-a. + + + + Address already present + Адрес уже существует + + + + Could not add chan because it appears to already be one of your identities. + Не могу добавить chan, потому что это один из Ваших уже существующих адресов. + + + + Success + Отлично + + + + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. + Chan был успешно создан. Чтобы добавить других в сhan, сообщите им имя chan-а и этот Bitmessage адрес: %1. Этот адрес также отображается во вкладке "Ваши Адреса". + + + + Address too new + Адрес слишком новый + + + + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. + Этот Bitmessage адрес похож на правильный, но версия этого адреса слишком новая. Возможно, Вам необходимо обновить программу Bitmessage. + + + + Address invalid + Неправильный адрес + + + + That Bitmessage address is not valid. + Этот Bitmessage адрес введен неправильно. + + + + Address does not match chan name + Адрес не сходится с именем chan-а + + + + Although the Bitmessage address you entered was valid, it doesn't match the chan name. + Вы ввели верный адрес Bitmessage, но он не сходится с именем chan-а. + + + + Successfully joined chan. + Успешно присоединились к chan-у. + + + + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). + Bitmessage будет использовать Ваш прокси, начиная прямо сейчас. Тем не менее Вам имеет смысл перезапустить Bitmessage, чтобы закрыть уже существующие соединения. + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + Это адрес chan-а. Вы не можете его использовать как адрес рассылки. + + + + Search + Поиск + + + + All + По всем полям + + + + Message + Текст сообщения + + + + Join / Create chan + Подсоединиться или создать chan + + + + Mark Unread + Отметить как непрочитанное + + + + Fetched address from namecoin identity. + Получить адрес через Namecoin. + + + + Testing... + Проверяем... + + + + Fetch Namecoin ID + Получить Namecoin ID + + + + Ctrl+Q + Ctrl+Q + + + + F1 + F1 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + + + + Set avatar... + + + + + Bad address version number + + + + + Your address version number must be a number: either 3 or 4. + + + + + Your address version number must be either 3 or 4. + + + + + Inventory lookups per second: %1 + + + + + Will not resend ever + + + + + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. + + + + + Do you really want to remove this avatar? + + + + + You have already set an avatar for this address. Do you really want to overwrite it? + + + + + Start-on-login not yet supported on your OS. + + + + + Minimize-to-tray not yet supported on your OS. + + + + + Tray notifications not yet supported on your OS. + + + + + Enter an address above. + + + + + Address is an old type. We cannot display its past broadcasts. + + + + + There are no recent broadcasts from this address to display. + + + + + Display the %1 recent broadcast from this address. + + + + + Display the %1 recent broadcasts from this address. + + + + + Inventory lookups per second: 0 + NewAddressDialog - + Create new Address Создать новый адрес - + Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Здесь Вы сможете сгенерировать столько адресов сколько хотите. На самом деле, создание и выкидывание адресов даже поощряется. Вы можете сгенерировать адреса используя либо генератор случайных чисел, либо придумав секретную фразу. Если Вы используете секретную фразу, то адреса будут называться "детерминистическими". Генератор случайных чисел выбран по умолчанию, однако детерминистические адреса имеют следующие плюсы и минусы по сравнению с ними: + Здесь Вы сможете сгенерировать столько адресов сколько хотите. На самом деле, создание и выкидывание адресов даже поощряется. Вы можете сгенерировать адреса используя либо генератор случайных чисел либо придумав секретную фразу. Если Вы используете секретную фразу, то адреса будут называться "детерминистическими". Генератор случайных чисел выбран по умолчанию, однако детерминистические адреса имеют следующие плюсы и минусы по сравнению с ними: - + <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> <html><head/><body><p><span style=" font-weight:600;">Плюсы:<br/></span>Вы сможете восстановить адрес по памяти на любом компьютере<br/>Вам не нужно беспокоиться о сохранении файла keys.dat, если Вы запомнили секретную фразу<br/><span style=" font-weight:600;">Минусы:<br/></span>Вы должны запомнить (или записать) секретную фразу, если Вы хотите когда-либо восстановить Ваш адрес на другом компьютере <br/>Вы должны также запомнить версию адреса и номер потока вместе с секретной фразой<br/>Если Вы выберите слишком короткую секретную фразу, кто-нибудь в интернете сможет подобрать ключ и, как следствие, читать и отправлять от Вашего имени сообщения.</p></body></html> - + Use a random number generator to make an address Использовать генератор случайных чисел для создания адреса - + Use a passphrase to make addresses Использовать секретную фразу для создания адресов - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter Потратить несколько лишних минут, чтобы сделать адрес(а) короче на 1 или 2 символа - + Make deterministic addresses - Создать детерминистические адреса + Создать детерминистический адрес - - Address version number: 4 - Номер версии адреса: 4 + + Address version number: 3 + Версия адреса: 3 - + In addition to your passphrase, you must remember these numbers: В дополнение к секретной фразе, Вам необходимо запомнить эти числа: - + Passphrase - Секретная фраза + Придумайте секретную фразу - + Number of addresses to make based on your passphrase: - Количество адресов, которые нужно создать из секретной фразы: + Кол-во адресов, которые Вы хотите получить из секретной фразы: - + Stream number: 1 Номер потока: 1 - + Retype passphrase Повторите секретную фразу - + Randomly generate address Сгенерировать случайный адрес - + Label (not shown to anyone except you) Имя (не показывается никому кроме Вас) - + Use the most available stream Использовать наиболее доступный поток - + (best if this is the first of many addresses you will create) (выберите этот вариант если это лишь первый из многих адресов, которые Вы планируете создать) - + Use the same stream as an existing address Использовать тот же поток, что и указанный существующий адрес - + (saves you some bandwidth and processing power) (немного сэкономит Вам пропускную способность сети и вычислительную мощь) + + + Address version number: 4 + Версия адреса: 4 + + + + NewChanDialog + + + Dialog + Новый chan + + + + Create a new chan + Создать новый chan + + + + Join a chan + Присоединиться к chan + + + + <html><head/><body><p>A chan is a set of encryption keys that is shared by a group of people. The keys and bitmessage address used by a chan is generated from a human-friendly word or phrase (the chan name).</p><p>Chans are experimental and are unmoderatable.</p></body></html> + <html><head/><body><p>Chan - это набор ключей шифрования, которые известны некоторой группе людей. Ключи и Bitmessage-адрес используемый chan-ом генерируется из слова или фразы (имя chan-а).</p><p>Chan-ы - это экспериментальная новинка.</p></body></html> + + + + Chan name: + Имя chan: + + + + Chan bitmessage address: + Bitmessage адрес chan: + + + + Create a chan + Создать chan + + + + Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. + Введите имя Вашего chan-a. Если Вы выберете достаточно сложное имя для chan-а (например, сложную и необычную секретную фразу) и никто из Ваших друзей не опубликует эту фразу, то Ваш chan будет надёжно зашифрован. + NewSubscriptionDialog - + Add new entry Добавить новую запись - + Label Имя - + Address Адрес - - Enter an address above. - Введите адрес выше. + + CheckBox + SpecialAddressBehaviorDialog - + Special Address Behavior Особое поведение адреса - + Behave as a normal address Вести себя как обычный адрес - + Behave as a pseudo-mailing-list address Вести себя как адрес псевдо-рассылки - + Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Почта, полученная на адрес псевдо-рассылки, будет автоматически разослана всем подписчикам (и поэтому будет публичной). + Почта, полученная на адрес псевдо-рассылки, будет автоматически разослана всем подписчикам (и поэтому будет доступна общей публике). - + Name of the pseudo-mailing-list: Имя псевдо-рассылки: - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Это адрес чана. Вы не можете его использовать как адрес рассылки. - aboutDialog - + About О программе - + PyBitmessage - + PyBitmessage - + version ? - + версия ? + + + + Copyright © 2013 Jonathan Warren + Копирайт © 2013 Джонатан Уоррен - + <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> <html><head/><body><p>Программа распространяется в соответствии с лицензией MIT/X11; см. <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> - + This is Beta software. Это бета версия программы. - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Авторское право: &copy; 2012-2016 Джонатан Уоррен<br/>Авторское право: &copy; 2013-2017 Разработчики Bitmessage</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Использовать чёрный список (разрешить все входящие сообщения, кроме указанных в чёрном списке) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Использовать белый список (блокировать все входящие сообщения, кроме указанных в белом списке) - - - - Add new entry - Добавить новую запись - - - - Name or Label - Имя - - - - Address - Адрес - - - - Blacklist - Чёрный список - - - - Whitelist - Белый список + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + connectDialog - + Bitmessage Bitmessage - + Bitmessage won't connect to anyone until you let it. Bitmessage не будет соединяться ни с кем, пока Вы это не разрешите. - + Connect now Соединиться прямо сейчас - + Let me configure special network settings first Я хочу сперва настроить сетевые настройки - - - Work offline - Работать без соединения с сетью - helpDialog - + Help Помощь - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Bitmessage - общественный проект. Вы можете найти подсказки и советы на Wiki-страничке Bitmessage: @@ -1929,671 +1305,460 @@ The 'Random Number' option is selected by default but deterministic ad iconGlossaryDialog - + Icon Glossary Описание значков - + You have no connections with other peers. Нет соединения с другими участниками сети. - + 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. - Вы установили по-крайней мере одно исходящее соединение, но пока ни одного входящего. Ваш файрвол или маршрутизатор скорее всего не настроен на переброс входящих TCP соединений к Вашему компьютеру. Bitmessage будет прекрасно работать и без этого, но Вы могли бы помочь сети если бы разрешили и входящие соединения тоже. Это помогло бы Вам стать более важным узлом сети. + На текущий момент Вы установили по-крайней мере одно исходящее соединение, но пока ни одного входящего. Ваш файрвол или маршрутизатор скорее всего не настроен на переброс входящих TCP соединений к Вашему компьютеру. Bitmessage будет прекрасно работать и без этого, но Вы могли бы помочь сети если бы разрешили и входящие соединения тоже. Это помогло бы Вам стать более важным узлом сети. You are using TCP port ?. (This can be changed in the settings). - + Вы используете TCP порт ?. (Его можно поменять в настройках). - + You do have connections with other peers and your firewall is correctly configured. Вы установили соединение с другими участниками сети и ваш файрвол настроен правильно. - - - You are using TCP port %1. (This can be changed in the settings). - Вы используете TCP порт %1. (Его можно поменять в настройках). - - - - networkstatus - - - Total connections: - Всего соединений: - - - - Since startup: - С начала работы: - - - - Processed 0 person-to-person messages. - Обработано 0 сообщений. - - - - Processed 0 public keys. - Обработано 0 открытых ключей. - - - - Processed 0 broadcasts. - Обработано 0 рассылок. - - - - Inventory lookups per second: 0 - Поисков в каталоге в секунду: 0 - - - - Objects to be synced: - Несинхронизированные объекты: - - - - Stream # - № потока - - - - Connections - - - - - Since startup on %1 - С начала работы, %1 - - - - Down: %1/s Total: %2 - Загрузка: %1/s Всего: %2 - - - - Up: %1/s Total: %2 - Отправка: %1/s Всего: %2 - - - - Total Connections: %1 - Всего соединений: %1 - - - - Inventory lookups per second: %1 - Поисков в каталоге в секунду: %1 - - - - Up: 0 kB/s - Отправка: 0 кБ/с - - - - Down: 0 kB/s - Загрузка: 0 кБ/с - - - - Network Status - Состояние сети - - - - byte(s) - байтбайтбайтбайт - - - - Object(s) to be synced: %n - Несинхронизированные объекты: %nНесинхронизированные объекты: %nНесинхронизированные объекты: %nНесинхронизированные объекты: %n - - - - Processed %n person-to-person message(s). - Обработано %n сообщение.Обработано %n сообщения.Обработано %n сообщений.Обработано %n сообщений. - - - - Processed %n broadcast message(s). - Обработана %n рассылка.Обработано %n рассылки.Обработано %n рассылок.Обработано %n рассылок. - - - - Processed %n public key(s). - Обработан %n открытый ключ.Обработано %n открытых ключа.Обработано %n открытых ключей.Обработано %n открытых ключей. - - - - Peer - Узел - - - - IP address or hostname - Адрес IP или имя узла - - - - Rating - Рейтинг - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage отслеживает шанс успеха попыток подключения к отдельным узлам. Рейтинг варьируется в диапазоне от -1 до 1 и влияет на вероятность выбора узла в будущем. - - - - User agent - Название приложения - - - - Peer's self-reported software - Название ПО, как сообщает узел - - - - TLS - TLS - - - - Connection encryption - Шифрование соединения - - - - List of streams negotiated between you and the peer - Перечень потоков, согласованных с конкретным узлом - newChanDialog Dialog - + Новый chan Create a new chan - + Создать новый chan Join a chan - + Присоединиться к chan Create a chan - + Создать chan - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + + Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. + Введите имя Вашего chan-a. Если Вы выберете достаточно сложное имя для chan-а (например, сложную и необычную секретную фразу) и никто из Ваших друзей не опубликует эту фразу, то Ваш chan будет надёжно зашифрован. Chan name: - + Имя chan: <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + <html><head/><body><p>Chan - это способ общения, когда набор ключей шифрования известен сразу целой группе людей. Ключи и Bitmessage-адрес, используемый chan-ом, генерируется из слова или фразы (имя chan-а). Чтобы отправить сообщение всем, находящимся в chan-е, отправьте обычное приватное сообщение на адрес chan-a.</p><p>Chan-ы — это экспериментальная фича.</p></body></html> Chan bitmessage address: - + Bitmessage адрес chan: - - Create or join a chan - Создать или подключить чан - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Чан получается, когда группа людей использует общие ключи дешифрования. Ключи и адрес bitmessage, используемые чаном, генерируются из понятного слова или фразы (имя чана). Для отправки сообщения всем пользователям чана, нужно отправить его на адрес чана.</p><p>Чаны это экспериментальная абсолютно немодерируемая среда.</p><p>Введите имя вашего чана. Если вы выберете достаточно сложное имя чана (как надежный и уникальный пароль) и никто из ваших друзей не обнародует его, чан будет безопасным и приватным. Однако, если кто-то создаст чан с таким-же именем, как ваш, то вы будете использовать общий чан.</p></body></html> - - - - Chan passphrase/name: - Пароль/имя чана: - - - - Optional, for advanced usage - Необязательно, для продвинутых пользователей - - - - Chan address - Адрес чана - - - - Please input chan name/passphrase: - Пожалуйста, введите имя/пароль чана: - - - - newchandialog - - - Successfully created / joined chan %1 - Успешно создан / подключен чан %1 - - - - Chan creation / joining failed - Не удалось создать / подключить чан - - - - Chan creation / joining cancelled - Создание / подключение чана отменено - - - - proofofwork - - - C PoW module built successfully. - Модуль C для PoW успешно собран. - - - - Failed to build C PoW module. Please build it manually. - Не удалось собрать модуль C для PoW. Пожалуйста, соберите его вручную. - - - - C PoW module unavailable. Please build it. - Модуль C для PoW недоступен. Пожалуйста, соберите его. - - - - qrcodeDialog - - - QR-code - QR-код + + <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> + <html><head/><body><p>Введите имя Вашего chan-a. Если Вы выберете достаточно сложное имя для chan-а (например, сложную и необычную секретную фразу) и никто из Ваших друзей не опубликует эту фразу, то Ваш chan будет надёжно зашифрован. Если Вы и кто-то другой независимо создадите chan с полностью идентичным именем, то скорее всего Вы получите в итоге один и тот же chan.</p></body></html> regenerateAddressesDialog - + Regenerate Existing Addresses Сгенерировать заново существующие адреса - + Regenerate existing addresses Сгенерировать заново существующие адреса - + Passphrase Секретная фраза - + Number of addresses to make based on your passphrase: - Количество адресов, которые нужно создать из секретной фразы: + Кол-во адресов, которые Вы хотите получить из Вашей секретной фразы: - - Address version number: - Номер версии адреса: + + Address version Number: + Версия адреса: - + + 3 + 3 + + + Stream number: Номер потока: - + 1 1 - + Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter Потратить несколько лишних минут, чтобы сделать адрес(а) короче на 1 или 2 символа - + You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Вы должны отметить эту галочку (или не отмечать) точно так же, как Вы сделали (или не сделали) в самый первый раз, когда создавали Ваши адреса. + Вы должны кликнуть эту галочку (или не кликать) точно так же, как Вы сделали в самый первый раз, когда создавали Ваши адреса. - + If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Если Вы ранее создали детерминистические адреса, но случайно потеряли их, Вы можете их восстановить здесь. Если же Вы использовали генератор случайных чисел чтобы создать Ваши адреса, то Вы не сможете их здесь восстановить. + Если Вы ранее создавали детерминистические адреса, но случайно потеряли их, Вы можете их восстановить здесь. Если же Вы использовали генератор случайных чисел чтобы создать Ваши адреса, то Вы не сможете их здесь восстановить. + + + + Address version number: + settingsDialog - + Settings Настройки - + Start Bitmessage on user login Запускать Bitmessage при входе в систему - - Tray - Трей - - - + Start Bitmessage in the tray (don't show main window) Запускать Bitmessage в свернутом виде (не показывать главное окно) - + Minimize to tray Сворачивать в трей - - Close to tray - Закрывать в трей - - - + Show notification when message received Показывать уведомления при получении новых сообщений - + Run in Portable Mode Запустить в переносном режиме - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. В переносном режиме, все сообщения и конфигурационные файлы сохраняются в той же самой папке что и сама программа. Это делает более удобным использование Bitmessage с USB-флэшки. - + + User Interface + Пользовательские + + + + Listening port + Порт прослушивания + + + + Listen for connections on port: + Прослушивать соединения на порту: + + + + Proxy server / Tor + Прокси сервер / Tor + + + + Type: + Тип: + + + + none + отсутствует + + + + SOCKS4a + SOCKS4a + + + + SOCKS5 + SOCKS5 + + + + Server hostname: + Адрес сервера: + + + + Port: + Порт: + + + + Authentication + Авторизация + + + + Username: + Имя пользователя: + + + + Pass: + Прль: + + + + Network Settings + Сетевые настройки + + + + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. + Когда кто-либо отправляет Вам сообщение, его компьютер должен сперва решить определённую вычислительную задачу. Сложность этой задачи по умолчанию равна 1. Вы можете повысить эту сложность для новых адресов, которые Вы создадите, здесь. Таким образом, любые новые адреса, которые Вы создадите, могут требовать от отправителей сложность большую чем 1. Однако, есть одно исключение: если Вы специально добавите Вашего собеседника в адресную книгу, то Bitmessage автоматически уведомит его о том, что для него минимальная сложность будет составлять всегда всего лишь 1. + + + + Total difficulty: + Общая сложность: + + + + Small message difficulty: + Сложность для маленьких сообщений: + + + + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. + "Сложность для маленьких сообщений" влияет исключительно на небольшие сообщения. Увеличив это число в два раза, вы сделаете отправку маленьких сообщений в два раза сложнее, в то время как сложность отправки больших сообщений не изменится. + + + + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. + "Общая сложность" влияет на абсолютное количество вычислений, которые отправитель должен провести, чтобы отправить сообщение. Увеличив это число в два раза, вы увеличите в два раза объем требуемых вычислений. + + + + Demanded difficulty + Требуемая сложность + + + + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. + Здесь Вы можете установить максимальную вычислительную работу, которую Вы согласны проделать, чтобы отправить сообщение другому пользователю. Ноль означает, что любое значение допустимо. + + + + Maximum acceptable total difficulty: + Максимально допустимая общая сложность: + + + + Maximum acceptable small message difficulty: + Максимально допустимая сложность для маленький сообщений: + + + + Max acceptable difficulty + Макс допустимая сложность + + + + Listen for incoming connections when using proxy + Прослушивать входящие соединения если используется прокси + + + Willingly include unencrypted destination address when sending to a mobile device Специально прикреплять незашифрованный адрес получателя, когда посылаем на мобильное устройство - - Use Identicons - Включить иконки адресов + + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> + <html><head/><body><p>Bitmessage умеет пользоваться программой Namecoin для того, чтобы сделать адреса более дружественными для пользователей. Например, вместо того, чтобы диктовать Вашему другу длинный и нудный адрес Bitmessage, Вы можете попросить его отправить сообщение на адрес вида <span style=" font-style:italic;">test. </span></p><p>(Перенести Ваш Bitmessage адрес в Namecoin по-прежнему пока довольно сложно).</p><p>Bitmessage может использовать либо прямо namecoind, либо уже запущенную программу nmcontrol.</p></body></html> - - Reply below Quote - Отвечать после цитаты + + Host: + Адрес: - + + Password: + Пароль: + + + + Test + Проверить + + + + Connect to: + Подсоединиться к: + + + + Namecoind + Namecoind + + + + NMControl + NMControl + + + + Namecoin integration + Интеграция с Namecoin + + + Interface Language Язык интерфейса - + System Settings system Язык по умолчанию - - User Interface - Пользовательские + + English + en + English - - Listening port - Порт прослушивания + + Esperanto + eo + Esperanto - - Listen for connections on port: - Прослушивать соединения на порту: + + Français + fr + Francais - - UPnP: - UPnP: + + Deutsch + de + Deutsch - - Bandwidth limit - Ограничение пропускной способности + + Español + es + Espanol - - Maximum download rate (kB/s): [0: unlimited] - Максимальная скорость загрузки (кБ/с): [0: не ограничено] + + Русский + ru + Русский - - Maximum upload rate (kB/s): [0: unlimited] - Максимальная скорость отдачи (кБ/с): [0: не ограничено] + + Pirate English + en_pirate + Pirate English - - Proxy server / Tor - Прокси сервер / Tor + + Other (set in keys.dat) + other + Другие (настроено в keys.dat) - - Type: - Тип: + + Use Identicons + - - Server hostname: - Адрес сервера: + + Españl + es + - - Port: - Порт: + + русский язык + ru + - - Authentication - Авторизация + + Norsk + no + - - Username: - Имя пользователя: - - - - Pass: - Пароль: - - - - Listen for incoming connections when using proxy - Прослушивать входящие соединения если используется прокси - - - - none - отсутствует - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Сетевые настройки - - - - Total difficulty: - Общая сложность: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - "Общая сложность" влияет на абсолютное количество вычислений, которые отправитель должен провести, чтобы отправить сообщение. Увеличив это число в два раза, вы увеличите в два раза объем требуемых вычислений. - - - - Small message difficulty: - Сложность для маленьких сообщений: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Когда кто-либо отправляет Вам сообщение, его компьютер должен сперва решить определённую вычислительную задачу. Сложность этой задачи по умолчанию равна 1. Вы можете повысить эту сложность для новых адресов, которые Вы создадите, здесь. Таким образом, любые новые адреса, которые Вы создадите, могут требовать от отправителей сложность большую чем 1. Однако, есть одно исключение: если Вы специально добавите Вашего собеседника в адресную книгу, то Bitmessage автоматически уведомит его о том, что для него минимальная сложность будет составлять всегда всего лишь 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - "Сложность для маленьких сообщений" влияет исключительно на небольшие сообщения. Увеличив это число в два раза, вы сделаете отправку маленьких сообщений в два раза сложнее, в то время как сложность отправки больших сообщений не изменится. - - - - Demanded difficulty - Требуемая сложность - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Здесь Вы можете установить максимальную вычислительную работу, которую Вы согласны проделать, чтобы отправить сообщение другому пользователю. Ноль означает, что любое значение допустимо. - - - - Maximum acceptable total difficulty: - Максимально допустимая общая сложность: - - - - Maximum acceptable small message difficulty: - Максимально допустимая сложность для маленький сообщений: - - - - Max acceptable difficulty - Макс допустимая сложность - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage умеет пользоваться программой Namecoin для того, чтобы сделать адреса более дружественными для пользователей. Например, вместо того, чтобы диктовать Вашему другу длинный и нудный адрес Bitmessage, Вы можете попросить его отправить сообщение на адрес вида <span style=" font-style:italic;">test. </span></p><p>(Перенести Ваш Bitmessage адрес в Namecoin по-прежнему пока довольно сложно).</p><p>Bitmessage может использовать либо прямо namecoind, либо уже запущенную программу nmcontrol.</p></body></html> - - - - Host: - Адрес: - - - - Password: - Пароль: - - - - Test - Проверить - - - - Connect to: - Подсоединиться к: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Интеграция с Namecoin - - - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>По умолчанию, когда вы отправляете сообщение кому-либо, и адресат находится оффлайн несколько дней, ваш Bitmessage перепосылает сообщение. Это будет продолжаться с увеличивающимся по экспоненте интервалом; сообщение будет переотправляться, например, через 5, 10, 20 дней, пока адресат их запрашивает. Здесь вы можете изменить это поведение, заставив Bitmessage прекращать переотправку по прошествии указанного количества дней или месяцев.</p><p>Оставьте поля пустыми, чтобы вернуться к поведению по умолчанию.</p></body></html> + - + Give up after - Прекратить через + - + and - и + - + days - дней + - + months. - месяцев. + - + Resends Expire - Окончание попыток отправки - - - - Hide connection notifications - Спрятать уведомления о подключениях - - - - Maximum outbound connections: [0: none] - Максимальное число исходящих подключений: [0: неограничено] - - - - Hardware GPU acceleration (OpenCL): - Аппаратное ускорение GPU + - \ No newline at end of file + diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm deleted file mode 100644 index 26c2a24d..00000000 Binary files a/src/translations/bitmessage_sk.qm and /dev/null differ diff --git a/src/translations/bitmessage_sk.ts b/src/translations/bitmessage_sk.ts deleted file mode 100644 index 8c3b0209..00000000 --- a/src/translations/bitmessage_sk.ts +++ /dev/null @@ -1,2597 +0,0 @@ - - - AddAddressDialog - - - Add new entry - Pridať nový záznam - - - - Label - Označenie - - - - Address - Adresa - - - - EmailGatewayDialog - - - Email gateway - E-mailová brána - - - - Register on email gateway - Registrácia na e-mailovej bráne - - - - Account status at email gateway - Stav účtu na e-mailovej bráne - - - - Change account settings at email gateway - Zmena nastavení účtu na e-mailovej bráne - - - - Unregister from email gateway - Zrušiť registráciu na e-mailovej bráne - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - E-mailové brány umožňujú komunikovať s užívateľmi e-mailu. Momentálne je k dispozícii iba e-mailová brána Mailchuck (@mailchuck.com). - - - - Desired email address (including @mailchuck.com): - Požadovaná e-mailová adresa (vrátane @ mailchuck.com): - - - - @mailchuck.com - @mailchuck.com - - - - Registration failed: - Registrácia zlyhala: - - - - The requested email address is not available, please try a new one. - Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. - - - - Sending email gateway registration request - Odosielam žiadosť o registráciu na e-mailovej bráne - - - - Sending email gateway unregistration request - Odosielam žiadosť o odhlásenie z e-mailovej brány - - - - Sending email gateway status request - Odosielam žiadosť o stav e-mailovej brány - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - # Tento text môžete použiť na konfiguráciu vášho účtu na e-mailovej bráne -# odkomentujte nastavenia, ktoré chcete použiť -# Tu sú možnosti: -# -# pgp: server -# E-mailová brána bude za vás vytvárať a udržiavať PGP kľúče a podpisovať, overovať, -# šifrovať a dešifrovať vaše e-maily. Ak chcete používať PGP, ale ste leniví, -# toto je voľba pre vás. Vyžaduje predplatné. -# -# pgp: local -# E-mailová brána nebude za vás vykonávať operácie PGP. Môžete buď -# nepoužívať PGP vôbec, alebo ho použiť lokálne. -# -# attachments: yes -# Prichádzajúce prílohy v e-maile budú nahrané na MEGA.nz, a môžete si ich odtiaľ stiahnuť -# pomocou odkazu v správe. Vyžaduje predplatné. -# -# attachments: no -# Prílohy budú ignorované. -# -# archive: yes -# Prichádzajúce e-maily budú archivované na serveri. Použite, ak potrebujete -# pomoc s problémami, alebo potrebujete doklad pre tretie strán o obsahu e-mailov. Táto voľba však -# znamená, že prevádzkovateľ služby budú môcť čítať vaše e-maily -# aj potom, ako vám budú doručené -# -# archive: no -# Prichádzajúce e-maily budú odstránené zo servera, akonáhle vám budú doručené -# -# masterpubkey_btc: BIP44 xpub kľúč alebo electrum v1 základ (seed) -# offset_btc: celé číslo (predvolená 0) -# feeamount: číslo s max. 8 desatinnými miest -# feecurrency: BTC, XBT, USD, EUR alebo GBP -# Ak chcete účtovať ľuďom, ktorí vám posielať e-maily, použite tieto parametre. Ak vám potom -# neznáma osoba pošle e-mail, bude požiadaná o zaplatenie poplatku -# určeného týmito premennými. -# feeamount je výška platby -# feecurrency je mena, v ktorej sa bude počítať -# Keďže systém používa deterministické verejné kľúče, platby obdržíte priamo vy -# Ak ju chcete túto funkciu opäť vypnúť, nastavte "feeamount" na 0. Vyžaduje -# predplatné. - - - - - MainWindow - - - Reply to sender - Odpovedať odosielateľovi - - - - Reply to channel - Odpoveď na kanál - - - - Add sender to your Address Book - Pridať odosielateľa do adresára - - - - Add sender to your Blacklist - Pridať odosielateľa do svojho zoznamu zakázaných - - - - Move to Trash - Presunúť do koša - - - - Undelete - Obnoviť - - - - View HTML code as formatted text - Zobraziť HTML kód ako formátovaný text - - - - Save message as... - Uložiť správu ako... - - - - Mark Unread - Označiť ako neprečítané - - - - New - Nová - - - - Enable - Aktivovať - - - - Disable - Deaktivovať - - - - Set avatar... - Nastaviť avatar ... - - - - Copy address to clipboard - Kopírovať adresu do clipboardu - - - - Special address behavior... - Zvláštne správanie adresy... - - - - Email gateway - E-mailová brána - - - - Delete - Zmazať - - - - Send message to this address - Poslať správu na túto adresu - - - - Subscribe to this address - Prihlásiť sa k odberu tejto adresy - - - - Add New Address - Pridať novú adresu - - - - Copy destination address to clipboard - Kopírovať cieľovú adresu do clipboardu - - - - Force send - Vynútiť odoslanie - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - Jedna z vašich adries, %1, je stará verzia adresy, 1. Verzie adresy 1 už nie sú podporované. Odstrániť ju teraz? - - - - Waiting for their encryption key. Will request it again soon. - Čakanie na šifrovací kľúč príjemcu. Čoskoro bude vyžiadaný znova. - - - - Encryption key request queued. - - - - - Queued. - Vo fronte. - - - - Message sent. Waiting for acknowledgement. Sent at %1 - Správa odoslaná. Čakanie na potvrdenie. Odoslaná %1 - - - - Message sent. Sent at %1 - Správa odoslaná. Odoslaná %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - Potvrdenie prijatia správy %1 - - - - Broadcast queued. - Rozoslanie vo fronte. - - - - Broadcast on %1 - Rozoslané 1% - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - Problém: práca požadovná príjemcom je oveľa ťažšia, než je povolené v nastaveniach. %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - Problém: šifrovací kľúč príjemcu je nesprávny. Nie je možné zašifrovať správu. %1 - - - - Forced difficulty override. Send should start soon. - Obmedzenie obtiažnosti práce zrušené. Odosielanie by malo čoskoro začať. - - - - Unknown status: %1 %2 - Neznámy stav: %1 %2 - - - - Not Connected - Nepripojený - - - - Show Bitmessage - Ukázať Bitmessage - - - - Send - Odoslať - - - - Subscribe - Prihlásiť sa k odberu - - - - Channel - Kanál - - - - Quit - Ukončiť - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - Kľúče môžete spravovať úpravou súboru keys.dat, ktorý je uložený v rovnakom adresári ako tento program. Tento súbor je dôležité zálohovať. - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - Kľúče môžete spravovať úpravou súboru keys.dat, ktorý je uložený v adresári -%1 -Tento súbor je dôležité zálohovať. - - - - Open keys.dat? - Otvoriť keys.dat? - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Kľúče môžete spravovať úpravou súboru keys.dat, ktorý je uložený v rovnakom adresári ako tento program. Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Nezabudnite zatvoriť Bitmessage pred vykonaním akýchkoľvek zmien.) - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Kľúče môžete spravovať úpravou súboru keys.dat, ktorý je uložený v adresári -%1 -Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Nezabudnite zatvoriť Bitmessage pred vykonaním akýchkoľvek zmien.) - - - - Delete trash? - Vyprázdniť kôš? - - - - Are you sure you want to delete all trashed messages? - Ste si istí, že chcete všetky správy z koša odstrániť? - - - - bad passphrase - zlé heslo - - - - You must type your passphrase. If you don't have one then this is not the form for you. - Je nutné zadať prístupové heslo. Ak heslo nemáte, tento formulár nie je pre Vás. - - - - Bad address version number - Nesprávne číslo verzie adresy - - - - Your address version number must be a number: either 3 or 4. - Číslo verzie adresy musí byť číslo: buď 3 alebo 4. - - - - Your address version number must be either 3 or 4. - Vaše číslo verzie adresy musí byť buď 3 alebo 4. - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - Spojenie bolo stratené - - - - Connected - Spojený - - - - Message trashed - Správa odstránenia - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - TTL (doba životnosti) je čas, počas ktorého bude sieť udržiavať správu. Príjemca musí správu prijať počas tejto životnosti. Keď odosielateľov Bitmessage nedostane po vypršaní životnosti potvrdenie o prijatí, automaticky správu odošle znova. Čím vyššia doba životnosti, tým viac práce musí počítač odosielateľa vykonat na odoslanie správy. Zvyčajne je vhodná doba životnosti okolo štyroch-piatich dní. - - - - Message too long - Správa je príliš dlhá - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - Správa, ktorú skúšate poslať, má %1 bajtov naviac. (Maximum je 261 644 bajtov). Prosím pred odoslaním skrátiť. - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - Chyba: Váš účet nebol registrovaný na e-mailovej bráne. Skúšam registrovať ako %1, prosím počkajte na spracovanie registrácie pred opakovaným odoslaním správy. - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - Chyba: musíte zadať adresu "Od". Ak žiadnu nemáte, prejdite na kartu "Vaše identity". - - - - Address version number - Číslo verzie adresy - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Čo sa týka adresy %1, Bitmessage nepozná číslo verzie adresy %2. Možno by ste mali upgradenúť Bitmessage na najnovšiu verziu. - - - - Stream number - Číslo prúdu - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - Čo sa týka adresy %1, Bitmessage nespracováva číslo prúdu %2. Možno by ste mali upgradenúť Bitmessage na najnovšiu verziu. - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - Upozornenie: momentálne nie ste pripojení. Bitmessage vykoná prácu potrebnú na odoslanie správy, ale odoslať ju môže, až keď budete pripojení. - - - - Message queued. - Správa vo fronte. - - - - Your 'To' field is empty. - Pole "Komu" je prázdne. - - - - Right click one or more entries in your address book and select 'Send message to this address'. - Vybertie jednu alebo viacero položiek v adresári, pravým tlačidlom myši zvoľte "Odoslať správu na túto adresu". - - - - Fetched address from namecoin identity. - Prebratá adresa z namecoin-ovej identity. - - - - New Message - Nová správa - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - Adresa je platná. - - - - The address you entered was invalid. Ignoring it. - Zadaná adresa bola neplatná a bude ignorovaná. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - Chyba: tú istú adresu nemožno pridať do adresára dvakrát. Ak chcete, môžete skúsiť premenovať existujúcu menovku. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Chyba: nemožno pridať rovnakú adresu k odberu dvakrát. Keď chcete, môžete premenovať existujúci záznam. - - - - Restart - Reštart - - - - You must restart Bitmessage for the port number change to take effect. - Aby sa zmena čísla portu prejavila, musíte reštartovať Bitmessage. - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - Bitmessage bude odteraz používať proxy, ale ak chcete ukončiť existujúce spojenia, musíte Bitmessage manuálne reštartovať. - - - - Number needed - Číslo potrebné - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - Maxímálna rýchlosť príjmu a odoslania musí byť uvedená v číslach. Ignorujem zadané údaje. - - - - Will not resend ever - Nikdy opätovne neodosielať - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - Upozornenie: časový limit, ktorý ste zadali, je menší ako čas, ktorý Bitmessage čaká na prvý pokus o opätovné zaslanie, a preto vaše správy nebudú nikdy opätovne odoslané. - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - Nezhoda hesla - - - - The passphrase you entered twice doesn't match. Try again. - Zadané heslá sa rôznia. Skúste znova. - - - - Choose a passphrase - Vyberte heslo - - - - You really do need a passphrase. - Heslo je skutočne potrebné. - - - - Address is gone - Adresa zmizla - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmessage nemôže nájsť vašu adresu %1. Možno ste ju odstránili? - - - - Address disabled - Adresa deaktivovaná - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - Chyba: adresa, z ktorej sa pokúšate odoslať, je neaktívna. Pred použitím ju musíte aktivovať v karte "Vaše identity". - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - Záznam pridaný na zoznam zakázaných. Upravte označenie podľa vašich predstáv. - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - Chyba: tú istú adresu nemožno pridať na zoznam zakázaných dvakrát. Ak chcete, môžete skúsiť premenovať existujúce označenie. - - - - Moved items to trash. - Položky presunuté do koša. - - - - Undeleted item. - Položka obnovená. - - - - Save As... - Uložiť ako... - - - - Write error. - Chyba pri zapisovaní. - - - - No addresses selected. - Nevybraná žiadna adresa. - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - Ak odstránite odber, správy, ktoré ste už prijali, sa stanú nedostupné. Možno by ste mali zvážit namiesto toho odber deaktivovať. Deaktivované odbery nebudú prijímať nové správy, ale stále si môžete pozrieť správy, ktoré ste už prijali. - -Ste si istý, že chcete odber odstrániť? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - Ak odstránite kanál, správy, ktoré ste už prijali, sa stanú nedostupné. Možno by ste mali zvážit namiesto toho kanál deaktivovať. Deaktivované kanály nebudú prijímať nové správy, ale stále si môžete pozrieť správy, ktoré ste už prijali. - -Ste si istý, že chcete kanál odstrániť? - - - - Do you really want to remove this avatar? - Naozaj chcete odstrániť tento avatar? - - - - You have already set an avatar for this address. Do you really want to overwrite it? - Pre túto adresu ste už ste nastavili avatar. Naozaj ho chcete ho zmeniť? - - - - Start-on-login not yet supported on your OS. - Spustenie pri prihlásení zatiaľ pre váš operačný systém nie je podporované. - - - - Minimize-to-tray not yet supported on your OS. - Minimalizovanie do panelu úloh zatiaľ pre váš operačný systém nie je podporované. - - - - Tray notifications not yet supported on your OS. - Oblasť oznámení zatiaľ pre váš operačný systém nie je podporovaná. - - - - Testing... - Testujem... - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - Adresa by mala začínať ''BM-'' - - - - The address is not typed or copied correctly (the checksum failed). - Nesprávne zadaná alebo skopírovaná adresa (kontrolný súčet zlyhal). - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - Číslo verzie tejto adresy je vyššie ako tento softvér podporuje. Prosím inovujte Bitmessage. - - - - The address contains invalid characters. - Adresa obsahuje neplatné znaky. - - - - Some data encoded in the address is too short. - Niektoré dáta zakódované v adrese sú príliš krátke. - - - - Some data encoded in the address is too long. - Niektoré dáta zakódované v adrese sú príliš dlhé. - - - - Some data encoded in the address is malformed. - Niektoré dáta zakódované v adrese sú poškodené. - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - Starý typ adresy. Nie je možné zobraziť jej predchádzajúce hromadné správy. - - - - There are no recent broadcasts from this address to display. - Neboli nájdené žiadne nedávne hromadé správy z tejto adresy. - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - Bitmessage - - - - Identities - Identity - - - - New Identity - Nová identita - - - - Search - Hľadaj - - - - All - Všetky - - - - To - Príjemca - - - - From - Odosielateľ - - - - Subject - Predmet - - - - Message - Správa - - - - Received - Prijaté - - - - Messages - Správy - - - - Address book - Adresár - - - - Address - Adresa - - - - Add Contact - Pridať kontakt - - - - Fetch Namecoin ID - Získať identifikátor namecoin-u - - - - Subject: - Predmet: - - - - From: - Odosielateľ: - - - - To: - Príjemca: - - - - Send ordinary Message - Poslať obyčajnú správu - - - - Send Message to your Subscribers - Poslať správu vašim odberateľom - - - - TTL: - Doba životnosti: - - - - Subscriptions - Odbery - - - - Add new Subscription - Pridať nový odber - - - - Chans - Kanály - - - - Add Chan - Pridať kanál - - - - File - Súbor - - - - Settings - Nastavenia - - - - Help - Pomoc - - - - Import keys - Importovať kľúče - - - - Manage keys - Spravovať kľúče - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - Kontaktovať používateľskú podporu - - - - About - O - - - - Regenerate deterministic addresses - Znova vytvoriť deterministické adresy - - - - Delete all trashed messages - Odstrániť všetky správy z koša - - - - Join / Create chan - Pripojiť / vytvoriť kanál - - - - All accounts - Všetky účty - - - - Zoom level %1% - Úroveň priblíženia %1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Chyba: nemožno pridať rovnakú adresu do vášho zoznamu dvakrát. Keď chcete, môžete premenovať existujúci záznam. - - - - Add new entry - Pridať nový záznam - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - K dispozícii je nová verzia PyBitmessage: %1. Môžete ju stiahnuť na https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - Waiting for PoW to finish... %1% - Čakám na ukončenie práce... %1% - - - - Shutting down Pybitmessage... %1% - Ukončujem PyBitmessage... %1% - - - - Waiting for objects to be sent... %1% - Čakám na odoslanie objektov... %1% - - - - Saving settings... %1% - Ukladám nastavenia... %1% - - - - Shutting down core... %1% - Ukončujem jadro... %1% - - - - Stopping notifications... %1% - Zastavujem oznámenia... %1% - - - - Shutdown imminent... %1% - Posledná fáza ukončenia... %1% - - - - %n hour(s) - %n hodina%n hodiny%n hodín - - - - %n day(s) - %n deň%n dni%n dní - - - - Shutting down PyBitmessage... %1% - Ukončujem PyBitmessage... %1% - - - - Sent - Odoslané - - - - Generating one new address - Vytváram jednu novú adresu - - - - Done generating address. Doing work necessary to broadcast it... - Vytváranie adresy ukončené. Vykonávam prácu potrebnú na rozoslanie... - - - - Generating %1 new addresses. - Vytváram %1 nových adries. - - - - %1 is already in 'Your Identities'. Not adding it again. - %1 sa už nachádza medzi vášmi identitami, nepridávam dvojmo. - - - - Done generating address - Vytváranie adresy ukončené - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - Disk plný - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - Upozornenie: Váš disk alebo priestor na ukladanie dát je plný. Bitmessage bude teraz ukončený. - - - - Error! Could not find sender address (your address) in the keys.dat file. - Chyba! Nemožno nájsť adresu odosielateľa (vašu adresu) v súbore keys.dat. - - - - Doing work necessary to send broadcast... - Vykonávam prácu potrebnú na rozoslanie... - - - - Broadcast sent on %1 - Rozoslané %1 - - - - Encryption key was requested earlier. - Šifrovací klúč bol vyžiadaný. - - - - Sending a request for the recipient's encryption key. - Odosielam požiadavku na kľúč príjemcu. - - - - Looking up the receiver's public key - Hľadám príjemcov verejný kľúč - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - Problém: adresa príjemcu je na mobilnom zariadení a požaduje, aby správy obsahovali nezašifrovanú adresu príjemcu. Vaše nastavenia však túto možnost nemajú povolenú. %1 - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - Vykonávam prácu potrebnú na odoslanie správy. -Adresy verzie dva, ako táto, nepožadujú obtiažnosť. - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - Vykonávam prácu potrebnú na odoslanie správy. -Priímcova požadovaná obtiažnosť: %1 a %2 - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - Problém: Práca požadovná príjemcom (%1 a %2) je obtiažnejšia, ako máte povolené. %3 - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - Problém: skúšate odslať správu sami sebe, ale nemôžem nájsť šifrovací kľúč v súbore keys.dat. Nemožno správu zašifrovať: %1 - - - - Doing work necessary to send message. - Vykonávam prácu potrebnú na odoslanie... - - - - Message sent. Waiting for acknowledgement. Sent on %1 - Správa odoslaná. Čakanie na potvrdenie. Odoslaná %1 - - - - Doing work necessary to request encryption key. - Vykonávam prácu potrebnú na vyžiadanie šifrovacieho kľúča. - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - Rozosielam požiadavku na verejný kľúč. Ak nebude príjemca spojený zo sieťou, budem skúšať znova. - - - - Sending public key request. Waiting for reply. Requested at %1 - Odosielam požiadavku na verejný kľúč. Čakám na odpoveď. Vyžiadaný %1 - - - - UPnP port mapping established on port %1 - Mapovanie portov UPnP vytvorené na porte %1 - - - - UPnP port mapping removed - Mapovanie portov UPnP zrušené - - - - Mark all messages as read - Označiť všetky správy ako prečítané - - - - Are you sure you would like to mark all messages read? - Ste si istý, že chcete označiť všetky správy ako prečítané? - - - - Doing work necessary to send broadcast. - Vykonávam prácu potrebnú na rozoslanie. - - - - Proof of work pending - Vykonávaná práca - - - - %n object(s) pending proof of work - %n objekt čaká na vykonanie práce%n objekty čakajú na vykonanie práce%n objektov čaká na vykonanie práce - - - - %n object(s) waiting to be distributed - %n objekt čaká na rozoslanie%n objekty čakajú na rozoslanie%n objektov čaká na rozoslanie - - - - Wait until these tasks finish? - Počkať, kým tieto úlohy skončia? - - - - Problem communicating with proxy: %1. Please check your network settings. - Problém komunikácie s proxy: %1. Prosím skontrolujte nastavenia siete. - - - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - Problém autentikácie SOCKS5: %1. Prosím skontrolujte nastavenia SOCKS5. - - - - The time on your computer, %1, may be wrong. Please verify your settings. - Čas na vašom počítači, %1, možno nie je správny. Prosím, skontrolujete nastavenia. - - - - The name %1 was not found. - Meno % nenájdené. - - - - The namecoin query failed (%1) - Dotaz prostredníctvom namecoinu zlyhal (%1) - - - - The namecoin query failed. - Dotaz prostredníctvom namecoinu zlyhal. - - - - The name %1 has no valid JSON data. - Meno %1 neobsahuje planté JSON dáta. - - - - The name %1 has no associated Bitmessage address. - Meno %1 nemá priradenú žiadnu adresu Bitmessage. - - - - Success! Namecoind version %1 running. - Úspech! Namecoind verzia %1 spustený. - - - - Success! NMControll is up and running. - Úspech! NMControl spustený. - - - - Couldn't understand NMControl. - Nie je rozumieť NMControl-u. - - - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Vaša grafická karta vykonala nesprávny výpočet, deaktivujem OpenCL. Prosím, pošlite správu vývojárom. - - - - Set notification sound... - Nastaviť zvuk oznámenia... - - - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -Vitajte v jednoduchom a bezpečnom Bitmessage -* posielajte správy druhým ľuďom -* posielajte hromadné správy ako na twitteri alebo -* diskutuje s druhými v kanáloch - - - - - not recommended for chans - nie je odporúčaná pre kanály - - - - Quiet Mode - Tichý režim - - - - Problems connecting? Try enabling UPnP in the Network Settings - Problémy so spojením? Skúste zapnúť UPnP v Nastaveniach siete - - - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - Pokúšate sa odoslať e-mail namiesto bitmessage. To si vyžaduje registráciu na bráne. Pokúsiť sa o registráciu? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - Chyba: Bitmessage adresy začínajú s BM- Prosím skontrolujte adresu príjemcu %1 - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - Chyba: adresa príjemcu %1 nie je na správne napísaná alebo skopírovaná. Prosím skontrolujte ju. - - - - Error: The recipient address %1 contains invalid characters. Please check it. - Chyba: adresa príjemcu %1 obsahuje neplatné znaky. Prosím skontrolujte ju. - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Chyba: verzia adresy príjemcu %1 je príliš veľká. Buď musíte aktualizovať program Bitmessage alebo váš známy s vami žartuje. - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - Chyba: niektoré údaje zakódované v adrese príjemcu %1 sú príliš krátke. Softér vášho známeho možno nefunguje správne. - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - Chyba: niektoré údaje zakódované v adrese príjemcu %1 sú príliš dlhé. Softvér vášho známeho možno nefunguje správne. - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - Chyba: niektoré údaje zakódované v adrese príjemcu %1 sú poškodené. Softvér vášho známeho možno nefunguje správne. - - - - Error: Something is wrong with the recipient address %1. - Chyba: niečo s adresou príjemcu %1 je nie je v poriadku. - - - - Error: %1 - Chyba: %1 - - - - From %1 - Od %1 - - - - Synchronisation pending - Prebieha synchronizácia - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage sa nezosynchronizoval so sieťou, treba prevzať ešte %n objekt. Keď program ukončíte teraz, môže dôjsť k spozdeniu doručenia. Počkať, kým sa synchronizácia ukončí?Bitmessage sa nezosynchronizoval so sieťou, treba prevzať ešte %n objekty. Keď program ukončíte teraz, môže dôjsť k spozdeniu doručenia. Počkať, kým sa synchronizácia ukončí?Bitmessage sa nezosynchronizoval so sieťou, treba prevzať ešte %n objektov. Keď program ukončíte teraz, môže dôjsť k spozdeniu doručenia. Počkať, kým sa synchronizácia ukončí? - - - - Not connected - Nepripojený - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage nie je pripojený do siete. Keď program ukončíte teraz, môže dôjsť k spozdeniu doručenia. Počkať, kým dôjde k spojeniu a prebehne synchronizácia? - - - - Waiting for network connection... - Čakám na pripojenie do siete... - - - - Waiting for finishing synchronisation... - Čakám na ukončenie synchronizácie... - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - Pre túto adresu ste už ste nastavili zvuk oznámenia. Naozaj ho chcete ho zmeniť? - - - - Error occurred: could not load message from disk. - Chyba pri načítaní správy. - - - - Display the %n recent broadcast(s) from this address. - Zobraziť poslednú %1 hromadnú správu z tejto adresy.Zobraziť posledné %1 hromadné správy z tejto adresy.Zobraziť posledných %1 hromadných správ z tejto adresy. - - - - Go online - Pripojiť k sieti - - - - Go offline - Odpojiť od siete - - - - Clear - Vymazať - - - - inbox - Doručená pošta - - - - new - Nová doručená pošta - - - - sent - - - - - trash - - - - - MessageView - - - Follow external link - Nasledovať externý odkaz - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - Odkaz "%1" bude otvorený v prehliadači. Tento úkon môže predstavovať bezpečnostné riziko a Vás deanonymizovať, alebo vykonať škodlivú činnost. Ste si istý? - - - - HTML detected, click here to display - Nájdené HTML, kliknite sem ak chcete zobraziť - - - - Click here to disable HTML - Kliknite sem na vypnutie HTML - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - Správa má neznáme kódovanie. -Možno by ste mali inovovať Bitmessage. - - - - Unknown encoding - Neznáme kódovanie - - - - NewAddressDialog - - - Create new Address - Vytvoriť novú adresu - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - Tu si môžete vygenerovať toľko adries, koľko chcete. Vytváranie a opúšťanie adries je vrelo odporúčané. Adresy môžete generovať buď pomocou náhodných čísel alebo pomocou hesla. Ak používate heslo, takáto adresa sa nazýva "deterministická". -Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adresy majú niekoľko výhod a nevýhod: - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - <html><head/><body><p> <span style=" font-weight:600;">Pros: <br/></span>Svoje adresy môžete znovu vytvoriť na ľubovoľnom počítači z pamäte.<br/>Dokým si pamätáte heslo, nemusíte sa starať o zálohovanie keys.dat<br/> <span style=" font-weight:600;"Nevýhody: <br/></span>Ak chcete znovu vytvoriť kľúče ak ich stratíte, musíte si pamätať (alebo niekam zapísať) heslo. <br/> Zároveň si musíte si zapamätať aj číslo verzie adresy a číslo toku.<br/>Ak si zvolíte slabé prístupové heslo a niekto na internete ho uhádne, napr. hrubou silou, môže čítať vaše správy a odosielať ich za vás.</p></body></html> - - - - Use a random number generator to make an address - Vytvoriť novú adresu pomocou generátora náhodných čísel - - - - Use a passphrase to make addresses - Vytvoriť novú adresu pomocou hesla - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Stráviť niekoľko minút výpočtového času navyše, aby adresa(y) bola o 1 alebo 2 znakov kratšia - - - - Make deterministic addresses - Vytvoriť deterministické adresy - - - - Address version number: 4 - Číslo verzie adresy: 4 - - - - In addition to your passphrase, you must remember these numbers: - Okrem svojho hesla si musíte zapamätať tiejto údaje: - - - - Passphrase - Heslo - - - - Number of addresses to make based on your passphrase: - Počet adries, ktoré majú byť na základe vášho hesla vytvorené: - - - - Stream number: 1 - Číslo prúdu: 1 - - - - Retype passphrase - Opakovať heslo - - - - Randomly generate address - Adresu generovať náhodne - - - - Label (not shown to anyone except you) - Označenie (zobrazené len vám a nikomu inému) - - - - Use the most available stream - Použiť najviac prístupný prúd - - - - (best if this is the first of many addresses you will create) - (najlepšie, ak ide o prvú z mnohých vytvorených adries) - - - - Use the same stream as an existing address - Použiť ten istý prúd ako existujúca adresa - - - - (saves you some bandwidth and processing power) - (ušetrí nejaké množstvo prenesených dát a výpočtový výkon) - - - - NewSubscriptionDialog - - - Add new entry - Pridať nový záznam - - - - Label - Označenie - - - - Address - Adresa - - - - Enter an address above. - Zadajte adresu vyššie. - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - Zvláštne správanie adresy - - - - Behave as a normal address - Správanie ako normálna adresa - - - - Behave as a pseudo-mailing-list address - Správanie ako pseudo poštový zoznam - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - Správy prijaté na adresu pseudo poštového zoznamu budú automaticky rozoslaná odberateľom (a teda budú zverejnené). - - - - Name of the pseudo-mailing-list: - Meno pseudo poštového zoznamu: - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - - - - aboutDialog - - - About - O - - - - PyBitmessage - - - - - version ? - - - - - <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> - <html><head/><body><p>Šírený pod licenciou na softvér MIT / X11; pozri <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> - - - - This is Beta software. - Toto je beta softvér. - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2017 Vývojári Bitmessage</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Použiť ako zoznam zakázaných (prijať všetky prichádzajúce správy s výnimkou odosielateľov na zozname) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Použiť ako zoznam povolených (blokovať všetky prichádzajúce správy s výnimkou odosielateľov na zozname) - - - - Add new entry - Pridať nový záznam - - - - Name or Label - Meno alebo popis - - - - Address - Adresa - - - - Blacklist - Zoznam zakázaných - - - - Whitelist - Zoznam povolených - - - - connectDialog - - - Bitmessage - Bitmessage - - - - Bitmessage won't connect to anyone until you let it. - Bitmessage sa s nikým nespojí, dokým to nepovolíte. - - - - Connect now - Spojiť teraz - - - - Let me configure special network settings first - Najprv upraviť zvláštne sieťové nastavenia - - - - Work offline - Zostať odpojený - - - - helpDialog - - - Help - Pomoc - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - Keďže Bitmessage je projekt založený na spolupráci, pomoc možno nájsť na internete v Bitmessage Wiki: - - - - iconGlossaryDialog - - - Icon Glossary - Legenda ikon - - - - You have no connections with other peers. - Nemáte žiadne spojenia s partnerskými uzlami. - - - - 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. - Vykonali ste aspoň jedno vychádzajúce spojenie do siete, ale ešte ste nenaviazali žiadne prichádzajúce spojenia. Váš firewall alebo domáci router pravdepodobne nie je nakonfigurovaný tak, aby presmeroval prichádzajúce TCP spojenia k vášmu počítaču. Bitmessage bude fungovať v pohode, keby ste však mali fungujúce prichádzajúce spojenia, pomôžete sieti Bitmessage a váš uzol bude lepšie pripojený. - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - Máte spojenia s partnerskými uzlami a vaša brána firewall je nastavená správne. - - - - You are using TCP port %1. (This can be changed in the settings). - Používate port TCP %1. (Možno zmeniť v nastaveniach). - - - - networkstatus - - - Total connections: - Spojení spolu: - - - - Since startup: - Od spustenia: - - - - Processed 0 person-to-person messages. - Spracovaných 0 bežných správ. - - - - Processed 0 public keys. - Spracovaných 0 verejných kľúčov. - - - - Processed 0 broadcasts. - Spracovaných 0 hromadných správ. - - - - Inventory lookups per second: 0 - Vyhľadaní v inventári za sekundu: 0 - - - - Objects to be synced: - Zostáva synchronizovať objektov: - - - - Stream # - Prúd # - - - - Connections - - - - - Since startup on %1 - Od spustenia %1 - - - - Down: %1/s Total: %2 - Prijatých: %1/s Spolu: %2 - - - - Up: %1/s Total: %2 - Odoslaných: %1/s Spolu: %2 - - - - Total Connections: %1 - Spojení spolu: %1 - - - - Inventory lookups per second: %1 - Vyhľadaní v inventári za sekundu: %1 - - - - Up: 0 kB/s - Odoslaných: 0 kB/s - - - - Down: 0 kB/s - Prijatých: 0 kB/s - - - - Network Status - Stav siete - - - - byte(s) - bajtbajtybajtov - - - - Object(s) to be synced: %n - Zostáva synchronizovať %n objektZostáva synchronizovať %n objektyZostáva synchronizovať %n objektov - - - - Processed %n person-to-person message(s). - Spracovaná %n bežná správa.Spracované %n bežné správy.Spracovaných %n bežných správ. - - - - Processed %n broadcast message(s). - Spracovaná %n hromadná správa.Spracované %n hromadné správy.Spracovaných %n hromadných správ. - - - - Processed %n public key(s). - Spracovaný %n verejný kľúč.Spracované %n verejné kľúče.Spracovaných %n verejných kľúčov. - - - - Peer - Partnerský uzol - - - - IP address or hostname - IP adresa alebo názov hostiteľa - - - - Rating - Hodnotenie - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage sleduje úspešnosť pokusov o pripojenie k jednotlivým uzlom. Hodnotenie sa pohybuje od -1 do 1 a ovplyvňuje pravdepodobnosť výberu uzla v budúcnosti - - - - User agent - Užívateľský agent - - - - Peer's self-reported software - Software hlásený partnerským uzlom - - - - TLS - TLS - - - - Connection encryption - Šifrovanie pripojenia - - - - List of streams negotiated between you and the peer - Zoznam prúdov dohodnutých medzi vami a partnerom - - - - newChanDialog - - - Dialog - - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - Create or join a chan - Vytvoriť alebo pripojiť sa ku kanálu - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>Kanál existuje, keď skupina ľudí zdieľa tie isté dešifrovacie kľúče. Kľúče a bitmessage adresa používané v kanáli sú generované zo slova alebo frázy (názov kanálu). Ak chcete poslať správu všetkým užívateľom v kanáli, pošlite bežnú správu na adresu kanálu.</p><p>Kanály sú experimentálne a vôbec sa nedajú moderovať/cenzúrovať.</p><p>Zadajte názov pre váš kanál. Ak zvolíte dostatočne zložitý názov kanálu (napríklad zložité a jedinečné heslo) a nikto z vašich známych ho nebude verejne zdieľať, potom bude kanál bezpečný a súkromný. Ak vy a niekto iný vytvoríte kanál s rovnakým názvom, bude to v skutočnosti ten istý kanál, ktorý budete zdieľať.</p></body></html> - - - - Chan passphrase/name: - Názov kanálu: - - - - Optional, for advanced usage - Nepovinné, pre pokročilé možnosti - - - - Chan address - Adresa kanálu - - - - Please input chan name/passphrase: - Prosím zadajte názov kanálu - - - - newchandialog - - - Successfully created / joined chan %1 - Kanál %1 úspešne vytvorený/pripojený - - - - Chan creation / joining failed - Vytvorenie/pripojenie kanálu zlyhalo - - - - Chan creation / joining cancelled - Vytvorenie/pripojenie kanálu zrušené - - - - proofofwork - - - C PoW module built successfully. - C PoW modul úspešne zostavený. - - - - Failed to build C PoW module. Please build it manually. - Zostavenie C PoW modulu zlyhalo. Prosím, zostavte ho manuálne. - - - - C PoW module unavailable. Please build it. - C PoW modul nie je dostupný. Prosím, zostavte ho. - - - - qrcodeDialog - - - QR-code - QR kód - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - Znova vytvoriť existujúce adresy - - - - Regenerate existing addresses - Znova vytvoriť existujúce adresy - - - - Passphrase - Heslo - - - - Number of addresses to make based on your passphrase: - Počet adries, ktoré majú byť na základe vášho hesla vytvorené: - - - - Address version number: - Číslo verzie adresy: - - - - Stream number: - Číslo prúdu: - - - - 1 - 1 - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - Stráviť niekoľko minút výpočtového času navyše, aby adresa(y) bola o 1 alebo 2 znakov kratšia - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - Je nutné začiarknuť (alebo nezačiarknuť) toto políčko tak isto, ako keď ste vytvárali svoje adresy prvýkrát. - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - Ak ste v minulosti používali deterministické adresy, ale stratili ich kvôli nehode (ako je napráklad zlyhanie pevného disku), môžete ich vytvoriť znova. Ak ste na vytvorenie adries použili generátor náhodných čísel, potom je vám tento formulár zbytočný. - - - - settingsDialog - - - Settings - Nastavenia - - - - Start Bitmessage on user login - Spustiť Bitmessage pri prihlásení používateľa - - - - Tray - Panel úloh - - - - Start Bitmessage in the tray (don't show main window) - Spustiť Bitmessage v paneli úloh (nezobrazovať hlavné okno) - - - - Minimize to tray - Minimalizovať do panelu úloh - - - - Close to tray - Zavrieť do panelu úloh - - - - Show notification when message received - Zobraziť oznámenie, ked obdržíte správu - - - - Run in Portable Mode - Spustiť v prenosnom režime - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - V prenosnom režime budú správy a konfiguračné súbory uložené v rovnakom priečinku ako program, namiesto v bežnom priečinku pre údaje aplikácie. Vďaka tomu je pohodlné používať Bitmessage na USB kľúči. - - - - Willingly include unencrypted destination address when sending to a mobile device - Povoliť pridanie nezašifrovanej adresy prijímateľa pri posielaní na mobilné zariadenie - - - - Use Identicons - Zobrazuj identikony (ikony automaticky vytvorené pre každú adresu) - - - - Reply below Quote - Odpovedať pod citáciou - - - - Interface Language - Jazyk rozhrania - - - - System Settings - system - Systémové nastavenia - - - - User Interface - Užívateľské rozhranie - - - - Listening port - Prijímajúci port - - - - Listen for connections on port: - Prijímať spojenia na porte: - - - - UPnP: - UPnP: - - - - Bandwidth limit - Obmedzenie šírky pásma - - - - Maximum download rate (kB/s): [0: unlimited] - Maximálna rýchlosť sťahovania (kB/s): [0: bez obmedzenia] - - - - Maximum upload rate (kB/s): [0: unlimited] - Maximálna rýchlosť odosielania (kB/s): [0: bez obmedzenia] - - - - Proxy server / Tor - Proxy server / Tor - - - - Type: - Typ: - - - - Server hostname: - Názov hostiteľského servera: - - - - Port: - Port: - - - - Authentication - Overovanie - - - - Username: - Používateľské meno: - - - - Pass: - Heslo: - - - - Listen for incoming connections when using proxy - Prijímať prichádzajúce spojenia ak je používaný proxy - - - - none - žiadny - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - - - - Network Settings - Nastavenia siete - - - - Total difficulty: - Celková obtiažnosť: - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - 'Celková obtiažnosť' ovplyvňuje celkové množstvo práce, ktorú musí odosielateľ vykonať. Zdvojnásobenie tejto hodnoty zdvojnásobí potrebné množstvo práce. - - - - Small message difficulty: - Obtiažnosť malých správ: - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - Keď vám niekto pošle správu, ich počítač musí najprv vykonať nejakú prácu. Obtiažnosť tejto práce je predvolená na 1. Túto predvoľbu môžete zvýšiť nastavením parametrov. Každá novo vygenerovaná adresa bude od odosielateľa požadovať túto zvýšenú obtiažnosť. Existuje však výnimka: ak vášho známeho máte v adresári, pri poslaní nasledujúcej správy im Bitmessage automaticky oznámi, že im stačí minimálne množstvo práce: obtiažnosť 1. - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - 'Obtiažnosť malých správ' ovplyvňuje najmä náročnosť odosielania malých správ. Zdvojnásobenie tejto hodnoty zdvojnásobí potrebné množstvo práce na odoslanie malých správ, ale veľké správy príliš neovplyvňuje. - - - - Demanded difficulty - Požadovaná obtiažnosť - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - Tu môžete nastaviť maximálne množstvo práce, ktorú váš počítač je ochotný urobiť pre odoslanie správy inej osobe. Nastavenie týchto hodnôt na 0 znamená, že ľubovoľné množtvo práce je prijateľné. - - - - Maximum acceptable total difficulty: - Maximálna prijateľná celková obtiažnosť: - - - - Maximum acceptable small message difficulty: - Maximálna prijateľná obtiažnost malých správ: - - - - Max acceptable difficulty - Max. prijateľná obtiažnosť - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - <html><head/><body><p>Bitmessage sa môže pripojiť k systému s názvom Namecoin, ktorý je podobný Bitcoinu, a s jeho pomocou používať používateľsky príjemné identifikátory. Napríklad namiesto zverejňovania dlhej Bitmessage adresy môžete jednoducho zverejniť meno, povedzme <span style=" font-style:italic;">test.</span></p><p>(Dostať vašu vlastnú adresu do Namecoin-u je však zatiaľ pomerne zložité).</p><p>Bitmessage sa môže pripojiť priamo na namecoind, alebo na aktívnu inštanciu nmcontrol.</p></body</html> - - - - Host: - Hostiteľ: - - - - Password: - Heslo: - - - - Test - Test - - - - Connect to: - Pripojiť ku: - - - - Namecoind - Namecoind - - - - NMControl - NMControl - - - - Namecoin integration - Integrácia namecoin-u - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - <html><head/><body><p>Predvoľba spôsobí opätovné odoslanie správy ak nebude príjemca pripojený na sieť viac ako dva dni. Tieto pokusy budú opakované, dokým príjemca nepotvrdí obdržanie správy. Toto správanie môžete zmeniť zadaním počtu dní alebo mesiacov, po ktorých má Bitmessage s opätovným odosielaním prestať.</p><p>Vstupné polia nechajte prázdne, ak chcete predvolené správanie. </p></body></html> - - - - Give up after - Vzdať po - - - - and - a - - - - days - dňoch - - - - months. - mesiacoch. - - - - Resends Expire - Vypršanie opätovného odosielania - - - - Hide connection notifications - Skryť oznámenia o stave pripojenia - - - - Maximum outbound connections: [0: none] - Maximálny počet odchádzajúcich spojení: [0: žiadne] - - - - Hardware GPU acceleration (OpenCL): - Hardvérové GPU urýchľovanie (OpenCL): - - - \ No newline at end of file diff --git a/src/translations/bitmessage_sv.ts b/src/translations/bitmessage_sv.ts deleted file mode 100644 index 015546b3..00000000 --- a/src/translations/bitmessage_sv.ts +++ /dev/null @@ -1,2058 +0,0 @@ - - - AddAddressDialog - - - Add new entry - - - - - Label - - - - - Address - - - - - EmailGatewayDialog - - - Email gateway - - - - - Register on email gateway - - - - - Account status at email gateway - - - - - Change account settings at email gateway - - - - - Unregister from email gateway - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - - - - - Desired email address (including @mailchuck.com): - - - - - EmailGatewayRegistrationDialog - - - Registration failed: - - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - - - - - Email gateway registration - - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - - - - - MainWindow - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Address Book - - - - - Add sender to your Blacklist - - - - - Move to Trash - - - - - Undelete - - - - - View HTML code as formatted text - - - - - Save message as... - - - - - Mark Unread - - - - - New - - - - - Enable - - - - - Disable - - - - - Set avatar... - - - - - Copy address to clipboard - - - - - Special address behavior... - - - - - Email gateway - - - - - Delete - - - - - Send message to this address - - - - - Subscribe to this address - - - - - Add New Address - - - - - Copy destination address to clipboard - - - - - Force send - - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - - - - - Waiting for their encryption key. Will request it again soon. - - - - - Encryption key request queued. - - - - - Queued. - - - - - Message sent. Waiting for acknowledgement. Sent at %1 - - - - - Message sent. Sent at %1 - - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - - - - - Broadcast queued. - - - - - Broadcast on %1 - - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - - - - - Forced difficulty override. Send should start soon. - - - - - Unknown status: %1 %2 - - - - - Not Connected - - - - - Show Bitmessage - - - - - Send - - - - - Subscribe - - - - - Channel - - - - - Quit - - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. - - - - - Open keys.dat? - - - - - You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - You may manage your keys by editing the keys.dat file stored in - %1 -It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - - - - - Delete trash? - - - - - Are you sure you want to delete all trashed messages? - - - - - bad passphrase - - - - - You must type your passphrase. If you don't have one then this is not the form for you. - - - - - Bad address version number - - - - - Your address version number must be a number: either 3 or 4. - - - - - Your address version number must be either 3 or 4. - - - - - Chan name needed - - - - - You didn't enter a chan name. - - - - - Address already present - - - - - Could not add chan because it appears to already be one of your identities. - - - - - Success - - - - - Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - - - - - Address too new - - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - - - - - Address invalid - - - - - That Bitmessage address is not valid. - - - - - Address does not match chan name - - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - - - - - Successfully joined chan. - - - - - Connection lost - - - - - Connected - - - - - Message trashed - - - - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - - - - - Message too long - - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - - - - - Error: Bitmessage addresses start with BM- Please check %1 - - - - - Error: The address %1 is not typed or copied correctly. Please check it. - - - - - Error: The address %1 contains invalid characters. Please check it. - - - - - Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - - - - - Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Error: Something is wrong with the address %1. - - - - - Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. - - - - - Address version number - - - - - Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Stream number - - - - - Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. - - - - - Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. - - - - - Message queued. - - - - - Your 'To' field is empty. - - - - - Right click one or more entries in your address book and select 'Send message to this address'. - - - - - Fetched address from namecoin identity. - - - - - New Message - - - - - From - - - - - Sending email gateway registration request - - - - - Address is valid. - - - - - The address you entered was invalid. Ignoring it. - - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Restart - - - - - You must restart Bitmessage for the port number change to take effect. - - - - - Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). - - - - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Will not resend ever - - - - - Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - Passphrase mismatch - - - - - The passphrase you entered twice doesn't match. Try again. - - - - - Choose a passphrase - - - - - You really do need a passphrase. - - - - - Address is gone - - - - - Bitmessage cannot find your address %1. Perhaps you removed it? - - - - - Address disabled - - - - - Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. - - - - - Entry added to the Address Book. Edit the label to your liking. - - - - - Entry added to the blacklist. Edit the label to your liking. - - - - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - - - - - Moved items to trash. - - - - - Undeleted item. - - - - - Save As... - - - - - Write error. - - - - - No addresses selected. - - - - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - - - - - Do you really want to remove this avatar? - - - - - You have already set an avatar for this address. Do you really want to overwrite it? - - - - - Start-on-login not yet supported on your OS. - - - - - Minimize-to-tray not yet supported on your OS. - - - - - Tray notifications not yet supported on your OS. - - - - - Testing... - - - - - This is a chan address. You cannot use it as a pseudo-mailing list. - - - - - The address should start with ''BM-'' - - - - - The address is not typed or copied correctly (the checksum failed). - - - - - The version number of this address is higher than this software can support. Please upgrade Bitmessage. - - - - - The address contains invalid characters. - - - - - Some data encoded in the address is too short. - - - - - Some data encoded in the address is too long. - - - - - Some data encoded in the address is malformed. - - - - - Enter an address above. - - - - - Address is an old type. We cannot display its past broadcasts. - - - - - There are no recent broadcasts from this address to display. - - - - - You are using TCP port %1. (This can be changed in the settings). - - - - - Bitmessage - - - - - Identities - - - - - New Identity - - - - - Search - - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - - - - Received - - - - - Messages - - - - - Address book - - - - - Address - - - - - Add Contact - - - - - Fetch Namecoin ID - - - - - Subject: - - - - - From: - - - - - To: - - - - - Send ordinary Message - - - - - Send Message to your Subscribers - - - - - TTL: - - - - - Subscriptions - - - - - Add new Subscription - - - - - Chans - - - - - Add Chan - - - - - File - - - - - Settings - - - - - Help - - - - - Import keys - - - - - Manage keys - - - - - Ctrl+Q - - - - - F1 - - - - - Contact support - - - - - About - - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - Join / Create chan - - - - - All accounts - - - - - Zoom level %1% - - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - - Add new entry - - - - - Display the %1 recent broadcast(s) from this address. - - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - - - - - Waiting for objects to be sent... %1% - - - - - Saving settings... %1% - - - - - Shutting down core... %1% - - - - - Stopping notifications... %1% - - - - - Shutdown imminent... %1% - - - - - %n hour(s) - - - - - %n day(s) - - - - - Shutting down PyBitmessage... %1% - - - - - Sent - - - - - Generating one new address - - - - - Done generating address. Doing work necessary to broadcast it... - - - - - Generating %1 new addresses. - - - - - %1 is already in 'Your Identities'. Not adding it again. - - - - - Done generating address - - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - - - - - Error! Could not find sender address (your address) in the keys.dat file. - - - - - Doing work necessary to send broadcast... - - - - - Broadcast sent on %1 - - - - - Encryption key was requested earlier. - - - - - Sending a request for the recipient's encryption key. - - - - - Looking up the receiver's public key - - - - - Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - - - - - Doing work necessary to send message. -There is no required difficulty for version 2 addresses like this. - - - - - Doing work necessary to send message. -Receiver's required difficulty: %1 and %2 - - - - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - - - - - Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - - - - - Doing work necessary to send message. - - - - - Message sent. Waiting for acknowledgement. Sent on %1 - - - - - Doing work necessary to request encryption key. - - - - - Broadcasting the public key request. This program will auto-retry if they are offline. - - - - - Sending public key request. Waiting for reply. Requested at %1 - - - - - UPnP port mapping established on port %1 - - - - - UPnP port mapping removed - - - - - NewAddressDialog - - - Create new Address - - - - - Here you may generate as many addresses as you like. Indeed, creating and abandoning addresses is encouraged. You may generate addresses by using either random numbers or by using a passphrase. If you use a passphrase, the address is called a "deterministic" address. -The 'Random Number' option is selected by default but deterministic addresses have several pros and cons: - - - - - <html><head/><body><p><span style=" font-weight:600;">Pros:<br/></span>You can recreate your addresses on any computer from memory. <br/>You need-not worry about backing up your keys.dat file as long as you can remember your passphrase. <br/><span style=" font-weight:600;">Cons:<br/></span>You must remember (or write down) your passphrase if you expect to be able to recreate your keys if they are lost. <br/>You must remember the address version number and the stream number along with your passphrase. <br/>If you choose a weak passphrase and someone on the Internet can brute-force it, they can read your messages and send messages as you.</p></body></html> - - - - - Use a random number generator to make an address - - - - - Use a passphrase to make addresses - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - Make deterministic addresses - - - - - Address version number: 4 - - - - - In addition to your passphrase, you must remember these numbers: - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Stream number: 1 - - - - - Retype passphrase - - - - - Randomly generate address - - - - - Label (not shown to anyone except you) - - - - - Use the most available stream - - - - - (best if this is the first of many addresses you will create) - - - - - Use the same stream as an existing address - - - - - (saves you some bandwidth and processing power) - - - - - NewSubscriptionDialog - - - Add new entry - - - - - Label - - - - - Address - - - - - Enter an address above. - - - - - SpecialAddressBehaviorDialog - - - Special Address Behavior - - - - - Behave as a normal address - - - - - Behave as a pseudo-mailing-list address - - - - - Mail received to a pseudo-mailing-list address will be automatically broadcast to subscribers (and thus will be public). - - - - - Name of the pseudo-mailing-list: - - - - - aboutDialog - - - About - - - - - PyBitmessage - - - - - version ? - - - - - <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> - - - - - This is Beta software. - - - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - - - - - Add new entry - - - - - Name or Label - - - - - Address - - - - - Blacklist - - - - - Whitelist - - - - - connectDialog - - - Bitmessage - - - - - Bitmessage won't connect to anyone until you let it. - - - - - Connect now - - - - - Let me configure special network settings first - - - - - helpDialog - - - Help - - - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - - - - - iconGlossaryDialog - - - Icon Glossary - - - - - You have no connections with other peers. - - - - - 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. - - - - - You are using TCP port ?. (This can be changed in the settings). - - - - - You do have connections with other peers and your firewall is correctly configured. - - - - - networkstatus - - - Total connections: - - - - - Since startup: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Inventory lookups per second: 0 - - - - - Objects to be synced: - - - - - Stream # - - - - - Connections - - - - - Since startup on %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Total Connections: %1 - - - - - Inventory lookups per second: %1 - - - - - Up: 0 kB/s - - - - - Down: 0 kB/s - - - - - Network Status - - - - - byte(s) - - - - - Object(s) to be synced: %n - - - - - Processed %n person-to-person message(s). - - - - - Processed %n broadcast message(s). - - - - - Processed %n public key(s). - - - - - newChanDialog - - - Dialog - - - - - Create a new chan - - - - - Join a chan - - - - - Create a chan - - - - - <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - - - - - Chan name: - - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - - - - - Chan bitmessage address: - - - - - regenerateAddressesDialog - - - Regenerate Existing Addresses - - - - - Regenerate existing addresses - - - - - Passphrase - - - - - Number of addresses to make based on your passphrase: - - - - - Address version number: - - - - - Stream number: - - - - - 1 - - - - - Spend several minutes of extra computing time to make the address(es) 1 or 2 characters shorter - - - - - You must check (or not check) this box just like you did (or didn't) when you made your addresses the first time. - - - - - If you have previously made deterministic addresses but lost them due to an accident (like hard drive failure), you can regenerate them here. If you used the random number generator to make your addresses then this form will be of no use to you. - - - - - settingsDialog - - - Settings - - - - - Start Bitmessage on user login - - - - - Tray - - - - - Start Bitmessage in the tray (don't show main window) - - - - - Minimize to tray - - - - - Close to tray - - - - - Show notification when message received - - - - - Run in Portable Mode - - - - - In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. - - - - - Willingly include unencrypted destination address when sending to a mobile device - - - - - Use Identicons - - - - - Reply below Quote - - - - - Interface Language - - - - - System Settings - system - - - - - User Interface - - - - - Listening port - - - - - Listen for connections on port: - - - - - UPnP: - - - - - Bandwidth limit - - - - - Maximum download rate (kB/s): [0: unlimited] - - - - - Maximum upload rate (kB/s): [0: unlimited] - - - - - Proxy server / Tor - - - - - Type: - - - - - Server hostname: - - - - - Port: - - - - - Authentication - - - - - Username: - - - - - Pass: - - - - - Listen for incoming connections when using proxy - - - - - none - - - - - SOCKS4a - - - - - SOCKS5 - - - - - Network Settings - - - - - Total difficulty: - - - - - The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. - - - - - Small message difficulty: - - - - - When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. - - - - - The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. - - - - - Demanded difficulty - - - - - Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. - - - - - Maximum acceptable total difficulty: - - - - - Maximum acceptable small message difficulty: - - - - - Max acceptable difficulty - - - - - Hardware GPU acceleration (OpenCL) - - - - - <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> - - - - - Host: - - - - - Password: - - - - - Test - - - - - Connect to: - - - - - Namecoind - - - - - NMControl - - - - - Namecoin integration - - - - - <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> - - - - - Give up after - - - - - and - - - - - days - - - - - months. - - - - - Resends Expire - - - - \ No newline at end of file diff --git a/src/translations/bitmessage_zh_cn.pro b/src/translations/bitmessage_zh_cn.pro new file mode 100644 index 00000000..cde33c9f --- /dev/null +++ b/src/translations/bitmessage_zh_cn.pro @@ -0,0 +1,35 @@ +SOURCES = ../addresses.py\ + ../bitmessagemain.py\ + ../class_addressGenerator.py\ + ../class_outgoingSynSender.py\ + ../class_objectProcessor.py\ + ../class_receiveDataThread.py\ + ../class_sendDataThread.py\ + ../class_singleCleaner.py\ + ../class_singleListener.py\ + ../class_singleWorker.py\ + ../class_sqlThread.py\ + ../helper_bitcoin.py\ + ../helper_bootstrap.py\ + ../helper_generic.py\ + ../helper_inbox.py\ + ../helper_sent.py\ + ../helper_startup.py\ + ../shared.py\ + ../bitmessageqt/__init__.py\ + ../bitmessageqt/about.py\ + ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/connect.py\ + ../bitmessageqt/help.py\ + ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/newaddressdialog.py\ + ../bitmessageqt/newchandialog.py\ + ../bitmessageqt/newsubscriptiondialog.py\ + ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/settings.py\ + ../bitmessageqt/specialaddressbehavior.py + + +TRANSLATIONS = bitmessage_zh_cn.ts +CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index cc37b146..3f894afd 100644 Binary files a/src/translations/bitmessage_zh_cn.qm and b/src/translations/bitmessage_zh_cn.qm differ diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 58e16cb8..adc055e5 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -1,4 +1,6 @@ - + + + AddAddressDialog @@ -17,1550 +19,1059 @@ 地址 - - EmailGatewayDialog - - - Email gateway - 电子邮件网关 - - - - Register on email gateway - 注册电子邮件网关 - - - - Account status at email gateway - 电子邮件网关帐户状态 - - - - Change account settings at email gateway - 更改电子邮件网关帐户设置 - - - - Unregister from email gateway - 取消电子邮件网关注册 - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. - 电子邮件网关允许您与电子邮件用户通信。目前,只有Mailchuck电子邮件网关(@mailchuck.com)可用。 - - - - Desired email address (including @mailchuck.com): - 所需的电子邮件地址(包括 @mailchuck.com): - - - - EmailGatewayRegistrationDialog - - - Registration failed: - 注册失败: - - - - The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - 要求的电子邮件地址不详,请尝试一个新的。填写新的所需电子邮件地址(包括 @mailchuck.com)如下: - - - - Email gateway registration - 电子邮件网关注册 - - - - Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desired email address (including @mailchuck.com) below: - 电子邮件网关允许您与电子邮件用户通信。目前,只有Mailchuck电子邮件网关(@mailchuck.com)可用。请键入所需的电子邮件地址(包括 @mailchuck.com)如下: - - - - Mailchuck - - - # You can use this to configure your email gateway account -# Uncomment the setting you want to use -# Here are the options: -# -# pgp: server -# The email gateway will create and maintain PGP keys for you and sign, verify, -# encrypt and decrypt on your behalf. When you want to use PGP but are lazy, -# use this. Requires subscription. -# -# pgp: local -# The email gateway will not conduct PGP operations on your behalf. You can -# either not use PGP at all, or use it locally. -# -# attachments: yes -# Incoming attachments in the email will be uploaded to MEGA.nz, and you can -# download them from there by following the link. Requires a subscription. -# -# attachments: no -# Attachments will be ignored. -# -# archive: yes -# Your incoming emails will be archived on the server. Use this if you need -# help with debugging problems or you need a third party proof of emails. This -# however means that the operator of the service will be able to read your -# emails even after they have been delivered to you. -# -# archive: no -# Incoming emails will be deleted from the server as soon as they are relayed -# to you. -# -# masterpubkey_btc: BIP44 xpub key or electrum v1 public seed -# offset_btc: integer (defaults to 0) -# feeamount: number with up to 8 decimal places -# feecurrency: BTC, XBT, USD, EUR or GBP -# Use these if you want to charge people who send you emails. If this is on and -# an unknown person sends you an email, they will be requested to pay the fee -# specified. As this scheme uses deterministic public keys, you will receive -# the money directly. To turn it off again, set "feeamount" to 0. Requires -# subscription. - - #您可以用它来配置你的电子邮件网关帐户 -#取消您要使用的设定 -#这里的选项: -# -# pgp: server -#电子邮件网关将创建和维护PGP密钥,为您签名和验证, -#代表加密和解密。当你想使用PGP,但懒惰, -#用这个。需要订阅。 -# -# pgp: local -#电子邮件网关不会代你进行PGP操作。您可以 -#选择或者不使用PGP, 或在本地使用它。 -# -# attachement: yes -#传入附件的电子邮件将会被上传到MEGA.nz,您可以从 -# 按照那里链接下载。需要订阅。 -# -# attachement: no -#附件将被忽略。 -# -# archive: yes -#您收到的邮件将在服务器上存档。如果您有需要请使用 -#帮助调试问题,或者您需要第三方电子邮件的证明。这 -#然而,意味着服务的操作运将能够读取您的 -#电子邮件即使电子邮件已经传送给你。 -# -# archive: no -# 已传入的电子邮件将从服务器被删除只要他们已中继。 -# -# masterpubkey_btc:BIP44 XPUB键或琥珀金V1公共种子 -#offset_btc:整数(默认为0) -#feeamount:多达8位小数 -#feecurrency号:BTC,XBT,美元,欧元或英镑 -#用这些,如果你想主管谁送你的电子邮件的人。如果这是在和 -#一个不明身份的人向您发送一封电子邮件,他们将被要求支付规定的费用 -#。由于这个方案使用确定性的公共密钥,你会直接接收 -#钱。要再次将其关闭,设置“feeamount”0 -#需要订阅。 - - MainWindow - - Reply to sender - 回复发件人 + + Bitmessage + 比特信 - - Reply to channel - 回复通道 + + Search + 搜索 - - Add sender to your Address Book - 将发送者添加到您的通讯簿 + + All + 全部 - - Add sender to your Blacklist - 将发件人添加到您的黑名单 + + To + - - Move to Trash - 移入回收站 + + From + 来自 - - Undelete - 取消删除 + + Subject + 标题 - - View HTML code as formatted text - 作为HTML查看 + + Message + 消息 - - Save message as... - 将消息保存为... + + Received + 接收时间 - - Mark Unread - 标记为未读 + + Inbox + 收件箱 - - New - 新建 + + Load from Address book + 从地址本中选择 - - Enable - 启用 + + Fetch Namecoin ID + 接收Namecoin ID - - Disable - 禁用 + + Message: + 消息: - - Set avatar... - 设置头像... + + Subject: + 标题: - - Copy address to clipboard - 将地址复制到剪贴板 + + Send to one or more specific people + 发送给一个或更多指定的人 - - Special address behavior... - 特别的地址行为... + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'MS Shell Dlg 2';"><br /></p></body></html> + - - Email gateway - 电子邮件网关 + + To: + 至: - - Delete - 删除 + + From: + 来自: - - Send message to this address - 发送消息到这个地址 + + Broadcast to everyone who is subscribed to your address + 广播给全部订阅到您的地址的人 - - Subscribe to this address - 订阅到这个地址 - - - - Add New Address - 创建新地址 - - - - Copy destination address to clipboard - 复制目标地址到剪贴板 - - - - Force send - 强制发送 - - - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - 您的地址中的一个, %1,是一个过时的版本1地址. 版本1地址已经不再受到支持了. 我们可以将它删除掉么? - - - - Waiting for their encryption key. Will request it again soon. - 正在等待他们的加密密钥,我们会在稍后再次请求。 - - - - Encryption key request queued. - - - - - Queued. - 已经添加到队列。 - - - - Message sent. Waiting for acknowledgement. Sent at %1 - 消息已经发送. 正在等待回执. 发送于 %1 - - - - Message sent. Sent at %1 - 消息已经发送. 发送于 %1 - - - - Need to do work to send message. Work is queued. - - - - - Acknowledgement of the message received %1 - 消息的回执已经收到于 %1 - - - - Broadcast queued. - 广播已经添加到队列中。 - - - - Broadcast on %1 - 已经广播于 %1 - - - - Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 - 错误: 收件人要求的做工量大于我们的最大接受做工量。 %1 - - - - Problem: The recipient's encryption key is no good. Could not encrypt message. %1 - 错误: 收件人的加密密钥是无效的。不能加密消息。 %1 - - - - Forced difficulty override. Send should start soon. - 已经忽略最大做工量限制。发送很快就会开始。 - - - - Unknown status: %1 %2 - 未知状态: %1 %2 - - - - Not Connected - 未连接 - - - - Show Bitmessage - 显示比特信 - - - + Send 发送 - - Subscribe + + Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. + 请注意,广播的消息仅仅使用您的地址加密。任何知道您的地址的人可以阅读其中的内容。 + + + + Status + 状态 + + + + Sent + 已发送 + + + + New + 新建 + + + + Label (not shown to anyone) + 标签(只有您看的到) + + + + Address + 地址 + + + + Stream + 节点流 + + + + Your Identities + 您的身份 + + + + Here you can subscribe to 'broadcast messages' that are sent by other users. Messages will appear in your Inbox. Addresses here override those on the Blacklist tab. + 您可以在这里订阅到广播地址,接收来自其他用户的广播。消息将出现在您的收件箱。您的黑名单对在这里的地址无效。 + + + + Add new Subscription + 添加新的订阅 + + + + Label + 标签 + + + + Subscriptions 订阅 - - Channel - 频道 + + The Address book is useful for adding names or labels to other people's Bitmessage addresses so that you can recognize them more easily in your inbox. You can add entries here using the 'Add' button, or from your inbox by right-clicking on a message. + 这个地址本将帮助您给其他人的地址添加名字或标签,这样的话您就可以在收件箱中更容易的认出它们。您可以在这里点“新建”,或在一条在收件箱中的消息上右击来添加条目。 - + + Add new entry + 添加新条目 + + + + Name or Label + 名称或标签 + + + + Address Book + 地址本 + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + 使用黑名单(允许所有黑名单以外的人向您发送消息) + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + 使用白名单(仅允许在白名单上的人向您发送消息) + + + + Blacklist + 黑名单 + + + + Stream # + 节点流 # + + + + Connections + 连接 + + + + Total connections: 0 + 总连接数: 0 + + + + Since startup at asdf: + 自启动于 asdf: + + + + Processed 0 person-to-person message. + 处理了 0 个点对点消息。 + + + + Processed 0 public key. + 处理了 0 个公匙。 + + + + Processed 0 broadcast. + 处理了 0 个广播。 + + + + Inventory lookups per second: 0 + 每秒种的同步请求数: 0 + + + + Network Status + 网络状态 + + + + File + 文件 + + + + Settings + 设置 + + + + Help + 帮助 + + + + Import keys + 导入密钥 + + + + Manage keys + 管理密钥 + + + Quit 退出 - + + Ctrl+Q + Ctrl+Q + + + + F1 + F1 + + + + About + 关于 + + + + Regenerate deterministic addresses + 重新生成静态地址 + + + + Delete all trashed messages + 彻底删除全部回收站中的消息 + + + + Join / Create chan + 加入或创建一个频道 + + + + Reply + 回复 + + + + Add sender to your Address Book + 将发送者添加到地址本 + + + + Move to Trash + 移入回收站 + + + + View HTML code as formatted text + 作为HTML查看 + + + + Save message as... + 将消息保存为... + + + + Mark Unread + 标记为未读 + + + + Enable + 启用 + + + + Disable + 禁用 + + + + Set avatar... + 设置头像... + + + + Copy address to clipboard + 将地址复制到剪贴板 + + + + Special address behavior... + 特别的地址行为... + + + + Send message to this address + 发送消息到这个地址 + + + + Subscribe to this address + 订阅到这个地址 + + + + Add New Address + 创建新地址 + + + + Delete + 删除 + + + + Copy destination address to clipboard + 复制目标地址到剪贴板 + + + + Force send + 强制发送 + + + + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + 您的地址中的一个, %1,是一个过时的版本1地址. 版本1地址已经不再受到支持了. 我们可以将它删除掉么? + + + + Since startup on %1 + 自启动于 %1 + + + + Waiting on their encryption key. Will request it again soon. + 正在等待他们的加密密钥,我们会在稍后再次请求。 + + + + Encryption key request queued. + 加密密钥请求已经添加到队列中。 + + + + Queued. + 已经添加到队列。 + + + + Message sent. Waiting on acknowledgement. Sent at %1 + 消息已经发送. 正在等待回执. 发送于 %1 + + + + Message sent. Sent at %1 + 消息已经发送. 发送于 %1 + + + + Need to do work to send message. Work is queued. + 发生消息需要做工。做工正在队列中等待。 + + + + Acknowledgement of the message received %1 + 消息的回执已经收到于 %1 + + + + Broadcast queued. + 广播已经添加到队列中。 + + + + Broadcast on %1 + 已经广播于 %1 + + + + Problem: The work demanded by the recipient is more difficult than you are willing to do. %1 + 错误: 收件人要求的做工量大于我们的最大接受做工量。 %1 + + + + Problem: The recipient's encryption key is no good. Could not encrypt message. %1 + 错误: 收件人的加密密钥是无效的。不能加密消息。 %1 + + + + Forced difficulty override. Send should start soon. + 已经忽略最大做工量限制。发送很快就会开始。 + + + + Unknown status: %1 %2 + 未知状态: %1 %2 + + + + Not Connected + 未连接 + + + + Show Bitmessage + 显示比特信 + + + + Subscribe + 订阅 + + + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. 您可以通过编辑和程序储存在同一个目录的 keys.dat 来编辑密钥。备份这个文件十分重要。 - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. 您可以通过编辑储存在 %1 的 keys.dat 来编辑密钥。备份这个文件十分重要。 - + Open keys.dat? 打开 keys.dat ? - + You may manage your keys by editing the keys.dat file stored in the same directory as this program. It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) 您可以通过编辑和程序储存在同一个目录的 keys.dat 来编辑密钥。备份这个文件十分重要。您现在想打开这个文件么?(请在进行任何修改前关闭比特信) - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) 您可以通过编辑储存在 %1 的 keys.dat 来编辑密钥。备份这个文件十分重要。您现在想打开这个文件么?(请在进行任何修改前关闭比特信) - + Delete trash? 清空回收站? - + Are you sure you want to delete all trashed messages? 您确定要删除全部被回收的消息么? - + bad passphrase 错误的密钥 - + You must type your passphrase. If you don't have one then this is not the form for you. 您必须输入您的密钥。如果您没有的话,这个表单不适用于您。 - + Bad address version number 地址的版本号无效 - + Your address version number must be a number: either 3 or 4. 您的地址的版本号必须是一个数字: 3 或 4. - + Your address version number must be either 3 or 4. 您的地址的版本号必须是 3 或 4. - + Chan name needed - + 需要频道的名称 - + You didn't enter a chan name. - + 您没有输入一个频道的名称。 - + Address already present - + 地址已经在这里了 - + Could not add chan because it appears to already be one of your identities. - + 无法添加频道,因为它似乎已经是您的身份之一。 - + Success - + 成功 - + Successfully created chan. To let others join your chan, give them the chan name and this Bitmessage address: %1. This address also appears in 'Your Identities'. - + 成功的创建了频道。要让他人加入,请告诉他们频道的名称和这个比特信地址 %1 。这个比特信地址也会出现在“您的身份”中。 - + Address too new - + 地址太新了 - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - + 尽管比特信地址也许是有效的,不过比特信地址的版本号比我们能处理的要新。也许您应该升级比特信了。 - + Address invalid - + 地址有效 - + That Bitmessage address is not valid. - + 比特信地址无效。 - + Address does not match chan name - + 地址和频道的名称不符 - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. - + 尽管您输入的比特信地址是有效的,不过它和频道的名称不符。 - + Successfully joined chan. - + 成功的加入到频道。 - + + Processed %1 person-to-person messages. + 处理了 %1 个点对点消息。 + + + + Processed %1 broadcast messages. + 处理了 %1 个广播。 + + + + Processed %1 public keys. + 处理了 %1 个公匙。 + + + + Total Connections: %1 + 总连接数: %1 + + + + Inventory lookups per second: %1 + 每秒种的同步请求数: %1 + + + Connection lost 连接已丢失 - + Connected 已经连接 - + Message trashed 消息已经移入回收站 - - The TTL, or Time-To-Live is the length of time that the network will hold the message. - The recipient must get it during this time. If your Bitmessage client does not hear an acknowledgement, it - will resend the message automatically. The longer the Time-To-Live, the - more work your computer must do to send the message. A Time-To-Live of four or five days is often appropriate. - 這TTL,或Time-To-Time是保留信息网络时间的长度. -收件人必须在此期间得到它. 如果您的Bitmessage客户沒有听到确认, 它会自动重新发送信息. Time-To-Live的时间越长, 您的电脑必须要做更多工作來发送信息. 四天或五天的 Time-To-Time, 经常是合适的. - - - - Message too long - 信息太长 - - - - The message that you are trying to send is too long by %1 bytes. (The maximum is 261644 bytes). Please cut it down before sending. - 你正在尝试发送的信息已超过%1个字节太长, (最大为261644个字节). 发送前请剪下来。 - - - - Error: Your account wasn't registered at an email gateway. Sending registration now as %1, please wait for the registration to be processed before retrying sending. - 错误: 您的帐户没有在电子邮件网关注册。现在发送注册为%1​​, 注册正在处理请稍候重试发送. - - - + Error: Bitmessage addresses start with BM- Please check %1 - + 错误:比特信地址以BM-开始,请检查 %1 - + Error: The address %1 is not typed or copied correctly. Please check it. - + 错误:地址 %1 没有被正确的键入或复制。 请检查一下。 - + Error: The address %1 contains invalid characters. Please check it. - + 错误: 比特信地址 %1 包含无效的字符。请检查一下。 - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - + 错误:地址 %1 的版本号过高。您可能需要升级您的比特信软件或者您的朋友正在使用本程序的非主线版本。 - + Error: Some data encoded in the address %1 is too short. There might be something wrong with the software of your acquaintance. - + 错误:在地址 %1 中编码的部分信息过短。您的朋友的软件可能有点问题。 - + Error: Some data encoded in the address %1 is too long. There might be something wrong with the software of your acquaintance. - + 错误:在地址 %1 中编码的部分信息过长。您的朋友的软件可能有点问题。 - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - + Error: Something is wrong with the address %1. - + 错误: 地址%1 有为未知的错误。 - + Error: You must specify a From address. If you don't have one, go to the 'Your Identities' tab. 错误: 您必须指出一个表单地址, 如果您没有,请到“您的身份”标签页。 - + Address version number 地址版本号 - + Concerning the address %1, Bitmessage cannot understand address version numbers of %2. Perhaps upgrade Bitmessage to the latest version. 地址 %1 的地址版本号 %2 无法被比特信理解。也许你应该升级你的比特信到最新版本。 - + Stream number 节点流序号 - + Concerning the address %1, Bitmessage cannot handle stream numbers of %2. Perhaps upgrade Bitmessage to the latest version. 地址 %1 的节点流序号 %2 无法被比特信理解。也许你应该升级你的比特信到最新版本。 - + Warning: You are currently not connected. Bitmessage will do the work necessary to send the message but it won't send until you connect. 警告: 您尚未连接。 比特信将做足够的功来发送消息,但是消息不会被发出直到您连接。 - - Message queued. - 信息排队。 - - - + Your 'To' field is empty. “收件人"是空的。 - + Right click one or more entries in your address book and select 'Send message to this address'. 在您的地址本的一个条目上右击,之后选择”发送消息到这个地址“。 - + Fetched address from namecoin identity. 已经自namecoin接收了地址。 - + + Work is queued. %1 + 做工已经添加到队列中。 %1 + + + New Message 新消息 - + From - + 来自 - - Sending email gateway registration request - 发送电​​子邮件网关注册请求 - - - + Address is valid. 地址有效。 - + The address you entered was invalid. Ignoring it. 您输入的地址是无效的,将被忽略。 - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. 错误:您无法将一个地址添加到您的地址本两次,请尝试重命名已经存在的那个。 - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - 错误: 您不能在同一地址添加到您的订阅两次. 也许您可重命名现有之一. + + Error: You cannot add the same address to your subsciptions twice. Perhaps rename the existing one if you want. + 错误:您无法将一个地址添加到您的订阅两次,也许您想重命名已经存在的那个。 - + Restart 重启 - + You must restart Bitmessage for the port number change to take effect. 您必须重启以便使比特信对于使用的端口的改变生效。 - + Bitmessage will use your proxy from now on but you may want to manually restart Bitmessage now to close existing connections (if any). 比特信将会从现在开始使用代理,但是您可能想手动重启比特信以便使之前的连接关闭(如果有的话)。 - - Number needed - 需求数字 - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - 您最大的下载和上传速率必须是数字. 忽略您键入的内容. - - - + Will not resend ever 不尝试再次发送 - + Note that the time limit you entered is less than the amount of time Bitmessage waits for the first resend attempt therefore your messages will never be resent. 请注意,您所输入的时间限制小于比特信的最小重试时间,因此您将永远不会重发消息。 - - Sending email gateway unregistration request - 发送电​​子邮件网关注销请求 + + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. + 错误:您无法将一个地址添加到您的列表两次,也许您想重命名已经存在的那个。 - - Sending email gateway status request - 发送电​​子邮件网关状态请求 - - - + Passphrase mismatch 密钥不匹配 - + The passphrase you entered twice doesn't match. Try again. 您两次输入的密码并不匹配,请再试一次。 - + Choose a passphrase 选择一个密钥 - + You really do need a passphrase. 您真的需要一个密码。 - + + All done. Closing user interface... + 全部完成,正在关闭用户界面... + + + Address is gone 已经失去了地址 - + Bitmessage cannot find your address %1. Perhaps you removed it? 比特信无法找到你的地址 %1。 也许你已经把它删掉了? - + Address disabled 地址已经禁用 - + Error: The address from which you are trying to send is disabled. You'll have to enable it on the 'Your Identities' tab before using it. 错误: 您想以一个您已经禁用的地址发出消息。在使用之前您需要在“您的身份”处再次启用。 - + Entry added to the Address Book. Edit the label to your liking. 条目已经添加到地址本。您可以去修改您的标签。 - - Entry added to the blacklist. Edit the label to your liking. - 条目添加到黑名单. 根据自己的喜好编辑标签. + + Moved items to trash. There is no user interface to view your trash, but it is still on disk if you are desperate to get it back. + 已经移动项目到回收站。没有图形化的界面可以查看您的回收站,不过如果您还想找回的话它还在您的硬盘上。 - - Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want. - 错误: 您不能在同一地址添加到您的黑名单两次. 也许您可重命名现有之一. - - - - Moved items to trash. - 已经移动项目到回收站。 - - - - Undeleted item. - 未删除的项目。 - - - + Save As... 另存为... - + Write error. 写入失败。 - + No addresses selected. 没有选择地址。 - - If you delete the subscription, messages that you already received will become inaccessible. Maybe you can consider disabling the subscription instead. Disabled subscriptions will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the subscription? - 如果删除订阅, 您已经收到的信息将无法访问. 也许你可以考虑禁用订阅.禁用订阅将不会收到新信息, 但您仍然可以看到你已经收到的信息. - -你确定要删除订阅? - - - - If you delete the channel, messages that you already received will become inaccessible. Maybe you can consider disabling the channel instead. Disabled channels will not receive new messages, but you can still view messages you already received. - -Are you sure you want to delete the channel? - 如果您删除的频道, 你已经收到的信息将无法访问. 也许你可以考虑禁用频道. 禁用频道将不会收到新信息, 但你仍然可以看到你已经收到的信息. - -你确定要删除频道? - - - + Do you really want to remove this avatar? 您真的想移除这个头像么? - + You have already set an avatar for this address. Do you really want to overwrite it? 您已经为这个地址设置了头像了。您真的想移除么? - + Start-on-login not yet supported on your OS. 登录时启动尚未支持您在使用的操作系统。 - + Minimize-to-tray not yet supported on your OS. 最小化到托盘尚未支持您的操作系统。 - + Tray notifications not yet supported on your OS. 托盘提醒尚未支持您所使用的操作系统。 - + Testing... 正在测试... - + This is a chan address. You cannot use it as a pseudo-mailing list. 这是一个频道地址,您无法把它作为伪邮件列表。 - + The address should start with ''BM-'' 地址应该以"BM-"开始 - + The address is not typed or copied correctly (the checksum failed). 地址没有被正确的键入或复制(校验码校验失败)。 - + The version number of this address is higher than this software can support. Please upgrade Bitmessage. 这个地址的版本号大于此软件的最大支持。 请升级比特信。 - + The address contains invalid characters. 这个地址中包含无效字符。 - + Some data encoded in the address is too short. 在这个地址中编码的部分信息过少。 - + Some data encoded in the address is too long. 在这个地址中编码的部分信息过长。 - - Some data encoded in the address is malformed. - 在地址编码的某些数据格式不正确. - - - + Enter an address above. 请在上方键入地址。 - + Address is an old type. We cannot display its past broadcasts. 地址没有近期的广播。我们无法显示之间的广播。 - + There are no recent broadcasts from this address to display. 没有可以显示的近期广播。 - + + Display the %1 recent broadcast from this address. + 显示 %1 条近期广播。 + + + + Display the %1 recent broadcasts from this address. + 显示 %1 条近期广播。 + + + You are using TCP port %1. (This can be changed in the settings). 您正在使用TCP端口 %1 。(可以在设置中修改)。 - - Bitmessage - 比特信 + + Waiting for their encryption key. Will request it again soon. + 正在等待他们的加密密钥,我们会在稍后再次请求。 - - Identities - 身份标识 + + Message sent. Waiting for acknowledgement. Sent at %1 + 消息已经发送. 正在等待回执. 发送于 %1 - - New Identity - 新身份标识 - - - - Search - 搜索 - - - - All - 全部 - - - - To - - - - - From - 来自 - - - - Subject - 标题 - - - - Message - 消息 - - - - Received - 接收时间 - - - - Messages - 信息 - - - - Address book - 地址簿 - - - - Address - 地址 - - - - Add Contact - 增加联系人 - - - - Fetch Namecoin ID - 接收Namecoin ID - - - - Subject: - 标题: - - - - From: - 来自: - - - - To: - 至: - - - - Send ordinary Message - 发送普通信息 - - - - Send Message to your Subscribers - 发送信息给您的订户 - - - - TTL: - TTL: - - - - Subscriptions - 订阅 - - - - Add new Subscription - 添加新的订阅 - - - - Chans - Chans - - - - Add Chan - 添加 Chans - - - - File - 文件 - - - - Settings - 设置 - - - - Help - 帮助 - - - - Import keys - 导入密钥 - - - - Manage keys - 管理密钥 - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Contact support - 联系支持 - - - - About - 关于 - - - - Regenerate deterministic addresses - 重新生成静态地址 - - - - Delete all trashed messages - 彻底删除全部回收站中的消息 - - - - Join / Create chan - 加入或创建一个频道 - - - - All accounts - 所有帐户 - - - - Zoom level %1% - 缩放级别%1% - - - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - 错误: 您不能在同一地址添加到列表中两次. 也许您可重命名现有之一. - - - - Add new entry - 添加新条目 - - - - Display the %1 recent broadcast(s) from this address. - 显示从这个地址%1的最近广播 - - - - New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest - PyBitmessage的新版本可用: %1. 从https://github.com/Bitmessage/PyBitmessage/releases/latest下载 - - - - Waiting for PoW to finish... %1% - 等待PoW完成...%1% - - - - Shutting down Pybitmessage... %1% - 关闭Pybitmessage ...%1% - - - - Waiting for objects to be sent... %1% - 等待要发送对象...%1% - - - - Saving settings... %1% - 保存设置...%1% - - - - Shutting down core... %1% - 关闭核心...%1% - - - - Stopping notifications... %1% - 停止通知...%1% - - - - Shutdown imminent... %1% - 关闭即将来临...%1% - - - - %n hour(s) - %n 小时 - - - - %n day(s) - %n 天 - - - - Shutting down PyBitmessage... %1% - 关闭PyBitmessage...%1% - - - - Sent - 发送 - - - - Generating one new address - 生成一个新的地址 - - - - Done generating address. Doing work necessary to broadcast it... - 完成生成地址. 做必要的工作, 以播放它... - - - - Generating %1 new addresses. - 生成%1个新地址. - - - - %1 is already in 'Your Identities'. Not adding it again. - %1已经在'您的身份'. 不必重新添加. - - - - Done generating address - 完成生成地址 - - - - SOCKS5 Authentication problem: %1 - - - - - Disk full - 磁盘已满 - - - - Alert: Your disk or data storage volume is full. Bitmessage will now exit. - 警告: 您的磁盘或数据存储量已满. 比特信将立即退出. - - - + Error! Could not find sender address (your address) in the keys.dat file. - 错误! 找不到在keys.dat 件发件人的地址 ( 您的地址). + 错误! 无法在文件 keys.dat 中找到发送者地址(你的地址) + + + + Doing work necessary to send broadcast... + 正在做一些必须的工作来发送广播. + + + + Broadcast sent on %1 + 广播发送于 %1 - Doing work necessary to send broadcast... - 做必要的工作, 以发送广播... - - - - Broadcast sent on %1 - 广播发送%1 - - - Encryption key was requested earlier. - 加密密钥已请求. + 已在更早的时候得到加密密钥. - + Sending a request for the recipient's encryption key. - 发送收件人的加密密钥的请求. + 正在请求收件人的加密密钥. - + Looking up the receiver's public key - 展望接收方的公钥 + 正在查找收件人的公钥. - + Problem: Destination is a mobile device who requests that the destination be included in the message but this is disallowed in your settings. %1 - 问题: 目标是移动电话设备所请求的目的地包括在消息中, 但是这是在你的设置禁止. %1 + 错误: 目标是一个移动设备, 要求不加密目标地址, 但是你的设置中不允许这么做. %1 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. - 做必要的工作, 以发送信息. -这样第2版的地址没有难度. + 正在做一些必要的工作来发送消息. +这里要求的难度不像第2版的地址那样. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %2 - 做必要的工作, 以发送短信. -接收者的要求难度: %1与%2 + 正在做一些必要的工作来发送消息. +接收者要求的难度为: %1 和 %2 - - Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. %3 - 问题: 由接收者(%1%2)要求的工作量比您愿意做的工作量來得更困难. %3 + + Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. + 错误: 收件人要求的做工量(%1 和 %2)大于我们的最大接受做工量. - + Problem: You are trying to send a message to yourself or a chan but your encryption key could not be found in the keys.dat file. Could not encrypt message. %1 - 问题: 您正在尝试将信息发送给自己或频道, 但您的加密密钥无法在keys.dat文件中找到. 无法加密信息. %1 + 错误: 你正在尝试发送消息到你自身或者一个频道, 但是你的加密密钥无法在文件keys.dat中找到. 无法加密消息. %1 - + Doing work necessary to send message. - 做必要的工作, 以发送信息. + 正在做一些必要的工作来发送消息. + + + + Message sent. Sent on %1 + 消息已经发送. 发送于 %1 Message sent. Waiting for acknowledgement. Sent on %1 - 信息发送. 等待确认. 已发送%1 + 消息已经发送. 正在等待回执. 发送于 %1 - + Doing work necessary to request encryption key. - 做必要的工作以要求加密密钥. + 正在做一些必要的工作来请求加密密钥. - - Broadcasting the public key request. This program will auto-retry if they are offline. - 广播公钥请求. 这个程序将自动重试, 如果他们处于离线状态. + + Broacasting the public key request. This program will auto-retry if they are offline. + 正在广播公钥请求. 如果他们不在线, 这一过程将自动重试. - + Sending public key request. Waiting for reply. Requested at %1 - 发送公钥的请求. 等待回复. 请求在%1 - - - - UPnP port mapping established on port %1 - UPnP端口映射建立在端口%1 - - - - UPnP port mapping removed - UPnP端口映射被删除 - - - - Mark all messages as read - 标记全部信息为已读 - - - - Are you sure you would like to mark all messages read? - 确定将所有信息标记为已读吗? - - - - Doing work necessary to send broadcast. - 持续进行必要的工作,以发送广播。 - - - - Proof of work pending - 待传输内容的校验 - - - - %n object(s) pending proof of work - %n 待传输内容校验任务 - - - - %n object(s) waiting to be distributed - %n 任务等待分配 - - - - Wait until these tasks finish? - 等待所有任务执行完? - - - - Problem communicating with proxy: %1. Please check your network settings. - 与代理通信故障率:%1。请检查你的网络连接。 - - - - SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. - SOCK5认证错误:%1。请检查你的SOCK5设置。 - - - - The time on your computer, %1, may be wrong. Please verify your settings. - 你电脑上时间有误:%1。请检查你的设置。 - - - - The name %1 was not found. - 名字%1未找到。 - - - - The namecoin query failed (%1) - 域名币查询失败(%1) - - - - The namecoin query failed. - 域名币查询失败。 - - - - The name %1 has no valid JSON data. - 名字%1没有有效地JSON数据。 - - - - The name %1 has no associated Bitmessage address. - 名字%1没有关联比特信地址。 - - - - Success! Namecoind version %1 running. - 成功!域名币系统%1运行中。 - - - - Success! NMControll is up and running. - 成功!域名币控制上线运行! - - - - Couldn't understand NMControl. - 不能理解 NMControl。 - - - - Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - 你的GPU(s)不能够正确计算,关闭OpenGL。请报告给开发者。 - - - - Set notification sound... - 设置通知提示音... - - - - - Welcome to easy and secure Bitmessage - * send messages to other people - * send broadcast messages like twitter or - * discuss in chan(nel)s with other people - - -欢迎使用简便安全的比特信 -*发送信息给其他人 -*像推特那样发送广播信息 -*在频道(s)里和其他人讨论 - - - - not recommended for chans - 频道内不建议的内容 - - - - Quiet Mode - 静默模式 - - - - Problems connecting? Try enabling UPnP in the Network Settings - 连接问题?请尝试在网络设置里打开UPnP - - - - You are trying to send an email instead of a bitmessage. This requires registering with a gateway. Attempt to register? - 您将要尝试经由 Bitmessage 发送一封电子邮件。该操作需要在一个网关上注册。尝试注册? - - - - Error: Bitmessage addresses start with BM- Please check the recipient address %1 - 错误:Bitmessage地址是以BM-开头的,请检查收信地址%1. - - - - Error: The recipient address %1 is not typed or copied correctly. Please check it. - 错误:收信地址%1未填写或复制错误。请检查。 - - - - Error: The recipient address %1 contains invalid characters. Please check it. - 错误:收信地址%1还有非法字符。请检查。 - - - - Error: The version of the recipient address %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - 错误:收信地址%1版本太高。要么你需要更新你的软件,要么对方需要降级 。 - - - - Error: Some data encoded in the recipient address %1 is too short. There might be something wrong with the software of your acquaintance. - 错误:收信地址%1编码数据太短。可能对方使用的软件有问题。 - - - - Error: Some data encoded in the recipient address %1 is too long. There might be something wrong with the software of your acquaintance. - 错误: - - - - Error: Some data encoded in the recipient address %1 is malformed. There might be something wrong with the software of your acquaintance. - 错误:收信地址%1编码数据太长。可能对方使用的软件有问题。 - - - - Error: Something is wrong with the recipient address %1. - 错误:收信地址%1有问题。 - - - - Error: %1 - 错误:%1 - - - - From %1 - 来自 %1 - - - - Synchronisation pending - 待同步 - - - - Bitmessage hasn't synchronised with the network, %n object(s) to be downloaded. If you quit now, it may cause delivery delays. Wait until the synchronisation finishes? - Bitmessage还没有与网络同步,%n 件任务需要下载。如果你现在退出软件,可能会造成传输延时。是否等同步完成? - - - - Not connected - 未连接成功。 - - - - Bitmessage isn't connected to the network. If you quit now, it may cause delivery delays. Wait until connected and the synchronisation finishes? - Bitmessage未连接到网络。如果现在退出软件,可能会造成传输延时。是否等待同步完成? - - - - Waiting for network connection... - 等待网络连接…… - - - - Waiting for finishing synchronisation... - 等待同步完成…… - - - - You have already set a notification sound for this address book entry. Do you really want to overwrite it? - - - - - MessageView - - - Follow external link - 查看外部链接 - - - - The link "%1" will open in a browser. It may be a security risk, it could de-anonymise you or download malicious data. Are you sure? - 此链接“%1”将在浏览器中打开。可能会有安全风险,可能会暴露你或下载恶意数据。确定吗? - - - - HTML detected, click here to display - 检测到HTML,单击此处来显示内容。 - - - - Click here to disable HTML - 单击此处以禁止HTML。 - - - - MsgDecode - - - The message has an unknown encoding. -Perhaps you should upgrade Bitmessage. - 这些消息使用了未知编码方式。 -你可能需要更新Bitmessage软件。 - - - - Unknown encoding - 未知编码 + 正在发送公钥请求. 等待回应中. 请求于 %1 @@ -1681,8 +1192,8 @@ The 'Random Number' option is selected by default but deterministic ad - Enter an address above. - 输入上述地址. + CheckBox + 显示在添加之前2天内的广播 @@ -1716,78 +1227,35 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog - + About 关于 - + PyBitmessage PyBitmessage - + version ? 版本 ? - + + <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>版权所有 © 2012-2013 Jonathan Warren<br/>版权所有 © 2013 比特信开发者</p></body></html> + + + <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> <html><head/><body><p>以 MIT/X11 软件授权发布; 详情参见 <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> - + This is Beta software. 本软件处于Beta阶段。 - - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - - - <html><head/><body><p>Copyright &copy; 2012-2016 Jonathan Warren<br/>Copyright &copy; 2013-2016 The Bitmessage Developers</p></body></html> - <html><head/><body><p>版权:2012-2016 Jonathan Warren<br/>版权: 2013-2016 The Bitmessage Developers</p></body></html> - - - - blacklist - - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - 使用黑名单 (允许所有传入的信息除了那些在黑名单) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - 使用白名单 (阻止所有传入的消息除了那些在白名单) - - - - Add new entry - 添加新条目 - - - - Name or Label - 名称或标签 - - - - Address - 地址 - - - - Blacklist - 黑名单 - - - - Whitelist - 白名单 - connectDialog @@ -1821,8 +1289,8 @@ The 'Random Number' option is selected by default but deterministic ad - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> + <a href="http://Bitmessage.org/wiki/PyBitmessage_Help">http://Bitmessage.org/wiki/PyBitmessage_Help</a> @@ -1858,279 +1326,47 @@ The 'Random Number' option is selected by default but deterministic ad 您有和其他节点的连接且您的防火墙已经正确配置。 - - networkstatus - - - Total connections: - 总连接: - - - - Since startup: - 自启动: - - - - Processed 0 person-to-person messages. - 处理0人对人的信息. - - - - Processed 0 public keys. - 处理0公钥。 - - - - Processed 0 broadcasts. - 处理0广播. - - - - Inventory lookups per second: 0 - 每秒库存查询: 0 - - - - Objects to be synced: - 对象 已同步: - - - - Stream # - 数据流 # - - - - Connections - - - - - Since startup on %1 - 自从%1启动 - - - - Down: %1/s Total: %2 - 下: %1/秒 总计: %2 - - - - Up: %1/s Total: %2 - 上: %1/秒 总计: %2 - - - - Total Connections: %1 - 总的连接数: %1 - - - - Inventory lookups per second: %1 - 每秒库存查询: %1 - - - - Up: 0 kB/s - 上载: 0 kB /秒 - - - - Down: 0 kB/s - 下载: 0 kB /秒 - - - - Network Status - 网络状态 - - - - byte(s) - 字节 - - - - Object(s) to be synced: %n - 要同步的对象: %n - - - - Processed %n person-to-person message(s). - 处理%n人对人的信息. - - - - Processed %n broadcast message(s). - 处理%n广播信息. - - - - Processed %n public key(s). - 处理%n公钥. - - - - Peer - 节点 - - - - IP address or hostname - IP地址或主机名 - - - - Rating - 评分 - - - - PyBitmessage tracks the success rate of connection attempts to individual nodes. The rating ranges from -1 to 1 and affects the likelihood of selecting the node in the future - PyBitmessage 跟踪连接尝试到各个节点的成功率。评分范围从 -1 到 1 ,这会影响到未来选择节点的可能性。 - - - - User agent - 用户代理 - - - - Peer's self-reported software - 节点自我报告的软件 - - - - TLS - TLS - - - - Connection encryption - 连接加密 - - - - List of streams negotiated between you and the peer - 您和节点之间已协商的流列表 - - newChanDialog Dialog - + 对话框 Create a new chan - + 创建一个新的频道 Join a chan - + 加入一个频道 Create a chan - + 创建一个频道 <html><head/><body><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly then the chan will be secure and private. If you and someone else both create a chan with the same chan name then it is currently very likely that they will be the same chan.</p></body></html> - + <html><head/><body><p>为您的频道起一个名字。如果您选择了一个足够难的名字(比如一个唯一而且强度很高的密码)而您的朋友们也没有公开这个名字,那么频道将会是私密并安全的。目前看来,如果有人和您使用相同的名字创建频道,创建的频道将和您的相同。</p></body></html> Chan name: - + 频道名称: <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - + <html><head/><body><p>一个频道存在于一群共有同一个解密密钥的人之间。频道的密钥和比特信地址生成自可读的文字或密码(频道的名字)。要给一个频道中的每一个人发送消息,仅仅需要发送一个普通的点对点消息到频道的地址。</p><p>频道是实验性的且不受到监管。</p></body></html> Chan bitmessage address: - - - - - Create or join a chan - 创建或加入一个频道 - - - - <html><head/><body><p>A chan exists when a group of people share the same decryption keys. The keys and bitmessage address used by a chan are generated from a human-friendly word or phrase (the chan name). To send a message to everyone in the chan, send a message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p><p>Enter a name for your chan. If you choose a sufficiently complex chan name (like a strong and unique passphrase) and none of your friends share it publicly, then the chan will be secure and private. However if you and someone else both create a chan with the same chan name, the same chan will be shared.</p></body></html> - <html><head/><body><p>当一群人共享同一样的加密钥匙时会创建一个频道。使用一个词组来命名密钥和bitmessage地址。发送信息到频道地址就可以发送消息给每个成员。</p><p>频道功能为实验性功能,也不稳定。</p><p>为你的频道命名。如果你选择使用一个十分复杂的名字命令并且你的朋友不会公开它,那这个频道就是安全和私密的。然而如果你和其他人都创建了一个同样命名的频道,那么相同名字的频道将会被共享。</p></body></html> - - - - Chan passphrase/name: - - - - - Optional, for advanced usage - 可选,适用于高级应用 - - - - Chan address - 频道地址 - - - - Please input chan name/passphrase: - 请输入频道名字: - - - - newchandialog - - - Successfully created / joined chan %1 - 成功创建或加入频道%1 - - - - Chan creation / joining failed - 频道创建或加入失败 - - - - Chan creation / joining cancelled - 频道创建或加入已取消 - - - - proofofwork - - - C PoW module built successfully. - C PoW模块编译成功。 - - - - Failed to build C PoW module. Please build it manually. - 无法编译C PoW模块。请手动编译。 - - - - C PoW module unavailable. Please build it. - C PoW模块不可用。请编译它。 - - - - qrcodeDialog - - - QR-code - 二维码 + 频道的地址: @@ -2189,310 +1425,310 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings 设置 - + Start Bitmessage on user login 在用户登录时启动比特信 - - Tray - 任务栏 - - - + Start Bitmessage in the tray (don't show main window) 启动比特信到托盘 (不要显示主窗口) - + Minimize to tray 最小化到托盘 - - Close to tray - 关闭任务栏 - - - + Show notification when message received 在收到消息时提示 - + Run in Portable Mode 以便携方式运行 - + In Portable Mode, messages and config files are stored in the same directory as the program rather than the normal application-data folder. This makes it convenient to run Bitmessage from a USB thumb drive. 在便携模式下, 消息和配置文件和程序保存在同一个目录而不是通常的程序数据文件夹。 这使在U盘中允许比特信很方便。 - + Willingly include unencrypted destination address when sending to a mobile device + It seems that this func is still at dev when translation was done. 愿意在发送到手机时使用不加密的目标地址 - + Use Identicons 用户身份 - - Reply below Quote - 回复 引述如下 - - - + Interface Language 界面语言 - + System Settings system 系统设置 - + + English + en + + + + + Esperanto + eo + + + + + Français + fr + + + + + Deutsch + de + + + + + Españl + es + + + + + русский язык + ru + + + + + Norsk + no + + + + + Pirate English + en_pirate + + + + + Other (set in keys.dat) + other + 其他(在keys.dat中设置) + + + User Interface 用户界面 - + Listening port 监听端口 - + Listen for connections on port: 监听连接于端口: - - UPnP: - UPnP: - - - - Bandwidth limit - 带宽限制 - - - - Maximum download rate (kB/s): [0: unlimited] - 最大下载速率(kB/秒): [0: 无限制] - - - - Maximum upload rate (kB/s): [0: unlimited] - 最大上传速度 (kB/秒): [0: 无限制] - - - + Proxy server / Tor 代理服务器 / Tor - + Type: 类型: - + Server hostname: 服务器主机名: - + Port: 端口: - + Authentication 认证 - + Username: 用户名: - + Pass: 密码: - + Listen for incoming connections when using proxy 在使用代理时仍然监听入站连接 - + none - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + Network Settings 网络设置 - + Total difficulty: 总难度: - + The 'Total difficulty' affects the absolute amount of work the sender must complete. Doubling this value doubles the amount of work. “总难度”影响发送者所需要的做工总数。当这个值翻倍时,做工的总数也翻倍。 - + Small message difficulty: 小消息难度: - + When someone sends you a message, their computer must first complete some work. The difficulty of this work, by default, is 1. You may raise this default for new addresses you create by changing the values here. Any new addresses you create will require senders to meet the higher difficulty. There is one exception: if you add a friend or acquaintance to your address book, Bitmessage will automatically notify them when you next send a message that they need only complete the minimum amount of work: difficulty 1. 当一个人向您发送消息的时候, 他们的电脑必须先做工。这个难度的默认值是1,您可以在创建新的地址前提高这个值。任何新创建的地址都会要求更高的做工量。这里有一个例外,当您将您的朋友添加到地址本的时候,比特信将自动提示他们,当他们下一次向您发送的时候,他们需要的做功量将总是1. - + The 'Small message difficulty' mostly only affects the difficulty of sending small messages. Doubling this value makes it almost twice as difficult to send a small message but doesn't really affect large messages. “小消息困难度”几乎仅影响发送消息。当这个值翻倍时,发小消息时做工的总数也翻倍,但是并不影响大的消息。 - + Demanded difficulty 要求的难度 - + Here you may set the maximum amount of work you are willing to do to send a message to another person. Setting these values to 0 means that any value is acceptable. 你可以在这里设置您所愿意接受的发送消息的最大难度。0代表接受任何难度。 - + Maximum acceptable total difficulty: 最大接受难度: - + Maximum acceptable small message difficulty: 最大接受的小消息难度: - + Max acceptable difficulty 最大可接受难度 - - Hardware GPU acceleration (OpenCL) - - - - + <html><head/><body><p>Bitmessage can utilize a different Bitcoin-based program called Namecoin to make addresses human-friendly. For example, instead of having to tell your friend your long Bitmessage address, you can simply tell him to send a message to <span style=" font-style:italic;">test. </span></p><p>(Getting your own Bitmessage address into Namecoin is still rather difficult).</p><p>Bitmessage can use either namecoind directly or a running nmcontrol instance.</p></body></html> <html><head/><body><p>比特信可以利用基于比特币的Namecoin让地址更加友好。比如除了告诉您的朋友您的长长的比特信地址,您还可以告诉他们发消息给 <span style=" font-style:italic;">test. </span></p><p>把您的地址放入Namecoin还是相当的难的.</p><p>比特信可以不但直接连接到namecoin守护程序或者连接到运行中的nmcontrol实例.</p></body></html> - + Host: 主机名: - + Password: 密码: - + Test 测试 - + Connect to: 连接到: - + Namecoind - Namecoind + - + NMControl - NMControl + - + Namecoin integration Namecoin整合 - + <html><head/><body><p>By default, if you send a message to someone and he is offline for more than two days, Bitmessage will send the message again after an additional two days. This will be continued with exponential backoff forever; messages will be resent after 5, 10, 20 days ect. until the receiver acknowledges them. Here you may change that behavior by having Bitmessage give up after a certain number of days or months.</p><p>Leave these input fields blank for the default behavior. </p></body></html> <html><head/><body><p>您发给他们的消息默认会在网络上保存两天,之后比特信会再重发一次. 重发时间会随指数上升; 消息会在5, 10, 20... 天后重发并以此类推. 直到收到收件人的回执. 你可以在这里改变这一行为,让比特信在尝试一段时间后放弃.</p><p>留空意味着默认行为. </p></body></html> - + Give up after - + and - + days - + months. 月后放弃。 - + Resends Expire 重发超时 - - - Hide connection notifications - 隐藏连接通知 - - - - Maximum outbound connections: [0: none] - 最大外部连接:[0: 无] - - - - Hardware GPU acceleration (OpenCL): - 硬件GPU加速(OpenCL): - - \ No newline at end of file + diff --git a/src/upnp.py b/src/upnp.py index ad72560c..5104ea34 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -1,20 +1,37 @@ # A simple upnp module to forward port for BitMessage # Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port -import httplib -from random import randint import socket -from struct import unpack, pack -import threading -import time -from bmconfigparser import BMConfigParser -from network.connectionpool import BMConnectionPool -from helper_threading import * -import queues -import shared -import state -import tr +import httplib +from shared import config -def createRequestXML(service, action, arguments=None): +routers = [] + +def searchRouter(): + SSDP_ADDR = "239.255.255.250" + SSDP_PORT = 1900 + SSDP_MX = 2 + SSDP_ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1" + + ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \ + "HOST: %s:%d\r\n" % (SSDP_ADDR, SSDP_PORT) + \ + "MAN: \"ssdp:discover\"\r\n" + \ + "MX: %d\r\n" % (SSDP_MX, ) + \ + "ST: %s\r\n" % (SSDP_ST, ) + "\r\n" + + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT)) + routers = [] + sock.settimeout(0.5) + try: + resp,(ip,port) = sock.recvfrom(1000) + while resp: + routers.append(Router(resp, ip)) + resp,(ip,port) = sock.recvfrom(1000) + except:pass + + return routers + +def createRequestXML(service, action, arguments=[]): from xml.dom.minidom import Document doc = Document() @@ -40,12 +57,11 @@ def createRequestXML(service, action, arguments=None): # iterate over arguments, create nodes, create text nodes, # append text nodes to nodes, and finally add the ready product # to argument_list - if arguments is not None: - for k, v in arguments: - tmp_node = doc.createElement(k) - tmp_text_node = doc.createTextNode(v) - tmp_node.appendChild(tmp_text_node) - argument_list.append(tmp_node) + for k, v in arguments: + tmp_node = doc.createElement(k) + tmp_text_node = doc.createTextNode(v) + tmp_node.appendChild(tmp_text_node) + argument_list.append(tmp_node) # append the prepared argument nodes to the function element for arg in argument_list: @@ -72,13 +88,10 @@ class Router: path = "" address = None routerPath = None - extPort = None - def __init__(self, ssdpResponse, address): import urllib2 from xml.dom.minidom import parseString from urlparse import urlparse - from debug import logger self.address = address @@ -89,12 +102,7 @@ class Router: if len(part) == 2: header[part[0].lower()] = part[1] - try: - self.routerPath = urlparse(header['location']) - if not self.routerPath or not hasattr(self.routerPath, "hostname"): - logger.error ("UPnP: no hostname: %s", header['location']) - except KeyError: - logger.error ("UPnP: missing location header") + self.routerPath = urlparse(header['location']) # get the profile xml file and read it into a variable directory = urllib2.urlopen(header['location']).read() @@ -107,15 +115,11 @@ class Router: service_types = dom.getElementsByTagName('serviceType') for service in service_types: - if service.childNodes[0].data.find('WANIPConnection') > 0 or \ - service.childNodes[0].data.find('WANPPPConnection') > 0: + if service.childNodes[0].data.find('WANIPConnection') > 0: self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data - self.upnp_schema = service.childNodes[0].data.split(':')[-2] def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): - from debug import logger - resp = self.soapRequest(self.upnp_schema + ':1', 'AddPortMapping', [ - ('NewRemoteHost', ''), + resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ ('NewExternalPort', str(externalPort)), ('NewProtocol', protocol), ('NewInternalPort', str(internalPort)), @@ -124,29 +128,23 @@ class Router: ('NewPortMappingDescription', str(description)), ('NewLeaseDuration', str(leaseDuration)) ]) - self.extPort = externalPort - logger.info("Successfully established UPnP mapping for %s:%i on external port %i", internalClient, internalPort, externalPort) return resp def DeletePortMapping(self, externalPort, protocol): - from debug import logger - resp = self.soapRequest(self.upnp_schema + ':1', 'DeletePortMapping', [ - ('NewRemoteHost', ''), + resp = self.soapRequest('WANIPConnection:1', 'DeletePortMapping', [ ('NewExternalPort', str(externalPort)), ('NewProtocol', protocol), ]) - logger.info("Removed UPnP mapping on external port %i", externalPort) return resp def GetExternalIPAddress(self): from xml.dom.minidom import parseString - resp = self.soapRequest(self.upnp_schema + ':1', 'GetExternalIPAddress') + resp = self.soapRequest('WANIPConnection:1', 'GetExternalIPAddress') dom = parseString(resp) return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data - def soapRequest(self, service, action, arguments=None): + def soapRequest(self, service, action, arguments=[]): from xml.dom.minidom import parseString - from debug import logger conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) conn.request( 'POST', @@ -157,156 +155,44 @@ class Router: 'Content-Type': 'text/xml' } ) - resp = conn.getresponse() - conn.close() - if resp.status == 500: - respData = resp.read() - try: - dom = parseString(respData) - errinfo = dom.getElementsByTagName('errorDescription') - if len(errinfo) > 0: - logger.error("UPnP error: %s", respData) - raise UPnPError(errinfo[0].childNodes[0].data) - except: - raise UPnPError("Unable to parse SOAP error: %s" %(respData)) + resp = conn.getresponse().read() + dom = parseString(resp) + errinfo = dom.getElementsByTagName('errorDescription') + if len(errinfo) > 0: + raise UPnPError(errinfo[0].childNodes[0].data) return resp -class uPnPThread(threading.Thread, StoppableThread): - SSDP_ADDR = "239.255.255.250" - GOOGLE_DNS = "8.8.8.8" - SSDP_PORT = 1900 - SSDP_MX = 2 - SSDP_ST = "urn:schemas-upnp-org:device:InternetGatewayDevice:1" - def __init__ (self): - threading.Thread.__init__(self, name="uPnPThread") - try: - self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') - except: - self.extPort = None - self.localIP = self.getLocalIP() - self.routers = [] - self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.sock.bind((self.localIP, 0)) - self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) - self.sock.settimeout(5) - self.sendSleep = 60 - self.initStop() - - def run(self): - from debug import logger - - logger.debug("Starting UPnP thread") - logger.debug("Local IP: %s", self.localIP) - lastSent = 0 - - # wait until asyncore binds so that we know the listening port - bound = False - while state.shutdown == 0 and not self._stopped and not bound: - for s in BMConnectionPool().listeningSockets.values(): - if s.is_bound(): - bound = True - if not bound: - time.sleep(1) - - self.localPort = BMConfigParser().getint('bitmessagesettings', 'port') - while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): - if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: - try: - self.sendSearchRouter() - except: - pass - lastSent = time.time() - try: - while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): - resp,(ip,port) = self.sock.recvfrom(1000) - if resp is None: - continue - newRouter = Router(resp, ip) - for router in self.routers: - if router.location == newRouter.location: - break - else: - logger.debug("Found UPnP router at %s", ip) - self.routers.append(newRouter) - self.createPortMapping(newRouter) - queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort)))) - # retry connections so that the submitted port is refreshed - with shared.alreadyAttemptedConnectionsListLock: - shared.alreadyAttemptedConnectionsList.clear() - shared.alreadyAttemptedConnectionsListResetTime = int( - time.time()) - break - except socket.timeout as e: - pass - except: - logger.error("Failure running UPnP router search.", exc_info=True) - for router in self.routers: - if router.extPort is None: - self.createPortMapping(router) - try: - self.sock.shutdown(socket.SHUT_RDWR) - except: - pass - try: - self.sock.close() - except: - pass - deleted = False - for router in self.routers: - if router.extPort is not None: - deleted = True - self.deletePortMapping(router) - shared.extPort = None - if deleted: - queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping removed'))) - logger.debug("UPnP thread done") - - def getLocalIP(self): - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - s.connect((uPnPThread.GOOGLE_DNS, 1)) - return s.getsockname()[0] - - def sendSearchRouter(self): - from debug import logger - ssdpRequest = "M-SEARCH * HTTP/1.1\r\n" + \ - "HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \ - "MAN: \"ssdp:discover\"\r\n" + \ - "MX: %d\r\n" % (uPnPThread.SSDP_MX, ) + \ - "ST: %s\r\n" % (uPnPThread.SSDP_ST, ) + "\r\n" - - try: - logger.debug("Sending UPnP query") - self.sock.sendto(ssdpRequest, (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT)) - except: - logger.exception("UPnP send query failed") - - def createPortMapping(self, router): - from debug import logger - - for i in range(50): - try: - routerIP, = unpack('>I', socket.inet_aton(router.address)) - localIP = self.localIP - if i == 0: - extPort = self.localPort # try same port first - elif i == 1 and self.extPort: - extPort = self.extPort # try external port from last time next - else: - extPort = randint(32767, 65535) - logger.debug("Attempt %i, requesting UPnP mapping for %s:%i on external port %i", i, localIP, self.localPort, extPort) - router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage') - shared.extPort = extPort - self.extPort = extPort - BMConfigParser().set('bitmessagesettings', 'extport', str(extPort)) - BMConfigParser().save() - break - except UPnPError: - logger.debug("UPnP error: ", exc_info=True) - - def deletePortMapping(self, router): - router.DeletePortMapping(router.extPort, 'TCP') +def createPortMapping(): + from struct import unpack, pack + global routers + routers = searchRouter() + localIPs = socket.gethostbyname_ex(socket.gethostname())[2] + for i in range(len(localIPs)): + localIPs[i], = unpack('>I', socket.inet_aton(localIPs[i])) + try: + #add port mapping for each router + for router in routers: + routerIP, = unpack('>I', socket.inet_aton(router.address)) + localIP = None + minDiff = 0xFFFFFFFF + #find nearest localIP as clientIP to specified router + for IP in localIPs: + if IP ^ routerIP < minDiff: + minDiff = IP ^ routerIP + localIP = IP + localIP = socket.inet_ntoa(pack('>I', localIP)) + localPort = config.getint('bitmessagesettings', 'port') + router.AddPortMapping(localPort, localPort, localIP, 'TCP', 'BitMessage') + except UPnPError: + from random import randint + newPort = str(randint(32767, 65535)) + config.set('bitmessagesettings', 'port', newPort) + createPortMapping() +def deletePortMapping(): + localPort = config.getint('bitmessagesettings', 'port') + for router in routers: + router.DeletePortMapping(localPort, 'TCP') diff --git a/src/version.py b/src/version.py deleted file mode 100644 index 076b8c56..00000000 --- a/src/version.py +++ /dev/null @@ -1,2 +0,0 @@ -softwareName = 'PyBitmessage' -softwareVersion = '0.6.3.2'