From cfae964761801b85840f4733c0ba4be4ac7fe05c Mon Sep 17 00:00:00 2001 From: lightrabbit Date: Sat, 22 Aug 2015 16:48:49 +0800 Subject: [PATCH 0001/1102] Add UPnP support. --- src/bitmessagemain.py | 6 +- src/shared.py | 4 +- src/upnp.py | 198 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 src/upnp.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index bf1d74f2..daae1af9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 +#!/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 @@ -44,6 +44,7 @@ from debug import logger # Helper Functions import helper_bootstrap import helper_generic +import upnp def connectToStream(streamNumber): @@ -145,6 +146,9 @@ class Main: # is the application already running? If yes then exit. thisapp = singleton.singleinstance() + import upnp + upnp.createPortMapping() + # get curses flag curses = False if '-c' in sys.argv: diff --git a/src/shared.py b/src/shared.py index d82f00a5..5351947f 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -from __future__ import division +from __future__ import division softwareVersion = '0.4.4' verbose = 1 @@ -370,6 +370,8 @@ def doCleanShutdown(): '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: diff --git a/src/upnp.py b/src/upnp.py new file mode 100644 index 00000000..5104ea34 --- /dev/null +++ b/src/upnp.py @@ -0,0 +1,198 @@ +# A simple upnp module to forward port for BitMessage +# Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port +import socket +import httplib +from shared import config + +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() + + # create the envelope element and set its attributes + envelope = doc.createElementNS('', 's:Envelope') + envelope.setAttribute('xmlns:s', 'http://schemas.xmlsoap.org/soap/envelope/') + envelope.setAttribute('s:encodingStyle', 'http://schemas.xmlsoap.org/soap/encoding/') + + # create the body element + body = doc.createElementNS('', 's:Body') + + # create the function element and set its attribute + fn = doc.createElementNS('', 'u:%s' % action) + fn.setAttribute('xmlns:u', 'urn:schemas-upnp-org:service:%s' % service) + + # setup the argument element names and values + # using a list of tuples to preserve order + + # container for created nodes + argument_list = [] + + # iterate over arguments, create nodes, create text nodes, + # append text nodes to nodes, and finally add the ready product + # to argument_list + 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: + fn.appendChild(arg) + + # append function element to the body element + body.appendChild(fn) + + # append body element to envelope element + envelope.appendChild(body) + + # append envelope element to document, making it the root element + doc.appendChild(envelope) + + # our tree is ready, conver it to a string + return doc.toxml() + +class UPnPError(Exception): + def __init__(self, message): + self.message + +class Router: + name = "" + path = "" + address = None + routerPath = None + def __init__(self, ssdpResponse, address): + import urllib2 + from xml.dom.minidom import parseString + from urlparse import urlparse + + self.address = address + + row = ssdpResponse.split('\r\n') + header = {} + for i in range(1, len(row)): + part = row[i].split(': ') + if len(part) == 2: + header[part[0].lower()] = part[1] + + self.routerPath = urlparse(header['location']) + + # get the profile xml file and read it into a variable + directory = urllib2.urlopen(header['location']).read() + + # create a DOM object that represents the `directory` document + dom = parseString(directory) + + self.name = dom.getElementsByTagName('friendlyName')[0].childNodes[0].data + # find all 'serviceType' elements + service_types = dom.getElementsByTagName('serviceType') + + for service in service_types: + if service.childNodes[0].data.find('WANIPConnection') > 0: + self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data + + def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): + resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ + ('NewExternalPort', str(externalPort)), + ('NewProtocol', protocol), + ('NewInternalPort', str(internalPort)), + ('NewInternalClient', internalClient), + ('NewEnabled', str(enabled)), + ('NewPortMappingDescription', str(description)), + ('NewLeaseDuration', str(leaseDuration)) + ]) + return resp + + def DeletePortMapping(self, externalPort, protocol): + resp = self.soapRequest('WANIPConnection:1', 'DeletePortMapping', [ + ('NewExternalPort', str(externalPort)), + ('NewProtocol', protocol), + ]) + return resp + + def GetExternalIPAddress(self): + from xml.dom.minidom import parseString + resp = self.soapRequest('WANIPConnection:1', 'GetExternalIPAddress') + dom = parseString(resp) + return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data + + def soapRequest(self, service, action, arguments=[]): + from xml.dom.minidom import parseString + conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) + conn.request( + 'POST', + self.path, + createRequestXML(service, action, arguments), + { + 'SOAPAction': '"urn:schemas-upnp-org:service:%s#%s"' % (service, action), + 'Content-Type': 'text/xml' + } + ) + resp = conn.getresponse().read() + dom = parseString(resp) + errinfo = dom.getElementsByTagName('errorDescription') + if len(errinfo) > 0: + raise UPnPError(errinfo[0].childNodes[0].data) + return resp + + +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') -- 2.45.1 From 1796c20887c99c5dd69af87afc730445b1724cf5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 19 Jan 2015 18:39:02 +0100 Subject: [PATCH 0002/1102] Merge OpenCL code and make OpenCL auto-detectable --- src/kernel.cl | 278 +++++++++++++++++++++++++++++++++++++++++++++ src/openclpow.py | 66 +++++++++++ src/proofofwork.py | 12 +- 3 files changed, 354 insertions(+), 2 deletions(-) create mode 100644 src/kernel.cl create mode 100644 src/openclpow.py diff --git a/src/kernel.cl b/src/kernel.cl new file mode 100644 index 00000000..d8db974a --- /dev/null +++ b/src/kernel.cl @@ -0,0 +1,278 @@ +/* +* 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, +}; + + + +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/openclpow.py b/src/openclpow.py new file mode 100644 index 00000000..0876aa79 --- /dev/null +++ b/src/openclpow.py @@ -0,0 +1,66 @@ +import numpy +from struct import pack, unpack +import time +import hashlib +import pyopencl as cl + +hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) +ctx = False +queue = False +program = False + +try: + if (len(cl.get_platforms()) > 0): + ctx = cl.create_some_context() + queue = cl.CommandQueue(ctx) + + f = open('kernel.cl', 'r') + fstr = ''.join(f.readlines()) + program = cl.Program(ctx, fstr).build() +except: + ctx = False + +def has_opencl(): + return (ctx != False) + +def do_opencl_pow(hash, target): + output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) + if (ctx == False): + 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, cl.get_platforms()[0].get_devices()[0]) + + kernel.set_arg(0, hash_buf) + kernel.set_arg(1, dest_buf) + + start = time.time() + startpos = 0 + globamt = worksize*2000 + + while output[0][0] == 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/proofofwork.py b/src/proofofwork.py index 4392bc7e..f05e7eea 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -6,6 +6,7 @@ from struct import unpack, pack import sys from shared import config, frozen import shared +from openclpow import do_opencl_pow #import os def _set_idle(): @@ -70,9 +71,16 @@ def _doFastPoW(target, initialHash): return result[0], result[1] time.sleep(0.2) +def _doGPUPow(target, initialHash): + nonce = 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) + return [trialValue, nonce] + def run(target, initialHash): - target = int(target) - if frozen == "macosx_app" or not frozen: + if has_opencl: + return _doGPUPow(target, initialHash) + elif frozen == "macosx_app" or not frozen: return _doFastPoW(target, initialHash) else: return _doSafePoW(target, initialHash) -- 2.45.1 From 8198e1922ad010da6ea4367da317b35f51c04562 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 19 Jan 2015 18:53:07 +0100 Subject: [PATCH 0003/1102] Added a CLI interface to the daemon from https://github.com/Dokument/PyBitmessage-Daemon/raw/master/daemon.py --- src/bitmessagecli.py | 1710 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1710 insertions(+) create mode 100644 src/bitmessagecli.py diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py new file mode 100644 index 00000000..cfe892b6 --- /dev/null +++ b/src/bitmessagecli.py @@ -0,0 +1,1710 @@ +#!/usr/bin/env python2.7.x +# 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.4.2, by .dok (Version 0.3.0) + + +import ConfigParser +import xmlrpclib +import datetime +import hashlib +import getopt +import imghdr +import ntpath +import json +import time +import sys +import os + +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' + +def safeConfigGetBoolean(section,field): + global keysPath + config = ConfigParser.SafeConfigParser() + config.read(keysPath) + + try: + return config.getboolean(section,field) + except: + return False + +#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(): + global keysName + config = ConfigParser.SafeConfigParser() + + config.add_section('bitmessagesettings') + config.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. + config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat + + with open(keysName, 'wb') as configfile: + config.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 keysPath + global usrPrompt + config = ConfigParser.SafeConfigParser() + config.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": # + config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat + with open(keysPath, 'wb') as configfile: + config.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' + + config.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. + config.set('bitmessagesettings','apienabled','true') + config.set('bitmessagesettings', 'apiport', apiPort) + config.set('bitmessagesettings', 'apiinterface', '127.0.0.1') + config.set('bitmessagesettings', 'apiusername', apiUsr) + config.set('bitmessagesettings', 'apipassword', apiPwd) + config.set('bitmessagesettings', 'daemon', daemon) + with open(keysPath, 'wb') as configfile: + config.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 + + config = ConfigParser.SafeConfigParser() + config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory + + try: + config.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 + config = ConfigParser.SafeConfigParser() + config.read(keysPath) + + try: + config.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 + config.get('bitmessagesettings', 'apiport') + config.get('bitmessagesettings', 'apiinterface') + config.get('bitmessagesettings', 'apiusername') + config.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(safeConfigGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true + + config.read(keysPath)#read again since changes have been made + apiPort = int(config.get('bitmessagesettings', 'apiport')) + apiInterface = config.get('bitmessagesettings', 'apiinterface') + apiUsername = config.get('bitmessagesettings', 'apiusername') + apiPassword = config.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 + config = ConfigParser.SafeConfigParser() + keysPath = 'keys.dat' + + config.read(keysPath)#Read the keys.dat + try: + port = config.get('bitmessagesettings', 'port') + except: + print '\n File not found.\n' + usrPrompt = 0 + main() + + startonlogon = safeConfigGetBoolean('bitmessagesettings', 'startonlogon') + minimizetotray = safeConfigGetBoolean('bitmessagesettings', 'minimizetotray') + showtraynotifications = safeConfigGetBoolean('bitmessagesettings', 'showtraynotifications') + startintray = safeConfigGetBoolean('bitmessagesettings', 'startintray') + defaultnoncetrialsperbyte = config.get('bitmessagesettings', 'defaultnoncetrialsperbyte') + defaultpayloadlengthextrabytes = config.get('bitmessagesettings', 'defaultpayloadlengthextrabytes') + daemon = safeConfigGetBoolean('bitmessagesettings', 'daemon') + + socksproxytype = config.get('bitmessagesettings', 'socksproxytype') + sockshostname = config.get('bitmessagesettings', 'sockshostname') + socksport = config.get('bitmessagesettings', 'socksport') + socksauthentication = safeConfigGetBoolean('bitmessagesettings', 'socksauthentication') + socksusername = config.get('bitmessagesettings', 'socksusername') + sockspassword = config.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.") + config.set('bitmessagesettings', 'port', str(uInput)) + elif uInput == "startonlogon": + print ' Current status: ' + str(startonlogon) + uInput = userInput("Enter the new status.") + config.set('bitmessagesettings', 'startonlogon', str(uInput)) + elif uInput == "minimizetotray": + print ' Current status: ' + str(minimizetotray) + uInput = userInput("Enter the new status.") + config.set('bitmessagesettings', 'minimizetotray', str(uInput)) + elif uInput == "showtraynotifications": + print ' Current status: ' + str(showtraynotifications) + uInput = userInput("Enter the new status.") + config.set('bitmessagesettings', 'showtraynotifications', str(uInput)) + elif uInput == "startintray": + print ' Current status: ' + str(startintray) + uInput = userInput("Enter the new status.") + config.set('bitmessagesettings', 'startintray', str(uInput)) + elif uInput == "defaultnoncetrialsperbyte": + print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte + uInput = userInput("Enter the new defaultnoncetrialsperbyte.") + config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) + elif uInput == "defaultpayloadlengthextrabytes": + print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes + uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") + config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) + elif uInput == "daemon": + print ' Current status: ' + str(daemon) + uInput = userInput("Enter the new status.").lower() + config.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.") + config.set('bitmessagesettings', 'socksproxytype', str(uInput)) + elif uInput == "sockshostname": + print ' Current socks host name: ' + sockshostname + uInput = userInput("Enter the new sockshostname.") + config.set('bitmessagesettings', 'sockshostname', str(uInput)) + elif uInput == "socksport": + print ' Current socks port number: ' + socksport + uInput = userInput("Enter the new socksport.") + config.set('bitmessagesettings', 'socksport', str(uInput)) + elif uInput == "socksauthentication": + print ' Current status: ' + str(socksauthentication) + uInput = userInput("Enter the new status.") + config.set('bitmessagesettings', 'socksauthentication', str(uInput)) + elif uInput == "socksusername": + print ' Current socks username: ' + socksusername + uInput = userInput("Enter the new socksusername.") + config.set('bitmessagesettings', 'socksusername', str(uInput)) + elif uInput == "sockspassword": + print ' Current socks password: ' + sockspassword + uInput = userInput("Enter the new password.") + config.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: + config.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 + + + uInput = userInput("Are you sure, (Y)es or (N)o?").lower() + + 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 = str(jsonAddresses['addresses'][addNum]['label']) + 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 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): + uInput = userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() + + 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): + uInput = userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() + + 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): + global usrPrompt + + 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 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() + userPrompt = 1 + main() + + elif usrInput == "join": + joinChan() + userPrompt = 1 + main() + + elif usrInput == "leave": + leaveChan() + userPrompt = 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' + userPrompt = 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() + + 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.2.6 for BM 0.3.5 |' + 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() -- 2.45.1 From 44414c2e885b7aeb16c76a5e6ce4939d5754c478 Mon Sep 17 00:00:00 2001 From: sbkaf Date: Tue, 3 Mar 2015 18:17:56 +0100 Subject: [PATCH 0004/1102] make interface look more like an e-mail programm, not yet functional --- src/bitmessageqt/__init__.py | 244 +++-- src/bitmessageqt/bitmessageui.py | 684 +++++++------- src/bitmessageqt/bitmessageui.ui | 1520 ++++++++++++++---------------- 3 files changed, 1158 insertions(+), 1290 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1819628b..38087497 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -199,13 +199,11 @@ class MyForm(QtGui.QMainWindow): QtCore.SIGNAL( "triggered()"), self.click_actionRegenerateDeterministicAddresses) - QtCore.QObject.connect(self.ui.actionJoinChan, QtCore.SIGNAL( - "triggered()"), + QtCore.QObject.connect(self.ui.pushButtonAddChanel, QtCore.SIGNAL( + "clicked()"), 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( @@ -216,12 +214,8 @@ class MyForm(QtGui.QMainWindow): "clicked()"), self.click_pushButtonTTL) 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.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( @@ -299,12 +293,14 @@ class MyForm(QtGui.QMainWindow): _translate( "MainWindow", "Special address behavior..."), self.on_action_SpecialAddressBehaviorDialog) + self.ui.tableWidgetYourIdentities.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: self.connect(self.ui.tableWidgetYourIdentities, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuYourIdentities) + self.popMenu = QtGui.QMenu(self) self.popMenu.addAction(self.actionNew) self.popMenu.addSeparator() @@ -407,12 +403,6 @@ class MyForm(QtGui.QMainWindow): 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 ) @@ -500,8 +490,6 @@ class MyForm(QtGui.QMainWindow): 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) @@ -514,7 +502,7 @@ class MyForm(QtGui.QMainWindow): self.init_sent_popup_menu() self.init_blacklist_popup_menu() - # Initialize the user's list of addresses on the 'Your Identities' tab. + # Initialize the user's list of addresses on the 'Your Identities' table. configSections = shared.config.sections() for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': @@ -548,6 +536,26 @@ class MyForm(QtGui.QMainWindow): status, addressVersionNumber, streamNumber, hash = decodeAddress( addressInKeysFile) + # Initialize the user's list of addresses on the 'Received' tab. + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + isEnabled = shared.config.getboolean( + addressInKeysFile, 'enabled') + + if isEnabled and not shared.safeConfigGetBoolean(addressInKeysFile, 'chan') and not shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): + newItem = QtGui.QTreeWidgetItem(self.ui.treeWidgetYourIdentities) + newItem.setIcon(0, avatarize(addressInKeysFile)) + newItem.setText(0, unicode( + shared.config.get(addressInKeysFile, 'label'), 'utf-8)') + + ' (' + addressInKeysFile + ')') + newSubItem = QtGui.QTreeWidgetItem(newItem) + newSubItem.setText(0, _translate("MainWindow", "inbox")) + newSubItem = QtGui.QTreeWidgetItem(newItem) + newSubItem.setText(0, _translate("MainWindow", "sent")) + newSubItem = QtGui.QTreeWidgetItem(newItem) + newSubItem.setText(0, _translate("MainWindow", "trash")) + # Load inbox from messages database file self.loadInbox() @@ -564,10 +572,6 @@ class MyForm(QtGui.QMainWindow): QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL( "returnPressed()"), self.inboxSearchLineEditPressed) - # 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') @@ -582,8 +586,6 @@ class MyForm(QtGui.QMainWindow): "itemChanged(QTableWidgetItem *)"), self.tableWidgetSubscriptionsItemChanged) QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL( "itemSelectionChanged ()"), self.tableWidgetInboxItemClicked) - QtCore.QObject.connect(self.ui.tableWidgetSent, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.tableWidgetSentItemClicked) # Put the colored icon on the status bar # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) @@ -598,8 +600,8 @@ class MyForm(QtGui.QMainWindow): # Set the icon sizes for the identicons identicon_size = 3*7 self.ui.tableWidgetInbox.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.treeWidgetYourIdentities.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)) @@ -671,28 +673,12 @@ class MyForm(QtGui.QMainWindow): 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() + #if nc.test()[0] == 'failed': + #self.ui.pushButtonFetchNamecoinID.hide() except: 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) - shared.config.set('bitmessagesettings', 'ttl', str(TTL)) - shared.writeKeysFile() - - def updateHumanFriendlyTTLDescription(self, TTL): - numberOfHours = int(round(TTL / (60*60))) - if numberOfHours < 48: - 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", "%1 days").arg(numberOfDays)) + #self.ui.pushButtonFetchNamecoinID.hide() + # Show or hide the application window after clicking an item within the # tray icon or, on Windows, the try icon itself. @@ -781,12 +767,12 @@ class MyForm(QtGui.QMainWindow): # Show the program window and select subscriptions tab def appIndicatorSubscribe(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex(4) + self.ui.tabWidget.setCurrentIndex(2) - # Show the program window and select the address book tab - def appIndicatorAddressBook(self): + # Show the program window and select chanels tab + def appIndicatorChanel(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex(5) + self.ui.tabWidget.setCurrentIndex(3) # Load Sent items from database def loadSent(self, where="", what=""): @@ -808,8 +794,8 @@ class MyForm(QtGui.QMainWindow): ORDER BY lastactiontime ''' % (where,) - while self.ui.tableWidgetSent.rowCount() > 0: - self.ui.tableWidgetSent.removeRow(0) + while self.ui.tableWidgetInbox.rowCount() > 0: + self.ui.tableWidgetInbox.removeRow(0) queryreturn = sqlQuery(sqlStatement, what) for row in queryreturn: @@ -843,14 +829,14 @@ class MyForm(QtGui.QMainWindow): if toLabel == '': toLabel = toAddress - self.ui.tableWidgetSent.insertRow(0) + self.ui.tableWidgetInbox.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) + self.ui.tableWidgetInbox.setItem(0, 0, toAddressItem) if fromLabel == '': fromLabel = fromAddress @@ -860,13 +846,13 @@ class MyForm(QtGui.QMainWindow): fromAddressItem.setData(Qt.UserRole, str(fromAddress)) fromAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.tableWidgetSent.setItem(0, 1, fromAddressItem) + self.ui.tableWidgetInbox.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) + self.ui.tableWidgetInbox.setItem(0, 2, subjectItem) if status == 'awaitingpubkey': statusText = _translate( @@ -913,9 +899,9 @@ class MyForm(QtGui.QMainWindow): 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 + self.ui.tableWidgetInbox.setItem(0, 3, newItem) + self.ui.tableWidgetInbox.sortItems(3, Qt.DescendingOrder) + self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent # Load inbox from messages database file def loadInbox(self, where="", what=""): @@ -1065,11 +1051,11 @@ class MyForm(QtGui.QMainWindow): actionSubscribe.triggered.connect(self.appIndicatorSubscribe) m.addAction(actionSubscribe) - # Address book - actionAddressBook = QtGui.QAction(_translate( - "MainWindow", "Address Book"), m, checkable=False) - actionAddressBook.triggered.connect(self.appIndicatorAddressBook) - m.addAction(actionAddressBook) + # Chanels + actionSubscribe = QtGui.QAction(_translate( + "MainWindow", "Chanel"), m, checkable=False) + actionSubscribe.triggered.connect(self.appIndicatorChanel) + m.addAction(actionSubscribe) # separator actionSeparator = QtGui.QAction('', m, checkable=False) @@ -1346,16 +1332,13 @@ class MyForm(QtGui.QMainWindow): else: self.tray.showMessage(title, subtitle, 1, 2000) + # set delete key in inbox def tableWidgetInboxKeyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Delete: 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 shared.appdata == '': @@ -1379,11 +1362,13 @@ class MyForm(QtGui.QMainWindow): 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') + # menu botton 'regenerate deterministic addresses' def click_actionRegenerateDeterministicAddresses(self): self.regenerateAddressesDialogInstance = regenerateAddressesDialog( self) @@ -1409,6 +1394,7 @@ class MyForm(QtGui.QMainWindow): ), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) self.ui.tabWidget.setCurrentIndex(3) + # opens 'join chan' dialog def click_actionJoinChan(self): self.newChanDialogInstance = newChanDialog(self) if self.newChanDialogInstance.exec_(): @@ -1533,7 +1519,6 @@ class MyForm(QtGui.QMainWindow): 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(): @@ -1694,41 +1679,43 @@ class MyForm(QtGui.QMainWindow): cnt, = row return int(cnt) - def updateSentItemStatusByToAddress(self, toAddress, textToDisplay): - for i in range(self.ui.tableWidgetSent.rowCount()): - rowAddress = str(self.ui.tableWidgetSent.item( + def updateSentItemStatusByHash(self, toRipe, textToDisplay): + for i in range(self.ui.tableWidgetInbox.rowCount()): + toAddress = str(self.ui.tableWidgetInbox.item( i, 0).data(Qt.UserRole).toPyObject()) - if toAddress == rowAddress: - self.ui.tableWidgetSent.item(i, 3).setToolTip(textToDisplay) + status, addressVersionNumber, streamNumber, ripe = decodeAddress( + toAddress) + if ripe == toRipe: + self.ui.tableWidgetInbox.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( + self.ui.tableWidgetInbox.item(i, 3).setText( textToDisplay[:newlinePosition]) else: - self.ui.tableWidgetSent.item(i, 3).setText(textToDisplay) + self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) def updateSentItemStatusByAckdata(self, ackdata, textToDisplay): - for i in range(self.ui.tableWidgetSent.rowCount()): - toAddress = str(self.ui.tableWidgetSent.item( + for i in range(self.ui.tableWidgetInbox.rowCount()): + toAddress = str(self.ui.tableWidgetInbox.item( i, 0).data(Qt.UserRole).toPyObject()) - tableAckdata = self.ui.tableWidgetSent.item( + tableAckdata = self.ui.tableWidgetInbox.item( i, 3).data(Qt.UserRole).toPyObject() status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if ackdata == tableAckdata: - self.ui.tableWidgetSent.item(i, 3).setToolTip(textToDisplay) + self.ui.tableWidgetInbox.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( + self.ui.tableWidgetInbox.item(i, 3).setText( textToDisplay[:newlinePosition]) else: - self.ui.tableWidgetSent.item(i, 3).setText(textToDisplay) + self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing for i in range(self.ui.tableWidgetInbox.rowCount()): @@ -1809,22 +1796,22 @@ class MyForm(QtGui.QMainWindow): i, 0).setTextColor(QApplication.palette().text().color()) def rerenderSentFromLabels(self): - for i in range(self.ui.tableWidgetSent.rowCount()): - fromAddress = str(self.ui.tableWidgetSent.item( + for i in range(self.ui.tableWidgetInbox.rowCount()): + fromAddress = str(self.ui.tableWidgetInbox.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( + self.ui.tableWidgetInbox.item( i, 1).setText(unicode(fromLabel, 'utf-8')) - self.ui.tableWidgetSent.item( + self.ui.tableWidgetInbox.item( i, 1).setIcon(avatarize(fromAddress)) def rerenderSentToLabels(self): - for i in range(self.ui.tableWidgetSent.rowCount()): - addressToLookup = str(self.ui.tableWidgetSent.item( + for i in range(self.ui.tableWidgetInbox.rowCount()): + addressToLookup = str(self.ui.tableWidgetInbox.item( i, 0).data(Qt.UserRole).toPyObject()) toLabel = '' queryreturn = sqlQuery( @@ -1839,7 +1826,7 @@ class MyForm(QtGui.QMainWindow): toLabel = shared.config.get(addressToLookup, 'label') if toLabel == '': toLabel = addressToLookup - self.ui.tableWidgetSent.item( + self.ui.tableWidgetInbox.item( i, 0).setText(unicode(toLabel, 'utf-8')) def rerenderAddressBook(self): @@ -1906,7 +1893,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f def click_pushButtonSend(self): 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()) @@ -2008,12 +1994,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.setText('') self.ui.tabWidget.setCurrentIndex(2) - self.ui.tableWidgetSent.setCurrentCell(0, 0) + self.ui.tableWidgetInbox.setCurrentCell(0, 0) else: self.statusBar().showMessage(_translate( "MainWindow", "Your \'To\' field is empty.")) @@ -2056,12 +2041,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f shared.workerQueue.put(('sendbroadcast', '')) 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) + self.ui.tableWidgetInbox.setCurrentCell(0, 0) def click_pushButtonLoadFromAddressBook(self): self.ui.tabWidget.setCurrentIndex(5) @@ -2083,11 +2067,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.statusBar().showMessage(_translate( "MainWindow", "Fetched address from namecoin identity.")) - 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. @@ -2099,7 +2078,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() - self.ui.labelFrom.setText('') configSections = shared.config.sections() for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': @@ -2111,7 +2089,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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) @@ -2129,8 +2106,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f if fromLabel == '': fromLabel = fromAddress - self.ui.tableWidgetSent.setSortingEnabled(False) - self.ui.tableWidgetSent.insertRow(0) + self.ui.tableWidgetInbox.setSortingEnabled(False) + self.ui.tableWidgetInbox.insertRow(0) if toLabel == '': newItem = QtGui.QTableWidgetItem(unicode(toAddress, 'utf-8')) newItem.setToolTip(unicode(toAddress, 'utf-8')) @@ -2139,7 +2116,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setToolTip(unicode(toLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(toAddress)) newItem.setIcon(avatarize(toAddress)) - self.ui.tableWidgetSent.setItem(0, 0, newItem) + self.ui.tableWidgetInbox.setItem(0, 0, newItem) if fromLabel == '': newItem = QtGui.QTableWidgetItem(unicode(fromAddress, 'utf-8')) newItem.setToolTip(unicode(fromAddress, 'utf-8')) @@ -2148,11 +2125,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setToolTip(unicode(fromLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setIcon(avatarize(fromAddress)) - self.ui.tableWidgetSent.setItem(0, 1, newItem) + 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. - self.ui.tableWidgetSent.setItem(0, 2, newItem) + self.ui.tableWidgetInbox.setItem(0, 2, newItem) # newItem = QtGui.QTableWidgetItem('Doing work necessary to send # broadcast...'+ # l10n.formatTimestamp()) @@ -2160,9 +2137,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.tableWidgetInbox.setItem(0, 3, newItem) self.ui.textEditSentMessage.setPlainText(unicode(message, 'utf-8)')) - self.ui.tableWidgetSent.setSortingEnabled(True) + self.ui.tableWidgetInbox.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): subject = shared.fixPotentiallyInvalidUTF8Data(subject) @@ -2773,17 +2750,15 @@ more work your computer must do to send the message. A Time-To-Live of four or f for row in queryreturn: messageAtCurrentInboxRow, = row if toAddressAtCurrentInboxRow == self.str_broadcast_subscribers: - self.ui.labelFrom.setText('') + #TODO what does this if?.. + a = a 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), 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."), QMessageBox.Ok) - self.ui.labelFrom.setText('') else: - self.ui.labelFrom.setText(toAddressAtCurrentInboxRow) self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) self.ui.lineEditTo.setText(str(fromAddressAtCurrentInboxRow)) @@ -2887,23 +2862,23 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Send item on the Sent tab to trash def on_action_SentTrash(self): - while self.ui.tableWidgetSent.selectedIndexes() != []: - currentRow = self.ui.tableWidgetSent.selectedIndexes()[0].row() - ackdataToTrash = str(self.ui.tableWidgetSent.item( + while self.ui.tableWidgetInbox.selectedIndexes() != []: + currentRow = self.ui.tableWidgetInbox.selectedIndexes()[0].row() + ackdataToTrash = str(self.ui.tableWidgetInbox.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.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: - self.ui.tableWidgetSent.selectRow(currentRow) + self.ui.tableWidgetInbox.selectRow(currentRow) else: - self.ui.tableWidgetSent.selectRow(currentRow - 1) + self.ui.tableWidgetInbox.selectRow(currentRow - 1) def on_action_ForceSend(self): - currentRow = self.ui.tableWidgetSent.currentRow() - addressAtCurrentRow = str(self.ui.tableWidgetSent.item( + currentRow = self.ui.tableWidgetInbox.currentRow() + addressAtCurrentRow = str(self.ui.tableWidgetInbox.item( currentRow, 0).data(Qt.UserRole).toPyObject()) toRipe = decodeAddress(addressAtCurrentRow)[3] sqlExecute( @@ -2917,8 +2892,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f shared.workerQueue.put(('sendmessage', '')) def on_action_SentClipboard(self): - currentRow = self.ui.tableWidgetSent.currentRow() - addressAtCurrentRow = str(self.ui.tableWidgetSent.item( + currentRow = self.ui.tableWidgetInbox.currentRow() + addressAtCurrentRow = str(self.ui.tableWidgetInbox.item( currentRow, 0).data(Qt.UserRole).toPyObject()) clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) @@ -3256,15 +3231,15 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Check to see if this item is toodifficult and display an additional # menu option (Force Send) if it is. - currentRow = self.ui.tableWidgetSent.currentRow() - ackData = str(self.ui.tableWidgetSent.item( + currentRow = self.ui.tableWidgetInbox.currentRow() + ackData = str(self.ui.tableWidgetInbox.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() @@ -3273,13 +3248,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.textEditInboxMessage.setPlainText(QString("")) self.loadInbox(searchOption, searchKeyword) - 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): currentRow = self.ui.tableWidgetInbox.currentRow() if currentRow >= 0: @@ -3327,10 +3295,10 @@ more work your computer must do to send the message. A Time-To-Live of four or f sqlExecute('''update inbox set read=1 WHERE msgid=?''', inventoryHash) self.changedInboxUnread() - def tableWidgetSentItemClicked(self): - currentRow = self.ui.tableWidgetSent.currentRow() + def tableWidgetInboxItemClicked(self): + currentRow = self.ui.tableWidgetInbox.currentRow() if currentRow >= 0: - ackdata = str(self.ui.tableWidgetSent.item( + ackdata = str(self.ui.tableWidgetInbox.item( currentRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from sent where ackdata=?''', ackdata) @@ -3655,8 +3623,8 @@ class settingsDialog(QtGui.QDialog): responseStatus = response[0] responseText = response[1] self.ui.labelNamecoinTestResult.setText(responseText) - if responseStatus== 'success': - self.parent.ui.pushButtonFetchNamecoinID.show() + #if responseStatus== 'success': + #self.parent.ui.pushButtonFetchNamecoinID.show() class SpecialAddressBehaviorDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index e35b30cd..f3a600f6 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'bitmessageui.ui' +# Form implementation generated from reading ui file 'bmail.ui' # -# Created: Sun Mar 08 22:07:43 2015 -# by: PyQt4 UI code generator 4.10.3 +# Created: Sun Mar 1 23:18:09 2015 +# by: PyQt4 UI code generator 4.10.4 # # WARNING! All changes made in this file will be lost! @@ -33,9 +33,8 @@ class Ui_MainWindow(object): MainWindow.setTabShape(QtGui.QTabWidget.Rounded) self.centralwidget = QtGui.QWidget(MainWindow) self.centralwidget.setObjectName(_fromUtf8("centralwidget")) - self.gridLayout = QtGui.QGridLayout(self.centralwidget) - self.gridLayout.setMargin(0) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.gridLayout_10 = QtGui.QGridLayout(self.centralwidget) + self.gridLayout_10.setObjectName(_fromUtf8("gridLayout_10")) self.tabWidget = QtGui.QTabWidget(self.centralwidget) sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -52,27 +51,34 @@ class Ui_MainWindow(object): self.tabWidget.setObjectName(_fromUtf8("tabWidget")) self.inbox = QtGui.QWidget() self.inbox.setObjectName(_fromUtf8("inbox")) - self.verticalLayout_2 = QtGui.QVBoxLayout(self.inbox) - self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) + self.gridLayout = QtGui.QGridLayout(self.inbox) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.horizontalLayout_3 = QtGui.QHBoxLayout() + self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3")) + self.verticalLayout_12 = QtGui.QVBoxLayout() + self.verticalLayout_12.setObjectName(_fromUtf8("verticalLayout_12")) + self.treeWidgetYourIdentities = QtGui.QTreeWidget(self.inbox) + self.treeWidgetYourIdentities.setMaximumSize(QtCore.QSize(200, 16777215)) + self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities")) + 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.verticalLayout_12.addWidget(self.treeWidgetYourIdentities) + self.pushButtonNewAddress = QtGui.QPushButton(self.inbox) + self.pushButtonNewAddress.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) + self.verticalLayout_12.addWidget(self.pushButtonNewAddress) + self.horizontalLayout_3.addLayout(self.verticalLayout_12) + self.verticalLayout_11 = QtGui.QVBoxLayout() + self.verticalLayout_11.setObjectName(_fromUtf8("verticalLayout_11")) 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.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.verticalLayout_11.addLayout(self.horizontalLayoutSearch) + self.tableWidgetInbox = QtGui.QTableWidget(self.inbox) self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInbox.setAlternatingRowColors(True) self.tableWidgetInbox.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) @@ -97,191 +103,212 @@ class Ui_MainWindow(object): self.tableWidgetInbox.horizontalHeader().setStretchLastSection(True) self.tableWidgetInbox.verticalHeader().setVisible(False) self.tableWidgetInbox.verticalHeader().setDefaultSectionSize(26) - self.textEditInboxMessage = QtGui.QTextEdit(self.splitter) + self.verticalLayout_11.addWidget(self.tableWidgetInbox) + self.textEditInboxMessage = QtGui.QTextEdit(self.inbox) self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessage.setReadOnly(True) self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage")) - 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.verticalLayout_11.addWidget(self.textEditInboxMessage) + self.horizontalLayout_3.addLayout(self.verticalLayout_11) + self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) + 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.send = QtGui.QWidget() self.send.setObjectName(_fromUtf8("send")) - self.gridLayout_2 = QtGui.QGridLayout(self.send) + self.gridLayout_11 = QtGui.QGridLayout(self.send) + self.gridLayout_11.setObjectName(_fromUtf8("gridLayout_11")) + self.horizontalLayout = QtGui.QHBoxLayout() + self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) + self.verticalLayout_2 = QtGui.QVBoxLayout() + self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) + self.tableWidgetAddressBook = QtGui.QTableWidget(self.send) + self.tableWidgetAddressBook.setMaximumSize(QtCore.QSize(200, 16777215)) + 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() + 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.verticalLayout_2.addWidget(self.tableWidgetAddressBook) + self.pushButtonAddAddressBook = QtGui.QPushButton(self.send) + self.pushButtonAddAddressBook.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) + self.verticalLayout_2.addWidget(self.pushButtonAddAddressBook) + self.horizontalLayout.addLayout(self.verticalLayout_2) + self.tabWidget_2 = QtGui.QTabWidget(self.send) + self.tabWidget_2.setObjectName(_fromUtf8("tabWidget_2")) + self.tab = QtGui.QWidget() + self.tab.setObjectName(_fromUtf8("tab")) + self.gridLayout_8 = QtGui.QGridLayout(self.tab) + self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) + self.verticalLayout = QtGui.QVBoxLayout() + self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) + self.gridLayout_2 = QtGui.QGridLayout() self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) - 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, 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 = QtGui.QComboBox(self.tab) self.comboBoxSendFrom.setMinimumSize(QtCore.QSize(300, 0)) self.comboBoxSendFrom.setObjectName(_fromUtf8("comboBoxSendFrom")) - 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.gridLayout_2.addWidget(self.comboBoxSendFrom, 0, 1, 1, 1) + self.label = QtGui.QLabel(self.tab) 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.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) - palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.SolidPattern) - palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush) - self.pushButtonTTL.setPalette(palette) - font = QtGui.QFont() - font.setUnderline(True) - self.pushButtonTTL.setFont(font) - self.pushButtonTTL.setFlat(True) - self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL")) - 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.gridLayout_2.addWidget(self.label, 1, 0, 1, 1) + self.lineEditTo = QtGui.QLineEdit(self.tab) 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.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) + self.label_3 = QtGui.QLabel(self.tab) + self.label_3.setObjectName(_fromUtf8("label_3")) + self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1) + self.label_2 = QtGui.QLabel(self.tab) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout_2.addWidget(self.label_2, 0, 0, 1, 1) + self.lineEditSubject = QtGui.QLineEdit(self.tab) 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) + self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1) + self.verticalLayout.addLayout(self.gridLayout_2) + self.textEditMessage = QtGui.QTextEdit(self.tab) + self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) + self.verticalLayout.addWidget(self.textEditMessage) + self.pushButtonSend = QtGui.QPushButton(self.tab) + self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) + self.verticalLayout.addWidget(self.pushButtonSend) + self.gridLayout_8.addLayout(self.verticalLayout, 0, 0, 1, 1) + self.tabWidget_2.addTab(self.tab, _fromUtf8("")) + self.tab_2 = QtGui.QWidget() + self.tab_2.setObjectName(_fromUtf8("tab_2")) + self.gridLayout_9 = QtGui.QGridLayout(self.tab_2) + self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) + self.verticalLayout_5 = QtGui.QVBoxLayout() + self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) + self.gridLayout_5 = QtGui.QGridLayout() + self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) + self.label_8 = QtGui.QLabel(self.tab_2) + self.label_8.setObjectName(_fromUtf8("label_8")) + self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1) + self.lineEditSubject_2 = QtGui.QLineEdit(self.tab_2) + self.lineEditSubject_2.setText(_fromUtf8("")) + self.lineEditSubject_2.setObjectName(_fromUtf8("lineEditSubject_2")) + self.gridLayout_5.addWidget(self.lineEditSubject_2, 1, 1, 1, 1) + self.label_7 = QtGui.QLabel(self.tab_2) + self.label_7.setObjectName(_fromUtf8("label_7")) + self.gridLayout_5.addWidget(self.label_7, 1, 0, 1, 1) + self.comboBoxSendFrom_2 = QtGui.QComboBox(self.tab_2) + self.comboBoxSendFrom_2.setMinimumSize(QtCore.QSize(300, 0)) + self.comboBoxSendFrom_2.setObjectName(_fromUtf8("comboBoxSendFrom_2")) + self.gridLayout_5.addWidget(self.comboBoxSendFrom_2, 0, 1, 1, 1) + self.verticalLayout_5.addLayout(self.gridLayout_5) + self.textEditMessage_2 = QtGui.QTextEdit(self.tab_2) + self.textEditMessage_2.setObjectName(_fromUtf8("textEditMessage_2")) + self.verticalLayout_5.addWidget(self.textEditMessage_2) + self.pushButtonSend_3 = QtGui.QPushButton(self.tab_2) + self.pushButtonSend_3.setObjectName(_fromUtf8("pushButtonSend_3")) + self.verticalLayout_5.addWidget(self.pushButtonSend_3) + self.gridLayout_9.addLayout(self.verticalLayout_5, 0, 0, 1, 1) + self.tabWidget_2.addTab(self.tab_2, _fromUtf8("")) + self.horizontalLayout.addWidget(self.tabWidget_2) + self.gridLayout_11.addLayout(self.horizontalLayout, 0, 0, 1, 1) + 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("")) + self.subscriptions = QtGui.QWidget() + self.subscriptions.setObjectName(_fromUtf8("subscriptions")) + self.gridLayout_4 = QtGui.QGridLayout(self.subscriptions) + self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.verticalLayout_3 = QtGui.QVBoxLayout() + self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) + self.tableWidgetSubscriptions = QtGui.QTableWidget(self.subscriptions) + self.tableWidgetSubscriptions.setMaximumSize(QtCore.QSize(200, 16777215)) + 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.tableWidgetSent.setHorizontalHeaderItem(0, item) + icon5 = QtGui.QIcon() + icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + item.setIcon(icon5) + self.tableWidgetSubscriptions.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() - self.tableWidgetSent.setHorizontalHeaderItem(1, item) + self.tableWidgetSubscriptions.setHorizontalHeaderItem(1, item) + self.tableWidgetSubscriptions.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetSubscriptions.horizontalHeader().setDefaultSectionSize(200) + self.tableWidgetSubscriptions.horizontalHeader().setHighlightSections(False) + self.tableWidgetSubscriptions.horizontalHeader().setSortIndicatorShown(False) + self.tableWidgetSubscriptions.horizontalHeader().setStretchLastSection(True) + self.tableWidgetSubscriptions.verticalHeader().setVisible(False) + self.verticalLayout_3.addWidget(self.tableWidgetSubscriptions) + self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) + self.pushButtonAddSubscription.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) + self.verticalLayout_3.addWidget(self.pushButtonAddSubscription) + self.horizontalLayout_2.addLayout(self.verticalLayout_3) + self.verticalLayout_4 = QtGui.QVBoxLayout() + self.verticalLayout_4.setObjectName(_fromUtf8("verticalLayout_4")) + self.inboxSearchLineSubscriptions = QtGui.QLineEdit(self.subscriptions) + self.inboxSearchLineSubscriptions.setObjectName(_fromUtf8("inboxSearchLineSubscriptions")) + self.verticalLayout_4.addWidget(self.inboxSearchLineSubscriptions) + self.tableWidgetInboxSubscriptions = QtGui.QTableWidget(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) item = QtGui.QTableWidgetItem() - self.tableWidgetSent.setHorizontalHeaderItem(2, item) + self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(0, 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.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(1, item) + item = QtGui.QTableWidgetItem() + self.tableWidgetInboxSubscriptions.setHorizontalHeaderItem(2, 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.verticalLayout_4.addWidget(self.tableWidgetInboxSubscriptions) + self.textEditInboxSubscriptions = QtGui.QTextEdit(self.subscriptions) + self.textEditInboxSubscriptions.setBaseSize(QtCore.QSize(0, 500)) + self.textEditInboxSubscriptions.setReadOnly(True) + self.textEditInboxSubscriptions.setObjectName(_fromUtf8("textEditInboxSubscriptions")) + self.verticalLayout_4.addWidget(self.textEditInboxSubscriptions) + self.horizontalLayout_2.addLayout(self.verticalLayout_4) + self.gridLayout_4.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) + 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.tab_3 = QtGui.QWidget() + self.tab_3.setObjectName(_fromUtf8("tab_3")) + self.gridLayout_3 = QtGui.QGridLayout(self.tab_3) 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.horizontalLayout_4 = QtGui.QHBoxLayout() + self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) + self.verticalLayout_17 = QtGui.QVBoxLayout() + self.verticalLayout_17.setObjectName(_fromUtf8("verticalLayout_17")) + self.tableWidgetYourIdentities = QtGui.QTableWidget(self.tab_3) + self.tableWidgetYourIdentities.setMaximumSize(QtCore.QSize(200, 16777215)) self.tableWidgetYourIdentities.setFrameShadow(QtGui.QFrame.Sunken) self.tableWidgetYourIdentities.setLineWidth(1) self.tableWidgetYourIdentities.setAlternatingRowColors(True) @@ -294,13 +321,14 @@ class Ui_MainWindow(object): font = QtGui.QFont() font.setKerning(True) item.setFont(font) + item.setIcon(icon1) 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().setDefaultSectionSize(200) self.tableWidgetYourIdentities.horizontalHeader().setMinimumSectionSize(52) self.tableWidgetYourIdentities.horizontalHeader().setSortIndicatorShown(True) self.tableWidgetYourIdentities.horizontalHeader().setStretchLastSection(True) @@ -308,77 +336,57 @@ class Ui_MainWindow(object): 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/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_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.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) + self.verticalLayout_17.addWidget(self.tableWidgetYourIdentities) + self.pushButtonAddChanel = QtGui.QPushButton(self.tab_3) + self.pushButtonAddChanel.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonAddChanel.setObjectName(_fromUtf8("pushButtonAddChanel")) + self.verticalLayout_17.addWidget(self.pushButtonAddChanel) + self.horizontalLayout_4.addLayout(self.verticalLayout_17) + self.verticalLayout_13 = QtGui.QVBoxLayout() + self.verticalLayout_13.setObjectName(_fromUtf8("verticalLayout_13")) + self.horizontalLayoutSearch_2 = QtGui.QHBoxLayout() + self.horizontalLayoutSearch_2.setContentsMargins(-1, 0, -1, -1) + self.horizontalLayoutSearch_2.setObjectName(_fromUtf8("horizontalLayoutSearch_2")) + self.inboxSearchLineEdit_2 = QtGui.QLineEdit(self.tab_3) + self.inboxSearchLineEdit_2.setObjectName(_fromUtf8("inboxSearchLineEdit_2")) + self.horizontalLayoutSearch_2.addWidget(self.inboxSearchLineEdit_2) + self.verticalLayout_13.addLayout(self.horizontalLayoutSearch_2) + self.tableWidgetInbox_2 = QtGui.QTableWidget(self.tab_3) + self.tableWidgetInbox_2.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.tableWidgetInbox_2.setAlternatingRowColors(True) + self.tableWidgetInbox_2.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + self.tableWidgetInbox_2.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.tableWidgetInbox_2.setWordWrap(False) + self.tableWidgetInbox_2.setObjectName(_fromUtf8("tableWidgetInbox_2")) + self.tableWidgetInbox_2.setColumnCount(4) + self.tableWidgetInbox_2.setRowCount(0) item = QtGui.QTableWidgetItem() - self.tableWidgetSubscriptions.setHorizontalHeaderItem(0, item) + self.tableWidgetInbox_2.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() - 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) + self.tableWidgetInbox_2.setHorizontalHeaderItem(1, item) item = QtGui.QTableWidgetItem() - self.tableWidgetAddressBook.setHorizontalHeaderItem(0, item) + self.tableWidgetInbox_2.setHorizontalHeaderItem(2, item) item = QtGui.QTableWidgetItem() - 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/addressbook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.addressbook, icon6, _fromUtf8("")) + self.tableWidgetInbox_2.setHorizontalHeaderItem(3, item) + self.tableWidgetInbox_2.horizontalHeader().setCascadingSectionResizes(True) + self.tableWidgetInbox_2.horizontalHeader().setDefaultSectionSize(200) + self.tableWidgetInbox_2.horizontalHeader().setHighlightSections(False) + self.tableWidgetInbox_2.horizontalHeader().setMinimumSectionSize(27) + self.tableWidgetInbox_2.horizontalHeader().setSortIndicatorShown(False) + self.tableWidgetInbox_2.horizontalHeader().setStretchLastSection(True) + self.tableWidgetInbox_2.verticalHeader().setVisible(False) + self.tableWidgetInbox_2.verticalHeader().setDefaultSectionSize(26) + self.verticalLayout_13.addWidget(self.tableWidgetInbox_2) + self.textEditInboxMessage_2 = QtGui.QTextEdit(self.tab_3) + self.textEditInboxMessage_2.setBaseSize(QtCore.QSize(0, 500)) + self.textEditInboxMessage_2.setReadOnly(True) + self.textEditInboxMessage_2.setObjectName(_fromUtf8("textEditInboxMessage_2")) + self.verticalLayout_13.addWidget(self.textEditInboxMessage_2) + self.horizontalLayout_4.addLayout(self.verticalLayout_13) + self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.tab_3, icon7, _fromUtf8("")) self.blackwhitelist = QtGui.QWidget() self.blackwhitelist.setObjectName(_fromUtf8("blackwhitelist")) self.gridLayout_6 = QtGui.QGridLayout(self.blackwhitelist) @@ -393,8 +401,8 @@ class Ui_MainWindow(object): 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) + spacerItem = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) + self.gridLayout_6.addItem(spacerItem, 2, 1, 1, 1) self.tableWidgetBlacklist = QtGui.QTableWidget(self.blackwhitelist) self.tableWidgetBlacklist.setAlternatingRowColors(True) self.tableWidgetBlacklist.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) @@ -413,17 +421,17 @@ class Ui_MainWindow(object): 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/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.blackwhitelist, icon7, _fromUtf8("")) + icon8 = QtGui.QIcon() + icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.blackwhitelist, icon8, _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/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.pushButtonStatusIcon.setIcon(icon8) + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pushButtonStatusIcon.setIcon(icon9) self.pushButtonStatusIcon.setFlat(True) self.pushButtonStatusIcon.setObjectName(_fromUtf8("pushButtonStatusIcon")) self.tableWidgetConnectionCount = QtGui.QTableWidget(self.networkstatus) @@ -479,13 +487,13 @@ class Ui_MainWindow(object): 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) + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.networkstatus, icon10, _fromUtf8("")) + self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 885, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 885, 27)) self.menubar.setObjectName(_fromUtf8("menubar")) self.menuFile = QtGui.QMenu(self.menubar) self.menuFile.setObjectName(_fromUtf8("menuFile")) @@ -537,7 +545,6 @@ class Ui_MainWindow(object): self.menuFile.addAction(self.actionManageKeys) self.menuFile.addAction(self.actionDeleteAllTrashedMessages) self.menuFile.addAction(self.actionRegenerateDeterministicAddresses) - self.menuFile.addAction(self.actionJoinChan) self.menuFile.addAction(self.actionExit) self.menuSettings.addAction(self.actionSettings) self.menuHelp.addAction(self.actionHelp) @@ -548,29 +555,16 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) 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) + self.tabWidget_2.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) - MainWindow.setTabOrder(self.tabWidget, self.tableWidgetInbox) MainWindow.setTabOrder(self.tableWidgetInbox, self.textEditInboxMessage) - MainWindow.setTabOrder(self.textEditInboxMessage, self.radioButtonSpecific) - MainWindow.setTabOrder(self.radioButtonSpecific, self.radioButtonBroadcast) - MainWindow.setTabOrder(self.radioButtonBroadcast, self.comboBoxSendFrom) + MainWindow.setTabOrder(self.textEditInboxMessage, self.comboBoxSendFrom) MainWindow.setTabOrder(self.comboBoxSendFrom, self.lineEditTo) - MainWindow.setTabOrder(self.lineEditTo, self.pushButtonLoadFromAddressBook) - MainWindow.setTabOrder(self.pushButtonLoadFromAddressBook, self.lineEditSubject) + MainWindow.setTabOrder(self.lineEditTo, self.lineEditSubject) MainWindow.setTabOrder(self.lineEditSubject, self.textEditMessage) 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.pushButtonSend, self.pushButtonAddSubscription) + MainWindow.setTabOrder(self.pushButtonAddSubscription, self.radioButtonBlacklist) MainWindow.setTabOrder(self.radioButtonBlacklist, self.radioButtonWhitelist) MainWindow.setTabOrder(self.radioButtonWhitelist, self.pushButtonAddBlacklist) MainWindow.setTabOrder(self.pushButtonAddBlacklist, self.tableWidgetBlacklist) @@ -578,13 +572,10 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.tableWidgetConnectionCount, self.pushButtonStatusIcon) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) + MainWindow.setWindowTitle(_translate("MainWindow", "B-Mail", None)) + self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) + self.pushButtonNewAddress.setText(_translate("MainWindow", "New Indentitiy", None)) self.inboxSearchLineEdit.setPlaceholderText(_translate("MainWindow", "Search", 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)) @@ -594,66 +585,69 @@ 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", "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.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Received", None)) + self.tableWidgetAddressBook.setSortingEnabled(True) + item = self.tableWidgetAddressBook.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Name", None)) + item = self.tableWidgetAddressBook.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Address", None)) + self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add Contact", 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_3.setText(_translate("MainWindow", "Subject:", 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)) +"\n" +"


", None)) + self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) + self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab), _translate("MainWindow", "Send ordinary Message", None)) + self.label_8.setText(_translate("MainWindow", "From:", None)) + self.label_7.setText(_translate("MainWindow", "Subject:", None)) + self.textEditMessage_2.setHtml(_translate("MainWindow", "\n" +"\n" +"


", None)) + self.pushButtonSend_3.setText(_translate("MainWindow", "Send", None)) + self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_2), _translate("MainWindow", "Send Message to your Subscribers", 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) + self.tableWidgetSubscriptions.setSortingEnabled(True) + item = self.tableWidgetSubscriptions.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "Name", None)) + item = self.tableWidgetSubscriptions.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "Address", None)) + self.pushButtonAddSubscription.setText(_translate("MainWindow", "Add new Subscription", None)) + self.inboxSearchLineSubscriptions.setPlaceholderText(_translate("MainWindow", "Search", None)) + self.tableWidgetInboxSubscriptions.setSortingEnabled(True) + item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "To", None)) - item = self.tableWidgetSent.horizontalHeaderItem(1) + item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "From", None)) - item = self.tableWidgetSent.horizontalHeaderItem(2) + item = self.tableWidgetInboxSubscriptions.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)) + item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3) + item.setText(_translate("MainWindow", "Received", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) self.tableWidgetYourIdentities.setSortingEnabled(True) item = self.tableWidgetYourIdentities.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Label (not shown to anyone)", None)) + item.setText(_translate("MainWindow", "Name", 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", "Name or Label", None)) - item = self.tableWidgetAddressBook.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.addressbook), _translate("MainWindow", "Address Book", None)) + self.pushButtonAddChanel.setText(_translate("MainWindow", "Add Chanel", None)) + self.inboxSearchLineEdit_2.setPlaceholderText(_translate("MainWindow", "Search", None)) + self.tableWidgetInbox_2.setSortingEnabled(True) + item = self.tableWidgetInbox_2.horizontalHeaderItem(0) + item.setText(_translate("MainWindow", "To", None)) + item = self.tableWidgetInbox_2.horizontalHeaderItem(1) + item.setText(_translate("MainWindow", "From", None)) + item = self.tableWidgetInbox_2.horizontalHeaderItem(2) + item.setText(_translate("MainWindow", "Subject", None)) + item = self.tableWidgetInbox_2.horizontalHeaderItem(3) + item.setText(_translate("MainWindow", "Received", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Chanels", 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)) @@ -692,3 +686,13 @@ 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 = QtGui.QMainWindow() + 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 e45cc22d..9340f531 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -21,10 +21,7 @@ QTabWidget::Rounded - - - 0 - + @@ -65,134 +62,147 @@ :/newPrefix/images/inbox.png:/newPrefix/images/inbox.png - Inbox + Received - - - - - 0 - + + + - - - Search - - + + + + + + 200 + 16777215 + + + + + Identities + + + + :/newPrefix/images/identities.png + + + + + + + + + + 200 + 16777215 + + + + New Indentitiy + + + + - + - - All - + + + 0 + + + + + Search + + + + - - To - + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + 200 + + + false + + + 27 + + + false + + + true + + + false + + + 26 + + + + To + + + + + From + + + + + Subject + + + + + Received + + + - - From - + + + + 0 + 500 + + + + true + + - - - 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 - - - - @@ -203,497 +213,225 @@ 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 - - - - Search - - + + + + + + 200 + 16777215 + + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 200 + + + false + + + true + + + false + + + + Name + + + + :/newPrefix/images/addressbook.png + + + + + + Address + + + + + + + + + 200 + 16777215 + + + + Add Contact + + + + - - - - All - - - - - To - - - - - From - - - - - Subject - - - - - Message - - + + + 0 + + + + Send ordinary Message + + + + + + + + + + + 300 + 0 + + + + + + + + To: + + + + + + + + + + Subject: + + + + + + + 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:'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 + + + + + + + + + + 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> + + + + + + + Send + + + + + + + - - - - 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 - - - - @@ -705,161 +443,380 @@ p, li { white-space: pre-wrap; } Subscriptions - - - - 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 - - - + + + + + + + + + 200 + 16777215 + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 200 + + + false + + + false + + + true + + + false + + + + Name + + + + :/newPrefix/images/subscriptions.png + + + + + + Address + + + + + + + + + 200 + 16777215 + + + + Add new Subscription + + + + + + + + + + + Search + + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + 200 + + + false + + + 27 + + + false + + + true + + + false + + + 26 + + + + To + + + + + From + + + + + Subject + + + + + Received + + + + + + + + + 0 + 500 + + + + true + + + + + + - + - :/newPrefix/images/addressbook.png:/newPrefix/images/addressbook.png + :/newPrefix/images/can-icon-16px.png:/newPrefix/images/can-icon-16px.png - Address Book + Chanels - - - - - 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 - - - + + + + + + + + + + 200 + 16777215 + + + + QFrame::Sunken + + + 1 + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + true + + + 200 + + + 52 + + + true + + + true + + + false + + + 26 + + + false + + + false + + + + Name + + + + true + + + + + :/newPrefix/images/identities.png + + + + + + Address + + + + + Stream + + + + + + + + + 200 + 16777215 + + + + Add Chanel + + + + + + + + + + + 0 + + + + + Search + + + + + + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + false + + + true + + + 200 + + + false + + + 27 + + + false + + + true + + + false + + + 26 + + + + To + + + + + From + + + + + Subject + + + + + Received + + + + + + + + + 0 + 500 + + + + true + + + + + + @@ -1182,7 +1139,7 @@ p, li { white-space: pre-wrap; } 0 0 885 - 21 + 27 @@ -1192,7 +1149,6 @@ p, li { white-space: pre-wrap; } - @@ -1319,25 +1275,14 @@ 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 @@ -1348,54 +1293,5 @@ 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 - - - - + -- 2.45.1 From 585873e4f39fefa4be02acc9df692816c75e4679 Mon Sep 17 00:00:00 2001 From: sbkaf Date: Thu, 19 Mar 2015 18:25:50 +0100 Subject: [PATCH 0005/1102] interface --- src/bitmessagemain.py | 2 +- src/bitmessageqt/__init__.py | 122 +++++++++++++++++++++++++++++-- src/bitmessageqt/bitmessageui.py | 6 +- 3 files changed, 121 insertions(+), 9 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index bf1d74f2..73f71cfb 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -197,7 +197,7 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() - connectToStream(1) + #connectToStream(1) singleListenerThread = singleListener() singleListenerThread.setup(selfInitiatedConnections) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 38087497..5c9e459e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -557,10 +557,8 @@ class MyForm(QtGui.QMainWindow): newSubItem.setText(0, _translate("MainWindow", "trash")) # Load inbox from messages database file - self.loadInbox() - - # Load Sent items from database - self.loadSent() + #self.loadInbox() + self.loadMessagelist("BM-2cTxBr9RxjorkjvkgTkD1AgjhUJBwDnVKY"); # Initialize the address book self.rerenderAddressBook() @@ -903,6 +901,120 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetInbox.sortItems(3, Qt.DescendingOrder) self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent + # Load inbox from messages database file + def loadMessagelist(self, account, folder="inbox", 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: + where = "toaddress || fromaddress || subject || message" + + if folder == "sent": + accountaddress = "fromaddress" + else: + accountaddress = "toaddress" + + sqlStatement = ''' + SELECT msgid, toaddress, fromaddress, subject, received, read + FROM inbox WHERE %s=? AND folder=? AND %s LIKE ? + ORDER BY received + ''' % (accounttype, where) + + while self.ui.tableWidgetInbox.rowCount() > 0: + self.ui.tableWidgetInbox.removeRow(0) + + font = QFont() + font.setBold(True) + queryreturn = sqlQuery(sqlStatement, account, folder, what) + for row in queryreturn: + 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 + + 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 + # Load inbox from messages database file def loadInbox(self, where="", what=""): what = "%" + what + "%" @@ -3308,7 +3420,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: message = "Error occurred: could not load message from disk." message = unicode(message, 'utf-8)') - self.ui.textEditSentMessage.setPlainText(message) + self.ui.textEditInboxMessage.setPlainText(message) def tableWidgetYourIdentitiesItemChanged(self): currentRow = self.ui.tableWidgetYourIdentities.currentRow() diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index f3a600f6..b4762f43 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'bmail.ui' +# Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Sun Mar 1 23:18:09 2015 +# Created: Wed Mar 4 00:11:02 2015 # by: PyQt4 UI code generator 4.10.4 # # WARNING! All changes made in this file will be lost! @@ -572,7 +572,7 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.tableWidgetConnectionCount, self.pushButtonStatusIcon) def retranslateUi(self, MainWindow): - MainWindow.setWindowTitle(_translate("MainWindow", "B-Mail", None)) + MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) self.pushButtonNewAddress.setText(_translate("MainWindow", "New Indentitiy", None)) self.inboxSearchLineEdit.setPlaceholderText(_translate("MainWindow", "Search", None)) -- 2.45.1 From 4763fb1238dcfc14e8132e9fed0c69670e90448a Mon Sep 17 00:00:00 2001 From: sbkaf Date: Thu, 19 Mar 2015 18:44:10 +0100 Subject: [PATCH 0006/1102] merge --- src/bitmessageqt/__init__.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5c9e459e..744373d6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -676,7 +676,23 @@ class MyForm(QtGui.QMainWindow): except: 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) + shared.config.set('bitmessagesettings', 'ttl', str(TTL)) + shared.writeKeysFile() + + def updateHumanFriendlyTTLDescription(self, TTL): + numberOfHours = int(round(TTL / (60*60))) + if numberOfHours < 48: + 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", "%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. -- 2.45.1 From f6f68dc9756552d54275e728034531c3c6682657 Mon Sep 17 00:00:00 2001 From: sbkaf Date: Sat, 21 Mar 2015 11:37:08 +0100 Subject: [PATCH 0007/1102] start changing QTreeWiget --- src/bitmessageqt/__init__.py | 726 +++++++++++++++++++++---------- src/bitmessageqt/bitmessageui.py | 274 ++++++------ src/bitmessageqt/bitmessageui.ui | 478 +++++++++++--------- 3 files changed, 921 insertions(+), 557 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 744373d6..b1150553 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -214,8 +214,8 @@ class MyForm(QtGui.QMainWindow): "clicked()"), self.click_pushButtonTTL) QtCore.QObject.connect(self.ui.pushButtonSend, QtCore.SIGNAL( "clicked()"), self.click_pushButtonSend) - #QtCore.QObject.connect(self.ui.pushButtonFetchNamecoinID, QtCore.SIGNAL( - #"clicked()"), self.click_pushButtonFetchNamecoinID) + 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( @@ -271,35 +271,77 @@ class MyForm(QtGui.QMainWindow): 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.ui.treeWidgetYourIdentities.setContextMenuPolicy( + QtCore.Qt.CustomContextMenu) + if connectSignal: + self.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL( + 'customContextMenuRequested(const QPoint&)'), + self.on_context_menuYourIdentities) + + self.popMenuYourIdentities = QtGui.QMenu(self) + self.popMenuYourIdentities.addAction(self.actionNewYourIdentities) + self.popMenuYourIdentities.addSeparator() + self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities) + self.popMenuYourIdentities.addSeparator() + self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities) + self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities) + self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities) + self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) + + def init_chan_popup_menu(self, connectSignal=True): + # Popup menu for the Chanels tab self.ui.addressContextMenuToolbar = QtGui.QToolBar() # Actions self.actionNew = self.ui.addressContextMenuToolbar.addAction(_translate( "MainWindow", "New"), self.on_action_YourIdentitiesNew) self.actionEnable = self.ui.addressContextMenuToolbar.addAction( _translate( - "MainWindow", "Enable"), self.on_action_YourIdentitiesEnable) + "MainWindow", "Enable"), self.on_action_Enable) self.actionDisable = self.ui.addressContextMenuToolbar.addAction( _translate( - "MainWindow", "Disable"), self.on_action_YourIdentitiesDisable) + "MainWindow", "Disable"), self.on_action_Disable) self.actionSetAvatar = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Set avatar..."), - self.on_action_YourIdentitiesSetAvatar) + self.on_action_TreeWidgetSetAvatar) self.actionClipboard = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Copy address to clipboard"), - self.on_action_YourIdentitiesClipboard) + self.on_action_Clipboard) self.actionSpecialAddressBehavior = self.ui.addressContextMenuToolbar.addAction( _translate( "MainWindow", "Special address behavior..."), self.on_action_SpecialAddressBehaviorDialog) - self.ui.tableWidgetYourIdentities.setContextMenuPolicy( + self.ui.treeWidgetChanList.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: - self.connect(self.ui.tableWidgetYourIdentities, QtCore.SIGNAL( + self.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), - self.on_context_menuYourIdentities) + self.on_context_menuChan) self.popMenu = QtGui.QMenu(self) self.popMenu.addAction(self.actionNew) @@ -372,11 +414,11 @@ class MyForm(QtGui.QMainWindow): self.on_action_SubscriptionsDisable) self.actionsubscriptionsSetAvatar = self.ui.subscriptionsContextMenuToolbar.addAction( _translate("MainWindow", "Set avatar..."), - self.on_action_SubscriptionsSetAvatar) - self.ui.tableWidgetSubscriptions.setContextMenuPolicy( + self.on_action_TreeWidgetSetAvatar) + self.ui.treeWidgetSubscriptions.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: - self.connect(self.ui.tableWidgetSubscriptions, QtCore.SIGNAL( + self.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuSubscriptions) self.popMenuSubscriptions = QtGui.QMenu(self) @@ -447,6 +489,58 @@ class MyForm(QtGui.QMainWindow): self.popMenuBlacklist.addAction(self.actionBlacklistDisable) self.popMenuBlacklist.addAction(self.actionBlacklistSetAvatar) + def rerenderTabTree(self, tab): + if tab == 'messages': + treeWidget = self.ui.treeWidgetYourIdentities + folders = ['inbox', 'sent', 'trash'] + elif tab == 'subscriptions': + treeWidget = self.ui.treeWidgetSubscriptions + folders = ['inbox', 'trash'] + elif tab == 'chan': + treeWidget = self.ui.treeWidgetChanList + folders = ['inbox', 'sent', 'trash'] + + treeWidget.clear() + + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile != 'bitmessagesettings': + isEnabled = shared.config.getboolean( + addressInKeysFile, 'enabled') + isChan = shared.safeConfigGetBoolean( + addressInKeysFile, 'chan') + isMaillinglist = shared.safeConfigGetBoolean( + addressInKeysFile, 'mailinglist') + + if tab == 'messages': + if isChan or isMaillinglist: + continue + elif tab == 'subscriptions': + if not isMaillinglist: + continue + elif tab == 'chan': + if not isChan: + continue + + newItem = QtGui.QTreeWidgetItem(treeWidget) + newItem.setIcon(0, avatarize(addressInKeysFile)) + newItem.setText(0, unicode( + shared.config.get(addressInKeysFile, 'label'), 'utf-8)') + + ' (' + addressInKeysFile + ')') + newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"]) + #set text color + if isEnabled: + brush = QtGui.QBrush(QApplication.palette().text().color()) + else: + brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + brush.setStyle(QtCore.Qt.NoBrush) + newItem.setForeground(0, brush) + + for folder in folders: + newSubItem = QtGui.QTreeWidgetItem(newItem) + newSubItem.setText(0, _translate("MainWindow", folder)) + newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder]) + def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_MainWindow() @@ -499,66 +593,61 @@ class MyForm(QtGui.QMainWindow): 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 'Your Identities' table. + # Initialize the user's list of addresses on the 'Chan' tab. + self.rerenderTabTree('chan') + """ + TODO remove 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) + newItem = QtGui.QTableWidgetItem(unicode( + shared.config.get(addressInKeysFile, 'label'), 'utf-8)')) + if not isEnabled: + newItem.setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetChanList.insertRow(0) + newItem.setIcon(avatarize(addressInKeysFile)) + self.ui.tableWidgetChanList.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.tableWidgetChanList.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.tableWidgetChanList.setItem(0, 2, newItem) + if isEnabled: + status, addressVersionNumber, streamNumber, hash = decodeAddress( + addressInKeysFile) + """ - # Initialize the user's list of addresses on the 'Received' tab. - configSections = shared.config.sections() - for addressInKeysFile in configSections: - if addressInKeysFile != 'bitmessagesettings': - isEnabled = shared.config.getboolean( - addressInKeysFile, 'enabled') + # Initialize the user's list of addresses on the 'Messages' tab. + self.rerenderTabTree('messages') - if isEnabled and not shared.safeConfigGetBoolean(addressInKeysFile, 'chan') and not shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): - newItem = QtGui.QTreeWidgetItem(self.ui.treeWidgetYourIdentities) - newItem.setIcon(0, avatarize(addressInKeysFile)) - newItem.setText(0, unicode( - shared.config.get(addressInKeysFile, 'label'), 'utf-8)') - + ' (' + addressInKeysFile + ')') - newSubItem = QtGui.QTreeWidgetItem(newItem) - newSubItem.setText(0, _translate("MainWindow", "inbox")) - newSubItem = QtGui.QTreeWidgetItem(newItem) - newSubItem.setText(0, _translate("MainWindow", "sent")) - newSubItem = QtGui.QTreeWidgetItem(newItem) - newSubItem.setText(0, _translate("MainWindow", "trash")) - - # Load inbox from messages database file - #self.loadInbox() - self.loadMessagelist("BM-2cTxBr9RxjorkjvkgTkD1AgjhUJBwDnVKY"); + # Set welcome message + self.ui.textEditInboxMessage.setText( + """ + Welcome to easy and secure Bitmessage + * send messages like e-mails + * send broadcast messages like twitter or + * discuss in chan(el)s with other people + """ + ) # Initialize the address book self.rerenderAddressBook() @@ -576,14 +665,24 @@ class MyForm(QtGui.QMainWindow): self.ui.radioButtonWhitelist.click() self.rerenderBlackWhiteList() - QtCore.QObject.connect(self.ui.tableWidgetYourIdentities, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.tableWidgetYourIdentitiesItemChanged) + # Initialize addresslists QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( "itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged) - QtCore.QObject.connect(self.ui.tableWidgetSubscriptions, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.tableWidgetSubscriptionsItemChanged) + """ + TODO implement + QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( + "itemChanged(QTableWidgetItem *)"), self.treeWidgetSubscriptionsItemChanged) + QtCore.QObject.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( + "itemChanged(QTableWidgetItem *)"), self.treeWidgetChanListItemChanged) + """ QtCore.QObject.connect(self.ui.tableWidgetInbox, QtCore.SIGNAL( "itemSelectionChanged ()"), self.tableWidgetInboxItemClicked) + QtCore.QObject.connect(self.ui.treeWidgetYourIdentities, QtCore.SIGNAL( + "itemSelectionChanged ()"), self.treeWidgetYourIdentitiesItemClicked) + QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( + "itemSelectionChanged ()"), self.treeWidgetSubscribtionsItemClicked) + QtCore.QObject.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( + "itemSelectionChanged ()"), self.treeWidgetChanListItemClicked) # Put the colored icon on the status bar # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) @@ -598,9 +697,9 @@ class MyForm(QtGui.QMainWindow): # Set the icon sizes for the identicons identicon_size = 3*7 self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.tableWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.treeWidgetChanList.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.tableWidgetSubscriptions.setIconSize(QtCore.QSize(identicon_size, identicon_size)) + self.ui.treeWidgetSubscriptions.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)) @@ -649,6 +748,7 @@ class MyForm(QtGui.QMainWindow): # structures were initialized. self.rerenderComboBoxSendFrom() + self.rerenderComboBoxSendFromBroadcast() # Put the TTL slider in the correct spot TTL = shared.config.getint('bitmessagesettings', 'ttl') @@ -671,11 +771,11 @@ class MyForm(QtGui.QMainWindow): 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() + if nc.test()[0] == 'failed': + self.ui.pushButtonFetchNamecoinID.hide() except: print 'There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button' - #self.ui.pushButtonFetchNamecoinID.hide() + self.ui.pushButtonFetchNamecoinID.hide() def updateTTL(self, sliderPosition): TTL = int(sliderPosition ** 3.199 + 3600) @@ -918,7 +1018,7 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent # Load inbox from messages database file - def loadMessagelist(self, account, folder="inbox", where="", what=""): + def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what=""): what = "%" + what + "%" if where == "To": where = "toaddress" @@ -932,9 +1032,9 @@ class MyForm(QtGui.QMainWindow): where = "toaddress || fromaddress || subject || message" if folder == "sent": - accountaddress = "fromaddress" + accounttype = "fromaddress" else: - accountaddress = "toaddress" + accounttype = "toaddress" sqlStatement = ''' SELECT msgid, toaddress, fromaddress, subject, received, read @@ -942,8 +1042,8 @@ class MyForm(QtGui.QMainWindow): ORDER BY received ''' % (accounttype, where) - while self.ui.tableWidgetInbox.rowCount() > 0: - self.ui.tableWidgetInbox.removeRow(0) + while tableWidget.rowCount() > 0: + tableWidget.removeRow(0) font = QFont() font.setBold(True) @@ -982,7 +1082,7 @@ class MyForm(QtGui.QMainWindow): fromLabel = fromAddress # message row - self.ui.tableWidgetInbox.insertRow(0) + tableWidget.insertRow(0) # to to_item = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) to_item.setToolTip(unicode(toLabel, 'utf-8')) @@ -996,7 +1096,7 @@ class MyForm(QtGui.QMainWindow): 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) + tableWidget.setItem(0, 0, to_item) # from from_item = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) from_item.setToolTip(unicode(fromLabel, 'utf-8')) @@ -1008,7 +1108,7 @@ class MyForm(QtGui.QMainWindow): 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) + tableWidget.setItem(0, 1, from_item) # subject subject_item = QtGui.QTableWidgetItem(unicode(subject, 'utf-8')) subject_item.setToolTip(unicode(subject, 'utf-8')) @@ -1016,7 +1116,7 @@ class MyForm(QtGui.QMainWindow): QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: subject_item.setFont(font) - self.ui.tableWidgetInbox.setItem(0, 2, subject_item) + tableWidget.setItem(0, 2, subject_item) # time received time_item = myTableWidgetItem(l10n.formatTimestamp(received)) time_item.setToolTip(l10n.formatTimestamp(received)) @@ -1026,10 +1126,10 @@ class MyForm(QtGui.QMainWindow): QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: time_item.setFont(font) - self.ui.tableWidgetInbox.setItem(0, 3, time_item) + tableWidget.setItem(0, 3, time_item) - self.ui.tableWidgetInbox.sortItems(3, Qt.DescendingOrder) - self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent + tableWidget.sortItems(3, Qt.DescendingOrder) + tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent # Load inbox from messages database file def loadInbox(self, where="", what=""): @@ -1586,7 +1686,7 @@ class MyForm(QtGui.QMainWindow): 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) @@ -1972,6 +2072,9 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) def rerenderSubscriptions(self): + self.rerenderTabTree('subscriptions') + """ + TODO remove self.ui.tableWidgetSubscriptions.setRowCount(0) queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') for row in queryreturn: @@ -1988,6 +2091,7 @@ class MyForm(QtGui.QMainWindow): 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) @@ -2020,10 +2124,18 @@ more work your computer must do to send the message. A Time-To-Live of four or f def click_pushButtonSend(self): self.statusBar().showMessage('') - toAddresses = str(self.ui.lineEditTo.text()) - subject = str(self.ui.lineEditSubject.text().toUtf8()) - message = str( - self.ui.textEditMessage.document().toPlainText().toUtf8()) + + if self.ui.tabWidgetSend.currentIndex() == 0: + sendMessageToPeople = True + toAddresses = str(self.ui.lineEditTo.text()) + subject = str(self.ui.lineEditSubject.text().toUtf8()) + message = str( + self.ui.textEditMessage.document().toPlainText().toUtf8()) + else: + sendMessageToPeople = False + subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8()) + message = str( + self.ui.textEditMessageBroadcast.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 @@ -2035,7 +2147,13 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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 - if self.ui.radioButtonSpecific.isChecked(): # To send a message to specific people (rather than broadcast) + + if toAddresses: + print toAddresses + print subject + print message + return + if sendMessageToPeople: # To send a message to specific people (rather than broadcast) toAddressesList = [s.strip() for s in toAddresses.replace(',', ';').split(';')] toAddressesList = list(set( @@ -2168,11 +2286,10 @@ more work your computer must do to send the message. A Time-To-Live of four or f shared.workerQueue.put(('sendbroadcast', '')) - self.ui.comboBoxSendFrom.setCurrentIndex(0) - self.ui.lineEditTo.setText('') - self.ui.lineEditSubject.setText('') - self.ui.textEditMessage.setText('') - self.ui.tabWidget.setCurrentIndex(2) + self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) + self.ui.lineEditSubjectBroadcast.setText('') + self.ui.textEditMessageBroadcast.setText('') + self.ui.tabWidget.setCurrentIndex(1) self.ui.tableWidgetInbox.setCurrentCell(0, 0) def click_pushButtonLoadFromAddressBook(self): @@ -2199,10 +2316,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. if shared.safeConfigGetBoolean(str(address), 'chan'): - self.ui.radioButtonSpecific.click() - self.ui.radioButtonBroadcast.setEnabled(False) + self.ui.tabWidgetSend.setCurrentIndex(0) else: - self.ui.radioButtonBroadcast.setEnabled(True) + self.ui.tabWidgetSend.setCurrentIndex(1) def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() @@ -2211,7 +2327,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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: + isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + if isEnabled and not isMaillinglist: self.ui.comboBoxSendFrom.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) self.ui.comboBoxSendFrom.insertItem(0, '', '') @@ -2220,6 +2337,23 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: self.ui.comboBoxSendFrom.setCurrentIndex(0) + def rerenderComboBoxSendFromBroadcast(self): + self.ui.comboBoxSendFromBroadcast.clear() + 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. + isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + if isEnabled and isMaillinglist: + self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( + addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) + 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 @@ -2378,7 +2512,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f #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 UI list + TODO remove self.ui.tableWidgetSubscriptions.setSortingEnabled(False) self.ui.tableWidgetSubscriptions.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) @@ -2388,10 +2524,13 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.rerenderTabTree('subscriptions') def click_pushButtonAddSubscription(self): self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self) @@ -2402,7 +2541,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.")) + self.statusBar().showMessage(_translate("MainWindow", "Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want.")) return label = self.NewSubscriptionDialogInstance.ui.newsubscriptionlabel.text().toUtf8() self.addSubscription(address, label) @@ -2702,9 +2841,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.dialog = SpecialAddressBehaviorDialog(self) # For Modal dialogs if self.dialog.exec_(): - currentRow = self.ui.tableWidgetYourIdentities.currentRow() - addressAtCurrentRow = str( - self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) + addressAtCurrentRow = self.getCurrentAccount() if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): return if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): @@ -2712,20 +2849,50 @@ more work your computer must do to send the message. A Time-To-Live of four or f addressAtCurrentRow), 'mailinglist', 'false') # Set the color to either black or grey if shared.config.getboolean(addressAtCurrentRow, 'enabled'): - self.ui.tableWidgetYourIdentities.item( + self.setCurrentItemColor(QApplication.palette() + .text().color()) + else: + self.setCurrentItemColor(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.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta + shared.writeKeysFile() + self.rerenderInboxToLabels() + + """ + TODO remove + def on_action_ChanSpecialAddressBehaviorDialog(self): + self.dialog = SpecialAddressBehaviorDialog(self) + # For Modal dialogs + if self.dialog.exec_(): + currentRow = self.ui.tableWidgetChanList.currentRow() + addressAtCurrentRow = str( + self.ui.tableWidgetChanList.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.tableWidgetChanList.item( currentRow, 1).setTextColor(QApplication.palette() .text().color()) else: - self.ui.tableWidgetYourIdentities.item( + self.ui.tableWidgetChanList.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 + self.ui.tableWidgetChanList.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta shared.writeKeysFile() self.rerenderInboxToLabels() + """ def click_NewAddressDialog(self): self.dialog = NewAddressDialog(self) @@ -2912,7 +3079,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: self.ui.lineEditSubject.setText( 'Re: ' + self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()) - self.ui.radioButtonSpecific.setChecked(True) + self.ui.tabWidgetSend.setCurrentIndex(0) self.ui.tabWidget.setCurrentIndex(1) def on_action_InboxAddSenderToAddressBook(self): @@ -3088,7 +3255,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.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.")) + self.statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want.")) continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) @@ -3104,6 +3271,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f def on_action_SubscriptionsDelete(self): print 'clicked Delete' + """ + TODO implement currentRow = self.ui.tableWidgetSubscriptions.currentRow() labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( currentRow, 0).text().toUtf8() @@ -3114,15 +3283,21 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetSubscriptions.removeRow(currentRow) self.rerenderInboxFromLabels() shared.reloadBroadcastSendersForWhichImWatching() + """ def on_action_SubscriptionsClipboard(self): + """ + TODO implement currentRow = self.ui.tableWidgetSubscriptions.currentRow() addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( currentRow, 1).text() clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) + """ def on_action_SubscriptionsEnable(self): + """ + TODO implement currentRow = self.ui.tableWidgetSubscriptions.currentRow() labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( currentRow, 0).text().toUtf8() @@ -3136,8 +3311,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetSubscriptions.item( currentRow, 1).setTextColor(QApplication.palette().text().color()) shared.reloadBroadcastSendersForWhichImWatching() + """ def on_action_SubscriptionsDisable(self): + """ + TODO implement currentRow = self.ui.tableWidgetSubscriptions.currentRow() labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( currentRow, 0).text().toUtf8() @@ -3151,10 +3329,14 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetSubscriptions.item( currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) shared.reloadBroadcastSendersForWhichImWatching() + """ def on_context_menuSubscriptions(self, point): + """ + TODO implement self.popMenuSubscriptions.exec_( self.ui.tableWidgetSubscriptions.mapToGlobal(point)) + """ # Group of functions for the Blacklist dialog box def on_action_BlacklistNew(self): @@ -3219,70 +3401,151 @@ more work your computer must do to send the message. A Time-To-Live of four or f sqlExecute( '''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) + 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] + else: + return False + # Group of functions for the Your Identities dialog box + def getCurrentAccount(self): + treeWidget = self.getCurrentTreeWidget() + if treeWidget: + currentItem = treeWidget.currentItem() + if currentItem: + accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() + account = accountFolder[0] + return str(account) + else: + # TODO need debug msg? + return False + + def getCurrentFolder(self): + treeWidget = self.getCurrentTreeWidget() + if treeWidget: + currentItem = treeWidget.currentItem() + if currentItem: + accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() + folder = accountFolder[1] + return str(folder) + else: + # TODO need debug msg? + return False + + def setCurrentItemColor(self, color): + treeWidget = self.getCurrentTreeWidget() + if treeWidget: + brush = QtGui.QBrush() + brush.setStyle(QtCore.Qt.NoBrush) + currentItem = treeWidget.currentItem() + currentItem.setForeground(0, brush) + def on_action_YourIdentitiesNew(self): self.click_NewAddressDialog() - def on_action_YourIdentitiesEnable(self): - currentRow = self.ui.tableWidgetYourIdentities.currentRow() + def on_action_Enable(self): + addressAtCurrentRow = self.getCurrentAccount() + self.enableIdentity(addressAtCurrentRow) + self.setCurrentItemColor(QApplication.palette().text().color()) + + """ + TODO remove + def on_action_ChanEnable(self): + currentRow = self.ui.tableWidgetChanList.currentRow() addressAtCurrentRow = str( - self.ui.tableWidgetYourIdentities.item(currentRow, 1).text()) - shared.config.set(addressAtCurrentRow, 'enabled', 'true') - shared.writeKeysFile() - self.ui.tableWidgetYourIdentities.item( + self.ui.tableWidgetChanList.item(currentRow, 1).text()) + self.ui.tableWidgetChanList.item( currentRow, 0).setTextColor(QApplication.palette().text().color()) - self.ui.tableWidgetYourIdentities.item( + self.ui.tableWidgetChanList.item( currentRow, 1).setTextColor(QApplication.palette().text().color()) - self.ui.tableWidgetYourIdentities.item( + self.ui.tableWidgetChanList.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 + self.ui.tableWidgetChanList.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.ui.tableWidgetChanList.item(currentRow, 1).setTextColor(QtGui.QColor(216, 119, 0)) # orange + self.enableIdentity(addressAtCurrentRow) + """ - 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 + def enableIdentity(self, address): + shared.config.set(address, 'enabled', 'true') shared.writeKeysFile() shared.reloadMyAddressHashes() - def on_action_YourIdentitiesClipboard(self): - currentRow = self.ui.tableWidgetYourIdentities.currentRow() - addressAtCurrentRow = self.ui.tableWidgetYourIdentities.item( - currentRow, 1).text() + def on_action_Disable(self): + address = self.getCurrentAccount() + self.disableIdentity(address) + self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) + + """ + TODO remove + def on_action_ChanDisable(self): + currentRow = self.ui.tableWidgetChanList.currentRow() + addressAtCurrentRow = str( + self.ui.tableWidgetChanList.item(currentRow, 1).text()) + self.ui.tableWidgetChanList.item( + currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetChanList.item( + currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) + self.ui.tableWidgetChanList.item( + currentRow, 2).setTextColor(QtGui.QColor(128, 128, 128)) + self.disableIdentity(address) + """ + + def disableIdentity(self, address): + shared.config.set(str(addressAtCurrentRow), 'enabled', 'false') + shared.writeKeysFile() + shared.reloadMyAddressHashes() + + def on_action_Clipboard(self): + addressAtCurrentRow = self.getCurrentAccount() clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) - def on_action_YourIdentitiesSetAvatar(self): - self.on_action_SetAvatar(self.ui.tableWidgetYourIdentities) - + """ + TODO remove + def on_action_ChanClipboard(self): + currentRow = self.ui.tableWidgetChanList.currentRow() + addressAtCurrentRow = self.ui.tableWidgetChanList.item( + currentRow, 1).text() + clipboard = QtGui.QApplication.clipboard() + clipboard.setText(str(addressAtCurrentRow)) + """ + + #set avatar functions + def on_action_TreeWidgetSetAvatar(self): + addressAtCurrentRow = self.getCurrentAccount() + treeWidget = self.getCurrentTreeWidget() + setToIdenticon = not self.setAvatar(addressAtCurrentRow) + if treeWidget and setToIdenticon: + currentItem = treeWidget.currentItem() + currentItem.setIcon(0, avatarize(addressAtCurrentRow)) + 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(shared.appdata + 'avatars/'): + os.makedirs(shared.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 @@ -3333,21 +3596,28 @@ more work your computer must do to send the message. A Time-To-Live of four or f copied = QtCore.QFile.copy(sourcefile, destination) if not copied: print 'couldn\'t copy :(' - return False # set the icon - thisTableWidget.item( - currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) self.rerenderSubscriptions() self.rerenderComboBoxSendFrom() + self.rerenderComboBoxSendFromBroadcast() self.rerenderInboxFromLabels() self.rerenderInboxToLabels() self.rerenderSentFromLabels() self.rerenderSentToLabels() self.rerenderBlackWhiteList() + # generate identicon + return False + + return True + # TODO make one popMenu def on_context_menuYourIdentities(self, point): + self.popMenuYourIdentities.exec_( + self.ui.treeWidgetYourIdentities.mapToGlobal(point)) + + def on_context_menuChan(self, point): self.popMenu.exec_( - self.ui.tableWidgetYourIdentities.mapToGlobal(point)) + self.ui.treeWidgetChanList.mapToGlobal(point)) def on_context_menuInbox(self, point): self.popMenuInbox.exec_(self.ui.tableWidgetInbox.mapToGlobal(point)) @@ -3376,60 +3646,28 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.textEditInboxMessage.setPlainText(QString("")) self.loadInbox(searchOption, searchKeyword) + def treeWidgetYourIdentitiesItemClicked(self): + currentItem = self.ui.treeWidgetYourIdentities.currentItem() + if currentItem: + accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() + account = accountFolder[0] + folder = accountFolder[1] + self.loadMessagelist(self.ui.tableWidgetInbox, str(account), str(folder)) + + # TODO trees + def treeWidgetSubscribtionsItemClicked(self): + pass + + def treeWidgetChanListItemClicked(self): + pass + def tableWidgetInboxItemClicked(self): 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 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) - - 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) - - 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 tableWidgetInboxItemClicked(self): - currentRow = self.ui.tableWidgetInbox.currentRow() - if currentRow >= 0: - ackdata = str(self.ui.tableWidgetInbox.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) - queryreturn = sqlQuery( - '''select message from sent where ackdata=?''', ackdata) if queryreturn != []: for row in queryreturn: message, = row @@ -3438,20 +3676,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f message = unicode(message, 'utf-8)') self.ui.textEditInboxMessage.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.rerenderInboxFromLabels() - self.rerenderInboxToLabels() - self.rerenderSentFromLabels() - # self.rerenderSentToLabels() - def tableWidgetAddressBookItemChanged(self): currentRow = self.ui.tableWidgetAddressBook.currentRow() if currentRow >= 0: @@ -3463,7 +3687,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.rerenderInboxFromLabels() self.rerenderSentToLabels() - def tableWidgetSubscriptionsItemChanged(self): + """ + TODO implement + def treeWidgetSubscriptionsItemChanged(self): currentRow = self.ui.tableWidgetSubscriptions.currentRow() if currentRow >= 0: addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( @@ -3474,25 +3700,46 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.rerenderInboxFromLabels() self.rerenderSentToLabels() + def treeWidgetChanListItemChanged(self): + currentRow = self.ui.tableWidgetChanList.currentRow() + if currentRow >= 0: + addressAtCurrentRow = self.ui.tableWidgetChanList.item( + currentRow, 1).text() + shared.config.set(str(addressAtCurrentRow), 'label', str( + self.ui.tableWidgetChanList.item(currentRow, 0).text().toUtf8())) + shared.writeKeysFile() + self.rerenderComboBoxSendFrom() + self.rerenderComboBoxSendFromBroadcast() + # self.rerenderInboxFromLabels() + self.rerenderInboxToLabels() + self.rerenderSentFromLabels() + # self.rerenderSentToLabels() + """ + def writeNewAddressToTable(self, label, address, streamNumber): - self.ui.tableWidgetYourIdentities.setSortingEnabled(False) - self.ui.tableWidgetYourIdentities.insertRow(0) + pass + """ + TODO implement + self.ui.tableWidgetChanList.setSortingEnabled(False) + self.ui.tableWidgetChanList.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) newItem.setIcon(avatarize(address)) - self.ui.tableWidgetYourIdentities.setItem( + self.ui.tableWidgetChanList.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) + self.ui.tableWidgetChanList.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.ui.tableWidgetChanList.setItem(0, 2, newItem) + # self.ui.tableWidgetChanList.setSortingEnabled(True) self.rerenderComboBoxSendFrom() + self.rerenderComboBoxSendFromBroadcast() + """ def updateStatusBar(self, data): if data != "": @@ -3751,8 +3998,8 @@ class settingsDialog(QtGui.QDialog): responseStatus = response[0] responseText = response[1] self.ui.labelNamecoinTestResult.setText(responseText) - #if responseStatus== 'success': - #self.parent.ui.pushButtonFetchNamecoinID.show() + if responseStatus== 'success': + self.parent.ui.pushButtonFetchNamecoinID.show() class SpecialAddressBehaviorDialog(QtGui.QDialog): @@ -3762,9 +4009,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): 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()) + addressAtCurrentRow = parent.getCurrentAccount() if not shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): self.ui.radioButtonBehaviorMailingList.click() @@ -3784,6 +4029,38 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) +""" +TODO remove +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.tableWidgetChanList.currentRow() + addressAtCurrentRow = str( + parent.ui.tableWidgetChanList.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): @@ -3888,6 +4165,8 @@ class NewSubscriptionDialog(QtGui.QDialog): class NewAddressDialog(QtGui.QDialog): def __init__(self, parent): + """ + TODO implement QtGui.QWidget.__init__(self, parent) self.ui = Ui_NewAddressDialog() self.ui.setupUi(self) @@ -3895,13 +4174,14 @@ class NewAddressDialog(QtGui.QDialog): 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): + while self.parent.ui.tableWidgetChanList.item(row - 1, 1): self.ui.radioButtonExisting.click() self.ui.comboBoxExisting.addItem( - self.parent.ui.tableWidgetYourIdentities.item(row - 1, 1).text()) + self.parent.ui.tableWidgetChanList.item(row - 1, 1).text()) row += 1 self.ui.groupBoxDeterministic.setHidden(True) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + """ class newChanDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index b4762f43..17ab57ee 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Wed Mar 4 00:11:02 2015 +# Created: Fri Mar 20 19:19:21 2015 # by: PyQt4 UI code generator 4.10.4 # # WARNING! All changes made in this file will be lost! @@ -116,8 +116,8 @@ class Ui_MainWindow(object): self.tabWidget.addTab(self.inbox, icon2, _fromUtf8("")) self.send = QtGui.QWidget() self.send.setObjectName(_fromUtf8("send")) - self.gridLayout_11 = QtGui.QGridLayout(self.send) - self.gridLayout_11.setObjectName(_fromUtf8("gridLayout_11")) + self.gridLayout_7 = QtGui.QGridLayout(self.send) + self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7")) self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) self.verticalLayout_2 = QtGui.QVBoxLayout() @@ -147,27 +147,26 @@ class Ui_MainWindow(object): self.pushButtonAddAddressBook.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) self.verticalLayout_2.addWidget(self.pushButtonAddAddressBook) + self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send) + self.pushButtonFetchNamecoinID.setMaximumSize(QtCore.QSize(200, 16777215)) + font = QtGui.QFont() + font.setPointSize(9) + self.pushButtonFetchNamecoinID.setFont(font) + self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) + self.verticalLayout_2.addWidget(self.pushButtonFetchNamecoinID) self.horizontalLayout.addLayout(self.verticalLayout_2) - self.tabWidget_2 = QtGui.QTabWidget(self.send) - self.tabWidget_2.setObjectName(_fromUtf8("tabWidget_2")) + self.verticalLayout = QtGui.QVBoxLayout() + self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) + self.tabWidgetSend = QtGui.QTabWidget(self.send) + self.tabWidgetSend.setObjectName(_fromUtf8("tabWidgetSend")) self.tab = QtGui.QWidget() self.tab.setObjectName(_fromUtf8("tab")) self.gridLayout_8 = QtGui.QGridLayout(self.tab) self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) - self.verticalLayout = QtGui.QVBoxLayout() - self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) + self.verticalLayout_5 = QtGui.QVBoxLayout() + self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) self.gridLayout_2 = QtGui.QGridLayout() self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) - self.comboBoxSendFrom = QtGui.QComboBox(self.tab) - self.comboBoxSendFrom.setMinimumSize(QtCore.QSize(300, 0)) - self.comboBoxSendFrom.setObjectName(_fromUtf8("comboBoxSendFrom")) - self.gridLayout_2.addWidget(self.comboBoxSendFrom, 0, 1, 1, 1) - self.label = QtGui.QLabel(self.tab) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1) - self.lineEditTo = QtGui.QLineEdit(self.tab) - self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) - self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) self.label_3 = QtGui.QLabel(self.tab) self.label_3.setObjectName(_fromUtf8("label_3")) self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1) @@ -178,48 +177,102 @@ class Ui_MainWindow(object): self.lineEditSubject.setText(_fromUtf8("")) self.lineEditSubject.setObjectName(_fromUtf8("lineEditSubject")) self.gridLayout_2.addWidget(self.lineEditSubject, 2, 1, 1, 1) - self.verticalLayout.addLayout(self.gridLayout_2) + self.label = QtGui.QLabel(self.tab) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout_2.addWidget(self.label, 1, 0, 1, 1) + self.comboBoxSendFrom = QtGui.QComboBox(self.tab) + 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.tab) + self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) + self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) + self.verticalLayout_5.addLayout(self.gridLayout_2) self.textEditMessage = QtGui.QTextEdit(self.tab) self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) - self.verticalLayout.addWidget(self.textEditMessage) - self.pushButtonSend = QtGui.QPushButton(self.tab) - self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) - self.verticalLayout.addWidget(self.pushButtonSend) - self.gridLayout_8.addLayout(self.verticalLayout, 0, 0, 1, 1) - self.tabWidget_2.addTab(self.tab, _fromUtf8("")) + self.verticalLayout_5.addWidget(self.textEditMessage) + self.gridLayout_8.addLayout(self.verticalLayout_5, 0, 0, 1, 1) + self.tabWidgetSend.addTab(self.tab, _fromUtf8("")) self.tab_2 = QtGui.QWidget() self.tab_2.setObjectName(_fromUtf8("tab_2")) self.gridLayout_9 = QtGui.QGridLayout(self.tab_2) self.gridLayout_9.setObjectName(_fromUtf8("gridLayout_9")) - self.verticalLayout_5 = QtGui.QVBoxLayout() - self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) + self.verticalLayout_6 = QtGui.QVBoxLayout() + self.verticalLayout_6.setObjectName(_fromUtf8("verticalLayout_6")) self.gridLayout_5 = QtGui.QGridLayout() self.gridLayout_5.setObjectName(_fromUtf8("gridLayout_5")) self.label_8 = QtGui.QLabel(self.tab_2) self.label_8.setObjectName(_fromUtf8("label_8")) self.gridLayout_5.addWidget(self.label_8, 0, 0, 1, 1) - self.lineEditSubject_2 = QtGui.QLineEdit(self.tab_2) - self.lineEditSubject_2.setText(_fromUtf8("")) - self.lineEditSubject_2.setObjectName(_fromUtf8("lineEditSubject_2")) - self.gridLayout_5.addWidget(self.lineEditSubject_2, 1, 1, 1, 1) + self.lineEditSubjectBroadcast = QtGui.QLineEdit(self.tab_2) + 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.tab_2) self.label_7.setObjectName(_fromUtf8("label_7")) self.gridLayout_5.addWidget(self.label_7, 1, 0, 1, 1) - self.comboBoxSendFrom_2 = QtGui.QComboBox(self.tab_2) - self.comboBoxSendFrom_2.setMinimumSize(QtCore.QSize(300, 0)) - self.comboBoxSendFrom_2.setObjectName(_fromUtf8("comboBoxSendFrom_2")) - self.gridLayout_5.addWidget(self.comboBoxSendFrom_2, 0, 1, 1, 1) - self.verticalLayout_5.addLayout(self.gridLayout_5) - self.textEditMessage_2 = QtGui.QTextEdit(self.tab_2) - self.textEditMessage_2.setObjectName(_fromUtf8("textEditMessage_2")) - self.verticalLayout_5.addWidget(self.textEditMessage_2) - self.pushButtonSend_3 = QtGui.QPushButton(self.tab_2) - self.pushButtonSend_3.setObjectName(_fromUtf8("pushButtonSend_3")) - self.verticalLayout_5.addWidget(self.pushButtonSend_3) - self.gridLayout_9.addLayout(self.verticalLayout_5, 0, 0, 1, 1) - self.tabWidget_2.addTab(self.tab_2, _fromUtf8("")) - self.horizontalLayout.addWidget(self.tabWidget_2) - self.gridLayout_11.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.comboBoxSendFromBroadcast = QtGui.QComboBox(self.tab_2) + self.comboBoxSendFromBroadcast.setMinimumSize(QtCore.QSize(300, 0)) + self.comboBoxSendFromBroadcast.setObjectName(_fromUtf8("comboBoxSendFromBroadcast")) + self.gridLayout_5.addWidget(self.comboBoxSendFromBroadcast, 0, 1, 1, 1) + self.verticalLayout_6.addLayout(self.gridLayout_5) + self.textEditMessageBroadcast = QtGui.QTextEdit(self.tab_2) + self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast")) + self.verticalLayout_6.addWidget(self.textEditMessageBroadcast) + self.gridLayout_9.addLayout(self.verticalLayout_6, 0, 0, 1, 1) + self.tabWidgetSend.addTab(self.tab_2, _fromUtf8("")) + self.verticalLayout.addWidget(self.tabWidgetSend) + self.horizontalLayout_5 = QtGui.QHBoxLayout() + self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5")) + self.pushButtonTTL = QtGui.QPushButton(self.send) + 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) + palette.setBrush(QtGui.QPalette.Active, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Inactive, QtGui.QPalette.ButtonText, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.SolidPattern) + palette.setBrush(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, brush) + self.pushButtonTTL.setPalette(palette) + font = QtGui.QFont() + font.setUnderline(True) + self.pushButtonTTL.setFont(font) + self.pushButtonTTL.setFlat(True) + self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL")) + self.horizontalLayout_5.addWidget(self.pushButtonTTL) + 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.horizontalLayout_5.addWidget(self.horizontalSliderTTL) + 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.horizontalLayout_5.addWidget(self.labelHumanFriendlyTTLDescription) + self.pushButtonSend = QtGui.QPushButton(self.send) + self.pushButtonSend.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) + self.horizontalLayout_5.addWidget(self.pushButtonSend) + self.verticalLayout.addLayout(self.horizontalLayout_5) + self.horizontalLayout.addLayout(self.verticalLayout) + self.gridLayout_7.addLayout(self.horizontalLayout, 0, 0, 1, 1) 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("")) @@ -231,28 +284,16 @@ class Ui_MainWindow(object): self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) self.verticalLayout_3 = QtGui.QVBoxLayout() self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) - self.tableWidgetSubscriptions = QtGui.QTableWidget(self.subscriptions) - self.tableWidgetSubscriptions.setMaximumSize(QtCore.QSize(200, 16777215)) - 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.treeWidgetSubscriptions = QtGui.QTreeWidget(self.subscriptions) + self.treeWidgetSubscriptions.setMaximumSize(QtCore.QSize(200, 16777215)) + self.treeWidgetSubscriptions.setAlternatingRowColors(True) + self.treeWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) + self.treeWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.treeWidgetSubscriptions.setObjectName(_fromUtf8("treeWidgetSubscriptions")) icon5 = QtGui.QIcon() icon5.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/subscriptions.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - item.setIcon(icon5) - self.tableWidgetSubscriptions.setHorizontalHeaderItem(0, item) - item = QtGui.QTableWidgetItem() - self.tableWidgetSubscriptions.setHorizontalHeaderItem(1, item) - self.tableWidgetSubscriptions.horizontalHeader().setCascadingSectionResizes(True) - self.tableWidgetSubscriptions.horizontalHeader().setDefaultSectionSize(200) - self.tableWidgetSubscriptions.horizontalHeader().setHighlightSections(False) - self.tableWidgetSubscriptions.horizontalHeader().setSortIndicatorShown(False) - self.tableWidgetSubscriptions.horizontalHeader().setStretchLastSection(True) - self.tableWidgetSubscriptions.verticalHeader().setVisible(False) - self.verticalLayout_3.addWidget(self.tableWidgetSubscriptions) + self.treeWidgetSubscriptions.headerItem().setIcon(0, icon5) + self.verticalLayout_3.addWidget(self.treeWidgetSubscriptions) self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) self.pushButtonAddSubscription.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) @@ -307,36 +348,18 @@ class Ui_MainWindow(object): self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) self.verticalLayout_17 = QtGui.QVBoxLayout() self.verticalLayout_17.setObjectName(_fromUtf8("verticalLayout_17")) - self.tableWidgetYourIdentities = QtGui.QTableWidget(self.tab_3) - self.tableWidgetYourIdentities.setMaximumSize(QtCore.QSize(200, 16777215)) - 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) - item.setIcon(icon1) - 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(200) - 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.verticalLayout_17.addWidget(self.tableWidgetYourIdentities) + self.treeWidgetChanList = QtGui.QTreeWidget(self.tab_3) + self.treeWidgetChanList.setMaximumSize(QtCore.QSize(200, 16777215)) + self.treeWidgetChanList.setFrameShadow(QtGui.QFrame.Sunken) + self.treeWidgetChanList.setLineWidth(1) + self.treeWidgetChanList.setAlternatingRowColors(True) + self.treeWidgetChanList.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) + self.treeWidgetChanList.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) + self.treeWidgetChanList.setObjectName(_fromUtf8("treeWidgetChanList")) + icon7 = QtGui.QIcon() + icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) + self.treeWidgetChanList.headerItem().setIcon(0, icon7) + self.verticalLayout_17.addWidget(self.treeWidgetChanList) self.pushButtonAddChanel = QtGui.QPushButton(self.tab_3) self.pushButtonAddChanel.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddChanel.setObjectName(_fromUtf8("pushButtonAddChanel")) @@ -384,9 +407,9 @@ class Ui_MainWindow(object): self.verticalLayout_13.addWidget(self.textEditInboxMessage_2) self.horizontalLayout_4.addLayout(self.verticalLayout_13) self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) - icon7 = QtGui.QIcon() - icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.tab_3, icon7, _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.tab_3, icon8, _fromUtf8("")) self.blackwhitelist = QtGui.QWidget() self.blackwhitelist.setObjectName(_fromUtf8("blackwhitelist")) self.gridLayout_6 = QtGui.QGridLayout(self.blackwhitelist) @@ -421,17 +444,17 @@ class Ui_MainWindow(object): self.tableWidgetBlacklist.horizontalHeader().setStretchLastSection(True) self.tableWidgetBlacklist.verticalHeader().setVisible(False) self.gridLayout_6.addWidget(self.tableWidgetBlacklist, 3, 0, 1, 2) - icon8 = QtGui.QIcon() - icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.blackwhitelist, icon8, _fromUtf8("")) + icon9 = QtGui.QIcon() + icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.blackwhitelist, icon9, _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("")) - icon9 = QtGui.QIcon() - icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.pushButtonStatusIcon.setIcon(icon9) + icon10 = QtGui.QIcon() + icon10.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.pushButtonStatusIcon.setIcon(icon10) self.pushButtonStatusIcon.setFlat(True) self.pushButtonStatusIcon.setObjectName(_fromUtf8("pushButtonStatusIcon")) self.tableWidgetConnectionCount = QtGui.QTableWidget(self.networkstatus) @@ -487,9 +510,9 @@ class Ui_MainWindow(object): self.labelBytesSentCount = QtGui.QLabel(self.networkstatus) self.labelBytesSentCount.setGeometry(QtCore.QRect(350, 230, 251, 16)) self.labelBytesSentCount.setObjectName(_fromUtf8("labelBytesSentCount")) - icon10 = QtGui.QIcon() - icon10.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.networkstatus, icon10, _fromUtf8("")) + icon11 = QtGui.QIcon() + icon11.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.tabWidget.addTab(self.networkstatus, icon11, _fromUtf8("")) self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) @@ -555,15 +578,14 @@ class Ui_MainWindow(object): self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) - self.tabWidget_2.setCurrentIndex(0) + self.tabWidgetSend.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.tableWidgetInbox, self.textEditInboxMessage) MainWindow.setTabOrder(self.textEditInboxMessage, self.comboBoxSendFrom) MainWindow.setTabOrder(self.comboBoxSendFrom, self.lineEditTo) MainWindow.setTabOrder(self.lineEditTo, self.lineEditSubject) MainWindow.setTabOrder(self.lineEditSubject, self.textEditMessage) - MainWindow.setTabOrder(self.textEditMessage, self.pushButtonSend) - MainWindow.setTabOrder(self.pushButtonSend, self.pushButtonAddSubscription) + MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription) MainWindow.setTabOrder(self.pushButtonAddSubscription, self.radioButtonBlacklist) MainWindow.setTabOrder(self.radioButtonBlacklist, self.radioButtonWhitelist) MainWindow.setTabOrder(self.radioButtonWhitelist, self.pushButtonAddBlacklist) @@ -585,38 +607,36 @@ 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", "Received", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Messages", None)) self.tableWidgetAddressBook.setSortingEnabled(True) item = self.tableWidgetAddressBook.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "Name", None)) item = self.tableWidgetAddressBook.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "Address", None)) self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add Contact", None)) - self.label.setText(_translate("MainWindow", "To:", 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(_translate("MainWindow", "\n" "\n" "


", None)) - self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) - self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab), _translate("MainWindow", "Send ordinary Message", None)) + self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.tab), _translate("MainWindow", "Send ordinary Message", None)) self.label_8.setText(_translate("MainWindow", "From:", None)) self.label_7.setText(_translate("MainWindow", "Subject:", None)) - self.textEditMessage_2.setHtml(_translate("MainWindow", "\n" + self.textEditMessageBroadcast.setHtml(_translate("MainWindow", "\n" "\n" "


", None)) - self.pushButtonSend_3.setText(_translate("MainWindow", "Send", None)) - self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_2), _translate("MainWindow", "Send Message to your Subscribers", None)) + self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.tab_2), _translate("MainWindow", "Send Message to your Subscribers", None)) + self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) + self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "X days", None)) + self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.send), _translate("MainWindow", "Send", None)) - self.tableWidgetSubscriptions.setSortingEnabled(True) - item = self.tableWidgetSubscriptions.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Name", None)) - item = self.tableWidgetSubscriptions.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) + self.treeWidgetSubscriptions.headerItem().setText(0, _translate("MainWindow", "Subscriptions", None)) self.pushButtonAddSubscription.setText(_translate("MainWindow", "Add new Subscription", None)) self.inboxSearchLineSubscriptions.setPlaceholderText(_translate("MainWindow", "Search", None)) self.tableWidgetInboxSubscriptions.setSortingEnabled(True) @@ -629,13 +649,7 @@ class Ui_MainWindow(object): item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) - self.tableWidgetYourIdentities.setSortingEnabled(True) - item = self.tableWidgetYourIdentities.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Name", None)) - item = self.tableWidgetYourIdentities.horizontalHeaderItem(1) - item.setText(_translate("MainWindow", "Address", None)) - item = self.tableWidgetYourIdentities.horizontalHeaderItem(2) - item.setText(_translate("MainWindow", "Stream", None)) + self.treeWidgetChanList.headerItem().setText(0, _translate("MainWindow", "Chans", None)) self.pushButtonAddChanel.setText(_translate("MainWindow", "Add Chanel", None)) self.inboxSearchLineEdit_2.setPlaceholderText(_translate("MainWindow", "Search", None)) self.tableWidgetInbox_2.setSortingEnabled(True) @@ -647,7 +661,7 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Subject", None)) item = self.tableWidgetInbox_2.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Chanels", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Chans", 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)) diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index 9340f531..d07b7388 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -62,7 +62,7 @@ :/newPrefix/images/inbox.png:/newPrefix/images/inbox.png - Received + Messages @@ -213,7 +213,7 @@ Send - + @@ -283,156 +283,297 @@
+ + + + + 200 + 16777215 + + + + + 9 + + + + Fetch Namecoin ID + + +
- - - 0 - - - - Send ordinary Message - - - - - - - - - - - 300 - 0 - - - + + + + + 0 + + + + Send ordinary Message + + + + + + + + + + Subject: + + + + + + + From: + + + + + + + + + + + + + + To: + + + + + + + + 300 + 0 + + + + + + + + - - - - To: - - - - - - - - - - Subject: - - - - - - - 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:'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> - - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> + + + + + 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> - - - - - - - Send - - - - - - - - - - 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> - - - - - - - Send - - - + + + + + + + + + + 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 + + - - + +
+ + pushButtonFetchNamecoinID
@@ -448,7 +589,7 @@ p, li { white-space: pre-wrap; } - + 200 @@ -464,30 +605,9 @@ p, li { white-space: pre-wrap; } QAbstractItemView::SelectRows - - true - - - true - - - 200 - - - false - - - false - - - true - - - false - - Name + Subscriptions @@ -495,11 +615,6 @@ p, li { white-space: pre-wrap; } - - - Address - - @@ -617,7 +732,7 @@ p, li { white-space: pre-wrap; } :/newPrefix/images/can-icon-16px.png:/newPrefix/images/can-icon-16px.png - Chanels + Chans @@ -625,7 +740,7 @@ p, li { white-space: pre-wrap; } - + 200 @@ -647,61 +762,16 @@ p, li { white-space: pre-wrap; } QAbstractItemView::SelectRows - - true - - - true - - - 200 - - - 52 - - - true - - - true - - - false - - - 26 - - - false - - - false - - Name - - - - true - + Chans - :/newPrefix/images/identities.png + :/newPrefix/images/can-icon-16px.png - - - Address - - - - - Stream - - -- 2.45.1 From 800fd2a1439fa3536f92e0b06ecf7920323e2fb1 Mon Sep 17 00:00:00 2001 From: sbkaf Date: Mon, 23 Mar 2015 22:35:56 +0100 Subject: [PATCH 0008/1102] finished implementing more email client like interface --- src/bitmessagemain.py | 2 +- src/bitmessageqt/__init__.py | 894 ++++++++++++------------------- src/bitmessageqt/bitmessageui.py | 219 +++++--- src/bitmessageqt/bitmessageui.ui | 135 ++++- 4 files changed, 587 insertions(+), 663 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 73f71cfb..bf1d74f2 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -197,7 +197,7 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() - #connectToStream(1) + connectToStream(1) singleListenerThread = singleListener() singleListenerThread.setup(selfInitiatedConnections) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b1150553..73dab84e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -199,7 +199,7 @@ class MyForm(QtGui.QMainWindow): QtCore.SIGNAL( "triggered()"), self.click_actionRegenerateDeterministicAddresses) - QtCore.QObject.connect(self.ui.pushButtonAddChanel, QtCore.SIGNAL( + QtCore.QObject.connect(self.ui.pushButtonAddChan, QtCore.SIGNAL( "clicked()"), self.click_actionJoinChan) # also used for creating chans. QtCore.QObject.connect(self.ui.pushButtonNewAddress, QtCore.SIGNAL( @@ -253,12 +253,27 @@ class MyForm(QtGui.QMainWindow): 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) @@ -312,7 +327,7 @@ class MyForm(QtGui.QMainWindow): self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) def init_chan_popup_menu(self, connectSignal=True): - # Popup menu for the Chanels tab + # Popup menu for the Channels tab self.ui.addressContextMenuToolbar = QtGui.QToolBar() # Actions self.actionNew = self.ui.addressContextMenuToolbar.addAction(_translate( @@ -336,10 +351,10 @@ class MyForm(QtGui.QMainWindow): "MainWindow", "Special address behavior..."), self.on_action_SpecialAddressBehaviorDialog) - self.ui.treeWidgetChanList.setContextMenuPolicy( + self.ui.treeWidgetChans.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) if connectSignal: - self.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( + self.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( 'customContextMenuRequested(const QPoint&)'), self.on_context_menuChan) @@ -489,19 +504,53 @@ class MyForm(QtGui.QMainWindow): self.popMenuBlacklist.addAction(self.actionBlacklistDisable) self.popMenuBlacklist.addAction(self.actionBlacklistSetAvatar) + def rerenderTabTreeSubscriptions(self): + treeWidget = self.ui.treeWidgetSubscriptions + folders = ['inbox', 'trash'] + treeWidget.clear() + queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') + for row in queryreturn: + label, address, enabled = row + newItem = QtGui.QTreeWidgetItem(treeWidget) + newItem.setExpanded(True) + newItem.setIcon(0, avatarize(address)) + newItem.setText(0, label + ' (' + address + ')') + newItem.setData(0, Qt.UserRole, [str(address), "inbox"]) + #set text color + if enabled: + brush = QtGui.QBrush(QApplication.palette().text().color()) + else: + brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + brush.setStyle(QtCore.Qt.NoBrush) + newItem.setForeground(0, brush) + + for folder in folders: + newSubItem = QtGui.QTreeWidgetItem(newItem) + newSubItem.setText(0, _translate("MainWindow", folder)) + newSubItem.setData(0, Qt.UserRole, [str(address), folder]) + + def rerenderTabTreeMessages(self): + self.rerenderTabTree('messages') + + def rerenderTabTreeChans(self): + self.rerenderTabTree('chan') + def rerenderTabTree(self, tab): + folders = ['inbox', 'sent', 'trash'] if tab == 'messages': treeWidget = self.ui.treeWidgetYourIdentities - folders = ['inbox', 'sent', 'trash'] - elif tab == 'subscriptions': - treeWidget = self.ui.treeWidgetSubscriptions - folders = ['inbox', 'trash'] elif tab == 'chan': - treeWidget = self.ui.treeWidgetChanList - folders = ['inbox', 'sent', 'trash'] + treeWidget = self.ui.treeWidgetChans treeWidget.clear() + # get number of (unread) messages + cntUnreadMsg = {} + 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 + cntUnreadMsg[toaddress + folder] = cnt + configSections = shared.config.sections() for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': @@ -513,16 +562,14 @@ class MyForm(QtGui.QMainWindow): addressInKeysFile, 'mailinglist') if tab == 'messages': - if isChan or isMaillinglist: - continue - elif tab == 'subscriptions': - if not isMaillinglist: + if isChan: continue elif tab == 'chan': if not isChan: continue newItem = QtGui.QTreeWidgetItem(treeWidget) + newItem.setExpanded(True) newItem.setIcon(0, avatarize(addressInKeysFile)) newItem.setText(0, unicode( shared.config.get(addressInKeysFile, 'label'), 'utf-8)') @@ -530,7 +577,10 @@ class MyForm(QtGui.QMainWindow): newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"]) #set text color if isEnabled: - brush = QtGui.QBrush(QApplication.palette().text().color()) + if isMaillinglist: + brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) + else: + brush = QtGui.QBrush(QApplication.palette().text().color()) else: brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) brush.setStyle(QtCore.Qt.NoBrush) @@ -538,7 +588,17 @@ class MyForm(QtGui.QMainWindow): for folder in folders: newSubItem = QtGui.QTreeWidgetItem(newItem) - newSubItem.setText(0, _translate("MainWindow", folder)) + + cnt = cntUnreadMsg.get(addressInKeysFile + folder, False) + if cnt: + unreadText = " (" + str(cnt) + ")" + font = QtGui.QFont() + font.setBold(True) + newSubItem.setFont(0, font) + else: + unreadText = "" + + newSubItem.setText(0, _translate("MainWindow", folder) + unreadText) newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder]) def __init__(self, parent=None): @@ -598,54 +658,18 @@ class MyForm(QtGui.QMainWindow): self.init_blacklist_popup_menu() # Initialize the user's list of addresses on the 'Chan' tab. - self.rerenderTabTree('chan') - """ - TODO remove - configSections = shared.config.sections() - for addressInKeysFile in configSections: - if addressInKeysFile != 'bitmessagesettings': - isEnabled = shared.config.getboolean( - addressInKeysFile, 'enabled') - if shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): - newItem = QtGui.QTableWidgetItem(unicode( - shared.config.get(addressInKeysFile, 'label'), 'utf-8)')) - if not isEnabled: - newItem.setTextColor(QtGui.QColor(128, 128, 128)) - self.ui.tableWidgetChanList.insertRow(0) - newItem.setIcon(avatarize(addressInKeysFile)) - self.ui.tableWidgetChanList.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.tableWidgetChanList.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.tableWidgetChanList.setItem(0, 2, newItem) - if isEnabled: - status, addressVersionNumber, streamNumber, hash = decodeAddress( - addressInKeysFile) - """ + self.rerenderTabTreeChans() # Initialize the user's list of addresses on the 'Messages' tab. - self.rerenderTabTree('messages') + self.rerenderTabTreeMessages() # Set welcome message self.ui.textEditInboxMessage.setText( """ Welcome to easy and secure Bitmessage - * send messages like e-mails + * send messages to other people * send broadcast messages like twitter or - * discuss in chan(el)s with other people + * discuss in chan(nel)s with other people """ ) @@ -658,6 +682,10 @@ class MyForm(QtGui.QMainWindow): # Initialize the inbox search QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL( "returnPressed()"), self.inboxSearchLineEditPressed) + QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL( + "returnPressed()"), self.inboxSearchLineEditPressed) + QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL( + "returnPressed()"), self.inboxSearchLineEditPressed) # Initialize the Blacklist or Whitelist if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': @@ -665,24 +693,25 @@ class MyForm(QtGui.QMainWindow): self.ui.radioButtonWhitelist.click() self.rerenderBlackWhiteList() - # Initialize addresslists + # Initialize addressbook QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( "itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged) - """ - TODO implement - QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.treeWidgetSubscriptionsItemChanged) - QtCore.QObject.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.treeWidgetChanListItemChanged) - """ + + # show messages from message list 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.treeWidgetYourIdentitiesItemClicked) + "itemSelectionChanged ()"), self.treeWidgetItemClicked) QtCore.QObject.connect(self.ui.treeWidgetSubscriptions, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.treeWidgetSubscribtionsItemClicked) - QtCore.QObject.connect(self.ui.treeWidgetChanList, QtCore.SIGNAL( - "itemSelectionChanged ()"), self.treeWidgetChanListItemClicked) + "itemSelectionChanged ()"), self.treeWidgetItemClicked) + QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( + "itemSelectionChanged ()"), self.treeWidgetItemClicked) # Put the colored icon on the status bar # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) @@ -697,7 +726,7 @@ class MyForm(QtGui.QMainWindow): # Set the icon sizes for the identicons identicon_size = 3*7 self.ui.tableWidgetInbox.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.ui.treeWidgetChanList.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.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size)) @@ -883,35 +912,35 @@ class MyForm(QtGui.QMainWindow): self.appIndicatorShow() self.ui.tabWidget.setCurrentIndex(2) - # Show the program window and select chanels tab - def appIndicatorChanel(self): + # Show the program window and select channels tab + def appIndicatorChannel(self): self.appIndicatorShow() self.ui.tabWidget.setCurrentIndex(3) # Load Sent items from database - def loadSent(self, where="", what=""): + def loadSent(self, tableWidget, account, where="", what=""): what = "%" + what + "%" - if where == "To": + if where == _translate("MainWindow", "To"): where = "toaddress" - elif where == "From": + elif where == _translate("MainWindow", "From"): where = "fromaddress" - elif where == "Subject": + elif where == _translate("MainWindow", "Subject"): where = "subject" - elif where == "Message": + elif where == _translate("MainWindow", "Message"): where = "message" else: where = "toaddress || fromaddress || subject || message" sqlStatement = ''' SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime - FROM sent WHERE folder="sent" AND %s LIKE ? + FROM sent WHERE fromaddress=? AND folder="sent" AND %s LIKE ? ORDER BY lastactiontime ''' % (where,) - while self.ui.tableWidgetInbox.rowCount() > 0: - self.ui.tableWidgetInbox.removeRow(0) + while tableWidget.rowCount() > 0: + tableWidget.removeRow(0) - queryreturn = sqlQuery(sqlStatement, what) + queryreturn = sqlQuery(sqlStatement, account, what) for row in queryreturn: toAddress, fromAddress, subject, status, ackdata, lastactiontime = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) @@ -943,14 +972,14 @@ class MyForm(QtGui.QMainWindow): if toLabel == '': toLabel = toAddress - self.ui.tableWidgetInbox.insertRow(0) + tableWidget.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.tableWidgetInbox.setItem(0, 0, toAddressItem) + tableWidget.setItem(0, 0, toAddressItem) if fromLabel == '': fromLabel = fromAddress @@ -960,13 +989,13 @@ class MyForm(QtGui.QMainWindow): fromAddressItem.setData(Qt.UserRole, str(fromAddress)) fromAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.tableWidgetInbox.setItem(0, 1, fromAddressItem) + tableWidget.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.tableWidgetInbox.setItem(0, 2, subjectItem) + tableWidget.setItem(0, 2, subjectItem) if status == 'awaitingpubkey': statusText = _translate( @@ -1013,34 +1042,33 @@ class MyForm(QtGui.QMainWindow): newItem.setData(33, int(lastactiontime)) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.tableWidgetInbox.setItem(0, 3, newItem) - self.ui.tableWidgetInbox.sortItems(3, Qt.DescendingOrder) - self.ui.tableWidgetInbox.keyPressEvent = self.tableWidgetInboxKeyPressEvent + tableWidget.setItem(0, 3, newItem) + tableWidget.sortItems(3, Qt.DescendingOrder) + tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent - # Load inbox from messages database file + # Load messages from database file def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what=""): + if folder == 'sent': + self.loadSent(tableWidget, account, where, what) + return + what = "%" + what + "%" - if where == "To": + if where == _translate("MainWindow", "To"): where = "toaddress" - elif where == "From": + elif where == _translate("MainWindow", "From"): where = "fromaddress" - elif where == "Subject": + elif where == _translate("MainWindow", "Subject"): where = "subject" - elif where == "Message": + elif where == _translate("MainWindow", "Message"): where = "message" else: where = "toaddress || fromaddress || subject || message" - if folder == "sent": - accounttype = "fromaddress" - else: - accounttype = "toaddress" - sqlStatement = ''' SELECT msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE %s=? AND folder=? AND %s LIKE ? + FROM inbox WHERE toaddress=? AND folder=? AND %s LIKE ? ORDER BY received - ''' % (accounttype, where) + ''' % (where) while tableWidget.rowCount() > 0: tableWidget.removeRow(0) @@ -1131,115 +1159,6 @@ class MyForm(QtGui.QMainWindow): tableWidget.sortItems(3, Qt.DescendingOrder) tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent - # 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: - where = "toaddress || fromaddress || subject || message" - - sqlStatement = ''' - SELECT msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE folder="inbox" AND %s LIKE ? - ORDER BY received - ''' % (where,) - - while self.ui.tableWidgetInbox.rowCount() > 0: - self.ui.tableWidgetInbox.removeRow(0) - - font = QFont() - font.setBold(True) - queryreturn = sqlQuery(sqlStatement, what) - for row in queryreturn: - 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 - - 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): self.initTrayIcon("can-icon-24px-red.png", app) @@ -1279,10 +1198,10 @@ class MyForm(QtGui.QMainWindow): actionSubscribe.triggered.connect(self.appIndicatorSubscribe) m.addAction(actionSubscribe) - # Chanels + # Channels actionSubscribe = QtGui.QAction(_translate( - "MainWindow", "Chanel"), m, checkable=False) - actionSubscribe.triggered.connect(self.appIndicatorChanel) + "MainWindow", "Channel"), m, checkable=False) + actionSubscribe.triggered.connect(self.appIndicatorChannel) m.addAction(actionSubscribe) # separator @@ -2072,26 +1991,7 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) def rerenderSubscriptions(self): - self.rerenderTabTree('subscriptions') - """ - TODO remove - 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) - """ + self.rerenderTabTreeSubscriptions() def rerenderBlackWhiteList(self): self.ui.tableWidgetBlacklist.setRowCount(0) @@ -2126,13 +2026,21 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.statusBar().showMessage('') if self.ui.tabWidgetSend.currentIndex() == 0: + # message to specific people sendMessageToPeople = True + fromAddress = self.ui.comboBoxSendFrom.itemData( + self.ui.comboBoxSendFrom.currentIndex(), + Qt.UserRole).toString() toAddresses = str(self.ui.lineEditTo.text()) subject = str(self.ui.lineEditSubject.text().toUtf8()) message = str( self.ui.textEditMessage.document().toPlainText().toUtf8()) else: + # broadcast message sendMessageToPeople = False + fromAddress = self.ui.comboBoxSendFromBroadcast.itemData( + self.ui.comboBoxSendFromBroadcast.currentIndex(), + Qt.UserRole).toString() subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8()) message = str( self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8()) @@ -2148,11 +2056,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f "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 - if toAddresses: - print toAddresses - print subject - print message - return if sendMessageToPeople: # To send a message to specific people (rather than broadcast) toAddressesList = [s.strip() for s in toAddresses.replace(',', ';').split(';')] @@ -2512,25 +2415,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f #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 UI list - TODO remove - 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.rerenderTabTree('subscriptions') + self.rerenderTabTreeSubscriptions() def click_pushButtonAddSubscription(self): self.NewSubscriptionDialogInstance = NewSubscriptionDialog(self) @@ -2862,38 +2752,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f shared.writeKeysFile() self.rerenderInboxToLabels() - """ - TODO remove - def on_action_ChanSpecialAddressBehaviorDialog(self): - self.dialog = SpecialAddressBehaviorDialog(self) - # For Modal dialogs - if self.dialog.exec_(): - currentRow = self.ui.tableWidgetChanList.currentRow() - addressAtCurrentRow = str( - self.ui.tableWidgetChanList.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.tableWidgetChanList.item( - currentRow, 1).setTextColor(QApplication.palette() - .text().color()) - else: - self.ui.tableWidgetChanList.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.tableWidgetChanList.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta - shared.writeKeysFile() - self.rerenderInboxToLabels() - """ - def click_NewAddressDialog(self): self.dialog = NewAddressDialog(self) # For Modal dialogs @@ -2961,10 +2819,10 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.quit() def on_action_InboxMessageForceHtml(self): - currentInboxRow = self.ui.tableWidgetInbox.currentRow() - - msgid = str(self.ui.tableWidgetInbox.item( - currentInboxRow, 3).data(Qt.UserRole).toPyObject()) + msgid = self.getCurrentMessageId() + textEdit = self.getCurrentMessageTextedit() + if not msgid: + return queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: @@ -2985,29 +2843,32 @@ more work your computer must do to send the message. A Time-To-Live of four or f content = ' '.join(lines) # To keep the whitespace between lines content = shared.fixPotentiallyInvalidUTF8Data(content) content = unicode(content, 'utf-8)') - self.ui.textEditInboxMessage.setHtml(QtCore.QString(content)) + textEdit.setHtml(QtCore.QString(content)) def on_action_InboxMarkUnread(self): + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return font = QFont() font.setBold(True) inventoryHashesToMarkUnread = [] - for row in self.ui.tableWidgetInbox.selectedIndexes(): + for row in tableWidget.selectedIndexes(): currentRow = row.row() - inventoryHashToMarkUnread = str(self.ui.tableWidgetInbox.item( + inventoryHashToMarkUnread = str(tableWidget.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) + tableWidget.item(currentRow, 0).setFont(font) + tableWidget.item(currentRow, 1).setFont(font) + tableWidget.item(currentRow, 2).setFont(font) + tableWidget.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) + # tableWidget.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. - # self.ui.tableWidgetInbox.clearSelection() manages to mark the message as read again. + # tableWidget.clearSelection() manages to mark the message as read again. # Format predefined text on message reply. def quoted_text(self, message): @@ -3032,12 +2893,15 @@ more work your computer must do to send the message. A Time-To-Live of four or f return '\n'.join([quote_line(l) for l in message.splitlines()]) + '\n\n' def on_action_InboxReply(self): - currentInboxRow = self.ui.tableWidgetInbox.currentRow() - toAddressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + currentInboxRow = tableWidget.currentRow() + toAddressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 0).data(Qt.UserRole).toPyObject()) - fromAddressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + fromAddressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 1).data(Qt.UserRole).toPyObject()) - msgid = str(self.ui.tableWidgetInbox.item( + msgid = str(tableWidget.item( currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) @@ -3073,19 +2937,22 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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:']: + if tableWidget.item(currentInboxRow, 2).text()[0:3] in ['Re:', 'RE:']: self.ui.lineEditSubject.setText( - self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()) + tableWidget.item(currentInboxRow, 2).text()) else: self.ui.lineEditSubject.setText( - 'Re: ' + self.ui.tableWidgetInbox.item(currentInboxRow, 2).text()) + 'Re: ' + tableWidget.item(currentInboxRow, 2).text()) self.ui.tabWidgetSend.setCurrentIndex(0) self.ui.tabWidget.setCurrentIndex(1) def on_action_InboxAddSenderToAddressBook(self): - currentInboxRow = self.ui.tableWidgetInbox.currentRow() - # self.ui.tableWidgetInbox.item(currentRow,1).data(Qt.UserRole).toPyObject() - addressAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item( + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + currentInboxRow = tableWidget.currentRow() + # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() + addressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 1).data(Qt.UserRole).toPyObject()) # Let's make sure that it isn't already in the address book queryreturn = sqlQuery('''select * from addressbook where address=?''', @@ -3103,7 +2970,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', '--New entry. Change label in Address Book.--', addressAtCurrentInboxRow) - self.ui.tabWidget.setCurrentIndex(5) + self.ui.tabWidget.setCurrentIndex(1) self.ui.tableWidgetAddressBook.setCurrentCell(0, 0) self.statusBar().showMessage(_translate( "MainWindow", "Entry added to the Address Book. Edit the label to your liking.")) @@ -3113,29 +2980,35 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Send item on the Inbox tab to trash def on_action_InboxTrash(self): - while self.ui.tableWidgetInbox.selectedIndexes() != []: - currentRow = self.ui.tableWidgetInbox.selectedIndexes()[0].row() - inventoryHashToTrash = str(self.ui.tableWidgetInbox.item( + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + while tableWidget.selectedIndexes() != []: + currentRow = tableWidget.selectedIndexes()[0].row() + inventoryHashToTrash = str(tableWidget.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) + tableWidget.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.tableWidgetInbox.selectRow(currentRow) + tableWidget.selectRow(currentRow) else: - self.ui.tableWidgetInbox.selectRow(currentRow - 1) + tableWidget.selectRow(currentRow - 1) def on_action_InboxSaveMessageAs(self): - currentInboxRow = self.ui.tableWidgetInbox.currentRow() + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + currentInboxRow = tableWidget.currentRow() try: - subjectAtCurrentInboxRow = str(self.ui.tableWidgetInbox.item(currentInboxRow,2).text()) + subjectAtCurrentInboxRow = str(tableWidget.item(currentInboxRow,2).text()) except: subjectAtCurrentInboxRow = '' # Retrieve the message data out of the SQL database - msgid = str(self.ui.tableWidgetInbox.item( + msgid = str(tableWidget.item( currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) @@ -3270,73 +3143,37 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.click_pushButtonAddSubscription() def on_action_SubscriptionsDelete(self): - print 'clicked Delete' - """ - TODO implement - 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) + address = self.getCurrentAccount() + sqlExecute('''DELETE FROM subscriptions WHERE address=?''', + address) + self.rerenderTabTreeSubscriptions() self.rerenderInboxFromLabels() shared.reloadBroadcastSendersForWhichImWatching() - """ def on_action_SubscriptionsClipboard(self): - """ - TODO implement - currentRow = self.ui.tableWidgetSubscriptions.currentRow() - addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( - currentRow, 1).text() + address = self.getCurrentAccount() clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(addressAtCurrentRow)) - """ + clipboard.setText(str(address)) def on_action_SubscriptionsEnable(self): - """ - TODO implement - currentRow = self.ui.tableWidgetSubscriptions.currentRow() - labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( - currentRow, 0).text().toUtf8() - addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( - currentRow, 1).text() + address = self.getCurrentAccount() sqlExecute( - '''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()) + '''update subscriptions set enabled=1 WHERE address=?''', + address) + self.setCurrentItemColor(QApplication.palette().text().color()) shared.reloadBroadcastSendersForWhichImWatching() - """ def on_action_SubscriptionsDisable(self): - """ - TODO implement - currentRow = self.ui.tableWidgetSubscriptions.currentRow() - labelAtCurrentRow = self.ui.tableWidgetSubscriptions.item( - currentRow, 0).text().toUtf8() - addressAtCurrentRow = self.ui.tableWidgetSubscriptions.item( - currentRow, 1).text() + address = self.getCurrentAccount() sqlExecute( - '''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)) + '''update subscriptions set enabled=0 WHERE address=?''', + address) + self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) shared.reloadBroadcastSendersForWhichImWatching() - """ def on_context_menuSubscriptions(self, point): - """ - TODO implement self.popMenuSubscriptions.exec_( - self.ui.tableWidgetSubscriptions.mapToGlobal(point)) - """ + self.ui.treeWidgetSubscriptions.mapToGlobal(point)) # Group of functions for the Blacklist dialog box def on_action_BlacklistNew(self): @@ -3414,6 +3251,68 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: return False + 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] + else: + return False + + def getCurrentMessageId(self): + messagelist = self.getCurrentMessagelist() + if messagelist: + currentRow = messagelist.currentRow() + if currentRow >= 0: + msgid = str(messagelist.item( + currentRow, 3).data(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 getCurrentSearchLine(self): + currentIndex = self.ui.tabWidget.currentIndex(); + messagelistList = [ + self.ui.inboxSearchLineEdit, + False, + self.ui.inboxSearchLineEditSubscriptions, + self.ui.inboxSearchLineEditChans, + ] + if currentIndex >= 0 and currentIndex < len(messagelistList): + return messagelistList[currentIndex] + else: + return False + + def getCurrentSearchOption(self): + 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 False + # Group of functions for the Your Identities dialog box def getCurrentAccount(self): treeWidget = self.getCurrentTreeWidget() @@ -3444,6 +3343,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f if treeWidget: brush = QtGui.QBrush() brush.setStyle(QtCore.Qt.NoBrush) + brush.setColor(color) currentItem = treeWidget.currentItem() currentItem.setForeground(0, brush) @@ -3455,25 +3355,6 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.enableIdentity(addressAtCurrentRow) self.setCurrentItemColor(QApplication.palette().text().color()) - """ - TODO remove - def on_action_ChanEnable(self): - currentRow = self.ui.tableWidgetChanList.currentRow() - addressAtCurrentRow = str( - self.ui.tableWidgetChanList.item(currentRow, 1).text()) - self.ui.tableWidgetChanList.item( - currentRow, 0).setTextColor(QApplication.palette().text().color()) - self.ui.tableWidgetChanList.item( - currentRow, 1).setTextColor(QApplication.palette().text().color()) - self.ui.tableWidgetChanList.item( - currentRow, 2).setTextColor(QApplication.palette().text().color()) - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): - self.ui.tableWidgetChanList.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): - self.ui.tableWidgetChanList.item(currentRow, 1).setTextColor(QtGui.QColor(216, 119, 0)) # orange - self.enableIdentity(addressAtCurrentRow) - """ - def enableIdentity(self, address): shared.config.set(address, 'enabled', 'true') shared.writeKeysFile() @@ -3484,49 +3365,20 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.disableIdentity(address) self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) - """ - TODO remove - def on_action_ChanDisable(self): - currentRow = self.ui.tableWidgetChanList.currentRow() - addressAtCurrentRow = str( - self.ui.tableWidgetChanList.item(currentRow, 1).text()) - self.ui.tableWidgetChanList.item( - currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) - self.ui.tableWidgetChanList.item( - currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) - self.ui.tableWidgetChanList.item( - currentRow, 2).setTextColor(QtGui.QColor(128, 128, 128)) - self.disableIdentity(address) - """ - def disableIdentity(self, address): - shared.config.set(str(addressAtCurrentRow), 'enabled', 'false') + shared.config.set(str(address), 'enabled', 'false') shared.writeKeysFile() shared.reloadMyAddressHashes() def on_action_Clipboard(self): - addressAtCurrentRow = self.getCurrentAccount() + address = self.getCurrentAccount() clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(addressAtCurrentRow)) - - """ - TODO remove - def on_action_ChanClipboard(self): - currentRow = self.ui.tableWidgetChanList.currentRow() - addressAtCurrentRow = self.ui.tableWidgetChanList.item( - currentRow, 1).text() - clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(addressAtCurrentRow)) - """ + clipboard.setText(str(address)) #set avatar functions def on_action_TreeWidgetSetAvatar(self): - addressAtCurrentRow = self.getCurrentAccount() - treeWidget = self.getCurrentTreeWidget() - setToIdenticon = not self.setAvatar(addressAtCurrentRow) - if treeWidget and setToIdenticon: - currentItem = treeWidget.currentItem() - currentItem.setIcon(0, avatarize(addressAtCurrentRow)) + address = self.getCurrentAccount() + self.setAvatar(address) def on_action_AddressBookSetAvatar(self): self.on_action_SetAvatar(self.ui.tableWidgetAddressBook) @@ -3597,7 +3449,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f if not copied: print 'couldn\'t copy :(' # set the icon - self.rerenderSubscriptions() + self.rerenderTabTreeMessages() + self.rerenderTabTreeSubscriptions() + self.rerenderTabTreeChans() self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() self.rerenderInboxFromLabels() @@ -3610,17 +3464,25 @@ more work your computer must do to send the message. A Time-To-Live of four or f return True - # TODO make one popMenu def on_context_menuYourIdentities(self, point): self.popMenuYourIdentities.exec_( self.ui.treeWidgetYourIdentities.mapToGlobal(point)) + # TODO make one popMenu def on_context_menuChan(self, point): self.popMenu.exec_( - self.ui.treeWidgetChanList.mapToGlobal(point)) + self.ui.treeWidgetChans.mapToGlobal(point)) def on_context_menuInbox(self, point): - self.popMenuInbox.exec_(self.ui.tableWidgetInbox.mapToGlobal(point)) + tableWidget = self.getCurrentMessagelist() + if tableWidget: + currentFolder = self.getCurrentFolder() + if currentFolder == False: + pass + if currentFolder == 'sent': + self.on_context_menuSent(point) + else: + self.popMenuInbox.exec_(tableWidget.mapToGlobal(point)) def on_context_menuSent(self, point): self.popMenuSent = QtGui.QMenu(self) @@ -3630,51 +3492,65 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Check to see if this item is toodifficult and display an additional # menu option (Force Send) if it is. currentRow = self.ui.tableWidgetInbox.currentRow() - ackData = str(self.ui.tableWidgetInbox.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) + if currentRow >= 0: + ackData = str(self.ui.tableWidgetInbox.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.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) + searchLine = self.getCurrentSearchLine() + searchOption = self.getCurrentSearchOption() + if searchLine: + searchKeyword = searchLine.text().toUtf8().data() + searchLine.setText(QString("")) + messageTextedit = self.getCurrentMessageTextedit() + if messageTextedit: + messageTextedit.setPlainText(QString("")) + messagelist = self.getCurrentMessagelist() + if messagelist: + account = self.getCurrentAccount() + folder = self.getCurrentFolder() + self.loadMessagelist(messagelist, account, folder, searchOption, searchKeyword) - def treeWidgetYourIdentitiesItemClicked(self): - currentItem = self.ui.treeWidgetYourIdentities.currentItem() - if currentItem: - accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() - account = accountFolder[0] - folder = accountFolder[1] - self.loadMessagelist(self.ui.tableWidgetInbox, str(account), str(folder)) - - # TODO trees - def treeWidgetSubscribtionsItemClicked(self): - pass - - def treeWidgetChanListItemClicked(self): - pass + def treeWidgetItemClicked(self): + messagelist = self.getCurrentMessagelist() + if messagelist: + account = self.getCurrentAccount() + folder = self.getCurrentFolder() + self.loadMessagelist(messagelist, account, folder) def tableWidgetInboxItemClicked(self): - currentRow = self.ui.tableWidgetInbox.currentRow() - if currentRow >= 0: - msgid = str(self.ui.tableWidgetInbox.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) - queryreturn = sqlQuery( - '''select message from inbox where msgid=?''', msgid) - if queryreturn != []: - for row in queryreturn: - message, = row - else: + folder = self.getCurrentFolder() + messageTextedit = self.getCurrentMessageTextedit() + queryreturn = [] + message = "" + + if folder == 'sent': + ackdata = self.getCurrentMessageId() + if ackdata and messageTextedit: + queryreturn = sqlQuery( + '''select message from sent where ackdata=?''', ackdata) + else: + msgid = self.getCurrentMessageId() + if msgid and messageTextedit: + queryreturn = sqlQuery( + '''select message from inbox where msgid=?''', msgid) + + if queryreturn != []: + for row in queryreturn: + message, = row + else: + data = self.getCurrentMessageId() + if data != False: message = "Error occurred: could not load message from disk." - message = unicode(message, 'utf-8)') - self.ui.textEditInboxMessage.setPlainText(message) + message = unicode(message, 'utf-8)') + messageTextedit.setPlainText(message) def tableWidgetAddressBookItemChanged(self): currentRow = self.ui.tableWidgetAddressBook.currentRow() @@ -3687,59 +3563,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.rerenderInboxFromLabels() self.rerenderSentToLabels() - """ - TODO implement - def treeWidgetSubscriptionsItemChanged(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 treeWidgetChanListItemChanged(self): - currentRow = self.ui.tableWidgetChanList.currentRow() - if currentRow >= 0: - addressAtCurrentRow = self.ui.tableWidgetChanList.item( - currentRow, 1).text() - shared.config.set(str(addressAtCurrentRow), 'label', str( - self.ui.tableWidgetChanList.item(currentRow, 0).text().toUtf8())) - shared.writeKeysFile() - self.rerenderComboBoxSendFrom() - self.rerenderComboBoxSendFromBroadcast() - # self.rerenderInboxFromLabels() - self.rerenderInboxToLabels() - self.rerenderSentFromLabels() - # self.rerenderSentToLabels() - """ - def writeNewAddressToTable(self, label, address, streamNumber): - pass - """ - TODO implement - self.ui.tableWidgetChanList.setSortingEnabled(False) - self.ui.tableWidgetChanList.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode(label, 'utf-8')) - newItem.setIcon(avatarize(address)) - self.ui.tableWidgetChanList.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.tableWidgetChanList.setItem(0, 1, newItem) - newItem = QtGui.QTableWidgetItem(streamNumber) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.ui.tableWidgetChanList.setItem(0, 2, newItem) - # self.ui.tableWidgetChanList.setSortingEnabled(True) + self.rerenderTabTreeMessages() + self.rerenderTabTreeSubscriptions() + self.rerenderTabTreeChans() self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - """ def updateStatusBar(self, data): if data != "": @@ -4029,39 +3858,6 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) -""" -TODO remove -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.tableWidgetChanList.currentRow() - addressAtCurrentRow = str( - parent.ui.tableWidgetChanList.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): @@ -4165,8 +3961,6 @@ class NewSubscriptionDialog(QtGui.QDialog): class NewAddressDialog(QtGui.QDialog): def __init__(self, parent): - """ - TODO implement QtGui.QWidget.__init__(self, parent) self.ui = Ui_NewAddressDialog() self.ui.setupUi(self) @@ -4174,14 +3968,16 @@ class NewAddressDialog(QtGui.QDialog): row = 1 # Let's fill out the 'existing address' combo box with addresses from # the 'Your Identities' tab. - while self.parent.ui.tableWidgetChanList.item(row - 1, 1): + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile == 'bitmessagesettings': + continue self.ui.radioButtonExisting.click() self.ui.comboBoxExisting.addItem( - self.parent.ui.tableWidgetChanList.item(row - 1, 1).text()) + addressInKeysFile) row += 1 self.ui.groupBoxDeterministic.setHidden(True) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - """ class newChanDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 17ab57ee..d795f17c 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'bitmessageui.ui' # -# Created: Fri Mar 20 19:19:21 2015 +# Created: Mon Mar 23 22:18:07 2015 # by: PyQt4 UI code generator 4.10.4 # # WARNING! All changes made in this file will be lost! @@ -69,15 +69,23 @@ class Ui_MainWindow(object): self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) self.verticalLayout_12.addWidget(self.pushButtonNewAddress) self.horizontalLayout_3.addLayout(self.verticalLayout_12) - self.verticalLayout_11 = QtGui.QVBoxLayout() - self.verticalLayout_11.setObjectName(_fromUtf8("verticalLayout_11")) + self.verticalLayout_7 = QtGui.QVBoxLayout() + self.verticalLayout_7.setObjectName(_fromUtf8("verticalLayout_7")) 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.horizontalLayoutSearch.addWidget(self.inboxSearchLineEdit) - self.verticalLayout_11.addLayout(self.horizontalLayoutSearch) + 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.horizontalLayoutSearch.addWidget(self.inboxSearchOption) + self.verticalLayout_7.addLayout(self.horizontalLayoutSearch) self.tableWidgetInbox = QtGui.QTableWidget(self.inbox) self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInbox.setAlternatingRowColors(True) @@ -103,13 +111,13 @@ class Ui_MainWindow(object): self.tableWidgetInbox.horizontalHeader().setStretchLastSection(True) self.tableWidgetInbox.verticalHeader().setVisible(False) self.tableWidgetInbox.verticalHeader().setDefaultSectionSize(26) - self.verticalLayout_11.addWidget(self.tableWidgetInbox) + self.verticalLayout_7.addWidget(self.tableWidgetInbox) self.textEditInboxMessage = QtGui.QTextEdit(self.inbox) self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessage.setReadOnly(True) self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage")) - self.verticalLayout_11.addWidget(self.textEditInboxMessage) - self.horizontalLayout_3.addLayout(self.verticalLayout_11) + self.verticalLayout_7.addWidget(self.textEditInboxMessage) + self.horizontalLayout_3.addLayout(self.verticalLayout_7) self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) @@ -278,10 +286,10 @@ class Ui_MainWindow(object): self.tabWidget.addTab(self.send, icon4, _fromUtf8("")) self.subscriptions = QtGui.QWidget() self.subscriptions.setObjectName(_fromUtf8("subscriptions")) - self.gridLayout_4 = QtGui.QGridLayout(self.subscriptions) - self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) - self.horizontalLayout_2 = QtGui.QHBoxLayout() - self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.gridLayout_3 = QtGui.QGridLayout(self.subscriptions) + self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) + self.horizontalLayout_4 = QtGui.QHBoxLayout() + self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) self.verticalLayout_3 = QtGui.QVBoxLayout() self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) self.treeWidgetSubscriptions = QtGui.QTreeWidget(self.subscriptions) @@ -298,12 +306,23 @@ class Ui_MainWindow(object): self.pushButtonAddSubscription.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) self.verticalLayout_3.addWidget(self.pushButtonAddSubscription) - self.horizontalLayout_2.addLayout(self.verticalLayout_3) + self.horizontalLayout_4.addLayout(self.verticalLayout_3) self.verticalLayout_4 = QtGui.QVBoxLayout() self.verticalLayout_4.setObjectName(_fromUtf8("verticalLayout_4")) - self.inboxSearchLineSubscriptions = QtGui.QLineEdit(self.subscriptions) - self.inboxSearchLineSubscriptions.setObjectName(_fromUtf8("inboxSearchLineSubscriptions")) - self.verticalLayout_4.addWidget(self.inboxSearchLineSubscriptions) + self.horizontalLayout_2 = QtGui.QHBoxLayout() + self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions) + self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions")) + self.horizontalLayout_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.horizontalLayout_2.addWidget(self.inboxSearchOptionSubscriptions) + self.verticalLayout_4.addLayout(self.horizontalLayout_2) self.tableWidgetInboxSubscriptions = QtGui.QTableWidget(self.subscriptions) self.tableWidgetInboxSubscriptions.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInboxSubscriptions.setAlternatingRowColors(True) @@ -330,83 +349,90 @@ class Ui_MainWindow(object): self.tableWidgetInboxSubscriptions.verticalHeader().setVisible(False) self.tableWidgetInboxSubscriptions.verticalHeader().setDefaultSectionSize(26) self.verticalLayout_4.addWidget(self.tableWidgetInboxSubscriptions) - self.textEditInboxSubscriptions = QtGui.QTextEdit(self.subscriptions) - self.textEditInboxSubscriptions.setBaseSize(QtCore.QSize(0, 500)) - self.textEditInboxSubscriptions.setReadOnly(True) - self.textEditInboxSubscriptions.setObjectName(_fromUtf8("textEditInboxSubscriptions")) - self.verticalLayout_4.addWidget(self.textEditInboxSubscriptions) - self.horizontalLayout_2.addLayout(self.verticalLayout_4) - self.gridLayout_4.addLayout(self.horizontalLayout_2, 0, 0, 1, 1) + self.textEditInboxMessageSubscriptions = QtGui.QTextEdit(self.subscriptions) + self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500)) + self.textEditInboxMessageSubscriptions.setReadOnly(True) + self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions")) + self.verticalLayout_4.addWidget(self.textEditInboxMessageSubscriptions) + self.horizontalLayout_4.addLayout(self.verticalLayout_4) + self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) 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.tab_3 = QtGui.QWidget() self.tab_3.setObjectName(_fromUtf8("tab_3")) - self.gridLayout_3 = QtGui.QGridLayout(self.tab_3) - self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - self.horizontalLayout_4 = QtGui.QHBoxLayout() - self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) + self.gridLayout_4 = QtGui.QGridLayout(self.tab_3) + self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) + self.horizontalLayout_7 = QtGui.QHBoxLayout() + self.horizontalLayout_7.setObjectName(_fromUtf8("horizontalLayout_7")) self.verticalLayout_17 = QtGui.QVBoxLayout() self.verticalLayout_17.setObjectName(_fromUtf8("verticalLayout_17")) - self.treeWidgetChanList = QtGui.QTreeWidget(self.tab_3) - self.treeWidgetChanList.setMaximumSize(QtCore.QSize(200, 16777215)) - self.treeWidgetChanList.setFrameShadow(QtGui.QFrame.Sunken) - self.treeWidgetChanList.setLineWidth(1) - self.treeWidgetChanList.setAlternatingRowColors(True) - self.treeWidgetChanList.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) - self.treeWidgetChanList.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.treeWidgetChanList.setObjectName(_fromUtf8("treeWidgetChanList")) + self.treeWidgetChans = QtGui.QTreeWidget(self.tab_3) + self.treeWidgetChans.setMaximumSize(QtCore.QSize(200, 16777215)) + 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")) icon7 = QtGui.QIcon() icon7.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Selected, QtGui.QIcon.Off) - self.treeWidgetChanList.headerItem().setIcon(0, icon7) - self.verticalLayout_17.addWidget(self.treeWidgetChanList) - self.pushButtonAddChanel = QtGui.QPushButton(self.tab_3) - self.pushButtonAddChanel.setMaximumSize(QtCore.QSize(200, 16777215)) - self.pushButtonAddChanel.setObjectName(_fromUtf8("pushButtonAddChanel")) - self.verticalLayout_17.addWidget(self.pushButtonAddChanel) - self.horizontalLayout_4.addLayout(self.verticalLayout_17) - self.verticalLayout_13 = QtGui.QVBoxLayout() - self.verticalLayout_13.setObjectName(_fromUtf8("verticalLayout_13")) - self.horizontalLayoutSearch_2 = QtGui.QHBoxLayout() - self.horizontalLayoutSearch_2.setContentsMargins(-1, 0, -1, -1) - self.horizontalLayoutSearch_2.setObjectName(_fromUtf8("horizontalLayoutSearch_2")) - self.inboxSearchLineEdit_2 = QtGui.QLineEdit(self.tab_3) - self.inboxSearchLineEdit_2.setObjectName(_fromUtf8("inboxSearchLineEdit_2")) - self.horizontalLayoutSearch_2.addWidget(self.inboxSearchLineEdit_2) - self.verticalLayout_13.addLayout(self.horizontalLayoutSearch_2) - self.tableWidgetInbox_2 = QtGui.QTableWidget(self.tab_3) - self.tableWidgetInbox_2.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) - self.tableWidgetInbox_2.setAlternatingRowColors(True) - self.tableWidgetInbox_2.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) - self.tableWidgetInbox_2.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.tableWidgetInbox_2.setWordWrap(False) - self.tableWidgetInbox_2.setObjectName(_fromUtf8("tableWidgetInbox_2")) - self.tableWidgetInbox_2.setColumnCount(4) - self.tableWidgetInbox_2.setRowCount(0) + self.treeWidgetChans.headerItem().setIcon(0, icon7) + self.verticalLayout_17.addWidget(self.treeWidgetChans) + self.pushButtonAddChan = QtGui.QPushButton(self.tab_3) + self.pushButtonAddChan.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonAddChan.setObjectName(_fromUtf8("pushButtonAddChan")) + self.verticalLayout_17.addWidget(self.pushButtonAddChan) + self.horizontalLayout_7.addLayout(self.verticalLayout_17) + self.verticalLayout_8 = QtGui.QVBoxLayout() + self.verticalLayout_8.setObjectName(_fromUtf8("verticalLayout_8")) + self.horizontalLayout_6 = QtGui.QHBoxLayout() + self.horizontalLayout_6.setObjectName(_fromUtf8("horizontalLayout_6")) + self.inboxSearchLineEditChans = QtGui.QLineEdit(self.tab_3) + self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans")) + self.horizontalLayout_6.addWidget(self.inboxSearchLineEditChans) + self.inboxSearchOptionChans = QtGui.QComboBox(self.tab_3) + 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.horizontalLayout_6.addWidget(self.inboxSearchOptionChans) + self.verticalLayout_8.addLayout(self.horizontalLayout_6) + self.tableWidgetInboxChans = QtGui.QTableWidget(self.tab_3) + 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.tableWidgetInbox_2.setHorizontalHeaderItem(0, item) + self.tableWidgetInboxChans.setHorizontalHeaderItem(0, item) item = QtGui.QTableWidgetItem() - self.tableWidgetInbox_2.setHorizontalHeaderItem(1, item) + self.tableWidgetInboxChans.setHorizontalHeaderItem(1, item) item = QtGui.QTableWidgetItem() - self.tableWidgetInbox_2.setHorizontalHeaderItem(2, item) + self.tableWidgetInboxChans.setHorizontalHeaderItem(2, item) item = QtGui.QTableWidgetItem() - self.tableWidgetInbox_2.setHorizontalHeaderItem(3, item) - self.tableWidgetInbox_2.horizontalHeader().setCascadingSectionResizes(True) - self.tableWidgetInbox_2.horizontalHeader().setDefaultSectionSize(200) - self.tableWidgetInbox_2.horizontalHeader().setHighlightSections(False) - self.tableWidgetInbox_2.horizontalHeader().setMinimumSectionSize(27) - self.tableWidgetInbox_2.horizontalHeader().setSortIndicatorShown(False) - self.tableWidgetInbox_2.horizontalHeader().setStretchLastSection(True) - self.tableWidgetInbox_2.verticalHeader().setVisible(False) - self.tableWidgetInbox_2.verticalHeader().setDefaultSectionSize(26) - self.verticalLayout_13.addWidget(self.tableWidgetInbox_2) - self.textEditInboxMessage_2 = QtGui.QTextEdit(self.tab_3) - self.textEditInboxMessage_2.setBaseSize(QtCore.QSize(0, 500)) - self.textEditInboxMessage_2.setReadOnly(True) - self.textEditInboxMessage_2.setObjectName(_fromUtf8("textEditInboxMessage_2")) - self.verticalLayout_13.addWidget(self.textEditInboxMessage_2) - self.horizontalLayout_4.addLayout(self.verticalLayout_13) - self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) + 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.verticalLayout_8.addWidget(self.tableWidgetInboxChans) + self.textEditInboxMessageChans = QtGui.QTextEdit(self.tab_3) + self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500)) + self.textEditInboxMessageChans.setReadOnly(True) + self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans")) + self.verticalLayout_8.addWidget(self.textEditInboxMessageChans) + self.horizontalLayout_7.addLayout(self.verticalLayout_8) + self.gridLayout_4.addLayout(self.horizontalLayout_7, 0, 0, 1, 1) icon8 = QtGui.QIcon() icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tabWidget.addTab(self.tab_3, icon8, _fromUtf8("")) @@ -598,6 +624,11 @@ class Ui_MainWindow(object): self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) self.pushButtonNewAddress.setText(_translate("MainWindow", "New Indentitiy", 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.tableWidgetInbox.setSortingEnabled(True) item = self.tableWidgetInbox.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "To", None)) @@ -610,7 +641,7 @@ class Ui_MainWindow(object): self.tabWidget.setTabText(self.tabWidget.indexOf(self.inbox), _translate("MainWindow", "Messages", None)) self.tableWidgetAddressBook.setSortingEnabled(True) item = self.tableWidgetAddressBook.horizontalHeaderItem(0) - item.setText(_translate("MainWindow", "Name", None)) + item.setText(_translate("MainWindow", "Address book", None)) item = self.tableWidgetAddressBook.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "Address", None)) self.pushButtonAddAddressBook.setText(_translate("MainWindow", "Add Contact", None)) @@ -638,7 +669,12 @@ class Ui_MainWindow(object): 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.inboxSearchLineSubscriptions.setPlaceholderText(_translate("MainWindow", "Search", 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)) @@ -649,17 +685,22 @@ class Ui_MainWindow(object): item = self.tableWidgetInboxSubscriptions.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.subscriptions), _translate("MainWindow", "Subscriptions", None)) - self.treeWidgetChanList.headerItem().setText(0, _translate("MainWindow", "Chans", None)) - self.pushButtonAddChanel.setText(_translate("MainWindow", "Add Chanel", None)) - self.inboxSearchLineEdit_2.setPlaceholderText(_translate("MainWindow", "Search", None)) - self.tableWidgetInbox_2.setSortingEnabled(True) - item = self.tableWidgetInbox_2.horizontalHeaderItem(0) + 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.tableWidgetInbox_2.horizontalHeaderItem(1) + item = self.tableWidgetInboxChans.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "From", None)) - item = self.tableWidgetInbox_2.horizontalHeaderItem(2) + item = self.tableWidgetInboxChans.horizontalHeaderItem(2) item.setText(_translate("MainWindow", "Subject", None)) - item = self.tableWidgetInbox_2.horizontalHeaderItem(3) + item = self.tableWidgetInboxChans.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Chans", None)) self.radioButtonBlacklist.setText(_translate("MainWindow", "Use a Blacklist (Allow all incoming messages except those on the Blacklist)", None)) diff --git a/src/bitmessageqt/bitmessageui.ui b/src/bitmessageqt/bitmessageui.ui index d07b7388..fef40be6 100644 --- a/src/bitmessageqt/bitmessageui.ui +++ b/src/bitmessageqt/bitmessageui.ui @@ -105,7 +105,7 @@ - + @@ -118,6 +118,35 @@ + + + + + All + + + + + To + + + + + From + + + + + Subject + + + + + Message + + + + @@ -255,7 +284,7 @@ - Name + Address book @@ -573,7 +602,6 @@ p, li { white-space: pre-wrap; } - pushButtonFetchNamecoinID @@ -583,9 +611,9 @@ p, li { white-space: pre-wrap; } Subscriptions - + - + @@ -635,11 +663,44 @@ p, li { white-space: pre-wrap; } - - - Search - - + + + + + Search + + + + + + + + All + + + + + To + + + + + From + + + + + Subject + + + + + Message + + + + + @@ -708,7 +769,7 @@ p, li { white-space: pre-wrap; } - + 0 @@ -734,13 +795,13 @@ p, li { white-space: pre-wrap; } Chans - + - + - + 200 @@ -775,7 +836,7 @@ p, li { white-space: pre-wrap; } - + 200 @@ -783,30 +844,56 @@ p, li { white-space: pre-wrap; } - Add Chanel + Add Chan - + - - - 0 - + - + Search + + + + + All + + + + + To + + + + + From + + + + + Subject + + + + + Message + + + + - + QAbstractItemView::NoEditTriggers @@ -872,7 +959,7 @@ p, li { white-space: pre-wrap; } - + 0 -- 2.45.1 From 69309b82fb90efdd97793968d16607b4cde32c36 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 20 Jun 2015 09:54:15 +0200 Subject: [PATCH 0009/1102] Minor changes in cli, PoW, and a couple of new api calls. --- src/api.py | 391 +++++++++++++++++++++++++++++------------ src/bitmessagecli.py | 68 +++++++ src/class_sqlThread.py | 2 +- src/openclpow.py | 14 +- src/proofofwork.py | 9 +- 5 files changed, 364 insertions(+), 120 deletions(-) diff --git a/src/api.py b/src/api.py index f142953b..a5ae7f5a 100644 --- a/src/api.py +++ b/src/api.py @@ -26,7 +26,7 @@ from pyelliptic.openssl import OpenSSL from struct import pack # Classes -from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute +from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger # Helper Functions @@ -149,16 +149,218 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return (status, addressVersionNumber, streamNumber, ripe) + def _handle_request(self, method, params): + if method == 'helloWorld': + (a, b) = params + return a + '-' + b + elif method == 'add': + (a, b) = params + return a + b + elif method == 'statusBar': + message, = params + shared.UISignalQueue.put(('updateStatusBar', message)) + elif method == 'listAddresses' or method == 'listAddresses2': + data = '{"addresses":[' + 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 + elif method == 'listAddressBookEntries' or method == 'listAddressbook': # the listAddressbook alias should be removed eventually. + queryreturn = sqlQuery('''SELECT label, address from addressbook''') + 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") + data = '{"addresses":[' + for row in queryreturn: + label, address = row + label = shared.fixPotentiallyInvalidUTF8Data(label) + if len(data) > 20: + data += ',' + data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) + data += ']}' + return data + elif method == 'getAddressBookEntry': # search by label + if len(params) != 1: + raise APIError(0, "I need a label") + label, = params + label = self._decode(label, "base64") + queryreturn = sqlQuery('''SELECT label, address from addressbook WHERE label = ?''', label) + data = '{"address":[' + for row in queryreturn: + label, address = row + label = shared.fixPotentiallyInvalidUTF8Data(label) + if len(data) > 20: + data += ',' + data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) + data += ']}' + return data + + elif method == 'addAddressBookEntry' or method == 'addAddressbook': # the addAddressbook alias should be deleted eventually. + if len(params) != 2: + raise APIError(0, "I need label and address") + address, label = params + label = self._decode(label, "base64") + address = addBMIfNotPresent(address) + self._verifyAddress(address) + queryreturn = sqlQuery("SELECT address FROM addressbook WHERE address=?", address) + if queryreturn != []: + raise APIError(16, 'You already have this address in your address book.') - #Request Handlers - - def HandleListAddresses(self, method): - data = '{"addresses":[' - configSections = shared.config.sections() - for addressInKeysFile in configSections: - if addressInKeysFile != 'bitmessagesettings': - status, addressVersionNumber, streamNumber, hash01 = decodeAddress( - addressInKeysFile) + sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderAddressBook','')) + return "Added address %s to address book" % address + elif method == 'deleteAddressBookEntry' or method == 'deleteAddressbook': # The deleteAddressbook alias should be deleted eventually. + if len(params) != 1: + raise APIError(0, "I need an address") + address, = params + address = addBMIfNotPresent(address) + self._verifyAddress(address) + sqlExecute('DELETE FROM addressbook WHERE address=?', address) + shared.UISignalQueue.put(('rerenderInboxFromLabels','')) + shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderAddressBook','')) + return "Deleted address book entry for %s if it existed" % address + elif method == 'createRandomAddress': + if len(params) == 0: + raise APIError(0, 'I need parameters!') + elif len(params) == 1: + label, = params + eighteenByteRipe = False + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 2: + label, eighteenByteRipe = params + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 3: + label, eighteenByteRipe, totalDifficulty = params + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 4: + label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = int( + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + else: + raise APIError(0, 'Too many parameters!') + label = self._decode(label, "base64") + try: + unicode(label, 'utf-8') + except: + raise APIError(17, 'Label is not valid UTF-8 data.') + shared.apiAddressGeneratorReturnQueue.queue.clear() + streamNumberForAddress = 1 + shared.addressGeneratorQueue.put(( + 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) + return shared.apiAddressGeneratorReturnQueue.get() + elif method == 'createDeterministicAddresses': + if len(params) == 0: + raise APIError(0, 'I need parameters!') + elif len(params) == 1: + passphrase, = params + numberOfAddresses = 1 + addressVersionNumber = 0 + streamNumber = 0 + eighteenByteRipe = False + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 2: + passphrase, numberOfAddresses = params + addressVersionNumber = 0 + streamNumber = 0 + eighteenByteRipe = False + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 3: + passphrase, numberOfAddresses, addressVersionNumber = params + streamNumber = 0 + eighteenByteRipe = False + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 4: + passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params + eighteenByteRipe = False + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 5: + passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params + nonceTrialsPerByte = shared.config.get( + 'bitmessagesettings', 'defaultnoncetrialsperbyte') + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 6: + passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = shared.config.get( + 'bitmessagesettings', 'defaultpayloadlengthextrabytes') + elif len(params) == 7: + passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params + nonceTrialsPerByte = int( + shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + payloadLengthExtraBytes = int( + shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + else: + raise APIError(0, 'Too many parameters!') + if len(passphrase) == 0: + raise APIError(1, 'The specified passphrase is blank.') + if not isinstance(eighteenByteRipe, bool): + raise APIError(23, 'Bool expected in eighteenByteRipe, saw %s instead' % type(eighteenByteRipe)) + passphrase = self._decode(passphrase, "base64") + if addressVersionNumber == 0: # 0 means "just use the proper addressVersionNumber" + addressVersionNumber = 4 + if addressVersionNumber != 3 and addressVersionNumber != 4: + raise APIError(2,'The address version number currently must be 3, 4, or 0 (which means auto-select). ' + addressVersionNumber + ' isn\'t supported.') + if streamNumber == 0: # 0 means "just use the most available stream" + streamNumber = 1 + if streamNumber != 1: + raise APIError(3,'The stream number must be 1 (or 0 which means auto-select). Others aren\'t supported.') + if numberOfAddresses == 0: + 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.') + shared.apiAddressGeneratorReturnQueue.queue.clear() + logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) + shared.addressGeneratorQueue.put( + ('createDeterministicAddresses', addressVersionNumber, streamNumber, + 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) + data = '{"addresses":[' + queueReturn = shared.apiAddressGeneratorReturnQueue.get() + for item in queueReturn: if len(data) > 20: data += ',' if shared.config.has_option(addressInKeysFile, 'chan'): @@ -908,108 +1110,73 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): '''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 2 ; ''') with SqlBulkExecute() as sql: for row in queryreturn: - hash01, payload = row - readPosition = 16 # Nonce length + time length - readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length - t = (payload[readPosition:readPosition+32],hash01) - sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t) - - queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''', - requestedHash) - data = '{"receivedMessageDatas":[' - for row in queryreturn: - payload, = row - if len(data) > 25: - data += ',' - data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data - - def HandleClientStatus(self, params): - if len(shared.connectedHostsList) == 0: - networkStatus = 'notConnected' - elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: - networkStatus = 'connectedButHaveNotReceivedIncomingConnections' - else: - networkStatus = 'connectedAndReceivingIncomingConnections' - 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. - if len(params) != 1: - raise APIError(0, 'I need 1 parameter!') - address, = params - status, addressVersion, streamNumber, ripe = decodeAddress(address) - return json.dumps({'status':status, 'addressVersion':addressVersion, - 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, - separators=(',', ': ')) - - def HandleHelloWorld(self, params): - (a, b) = params - return a + '-' + b - - def HandleAdd(self, params): - (a, b) = params - return a + b - - def HandleStatusBar(self, params): - message, = params - shared.UISignalQueue.put(('updateStatusBar', message)) - - - handlers = {} - handlers['helloWorld'] = HandleHelloWorld - handlers['add'] = HandleAdd - handlers['statusBar'] = HandleStatusBar - handlers['listAddresses'] = HandleListAddresses - handlers['listAddressBookEntries'] = HandleListAddressBookEntries; - handlers['listAddressbook'] = HandleListAddressBookEntries # the listAddressbook alias should be removed eventually. - handlers['addAddressBookEntry'] = HandleAddAddressBookEntry - handlers['addAddressbook'] = HandleAddAddressBookEntry # the addAddressbook alias should be deleted eventually. - handlers['deleteAddressBookEntry'] = HandleDeleteAddressBookEntry - handlers['deleteAddressbook'] = HandleDeleteAddressBookEntry # The deleteAddressbook alias should be deleted eventually. - handlers['createRandomAddress'] = HandleCreateRandomAddress - handlers['createDeterministicAddresses'] = HandleCreateDeterministicAddresses - handlers['getDeterministicAddress'] = HandleGetDeterministicAddress - handlers['createChan'] = HandleCreateChan - handlers['joinChan'] = HandleJoinChan - handlers['leaveChan'] = HandleLeaveChan - handlers['deleteAddress'] = HandleDeleteAddress - handlers['getAllInboxMessages'] = HandleGetAllInboxMessages - handlers['getAllInboxMessageIds'] = HandleGetAllInboxMessageIds - handlers['getAllInboxMessageIDs'] = HandleGetAllInboxMessageIds - handlers['getInboxMessageById'] = HandleGetInboxMessageById - handlers['getInboxMessageByID'] = HandleGetInboxMessageById - handlers['getAllSentMessages'] = HandleGetAllSentMessages - handlers['getAllSentMessageIds'] = HandleGetAllSentMessageIds - handlers['getAllSentMessageIDs'] = HandleGetAllSentMessageIds - handlers['getInboxMessagesByReceiver'] = HandleInboxMessagesByReceiver - handlers['getInboxMessagesByAddress'] = HandleInboxMessagesByReceiver #after some time getInboxMessagesByAddress should be removed - handlers['getSentMessageById'] = HandleGetSentMessageById - handlers['getSentMessageByID'] = HandleGetSentMessageById - handlers['getSentMessagesByAddress'] = HandleGetSentMessagesByAddress - handlers['getSentMessagesBySender'] = HandleGetSentMessagesByAddress - handlers['getSentMessageByAckData'] = HandleGetSentMessagesByAckData - handlers['trashMessage'] = HandleTrashMessage - handlers['trashInboxMessage'] = HandleTrashInboxMessage - handlers['trashSentMessage'] = HandleTrashSentMessage - handlers['trashSentMessageByAckData'] = HandleTrashSentMessageByAckDAta - handlers['sendMessage'] = HandleSendMessage - handlers['sendBroadcast'] = HandleSendBroadcast - handlers['getStatus'] = HandleGetStatus - handlers['addSubscription'] = HandleAddSubscription - handlers['deleteSubscription'] = HandleDeleteSubscription - handlers['listSubscriptions'] = ListSubscriptions - handlers['disseminatePreEncryptedMsg'] = HandleDisseminatePreEncryptedMsg - handlers['disseminatePubkey'] = HandleDissimatePubKey - handlers['getMessageDataByDestinationHash'] = HandleGetMessageDataByDestinationHash - handlers['getMessageDataByDestinationTag'] = HandleGetMessageDataByDestinationHash - handlers['clientStatus'] = HandleClientStatus - handlers['decodeAddress'] = HandleDecodeAddress - - def _handle_request(self, method, params): - if (self.handlers.has_key(method)): - return self.handlers[method](self ,params) + transmitdata, = row + data += json.dumps({'data':transmitdata.encode('hex')}, indent=4, separators=(',', ': ')) + data += ']}' + return data + elif method == 'clientStatus': + if len(shared.connectedHostsList) == 0: + networkStatus = 'notConnected' + elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: + networkStatus = 'connectedButHaveNotReceivedIncomingConnections' + else: + networkStatus = 'connectedAndReceivingIncomingConnections' + 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=(',', ': ')) + elif method == 'decodeAddress': + # Return a meaningful decoding of an address. + if len(params) != 1: + raise APIError(0, 'I need 1 parameter!') + address, = params + status, addressVersion, streamNumber, ripe = decodeAddress(address) + return json.dumps({'status':status, 'addressVersion':addressVersion, + 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, + separators=(',', ': ')) + elif method == 'getInboxCount': + #queryreturn = sqlQuery('''SELECT read, received < 'now' - 60 AS old, COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' GROUP BY read, old''') + ret = {} + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 0 AND received < 'now' - 60''') + for row in queryreturn: + count, = row + ret['oldread'] = count + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 1 AND received < 'now' - 60''') + for row in queryreturn: + count, = row + ret['oldunread'] = count + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 0 AND received >= 'now' - 60''') + for row in queryreturn: + count, = row + ret['newread'] = count + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 1 AND received >= 'now' - 60''') + for row in queryreturn: + count, = row + ret['newunread'] = count + data = '{"inboxCount":{' + for key in ret: + val = ret[key] + if len(data) > 16: + data += ',' + data += json.dumps({key:val}, indent=4, separators=(',', ': ')) + data += '}}' + elif method == 'getSentCount': + ret = {} + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM sent WHERE folder = 'sent' AND status = 'msgqueued' ''') + for row in queryreturn: + count, = row + ret['queued'] = count + queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM sent WHERE folder = 'sent' AND status = 'msgsent' ''') + for row in queryreturn: + count, = row + ret['awaitingack'] = count + data = '{"sentCount":{' + for key in ret: + val = ret[key] + if len(data) > 15: + data += ',' + data += json.dumps({key:val}, indent=4, separators=(',', ': ')) + data += '}}' + elif method == 'deleteAndVacuum': + sqlStoredProcedure('deleteandvacuume') + return 'done' else: raise APIError(20, 'Invalid method: %s' % method) diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index cfe892b6..87d71f05 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -575,6 +575,46 @@ def genAdd(lbl,deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe): # 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: + generatedAddress = api.createRandomAddress(addressLabel) + 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 ~ @@ -1249,6 +1289,19 @@ def markAllMessagesUnread(): 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 UI(usrInput): #Main user menu global usrPrompt @@ -1665,6 +1718,21 @@ def UI(usrInput): #Main user menu markAllMessagesUnread() usrPrompt = 1 main() + + elif usrInput == "status": + clientStatus() + 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' diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 514f772e..f0862591 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -450,7 +450,7 @@ class sqlThread(threading.Thread): queryreturn = self.cur.fetchall() for row in queryreturn: value, = row - if int(value) < int(time.time()) - 2592000: + if int(value) < int(time.time()) - 86400: logger.info('It has been a long time since the messages.dat file has been vacuumed. Vacuuming now...') try: self.cur.execute( ''' VACUUM ''') diff --git a/src/openclpow.py b/src/openclpow.py index 0876aa79..bd9dad3b 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -2,6 +2,7 @@ import numpy from struct import pack, unpack import time import hashlib +import random import pyopencl as cl hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) @@ -14,7 +15,7 @@ try: ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) - f = open('kernel.cl', 'r') + f = open('/usr/src/PyBitmessage/src/kernel.cl', 'r') fstr = ''.join(f.readlines()) program = cl.Program(ctx, fstr).build() except: @@ -42,7 +43,10 @@ def do_opencl_pow(hash, target): kernel.set_arg(1, dest_buf) start = time.time() + #startpos = random.getrandbits(32) << 32 | random.getrandbits(32) + #startpos = random.getrandbits(32) startpos = 0 + progress = 0 globamt = worksize*2000 while output[0][0] == 0: @@ -50,17 +54,19 @@ def do_opencl_pow(hash, target): cl.enqueue_nd_range_kernel(queue, kernel, (globamt,), (worksize,)) cl.enqueue_read_buffer(queue, dest_buf, output) queue.finish() + #startpos == (globamt + startpos) & 0xFFFFFFFFFFFFFFFF startpos += globamt + progress += globamt sofar = time.time() - start - print sofar, startpos / sofar, "hashes/sec" + print sofar, progress / sofar, "hashes/sec" taken = time.time() - start - print startpos, taken + print progress, taken return output[0][0] if __name__ == "__main__": target = 54227212183L initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex") - nonce = do_pow(initialHash.encode("hex"), target) + nonce = 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) diff --git a/src/proofofwork.py b/src/proofofwork.py index f05e7eea..fec70287 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -6,7 +6,7 @@ from struct import unpack, pack import sys from shared import config, frozen import shared -from openclpow import do_opencl_pow +import openclpow #import os def _set_idle(): @@ -33,6 +33,7 @@ def _pool_worker(nonce, initialHash, target, pool_size): return [trialValue, nonce] def _doSafePoW(target, initialHash): + print "Safe POW\n" nonce = 0 trialValue = float('inf') while trialValue > target: @@ -41,6 +42,7 @@ def _doSafePoW(target, initialHash): return [trialValue, nonce] def _doFastPoW(target, initialHash): + print "Fast POW\n" import time from multiprocessing import Pool, cpu_count try: @@ -72,13 +74,14 @@ def _doFastPoW(target, initialHash): time.sleep(0.2) def _doGPUPow(target, initialHash): - nonce = do_opencl_pow(initialHash.encode("hex"), target) + print "GPU POW\n" + 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) return [trialValue, nonce] def run(target, initialHash): - if has_opencl: + if openclpow.has_opencl(): return _doGPUPow(target, initialHash) elif frozen == "macosx_app" or not frozen: return _doFastPoW(target, initialHash) -- 2.45.1 From bd7c3e6e012ef2018c2a248e0d12f3c57b03eee7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 20 Jun 2015 10:17:39 +0200 Subject: [PATCH 0010/1102] Reverted the code that tried to randomise starting PoW position. The problem wasn't caused by the starting position but by an int being interpreted as a string. Fixed in upstream and merged. --- src/openclpow.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/openclpow.py b/src/openclpow.py index bd9dad3b..83d7513f 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -43,19 +43,14 @@ def do_opencl_pow(hash, target): kernel.set_arg(1, dest_buf) start = time.time() - #startpos = random.getrandbits(32) << 32 | random.getrandbits(32) - #startpos = random.getrandbits(32) - startpos = 0 progress = 0 globamt = worksize*2000 while output[0][0] == 0: - kernel.set_arg(2, pack(" Date: Sat, 22 Aug 2015 16:48:49 +0800 Subject: [PATCH 0011/1102] Add UPnP support. --- src/bitmessagemain.py | 6 +- src/shared.py | 4 +- src/upnp.py | 198 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 src/upnp.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index bf1d74f2..daae1af9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2.7 +#!/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 @@ -44,6 +44,7 @@ from debug import logger # Helper Functions import helper_bootstrap import helper_generic +import upnp def connectToStream(streamNumber): @@ -145,6 +146,9 @@ class Main: # is the application already running? If yes then exit. thisapp = singleton.singleinstance() + import upnp + upnp.createPortMapping() + # get curses flag curses = False if '-c' in sys.argv: diff --git a/src/shared.py b/src/shared.py index d82f00a5..5351947f 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,4 +1,4 @@ -from __future__ import division +from __future__ import division softwareVersion = '0.4.4' verbose = 1 @@ -370,6 +370,8 @@ def doCleanShutdown(): '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: diff --git a/src/upnp.py b/src/upnp.py new file mode 100644 index 00000000..5104ea34 --- /dev/null +++ b/src/upnp.py @@ -0,0 +1,198 @@ +# A simple upnp module to forward port for BitMessage +# Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port +import socket +import httplib +from shared import config + +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() + + # create the envelope element and set its attributes + envelope = doc.createElementNS('', 's:Envelope') + envelope.setAttribute('xmlns:s', 'http://schemas.xmlsoap.org/soap/envelope/') + envelope.setAttribute('s:encodingStyle', 'http://schemas.xmlsoap.org/soap/encoding/') + + # create the body element + body = doc.createElementNS('', 's:Body') + + # create the function element and set its attribute + fn = doc.createElementNS('', 'u:%s' % action) + fn.setAttribute('xmlns:u', 'urn:schemas-upnp-org:service:%s' % service) + + # setup the argument element names and values + # using a list of tuples to preserve order + + # container for created nodes + argument_list = [] + + # iterate over arguments, create nodes, create text nodes, + # append text nodes to nodes, and finally add the ready product + # to argument_list + 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: + fn.appendChild(arg) + + # append function element to the body element + body.appendChild(fn) + + # append body element to envelope element + envelope.appendChild(body) + + # append envelope element to document, making it the root element + doc.appendChild(envelope) + + # our tree is ready, conver it to a string + return doc.toxml() + +class UPnPError(Exception): + def __init__(self, message): + self.message + +class Router: + name = "" + path = "" + address = None + routerPath = None + def __init__(self, ssdpResponse, address): + import urllib2 + from xml.dom.minidom import parseString + from urlparse import urlparse + + self.address = address + + row = ssdpResponse.split('\r\n') + header = {} + for i in range(1, len(row)): + part = row[i].split(': ') + if len(part) == 2: + header[part[0].lower()] = part[1] + + self.routerPath = urlparse(header['location']) + + # get the profile xml file and read it into a variable + directory = urllib2.urlopen(header['location']).read() + + # create a DOM object that represents the `directory` document + dom = parseString(directory) + + self.name = dom.getElementsByTagName('friendlyName')[0].childNodes[0].data + # find all 'serviceType' elements + service_types = dom.getElementsByTagName('serviceType') + + for service in service_types: + if service.childNodes[0].data.find('WANIPConnection') > 0: + self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data + + def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): + resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ + ('NewExternalPort', str(externalPort)), + ('NewProtocol', protocol), + ('NewInternalPort', str(internalPort)), + ('NewInternalClient', internalClient), + ('NewEnabled', str(enabled)), + ('NewPortMappingDescription', str(description)), + ('NewLeaseDuration', str(leaseDuration)) + ]) + return resp + + def DeletePortMapping(self, externalPort, protocol): + resp = self.soapRequest('WANIPConnection:1', 'DeletePortMapping', [ + ('NewExternalPort', str(externalPort)), + ('NewProtocol', protocol), + ]) + return resp + + def GetExternalIPAddress(self): + from xml.dom.minidom import parseString + resp = self.soapRequest('WANIPConnection:1', 'GetExternalIPAddress') + dom = parseString(resp) + return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data + + def soapRequest(self, service, action, arguments=[]): + from xml.dom.minidom import parseString + conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) + conn.request( + 'POST', + self.path, + createRequestXML(service, action, arguments), + { + 'SOAPAction': '"urn:schemas-upnp-org:service:%s#%s"' % (service, action), + 'Content-Type': 'text/xml' + } + ) + resp = conn.getresponse().read() + dom = parseString(resp) + errinfo = dom.getElementsByTagName('errorDescription') + if len(errinfo) > 0: + raise UPnPError(errinfo[0].childNodes[0].data) + return resp + + +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') -- 2.45.1 From d3345e051a9af8484bee2b9a06defb089feab3a8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 28 Sep 2015 20:22:54 +0200 Subject: [PATCH 0012/1102] Add: debugging for freezing api call --- src/api.py | 219 ++++++++++++++++++++++++----------------------------- 1 file changed, 98 insertions(+), 121 deletions(-) diff --git a/src/api.py b/src/api.py index a5ae7f5a..b73f6f28 100644 --- a/src/api.py +++ b/src/api.py @@ -565,127 +565,104 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) return shared.apiAddressGeneratorReturnQueue.get() - def HandleCreateChan(self, params): - if len(params) == 0: - raise APIError(0, 'I need parameters.') - elif len(params) == 1: - passphrase, = params - passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: - raise APIError(1, 'The specified passphrase is blank.') - # It would be nice to make the label the passphrase but it is - # possible that the passphrase contains non-utf-8 characters. - try: - unicode(passphrase, 'utf-8') - label = str_chan + ' ' + passphrase - except: - label = str_chan + ' ' + repr(passphrase) - - addressVersionNumber = 4 - streamNumber = 1 - shared.apiAddressGeneratorReturnQueue.queue.clear() - logger.debug('Requesting that the addressGenerator create chan %s.', passphrase) - 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] - return address - - def HandleJoinChan(self, params): - if len(params) < 2: - raise APIError(0, 'I need two parameters.') - elif len(params) == 2: - passphrase, suppliedAddress= params - passphrase = self._decode(passphrase, "base64") - if len(passphrase) == 0: - raise APIError(1, 'The specified passphrase is blank.') - # It would be nice to make the label the passphrase but it is - # possible that the passphrase contains non-utf-8 characters. - try: - unicode(passphrase, 'utf-8') - label = str_chan + ' ' + passphrase - except: - label = str_chan + ' ' + repr(passphrase) - - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(suppliedAddress) - suppliedAddress = addBMIfNotPresent(suppliedAddress) - shared.apiAddressGeneratorReturnQueue.queue.clear() - shared.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase)) - addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() - - 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.') - #TODO: this variable is not used to anything - createdAddress = addressGeneratorReturnValue[0] # in case we ever want it for anything. - return "success" - - def HandleLeaveChan(self, params): - if len(params) == 0: - raise APIError(0, 'I need parameters.') - elif len(params) == 1: - address, = params - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) - address = addBMIfNotPresent(address) - if not shared.config.has_section(address): - raise APIError(13, 'Could not find this address in your keys.dat file.') - if not shared.safeConfigGetBoolean(address, 'chan'): - raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') - shared.config.remove_section(address) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) - return 'success' - - def HandleDeleteAddress(self, params): - if len(params) == 0: - raise APIError(0, 'I need parameters.') - elif len(params) == 1: - address, = params - status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) - address = addBMIfNotPresent(address) - if not shared.config.has_section(address): - raise APIError(13, 'Could not find this address in your keys.dat file.') - 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' - - def HandleGetAllInboxMessages(self, params): - queryreturn = sqlQuery( - '''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''') - data = '{"inboxMessages":[' - for row in queryreturn: - msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - message = shared.fixPotentiallyInvalidUTF8Data(message) - if len(data) > 25: - data += ',' - 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 - - def HandleGetAllInboxMessageIds(self, params): - queryreturn = sqlQuery( - '''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''') - data = '{"inboxMessageIds":[' - for row in queryreturn: - msgid = row[0] - if len(data) > 25: - data += ',' - data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data - - def HandleGetInboxMessageById(self, params): - if len(params) == 0: - raise APIError(0, 'I need parameters!') - elif len(params) == 1: + elif method == 'getAllInboxMessages': + queryreturn = sqlQuery( + '''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''') + data = '{"inboxMessages":[' + for row in queryreturn: + msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + message = shared.fixPotentiallyInvalidUTF8Data(message) + if len(data) > 25: + data += ',' + 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 + elif method == 'getAllInboxMessageIds' or method == 'getAllInboxMessageIDs': + queryreturn = sqlQuery( + '''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''') + data = '{"inboxMessageIds":[' + for row in queryreturn: + msgid = row[0] + if len(data) > 25: + data += ',' + data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) + data += ']}' + return data + elif method == 'getInboxMessageById' or method == 'getInboxMessageByID': + if len(params) == 0: + raise APIError(0, 'I need parameters!') + elif len(params) == 1: + msgid = self._decode(params[0], "hex") + elif len(params) >= 2: + msgid = self._decode(params[0], "hex") + readStatus = params[1] + if not isinstance(readStatus, bool): + raise APIError(23, 'Bool expected in readStatus, saw %s instead.' % type(readStatus)) + queryreturn = sqlQuery('''SELECT read FROM inbox WHERE msgid=?''', msgid) + # 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) + 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':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 + elif method == 'getAllSentMessages': + import pprint + try: + queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent where folder='sent' ORDER BY lastactiontime''') + except: + print "Exception in getallSentMessages" + pprint.pprint (queryreturn) + data = '{"sentMessages":[' + if type(queryreturn) is list: + for row in queryreturn: + msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + message = shared.fixPotentiallyInvalidUTF8Data(message) + if len(data) > 25: + data += ',' + 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=(',', ': ')) + else: + print "queryreturn is not a list" + pprint.pprint (queryreturn) + data += ']}' + return data + elif method == 'getAllSentMessageIds' or method == 'getAllSentMessageIDs': + queryreturn = sqlQuery('''SELECT msgid FROM sent where folder='sent' ORDER BY lastactiontime''') + data = '{"sentMessageIds":[' + for row in queryreturn: + msgid = row[0] + if len(data) > 25: + data += ',' + data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': ')) + data += ']}' + return data + elif method == 'getInboxMessagesByReceiver' or method == 'getInboxMessagesByAddress': #after some time getInboxMessagesByAddress should be removed + if len(params) == 0: + raise APIError(0, 'I need parameters!') + toAddress = params[0] + queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype FROM inbox WHERE folder='inbox' AND toAddress=?''', toAddress) + data = '{"inboxMessages":[' + for row in queryreturn: + msgid, toAddress, fromAddress, subject, received, message, encodingtype = row + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + message = shared.fixPotentiallyInvalidUTF8Data(message) + if len(data) > 25: + data += ',' + 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 + elif method == 'getSentMessageById' or method == 'getSentMessageByID': + if len(params) == 0: + raise APIError(0, 'I need parameters!') msgid = self._decode(params[0], "hex") elif len(params) >= 2: msgid = self._decode(params[0], "hex") -- 2.45.1 From bde5bfc42ea4c49e8bc9c43c0bbad2082ff6c8df Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 28 Sep 2015 20:55:40 +0200 Subject: [PATCH 0013/1102] Add: re-merge API changes API handler was rewritten in upstream, previous merge overwrote the changse. This re-enables them. --- src/api.py | 621 +++++++++++++++++++++-------------------------------- 1 file changed, 244 insertions(+), 377 deletions(-) diff --git a/src/api.py b/src/api.py index b73f6f28..20568ffc 100644 --- a/src/api.py +++ b/src/api.py @@ -149,218 +149,16 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return (status, addressVersionNumber, streamNumber, ripe) - def _handle_request(self, method, params): - if method == 'helloWorld': - (a, b) = params - return a + '-' + b - elif method == 'add': - (a, b) = params - return a + b - elif method == 'statusBar': - message, = params - shared.UISignalQueue.put(('updateStatusBar', message)) - elif method == 'listAddresses' or method == 'listAddresses2': - data = '{"addresses":[' - 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 - elif method == 'listAddressBookEntries' or method == 'listAddressbook': # the listAddressbook alias should be removed eventually. - queryreturn = sqlQuery('''SELECT label, address from addressbook''') - 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") - data = '{"addresses":[' - for row in queryreturn: - label, address = row - label = shared.fixPotentiallyInvalidUTF8Data(label) - if len(data) > 20: - data += ',' - data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) - data += ']}' - return data - elif method == 'getAddressBookEntry': # search by label - if len(params) != 1: - raise APIError(0, "I need a label") - label, = params - label = self._decode(label, "base64") - queryreturn = sqlQuery('''SELECT label, address from addressbook WHERE label = ?''', label) - data = '{"address":[' - for row in queryreturn: - label, address = row - label = shared.fixPotentiallyInvalidUTF8Data(label) - if len(data) > 20: - data += ',' - data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) - data += ']}' - return data - - elif method == 'addAddressBookEntry' or method == 'addAddressbook': # the addAddressbook alias should be deleted eventually. - if len(params) != 2: - raise APIError(0, "I need label and address") - address, label = params - label = self._decode(label, "base64") - address = addBMIfNotPresent(address) - self._verifyAddress(address) - queryreturn = sqlQuery("SELECT address FROM addressbook WHERE address=?", address) - if queryreturn != []: - raise APIError(16, 'You already have this address in your address book.') - sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - shared.UISignalQueue.put(('rerenderInboxFromLabels','')) - shared.UISignalQueue.put(('rerenderSentToLabels','')) - shared.UISignalQueue.put(('rerenderAddressBook','')) - return "Added address %s to address book" % address - elif method == 'deleteAddressBookEntry' or method == 'deleteAddressbook': # The deleteAddressbook alias should be deleted eventually. - if len(params) != 1: - raise APIError(0, "I need an address") - address, = params - address = addBMIfNotPresent(address) - self._verifyAddress(address) - sqlExecute('DELETE FROM addressbook WHERE address=?', address) - shared.UISignalQueue.put(('rerenderInboxFromLabels','')) - shared.UISignalQueue.put(('rerenderSentToLabels','')) - shared.UISignalQueue.put(('rerenderAddressBook','')) - return "Deleted address book entry for %s if it existed" % address - elif method == 'createRandomAddress': - if len(params) == 0: - raise APIError(0, 'I need parameters!') - elif len(params) == 1: - label, = params - eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 2: - label, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 3: - label, eighteenByteRipe, totalDifficulty = params - nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 4: - label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params - nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) - else: - raise APIError(0, 'Too many parameters!') - label = self._decode(label, "base64") - try: - unicode(label, 'utf-8') - except: - raise APIError(17, 'Label is not valid UTF-8 data.') - shared.apiAddressGeneratorReturnQueue.queue.clear() - streamNumberForAddress = 1 - shared.addressGeneratorQueue.put(( - 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) - return shared.apiAddressGeneratorReturnQueue.get() - elif method == 'createDeterministicAddresses': - if len(params) == 0: - raise APIError(0, 'I need parameters!') - elif len(params) == 1: - passphrase, = params - numberOfAddresses = 1 - addressVersionNumber = 0 - streamNumber = 0 - eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 2: - passphrase, numberOfAddresses = params - addressVersionNumber = 0 - streamNumber = 0 - eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 3: - passphrase, numberOfAddresses, addressVersionNumber = params - streamNumber = 0 - eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 4: - passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params - eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 5: - passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( - 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 6: - passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params - nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - elif len(params) == 7: - passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params - nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) - else: - raise APIError(0, 'Too many parameters!') - if len(passphrase) == 0: - raise APIError(1, 'The specified passphrase is blank.') - if not isinstance(eighteenByteRipe, bool): - raise APIError(23, 'Bool expected in eighteenByteRipe, saw %s instead' % type(eighteenByteRipe)) - passphrase = self._decode(passphrase, "base64") - if addressVersionNumber == 0: # 0 means "just use the proper addressVersionNumber" - addressVersionNumber = 4 - if addressVersionNumber != 3 and addressVersionNumber != 4: - raise APIError(2,'The address version number currently must be 3, 4, or 0 (which means auto-select). ' + addressVersionNumber + ' isn\'t supported.') - if streamNumber == 0: # 0 means "just use the most available stream" - streamNumber = 1 - if streamNumber != 1: - raise APIError(3,'The stream number must be 1 (or 0 which means auto-select). Others aren\'t supported.') - if numberOfAddresses == 0: - 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.') - shared.apiAddressGeneratorReturnQueue.queue.clear() - logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) - shared.addressGeneratorQueue.put( - ('createDeterministicAddresses', addressVersionNumber, streamNumber, - 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) - data = '{"addresses":[' - queueReturn = shared.apiAddressGeneratorReturnQueue.get() - for item in queueReturn: + #Request Handlers + + def HandleListAddresses(self, method): + data = '{"addresses":[' + 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'): @@ -376,7 +174,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleListAddressBookEntries(self, params): - queryreturn = sqlQuery('''SELECT label, address from addressbook''') + 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''') data = '{"addresses":[' for row in queryreturn: label, address = row @@ -565,104 +370,127 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) return shared.apiAddressGeneratorReturnQueue.get() - elif method == 'getAllInboxMessages': - queryreturn = sqlQuery( - '''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''') - data = '{"inboxMessages":[' - for row in queryreturn: - msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - message = shared.fixPotentiallyInvalidUTF8Data(message) - if len(data) > 25: - data += ',' - 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 - elif method == 'getAllInboxMessageIds' or method == 'getAllInboxMessageIDs': - queryreturn = sqlQuery( - '''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''') - data = '{"inboxMessageIds":[' - for row in queryreturn: - msgid = row[0] - if len(data) > 25: - data += ',' - data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data - elif method == 'getInboxMessageById' or method == 'getInboxMessageByID': - if len(params) == 0: - raise APIError(0, 'I need parameters!') - elif len(params) == 1: - msgid = self._decode(params[0], "hex") - elif len(params) >= 2: - msgid = self._decode(params[0], "hex") - readStatus = params[1] - if not isinstance(readStatus, bool): - raise APIError(23, 'Bool expected in readStatus, saw %s instead.' % type(readStatus)) - queryreturn = sqlQuery('''SELECT read FROM inbox WHERE msgid=?''', msgid) - # 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) - 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':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 - elif method == 'getAllSentMessages': - import pprint - try: - queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, lastactiontime, message, encodingtype, status, ackdata FROM sent where folder='sent' ORDER BY lastactiontime''') - except: - print "Exception in getallSentMessages" - pprint.pprint (queryreturn) - data = '{"sentMessages":[' - if type(queryreturn) is list: - for row in queryreturn: - msgid, toAddress, fromAddress, subject, lastactiontime, message, encodingtype, status, ackdata = row - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - message = shared.fixPotentiallyInvalidUTF8Data(message) - if len(data) > 25: - data += ',' - 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=(',', ': ')) - else: - print "queryreturn is not a list" - pprint.pprint (queryreturn) - data += ']}' - return data - elif method == 'getAllSentMessageIds' or method == 'getAllSentMessageIDs': - queryreturn = sqlQuery('''SELECT msgid FROM sent where folder='sent' ORDER BY lastactiontime''') - data = '{"sentMessageIds":[' - for row in queryreturn: - msgid = row[0] - if len(data) > 25: - data += ',' - data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data - elif method == 'getInboxMessagesByReceiver' or method == 'getInboxMessagesByAddress': #after some time getInboxMessagesByAddress should be removed - if len(params) == 0: - raise APIError(0, 'I need parameters!') - toAddress = params[0] - queryreturn = sqlQuery('''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype FROM inbox WHERE folder='inbox' AND toAddress=?''', toAddress) - data = '{"inboxMessages":[' - for row in queryreturn: - msgid, toAddress, fromAddress, subject, received, message, encodingtype = row - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - message = shared.fixPotentiallyInvalidUTF8Data(message) - if len(data) > 25: - data += ',' - 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 - elif method == 'getSentMessageById' or method == 'getSentMessageByID': - if len(params) == 0: - raise APIError(0, 'I need parameters!') + def HandleCreateChan(self, params): + if len(params) == 0: + raise APIError(0, 'I need parameters.') + elif len(params) == 1: + passphrase, = params + passphrase = self._decode(passphrase, "base64") + if len(passphrase) == 0: + raise APIError(1, 'The specified passphrase is blank.') + # It would be nice to make the label the passphrase but it is + # possible that the passphrase contains non-utf-8 characters. + try: + unicode(passphrase, 'utf-8') + label = str_chan + ' ' + passphrase + except: + label = str_chan + ' ' + repr(passphrase) + + addressVersionNumber = 4 + streamNumber = 1 + shared.apiAddressGeneratorReturnQueue.queue.clear() + logger.debug('Requesting that the addressGenerator create chan %s.', passphrase) + 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] + return address + + def HandleJoinChan(self, params): + if len(params) < 2: + raise APIError(0, 'I need two parameters.') + elif len(params) == 2: + passphrase, suppliedAddress= params + passphrase = self._decode(passphrase, "base64") + if len(passphrase) == 0: + raise APIError(1, 'The specified passphrase is blank.') + # It would be nice to make the label the passphrase but it is + # possible that the passphrase contains non-utf-8 characters. + try: + unicode(passphrase, 'utf-8') + label = str_chan + ' ' + passphrase + except: + label = str_chan + ' ' + repr(passphrase) + + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(suppliedAddress) + suppliedAddress = addBMIfNotPresent(suppliedAddress) + shared.apiAddressGeneratorReturnQueue.queue.clear() + shared.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase)) + addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() + + 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.') + #TODO: this variable is not used to anything + createdAddress = addressGeneratorReturnValue[0] # in case we ever want it for anything. + return "success" + + def HandleLeaveChan(self, params): + if len(params) == 0: + raise APIError(0, 'I need parameters.') + elif len(params) == 1: + address, = params + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) + address = addBMIfNotPresent(address) + if not shared.config.has_section(address): + raise APIError(13, 'Could not find this address in your keys.dat file.') + if not shared.safeConfigGetBoolean(address, 'chan'): + raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') + shared.config.remove_section(address) + with open(shared.appdata + 'keys.dat', 'wb') as configfile: + shared.config.write(configfile) + return 'success' + + def HandleDeleteAddress(self, params): + if len(params) == 0: + raise APIError(0, 'I need parameters.') + elif len(params) == 1: + address, = params + status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) + address = addBMIfNotPresent(address) + if not shared.config.has_section(address): + raise APIError(13, 'Could not find this address in your keys.dat file.') + 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' + + def HandleGetAllInboxMessages(self, params): + queryreturn = sqlQuery( + '''SELECT msgid, toaddress, fromaddress, subject, received, message, encodingtype, read FROM inbox where folder='inbox' ORDER BY received''') + data = '{"inboxMessages":[' + for row in queryreturn: + msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + message = shared.fixPotentiallyInvalidUTF8Data(message) + if len(data) > 25: + data += ',' + 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 + + def HandleGetAllInboxMessageIds(self, params): + queryreturn = sqlQuery( + '''SELECT msgid FROM inbox where folder='inbox' ORDER BY received''') + data = '{"inboxMessageIds":[' + for row in queryreturn: + msgid = row[0] + if len(data) > 25: + data += ',' + data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) + data += ']}' + return data + + def HandleGetInboxMessageById(self, params): + if len(params) == 0: + raise APIError(0, 'I need parameters!') + elif len(params) == 1: msgid = self._decode(params[0], "hex") elif len(params) >= 2: msgid = self._decode(params[0], "hex") @@ -1087,73 +915,112 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): '''SELECT hash, payload FROM inventory WHERE tag = '' and objecttype = 2 ; ''') with SqlBulkExecute() as sql: for row in queryreturn: - transmitdata, = row - data += json.dumps({'data':transmitdata.encode('hex')}, indent=4, separators=(',', ': ')) - data += ']}' - return data - elif method == 'clientStatus': - if len(shared.connectedHostsList) == 0: - networkStatus = 'notConnected' - elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: - networkStatus = 'connectedButHaveNotReceivedIncomingConnections' - else: - networkStatus = 'connectedAndReceivingIncomingConnections' - 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=(',', ': ')) - elif method == 'decodeAddress': - # Return a meaningful decoding of an address. - if len(params) != 1: - raise APIError(0, 'I need 1 parameter!') - address, = params - status, addressVersion, streamNumber, ripe = decodeAddress(address) - return json.dumps({'status':status, 'addressVersion':addressVersion, - 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, - separators=(',', ': ')) - elif method == 'getInboxCount': - #queryreturn = sqlQuery('''SELECT read, received < 'now' - 60 AS old, COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' GROUP BY read, old''') - ret = {} - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 0 AND received < 'now' - 60''') - for row in queryreturn: - count, = row - ret['oldread'] = count - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 1 AND received < 'now' - 60''') - for row in queryreturn: - count, = row - ret['oldunread'] = count - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 0 AND received >= 'now' - 60''') - for row in queryreturn: - count, = row - ret['newread'] = count - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' AND read = 1 AND received >= 'now' - 60''') - for row in queryreturn: - count, = row - ret['newunread'] = count - data = '{"inboxCount":{' - for key in ret: - val = ret[key] - if len(data) > 16: - data += ',' - data += json.dumps({key:val}, indent=4, separators=(',', ': ')) - data += '}}' - elif method == 'getSentCount': - ret = {} - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM sent WHERE folder = 'sent' AND status = 'msgqueued' ''') - for row in queryreturn: - count, = row - ret['queued'] = count - queryreturn = sqlQuery('''SELECT COUNT (*) AS cnt FROM sent WHERE folder = 'sent' AND status = 'msgsent' ''') - for row in queryreturn: - count, = row - ret['awaitingack'] = count - data = '{"sentCount":{' - for key in ret: - val = ret[key] - if len(data) > 15: - data += ',' - data += json.dumps({key:val}, indent=4, separators=(',', ': ')) - data += '}}' - elif method == 'deleteAndVacuum': - sqlStoredProcedure('deleteandvacuume') - return 'done' + hash01, payload = row + readPosition = 16 # Nonce length + time length + readPosition += decodeVarint(payload[readPosition:readPosition+10])[1] # Stream Number length + t = (payload[readPosition:readPosition+32],hash01) + sql.execute('''UPDATE inventory SET tag=? WHERE hash=?; ''', *t) + + queryreturn = sqlQuery('''SELECT payload FROM inventory WHERE tag = ?''', + requestedHash) + data = '{"receivedMessageDatas":[' + for row in queryreturn: + payload, = row + if len(data) > 25: + data += ',' + data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) + data += ']}' + return data + + def HandleClientStatus(self, params): + if len(shared.connectedHostsList) == 0: + networkStatus = 'notConnected' + elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: + networkStatus = 'connectedButHaveNotReceivedIncomingConnections' + else: + networkStatus = 'connectedAndReceivingIncomingConnections' + 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. + if len(params) != 1: + raise APIError(0, 'I need 1 parameter!') + address, = params + status, addressVersion, streamNumber, ripe = decodeAddress(address) + return json.dumps({'status':status, 'addressVersion':addressVersion, + 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, + separators=(',', ': ')) + + def HandleHelloWorld(self, params): + (a, b) = params + return a + '-' + b + + def HandleAdd(self, params): + (a, b) = params + return a + b + + def HandleStatusBar(self, params): + message, = params + shared.UISignalQueue.put(('updateStatusBar', message)) + + def HandleDeleteAndVacuum(self, params): + sqlStoredProcedure('deleteandvacuume') + return 'done' + + handlers = {} + handlers['helloWorld'] = HandleHelloWorld + handlers['add'] = HandleAdd + handlers['statusBar'] = HandleStatusBar + handlers['listAddresses'] = HandleListAddresses + handlers['listAddressBookEntries'] = HandleListAddressBookEntries; + handlers['listAddressbook'] = HandleListAddressBookEntries # the listAddressbook alias should be removed eventually. + handlers['addAddressBookEntry'] = HandleAddAddressBookEntry + handlers['addAddressbook'] = HandleAddAddressBookEntry # the addAddressbook alias should be deleted eventually. + handlers['deleteAddressBookEntry'] = HandleDeleteAddressBookEntry + handlers['deleteAddressbook'] = HandleDeleteAddressBookEntry # The deleteAddressbook alias should be deleted eventually. + handlers['createRandomAddress'] = HandleCreateRandomAddress + handlers['createDeterministicAddresses'] = HandleCreateDeterministicAddresses + handlers['getDeterministicAddress'] = HandleGetDeterministicAddress + handlers['createChan'] = HandleCreateChan + handlers['joinChan'] = HandleJoinChan + handlers['leaveChan'] = HandleLeaveChan + handlers['deleteAddress'] = HandleDeleteAddress + handlers['getAllInboxMessages'] = HandleGetAllInboxMessages + handlers['getAllInboxMessageIds'] = HandleGetAllInboxMessageIds + handlers['getAllInboxMessageIDs'] = HandleGetAllInboxMessageIds + handlers['getInboxMessageById'] = HandleGetInboxMessageById + handlers['getInboxMessageByID'] = HandleGetInboxMessageById + handlers['getAllSentMessages'] = HandleGetAllSentMessages + handlers['getAllSentMessageIds'] = HandleGetAllSentMessageIds + handlers['getAllSentMessageIDs'] = HandleGetAllSentMessageIds + handlers['getInboxMessagesByReceiver'] = HandleInboxMessagesByReceiver + handlers['getInboxMessagesByAddress'] = HandleInboxMessagesByReceiver #after some time getInboxMessagesByAddress should be removed + handlers['getSentMessageById'] = HandleGetSentMessageById + handlers['getSentMessageByID'] = HandleGetSentMessageById + handlers['getSentMessagesByAddress'] = HandleGetSentMessagesByAddress + handlers['getSentMessagesBySender'] = HandleGetSentMessagesByAddress + handlers['getSentMessageByAckData'] = HandleGetSentMessagesByAckData + handlers['trashMessage'] = HandleTrashMessage + handlers['trashInboxMessage'] = HandleTrashInboxMessage + handlers['trashSentMessage'] = HandleTrashSentMessage + handlers['trashSentMessageByAckData'] = HandleTrashSentMessageByAckDAta + handlers['sendMessage'] = HandleSendMessage + handlers['sendBroadcast'] = HandleSendBroadcast + handlers['getStatus'] = HandleGetStatus + handlers['addSubscription'] = HandleAddSubscription + handlers['deleteSubscription'] = HandleDeleteSubscription + handlers['listSubscriptions'] = ListSubscriptions + handlers['disseminatePreEncryptedMsg'] = HandleDisseminatePreEncryptedMsg + handlers['disseminatePubkey'] = HandleDissimatePubKey + handlers['getMessageDataByDestinationHash'] = HandleGetMessageDataByDestinationHash + handlers['getMessageDataByDestinationTag'] = HandleGetMessageDataByDestinationHash + handlers['clientStatus'] = HandleClientStatus + handlers['decodeAddress'] = HandleDecodeAddress + handlers['deleteAndVacuum'] = HandleDeleteAndVacuum + + def _handle_request(self, method, params): + if (self.handlers.has_key(method)): + return self.handlers[method](self ,params) else: raise APIError(20, 'Invalid method: %s' % method) -- 2.45.1 From 2b1222f970e5f8c7523e62726ccc6208105f7026 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 30 Sep 2015 10:22:41 +0200 Subject: [PATCH 0014/1102] Fix: UI --- src/bitmessageqt/__init__.py | 48 ++++++++++++++++++++++++++++++------ src/openclpow.py | 10 ++++++-- src/proofofwork.py | 5 ++-- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 73dab84e..894644b1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2028,9 +2028,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f if self.ui.tabWidgetSend.currentIndex() == 0: # message to specific people sendMessageToPeople = True - fromAddress = self.ui.comboBoxSendFrom.itemData( + fromAddress = str(self.ui.comboBoxSendFrom.itemData( self.ui.comboBoxSendFrom.currentIndex(), - Qt.UserRole).toString() + Qt.UserRole).toString()) toAddresses = str(self.ui.lineEditTo.text()) subject = str(self.ui.lineEditSubject.text().toUtf8()) message = str( @@ -2038,9 +2038,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: # broadcast message sendMessageToPeople = False - fromAddress = self.ui.comboBoxSendFromBroadcast.itemData( + fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData( self.ui.comboBoxSendFromBroadcast.currentIndex(), - Qt.UserRole).toString() + Qt.UserRole).toString()) subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8()) message = str( self.ui.textEditMessageBroadcast.document().toPlainText().toUtf8()) @@ -2098,6 +2098,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f "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: 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))) @@ -2262,6 +2263,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f # 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): + if self.getCurrentFolder() != "sent": + return subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) try: @@ -2303,10 +2306,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setData(Qt.UserRole, QByteArray(ackdata)) newItem.setData(33, int(time.time())) self.ui.tableWidgetInbox.setItem(0, 3, newItem) - self.ui.textEditSentMessage.setPlainText(unicode(message, 'utf-8)')) + self.ui.textEditInboxMessage.setPlainText(unicode(message, 'utf-8)')) self.ui.tableWidgetInbox.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): + if self.getCurrentFolder() != "inbox": + return subject = shared.fixPotentiallyInvalidUTF8Data(subject) fromLabel = '' queryreturn = sqlQuery( @@ -3535,16 +3540,43 @@ more work your computer must do to send the message. A Time-To-Live of four or f ackdata = self.getCurrentMessageId() if ackdata and messageTextedit: queryreturn = sqlQuery( - '''select message from sent where ackdata=?''', ackdata) + '''select message, 1 from sent where ackdata=?''', ackdata) else: msgid = self.getCurrentMessageId() if msgid and messageTextedit: queryreturn = sqlQuery( - '''select message from inbox where msgid=?''', msgid) + '''select message, read from inbox where msgid=?''', msgid) if queryreturn != []: + refresh = False for row in queryreturn: - message, = row + message, read = row + if folder == 'inbox' and read == 0: + markread = sqlQuery( + '''UPDATE inbox SET read = 1 WHERE msgid = ?''', msgid) + refresh = True + if refresh: + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + font = QFont() + font.setBold(False) +# inventoryHashesToMarkRead = [] + currentRow = self.getCurrentMessagelist().currentRow() +# inventoryHashToMarkRead = str(tableWidget.item( +# currentRow, 3).data(Qt.UserRole).toPyObject()) +# inventoryHashesToMarkRead.append(inventoryHashToMarkRead) + tableWidget.item(currentRow, 0).setFont(font) + tableWidget.item(currentRow, 1).setFont(font) + tableWidget.item(currentRow, 2).setFont(font) + tableWidget.item(currentRow, 3).setFont(font) + self.changedInboxUnread() +# if self.ui.tabWidget.currentIndex() == 0: +# self.rerenderTabTreeMessages() +# elif self.ui.tabWidget.currentIndex() == 2: +# self.rerenderTabTreeSubscriptions() +# elif self.ui.tabWidget.currentIndex() == 3: +# self.rerenderTabTreeChans() else: data = self.getCurrentMessageId() if data != False: diff --git a/src/openclpow.py b/src/openclpow.py index 83d7513f..65449b85 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -15,10 +15,16 @@ try: ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) - f = open('/usr/src/PyBitmessage/src/kernel.cl', 'r') + #f = open('/usr/src/PyBitmessage/src/kernel.cl', 'r') + import os + print "working directory: " + os.getcwd() +# time.sleep(5) + f = open('kernel.cl', 'r') fstr = ''.join(f.readlines()) program = cl.Program(ctx, fstr).build() -except: +except Exception as e: + print "opencl fail:" + str(e) +# time.sleep(5) ctx = False def has_opencl(): diff --git a/src/proofofwork.py b/src/proofofwork.py index fec70287..85f79430 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -81,8 +81,9 @@ def _doGPUPow(target, initialHash): return [trialValue, nonce] def run(target, initialHash): - if openclpow.has_opencl(): - return _doGPUPow(target, initialHash) + target = int(target) + if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): + return _doGPUPow(target, initialHash) elif frozen == "macosx_app" or not frozen: return _doFastPoW(target, initialHash) else: -- 2.45.1 From 3888eb11be6d5e51e1930b6ebf109d81f713f966 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 30 Sep 2015 11:14:56 +0200 Subject: [PATCH 0015/1102] UI fix All new messages appeared in current account message list, as opposed to only new messages associated with that account. --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 894644b1..34a6bc4f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2263,7 +2263,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f # 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): - if self.getCurrentFolder() != "sent": + if self.getCurrentFolder() != "sent" or self.getCurrentAccount() != fromAddress: return subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) @@ -2310,7 +2310,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetInbox.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): - if self.getCurrentFolder() != "inbox": + if self.getCurrentFolder() != "inbox" or self.getCurrentAccount() != toAddress: return subject = shared.fixPotentiallyInvalidUTF8Data(subject) fromLabel = '' -- 2.45.1 From b4fad5c49a3075369abd15f62ab9c2e88421fe49 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 30 Sep 2015 11:30:21 +0200 Subject: [PATCH 0016/1102] Shorten trashed summary Trash UI now exists, there is no need to tell the user it doesn't. --- src/bitmessageqt/__init__.py | 2 +- src/translations/bitmessage_ar.ts | 4 ++-- src/translations/bitmessage_cs.ts | 4 ++-- src/translations/bitmessage_de.ts | 4 ++-- src/translations/bitmessage_en_pirate.ts | 2 +- src/translations/bitmessage_eo.ts | 4 ++-- src/translations/bitmessage_fr.ts | 4 ++-- src/translations/bitmessage_ja.ts | 4 ++-- src/translations/bitmessage_nl.ts | 2 +- src/translations/bitmessage_no.ts | 4 ++-- src/translations/bitmessage_ru.ts | 4 ++-- src/translations/bitmessage_zh_cn.ts | 4 ++-- 12 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 34a6bc4f..ea0380f9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2996,7 +2996,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.textEditInboxMessage.setText("") tableWidget.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.")) + "MainWindow", "Moved items to trash.")) if currentRow == 0: tableWidget.selectRow(currentRow) else: diff --git a/src/translations/bitmessage_ar.ts b/src/translations/bitmessage_ar.ts index b37dcc0b..195db516 100644 --- a/src/translations/bitmessage_ar.ts +++ b/src/translations/bitmessage_ar.ts @@ -582,8 +582,8 @@ It is important that you back up this file. Would you like to open the file now? - 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. + تم نقل المادة لسلة المهملات. diff --git a/src/translations/bitmessage_cs.ts b/src/translations/bitmessage_cs.ts index c16012c9..438e5907 100755 --- a/src/translations/bitmessage_cs.ts +++ b/src/translations/bitmessage_cs.ts @@ -556,8 +556,8 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev - 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. + Moved items to trash. + Položky byly přesunuty do koše. diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 5d937bf9..1c817a98 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -491,8 +491,8 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die datei jetzt öffn - 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. + Moved items to trash. + Objekt in den Papierkorb verschoben. diff --git a/src/translations/bitmessage_en_pirate.ts b/src/translations/bitmessage_en_pirate.ts index ba97978a..02330897 100644 --- a/src/translations/bitmessage_en_pirate.ts +++ b/src/translations/bitmessage_en_pirate.ts @@ -551,7 +551,7 @@ It is important that you back up this file. Would you like to open the file now? - 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. diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 2f09691d..00e33f9e 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -491,8 +491,8 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - 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. + Moved items to trash. + Movis elementojn al rubujo. diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index e32eb5ef..a5483303 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -573,8 +573,8 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o - 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. + Moved items to trash. + Messages déplacés dans la corbeille. diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index da9edc69..08061f61 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -550,8 +550,8 @@ It is important that you back up this file. Would you like to open the file now? - 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. + アイテムをゴミ箱へ移動。 diff --git a/src/translations/bitmessage_nl.ts b/src/translations/bitmessage_nl.ts index 54237fdd..46969c0d 100644 --- a/src/translations/bitmessage_nl.ts +++ b/src/translations/bitmessage_nl.ts @@ -552,7 +552,7 @@ It is important that you back up this file. Would you like to open the file now? - 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. diff --git a/src/translations/bitmessage_no.ts b/src/translations/bitmessage_no.ts index 72ce1f4f..0b12acfb 100644 --- a/src/translations/bitmessage_no.ts +++ b/src/translations/bitmessage_no.ts @@ -573,8 +573,8 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne - 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. + Moved items to trash. + Kastet innholdet. diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index e72011ca..04ef8ab4 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -495,8 +495,8 @@ It is important that you back up this file. Would you like to open the file now? - 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. + Удалено в корзину. diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index adc055e5..40c648e9 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -861,8 +861,8 @@ It is important that you back up this file. Would you like to open the file now? - 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. + 已经移动项目到回收站。 -- 2.45.1 From 9a6db480bd5b8a686abd0925a6fd213e6bf3b306 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 30 Sep 2015 13:32:24 +0200 Subject: [PATCH 0017/1102] Typo --- src/bitmessageqt/bitmessageui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index d795f17c..36ccbbb0 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -622,7 +622,7 @@ class Ui_MainWindow(object): 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 Indentitiy", 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)) -- 2.45.1 From 324dbfb81a4cf39665717446d79622fc21a05635 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 09:42:31 +0200 Subject: [PATCH 0018/1102] Migration Wizard - from standard PyBitmessage to this one - not working yet --- src/bitmessageqt/migrationwizard.py | 84 +++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/bitmessageqt/migrationwizard.py diff --git a/src/bitmessageqt/migrationwizard.py b/src/bitmessageqt/migrationwizard.py new file mode 100644 index 00000000..945adefa --- /dev/null +++ b/src/bitmessageqt/migrationwizard.py @@ -0,0 +1,84 @@ +#!/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() + self.setPage(1, page) + page = MigrationWizardGPUPage(addresses) + 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 -- 2.45.1 From 8882912bf3878453ad96d3ae672226a12e2ac4b3 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 09:42:47 +0200 Subject: [PATCH 0019/1102] New address wizard Not working yet, just UI --- src/bitmessageqt/__init__.py | 13 + src/bitmessageqt/newaddresswizard.py | 354 +++++++++++++++++++++++++++ 2 files changed, 367 insertions(+) create mode 100644 src/bitmessageqt/newaddresswizard.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ea0380f9..8580d206 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -11,6 +11,8 @@ import shared from bitmessageui import * from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * +from newaddresswizard import * +from migrationwizard import * from addaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * @@ -2758,6 +2760,17 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.rerenderInboxToLabels() def click_NewAddressDialog(self): + addresses = [] + configSections = shared.config.sections() + for addressInKeysFile in configSections: + if addressInKeysFile == 'bitmessagesettings': + continue + addresses.append(addressInKeysFile) + self.dialog = Ui_NewAddressWizard(addresses) + self.dialog.exec_() +# print "Name: " + self.dialog.field("name").toString() +# print "Email: " + self.dialog.field("email").toString() + return self.dialog = NewAddressDialog(self) # For Modal dialogs if self.dialog.exec_(): diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py new file mode 100644 index 00000000..e54b18c3 --- /dev/null +++ b/src/bitmessageqt/newaddresswizard.py @@ -0,0 +1,354 @@ +#!/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:

" + "" + "" + " - + # 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 chanu + 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 - Przenies do kosza + 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 @@ -192,7 +232,7 @@ Wprowadź wybrany adres email (razem z końcówką @mailchuck.com) poniżej: Set avatar... - Ustaw avatar... + Ustaw awatar... @@ -200,14 +240,14 @@ Wprowadź wybrany adres email (razem z końcówką @mailchuck.com) poniżej:Kopiuj adres do schowka - + Special address behavior... - Specjalne zachownaie adresu... + Specjalne zachowanie adresu... - + Email gateway - Przekaźnik email + Przekaźnik e-mail @@ -215,57 +255,57 @@ Wprowadź wybrany adres email (razem z końcówką @mailchuck.com) poniżej:Usuń - + Send message to this address - Wyślij wiadomość do tego adresu + 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 atarum adresem wersji 1. Adresy tej wersji nie sa juz wspierane. Usunąć go? + 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. - Prośba o klucz szyfrujący w kolejce do wysłania. + - + 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 @@ -275,216 +315,220 @@ Wprowadź wybrany adres email (razem z końcówką @mailchuck.com) poniżej: - + 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 - - Chan name needed - Potrzebna nazwa chanu - - - + You didn't enter a chan name. - Nie wprowadzono nazwy chanu. + - + Address already present - Adres już dodany + + + + + 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. + - Could not add chan because it appears to already be one of your identities. - Nie można dołączyc do chanu, ponieważ jest to jedna z twoich tożsamości. - - - - Success - Sukces - - - - 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'. - Utworzono chan. Aby umozliwic innym osobom dołączenie do niego, daj im nazwę chanu oraz ten adres Bitmessage: %1. - - - - Address too new - Adres zbyt nowy - - - - Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - Wersja podanego adresu jest wyższa od obsługiwanej przez tę wersję programu. Aktualizacja Bitmessage powinna rozwiązać ten problem. - - - Address invalid - Nieprawidłowy adres + - + That Bitmessage address is not valid. - Podany adres Bitmessage jest nieprawidłowy. + - + Address does not match chan name - Niezgodnośc adresu z nazwą chanu + - + Although the Bitmessage address you entered was valid, it doesn't match the chan name. - Ten adres Bitmessage jest prawidłowy, jednak nie jest on adresem chanu o podanej nazwie. + - + Successfully joined chan. - Dołączono do chanu. + - + 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 @@ -495,775 +539,924 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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 przekażniku email. Rejestrowanie jako %1, prosze poczekać na zakończenie procesu przed ponowną próbą wysłania wiadomości. + 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 - Błąd: Adres Bitmessage nie zaczyna się od BM-, sprawdź %1 + - + Error: The address %1 is not typed or copied correctly. Please check it. - Błąd: Adres %1 nie został skopiowany lub przepisany poprawnie. + - + Error: The address %1 contains invalid characters. Please check it. - Błąd: Adres %1 zawiera nieprawidłowe znaki. + - + Error: The address version in %1 is too high. Either you need to upgrade your Bitmessage software or your acquaintance is being clever. - Błąd: Wersja adresu %1 jest za wysoka. Musisz albo zaktualizować Twoje oprogramowanie Bitmessage, albo twój znajomy Cię trolluje. + - + 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 - + Od - + Sending email gateway registration request - + Wysyłanie zapytania o rejestrację na bramce poczty 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 - + Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request - + Wysyłanie zapytania o stan bramki poczty - + 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. - + Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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. - + To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' - + Adres powinien zaczynać sie 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. - + Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. - + Adres starego typu - + There are no recent broadcasts from this address to display. - + Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). - + Bitmessage - + Bitmessage - + Identities - + Tożsamości - + 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: - + 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 - - - - - Settings - - - - - Help - - - - - Import keys - - - - - Manage keys - - - - - Ctrl+Q - + 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 - Contact support - + Regenerate deterministic addresses + Odtwórz adres deterministyczny - About - - - - - Regenerate deterministic addresses - - - - 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. - + Pokaż %1 ostatnich wiadomości przekazów 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 day(s) - + %n dzień%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 - + Przekaz wysłane o %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ó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 + + + + 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. + + + + 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. + + + + 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? + + + + 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... + + + + 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 @@ -1271,98 +1464,99 @@ Receiver's required difficulty: %1 and %2 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 procesora) @@ -1370,22 +1564,22 @@ The 'Random Number' option is selected by default but deterministic ad Add new entry - + Dodaj subskrypcję Label - + Etykieta Address - + Adres Enter an address above. - + Wpisz adres powyżej. @@ -1393,60 +1587,65 @@ The 'Random Number' option is selected by default but deterministic ad Special Address Behavior - + Specjalne zachowanie adresu Behave as a normal address - + Zachowuj się jako normalny adres Behave as a pseudo-mailing-list address - + Zachowuj się jako 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: aboutDialog - - - About - - - PyBitmessage - + About + O programie + PyBitmessage + PyBitmessage + + + version ? + wersja ? + + + + <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>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> - + <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>Prawa autorskie &copy; 2012-2016 Jonathan Warren<br/>Prawa autorskie &copy; 2013-2016 Programiści Bitmessage</p></body></html> @@ -1454,37 +1653,37 @@ The 'Random Number' option is selected by default but deterministic ad Use a Blacklist (Allow all incoming messages except those on the Blacklist) - + Użyj czarnej listy (zezwala na wszystkie przychodzące z wyjątkiem od 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 @@ -1492,22 +1691,22 @@ The 'Random Number' option is selected by default but deterministic ad 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 @@ -1515,17 +1714,17 @@ The 'Random Number' option is selected by default but deterministic ad 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: @@ -1533,27 +1732,27 @@ The 'Random Number' option is selected by default but deterministic ad 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). - + Używasz portu TCP ?. (Możesz go zmienić w ustawieniach.) 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. @@ -1561,112 +1760,112 @@ The 'Random Number' option is selected by default but deterministic ad 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 przekazów. Inventory lookups per second: 0 - + Zapytań o elementy na sekundę: 0 Objects to be synced: - + Obiektów do zsynchronizowania: Stream # - + Strumień # Connections - + Połączeń 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ów Object(s) to be synced: %n - + Jeden obiekt do zsynchronizowaniaObiekó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. Processed %n broadcast message(s). - + Przetworzono %n wiadomość przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. Processed %n public key(s). - + Przetworzono %1 klucz publiczny.Przetworzono %1 kluczy publicznych.Przetworzono %1 kluczy publicznych. @@ -1711,352 +1910,405 @@ The 'Random Number' option is selected by default but deterministic ad 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 passhphrase/name: + Wpisz hasło/nazwę: + + + + 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 + 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 - - - - - Start Bitmessage on user login - - - - - Tray - - - - - Start Bitmessage in the tray (don't show main window) - - - Minimize to tray - + Settings + Ustawienia - Close to tray - + Start Bitmessage on user login + Uruchom Bitmessage po zalogowaniu - Show notification when message received - + Tray + Zasobnik systemowy - Run in Portable Mode - + Start Bitmessage in the tray (don't show main window) + Uruchom Bitmessage w zasobniku (nie pokazuj tego okna) - 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. - + Minimize to tray + Minimalizuj do zasobnika - Willingly include unencrypted destination address when sending to a mobile device - - - - - Use Identicons - + Close to tray + Zamknij do zasobnika - Reply below Quote - + Show notification when message received + Wyświetl powiadomienia o przychodzących wiadomościach - Interface Language - + Run in Portable Mode + Uruchom w trybie przenośnym - System Settings - system - + 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. - User Interface - + 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. - Listening port - + Use Identicons + Użyj 'Identiconów' - Listen for connections on port: - + Reply below Quote + Odpowiedź pod cytatem - UPnP: - + Interface Language + Język interfejsu - Bandwidth limit - + System Settings + system + Język systemu - Maximum download rate (kB/s): [0: unlimited] - + User Interface + Interfejs - Maximum upload rate (kB/s): [0: unlimited] - + Listening port + Port nasłuchujący - Proxy server / Tor - + Listen for connections on port: + Nasłuchuj połaczeń na porcie: - Type: - + UPnP: + UPnP: - Server hostname: - + Bandwidth limit + Limity przepustowości - - Port: - + + Maximum download rate (kB/s): [0: unlimited] + Maksymalna prędkość pobierania (w kB/s): [0: bez limitu] - Authentication - + Maximum upload rate (kB/s): [0: unlimited] + Maksymalna prędkość wysyłania (w kB/s): [0: bez limitu] - - Username: - + + Proxy server / Tor + Serwer proxy / Tor - Pass: - + Type: + Typ: - 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: - + Server hostname: + Adres serwera: - Namecoind - + Port: + Port: + + + + Authentication + Uwierzytelnienie - NMControl - + 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) + Przyspieszenie sprzętowe 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> + <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: - Namecoin integration - + Password: + Hasło: - <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> - + Test + Test - Give up after - + Connect to: + Połącz z: - and - + Namecoind + Namecoind - days - + NMControl + NMControl - months. - + 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 + Nie wysyłaj ponownie po + + + + and + i + + + + days + dniach + + + + months. + miesiącach. + + + Resends Expire - + Niedoręczone wiadomości + + + + Hide connection notifications + Nie pokazuj powiadomień o połączeniu \ No newline at end of file -- 2.45.1 From 020a78b7765e307630c97e08ec4e9e81cd8b4ca0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Nov 2016 14:44:39 +0100 Subject: [PATCH 0486/1102] Exception prevention in hashCount - I got a report that an exception can occur, and while I can't reproduce it, this should avoid it --- src/class_objectHashHolder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 3fc260d2..30d27ea8 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -49,7 +49,7 @@ class objectHashHolder(threading.Thread): self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails) def hashCount(self): - return sum([len(x) for x in self.collectionOfHashLists]) + return sum([len(x) for x in self.collectionOfHashLists if type(x) is list]) def close(self): self.shutdown = True -- 2.45.1 From 8ce72d8d2d25973b7064b1cf76a6b0b3d62f0ba0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 3 Nov 2016 22:41:36 +0100 Subject: [PATCH 0487/1102] Extended encoding updates - more flexible and developer friendly. Still not active code --- src/helper_msgcoding.py | 32 +++++++++++++++++++++---------- src/messagetypes/__init__.py | 37 ++++++++++++++++++++++++++++++++++++ src/messagetypes/message.py | 8 ++++++++ src/messagetypes/vote.py | 8 ++++++++ 4 files changed, 75 insertions(+), 10 deletions(-) create mode 100644 src/messagetypes/__init__.py create mode 100644 src/messagetypes/message.py create mode 100644 src/messagetypes/vote.py diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index 8d71aca0..04c03fed 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -5,14 +5,16 @@ import msgpack import zlib from debug import logger +import messagetypes BITMESSAGE_ENCODING_IGNORE = 0 BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 + class MsgEncode(object): - def __init__(self, message, encoding = BITMESSAGE_ENCODING_SIMPLE): + def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): self.data = None self.encoding = encoding self.length = 0 @@ -27,10 +29,10 @@ class MsgEncode(object): try: self.data = zlib.compress(msgpack.dumps({"": "message", "subject": message['subject'], "message": ['body']}), 9) except zlib.error: - logger.error ("Error compressing message") + logger.error("Error compressing message") raise except msgpack.exceptions.PackException: - logger.error ("Error msgpacking message") + logger.error("Error msgpacking message") raise self.length = len(self.data) @@ -55,20 +57,30 @@ class MsgDecode(object): try: tmp = msgpack.loads(zlib.decompress(data)) except zlib.error: - logger.error ("Error decompressing message") + logger.error("Error decompressing message") raise except (msgpack.exceptions.UnpackException, msgpack.exceptions.ExtraData): - logger.error ("Error msgunpacking message") + logger.error("Error msgunpacking message") raise + try: - if tmp[""] == "message": - self.body = tmp["body"] - self.subject = tmp["subject"] - except: - logger.error ("Malformed message") + msgType = tmp[""] + except KeyError: + logger.error("Message type missing") raise + msgObj = messagetypes.constructObject(data) + if msgObj is None: + raise ValueError("Malformed message") + try: + msgObj.process() + except: + raise ValueError("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: diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py new file mode 100644 index 00000000..9b5c5a05 --- /dev/null +++ b/src/messagetypes/__init__.py @@ -0,0 +1,37 @@ +from importlib import import_module +from pprint import pprint +from os import path, listdir +import sys + + +def constructObject(data): + try: + classBase = eval(data[""] + "." + data[""].title()) + except NameError: + print "Don't know how to handle message type: \"%s\"" % (data[""]) + return None + try: + returnObj = classBase(data) + except KeyError as e: + print "Missing mandatory key %s" % (e) + return None + except: + print "classBase fail:" + pprint(sys.exc_info()) + return None + else: + return returnObj + +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: + print "Error importing %s" % (mod) + pprint(sys.exc_info()) + else: + print "Imported %s" % (mod) diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py new file mode 100644 index 00000000..654e6d6b --- /dev/null +++ b/src/messagetypes/message.py @@ -0,0 +1,8 @@ +class Message: + def __init__(self, data): + self.subject = data["subject"] + self.body = data["body"] + + def process(self): + print "Subject: %s" % (self.subject) + print "Body: %s" % (self.body) diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py new file mode 100644 index 00000000..5b692eb2 --- /dev/null +++ b/src/messagetypes/vote.py @@ -0,0 +1,8 @@ +class Vote: + def __init__(self, data): + self.msgid = data["msgid"] + self.vote = data["vote"] + + def process(self): + print "msgid: %s" % (self.msgid) + print "vote: %s" % (self.vote) -- 2.45.1 From a7f3afe5a6a55946c650ae93009aad8c2307f322 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 5 Nov 2016 00:46:07 +0100 Subject: [PATCH 0488/1102] Typo --- src/bitmessageqt/support.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 4742e175..b68619cd 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -31,7 +31,7 @@ Please describe what happens instead: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please write above this line and if possible, keep the information about your environment below intact. -PyBitmesage version: {} +PyBitmessage version: {} Operating system: {} Architecture: {}bit Python Version: {} -- 2.45.1 From 756f85c9f0f1cc63ead23a7b402d650de5d94683 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 8 Nov 2016 08:49:43 +0100 Subject: [PATCH 0489/1102] Don't connect to yourself when hidden service --- src/class_outgoingSynSender.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 898f655a..5bef66c6 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -47,6 +47,9 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.knownNodesLock.release() if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': if peer.host.find(".onion") == -1: + # don't connect to self + if peer.host == shared.config.get('bitmessagesettings', 'onionhostname') and peer.port == shared.config.getint("bitmessagesettings", "onionport"): + continue priority /= 10 # hidden services have 10x priority over plain net elif peer.host.find(".onion") != -1: # onion address and so proxy continue -- 2.45.1 From e9a3ef465ca68dd182b54437f061944a9d106786 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 10 Nov 2016 21:43:10 +0100 Subject: [PATCH 0490/1102] OpenCL vendor selector - when you have multiple OpenCL drivers at the same time, e.g. intel and nvidia, they won't mix leading to crashes. This patch makes it possible to select which driver to use by listing the available vendors --- src/bitmessageqt/__init__.py | 22 ++++--- src/bitmessageqt/settings.py | 8 +-- src/bitmessageqt/support.py | 4 +- src/openclpow.py | 109 ++++++++++++++++++++--------------- src/proofofwork.py | 8 +-- 5 files changed, 84 insertions(+), 67 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6ddafb35..ff4bfbcf 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2408,8 +2408,8 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - if openclpow.has_opencl() and self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked() != shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): - shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked())) + if self.settingsDialogInstance.ui.checkBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): + shared.config.set('bitmessagesettings', 'opencl', self.settingsDialogInstance.ui.checkBoxOpenCL.currentText().toUtf8()) acceptableDifficultyChanged = False @@ -4082,14 +4082,18 @@ class settingsDialog(QtGui.QDialog): 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # OpenCL - if openclpow.has_opencl(): - self.ui.checkBoxOpenCL.setEnabled(True) + if openclpow.openclAvailable(): + self.ui.comboBoxOpenCL.setEnabled(True) else: - self.ui.checkBoxOpenCL.setEnabled(False) - if shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): - self.ui.checkBoxOpenCL.setChecked(True) - else: - self.ui.checkBoxOpenCL.setChecked(False) + 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) == shared.safeConfigGet('bitmessagesettings', 'opencl'): + self.ui.comboBoxOpenCL.setCurrentIndex(i) + break # Namecoin integration tab nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 9b86ea5a..a67c7f42 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -298,9 +298,9 @@ class Ui_settingsDialog(object): self.labelOpenCL = QtGui.QLabel(self.tabMaxAcceptableDifficulty) self.labelOpenCL.setObjectName(_fromUtf8("labelOpenCL")) self.gridLayout_7.addWidget(self.labelOpenCL, 4, 0, 1, 1) - self.checkBoxOpenCL = QtGui.QCheckBox(self.tabMaxAcceptableDifficulty) - self.checkBoxOpenCL.setObjectName = (_fromUtf8("checkBoxOpenCL")) - self.gridLayout_7.addWidget(self.checkBoxOpenCL, 4, 1, 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")) @@ -475,7 +475,7 @@ 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.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/support.py b/src/bitmessageqt/support.py index b68619cd..0f52ec04 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -9,7 +9,7 @@ from debug import logger from foldertree import AccountMixin from helper_sql import * from l10n import getTranslationLanguage -from openclpow import has_opencl +from openclpow import openclAvailable, openclEnabled from proofofwork import bmpow from pyelliptic.openssl import OpenSSL import shared @@ -107,7 +107,7 @@ def createSupportMessage(myapp): portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" cpow = "True" if bmpow else "False" #cpow = QtGui.QApplication.translate("Support", cpow) - openclpow = "True" if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and has_opencl() else "False" + openclpow = str(shared.safeConfigGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" #openclpow = QtGui.QApplication.translate("Support", openclpow) locale = getTranslationLanguage() try: diff --git a/src/openclpow.py b/src/openclpow.py index b643ca57..2f7f0158 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,7 +5,7 @@ import hashlib import random import os -from shared import codePath, safeConfigGetBoolean, shutdown +from shared import codePath, safeConfigGetBoolean, safeConfigGet, shutdown from debug import logger libAvailable = True @@ -13,6 +13,8 @@ ctx = False queue = False program = False gpus = [] +enabledGpus = [] +vendors = [] hash_dt = None try: @@ -22,13 +24,20 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, gpus, hash_dt + global ctx, queue, program, gpus, hash_dt, vendors try: hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) - for platform in cl.get_platforms(): - gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if (len(gpus) > 0): - ctx = cl.Context(devices=gpus) + try: + for platform in cl.get_platforms(): + gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) + if safeConfigGet("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(codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') fstr = ''.join(f.readlines()) @@ -36,60 +45,64 @@ def initCL(): logger.info("Loaded OpenCL kernel") else: logger.info("No OpenCL GPUs found") - ctx = False + enabledGpus = [] except Exception as e: logger.error("OpenCL fail: ", exc_info=True) - ctx = False + enabledGpus = [] -def has_opencl(): - global ctx - return (ctx != False) +def openclAvailable(): + global gpus + return (len(gpus) > 0) + +def openclEnabled(): + global enabledGpus + return (len(enabledGpus) > 0) def do_opencl_pow(hash, target): - global ctx, queue, program, gpus, hash_dt + global ctx, queue, program, enabledGpus, hash_dt - output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) - if (ctx == False): - 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, gpus[0]) + output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) + if (len(enabledGpus) == 0): + return output[0][0] - kernel.set_arg(0, hash_buf) - kernel.set_arg(1, dest_buf) + data = numpy.zeros(1, dtype=hash_dt, order='C') + data[0]['v'] = ("0000000000000000" + hash).decode("hex") + data[0]['target'] = target - start = time.time() - progress = 0 - globamt = worksize*2000 + 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) - 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) + target = 54227212183L + initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex") + nonce = 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) diff --git a/src/proofofwork.py b/src/proofofwork.py index b4ce69b2..701f34ba 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -108,10 +108,10 @@ def _doGPUPoW(target, initialHash): 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.gpus) + deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'))) logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames) - openclpow.ctx = False + openclpow.enabledGpus = [] raise Exception("GPU did not calculate correctly.") if shared.shutdown != 0: raise StopIteration("Interrupted") @@ -144,7 +144,7 @@ def estimate(difficulty, format = False): return ret def getPowType(): - if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): + if openclpow.openclEnabled(): return "OpenCL" if bmpow: return "C" @@ -154,7 +154,7 @@ def run(target, initialHash): if shared.shutdown != 0: raise target = int(target) - if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): + if openclpow.openclEnabled(): # trialvalue1, nonce1 = _doGPUPoW(target, initialHash) # trialvalue, nonce = _doFastPoW(target, initialHash) # print "GPU: %s, %s" % (trialvalue1, nonce1) -- 2.45.1 From 87f607688f0ff3580d6333cd96b088018df7fe99 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 10 Nov 2016 21:52:21 +0100 Subject: [PATCH 0491/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 85148 -> 85151 bytes src/translations/bitmessage_sk.ts | 67 ++++++++++++++++-------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 0bc4a1d5fca489cb145523724e5d4fd3475ac589..90aa448c5d0490b59527794fc319e89ebcd878eb 100644 GIT binary patch delta 482 zcmXAmUr1AN9L2xKdw;*}-d&NsIP75ygQOPeAiFi#uF=L!G_7!3Vn`57g-8f<74yMi zrO+Sy62q|cRVBef7Nouj^{|In(t`wpSi%UyhY%#8OFbMuFNXu?oSA7cJ1w5Iqid=o zR<}&z{RH9kBFTA$V5P|skJ{XxdXqbA(dG0i5k2|Oue%hV93=SXC^2x4aKfPEN|@-B zi+XMc31%(z%1Jxy2WMcSgID0g2i`;qV;rjL#3g=QHG&)qy&j59WDTO`ymHbp$Ss3KQo!BYa5kE8%mu$VYcZ ziIP2Xrmai}H*rCjT3CLIpClY#;%aHSHyqhni^w`~JZP^YH12S>Od-u{vcX++p4r_Y zn&@&~33uDw_V~AahF{-YnnfL z3H5im?0PCI1B8}C&jXR{x{+TuFy}>EuFsEFgMv=`7LvA(=lsvkIj&*^$!@mTMPjSO$WC8pQ*vw#r(rowf)ON3VRRwWD9k|m zQ2Mer8HQz7sYM3Km_d0F2zfD5B8ox~Y)OTMAP6I=LtVW5uAYa7-#a`gh6cs$8jAKu zL#}a%$zIUjQ7B^)D3F3Z7PR=K|7m*vA=ICH3E<{`epo@QuMOn8kH*&XpdA{TGJarB z5t`c%fQ-#Jsq|T8i`+#9ML0tqn&kJCpl&v8byUkYY@KwMg;Zr9$jpTRvPn2E6?v zhjXhy{JY%pY?n3v5hvwFn&oM^lTj($+Rrym5oP9h@(^r7X3ADvR%wSNBXg kvQrLv=%#Qw?xV1-T91Qboi{zVaš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. @@ -845,67 +845,67 @@ Ste si istý, že chcete kanál odstrániť? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1115,7 +1115,7 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. @@ -1349,12 +1349,12 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. @@ -2229,9 +2229,9 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr Max. prijateľná obtiažnosť - + Hardware GPU acceleration (OpenCL) - Hardvérové GPU urýchľovanie (OpenCL) + @@ -2308,5 +2308,10 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr Hide connection notifications Skryť oznámenia o stave pripojenia + + + Hardware GPU acceleration (OpenCL): + Hardvérové GPU urýchľovanie (OpenCL): + \ No newline at end of file -- 2.45.1 From 0a948d382a32918b0c3988cc450803b72525f520 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 10 Nov 2016 21:54:24 +0100 Subject: [PATCH 0492/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 94806 -> 92273 bytes src/translations/bitmessage_de.ts | 371 +++++++++++++++++------------- 2 files changed, 212 insertions(+), 159 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 047805b9f13af634b02a62a173b5573980bf9efe..2b8b429adf83ff39811ee5e8721329cf52345ace 100644 GIT binary patch delta 4260 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 Zsx{rNu1^wKSJ&1g=6Cpi6WOw^{|9>WDQf@# diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 643550c2..9859028f 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -324,7 +324,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Bestätigung der Nachricht erhalten %1 - + Broadcast queued. Rundruf in Warteschlange. @@ -354,7 +354,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Unbekannter Status: %1 %2 - + Not Connected Nicht verbunden @@ -453,87 +453,87 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die Die Addressenversionnsnummer muss entweder 3 oder 4 sein. - + Chan name needed - Name für den Chan benötigt + + + + + 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'. + - 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. + - 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. + - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1174,7 +1174,7 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% @@ -1184,27 +1184,27 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Gesendet - + Generating one new address Neue Addresse wird erstellt - + Done generating address. Doing work necessary to broadcast it... Die Addresse wurde erstellt. Arbeit wird verrichtet, um sie zu versenden... - + Generating %1 new addresses. Erzeuge %1 neue Addressen. - + %1 is already in 'Your Identities'. Not adding it again. %1 befindet sich bereits unter Ihren Identitäten, wird nicht doppelt hinzugefügt. - + Done generating address Addresse fertiggestellt. @@ -1322,7 +1322,7 @@ Receiver's required difficulty: %1 and %2 Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? @@ -1332,32 +1332,32 @@ Receiver's required difficulty: %1 and %2 Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? - + Problem communicating with proxy: %1. Please check your network settings. Kommunikationsfehler mit dem Proxy: %s. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. @@ -1367,72 +1367,72 @@ Receiver's required difficulty: %1 and %2 Die Uhrzeit ihres Computers, %1, ist möglicherweise falsch. Bitte überprüfen Sie Ihre einstellungen. - + 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. - + 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... @@ -1874,42 +1874,90 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Dialog - Chan beitreten / erstellen + Create a new chan - Neuen Chan erstellen + Join a chan - Einem Chan beitreten + Create a chan - Chan erstellen + <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> + 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>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 Nachricht an die Chan-Adresse.</p><p>Chans sind experimentell und völlig 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 wird geteilt.</p></body></html> + + + + Chan passhphrase/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 @@ -2184,9 +2232,9 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Maximale akzeptierte Schwierigkeit - + Hardware GPU acceleration (OpenCL) - Hardwaregrafikkartenbeschleunigung (OpenCL) + @@ -2263,5 +2311,10 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Hide connection notifications Verbindungsbenachrichtigungen nicht anzeigen + + + Hardware GPU acceleration (OpenCL): + Hardwaregrafikkartenbeschleunigung (OpenCL): + \ No newline at end of file -- 2.45.1 From 7033527c41797425c407de71fa59da1273451742 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 10 Nov 2016 21:55:24 +0100 Subject: [PATCH 0493/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 86100 -> 86111 bytes src/translations/bitmessage_pl.ts | 71 ++++++++++++++++-------------- 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 71522e63c3a83c487912eab4e4ed11a8ccdeecb0..4c77faf6fac6a2be73eb78e2700720000c989b3c 100644 GIT binary patch delta 534 zcmXBRT}V>_6bJD0_kQf&>qLjulE}e|Rz0{%$F0TYmW{z$8HzK*2q~DeTn}XnWqS#= z29oO#7s6^4VMRq?Ytje3MK6P(*+UZgvc4XQtX`ytF8Ofyy`2AfIRA29TF6V2QCM^P z!wr2T&0ZvUPmp|1AhflRB^ENB&OJ1CeWi|bFNi3!;)nGV%MK9SW7M4(HeI4a1wTHZk2!7#`q^ld{kFh2~(*v%Nb=w`w`5Uc7fo98Cw1Lq4n!DsUI{2mRvP~;H ze|{&*ib|)yi?D5;|H$L;a@z7^ds6E^ex2Z%)CLwkL}mTIs4Hlh-fslwUG3`UzeKNY zYmfZP=3k!i6-76*CFK;V*{6nanMc*5ILH;%fyXRqtvJRZ&86n7^CRyFyVuSPX>q9K zTF;wC!lrdxslFuNN|;5wpBc6;E+ffr+nh$)0wRpH$E;k}p@+xLs sB%8Cr7;&4+UgM?<_Tm#aChBm;kb`g;i2!z}aqOXAl%iyDDuCJAe^#oR*#H0l delta 558 zcmXAmOGs346vodt_ul`#bF*|1!dcYNESzlNkQFWhhtUkCt7S*^2Rj6k+VFcG-HkD6+cYgQoh9-lM7e|-%p4^g=vG6=XNbNW zQyb?05Ov;HyI+^e^V|8N+KMdCse|~zLCr!X4`?3gGNE}~E^+h9Fi~5dn2h8Ib;~@b zS71~6D3unrTQe{;CKEd z60mqcUoW{}oSit zsIwDIoO62clr^&kU0iSaoOkk;u6>nh?3^7iV{m@X54_(?C@$jMj=N&2M}GTpHlDY# zi8B5a^4dc>yeP9%IwITHpD8p@=tIQz`4KSTwó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. @@ -847,67 +847,67 @@ Czy na pewno chcesz usunąć ten kanał? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,7 +1117,7 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów z tego adresu. @@ -1351,12 +1351,12 @@ Odbiorca wymaga trudności: %1 i %2 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. @@ -1865,7 +1865,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Processed %n public key(s). - Przetworzono %1 klucz publiczny.Przetworzono %1 kluczy publicznych.Przetworzono %1 kluczy publicznych. + Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. @@ -2032,7 +2032,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Start Bitmessage in the tray (don't show main window) - Uruchom Bitmessage w zasobniku (nie pokazuj tego okna) + Uruchom Bitmessage w zasobniku (nie pokazuj głównego okna) @@ -2231,9 +2231,9 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Maksymalna akceptowalna trudność - + Hardware GPU acceleration (OpenCL) - Przyspieszenie sprzętowe GPU (OpenCL) + @@ -2310,5 +2310,10 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Hide connection notifications Nie pokazuj powiadomień o połączeniu + + + Hardware GPU acceleration (OpenCL): + Przyspieszenie sprzętowe GPU (OpenCL): + \ No newline at end of file -- 2.45.1 From a6ac128e9ea1ad64aaa0a80a9a70eccf6af17dbe Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 10 Nov 2016 21:56:09 +0100 Subject: [PATCH 0494/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 80617 -> 82620 bytes src/translations/bitmessage_eo.ts | 858 ++++++++++++++++++------------ 2 files changed, 515 insertions(+), 343 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 56abaa7bf39f1e16feadaf1be690667e80626899..83822afdd9dff17d0de354ba9b0eb5d7f8e4362b 100644 GIT binary patch delta 8758 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 - + AddAddressDialog @@ -59,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi kun alia. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -167,52 +166,52 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 Malforviŝi - + View HTML code as formatted text Montri HTML-n kiel aranĝita teksto - + Save message as... Konservi mesaĝon kiel... - + Mark Unread Marki kiel nelegita - + New Nova @@ -237,12 +236,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso... - + Email gateway Retpoŝta kluzo @@ -252,137 +251,137 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 - + 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 forviŝi ĝin? - + Waiting for their encryption key. Will request it again soon. Atendante ilian ĉifroŝlosilon. Baldaŭ petos ĝin denove. Encryption key request queued. - Peto por ĉifroŝlosilo envicigita. + - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Message sent. Sent at %1 Mesaĝo sendita. Sendita je %1 Need to do work to send message. Work is queued. - Devas labori por sendi mesaĝon. Laboro en atendovico. + - + 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 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. @@ -391,17 +390,17 @@ It is important that you back up this file. 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.) @@ -410,122 +409,122 @@ It is important that you back up this file. Would you like to open the file now? 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? Ĉ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 ne estas la prava formularo por vi. - + Bad address version number Malkorekta 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 - Bezonas nomon de kanalo + - + You didn't enter a chan name. - Vi ne enmetis nomon 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 ĝisdatigi 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. + 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 @@ -533,122 +532,122 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 pro %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 - Eraro: Bitmesaĝaj 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 adresversio %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 address %1 is too short. There might be something wrong with the software of your acquaintance. - Eraro: Kelkaj datumoj koditaj 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 koditaj en la adreso %1 estas tro longaj. Povus esti ke io en la programo de via konato malfunkcias. + - + Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - Eraro: Kelkaj datumoj koditaj en la adreso %1 estas misformitaj. 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'. - + 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. Priaboranta adreson %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. Priaboranta adreson %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 ero(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 De - + Sending email gateway registration request Sendanta peton pri registrado je retpoŝta kluzo @@ -663,142 +662,142 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 jaman 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 jaman 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 vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn 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 Sendanta peton pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendanta peton pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -807,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -816,277 +815,277 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi la kanalon? - + Do you really want to remove this avatar? Ĉu vi certe volas forviŝi tiun avataron? - + You have already set an avatar for this address. Do you really want to overwrite it? Vi jam agordis avataron por tiu 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... Testante... - + This is a chan address. You cannot use it as a pseudo-mailing list. Tio estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. 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. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. - + There are no recent broadcasts from this address to display. Neniaj lastatempaj elsendoj de tiu adreso por montri. - + 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 - + 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 - Adresaro + Etikedo - + Address Adreso - + Add Contact Aldoni kontakton - + Fetch Namecoin ID Venigu 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 determinisman adreson - + Delete all trashed messages Forviŝi ĉiujn mesaĝojn el rubujo - + Join / Create chan Aniĝi / Krei kanalon @@ -1096,7 +1095,7 @@ Are you sure you want to delete the channel? Ĉiuj kontoj - + Zoom level %1% Pligrandigo: %1 @@ -1111,111 +1110,107 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% Atendanta ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% Fermanta PyBitmessage... %1% - + Waiting for objects to be sent... %1% Atendanta ĝis objektoj estos senditaj... %1% - + Saving settings... %1% Konservanta agordojn... %1% - + Shutting down core... %1% Fermanta kernon... %1% - + Stopping notifications... %1% Haltiganta sciigojn... %1% - + Shutdown imminent... %1% Fermanta tuj... %1% - + %n hour(s) - - - + %n horo%n horoj - + %n day(s) - - - + %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermanta PyBitmessage... %1% - + Sent Senditaj - + Generating one new address Kreanta unu novan adreson - + Done generating address. Doing work necessary to broadcast it... Adreso kreita. Faranta laborpruvon endan por elsendi ĝin... - + Generating %1 new addresses. Kreanta %1 novajn adresojn. - + %1 is already in 'Your Identities'. Not adding it again. %1 jam estas en 'Viaj Identigoj'. Ĝi ne estos aldonita ree. - + Done generating address Ĉiuj adresoj estas kreitaj SOCKS5 Authentication problem: %1 - SOCKS5 eraro kun aŭtentigado: %1 + - + Disk full Disko plenplena - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. @@ -1225,12 +1220,12 @@ Are you sure you want to delete the channel? Eraro! Ne povas trovi adreson de sendanto (vian adreson) en la dosiero keys.dat. - + Doing work necessary to send broadcast... Faranta laborpruvon endan por sendi elsendon... - + Broadcast sent on %1 Elsendo sendita je %1 @@ -1279,7 +1274,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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. Faranta laborpruvon endan por sendi mesaĝon. @@ -1289,7 +1284,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Doing work necessary to request encryption key. Faranta laborpruvon endan por peti pri ĉifroŝlosilo. @@ -1314,14 +1309,147 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pordo-mapigo forigita - + Mark all messages as read - + Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? - + Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? + + + + Doing work necessary to send broadcast. + Faranta laborpruvon endan por sendi elsendon. + + + + 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 + + + + Wait until these tasks finish? + Ĉu atendi ĝis tiujn taskojn finos? + + + + Problem communicating with proxy: %1. Please check your network settings. + Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. + + + + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. + Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. + + + + The time on your computer, %1, may be wrong. Please verify your settings. + La horloĝo de via komputilo, %1, eble malkorektas. Bonvolu kontroli viajn agordojn. + + + + 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. + + + + 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 liveradojn. Ĉu atendi ĝis la samtempigado finos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradojn. Ĉu atendi ĝis la samtempigado finos? + + + + 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 liveradojn. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finos? + + + + Waiting for network connection... + Atendanta retkonekton... + + + + Waiting for finishing synchronisation... + Atendanta ĝis samtempigado finos... + + + + MessageView + + + Follow external link + Sekvi la ekstran 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 @@ -1475,46 +1603,42 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Nomo de la kvazaŭ-dissendlisto: - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - + About Pri - + PyBitmessage PyBitmessage - + version ? versio ? - + <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 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> - + This is Beta software. Tio estas beta-eldono. - - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - <html><head/><body><p>Aŭtorrajto © 2012-2016 Jonathan Warren<br/>Aŭtorrajto © 2013-2016 La Programistoj de Bitmesaĝo</p></body></html> + + <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>Kopirajto &copy; 2012-2016 Jonathan WARREN<br/>Kopirajto &copy; 2013-2016 La programistoj de Bitmesaĝo</p></body></html> @@ -1616,7 +1740,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres You are using TCP port ?. (This can be changed in the settings). - Ĉu vi estas uzanta TCP pordon ?. (Tio estas ŝanĝebla en la agordoj). + Vi uzas TCP-pordon ?. (Ĝi estas ŝanĝebla en la agordoj). @@ -1707,44 +1831,34 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres 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. @@ -1752,42 +1866,90 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Dialog - Dialogo + Create a new chan - Krei novan kanalon + Join a chan - Aniĝi al kanalo + Create a chan - Krei kanalon + <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 elektos 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 ili iĝos tre verŝajne la saman kanalon.</p></body></html> + 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 da personoj havas komunajn malĉifrajn ŝlosilojn. La ŝlosiloj kaj Bitmesaĝa adreso uzitaj de kanalo estas generitaj el hom-legebla vorto aŭ frazo (la nomo de la kanalo). Por sendi mesaĝon al ĉiuj en la kanalo, sendu normalan inter-personan 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 passhphrase/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 la kanalon %1 + + + + Chan creation / joining failed + Kreado / aniĝado de kanalo malsukcesis + + + + Chan creation / joining cancelled + Kreado / aniĝado de kanalo nuligita @@ -1846,295 +2008,305 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres settingsDialog - + Settings Agordoj - + Start Bitmessage on user login 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 - + Minimize to tray Plejetigi al taskopleto - + Close to tray Fermi al taskopleto - + Show notification when message received Montri sciigon kiam mesaĝo alvenas - + Run in Portable Mode 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. - + Willingly include unencrypted destination address when sending to a mobile device Volonte inkluzivi malĉifritan cel-adreson dum sendado al portebla aparato. - + Use Identicons Uzi ID-avatarojn - + Reply below Quote Respondi sub citaĵo - + Interface Language Fasada lingvo - + System Settings system Sistemaj agordoj - + User Interface Fasado - + Listening port Aŭskultanta pordo (port) - + Listen for connections on port: Aŭskulti pri konektoj ĉe pordo: - + UPnP: UPnP: - + Bandwidth limit Rettrafika limo - + Maximum download rate (kB/s): [0: unlimited] Maksimuma rapido de elŝuto (kB/s): [0: senlima] - + Maximum upload rate (kB/s): [0: unlimited] Maksimuma rapido de alŝuto (kB/s): [0: senlima] - + Proxy server / Tor Prokurila (proxy) servilo / Tor - + Type: Speco: - + 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 prokurilo - + 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 kiu 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 kiuj 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) - Aparatara GPU-a plirapidigo (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>Defaŭlte 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 eblas ŝ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 + + + + Hardware GPU acceleration (OpenCL): + Aparatara GPU-a plirapidigo (OpenCL): + - + \ No newline at end of file -- 2.45.1 From 4af788e96399141ec9111e0b8b8e6fa9d64da688 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 12 Nov 2016 15:41:58 +0100 Subject: [PATCH 0495/1102] Placeholder proxy text - based on what tor you're probably using (9150 for OSX and Windows, 9050 for others) --- src/bitmessageqt/settings.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index a67c7f42..33b4c29d 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -9,6 +9,7 @@ from PyQt4 import QtCore, QtGui from languagebox import LanguageBox +from sys import platform try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -166,12 +167,17 @@ 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")) -- 2.45.1 From 2fc2c7829960b7e28ad8a7fb085ec82265c36e07 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 12 Nov 2016 17:20:45 +0100 Subject: [PATCH 0496/1102] Extended encoding update - modified to support both encoding and decoding - fixes - added test for all encodings --- src/helper_msgcoding.py | 35 ++++++++++++++++++++++++++++------- src/messagetypes/__init__.py | 23 ++++++++++++++--------- src/messagetypes/message.py | 23 +++++++++++++++++++---- src/messagetypes/vote.py | 23 +++++++++++++++++++---- 4 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index 04c03fed..99d617f8 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -1,10 +1,10 @@ #!/usr/bin/python2.7 -import string import msgpack +import string import zlib -from debug import logger +import shared import messagetypes BITMESSAGE_ENCODING_IGNORE = 0 @@ -12,7 +12,6 @@ BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 - class MsgEncode(object): def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): self.data = None @@ -27,7 +26,8 @@ class MsgEncode(object): def encodeExtended(self, message): try: - self.data = zlib.compress(msgpack.dumps({"": "message", "subject": message['subject'], "message": ['body']}), 9) + msgObj = messagetypes.message.Message() + self.data = zlib.compress(msgpack.dumps(msgObj.encode(message)), 9) except zlib.error: logger.error("Error compressing message") raise @@ -70,14 +70,14 @@ class MsgDecode(object): logger.error("Message type missing") raise - msgObj = messagetypes.constructObject(data) + msgObj = messagetypes.constructObject(tmp) if msgObj is None: raise ValueError("Malformed message") try: msgObj.process() except: raise ValueError("Malformed message") - if msgType[""] == "message": + if msgType == "message": self.subject = msgObj.subject self.body = msgObj.body @@ -96,4 +96,25 @@ class MsgDecode(object): if subject: subject = subject.splitlines()[0] self.subject = subject - self.message = body + 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/messagetypes/__init__.py b/src/messagetypes/__init__.py index 9b5c5a05..0b63519d 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -1,7 +1,13 @@ from importlib import import_module -from pprint import pprint from os import path, listdir -import sys +from string import lower + +from debug import logger + + +class MsgBase(object): + def encode(self): + self.data = {"": lower(type(self).__name__)} def constructObject(data): @@ -11,13 +17,13 @@ def constructObject(data): print "Don't know how to handle message type: \"%s\"" % (data[""]) return None try: - returnObj = classBase(data) + returnObj = classBase() + returnObj.decode(data) except KeyError as e: - print "Missing mandatory key %s" % (e) + logger.error("Missing mandatory key %s", e) return None except: - print "classBase fail:" - pprint(sys.exc_info()) + logger.error("classBase fail", exc_info=True) return None else: return returnObj @@ -31,7 +37,6 @@ for mod in listdir(path.dirname(__file__)): try: import_module("." + splitted[0], "messagetypes") except ImportError: - print "Error importing %s" % (mod) - pprint(sys.exc_info()) + logger.error("Error importing %s", mod, exc_info=True) else: - print "Imported %s" % (mod) + logger.debug("Imported message type module %s", mod) diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index 654e6d6b..aea621cc 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -1,8 +1,23 @@ -class Message: - def __init__(self, data): +from debug import logger +from messagetypes import MsgBase + +class Message(MsgBase): + def __init__(self): + return + + def decode(self, data): self.subject = data["subject"] self.body = data["body"] + 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 ", e.name) + return self.data + def process(self): - print "Subject: %s" % (self.subject) - print "Body: %s" % (self.body) + 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 index 5b692eb2..539aed8a 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -1,8 +1,23 @@ -class Vote: - def __init__(self, data): +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 ", e.name) + return self.data + def process(self): - print "msgid: %s" % (self.msgid) - print "vote: %s" % (self.vote) + logger.debug("msgid: %s", self.msgid) + logger.debug("vote: %s", self.vote) -- 2.45.1 From d35062b49c215c4ece23f7dc60cec9850d413154 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 13 Nov 2016 08:50:09 +0100 Subject: [PATCH 0497/1102] Half-open connection limit warning fix - it only should complain if on Windows and can't determine the Windows version --- src/helper_startup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helper_startup.py b/src/helper_startup.py index b7a1ef1b..cc74649a 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -140,10 +140,9 @@ def loadConfig(): 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 few 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 -- 2.45.1 From 54e3465575a9413e2f324f7a5c5102eb8646ced2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 14 Nov 2016 20:19:26 +0100 Subject: [PATCH 0498/1102] HTML parser queue flush fix - the queue wasn't correctly flushed --- src/bitmessageqt/safehtmlparser.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 1ca9cbb0..8009f02c 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -120,6 +120,13 @@ class SafeHTMLParser(HTMLParser): parserProcess = multiprocessing.Process(target=regexpSubprocess, name="RegExParser", args=(parserInputQueue, parserOutputQueue)) parserProcess.start() parserLock.release() + # flush queue + try: + while True: + tmp = parserOutputQueue.get(False) + except Queue.Empty: + logger.debug("Parser queue flushed") + pass parserInputQueue.put(tmp) try: tmp = parserOutputQueue.get(True, 1) @@ -130,14 +137,6 @@ class SafeHTMLParser(HTMLParser): parserProcess = multiprocessing.Process(target=regexpSubprocess, name="RegExParser", args=(parserInputQueue, parserOutputQueue)) parserProcess.start() parserLock.release() - else: - # flush queue - try: - while True: - tmp = parserOutputQueue.get(False) - except Queue.Empty: - logger.debug("Parser queue flushed") - pass self.raw += tmp -- 2.45.1 From b9748c55aac2120bdbcdf9ddbde85ef464230d95 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 14 Nov 2016 20:20:41 +0100 Subject: [PATCH 0499/1102] Don't connect to self fix - the hidden service don't connect to yourself fix was broken, this fixes the fix --- src/class_outgoingSynSender.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 5bef66c6..bca56b33 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -47,10 +47,11 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.knownNodesLock.release() if shared.config.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 == shared.config.get('bitmessagesettings', 'onionhostname') and peer.port == shared.config.getint("bitmessagesettings", "onionport"): continue - priority /= 10 # hidden services have 10x priority over plain net elif peer.host.find(".onion") != -1: # onion address and so proxy continue if priority <= 0.001: # everyone has at least this much priority -- 2.45.1 From 5a438ccddd843ad10e116b20b11791b4768ad5fb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 14 Nov 2016 20:21:46 +0100 Subject: [PATCH 0500/1102] OpenCL initialisation fix --- src/openclpow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openclpow.py b/src/openclpow.py index 2f7f0158..641db324 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -24,7 +24,7 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, gpus, hash_dt, vendors + global ctx, queue, program, gpus, enabledGpus, hash_dt, vendors try: hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) try: -- 2.45.1 From 966b4382d89103d950d68d7a38406431ab00ab80 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 14 Nov 2016 20:22:10 +0100 Subject: [PATCH 0501/1102] Add handler for unknown encoding --- src/helper_msgcoding.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index 99d617f8..ad26cbcb 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -6,6 +6,7 @@ import zlib import shared import messagetypes +from tr import _translate BITMESSAGE_ENCODING_IGNORE = 0 BITMESSAGE_ENCODING_TRIVIAL = 1 @@ -23,6 +24,8 @@ class MsgEncode(object): self.encodeSimple(message) elif self.encoding == BITMESSAGE_ENCODING_TRIVIAL: self.encodeTrivial(message) + else: + raise ValueError("Unknown encoding %i" % (encoding)) def encodeExtended(self, message): try: @@ -44,6 +47,7 @@ class MsgEncode(object): self.data = message['body'] self.length = len(self.data) + class MsgDecode(object): def __init__(self, encoding, data): self.encoding = encoding @@ -51,7 +55,9 @@ class MsgDecode(object): self.decodeExtended(data) elif self.encoding in [BITMESSAGE_ENCODING_SIMPLE, BITMESSAGE_ENCODING_TRIVIAL]: self.decodeSimple(data) - return + 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): try: -- 2.45.1 From 612333a26750240b08011e5d502e8435d07eeb9a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 14 Nov 2016 20:23:58 +0100 Subject: [PATCH 0502/1102] Enable support for extended encoding - receiving extended encoding now works - sending works from the GUI by pressing "Shift" while clicking on "Send" - requires https://pypi.python.org/pypi/msgpack-python --- src/bitmessageqt/__init__.py | 6 ++++-- src/class_objectProcessor.py | 37 ++++++++++-------------------------- src/class_singleWorker.py | 25 ++++++++++++------------ 3 files changed, 27 insertions(+), 41 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ff4bfbcf..03aec111 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1890,6 +1890,8 @@ class MyForm(settingsmixin.SMainWindow): 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() == 0: @@ -2022,7 +2024,7 @@ class MyForm(settingsmixin.SMainWindow): 'msgqueued', 0, # retryNumber 'sent', # folder - 2, # encodingtype + encoding, # encodingtype shared.config.getint('bitmessagesettings', 'ttl') ) @@ -2075,7 +2077,7 @@ class MyForm(settingsmixin.SMainWindow): 'broadcastqueued', 0, # retryNumber 'sent', # folder - 2, # encoding type + encoding, # encoding type shared.config.getint('bitmessagesettings', 'ttl') ) sqlExecute( diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index d5fe3a31..c85b58a1 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -17,6 +17,7 @@ import helper_generic from helper_generic import addDataPadding import helper_bitcoin import helper_inbox +import helper_msgcoding import helper_sent from helper_sql import * import tr @@ -482,24 +483,15 @@ class objectProcessor(threading.Thread): if queryreturn == []: logger.info('Message ignored because address not in whitelist.') blockMessage = True - + toLabel = shared.config.get(toAddress, 'label') if toLabel == '': toLabel = toAddress - 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 = '' + decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + subject = decodedMessage.subject + body = decodedMessage.body + # 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.') @@ -562,7 +554,7 @@ class objectProcessor(threading.Thread): 'broadcastqueued', 0, 'sent', - 2, + messageEncodingType, TTL) helper_sent.insert(t) @@ -746,18 +738,9 @@ class objectProcessor(threading.Thread): sendersAddressVersion, sendersStream, calculatedRipe) logger.debug('fromAddress: ' + fromAddress) - 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 - else: - body = 'Unknown encoding type.\n\n' + repr(message) - subject = '' + decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + subject = decodedMessage.subject + body = decodedMessage.body toAddress = '[Broadcast subscribers]' if helper_inbox.isMessageAlreadyInInbox(sigHash): diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index f6fc9a80..377f900b 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -15,6 +15,7 @@ from debug import logger from helper_sql import * import helper_inbox from helper_generic import addDataPadding +import helper_msgcoding from helper_threading import * import l10n from protocol import * @@ -370,10 +371,10 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='broadcastqueued' WHERE status = 'doingbroadcastpow' ''') queryreturn = sqlQuery( - '''SELECT fromaddress, subject, message, ackdata, ttl FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') + '''SELECT fromaddress, subject, message, ackdata, ttl, encodingtype FROM sent WHERE status=? and folder='sent' ''', 'broadcastqueued') for row in queryreturn: - fromaddress, subject, body, ackdata, TTL = row + fromaddress, subject, body, ackdata, TTL, encoding = row status, addressVersionNumber, streamNumber, ripe = decodeAddress( fromaddress) if addressVersionNumber <= 1: @@ -436,9 +437,10 @@ class singleWorker(threading.Thread, StoppableThread): if addressVersionNumber >= 3: 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 + dataToEncrypt += encodeVarint(encoding) # message encoding type + encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": body}, encoding) + dataToEncrypt += encodeVarint(encodedMessage.length) + dataToEncrypt += encodedMessage.data dataToSign = payload + dataToEncrypt signature = highlevelcrypto.sign( @@ -503,9 +505,9 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='msgqueued' WHERE status IN ('doingpubkeypow', 'doingmsgpow')''') queryreturn = sqlQuery( - '''SELECT toaddress, fromaddress, subject, message, ackdata, status, ttl, retrynumber FROM sent WHERE (status='msgqueued' or status='forcepow') and folder='sent' ''') + '''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 = row + toaddress, fromaddress, subject, message, ackdata, status, TTL, retryNumber, encoding = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress( toaddress) fromStatus, fromAddressVersionNumber, fromStreamNumber, fromRipe = decodeAddress( @@ -751,11 +753,10 @@ class singleWorker(threading.Thread, StoppableThread): 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 += '\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 + payload += encodeVarint(encoding) # message encoding type + encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding) + payload += encodeVarint(encodedMessage.length) + payload += encodedMessage.data if shared.config.has_section(toaddress): logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') fullAckPayload = '' -- 2.45.1 From ff2f3e62c09e8ff3f0ab8459e72a2e3cfb07b18a Mon Sep 17 00:00:00 2001 From: David Parrish Date: Mon, 14 Nov 2016 18:33:46 -0500 Subject: [PATCH 0503/1102] Update pybitmessage.desktop with more search friendly GenericName --- desktop/pybitmessage.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/pybitmessage.desktop b/desktop/pybitmessage.desktop index a97bd664..05970440 100644 --- a/desktop/pybitmessage.desktop +++ b/desktop/pybitmessage.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Type=Application Name=PyBitmessage -GenericName=PyBitmessage +GenericName=Bitmessage Client Comment=Send encrypted messages Exec=pybitmessage %F Icon=pybitmessage -- 2.45.1 From fbc9886eda03cca242173d360144a31ce5c8eb92 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:06:56 +0100 Subject: [PATCH 0504/1102] OpenCL settings saving fix --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 03aec111..a274212b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2410,8 +2410,8 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - if self.settingsDialogInstance.ui.checkBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): - shared.config.set('bitmessagesettings', 'opencl', self.settingsDialogInstance.ui.checkBoxOpenCL.currentText().toUtf8()) + if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): + shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) acceptableDifficultyChanged = False -- 2.45.1 From c6d45dd394b7ff39cc3120f4b4cc915d16a377bf Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:07:53 +0100 Subject: [PATCH 0505/1102] Encoding when sending to self - when sending to self, it always used encoding 2 when saving into the inbox. Now uses the one that's currently selected --- src/class_singleWorker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 377f900b..bab159af 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -841,7 +841,7 @@ class singleWorker(threading.Thread, StoppableThread): 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', 2, 0, sigHash) + time.time()), message, 'inbox', encoding, 0, sigHash) helper_inbox.insert(t) shared.UISignalQueue.put(('displayNewInboxMessage', ( -- 2.45.1 From bae7351849cfc89e36c58109acde32a8a78e92b8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:09:08 +0100 Subject: [PATCH 0506/1102] Formating and standalone fix - when running as a standalone program, helper_msgcoding logger import was missing --- src/helper_msgcoding.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index ad26cbcb..2ae44eea 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -5,6 +5,7 @@ import string import zlib import shared +from debug import logger import messagetypes from tr import _translate @@ -13,6 +14,7 @@ BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 + class MsgEncode(object): def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): self.data = None -- 2.45.1 From e76b10a6ed4c2453e94b4d6329d04a62ffcc7082 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:10:14 +0100 Subject: [PATCH 0507/1102] Logging fix --- src/messagetypes/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 0b63519d..16d97ae7 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -14,7 +14,7 @@ def constructObject(data): try: classBase = eval(data[""] + "." + data[""].title()) except NameError: - print "Don't know how to handle message type: \"%s\"" % (data[""]) + logger.error("Don't know how to handle message type: \"%s\"", data[""]) return None try: returnObj = classBase() -- 2.45.1 From 7cc0f8fab05df45e817f724e16648a59667d23e1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:10:33 +0100 Subject: [PATCH 0508/1102] Add extended encoding message validation - validates variables of the "message" type --- src/messagetypes/message.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index aea621cc..0ba97cd9 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -1,13 +1,21 @@ from debug import logger from messagetypes import MsgBase + class Message(MsgBase): def __init__(self): return def decode(self, data): - self.subject = data["subject"] - self.body = data["body"] + # 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() -- 2.45.1 From 3f3774ff1feefc111c0cdbd981febfcacdbc6843 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Nov 2016 17:11:36 +0100 Subject: [PATCH 0509/1102] Translation source update - add extended encoding translation sources --- src/translations/bitmessage.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 130982df..c8081610 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -13,6 +13,7 @@ SOURCES = ../addresses.py\ ../helper_bootstrap.py\ ../helper_generic.py\ ../helper_inbox.py\ + ../helper_msgcoding.py\ ../helper_sent.py\ ../helper_startup.py\ ../shared.py\ -- 2.45.1 From 3bafd597afa6351ddac250ab21304b5b6067291e Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 15 Nov 2016 21:36:16 +0100 Subject: [PATCH 0510/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 82620 -> 82985 bytes src/translations/bitmessage_eo.ts | 353 ++++++++++++++++-------------- 2 files changed, 184 insertions(+), 169 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 83822afdd9dff17d0de354ba9b0eb5d7f8e4362b..98ae14d60cfd19ccc9f3b2daee9efc583899c532 100644 GIT binary patch delta 2227 zcmZ`)YgAKL8r|n6xi`7FNk)8BQDRVu!bngoDyY~Nsa7S{QSng_QKI1$(1;IQf=C@L zio#r^%2HHHhk+40h*YgsT~!<(6BMyhtT=-8u^hn{=r|)dpYWq=b*=ev)?Vjv&)MJp z_V?YBn^dJ+R5`sg$pA)zv2D2?7H)KXZkUm~w>&q|9OS(cs$*Y(St7ufD!|4lAcTh! zI-m(X4kV0%zNiKmACDfPF925)dQ|)gXnU3G8l7Hy4ddQx1?G)LXz}O3(uZA;=rq$aD`qHqR*nCJ5NI#t7VZ;Xte#u>K;7kM*QC zB5*K!HgM-0$|ul%b2DlU+ko5i(b%8fV&CI#$ajEt7+zLWEIW@d&HgrEbUSm~rw5*1 zX9L}pK31Bg_f|Gc8Vvj+k@+ur1TB6U&)!cf02?|{p1>L1ZZxySpzo4KGW(lH z^u0<>#p9J`DT-J>qVCay&6z25$D9*L$5Rf*XyOB7AQgw{0Uw@WF19wv&4ZMit z?kk-@U8zFarULV`Ds;7n0k5$N!=^gmx<%3R@LeFIO<~$YBL7*X7(DhXpnZYDH{=^& zf01HDT?IW~rU;PE0v+{=(Mf4wz5cD3U^PL({4UEbg~ff)4~k1)ZUUBtDry89FzjA8 zHYw!ZO7qlb_mzey%GtnrWuLP7qeZwkgzNQ3%|7$tNx) zrS~r7lYaE45EA&59P*!8#cx@a2F&95JyY+21zh2aZ(RXayyE{NQ!K_HzWn!AAZ!O; zxxFWF)yyA#C&8^M{z9Z4@d)(fua~(|N(H_#oPrw^#kcbGP=2!DmXi)Fj}yj-HNf*Q zAt-t%uEZdZ0F3u#Job^VlwA?wbe%)(d}}-jBRiB5V)14ScK@a{5rt zS~}%O-t2#SfbiFCcd4EhcH^M`cH^~k-Prgq;pjAqcZV$e5Kss@F&kCMHY_F^5pUMLUFIBG&wE%Hh>a4F8PztiuxjvM#lN;6Y89i{MPJMFThd}ET z*+U3+uVd<$8aADmT59xcLL91h>nWo|ZLAXY8L~=k=Gu#7U$t>@^B6Jw zi-T0uZEympmpng@|NrSnjk8kt8%&8$h{XSyVOSU?L)0DBa}Ea%k64Q&_64+ z)~Q+40-C#!shD==+fp#kGukEVNRKwFc57-TVP9>|>6>)vd2K;m2)WWtj?@^_)s@;#7F(%v~h?rDk8K6WD$G_`3To2WDOZjwfXF9fpMqz{HuEH$Chq$&ll zI!~InJ|6IVBgM2w0p2FbmQMSNO=?8sUvKa@)l18F1?U-qB;F)sdR!lfz30!keSy=r}HVCRHan&APopglCH*C zsd3zpY7MP`W2)59?g3`9OFyrxqpsW`wQVN%XZY&W_o;s!E!6c-_ywpwryH{5EMPvU zGw-JRmk!nW%4NWfS-KHfCn)oYy1(hR0Evwk~>7BThoVn zoFTjWCr0+O`pBFhy{m|g=NC6vg+7NKT2;$$Fr{EQd-K!CXO=J!YR=@o;+Od8zTcxqC1j(J&zqHaHQ@Jdi{)8yv9H`YIYu znmcGEo^~8GUrED3YwzYUG?KA`c2m2)S=n{Q0#QC2F;bphVjMedw%uk*v^ky8%WNil zw9^#rFr_%+9Z9PlCYxhPQcSF4nMM56w!$8r>@=-SN-;U@Nht|2@~M)(i#1`+Ws_`l l$i~Qn@PYL=JpL~W^}E#YG=4YdH;)Ol`0Krug?~4$`ybB~qKp6l delta 1986 zcmX9OyUbraNZ%M~;#D2PCe zC<@z(%6dyoAd0KTh>AxA-2yi=k>F8)2T?GV2ZAD7?t<)3`Rl9hSN-01yCm0doUktta(+4vF ze-2SwyMYC#5LGS`-oy0dY_NB7@Y#ww;#NL{zZ(%#oDAmPjX6oQJ~|O|PlN&9PcT0# z1k5`P3pB-qA^1Y5fwGqQ<+&Wiy4m}IPyyRln1Id<>`QV0RyU%u))8#PAP$wx0`4T> za44<+QG_PrM&M>YZn@A|h{e6|(}3iKzDuNK>rYI#w-*R}!5sD&fTzpZC}$Or^pd&z zoC0&QFfVxw@b9;nf9yj@xO<09$gKeLysLzACWmW9Y!T?YbU&8Z{}AZ}D|o3iFLKI0NUd;vDbRnhaVJO=kF-n=>QI>*^!Yk=H&-1Srs zilUagvAUkjIl#3V76Q+}-B)D+zen=&Mm3qz!|R)l0iHp;v8b8eH}Q_g?g9C|yxUGP z@t~R?6Lf&08{oaej{tl3^S;eT0iS9&xyDkJ5@`(vH|tas^tUWz{P7yi7Je9ouk-P7Vc4`GN1}`Hf&HA ztce5j$Wm_)eix{Ny5e~jn0k^jTW#iCZOUr3$$#u6P3%{@fsP%T)c7=DSG*?unm;jJ zqFGi-HS+jD^X=EUz)X#1XGAC1gs&8v+LUK+)SP@RsBNyM;ct{!u)F4JwF9-TT5~Ig zn7VVCE)8v0o*_7t<^h?>!uz5f=62ca%lEIF z_^Yy7usHPpqRWb=>-^UQUH;2gBwSX`3g&UoBXqk88iCp--QG!qDU;I_bli;*)Ju_~DRPR1JAN zOVX{RJ_LOyiF^~VqD>MzmIALfNcwy$=_yhMw3fWvF;a9yF%5vCH^}%(X~tj`@m(w} z&LMA~^++4C3kc6hrRQ6T$G@bC=5R3832CQp0DAT2^}dErXONOD_F zGmW3Ua_>5FFW+0Qy?=t--K}?7LNQ-V(0eSd2h4}`<{h+u{8+uWQVm?~)B6^mp%$g; zgZs`wIW4|B+NnXG(nn_G4SFH-8SsJA1C6mLQ4g)TbQ)n`1 z-yuppg-WPo<^)cOlfv>kJ~G&SMpEA}gzl9?*rXc5o9`Q1qSpep$#0OU>kUt5c+lLt zZS?V^`f48-{nM6#xhygUG??foRd1Z=vIQ7)GEV!M$ffKtPOl^~M@x+J|9K9$Uuul4 zD5M`oxG`;WFy4bH!EmxTj?DQ#ujyne diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 05b2b1e2..ab043ac7 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi kun alia. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -316,7 +316,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Ricevis konfirmon de la mesaĝo je %1 - + Broadcast queued. Elsendo en atendovico. @@ -532,17 +532,17 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 pro %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. @@ -587,67 +587,67 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - + 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. Priaboranta adreson %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. Priaboranta adreson %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 ero(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 De - + Sending email gateway registration request Sendanta peton pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 jaman 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 jaman 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 vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn 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 Sendanta peton pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendanta peton pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi la kanalon? - + Do you really want to remove this avatar? Ĉu vi certe volas forviŝi tiun avataron? - + You have already set an avatar for this address. Do you really want to overwrite it? Vi jam agordis avataron por tiu 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... Testante... - + This is a chan address. You cannot use it as a pseudo-mailing list. Tio estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. 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. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. - + There are no recent broadcasts from this address to display. Neniaj lastatempaj elsendoj de tiu adreso por montri. - + 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). @@ -1110,7 +1110,7 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. @@ -1120,37 +1120,37 @@ Are you sure you want to delete the channel? La nova versio de PyBitmessage estas disponebla: %1. Elŝutu ĝin de https://github.com/Bitmessage/PyBitmessage/releases/latest - + Waiting for PoW to finish... %1% Atendanta ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% Fermanta PyBitmessage... %1% - + Waiting for objects to be sent... %1% Atendanta ĝis objektoj estos senditaj... %1% - + Saving settings... %1% Konservanta agordojn... %1% - + Shutting down core... %1% Fermanta kernon... %1% - + Stopping notifications... %1% Haltiganta sciigojn... %1% - + Shutdown imminent... %1% Fermanta tuj... %1% @@ -1165,7 +1165,7 @@ Are you sure you want to delete the channel? %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermanta PyBitmessage... %1% @@ -1215,61 +1215,61 @@ Are you sure you want to delete the channel? Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... Faranta laborpruvon endan por sendi elsendon... - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendanta peton pri ĉifroŝlosilo de ricevonto. - + Looking up the receiver's public key Serĉanta publikan ĉifroŝlosilon 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. Faranta laborpruvon endan 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 Faranta laborpruvon endan 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 @@ -1279,7 +1279,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Faranta laborpruvon endan por sendi mesaĝon. - + Message sent. Waiting for acknowledgement. Sent on %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 @@ -1289,12 +1289,12 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Faranta laborpruvon endan por peti pri ĉifroŝlosilo. - + Broadcasting the public key request. This program will auto-retry if they are offline. Elsendanta peton pri publika ĉifroŝlosilo. La programo reprovos se ili estas eksterrete. - + Sending public key request. Waiting for reply. Requested at %1 Sendanta peton pri publika ĉifroŝlosilo. Atendanta respondon. Petis je %1 @@ -1314,7 +1314,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? @@ -1324,32 +1324,32 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Faranta laborpruvon endan por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? - + Problem communicating with proxy: %1. Please check your network settings. Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. @@ -1359,72 +1359,72 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 La horloĝo de via komputilo, %1, eble malkorektas. Bonvolu kontroli viajn agordojn. - + 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. - + 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 liveradojn. Ĉu atendi ĝis la samtempigado finos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradojn. Ĉu atendi ĝis la samtempigado finos? - + 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 liveradojn. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finos? - + Waiting for network connection... Atendanta retkonekton... - + Waiting for finishing synchronisation... Atendanta ĝis samtempigado finos... @@ -1452,6 +1452,21 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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 + + NewAddressDialog @@ -2008,218 +2023,218 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres settingsDialog - + Settings Agordoj - + Start Bitmessage on user login 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 - + Minimize to tray Plejetigi al taskopleto - + Close to tray Fermi al taskopleto - + Show notification when message received Montri sciigon kiam mesaĝo alvenas - + Run in Portable Mode 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. - + Willingly include unencrypted destination address when sending to a mobile device Volonte inkluzivi malĉifritan cel-adreson dum sendado al portebla aparato. - + Use Identicons Uzi ID-avatarojn - + Reply below Quote Respondi sub citaĵo - + Interface Language Fasada lingvo - + System Settings system Sistemaj agordoj - + User Interface Fasado - + Listening port Aŭskultanta pordo (port) - + Listen for connections on port: Aŭskulti pri konektoj ĉe pordo: - + UPnP: UPnP: - + Bandwidth limit Rettrafika limo - + Maximum download rate (kB/s): [0: unlimited] Maksimuma rapido de elŝuto (kB/s): [0: senlima] - + Maximum upload rate (kB/s): [0: unlimited] Maksimuma rapido de alŝuto (kB/s): [0: senlima] - + Proxy server / Tor Prokurila (proxy) servilo / Tor - + Type: Speco: - + 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 prokurilo - + 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 kiu 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 kiuj 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 @@ -2229,82 +2244,82 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres - + <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>Defaŭlte 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 eblas ŝ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 - + Hardware GPU acceleration (OpenCL): Aparatara GPU-a plirapidigo (OpenCL): -- 2.45.1 From 1d3757ddc8d983651c9fa8cd47ea11e4d8902504 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 15 Nov 2016 21:38:05 +0100 Subject: [PATCH 0511/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 86111 -> 86508 bytes src/translations/bitmessage_pl.ts | 353 ++++++++++++++++-------------- 2 files changed, 184 insertions(+), 169 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 4c77faf6fac6a2be73eb78e2700720000c989b3c..19ccbbdf42fc02e0b75befdcf0ce5202fcf0ec43 100644 GIT binary patch delta 2231 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 diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index 668b5eb6..f8c1bafc 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -320,7 +320,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Otrzymano potwierdzenie odbioru wiadomości %1 - + Broadcast queued. Przekaz w kolejce do wysłania. @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,7 +1117,7 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów z tego adresu. @@ -1127,37 +1127,37 @@ Czy na pewno chcesz usunąć ten kanał? 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% @@ -1172,7 +1172,7 @@ Czy na pewno chcesz usunąć ten kanał? %n dzień%n dni%n dni - + Shutting down PyBitmessage... %1% Zamykanie PyBitmessage... %1% @@ -1222,61 +1222,61 @@ Czy na pewno chcesz usunąć ten kanał? 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 Przekaz wysłane o %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 @@ -1286,7 +1286,7 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1296,12 +1296,12 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1321,7 +1321,7 @@ Odbiorca wymaga trudności: %1 i %2 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? @@ -1331,32 +1331,32 @@ Odbiorca wymaga trudności: %1 i %2 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ó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 - + 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. @@ -1366,72 +1366,72 @@ Odbiorca wymaga trudności: %1 i %2 Czas na Twoim komputerze, %1, może być błędny. Proszę sprawdź swoje ustawienia. - + 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. - + 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? - + 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... @@ -1459,6 +1459,21 @@ Odbiorca wymaga trudności: %1 i %2 Kliknij tutaj aby wyłączyć HTML + + MsgDecode + + + The message has an unknown encoding. +Perhaps you should upgrade Bitmessage. + Wiadomość zawiera nierozpozne kodowanie. +Prawdopodobnie powinieneś zaktualizować Bitmessage. + + + + Unknown encoding + Nierozpoznane kodowanie + + NewAddressDialog @@ -2015,218 +2030,218 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 'Identiconó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ść @@ -2236,82 +2251,82 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - + <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 Nie wysyłaj ponownie po - + and i - + days dniach - + months. miesiącach. - + Resends Expire Niedoręczone wiadomości - + Hide connection notifications Nie pokazuj powiadomień o połączeniu - + Hardware GPU acceleration (OpenCL): Przyspieszenie sprzętowe GPU (OpenCL): -- 2.45.1 From 5cea1e04d1e35882893b069ce297730299a0c003 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Nov 2016 15:18:09 +0100 Subject: [PATCH 0512/1102] SSL disconnect fix - sometimes SSL connections unnecessarily disconnected on non-fatal errors. This should fix that. This is however a short term solution because of migrating to asyncore which has its own error handling --- src/class_receiveDataThread.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index df38f228..977250e0 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -90,9 +90,11 @@ class receiveDataThread(threading.Thread): shared.numberOfBytesReceivedLastSecond = 0 dataLen = len(self.data) try: + ssl = False if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and self.connectionIsOrWasFullyEstablished and shared.haveSSL(not self.initiatedConnection)): + ssl = True dataRecv = self.sslSock.recv(1024) else: dataRecv = self.sock.recv(1024) @@ -103,8 +105,11 @@ class receiveDataThread(threading.Thread): logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break except Exception as err: - if (sys.platform == 'win32' and err.errno in ([2, 10035])) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): - select.select([self.sslSock], [], []) + if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): + if ssl: + select.select([self.sslSock], [], []) + else: + select.select([self.sock], [], []) continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: -- 2.45.1 From 7ca6576dfc6ad7bd54ad8fc14aa65f78293b7d03 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Nov 2016 19:36:50 +0100 Subject: [PATCH 0513/1102] Connection indicator for hidden service - the number of connections as well as connection indicator was broken when running as a hidden service. This is a workaround --- src/class_receiveDataThread.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 977250e0..0b686ddf 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -58,8 +58,9 @@ class receiveDataThread(threading.Thread): 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 shared.config.get('bitmessagesettings', 'onionhostname') and shared.checkSocksIP(self.peer.host) else self.peer.host shared.connectedHostsList[ - 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.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.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 self.streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. @@ -131,9 +132,9 @@ class receiveDataThread(threading.Thread): pass self.sendDataThreadQueue.put((0, 'shutdown','no data')) # commands the corresponding sendDataThread to shut itself down. try: - del shared.connectedHostsList[self.peer.host] + del shared.connectedHostsList[self.hostIdent] except Exception as err: - logger.error('Could not delete ' + str(self.peer.host) + ' from shared.connectedHostsList.' + str(err)) + logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) try: del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ @@ -773,7 +774,7 @@ class receiveDataThread(threading.Thread): logger.debug ('Closed connection to ' + str(self.peer) + ' because they are interested in stream ' + str(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. + 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. # If this was an incoming connection, then the sendDataThread # doesn't know the stream. We have to set it. if not self.initiatedConnection: -- 2.45.1 From 303352099565dc9a441b8d741a4e0665b8b1defd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Dec 2016 16:45:04 +0100 Subject: [PATCH 0514/1102] Directory maintenance - rearrange obsolete build scripts - rearrange working build scripts - add build / devel scripts I use - add existing development tests (bloom filter, message encoding, thread interrupts) - add directory descriptions --- build/README.md | 2 + build/changelang.sh | 16 +++++ compiletest.py => build/compiletest.py | 0 build/mergepullrequest.sh | 11 ++++ osx.sh => build/osx.sh | 0 build/updatetranslations.sh | 22 +++++++ dev/README.md | 3 + dev/bloomfiltertest.py | 60 +++++++++++++++++++ dev/msgtest.py | 27 +++++++++ dev/powinterrupttest.py | 49 +++++++++++++++ packages/README.md | 36 +++++++++++ .../pyinstaller}/bitmessagemain.spec | 0 Makefile => packages/unmaintained/Makefile | 0 arch.sh => packages/unmaintained/arch.sh | 0 .../unmaintained/archpackage}/PKGBUILD | 0 debian.sh => packages/unmaintained/debian.sh | 0 .../unmaintained/debian}/changelog | 0 .../unmaintained/debian}/compat | 0 .../unmaintained/debian}/control | 0 .../unmaintained/debian}/copyright | 0 {debian => packages/unmaintained/debian}/docs | 0 .../unmaintained/debian}/manpages | 0 {debian => packages/unmaintained/debian}/pybm | 0 .../unmaintained/debian}/rules | 0 .../unmaintained/debian}/source/format | 0 .../debian}/source/include-binaries | 0 ebuild.sh => packages/unmaintained/ebuild.sh | 0 .../unmaintained/generate.sh | 0 puppy.sh => packages/unmaintained/puppy.sh | 0 .../unmaintained/puppypackage}/icon14.xpm | 0 .../pybitmessage-0.3.5.pet.specs | 0 rpm.sh => packages/unmaintained/rpm.sh | 0 .../rpmpackage}/pybitmessage.spec | 0 slack.sh => packages/unmaintained/slack.sh | 0 .../unmaintained/slackpackage}/doinst.sh | 0 .../unmaintained/slackpackage}/slack-desc | 0 {upstart => packages/upstart}/bitmessage.conf | 0 37 files changed, 226 insertions(+) create mode 100644 build/README.md create mode 100755 build/changelang.sh rename compiletest.py => build/compiletest.py (100%) create mode 100755 build/mergepullrequest.sh rename osx.sh => build/osx.sh (100%) create mode 100755 build/updatetranslations.sh create mode 100644 dev/README.md create mode 100644 dev/bloomfiltertest.py create mode 100644 dev/msgtest.py create mode 100644 dev/powinterrupttest.py create mode 100644 packages/README.md rename {pyinstaller => packages/pyinstaller}/bitmessagemain.spec (100%) rename Makefile => packages/unmaintained/Makefile (100%) rename arch.sh => packages/unmaintained/arch.sh (100%) rename {archpackage => packages/unmaintained/archpackage}/PKGBUILD (100%) rename debian.sh => packages/unmaintained/debian.sh (100%) rename {debian => packages/unmaintained/debian}/changelog (100%) rename {debian => packages/unmaintained/debian}/compat (100%) rename {debian => packages/unmaintained/debian}/control (100%) rename {debian => packages/unmaintained/debian}/copyright (100%) rename {debian => packages/unmaintained/debian}/docs (100%) rename {debian => packages/unmaintained/debian}/manpages (100%) rename {debian => packages/unmaintained/debian}/pybm (100%) rename {debian => packages/unmaintained/debian}/rules (100%) rename {debian => packages/unmaintained/debian}/source/format (100%) rename {debian => packages/unmaintained/debian}/source/include-binaries (100%) rename ebuild.sh => packages/unmaintained/ebuild.sh (100%) rename generate.sh => packages/unmaintained/generate.sh (100%) rename puppy.sh => packages/unmaintained/puppy.sh (100%) rename {puppypackage => packages/unmaintained/puppypackage}/icon14.xpm (100%) rename {puppypackage => packages/unmaintained/puppypackage}/pybitmessage-0.3.5.pet.specs (100%) rename rpm.sh => packages/unmaintained/rpm.sh (100%) rename {rpmpackage => packages/unmaintained/rpmpackage}/pybitmessage.spec (100%) rename slack.sh => packages/unmaintained/slack.sh (100%) rename {slackpackage => packages/unmaintained/slackpackage}/doinst.sh (100%) rename {slackpackage => packages/unmaintained/slackpackage}/slack-desc (100%) rename {upstart => packages/upstart}/bitmessage.conf (100%) diff --git a/build/README.md b/build/README.md new file mode 100644 index 00000000..248d2c41 --- /dev/null +++ b/build/README.md @@ -0,0 +1,2 @@ +This directory contains scripts that are helpful for developers when building +or maintaining PyBitmessage. diff --git a/build/changelang.sh b/build/changelang.sh new file mode 100755 index 00000000..915c5dea --- /dev/null +++ b/build/changelang.sh @@ -0,0 +1,16 @@ +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/compiletest.py b/build/compiletest.py similarity index 100% rename from compiletest.py rename to build/compiletest.py diff --git a/build/mergepullrequest.sh b/build/mergepullrequest.sh new file mode 100755 index 00000000..35e87566 --- /dev/null +++ b/build/mergepullrequest.sh @@ -0,0 +1,11 @@ +#!/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/osx.sh b/build/osx.sh similarity index 100% rename from osx.sh rename to build/osx.sh diff --git a/build/updatetranslations.sh b/build/updatetranslations.sh new file mode 100755 index 00000000..ba5a3fdb --- /dev/null +++ b/build/updatetranslations.sh @@ -0,0 +1,22 @@ +#!/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/dev/README.md b/dev/README.md new file mode 100644 index 00000000..41bf59c8 --- /dev/null +++ b/dev/README.md @@ -0,0 +1,3 @@ +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 new file mode 100644 index 00000000..539d00f3 --- /dev/null +++ b/dev/bloomfiltertest.py @@ -0,0 +1,60 @@ +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 new file mode 100644 index 00000000..d5a8be8e --- /dev/null +++ b/dev/msgtest.py @@ -0,0 +1,27 @@ +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 new file mode 100644 index 00000000..2f8cfcac --- /dev/null +++ b/dev/powinterrupttest.py @@ -0,0 +1,49 @@ +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 != "MainThread": + 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/packages/README.md b/packages/README.md new file mode 100644 index 00000000..ed2df3cc --- /dev/null +++ b/packages/README.md @@ -0,0 +1,36 @@ +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/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec similarity index 100% rename from pyinstaller/bitmessagemain.spec rename to packages/pyinstaller/bitmessagemain.spec diff --git a/Makefile b/packages/unmaintained/Makefile similarity index 100% rename from Makefile rename to packages/unmaintained/Makefile diff --git a/arch.sh b/packages/unmaintained/arch.sh similarity index 100% rename from arch.sh rename to packages/unmaintained/arch.sh diff --git a/archpackage/PKGBUILD b/packages/unmaintained/archpackage/PKGBUILD similarity index 100% rename from archpackage/PKGBUILD rename to packages/unmaintained/archpackage/PKGBUILD diff --git a/debian.sh b/packages/unmaintained/debian.sh similarity index 100% rename from debian.sh rename to packages/unmaintained/debian.sh diff --git a/debian/changelog b/packages/unmaintained/debian/changelog similarity index 100% rename from debian/changelog rename to packages/unmaintained/debian/changelog diff --git a/debian/compat b/packages/unmaintained/debian/compat similarity index 100% rename from debian/compat rename to packages/unmaintained/debian/compat diff --git a/debian/control b/packages/unmaintained/debian/control similarity index 100% rename from debian/control rename to packages/unmaintained/debian/control diff --git a/debian/copyright b/packages/unmaintained/debian/copyright similarity index 100% rename from debian/copyright rename to packages/unmaintained/debian/copyright diff --git a/debian/docs b/packages/unmaintained/debian/docs similarity index 100% rename from debian/docs rename to packages/unmaintained/debian/docs diff --git a/debian/manpages b/packages/unmaintained/debian/manpages similarity index 100% rename from debian/manpages rename to packages/unmaintained/debian/manpages diff --git a/debian/pybm b/packages/unmaintained/debian/pybm similarity index 100% rename from debian/pybm rename to packages/unmaintained/debian/pybm diff --git a/debian/rules b/packages/unmaintained/debian/rules similarity index 100% rename from debian/rules rename to packages/unmaintained/debian/rules diff --git a/debian/source/format b/packages/unmaintained/debian/source/format similarity index 100% rename from debian/source/format rename to packages/unmaintained/debian/source/format diff --git a/debian/source/include-binaries b/packages/unmaintained/debian/source/include-binaries similarity index 100% rename from debian/source/include-binaries rename to packages/unmaintained/debian/source/include-binaries diff --git a/ebuild.sh b/packages/unmaintained/ebuild.sh similarity index 100% rename from ebuild.sh rename to packages/unmaintained/ebuild.sh diff --git a/generate.sh b/packages/unmaintained/generate.sh similarity index 100% rename from generate.sh rename to packages/unmaintained/generate.sh diff --git a/puppy.sh b/packages/unmaintained/puppy.sh similarity index 100% rename from puppy.sh rename to packages/unmaintained/puppy.sh diff --git a/puppypackage/icon14.xpm b/packages/unmaintained/puppypackage/icon14.xpm similarity index 100% rename from puppypackage/icon14.xpm rename to packages/unmaintained/puppypackage/icon14.xpm diff --git a/puppypackage/pybitmessage-0.3.5.pet.specs b/packages/unmaintained/puppypackage/pybitmessage-0.3.5.pet.specs similarity index 100% rename from puppypackage/pybitmessage-0.3.5.pet.specs rename to packages/unmaintained/puppypackage/pybitmessage-0.3.5.pet.specs diff --git a/rpm.sh b/packages/unmaintained/rpm.sh similarity index 100% rename from rpm.sh rename to packages/unmaintained/rpm.sh diff --git a/rpmpackage/pybitmessage.spec b/packages/unmaintained/rpmpackage/pybitmessage.spec similarity index 100% rename from rpmpackage/pybitmessage.spec rename to packages/unmaintained/rpmpackage/pybitmessage.spec diff --git a/slack.sh b/packages/unmaintained/slack.sh similarity index 100% rename from slack.sh rename to packages/unmaintained/slack.sh diff --git a/slackpackage/doinst.sh b/packages/unmaintained/slackpackage/doinst.sh similarity index 100% rename from slackpackage/doinst.sh rename to packages/unmaintained/slackpackage/doinst.sh diff --git a/slackpackage/slack-desc b/packages/unmaintained/slackpackage/slack-desc similarity index 100% rename from slackpackage/slack-desc rename to packages/unmaintained/slackpackage/slack-desc diff --git a/upstart/bitmessage.conf b/packages/upstart/bitmessage.conf similarity index 100% rename from upstart/bitmessage.conf rename to packages/upstart/bitmessage.conf -- 2.45.1 From 95095526639b7a127be9c7fcb9c2cb2d25ab5e1c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Dec 2016 16:48:04 +0100 Subject: [PATCH 0515/1102] New network backend (WIP, not integrated) - current snapshot of the new network backend code - not working yet, just base classes and no integration --- src/network/http.py | 49 +++++++++ src/network/httpd.py | 148 ++++++++++++++++++++++++++ src/network/https.py | 53 ++++++++++ src/network/proxy.py | 241 +++++++++++++++++++++++++++++++++++++++++++ src/network/tls.py | 89 ++++++++++++++++ 5 files changed, 580 insertions(+) create mode 100644 src/network/http.py create mode 100644 src/network/httpd.py create mode 100644 src/network/https.py create mode 100644 src/network/proxy.py create mode 100644 src/network/tls.py diff --git a/src/network/http.py b/src/network/http.py new file mode 100644 index 00000000..56d24915 --- /dev/null +++ b/src/network/http.py @@ -0,0 +1,49 @@ +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/httpd.py b/src/network/httpd.py new file mode 100644 index 00000000..b8b6ba21 --- /dev/null +++ b/src/network/httpd.py @@ -0,0 +1,148 @@ +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 new file mode 100644 index 00000000..9744a6dc --- /dev/null +++ b/src/network/https.py @@ -0,0 +1,53 @@ +import asyncore + +from http import HTTPClient +from tls import TLSHandshake + +# self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.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/proxy.py b/src/network/proxy.py new file mode 100644 index 00000000..aab28c50 --- /dev/null +++ b/src/network/proxy.py @@ -0,0 +1,241 @@ +# SOCKS5 only + +import asyncore +import socket +import struct + + +class Proxy(asyncore.dispatcher): + # these are global, and if you change config during runtime, all active/new + # instances should change too + _proxy = ["", 1080] + _auth = None + _buf_len = 131072 + _remote_dns = True + + @property + def proxy(self): + return self.__class__._proxy + + @proxy.setter + def proxy(self, address): + if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): + raise + self.__class__._proxy = address + + @property + def auth(self): + return self.__class__._auth + + @auth.setter + def auth(self, authTuple): + self.__class__._auth = authTuple + + def __init__(self, address=None): + if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): + raise + asyncore.dispatcher.__init__(self, self.sock) + self.destination = address + self.read_buf = "" + self.write_buf = "" + self.stage = "init" + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.sslSocket.setblocking(0) + self.connect(self.proxy) + + def process(self): + try: + getattr(self, "state_" + str(self.stage))() + except AttributeError: + # missing stage + raise + + def set_state(self, state): + self.state = state + self.read_buf = "" + + def writable(self): + return len(self.write_buf) > 0 + + def readable(self): + return len(self.read_buf) < Proxy._buf_len + + def handle_read(self): + self.read_buf += self.recv(Proxy._buf_len) + self.process() + + def handle_write(self): + written = self.send(self.write_buf) + self.write_buf = self.write_buf[written:] + self.process() + + +class SOCKS5(Proxy): + def __init__(self, address=None, sock=None): + Proxy.__init__(self, address) + self.state = 0 + + def handle_connect(self): + self.process() + + def state_init(self): + if self._auth: + self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) + else: + self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) + self.set_state("auth_1") + + def state_auth_1(self): + if len(self.read_buf) < 2: + return + ret = struct.unpack('BB', self.read_buf) + self.read_buf = self.read_buf[2:] + if ret[0] != 5: + # general error + raise + elif ret[1] == 0: + # no auth required + self.set_state("auth_done") + elif ret[1] == 2: + # username/password + self.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_1") + else: + if ret[1] == 0xff: + # auth error + raise + else: + # other error + raise + + def state_auth_needed(self): + if len(self.read_buf) < 2: + return + ret = struct.unpack('BB', self.read_buf) + if ret[0] != 1: + # general error + raise + if ret[1] != 0: + # auth error + raise + # all ok + self.set_state = ("auth_done") + + +class SOCKS5Connection(SOCKS5): + def __init__(self, address): + SOCKS5.__init__(self, address) + + def state_auth_done(self): + # Now we can request the actual connection + self.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: + ipaddr = socket.inet_aton(self.destination[0]) + self.write_buf += chr(0x01).encode() + ipaddr + except socket.error: + # Well it's not an IP number, so it's probably a DNS name. + if Proxy._remote_dns: + # Resolve remotely + ipaddr = None + self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0] + else: + # Resolve locally + ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) + self.write_buf += chr(0x01).encode() + ipaddr + self.write_buf += struct.pack(">H", self.destination[1]) + self.set_state = ("pre_connect") + + def state_pre_connect(self): + if len(self.read_buf) < 4: + return + # Get the response + if self.read_buf[0:1] != chr(0x05).encode(): + # general error + self.close() + raise + elif self.read_buf[1:2] != chr(0x00).encode(): + # Connection failed + self.close() + if ord(self.read_buf[1:2])<=8: + # socks 5 erro + raise + #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) + else: + raise + #raise Socks5Error((9, _socks5errors[9])) + # Get the bound address/port + elif self_read_buf[3:4] == chr(0x01).encode(): + self.set_state("proxy_addr_long") + elif resp[3:4] == chr(0x03).encode(): + self.set_state("proxy_addr_short") + else: + self.close() + raise GeneralProxyError((1,_generalerrors[1])) + boundport = struct.unpack(">H", self.__recvall(2))[0] + self.__proxysockname = (boundaddr, boundport) + if ipaddr != None: + self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) + else: + self.__proxypeername = (destaddr, destport) + + def state_proxy_addr_long(self): + if len(self.read_buf) < 4: + return + self.boundaddr = self.read_buf[0:4] + self.set_state("proxy_port") + + def state_proxy_addr_short(self): + if len(self.read_buf) < 1: + return + self.boundaddr = self.read_buf[0:1] + self.set_state("proxy_port") + + def state_proxy_port(self): + if len(self.read_buf) < 2: + return + self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] + self.__proxysockname = (self.boundaddr, self.boundport) + if ipaddr != None: + self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) + else: + self.__proxypeername = (destaddr, destport) + + +class SOCKS5Resolver(SOCKS5): + def __init__(self, destpair): + SOCKS5.__init__(self, destpair) + + def state_auth_done(self): + # 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 diff --git a/src/network/tls.py b/src/network/tls.py new file mode 100644 index 00000000..f690acc9 --- /dev/null +++ b/src/network/tls.py @@ -0,0 +1,89 @@ +""" +SSL/TLS negotiation. +""" + +import asyncore +import socket +import ssl + + +class TLSHandshake(asyncore.dispatcher): + """ + Negotiates a SSL/TLS connection before handing itself spawning a + dispatcher that can deal with the overlying protocol as soon as the + handshake has been completed. + + `handoff` is a function/method called when the handshake has completed. + `address` is a tuple consisting of hostname/address and port to connect to + if nothing is passed in `sock`, which can take an already-connected socket. + `certfile` can take a path to a certificate bundle, and `server_side` + indicates whether the socket is intended to be a server-side or client-side + socket. + """ + + def __init__(self, address=None, sock=None, + certfile=None, keyfile=None, server_side=False, ciphers=None, init_parent=True): + if not hasattr(self, '_map'): + asyncore.dispatcher.__init__(self, sock) + self.want_read = self.want_write = True + self.certfile = certfile + self.keyfile = keyfile + self.server_side = server_side + self.ciphers = ciphers + self.tlsDone = False + if sock is None: + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) +# logger.info('Connecting to %s%d', address[0], address[1]) + self.connect(address) + elif self.connected: + # Initiate the handshake for an already-connected socket. + self.handle_connect() + + def handle_connect(self): + # Once the connection has been established, it's safe to wrap the + # socket. + self.sslSocket = ssl.wrap_socket(self.socket, + server_side=self.server_side, + ssl_version=ssl.PROTOCOL_TLSv1, + 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 +# if hasattr(self.socket, "context"): +# self.socket.context.set_ecdh_curve("secp256k1") + + def writable(self): + return self.want_write + + def readable(self): + return self.want_read + + def handle_read(self): + if not self.tlsDone: + self._handshake() + + def handle_write(self): + if not self.tlsDone: + self._handshake() + + def _handshake(self): + """ + Perform the handshake. + """ + try: + self.sslSocket.do_handshake() + except ssl.SSLError, err: + self.want_read = self.want_write = False + if err.args[0] == ssl.SSL_ERROR_WANT_READ: + self.want_read = True + elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + self.want_write = True + else: + raise + else: + # The handshake has completed, so remove this channel and... + self.del_channel() + self.set_socket(self.sslSocket) + self.tlsDone = True -- 2.45.1 From 9f891917424cd8da0b3e6e0905a2eb9aab52f1ef Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 5 Dec 2016 12:09:41 +0100 Subject: [PATCH 0516/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 34464 -> 62891 bytes src/translations/bitmessage_ja.ts | 1262 +++++++++++++++++------------ 2 files changed, 751 insertions(+), 511 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 51de113eb5cfb1b77b9973fa42bd12b3fd294ea5..706f3b97d0e61bdea4cf4ee4febb5a10ec352ebf 100644 GIT binary patch literal 62891 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

8+ODO|t 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 delta 5457 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 diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 5ad07551..086fbf3f 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -1,5 +1,4 @@ - - + AddAddressDialog @@ -23,61 +22,62 @@ 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 を含む) を以下に入力してください: @@ -124,58 +124,96 @@ Please type the desired email address (including @mailchuck.com) below: # 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 新規 @@ -192,7 +230,7 @@ Please type the desired email address (including @mailchuck.com) below: Set avatar... - + アバターを設定... @@ -200,14 +238,14 @@ Please type the desired email address (including @mailchuck.com) below: アドレスをコピー - + Special address behavior... アドレスの特別な動作 - + Email gateway - + メールゲートウェイ @@ -215,401 +253,404 @@ Please type the desired email address (including @mailchuck.com) below: 削除 - + 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 - + メッセージを送信しました。 確認応答を待っています。 %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 - Broadcast: %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 購読 - + 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. %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に参加しました。 + 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(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. エラー: 送信元アドレスを指定してください。まだ作成していない場合には「アドレス一覧」のタブを開いてください。 - + 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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request - + メールゲートウェイの登録リクエストを送信しています @@ -622,659 +663,809 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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 - 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 - - - - - Waiting for PoW to finish... %1% - - - - - Shutting down Pybitmessage... %1% - + 新しいバージョンの 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. - + アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. - + エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. - + メッセージの送信に必要な処理を行っています。 +このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. - + メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 - + メッセージを送信しました。 確認応答を待っています。 %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 - + 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました UPnP port mapping established on port %1 - + ポート%1でUPnPポートマッピングが確立しました 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 + PoW(証明)を待っています + + + + %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 は間違っている可能性があります。 設定を確認してください。 + + + + 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 には何かしら誤りがあります。 + + + + 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... + 同期の完了を待っています... + + + + 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 + 不明なエンコード @@ -1318,7 +1509,7 @@ The 'Random Number' option is selected by default but deterministic ad Address version number: 4 - + アドレスのバージョン番号: 4 @@ -1396,7 +1587,7 @@ The 'Random Number' option is selected by default but deterministic ad Enter an address above. - + 上にアドレスを入力してください。 @@ -1427,79 +1618,80 @@ 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 ? - 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 - + ホワイトリスト @@ -1507,7 +1699,7 @@ The 'Random Number' option is selected by default but deterministic ad Bitmessage - + Bitmessage @@ -1535,7 +1727,7 @@ 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> @@ -1576,122 +1768,112 @@ The 'Random Number' option is selected by default but deterministic ad 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 件の公開鍵を処理しました。 @@ -1699,42 +1881,90 @@ 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: - chanのbitmessageアドレス: + + + + + 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 passhphrase/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 + チャンネルの作成 / 参加をキャンセルしました @@ -1762,7 +1992,7 @@ The 'Random Number' option is selected by default but deterministic ad Address version number: - + アドレスのバージョン番号: @@ -1772,7 +2002,7 @@ The 'Random Number' option is selected by default but deterministic ad 1 - + 1 @@ -1793,295 +2023,305 @@ 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 - + 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で済むように通知します。 - + 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>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 + 接続通知を非表示 + + + + Hardware GPU acceleration (OpenCL): + ハードウェア GPU アクセラレーション (OpenCL): - + \ No newline at end of file -- 2.45.1 From e647d70bbcb450ab616f428374feb0de00866e77 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Dec 2016 10:47:39 +0100 Subject: [PATCH 0517/1102] New config parser class - workaround for % in labels - can be extended in the future --- src/bitmessagecli.py | 15 ++++++++------- src/configparser.py | 7 +++++++ src/shared.py | 4 ++-- 3 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 src/configparser.py diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index ff5f091a..c7d8b5cd 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -5,7 +5,6 @@ # This is an example of a daemon client for PyBitmessage 0.4.2, by .dok (Version 0.3.0) -import ConfigParser import xmlrpclib import datetime import hashlib @@ -17,6 +16,8 @@ import time import sys import os +from configparser import BMConfigParser + api = '' keysName = 'keys.dat' keysPath = 'keys.dat' @@ -46,7 +47,7 @@ def restartBmNotify(): #Prompts the user to restart Bitmessage. def safeConfigGetBoolean(section,field): global keysPath - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() config.read(keysPath) try: @@ -73,7 +74,7 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe def configInit(): global keysName - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() config.add_section('bitmessagesettings') config.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. @@ -88,7 +89,7 @@ def configInit(): def apiInit(apiEnabled): global keysPath global usrPrompt - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() config.read(keysPath) @@ -173,7 +174,7 @@ def apiData(): global keysPath global usrPrompt - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory try: @@ -183,7 +184,7 @@ def apiData(): #Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. appDataFolder = lookupAppdataFolder() keysPath = appDataFolder + keysPath - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() config.read(keysPath) try: @@ -252,7 +253,7 @@ def apiTest(): #Tests the API connection to bitmessage. Returns true if it is co def bmSettings(): #Allows the viewing and modification of keys.dat settings. global keysPath global usrPrompt - config = ConfigParser.SafeConfigParser() + config = BMConfigParser() keysPath = 'keys.dat' config.read(keysPath)#Read the keys.dat diff --git a/src/configparser.py b/src/configparser.py new file mode 100644 index 00000000..2deb3d0f --- /dev/null +++ b/src/configparser.py @@ -0,0 +1,7 @@ +from ConfigParser import SafeConfigParser + +class BMConfigParser(SafeConfigParser): + def set(self, section, option, value=None): + if value is not None: + value = value.replace('%', '%%') + return SafeConfigParser.set(self, section, option, value) diff --git a/src/shared.py b/src/shared.py index 19663472..d6d05374 100644 --- a/src/shared.py +++ b/src/shared.py @@ -11,7 +11,6 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. import base64 import collections -import ConfigParser import os import pickle import Queue @@ -32,6 +31,7 @@ from binascii import hexlify # Project imports. from addresses import * from class_objectProcessorQueue import ObjectProcessorQueue +from configparser import BMConfigParser import highlevelcrypto import shared #import helper_startup @@ -39,7 +39,7 @@ from helper_sql import * from helper_threading import * -config = ConfigParser.SafeConfigParser() +config = BMConfigParser() myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself. -- 2.45.1 From df18f7b042e7a5a6dc0d61310a176397382f5ac0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Dec 2016 11:01:17 +0100 Subject: [PATCH 0518/1102] Switch configparser to raw mode --- src/configparser.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/configparser.py b/src/configparser.py index 2deb3d0f..64b30b25 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -1,7 +1,15 @@ -from ConfigParser import SafeConfigParser +from ConfigParser import SafeConfigParser, ConfigParser class BMConfigParser(SafeConfigParser): def set(self, section, option, value=None): - if value is not None: - value = value.replace('%', '%%') - return SafeConfigParser.set(self, section, option, value) + if self._optcre is self.OPTCRE or value: + if not isinstance(value, basestring): + raise TypeError("option values must be strings") + return ConfigParser.set(self, section, option, value) + + def get(self, section, option, raw=False, vars=None): + return ConfigParser.get(self, section, option, True, vars) + + def items(self, section, raw=False, vars=None): + return ConfigParser.items(self, section, True, vars) + -- 2.45.1 From 0dde976dec4c466db0167109b5923505c29da6a6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Dec 2016 13:04:52 +0100 Subject: [PATCH 0519/1102] Fix timeformat in configparser - allow both raw (new) and non-raw (old) style timeformat for backwards compatibility --- src/configparser.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/configparser.py b/src/configparser.py index 64b30b25..900bef50 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -1,15 +1,20 @@ -from ConfigParser import SafeConfigParser, ConfigParser +import ConfigParser -class BMConfigParser(SafeConfigParser): +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") - return ConfigParser.set(self, section, option, value) + return ConfigParser.ConfigParser.set(self, section, option, value) def get(self, section, option, raw=False, vars=None): - return ConfigParser.get(self, section, option, True, vars) + if section == "bitmessagesettings" and option == "timeformat": + try: + return ConfigParser.ConfigParser.get(self, section, option, raw, vars) + except ConfigParser.InterpolationError: + return ConfigParser.ConfigParser.get(self, section, option, True, vars) + return ConfigParser.ConfigParser.get(self, section, option, True, vars) def items(self, section, raw=False, vars=None): - return ConfigParser.items(self, section, True, vars) + return ConfigParser.ConfigParser.items(self, section, True, vars) -- 2.45.1 From 114563ed2feaad3ac2f14193254f1a620b59b8e5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Dec 2016 16:15:37 +0100 Subject: [PATCH 0520/1102] Default logger output UTF-8 - fixes errors when using locales other than EN --- src/debug.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debug.py b/src/debug.py index 606308a0..cdf8d8cb 100644 --- a/src/debug.py +++ b/src/debug.py @@ -73,6 +73,7 @@ def configureLogging(): 'filename': shared.appdata + 'debug.log', 'maxBytes': 2097152, # 2 MiB 'backupCount': 1, + 'encoding': 'UTF-8', } }, 'loggers': { -- 2.45.1 From d8b8e0e9dd40f25142c01189378f447e5c42570e Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sat, 10 Dec 2016 20:12:30 +0100 Subject: [PATCH 0521/1102] Auto-updated language fr from transifex --- src/translations/bitmessage_fr.qm | Bin 90147 -> 93480 bytes src/translations/bitmessage_fr.ts | 906 ++++++++++++++++++------------ 2 files changed, 543 insertions(+), 363 deletions(-) diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 6be9aba6ca9d62ccbd8afd268cdc1c75789c3cf7..2513d3e6773809fb1d7831aeebc91a10efdc6abf 100644 GIT binary patch delta 10017 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 R<8lkD@3ifCbXXuH{{c%|(PjVu diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index 14c6d757..e9028bd2 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -1,5 +1,4 @@ - - + AddAddressDialog @@ -59,12 +58,12 @@ 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) : @@ -174,54 +173,54 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : 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 - Nouveau + Nouvelle @@ -244,12 +243,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Copier l’adresse dans le presse-papier - + Special address behavior... Comportement spécial de l’adresse… - + Email gateway Passerelle de courriel @@ -259,137 +258,137 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. - Demande de clé de chiffrement en attente. + - + 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. - Travail nécessaire pour envoyer le message. Travail en attente. + - + 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. @@ -397,139 +396,139 @@ It is important that you back up this file. 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 - Nécessite le nom du canal + - + You didn't enter a chan name. - Vous n’avez pas saisi de nom de canal + - + Address already present - Adresse déjà présente + - + Could not add chan because it appears to already be one of your identities. - Il n’a pas été possible d’ajouter le canal parce qu’il semble déjà être une de vos identités. + - + Success - Succès + - + 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'. - Canal créé avec succès. Pour laisser d’autres utilisateurs rejoindre votre canal, donnez leur le nom du canal et cette adresse Bitmessage : %1. Cette adresse apparaît aussi dans "Vos identités". + - + Address too new - Adresse trop récente + - + Although that Bitmessage address might be valid, its version number is too new for us to handle. Perhaps you need to upgrade Bitmessage. - Bien que l’adresse Bitmessage pourrait être valable, son numéro de version est trop récent pour pouvoir être traité. Peut-être que vous devez mettre à niveau Bitmessage. + - + Address invalid - Adresse invalide + - + That Bitmessage address is not valid. - Cette adresse Bitmessage n’est pas valide. - - - - Address does not match chan name - L’adresse ne correspond pas au nom du canal - - - - Although the Bitmessage address you entered was valid, it doesn't match the chan name. - Bien que l’adresse Bitmessage que vous avez saisie soit valable, elle ne correspond pas au nom du canal + - Successfully joined chan. - Canal rejoint avec succès. + 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 @@ -538,122 +537,122 @@ It is important that you back up this file. Would you like to open the file now? 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 - Erreur : Les adresses Bitmessage commencent avec BM- Merci de vérifier %1 + - + 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 %1 contains invalid characters. Please check it. - Erreur : L’adresse %1 contient des caractères invalides. 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - Erreur : quelques données codées dans l’adresse %1 sont mal formées. Il pourrait y avoir un soucis avec le logiciel de votre connaissance. + - + Error: Something is wrong with the address %1. - Erreur : Problème avec l’adresse %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 De - + Sending email gateway registration request Envoi de la demande d’inscription de la passerelle de courriel @@ -668,142 +667,142 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r 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? @@ -812,7 +811,7 @@ Are you sure you want to delete the subscription? Ê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? @@ -821,277 +820,277 @@ Are you sure you want to delete the channel? Ê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 - + Address book Carnet d’adresses - + Address Adresse - + Add Contact Ajouter un contact - + Fetch Namecoin ID Récupère l’ID Namecoin - + Subject: Sujet : - + From: De : - + To: Vers : - + Send ordinary Message Envoyer un message ordinaire - + Send Message to your Subscribers Envoyer un message à vos abonnés - + TTL: TTL : - + Subscriptions - Abonnement + Abonnements - + Add new Subscription Ajouter un nouvel abonnement - + 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 @@ -1101,7 +1100,7 @@ Are you sure you want to delete the channel? Tous les comptes - + Zoom level %1% Niveau de zoom %1% @@ -1116,197 +1115,191 @@ Are you sure you want to delete the channel? 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 heure%n heures - + %n day(s) - - %n jour - %n jours - + %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 - + 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… - + Generating %1 new addresses. Production de %1 nouvelles adresses. - + %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. - + Done generating address La production d’une adresse a été effectuée SOCKS5 Authentication problem: %1 - Problème d’authentification SOCKS5 : %1 + - + Disk full Disque plein - + 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. - + 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. - + Doing work necessary to send broadcast... Travail en cours afin d’envoyer le message de diffusion… - + Broadcast sent on %1 Message de diffusion envoyé %1 - + Encryption key was requested earlier. La clé de chiffrement a été demandée plus tôt. - + Sending a request for the recipient's encryption key. Envoi d’une demande de la clé de chiffrement du destinataire. - + Looking up the receiver's public key Recherche de la clé publique du récepteur - + 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 - + 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. - + 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 - + 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 - + 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 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. - + Message sent. Waiting for acknowledgement. Sent on %1 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. - + 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. - + 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 @@ -1321,14 +1314,162 @@ Difficulté requise du destinataire : %1 et %2 Transfert de port UPnP retiré - + Mark all messages as read - + Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? - + Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? + + + + Doing work necessary to send broadcast. + Travail en cours afin d’envoyer la diffusion. + + + + 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 + + + + Wait until these tasks finish? + Attendre jusqu'à ce que ces tâches se terminent ? + + + + 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. + + + + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. + Problème d’authentification SOCKS5 : %1. Veuillez vérifier vos réglages SOCKS5. + + + + 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. + + + + 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 + + + + 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. + + + + 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. + + + + 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 celui de votre connaissance est intelligent. + + + + 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. + + + + 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. + + + + 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: Something is wrong with the recipient address %1. + Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. + + + + 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 ? + + + + Not connected + Non connecté + + + + 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 ? + + + + Waiting for network connection... + En attente de connexion réseau... + + + + Waiting for finishing synchronisation... + En attente d'achèvement de la synchronisation... + + + + MessageView + + + 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 @@ -1481,46 +1622,42 @@ The 'Random Number' option is selected by default but deterministic ad Nom de la pseudo liste de diffusion : - - Ui_aboutDialog - - - aboutDialog - <html><head/><body><p>Copyright © 2012-2016 Jonathan Warren<br/>Copyright © 2013-2016 The Bitmessage Developers</p></body></html> - - - aboutDialog - + About À propos - + 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>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 © 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> + + + + + <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> @@ -1670,7 +1807,7 @@ The 'Random Number' option is selected by default but deterministic ad Stream # - Flux # + Flux N° @@ -1713,49 +1850,34 @@ The 'Random Number' option is selected by default but deterministic ad Téléchargement : 0 kO/s - + Network Status Statut du réseau byte(s) - - octet - octets - + octetoctets Object(s) to be synced: %n - - Objet à synchroniser : %n - Objets à synchroniser : %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. - + 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 - + Traité %n message de diffusion.Traité %n messages de diffusion. Processed %n public key(s). - - Traité %n clé publique. - Traité %n clés publiques. - + Traité %n clé publique.Traité %n clés publiques. @@ -1763,42 +1885,90 @@ The 'Random Number' option is selected by default but deterministic ad Dialog - Dialogue + Create a new chan - Créer un nouveau canal + Join a chan - Rejoindre un canal + Create a chan - Créer un canal + <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>Saisissez un nom pour votre canal. Si vous choisissez un nom de canal suffisamment complexe (comme l’est une phrase secrète forte et unique) et qu’aucun de vos amis ne le partage publiquement, alors le canal sera sécurisé et privé. Si vous-même et quelqu’un d’autre que vous créaient chacun un canal avec le même nom de canal, alors ce serait très probablement le même canal, actuellement.</p></body></html> + Chan name: - Nom du 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 normal person-to-person message to the chan address.</p><p>Chans are experimental and completely unmoderatable.</p></body></html> - <html><head/><body><p>Un canal existe lorsqu’un groupe de personnes partage les mêmes clés de déchiffrement. Les clés et l’adresse Bitmessage utilisées par un canal sont produites à partir d’un mot ou d’une phrase favorable à l’humain (le nom de canal). Pour envoyer un message à tout le monde dans le canal, envoyez un message de personne-à-personne normal vers cette adresse de canal.</p><p>Les canaux sont expérimentaux et complètement non modérées.</p></body></html> + Chan bitmessage address: - Adresse de canal Bitmessage : + + + + + 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 @@ -1857,295 +2027,305 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings Paramètres - + Start Bitmessage on user login 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 - + 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. - + 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 - + Listen for connections on 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 : - + 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 - + 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. - + 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é. - + Demanded difficulty Difficulté exigé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. - + Maximum acceptable total difficulty: Difficulté maximale acceptée : - + Maximum acceptable small message difficulty: Difficulté maximale acceptée pour les messages courts : - + Max acceptable difficulty Difficulté maximale acceptée Hardware GPU acceleration (OpenCL) - Accélération GPU matérielle (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 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 - + <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 + + + + Hardware GPU acceleration (OpenCL): + Accélération matérielle GPU (OpenCL) : + - + \ No newline at end of file -- 2.45.1 From dd777d6e437d7d29c7a4baf38c38be2f17861066 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 12 Dec 2016 00:44:09 +0100 Subject: [PATCH 0522/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 92273 -> 92708 bytes src/translations/bitmessage_de.ts | 354 ++++++++++++++++-------------- 2 files changed, 184 insertions(+), 170 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 2b8b429adf83ff39811ee5e8721329cf52345ace..0fe8b01313f30c98efaee20df2a3175508f329c1 100644 GIT binary patch delta 2329 zcmZuxYgAO%75>hhnS1APXKr|CA}q(z=m;vqBVq&<-n)aSsxK@!_y;ehTDVg>{P-$mK9Krvz-mEqqXXl4`5#!;bHeT$uwF+ld+3^nG$3 zW;TWa@7E#4845Pt8?*UJs`fGF2nQjrVu7yk(fBZFFID(CwiO$}6klOawmVRjh5BP2 zlp_Y8ZkP^q$Kk*PBhYgNm!$Q;kHxs@O}T~)#+}H|0nvgNXNgNgKc?CJ9Ef;_x$iQ7 zNo8!1ml9aIkq!1g4i=(dKH|H;z4PonAx66Pf3%S^pgvC}aYf>k%?&22sH3Gj6 z;PNUQKu8nkT9HozMsbx_-AKh*@-T(j^(=;KPCH0MySS@)LrJPL+&@>Gq2_Jlt{c+9 z+^=!>luqDDj6z(m0!!+z&|f+Nj2f+w*0j?46@|x809Pc(wDa|3xqQaH^8)i}8o0SuqqQD~lpp3Nb2kxFwPHv`tXRT4%4_U~0 zW@WC9Xmx$9T;Njz@G;6I-I2gIsqz|S7#9iotkS}19df5K%qy^6Rld>=7QafhEyNeN zlBKG9<^&twBU@EwSL907qu8l{1SzqyKg*(BxW2;a4HkY(DBm>^hz=5dJ7oaalyYHX@Ganja-q6E zX{Ng)r}E~Y9|hr)^&}}3+>5?#eb_O$4_{suni6&bd%J|c1{3dTv*bqJ91$O{9{YU< zu(?W|7?uPUSD>DCsumbwQ!k0O0434t%8yb=g461n5hU5=Pt@{h1Ms&8>XS3W!Nfp$ zpb+NOk*0pJY9VzYMdNud5llZufjiC#*b@yKZ7nW-e zhW$vw_-l{OcnvgN(;nB63wK}Ao^A;R^N5oVsEyn>Np4mfwWjepeHl%~LGf~@+7kLo ztFy&d(g=9ii_AP&H?3zsC6Ca}TSooxxTITGQchTTg0eF z1yHd|oVg+w@VP2xbk3m*H(RuCAyuyiiMa&{lggNcn|?L=yAQnpw-Hy-%*@3LNNc0FD#o?tXE>dd{!5+HuDB^+316BO=qk4{6liT9HCd=qxp5gPw&0pTj16c{m^-5 z0KaOz`FC{wqUU-)xdHegOdn8rf|T#C4|#D4@)4~s7jj0vsWoc#tMogswE(SZxm#;= z?|yB-Y3kUJO$PNlHX3covY*b(`974BbYU*8%+TULfLxD0^jY4A-<|Bkm&*)owpGAG zWiK+H3d56WLuruhm;8r$0h-fNkfR7}(p@R|oDnR{QyS-83uZbmC45G_m#vqk)`tP- z&PgeMJO!pwOKEkhf$*`CqbdaNVQ8YXa1@ng_>)u?LkIM8NmbWra;}*s)f?N0aGcc8 z{2FZJBk5o)nYB}pqeY955KT8bRX$oGimjT9h(b2(aLT8$y=B)#_0%FbFqc+xkxp+8 zEP@I1kdKVsxWeB5KFEU;nJA!`c@*gj3q^&~s;PIclcMaj*MtK3@V)`Ee8SVUm{tmV z;{xb+3_XGL-Gm}KC6m6SQ-(KtEb2Ec<>^V7o@F=X*`3bxOuH#7-Dyg9n2H>^j{GGK zlie{dKO@_bY0>`5UYM0$;504GFETl^@{1N^n2HKA3)3^~rikoC|JiO4XzD>@b!JA{ tX``KypD`Yh|HbPK@66tMe#!s;@cp^Ux03#+B;l8tQs8rR?Kcl9{tepOq1FHZ delta 1981 zcmX9N0f(1>g#;8I8#Iy?d=R5XRG1No z#vlsVsFC2C(v?lfDjSI!lv>s;k`$~gzA(|~DrgjmluFQm?hX7pKf3DPbI&>7>B>vm z?u*)zp@wt-6Tv(ZO5J_AdDhYd3x^Y>%dJ82C!qc2Q?R6N=#KMX^JYOvwG-CCU_TAy zPKN1lGZ3T05c?CL!-*j$c7mCIFKwFad>D`5*SmoC--f;NV_;1MqIdrbur3|Mo<_vp zPX?xjBVpHLAnOVec8kDL4l}dXgG~*_tekI&TlpY9ibHB)7Fg6Q%+93mQQu?E*P+0a za?D*71U4%N^L2%UF?d&~hPsJObcU7Ula#~6@C-i7v4C-7a46FZ6fZ&LH!fhoNASh= zcYxoI;>!>V@Y04Br3mP~j2mvW%fo>?k!Jwe7d;o~ma1XQaPTP*F@l*7n81uT*(g^H zuxfLilyo*$ehawUz-;LcAmLRJo8%}5i<_^8a29j7l`Vn^aOScleGkCo-Rg4A z!X@oew{wANGw0=MxXK0J$_Li2>XLX z%=^09Yx(c@Yz98^;G2aEz;Dzb_PMF<8f%txT(Vh{@s%$Ht3b0C!*k55~N8%imuC zoZO?!zH9>~{8hK6gi;hcRJZjb2aqo4D&pF~(tc8#v=-+tLv^)(9Mtnn*SLTToBo0B zQk9uP*QdLYN=)r@bX__cSM^XZmpFm^c43Ox4EEYEA!y+kVEZB=p{*I%StO*E3 zz;SJZ*y$L=-ibo(jQzmjUg4kqbmGiYYMss+5pzr*(A@>>D%K~5rciR4^l9hH0PjTo zTDvc>-mWh^G8ee%t}pc_6I%6pwcZ5$a9{uJoN%JBL-i6uT|4XaJ)2en_iGJ9JCea9 z)!=rFf*2E|<_W&$H#!Zg66rN(mKpM&zXUT~QR@V&w|TE&U%_|4#SaY!r@kU5_Zdzc znh7k+F*Mm+!7QT!V zf@~`iYi7R$YOjf>B?{cZ7O}oL2s7A_qhiCx8sN|^@!}TpCHtOudwx66d{=z5#{m|& zOkxSur15#lu#WN&`9Ko+7NBsbB;H+3_w1F7`BaJS$JBnkuk*!Uq{O&Fpgn2;nWsZa zdUYIZ`T^;^4WzBvSK79|fZk`PRC4}0t<_59t&w0}tx|;n1x?r>mRg4}%1L23T4d@(DLT z@c471U*TCw(Qsp6&pD`P#Bpy1co>)V(5~;!8nd0Vsd9sj>m!TFk#b{hZYWXzSv5)) zbKg7@>Pab&UrqWEq}*#YYKUaz#zv_bQm7L*P0bTVQr<9#V{-?wbL1fYcFok5xCywo zZ~&RL-SlgcC-u5cnc(FL80r<aZRBtx7GySez^7jhz(Rh diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 9859028f..c926d733 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -324,7 +324,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Bestätigung der Nachricht erhalten %1 - + Broadcast queued. Rundruf in Warteschlange. @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,7 +1119,7 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. @@ -1129,37 +1129,37 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neue Version von PyBitmessage steht zur Verfügung: %1. Sie können sie von https://github.com/Bitmessage/PyBitmessage/releases/latest herunterladen. - + 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% @@ -1174,7 +1174,7 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% @@ -1224,60 +1224,60 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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% @@ -1287,7 +1287,7 @@ Receiver's required difficulty: %1 and %2 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% @@ -1297,12 +1297,12 @@ Receiver's required difficulty: %1 and %2 Arbeit wird verrichtet, um den Schlüssel nachzufragen... - + 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. - + 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 @@ -1322,7 +1322,7 @@ Receiver's required difficulty: %1 and %2 Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? @@ -1332,107 +1332,107 @@ Receiver's required difficulty: %1 and %2 Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? - + Problem communicating with proxy: %1. Please check your network settings. Kommunikationsfehler mit dem Proxy: %s. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. - + 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. - + 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. - + 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... @@ -1460,6 +1460,20 @@ Receiver's required difficulty: %1 and %2 Klicken Sie hier um HTML-Anzeige zu deaktivieren + + MsgDecode + + + The message has an unknown encoding. +Perhaps you should upgrade Bitmessage. + Diese Bitmessage ist unbekannt codiert (msgpack). Am besten pyBitmessage höher als ver. 0.6.1 upgraden. + + + + Unknown encoding + Codierung unbekannt (msgpack). + + NewAddressDialog @@ -2016,218 +2030,218 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 - + 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 - + 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 - + 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. - + 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. - + 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 @@ -2237,82 +2251,82 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - + <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 - + <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 Verfalldatum herunterlädt, zum Beisplel 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> - + Give up after Gib auf nach - + and und - + days Tagen - + months. Monaten. - + Resends Expire Verfall der erneuten Sendungen - + Hide connection notifications Verbindungsbenachrichtigungen nicht anzeigen - + Hardware GPU acceleration (OpenCL): Hardwaregrafikkartenbeschleunigung (OpenCL): -- 2.45.1 From 025950c05eb8f9b4ea4e54e644f060c251ec73d5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 13 Dec 2016 11:54:01 +0100 Subject: [PATCH 0523/1102] Fix locale init - date/time wasn't localised correctly on startup --- src/bitmessageqt/__init__.py | 18 +++++++++--------- src/l10n.py | 6 ++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a274212b..a4e101c0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -48,7 +48,7 @@ from about import * from help import * from iconglossary import * from connect import * -import locale as pythonlocale +import locale import sys from time import strftime, localtime, gmtime import time @@ -83,7 +83,7 @@ def _translate(context, text, disambiguation = None, encoding = None, number = N else: return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, number) -def change_translation(locale): +def change_translation(newlocale): global qmytranslator, qsystranslator try: if not qmytranslator.isEmpty(): @@ -97,29 +97,29 @@ def change_translation(locale): pass qmytranslator = QtCore.QTranslator() - translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + locale) + translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + newlocale) qmytranslator.load(translationpath) QtGui.QApplication.installTranslator(qmytranslator) qsystranslator = QtCore.QTranslator() if shared.frozen: - translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + locale) + translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + newlocale) else: - translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + locale) + translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + newlocale) qsystranslator.load(translationpath) QtGui.QApplication.installTranslator(qsystranslator) - lang = pythonlocale.normalize(l10n.getTranslationLanguage()) + 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: - pythonlocale.setlocale(pythonlocale.LC_ALL, lang) + l10n.setlocale(locale.LC_ALL, lang) if 'win32' not in sys.platform and 'win64' not in sys.platform: - l10n.encoding = pythonlocale.nl_langinfo(pythonlocale.CODESET) + l10n.encoding = locale.nl_langinfo(locale.CODESET) else: - l10n.encoding = pythonlocale.getlocale()[1] + l10n.encoding = locale.getlocale()[1] logger.info("Successfully set locale to %s", lang) break except: diff --git a/src/l10n.py b/src/l10n.py index a32abb84..0300085a 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -1,5 +1,6 @@ import logging +import os import time import shared @@ -78,6 +79,11 @@ 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. -- 2.45.1 From 49832231ca226c3a5a0d4885f3637e7ac64c9b6e Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 13 Dec 2016 17:39:49 +0100 Subject: [PATCH 0524/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 92708 -> 92732 bytes src/translations/bitmessage_de.ts | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 0fe8b01313f30c98efaee20df2a3175508f329c1..74979801c1bd626e8e8e955f97ae0fe496d80255 100644 GIT binary patch delta 1903 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 diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index c926d733..7d891e80 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -1466,12 +1466,13 @@ Receiver's required difficulty: %1 and %2 The message has an unknown encoding. Perhaps you should upgrade Bitmessage. - Diese Bitmessage ist unbekannt codiert (msgpack). Am besten pyBitmessage höher als ver. 0.6.1 upgraden. + Diese Bitmessage verwendtet eine unbekannte codierung. +Womöglich sollten Sie Bitmessage upgraden. Unknown encoding - Codierung unbekannt (msgpack). + Codierung unbekannt @@ -1933,7 +1934,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi <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>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 Nachricht an die Chan-Adresse.</p><p>Chans sind experimentell und völlig 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 wird geteilt.</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> -- 2.45.1 From 9d9052dda25600f5b8d6685c6e975cb003adc868 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 13 Dec 2016 17:52:23 +0100 Subject: [PATCH 0525/1102] Auto-updated language zh_cn from transifex --- src/translations/bitmessage_zh_cn.qm | Bin 53667 -> 54427 bytes src/translations/bitmessage_zh_cn.ts | 897 ++++++++++++++++----------- 2 files changed, 542 insertions(+), 355 deletions(-) diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index 3b2f6e72878350b2f4de22ba92933e2830d750fa..14625aef1df9c67a46a6983006d20f671c2b9baa 100644 GIT binary patch delta 7615 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 Pd7wx)8I4T(o2~x~T|E>- diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 6543551b..323bf123 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -1,5 +1,4 @@ - - + AddAddressDialog @@ -59,12 +58,12 @@ 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)如下: @@ -167,52 +166,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 新建 @@ -237,12 +236,12 @@ Please type the desired email address (including @mailchuck.com) below: 将地址复制到剪贴板 - + Special address behavior... 特别的地址行为... - + Email gateway 电子邮件网关 @@ -252,276 +251,276 @@ Please type the desired email address (including @mailchuck.com) below: 删除 - + 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 消息已经发送. 正在等待回执. 发送于 %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 订阅 - + 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. 您可以通过编辑储存在 %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. - 成功的加入到频道。 + 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 @@ -530,122 +529,122 @@ It is important that you back up this file. Would you like to open the file now? 收件人必须在此期间得到它. 如果您的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. - 错误: 一些地址数据%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. 错误: 您必须指出一个表单地址, 如果您没有,请到“您的身份”标签页。 - + 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接收了地址。 - + New Message 新消息 - + From 来自 - + Sending email gateway registration request 发送电​​子邮件网关注册请求 @@ -660,142 +659,142 @@ It is important that you back up this file. Would you like to open the file now? 您输入的地址是无效的,将被忽略。 - + 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? 比特信无法找到你的地址 %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? @@ -804,7 +803,7 @@ 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? @@ -813,277 +812,277 @@ 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. 没有可以显示的近期广播。 - + You are using TCP port %1. (This can be changed in the settings). 您正在使用TCP端口 %1 。(可以在设置中修改)。 - + 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 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 加入或创建一个频道 @@ -1093,7 +1092,7 @@ Are you sure you want to delete the channel? 所有帐户 - + Zoom level %1% 缩放级别%1% @@ -1108,195 +1107,191 @@ Are you sure you want to delete the channel? 添加新条目 - + 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 小时 - + %n day(s) - - %n 天 - + %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 - SOCKS5 认证问题: %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 件发件人的地址 ( 您的地址). - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. 做必要的工作, 以发送信息. 这样第2版的地址没有难度. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. 做必要的工作, 以发送信息. - + Message sent. Waiting for acknowledgement. Sent on %1 信息发送. 等待确认. 已发送%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 发送公钥的请求. 等待回复. 请求在%1 @@ -1311,14 +1306,162 @@ Receiver's required difficulty: %1 and %2 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。请检查你的设置。 + + + + 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有问题。 + + + + 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... + 等待同步完成…… + + + + 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 + 未知编码 @@ -1471,46 +1614,42 @@ 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> <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>版权©2012-2016 Jonathan Warren<br/>版权©2013-2016的比特信开发人员</p></body></html> + + <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> @@ -1655,7 +1794,7 @@ The 'Random Number' option is selected by default but deterministic ad Objects to be synced: - 对象已同步: + 对象 已同步: @@ -1703,44 +1842,34 @@ The 'Random Number' option is selected by default but deterministic ad 下载: 0 kB /秒 - + Network Status 网络状态 byte(s) - - 字节 - + 字节 Object(s) to be synced: %n - - 要同步的对象: %n - + 要同步的对象: %n Processed %n person-to-person message(s). - - 处理%n人对人的信息. - + 处理%n人对人的信息. Processed %n broadcast message(s). - - 处理%n广播信息. - + 处理%n广播信息. Processed %n public key(s). - - 处理%n公钥. - + 处理%n公钥. @@ -1748,42 +1877,90 @@ 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> - <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 passhphrase/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 + 频道创建或加入已取消 @@ -1842,295 +2019,305 @@ 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 愿意在发送到手机时使用不加密的目标地址 - + Use 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 - + 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) - 硬件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> <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 + 隐藏连接通知 + + + + Hardware GPU acceleration (OpenCL): + 硬件GPU加速(OpenCL): + - + \ No newline at end of file -- 2.45.1 From fefb9593383a8a65b49a0ee033ea043b80c546da Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 15 Dec 2016 16:11:29 +0100 Subject: [PATCH 0526/1102] Notify if C PoW missing - Linux users often don't know that the C PoW is available and complain it's slow. This will try to build it, and adds availability notification in the status bar - also, the updateStatusBar signal now allows emphasised notifications, which will remain visible for a longer period of time and also reappear if a status change happened in the meantime --- src/bitmessageqt/__init__.py | 17 ++++- src/bitmessageqt/statusbar.py | 38 ++++++++++++ src/proofofwork.py | 106 ++++++++++++++++++++++---------- src/translations/bitmessage.pro | 1 + 4 files changed, 125 insertions(+), 37 deletions(-) create mode 100644 src/bitmessageqt/statusbar.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a4e101c0..37c52917 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -76,6 +76,7 @@ from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize from proofofwork import getPowType +from statusbar import BMStatusBar def _translate(context, text, disambiguation = None, encoding = None, number = None): if number is None: @@ -703,6 +704,7 @@ class MyForm(settingsmixin.SMainWindow): # Put the colored icon on the status bar # self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) + self.setStatusBar(BMStatusBar()) self.statusbar = self.statusBar() self.pushButtonStatusIcon = QtGui.QPushButton(self) @@ -3927,10 +3929,19 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFromBroadcast() def updateStatusBar(self, data): - if data != "": - logger.info('Status bar: ' + 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) - self.statusBar().showMessage(data, 10000) + if option == 1: + self.statusBar().addImportant(message) + else: + self.statusBar().showMessage(message, 10000) def initSettings(self): QtCore.QCoreApplication.setOrganizationName("PyBitmessage") diff --git a/src/bitmessageqt/statusbar.py b/src/bitmessageqt/statusbar.py new file mode 100644 index 00000000..65a5acfb --- /dev/null +++ b/src/bitmessageqt/statusbar.py @@ -0,0 +1,38 @@ +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/proofofwork.py b/src/proofofwork.py index 701f34ba..4bb02fd7 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -3,6 +3,7 @@ #from multiprocessing import Pool, cpu_count import hashlib from struct import unpack, pack +from subprocess import call import sys import time from debug import logger @@ -12,6 +13,8 @@ import tr import os import ctypes +bitmsglib = 'bitmsghash.so' + def _set_idle(): if 'linux' in sys.platform: import os @@ -109,7 +112,7 @@ def _doGPUPoW(target, initialHash): #print "{} - value {} < {}".format(nonce, trialValue, target) if trialValue > target: deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) - shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'))) + shared.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.") @@ -150,6 +153,37 @@ def getPowType(): return "C" return "python" +def notifyBuild(tried=False): + global bmpow + + if bmpow: + shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1))) + elif tried: + shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1))) + else: + shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1))) + +def buildCPoW(): + global bmpow + + if bmpow is not None: + return + if shared.frozen is not None: + notifyBuild(False) + return + if sys.platform in ["win32", "win64"]: + notifyBuild(False) + return + try: + call(["make", "-C", os.path.join(shared.codePath(), "bitmsghash")]) + if os.path.exists(os.path.join(shared.codePath(), "bitmsghash", "bitmsghash.so")): + init() + notifyBuild(True) + else: + notifyBuild(True) + except: + notifyBuild(True) + def run(target, initialHash): if shared.shutdown != 0: raise @@ -194,45 +228,49 @@ def run(target, initialHash): pass #fallback # init -bitmsglib = 'bitmsghash.so' -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(shared.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) +def init(): + global bitmsglib, bso, bmpow + if "win32" == sys.platform: + if ctypes.sizeof(ctypes.c_voidp) == 4: + bitmsglib = 'bitmsghash32.dll' + else: + bitmsglib = 'bitmsghash64.dll' try: - # MinGW - bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) + # MSVS + bso = ctypes.WinDLL(os.path.join(shared.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 (cdecl) %s", bitmsglib) + 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(shared.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(shared.codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL %s", bitmsglib) + except: bso = None -else: - try: - bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL %s", bitmsglib) - except: - bso = None -if bso: - try: - bmpow = bso.BitmessagePOW - bmpow.restype = ctypes.c_ulonglong - except: + if bso: + try: + bmpow = bso.BitmessagePOW + bmpow.restype = ctypes.c_ulonglong + except: + bmpow = None + else: bmpow = None -else: - bmpow = None +init() +if bmpow is None: + buildCPoW() diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index c8081610..22044d46 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -16,6 +16,7 @@ SOURCES = ../addresses.py\ ../helper_msgcoding.py\ ../helper_sent.py\ ../helper_startup.py\ + ../proofofwork.py\ ../shared.py\ ../upnp.py\ ../bitmessageqt/__init__.py\ -- 2.45.1 From 3b896e69e7f8c8fa1ce2dd891240eaa2a0f9d37d Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 15 Dec 2016 16:26:50 +0100 Subject: [PATCH 0527/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 92732 -> 93645 bytes src/translations/bitmessage_de.ts | 321 ++++++++++++++++-------------- 2 files changed, 172 insertions(+), 149 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 74979801c1bd626e8e8e955f97ae0fe496d80255..0187f1f5965e705f029df9bc7c9fa46e929c5053 100644 GIT binary patch delta 2746 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 QYIxMPx# diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 7d891e80..f7f5a890 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -174,52 +174,52 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 @@ -244,12 +244,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + Email gateway E-Mail Schnittstelle @@ -259,37 +259,37 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 - + 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -398,17 +398,17 @@ It is important that you back up this file. Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. - + 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 anlegen. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1169,17 +1169,17 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Stunde%n Stunden - + %n day(s) %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1282,7 +1282,7 @@ Receiver's required difficulty: %1 and %2 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. @@ -1292,7 +1292,7 @@ Receiver's required difficulty: %1 and %2 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... @@ -1317,37 +1317,37 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1367,72 +1367,77 @@ Receiver's required difficulty: %1 and %2 Die Uhrzeit ihres Computers, %1, ist möglicherweise falsch. Bitte überprüfen Sie Ihre einstellungen. - + + 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. + + + 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. - + 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... @@ -1975,6 +1980,24 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. + + regenerateAddressesDialog -- 2.45.1 From 77d7dcbd2d161ff76f22acfe4e06481a11b99490 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 15 Dec 2016 16:33:21 +0100 Subject: [PATCH 0528/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 85151 -> 86349 bytes src/translations/bitmessage_sk.ts | 488 ++++++++++++++++-------------- 2 files changed, 263 insertions(+), 225 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 90aa448c5d0490b59527794fc319e89ebcd878eb..5613d6e62da13b807b564a1fee77182959a7073a 100644 GIT binary patch delta 3262 zcmah~dstL;8h+2rFqd=A%mk>FB%VM=KpZZK2q+qtG!?{5RLaZ19A#i;4$d$rn2w5R zk|uVDiqN!pp2}6qh_%$vFt^r(a=n6UtB*HimD*I=N_4-0XS3RR_K$hK`F`j3`+e{C zzVG?Y>#zE?yx~{bPge;b28@2hra@*!YU`$qV8yk)n;fRZQBm;wa2=SWaH!u=f=TU$ zCOaKWnh0I`M}W%#!yBzYiWmOrH-O^}@Za?!aA(@4mQmi*N04-X7cl2jq}Qzm?Ek=o z>Q8}?U48L_9glZR2jXucJ*;DEE=F}a{~ z9*N1n-3feuU3Msf6^UQU8x#o|-f;yuI7L3BFeTnRsz^Gw5^!cJCaj<+X%+e7Z-I&F zudt73BvNK79M3s{xK4$4nFNeTQB<7t2gAN84^^7HUpo{n^Xq}t8H$sRAtcpzic`xD zf{FS<(QdE+w@)Z8tK2|)qmp0m2WHGtrT*yqKv<&E`0O#@OrkRI{R_ZzPztp~@{TLY z(9v&_wEL7JQr`vM%2Gxj+ePK;lyN-Wt68QTB`pW@aH(=^rT`@~HcW0&ng>R0P#%8y zS->$z*{TtN$YFi4BVO*WGEMqvzREa{G>a@y4cI=Lcwem=yE_fcaHvu<-vR!%N;R>C z_@39P65lnG^M|DV05}4Df4KE$&GLTGaBhss!Vn?a5%cdetY_!s(7_@*$O3 zapS6dOO-tEp*X+t6(X3}b$+iTgae;C{AzBv!30#v8Ga`3@K5|YCrkw*uKIN=>&UEY z{k~80C$pYX`xnr*xD)F6t}Vdzk!r^RqP--a(ZsW@z)x+OM9VN><#kO)8|7*IiNJ(@LB9wg)0H7~?{4NT!Rl>OeFAlxl7uyc^ z#f$qjyC+k>)emZ#TEio0wGa}fxAl{J+g2dyv*Z<(^<0W)j-B+t`n|n-~tcnLW^&2=s)p2Uj!zRX?#`ts!X^R)^sZo(oKj;G)&bfsbc!$+KwvNq=r! z;Df;B-CX9R3Ys}}y^*=EgPV5u9l~GEcP)TicXcFpO`y3LvV@P$ zCQO^O{P;-X=ETE%TB8zJcA1~GtPmJ-lDFQPN3Xk;7pu1bhvN9cohj66FkkfeW-ud~ z`QkH4fbbGuI-8-_=@kF`p-KdzdjMZGj_eSQC zaDIO^^|m6BZ@ogCjNizARgg(z>okAV*aZ}?;oEKvqB;zJX6Z5dCj5oJxt3nHwefoG zWtyH%t@ zn`(Xdp5FNZ>9c2>Uh>YQ$=s|jOWg=0FV#QuOfs4Iynf5+R-k!~+`|SZb}TmF08y&{ z!k~SCAl`n;(9b>;*f`k`nnL-$IzvQ%+Fm%%5SjTJ$v)UHv71I>zXkFP&g4B%ZrJ+N zXc{C{hHU~Nem=!;q&5M#)?sLkBK3j3IAl#?94WR+u zWVjP-0K?}PqlOLywC9YmP7j#yCC0eVgXxR-y)h}MioPR3#>szPj_Fu*#yGW(+S>h@ zG3UJ|;F}=h{F>Fkm?)!jBLNZ2#zm3T$G@${m5&7jcjp*4w$qoP?6|QmxQ+U1Hg0dZ z17<*sv3`O9I2R(P^JdK>`82H3UU@Mlt)Ypx?C~B(HY|(<76@1f7sUmzA&(~Gd0Hu? z+=b%arzI$*T!ND_d+&-9BHSpV9p_O(>!oy}1U6`WGBkY};ydF+;AQOJ{AE-|mzUK%OHSZ!`guHEKbC`>I9 zovBmILY7^$xJAJw7D=vRp;!`%^F_fbmWXz#NOZa7McqYi6+W-N%ONY?S-frI)j!nL%>vPImO0L`HYJohNvV6<2&qDrG*fU$R*zj2ay>SCvEcUPgXJP`r;+q1RVFxAm3wkTku8dr$q^SigkVXRUlXbq`|1uONDymJ*B2Zt>>Y z#h=~b!)+C8#lMgC8RYzi0iW)|AModMa~bhiihN?s?t}7spuNAi@*ZlR?R>O*$Z+;v m`tS7-{}|yGtv(O;;r(S_|I>=#usA)IKU6@m+uWa76#pM@yrPi+ delta 2150 zcmX9*lP#OX6_r5}H;kxpzL8&b-g57)ud2T9*6i2s+ojLx zVT=Rd2WB{$>u%MAPRxxqYuW;HlP$r1Wze781UBptxC2_S(3Rk0A_*VB7wu*HAS(Yypl?|>Hb26chm(Qf z&k?=-H(+iiqVom9Bbbno3f4CipR7Df+_rUN{S(AwC4dbo!n6hSeXxYs?`^LBq55boj;1zEOXrhx{I${+J!$h+D_=Vf^bgjW*4NSd3a!iWyTDh_ zdK8j|haYG?1HT5|1ZjODjso9K)cV$y0Rbi20Ezb1b!msCq=EhUwKl}=0WAwWsNT?8 z-3FPo)jQS$$+NVzd^|ANyBqJHP~CNwvA^HenP!tE-tD@c2d4vfnJ%Pa6qqGL7hyjD z{QOQgx`yPO-KL8_YNcQu&?Smg)}1N3r2eUZzEZd1Z3IxAsczK;@fX_%(AqlnhR&*a z@`b9`+uS~?&}XK{gIPuW&Y%In#WsDxv!!54Pj!~w;_!~pw?$0=20qevYD*}C8}%mcNu@ETHaVaDm`(QR- zuH;`o1FIsr?^G(N_bu+oAUiPGi7Vgc0$g`+75~@a&IjD(Sqc&nI)b}?(3$MBakpcr z!hxk+2S*3(N#dPz9Kebz{BWTbcooA3&+!JyxAm(i^*wJ3oh}bl;)k#m)!$AcL|ov>p*L#5VPqpwRn;+uYfpu&Jg0; z$CL7lg!%Jm8^2~Dp*aA!_VPV4d5n-YvklDLEEGI=1N`GBq14tzt#n-|pGGXdYYTIZXiqknlId$d7l>g36FPBkMv$7vglG^d!uMvMOm;_ ziGubT;BXOzd&|IhS(Mk(6y;o0*=Tm0brNl{=YT0rVyKHNaBrw+ADcz|`n*RbC5V&W z9U%UC@$=QB^=mJ2b805F_^)El`9|W^DHha4fXSQ1LgP>%fBDQqwa z^~+wh#%K<%JT4_32`8P3q(x))fDITWEo&M9cx;zeO=r|P_0s059Lj-sRLNHL27v6 z4%Rfr~st`G-^BmM_VSvLNCMR~%StpOlDUNA0TPx+%h-`9bwY+AHjq>`Le6!jL92qI! z%brWprpv$A(_ZY6{Azv}-4f3gTp$UJ(Td?u#P!uJrALw%kUdWE45#Naamv6CYk|bs z%3%9$YMUC3zxq*tRG##w@1I(%1R2roKxA&>bB`a@jqv;gpruzDgD({fyoGw={ SujIEb diff --git a/src/translations/bitmessage_sk.ts b/src/translations/bitmessage_sk.ts index b709052c..04ac4fcb 100644 --- a/src/translations/bitmessage_sk.ts +++ b/src/translations/bitmessage_sk.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrácia zlyhala: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: @@ -171,52 +171,52 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: 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á @@ -241,12 +241,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Kopírovať adresu do clipboardu - + Special address behavior... Zvláštne správanie adresy... - + Email gateway E-mailová brána @@ -256,37 +256,37 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -296,17 +296,17 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -316,47 +316,47 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -366,12 +366,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Odoslať - + Subscribe Prihlásiť sa k odberu - + Channel Kanál @@ -381,12 +381,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -395,17 +395,17 @@ It is important that you back up this file. 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.) @@ -414,37 +414,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -514,22 +514,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +537,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,67 +592,67 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 Od - + Sending email gateway registration request Odosielam požiadavku o registráciu na e-mailovej bráne @@ -667,142 +667,142 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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 Odosielam žiadosť o odhlásenie z e-mailovej brány - + Sending email gateway status request Odosielam požiadavku o stave e-mailovej brány - + 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. Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1115,47 +1115,47 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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% @@ -1165,17 +1165,17 @@ Ste si istý, že chcete kanál odstrániť? %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é @@ -1220,86 +1220,86 @@ Ste si istý, že chcete kanál odstrániť? 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 @@ -1314,122 +1314,127 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. - + + 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. + + + 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. - + 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... @@ -1457,6 +1462,21 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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 @@ -1957,6 +1977,24 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. + + regenerateAddressesDialog @@ -2013,218 +2051,218 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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ť @@ -2234,82 +2272,82 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - + <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 - + Hardware GPU acceleration (OpenCL): Hardvérové GPU urýchľovanie (OpenCL): -- 2.45.1 From a87bfb8a82bf0b58163dc00ffc99fd7cd0c96e90 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 15 Dec 2016 19:53:55 +0100 Subject: [PATCH 0529/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 82985 -> 83862 bytes src/translations/bitmessage_eo.ts | 323 ++++++++++++++++-------------- 2 files changed, 173 insertions(+), 150 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 98ae14d60cfd19ccc9f3b2daee9efc583899c532..549329085d2870aa762888b4e3814b072b0e86f0 100644 GIT binary patch delta 2825 zcmaJ?dstLu9)7>M&p9(^Hi%S|=^!|Q;wTg?j%D@KQdY*_tNa)7&;IAqn#Ocv(@i9-<6npLSFCH&D;EPuu=6=RMzi=X~FL`F+1r zwL)E9sxEt6Uj`r+Om%5(m{pMξ0TxN~%Eo+UBn6x4@Sg2h%rQ>6q;91CrF3gJ=c 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 QrI*f@jX$=g9n%8;4<~V!rT_o{ diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index ab043ac7..ffdaa0d2 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi kun alia. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -166,52 +166,52 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 Malforviŝi - + View HTML code as formatted text Montri HTML-n kiel aranĝita teksto - + Save message as... Konservi mesaĝon kiel... - + Mark Unread Marki kiel nelegita - + New Nova @@ -236,12 +236,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso... - + Email gateway Retpoŝta kluzo @@ -251,37 +251,37 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 - + 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 forviŝi ĝin? - + Waiting for their encryption key. Will request it again soon. Atendante ilian ĉifroŝlosilon. Baldaŭ petos ĝin denove. @@ -291,17 +291,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Message sent. Sent at %1 Mesaĝo sendita. Sendita je %1 @@ -311,47 +311,47 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -361,12 +361,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Sendi - + Subscribe Aboni - + Channel Kanalo @@ -376,12 +376,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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. @@ -390,17 +390,17 @@ It is important that you back up this file. 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.) @@ -409,37 +409,37 @@ It is important that you back up this file. Would you like to open the file now? 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? Ĉ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 ne estas la prava formularo por vi. - + Bad address version number Malkorekta 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. @@ -509,22 +509,22 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - + 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 @@ -532,17 +532,17 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 pro %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. @@ -587,67 +587,67 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - + 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. Priaboranta adreson %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. Priaboranta adreson %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 ero(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 De - + Sending email gateway registration request Sendanta peton pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 jaman 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 jaman 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 vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn 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 Sendanta peton pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendanta peton pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi la kanalon? - + Do you really want to remove this avatar? Ĉu vi certe volas forviŝi tiun avataron? - + You have already set an avatar for this address. Do you really want to overwrite it? Vi jam agordis avataron por tiu 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... Testante... - + This is a chan address. You cannot use it as a pseudo-mailing list. Tio estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. 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. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. - + There are no recent broadcasts from this address to display. Neniaj lastatempaj elsendoj de tiu adreso por montri. - + 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). @@ -1110,47 +1110,47 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% Atendanta ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% Fermanta PyBitmessage... %1% - + Waiting for objects to be sent... %1% Atendanta ĝis objektoj estos senditaj... %1% - + Saving settings... %1% Konservanta agordojn... %1% - + Shutting down core... %1% Fermanta kernon... %1% - + Stopping notifications... %1% Haltiganta sciigojn... %1% - + Shutdown imminent... %1% Fermanta tuj... %1% @@ -1160,17 +1160,17 @@ Are you sure you want to delete the channel? %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermanta PyBitmessage... %1% - + Sent Senditaj @@ -1274,7 +1274,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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. Faranta laborpruvon endan por sendi mesaĝon. @@ -1284,7 +1284,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Doing work necessary to request encryption key. Faranta laborpruvon endan por peti pri ĉifroŝlosilo. @@ -1309,37 +1309,37 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pordo-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Faranta laborpruvon endan por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? @@ -1354,77 +1354,82 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. - + The time on your computer, %1, may be wrong. Please verify your settings. La horloĝo de via komputilo, %1, eble malkorektas. Bonvolu kontroli viajn agordojn. - + + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. + Via(j) vidprocesoro(j) ne kalkulis korekte, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. + + + 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. - + 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 liveradojn. Ĉu atendi ĝis la samtempigado finos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradojn. Ĉu atendi ĝis la samtempigado finos? - + 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 liveradojn. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finos? - + Waiting for network connection... Atendanta retkonekton... - + Waiting for finishing synchronisation... Atendanta ĝis samtempigado finos... @@ -1967,6 +1972,24 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Kreado / aniĝado de 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. + + regenerateAddressesDialog -- 2.45.1 From e92161650b40c93d98fab41abf47188b5a6157a5 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 15 Dec 2016 19:57:09 +0100 Subject: [PATCH 0530/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 86508 -> 87399 bytes src/translations/bitmessage_pl.ts | 325 ++++++++++++++++-------------- 2 files changed, 174 insertions(+), 151 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 19ccbbdf42fc02e0b75befdcf0ce5202fcf0ec43..f719f103ca0c5fba45da8977c3493f141274b6ca 100644 GIT binary patch delta 2909 zcmZ`)X;@Qd7Jk3%x%Vcwf?9aN}-kDRw-`K ztG2ajU6^O8qjZ$EE>+yefLMoe{NKmpLIm`n2QxNZ#DkG4HuwIPbTz3 zpS%NbPlj<_Es&%{tK^%&xiM(9<$W;LP+k+`Kc9{P&o=>+9Z0U23pi$A*z$uw$D2XC zIu0*g8w2z&LCUflfb}L)mUBQx2aL)o1dG^*SKr!2+=_yD5lAo10qgrZ#%9xg-(wi} zMLf`V3?_Kuh-EbN5zC|m*`dj2d3RB3Xbu0t)o-c(>yMGK~ps`3CA6O_V2HCSS@(r|Js(9NP0 z=bfVUW6IF2KL91$mC{O*u`*fNssDN~MY^&F$%RiNl)X-E0b)$bXo2$bJ(Mx7BCsy= zl!H*6>^T|g{X!L+P^QPj$wEZ%?UxgFe!))o3-0srqY&g*6xp94K^r3-mNhY ziSg_D|GNn&Rq4jWr;&}SbmOa+0_L5%{A3Gxw@g>MegY|6rz?-3jvQ*%$$O2!?!&rW z;|3Fjg>n~deAtB#bhl^E0P1?^TVJJXd$(L4{x@=EOo%*FYYE{!dQU3d?x~ygv+h0w z9;}sjYt0dCfqvDTqrkpz^=k$`0ve+ATh@*OZ0q$kQDI=hm-?Cq#FalT8+2yBqJraR zQ17sn3r!)jiEX)1JISW_jqAuR1Dy?=dCqCNr`@^q_coFFHC*Nj;@as1XKx%yZ5YZ; z%cOL1)3}^V(KM05T9CC_#1&1t4%W4pThVZz=%~5M_H_V@D-z(vpBp3S-%0op5=Y z>HyX|TR8vrDH`23gy#9A=KP-xx~pH1+FK3b4r=@H)`rfu13>pr4d#z1|MWwK9`Z)u zQmCO<=~vXwnTFWg)sS~`-J{IM4AXDZSvxZg&d;5|F1x|y9}BoP848n@P^Y#T-gzgU zN;qR!{jXZ!phq_FrnsNNjo3@dwc23RwIhm;4j5ZIx&TXV89NQ3=jsw;L>mgvIcJPa z{g`f#%Q*Zt&9!za+0L8&`wNU~CiVvkW*gT^#CXB4#;;e#0>4xnYkN||fgpBn4&nu6 z5F4Dvy42aE|8FhG+8#Cj@=9l#vS*DCO-8Wi;>4a^!T^0cG0N!!>#<3UK4PLjuAAb3 z@TKIlQ{u~C7Ljph>=s8=P+2=>h!g%%4g5zGr>>X_4E#cLE+HaPmN+Al>iBK6IBO^+ zP}~uh)YEt`JS|q3>PXTkabwLxu=bC{%3(&}`(`;!uxR@g(vTWnSyd`z@A6;6YsiNS zIj}=Q9^CZXM!!9TZWPek8-!M5A)D3<;cSU>(o-Pbg$y_z?-Z~hE%AA@8pva%yur9g zip&S?Gj&T2D{^UN6h+zn6q1CIu+YNjmcu=iF1IC7A*BeU2_$sGOW*mhGA%_0(ic)p z9_?llk?FMNrQMsfZlkzB`d}$R^11NAq6>6PL!XJ`T|T!oY;;;TPxnz$W_G6Jba^G4 z)nW5FtX{ihbGhAio7YhgNt+&Ph9leghBPYA?o1kKkw!c0R*zkB+w)v*ujF+}-f4Cz z)BdL2;mWhSJ@UyH+sL0E&8xB<9jIZuFA>!Dp6jX@h7?ZzCJ}tl1976O1Z8~pTjO?__7^d$>X!x>>f{+&*3PrXsH%H z&+T$$xw7(I?&(ZP3lpAwhTO{gyuaZ8$o%B&$MU{GJf6xG@jD(qr}a&1wu4l$KM^Cq zEmO+&KATY?QiE=hkG?1R|9DpJ6GeQ#)8yHP_~Y9FrV`w&{bO$iT=|rFzoEp`o*C#; ckYbV){Z!Kbp)ciHoj&Wcl-(8^#;W@L7o49-`v3p{ delta 2171 zcmX9s0hd+hytS(DMkZojJQ`^@DpT_ATeTO6f`0# zOP(4-Tm!8_g+z%3cM~OATTlXuK-?NZgGfwOTq4?E<*)O-@6O!&JIg)yZkeI8*ig{N zvk=xG!10VI`o&Vz9dsBhn z97Jt<2+V(ksO=)KU;rj1WPlA?jQ2l2L9=D{Vrvm%audM(I82YHb-xtMIAQ~aPsOaX zQDC79F^A7348T000$LXHvwQvx8>W3l6Ml^yAG-p-rej~cBd~5ZN~)c}tT%9Q%Ll+O z!6*--_4|3KH*W^okKnosou%By&*8@aX)L;Hh|8`-X4?B02uos)dsN`}KI|Q5J+O>p ze;jrcY+w@`EV~1ZE17?62PAafW5Y9xz=k(yVLDgGo1tt0=zr-^Y{|F*<$wFpy=$cla1@pb2YfDmCjbwW?H-aL<7@lMtEE1L=2)$7Bm#(@oO(}zcw z0u4Xt$Jdgg^S0~bzV@Mv-O(?Vh*n#wK5=jcU}({==m`hv`fFSCBZcoehk$tnYghC> zx+kfc!C-U#L$x7$O&nOj9K(*0Lx7qUhN4GlV2;0Oa}8Fz*SCg_$Vq_benU4`LUTG9 zo{n<>+`V~+1o~OfXMF63yMeCVeA41%pyYc#<%&P?$l}urC}shLe9lLiz|2H`=Y%$} z@HoEYr%S-fLHq%Y2)W68`Os+KgM7X+&k49Tkgxi`4sG82g}Ex0VsskcSmsFf?c=Y< z5JTS~d>2m#?e-EJ3+%v(bHWI*4(PcgjG8|P$Vw5Sn(2E(q!3fE8fac1#QDXOVgrTj zJ)?m!0m7&6y$u!^F60H?0HQpFf_}w7ccYfXTm9QV68^rKe8u=)w2tn@mhN6`j})pV z65s9R!uNr@!A4%vYIy6|0E;pBw=N)8Z=7nI2IfD*IP=t2zAa~=J6-N)LrpIGDZBnv+Iqpq zQB+K6(bNI4<)*dIUjZ*ev>L(c2@lh*?0*7hR-5*Qz9#K1nGWqE&lVP&YWf1NS9R0=2IUQgY53%U(OW<^|SYdlXj*Sp2r_+?B&&8t> zWprzfc&2U?CgQbCJiDe6*tS8u{3%(o_=R|TP8)FQiTL1ix+9hz#brpca{^MMoC#qMJis^6qBp{0tYjI=2un=nf%INd^XRZB$;;gtC0(oWNGAp3pk!kT#CP^Wa^KQzXd zv!$jlqQUwKQuE3#io98B8NUq}lq=oZ=LC0jTcl1$ie5*i)agdG=RQpKjrj{ucu^kX zMM7N-*J@3!qkeFamzIyE<@55gcXxsL)XK|SL+A=L$SY?u;IF&nO*I9Sg)({TXtFKL zTi&{00`Oyx<{?_`*Y?ZDSsIY%@&;MJE&23zqO&GhuDhE_!9FivPKXAst8%@$3s}BL zZhkU=j#1^-RSnc&+vLX^NX-oo6eAThPES@`63O=33dOSUEHLDNV*P^lUs|JhYh}QV za>Y0IIHk%(8QFab+C_1Q-91HF+D&I2Tco7ervoVmm5lIwa;QrA#j+{s@+5{D|!nrKgUQ+d8*3_Tb}RGc9x)o9h&pJskFSM8JN0pveX-N(}R zNvrDFm-b0$QoW+Tq-&I-j_=N;*6dTNt(L6z@7_}P&JLy)$x`>Z5r<9B)PL_BNi8%( zts6!W0D95#xEEV?^kb*yvjVx!x=F3H~S~2gLzId2VQWc zM|6id#APd(oMfK(58|DA(mbieMiD-mYM%AYDd1tLIkspW5PHO%oKFL|EjFim5rO9& z=CyyO4OpQ$zlENGj7D>bYcq-KZ!W8S1=g>`ToI`PxAU}g*+&@u4mDK7)XFkB{)86v luVs~O7ejegt?kL^tBt6)Xt6)`tz2F|c|z6E0jy%g{{XBDoPGcR diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index f8c1bafc..799e76c6 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -170,52 +170,52 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: 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 @@ -240,12 +240,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Kopiuj adres do schowka - + Special address behavior... Specjalne zachowanie adresu... - + Email gateway Przekaźnik e-mail @@ -255,37 +255,37 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -295,17 +295,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,47 +315,47 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -365,12 +365,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Wyślij - + Subscribe Subskrybuj - + Channel Kanał @@ -380,12 +380,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -394,17 +394,17 @@ It is important that you back up this file. 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.) @@ -413,37 +413,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,47 +1117,47 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów 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% @@ -1167,17 +1167,17 @@ Czy na pewno chcesz usunąć ten kanał? %n godzina%n godziny%n godzin - + %n day(s) %n dzień%n dni%n dni - + Shutting down PyBitmessage... %1% Zamykanie PyBitmessage... %1% - + Sent Wysłane @@ -1281,7 +1281,7 @@ Odbiorca wymaga trudności: %1 i %2 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. @@ -1291,7 +1291,7 @@ Odbiorca wymaga trudności: %1 i %2 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. @@ -1316,37 +1316,37 @@ Odbiorca wymaga trudności: %1 i %2 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ó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 - + Wait until these tasks finish? Czy poczekać aż te zadania zostaną zakończone? @@ -1361,77 +1361,82 @@ Odbiorca wymaga trudności: %1 i %2 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. - + + 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. + + + 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. - + 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? - + 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... @@ -1465,7 +1470,7 @@ Odbiorca wymaga trudności: %1 i %2 The message has an unknown encoding. Perhaps you should upgrade Bitmessage. - Wiadomość zawiera nierozpozne kodowanie. + Wiadomość zawiera nierozpoznane kodowanie. Prawdopodobnie powinieneś zaktualizować Bitmessage. @@ -1974,6 +1979,24 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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. + + regenerateAddressesDialog -- 2.45.1 From 9a26ce5be17954bd4207c91de3fc31b0703a48d2 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 16 Dec 2016 10:18:29 +0100 Subject: [PATCH 0531/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 62891 -> 63540 bytes src/translations/bitmessage_ja.ts | 321 ++++++++++++++++-------------- 2 files changed, 172 insertions(+), 149 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 706f3b97d0e61bdea4cf4ee4febb5a10ec352ebf..f01e2060090fb13b7ee7a3949eac3a3a313cc585 100644 GIT binary patch delta 2579 zcmZ`)c~BI07XId7j_#fr1q>_1v5h*SBDRzmLBR+fgi}E-kI2dkLNXM*z)Mbf13)q%V_c zH@yS~Kattj=z#+nvcAqrAk0D5Z}?%LZMw{r>kq6yF7t?c3>Lel%SPr`0C)A0kKAa# zsX>+idM_eEHuv>oVEUGw_*z;iA1CXQTI43@eMjYE?iK+>c%X z9WqI$Fv?GtOT!eVf?8JI64wBH;v)YcZ2&M;kY8JL7Pxg&enTG*91`VS%1mJ6ECp9$ zM}nMJ=q~RA-fvbIzG$QS#}p3xI)S*m3ciX2Tv)E?KY9z9^H0Sv|2@Eh5{1yV7Z?zw z@Z>1&Nv&d(H6Qr?k-{gGhXP#_q^k;d=Udf^Z`XYR1n*U}szsph9vjxpm-;A8fd?lk z4YSFQ8*`QK)yI;s=afE&CIIbmO8?M05-MC7&_aUxhbzTB?$jv5m8mS1wM|r-UCCdi zMLGYCKd@$vv{LD1I8skk&*UjjKOIalYNZyXyL_LM^hW9H+`7(g$zmeV@vGf>FFIX$ z*{|VWvb#bHUhghtJ3CJfb4FS^{NNaj!|WoQocJQRbS>% znZ8g}1wI5GyGku~#)8UKszdLp+tyFjJWCG@-J-fuPknTIzv^}r(Y_U~dZwaq^OS1) z(gI*wtNKHx6*yR__KqI}%p9f;X{YPid(=^-i-4*uwKyUfxc*SRq-Gr8Hc-7RxHq*) zl6sYA2jJO5UHTrm(deiyeHaQUMb*z^dyIN#NhghhpADVg*syw)4YvBxwQh-~c*}HB_>QJ*2syHH zfJQo{2bTBJ9E%xG6k?=-YG3E-3!3iF=K+r3I+&EZp1_73HvHx)lRuNj?Mf6=@#r;BRKqm*{+sLzW*Vc3ZSHr> zVfG~=ko=lC)#^>tvx7OixDiOX$Xr@R{sdfN?#-ljDC)!feH{_Ia-EfhG?3O=tTvbW zV(1u_QCtRMU$D%BEUN1mt1FyHb-k3{Xp9A4MzFpyCjjps*>MhJ^NvC`G?1oZgUN>9 z1hP|qCGBsvu!*0M=1tD*io7L6<33w@@&?f`u@!AJ1s8g=Roao%P91FX;$)z}m2JLH zG%P={*EWO#&E0H!?lY=i$=(Pkr(qw<-mP^&f9xw}pW0I&)=y!d@+q{Z)^kGCC%{}i z_mLY3RpBEY*BZT7jptH#`%!t0T>8h=#3zu;x;X}L`i{$umC+Jj#H~0_%fGRSTQiRA z>*BaI34y@615z($P{GgKQ5j8K(ls02$>mP2rD~?1;aVS&Xl~`)r4(XWGm5)xAeP}< zx%O9mXg8eaZhqEAD=LS3xtzp|^U`U$4v^S!Iu|p!zGk#;K;l`zsMnb`Q2d}*x?xg1 zuxY$bC_YNfrO9kY4n7P>|j& zw34Q0s6L>Z9BketiL9xh_=0}ZjL|@pQD4gw z+n(#&Lq8||m)r0{r~V&P2arGS>)#sn^!=FFlPT5a6H+ASuD-K_`szusw9zCq9^o98h0VldOhKd&oSG;^3t?tI zp-?CiN`w?)f-sx@%MgZih_JvP!9wu7e&L6OR5~pd^6B~6f*gGLik!T~c0y{*h-rb+ zrC_HSGh(gT8T{lak*=A8`K06|-eS$-6XVT^+2;5xkx#T{WQd7b=3F;A%#2SkCtE({ z!_q~If3Q10#Vp2WihPEcZq3Nzv#fm9T#-)_b40T>UChXo?)C50*z(oS-UHo<5Kq*t zhz2j*7n+2J!fWA)U=iBr_o9%R&?CG?>UqXNnv`u8`Go9ba~7YOotP+Q zX3ohrn{(aOWFVWKVYSY&&Y5q`NR=t*#@IiJ9~?e7+g12f2q6Jx2$CST<$G6n!I1yS zlx>O6iBC3Df#UCVz001&CujX}&VWD3`Fl;VBgANu{Ws|og2Jy76I;E}!W`*JutUIy hlPIT{^iDckvj67ve?0iKcuRKtABoU-vgPTZ{{ZR}Hn{)* delta 2076 zcmX9VHbRVr3cgNjxv6020uE-H$&JXNZ6l?w5RqEKMR z2O_AfXaz(U5uw{IqKJ!CvLGq~z7XHFZ24MoZMF99m%q+8`DK3hoO92;bLwZd>_;|d zfNmv#_kgqGa))>_kCSsljLfm9+(eV%P7pLT8Nj_Xa3w78xDeW~>4bf`<%4t*`d9o7 zsBXw@8prJWP0^@^E*OE29)|)ZcZBTv8JO;jklj4tbj*%R0j@HbyXJc;_oW>R=OS!- z9MDmP@K`$UbjJKDGvG1>pRV$!!kviVwiA{qsj6|->#o>3@9%(TDDu`Af%3&Digg4Q zR-?Ga31~fuV_Ba7M-xy!iOx&i(4x--j#T58GnF~}Il2S?2{;s^ub~H6nXb|u{1tfj zN0s9N88}s-8fs7jvz=7Ky}kvSdsVKY3$W*r$|v$E1e9%7jZMo3ZXH%8F-FG&H&jbO z?}dh{VqQH3D!Y|L#>m{8sAMq#s(wlnV=`1cU?$w%0EFZ)Gu9JYyqTEE&q->YBC$rM z?u_EWnyd$XnWo6&z#?bndg4f6jyKbmT2ID&!F0$=fYaH`L-i`4a4RcjYJlztR%$s3 zywk|)x3tpl4_T*^-9Y4Bc31%!xNaBgGX4-y^A76~cmi0H$$Ga|03*X#Uy<&ueV-k- zB8?QLv6C#rz@ocTxyE`LI>xd;?AZd$s$gx}Xkh3GJ02}khNw+5t5&M@i>V)NZ`5y< zE+Auj)RU^G0oPxs11%+F)H-!g6B!yfR~>!AlY(+V9WRiq!`bQtSL&~Nx%#iK0|BL0 z$x{1i&pvyX?i#OLQ+qNMQxuKHY`E;H*|eSt-`uUq^P|(u-!=Kakno0q%0i9F+O|#e zbjEDJ*sAGci;3rG&5LRMfw%v~^^c>!-Ql^&FZKh+E^~>WEeDeOxE0rYNXL9GIfn?` zyu@w$l60HF70i49JUYV_-~10Sua!Hhkf1>^T=^Ia;P1s%e(eP0*KpPU_u+6b*SJtd zJjNX2u9i~dI)k}eVWhDA3D?6>p(M4|F~cB9GP`MD zrrOc)+KvS^c04jqTOCY#;}2`k`4V=$uQYHb$D4~B#`pFBOKc9I=6S^Ss`8o}G+5`5 z>qcG5v^XerGLRnN@csNLRBNN+p*0%{dL8;UCXwbO-GGOol;!}P^EZ^#oBfq7T2IH? zWZf#ud0?8KZo|tzNTHL`pf$NwXXpwyT?8_cbq6QDA*UYbDvGE>A7<#9d3lq(cP~8UxNAadjSAmi;J}l!Hjr1CRSw3+b?9N9& zn?*jC@iEKjnmfsS++ANF?}{DIC-7+zG5Z zuLZb}CA6>Y0dDUTI)Zl5;7=6p7CFHM6{mz}juf<#6ye#hI5NUZ^bT7D#K_`gcQR`4 z=Sq{#=${oY#+Of}<1%sOM}@$RE^&3|1Pc5maqR*XE#y>jM?(%};hwlNfZEo5NZh$} zCb0XCGKwE<9WH*SqVZbRX2)Co#521|&8O!?+aof~eV5oAM=bY8iYECEnHA5-r8|QL)W7X@xbMHmOZY3CsrEUP|lMnJKRur2RK+z>X=>^&dQG z2R2LhvzJoq&q@Dlqf1p=rI#_2>FdxXqmD?Py&yZhZK2)zfjl5#6!2Mz>@t;})9=b| z18qbmSa!GU1DwamL4Dh4M_ve2QU#MWqgOuom+?TDQ7#%rBBK1|%LRV4b24R{7exTD zqhWv@3zF=3#2~j@Hd03_?AVYZ|98$v+QF52uTf+rVKeuDE( zpe|e=e42EB9HO6HY=+_{@>87kk@=hH!?i@eJex`n%F`#g6ZKR6`VAk_t2J5r><(J@ z;Uo0L#&(jjTVLAr2k`Hs`r|WXpy;uZEP85h1yItS3|D$fyem6Ir}WBt<%NG`Nb{r7 Fe*z$ 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 を含む) を次のように記入してください: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 新規 @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: アドレスをコピー - + Special address behavior... アドレスの特別な動作 - + Email gateway メールゲートウェイ @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: 削除 - + 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. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1161,17 +1161,17 @@ Are you sure you want to delete the channel? %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1275,7 +1275,7 @@ Receiver's required difficulty: %1 and %2 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 @@ -1285,7 +1285,7 @@ Receiver's required difficulty: %1 and %2 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 @@ -1310,37 +1310,37 @@ Receiver's required difficulty: %1 and %2 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 PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1360,72 +1360,77 @@ Receiver's required difficulty: %1 and %2 お使いのコンピュータの時間 %1 は間違っている可能性があります。 設定を確認してください。 - + + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. + GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 + + + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... @@ -1967,6 +1972,24 @@ The 'Random Number' option is selected by default but deterministic ad チャンネルの作成 / 参加をキャンセルしました + + 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 モジュールが利用できません。ビルドしてください。 + + regenerateAddressesDialog -- 2.45.1 From 541979a159e68e9eb81276a9eff40b10ab6dd031 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 5 Jan 2017 19:24:45 +0100 Subject: [PATCH 0532/1102] Auto-updated language fr from transifex --- src/translations/bitmessage_fr.qm | Bin 93480 -> 94455 bytes src/translations/bitmessage_fr.ts | 323 ++++++++++++++++-------------- 2 files changed, 173 insertions(+), 150 deletions(-) diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 2513d3e6773809fb1d7831aeebc91a10efdc6abf..1796355d71586cdaf7beb15f2417531d2eb82658 100644 GIT binary patch delta 3944 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 delta 3120 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 diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index e9028bd2..16d06f3d 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -58,12 +58,12 @@ 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) : @@ -173,52 +173,52 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : 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 @@ -243,12 +243,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Copier l’adresse dans le presse-papier - + Special address behavior... Comportement spécial de l’adresse… - + Email gateway Passerelle de courriel @@ -258,37 +258,37 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -298,17 +298,17 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -318,47 +318,47 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -368,12 +368,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Envoyer - + Subscribe S’abonner - + Channel Canal @@ -383,12 +383,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -396,54 +396,54 @@ It is important that you back up this file. 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. @@ -513,22 +513,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -537,17 +537,17 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -592,67 +592,67 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + 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 De - + Sending email gateway registration request Envoi de la demande d’inscription de la passerelle de courriel @@ -667,142 +667,142 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? Ê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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? Ê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). @@ -1115,47 +1115,47 @@ Are you sure you want to delete the channel? 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% @@ -1165,17 +1165,17 @@ Are you sure you want to delete the channel? %n heure%n heures - + %n day(s) %n jour%n jours - + Shutting down PyBitmessage... %1% PyBitmessage en cours d’arrêt… %1% - + Sent Envoyé @@ -1279,7 +1279,7 @@ Difficulté requise du destinataire : %1 et %2 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 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. @@ -1289,7 +1289,7 @@ Difficulté requise du destinataire : %1 et %2 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. @@ -1314,37 +1314,37 @@ Difficulté requise du destinataire : %1 et %2 Transfert de port UPnP retiré - + Mark all messages as read Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? - + Doing work necessary to send broadcast. Travail en cours afin d’envoyer la diffusion. - + 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 - + Wait until these tasks finish? Attendre jusqu'à ce que ces tâches se terminent ? @@ -1364,72 +1364,77 @@ Difficulté requise du destinataire : %1 et %2 L'heure sur votre ordinateur, %1, pourrait être faussse. Veuillez vérifier vos paramètres. - + + 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. + + + 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 - + 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. - + 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. - + 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 celui de votre connaissance est intelligent. + 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. - + 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. - + 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. - + 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: Something is wrong with the recipient address %1. Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. - + 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 ? - + Not connected Non connecté - + 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 ? - + Waiting for network connection... En attente de connexion réseau... - + Waiting for finishing synchronisation... En attente d'achèvement de la synchronisation... @@ -1971,6 +1976,24 @@ The 'Random Number' option is selected by default but deterministic ad 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. + + regenerateAddressesDialog -- 2.45.1 From 4f543e14c1cf6b6514160f537cb695f509c115be Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 7 Jan 2017 23:42:07 +0100 Subject: [PATCH 0533/1102] TLS handshake fix - TLS handshake in python is apparently always asynchronous, so it needs proper handling of SSLWantReadError and SSLWantWriteError - also adds a timeout and a proper shutdown if handshake fails --- src/class_receiveDataThread.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 0b686ddf..c69697d6 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -294,14 +294,18 @@ class receiveDataThread(threading.Thread): while True: try: self.sslSock.do_handshake() + logger.debug("TLS handshake success") break - except ssl.SSLError as e: - if e.errno == 2: - select.select([self.sslSock], [self.sslSock], []) - else: - break + except ssl.SSLWantReadError: + logger.debug("Waiting for SSL socket handhake read") + select.select([self.sslSock], [], [], 10) + except ssl.SSLWantWriteError: + logger.debug("Waiting for SSL socket handhake write") + select.select([], [self.sslSock], [], 10) except: - break + logger.debug("SSL socket handhake failed, shutting down connection") + self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) + return # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) -- 2.45.1 From e84b19613e2bfc4ed44e3f6350b23f6c2e01e9e3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:15:35 +0100 Subject: [PATCH 0534/1102] Inventory refactoring - minor refactoring, made it into singleton instead of a shared global variable. This makes it a little bit cleaner and moves the class into a separate file - removed duplicate inventory locking - renamed singleton.py to singleinstance.py (this is the code that ensures only one instance of PyBitmessage runs at the same time) --- src/bitmessagecurses/__init__.py | 5 +- src/bitmessagemain.py | 4 +- src/bitmessageqt/__init__.py | 2 +- src/bitmessageqt/networkstatus.py | 5 +- src/class_receiveDataThread.py | 19 ++--- src/class_singleCleaner.py | 5 +- src/class_singleWorker.py | 15 ++-- src/inventory.py | 84 ++++++++++++++++++++ src/shared.py | 127 +++--------------------------- src/singleinstance.py | 84 ++++++++++++++++++++ src/singleton.py | 91 ++------------------- 11 files changed, 214 insertions(+), 227 deletions(-) create mode 100644 src/inventory.py create mode 100644 src/singleinstance.py diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 3b740247..1d667b2b 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -26,6 +26,7 @@ import ConfigParser from addresses import * from pyelliptic.openssl import OpenSSL import l10n +from inventory import Inventory quit = False menutab = 1 @@ -108,8 +109,8 @@ def scrollbox(d, text, height=None, width=None): def resetlookups(): global inventorydata - inventorydata = shared.numberOfInventoryLookupsPerformed - shared.numberOfInventoryLookupsPerformed = 0 + inventorydata = Inventory().numberOfInventoryLookupsPerformed + Inventory().numberOfInventoryLookupsPerformed = 0 Timer(1, resetlookups, ()).start() def drawtab(stdscr): if menutab in range(1, len(menu)+1): diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 830dca31..3b2d1aae 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -14,7 +14,7 @@ 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 -import singleton +from singleinstance import singleinstance import os import socket import ctypes @@ -162,7 +162,7 @@ class Main: shared.curses = True # is the application already running? If yes then exit. - shared.thisapp = singleton.singleinstance("", daemon) + shared.thisapp = singleinstance("", daemon) if daemon: with shared.printLock: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 37c52917..4e3366c7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4428,7 +4428,7 @@ class MySingleApplication(QApplication): # Checks if there's an instance of the local server id running if self.is_running: - # This should be ignored, singleton.py will take care of exiting me. + # 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 diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 09d05c63..c792f81c 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -2,6 +2,7 @@ from PyQt4 import QtCore, QtGui import time import shared from tr import _translate +from inventory import Inventory import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler @@ -127,8 +128,8 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): # timer driven def runEveryTwoSeconds(self): self.labelLookupsPerSecond.setText(_translate( - "networkstatus", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) - shared.numberOfInventoryLookupsPerformed = 0 + "networkstatus", "Inventory lookups per second: %1").arg(str(Inventory().numberOfInventoryLookupsPerformed/2))) + Inventory().numberOfInventoryLookupsPerformed = 0 self.updateNumberOfBytes() self.updateNumberOfObjectsToBeSynced() diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c69697d6..f29b1f4c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -27,6 +27,7 @@ from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +from inventory import Inventory import tr # This thread is created either by the synSenderThread(for outgoing @@ -230,10 +231,9 @@ class receiveDataThread(threading.Thread): if self.data == '': # if there are no more messages while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: - shared.numberOfInventoryLookupsPerformed += 1 objectHash, = random.sample( self.objectsThatWeHaveYetToGetFromThisPeer, 1) - if objectHash in shared.inventory: + if objectHash in Inventory(): logger.debug('Inventory already has object listed in inv message.') del self.objectsThatWeHaveYetToGetFromThisPeer[objectHash] else: @@ -336,7 +336,7 @@ class receiveDataThread(threading.Thread): def sendBigInv(self): # Select all hashes for objects in this stream. bigInvList = {} - for hash in shared.inventory.unexpired_hashes_by_stream(self.streamNumber): + for hash in Inventory().unexpired_hashes_by_stream(self.streamNumber): if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 @@ -442,8 +442,7 @@ class receiveDataThread(threading.Thread): return self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ data[lengthOfVarint:32 + lengthOfVarint]] = 0 - shared.numberOfInventoryLookupsPerformed += 1 - if data[lengthOfVarint:32 + lengthOfVarint] in shared.inventory: + if data[lengthOfVarint:32 + lengthOfVarint] in Inventory(): logger.debug('Inventory has inventory item already.') else: self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) @@ -455,7 +454,7 @@ class receiveDataThread(threading.Thread): advertisedSet = set() for i in range(numberOfItemsInInv): advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) - objectsNewToMe = advertisedSet - shared.inventory.hashes_by_stream(self.streamNumber) + objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(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 and shared.trustedPeer == None: # inv flooding attack mitigation @@ -488,15 +487,11 @@ class receiveDataThread(threading.Thread): i * 32):32 + lengthOfVarint + (i * 32)] logger.debug('received getdata request for item:' + hexlify(hash)) - shared.numberOfInventoryLookupsPerformed += 1 - shared.inventoryLock.acquire() if self.objectHashHolderInstance.hasHash(hash): - shared.inventoryLock.release() self.antiIntersectionDelay() else: - shared.inventoryLock.release() - if hash in shared.inventory: - self.sendObject(shared.inventory[hash].payload) + if hash in Inventory(): + self.sendObject(Inventory()[hash].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,)) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 04ee3f9b..533184d3 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -8,6 +8,7 @@ import pickle import tr#anslate from helper_sql import * from helper_threading import * +from inventory import Inventory from debug import logger """ @@ -47,7 +48,7 @@ class singleCleaner(threading.Thread, StoppableThread): while shared.shutdown == 0: shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) - shared.inventory.flush() + Inventory().flush() shared.UISignalQueue.put(('updateStatusBar', '')) shared.broadcastToSendDataQueues(( @@ -59,7 +60,7 @@ class singleCleaner(threading.Thread, StoppableThread): shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) - shared.inventory.clean() + Inventory().clean() # pubkeys sqlExecute( '''DELETE FROM pubkeys WHERE timeQ', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -351,7 +352,7 @@ class singleWorker(threading.Thread, StoppableThread): payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -482,7 +483,7 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(payload) objectType = 3 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( @@ -576,7 +577,7 @@ class singleWorker(threading.Thread, StoppableThread): tag = doubleHashOfToAddressData[32:] # The second half of the sha512 hash. shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) - for value in shared.inventory.by_type_and_tag(1, toTag): + 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( @@ -808,7 +809,7 @@ class singleWorker(threading.Thread, StoppableThread): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) @@ -917,7 +918,7 @@ class singleWorker(threading.Thread, StoppableThread): payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) objectType = 1 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') logger.info('sending inv (for the getpubkey message)') shared.broadcastToSendDataQueues(( diff --git a/src/inventory.py b/src/inventory.py new file mode 100644 index 00000000..83a9ce82 --- /dev/null +++ b/src/inventory.py @@ -0,0 +1,84 @@ +import collections +from threading import RLock +import time + +from helper_sql import * +from singleton import Singleton + +inventoryLock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) +InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') + + +@Singleton +class Inventory(collections.MutableMapping): + 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.numberOfInventoryLookupsPerformed = 0 + self._streams = collections.defaultdict(set) # 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. + + def __contains__(self, hash): + with inventoryLock: + self.numberOfInventoryLookupsPerformed += 1 + if hash in self._inventory: + return True + return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) + + def __getitem__(self, hash): + with inventoryLock: + if hash in self._inventory: + return self._inventory[hash] + rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', hash) + if not rows: + raise KeyError(hash) + return InventoryItem(*rows[0]) + + def __setitem__(self, hash, value): + with inventoryLock: + value = InventoryItem(*value) + self._inventory[hash] = value + self._streams[value.stream].add(hash) + + def __delitem__(self, hash): + raise NotImplementedError + + def __iter__(self): + with inventoryLock: + hashes = self._inventory.keys()[:] + hashes += (hash for hash, in sqlQuery('SELECT hash FROM inventory')) + return hashes.__iter__() + + def __len__(self): + with inventoryLock: + return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0] + + def by_type_and_tag(self, type, tag): + with inventoryLock: + values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] + values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) + return values + + def hashes_by_stream(self, stream): + with inventoryLock: + return self._streams[stream] + + def unexpired_hashes_by_stream(self, stream): + with inventoryLock: + t = int(time.time()) + hashes = [hash for hash, value in self._inventory.items() if value.stream == stream and value.expires > t] + hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) + return hashes + + def flush(self): + with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + with SqlBulkExecute() as sql: + for hash, value in self._inventory.items(): + sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value) + self._inventory.clear() + + def clean(self): + with inventoryLock: + sqlExecute('DELETE FROM inventory WHERE expirestime t] - hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) - return hashes - - def flush(self): - with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. - with SqlBulkExecute() as sql: - for hash, value in self._inventory.items(): - sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value) - self._inventory.clear() - - def clean(self): - with inventoryLock: - sqlExecute('DELETE FROM inventory WHERE expirestimeI', data[16:20]) - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - inventoryLock.release() logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -833,17 +746,13 @@ def _checkAndShareMsgWithPeers(data): return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) - shared.numberOfInventoryLookupsPerformed += 1 - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this msg message. Ignoring.') - 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,'') - inventoryLock.release() logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -868,18 +777,14 @@ def _checkAndShareGetpubkeyWithPeers(data): return readPosition += streamNumberLength - shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this getpubkey request. Ignoring it.') - inventoryLock.release() return objectType = 0 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - inventoryLock.release() # This getpubkey request is valid. Forward to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -907,17 +812,13 @@ def _checkAndSharePubkeyWithPeers(data): else: tag = '' - shared.numberOfInventoryLookupsPerformed += 1 inventoryHash = calculateInventoryHash(data) - inventoryLock.acquire() - if inventoryHash in inventory: + if inventoryHash in Inventory(): logger.debug('We have already received this pubkey. Ignoring it.') - inventoryLock.release() return objectType = 1 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) - inventoryLock.release() # This object is valid. Forward it to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -946,18 +847,14 @@ def _checkAndShareBroadcastWithPeers(data): 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 # It is valid. Let's let our peers know about it. objectType = 3 - inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) - inventoryLock.release() # This object is valid. Forward it to peers. logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) diff --git a/src/singleinstance.py b/src/singleinstance.py new file mode 100644 index 00000000..8bf7ed01 --- /dev/null +++ b/src/singleinstance.py @@ -0,0 +1,84 @@ +#! /usr/bin/env python + +import atexit +import errno +from multiprocessing import Process +import os +import sys +import shared + +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(shared.appdata, 'singleton%s.lock' % flavor_id)) + + if not self.daemon and not shared.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) + 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 + self.fp = open(self.lockfile, 'w') + 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) + + def cleanup(self): + if not self.initialized: + return + if self.daemon and self.lockPid == os.getpid(): + # these are the two initial forks while daemonizing + 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 8bf7ed01..1eef08e1 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -1,84 +1,7 @@ -#! /usr/bin/env python - -import atexit -import errno -from multiprocessing import Process -import os -import sys -import shared - -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(shared.appdata, 'singleton%s.lock' % flavor_id)) - - if not self.daemon and not shared.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) - 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 - self.fp = open(self.lockfile, 'w') - 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) - - def cleanup(self): - if not self.initialized: - return - if self.daemon and self.lockPid == os.getpid(): - # these are the two initial forks while daemonizing - 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 +def Singleton(cls): + instances = {} + def getinstance(): + if cls not in instances: + instances[cls] = cls() + return instances[cls] + return getinstance -- 2.45.1 From 9c214b4a249ba0092434c5068ee13b472944e549 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:17:25 +0100 Subject: [PATCH 0535/1102] Inventory refactoring #2 - forgot to add api.py --- src/api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api.py b/src/api.py index 30ab426e..0a76ff1b 100644 --- a/src/api.py +++ b/src/api.py @@ -29,6 +29,7 @@ from struct import pack # Classes from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger +from inventory import Inventory # Helper Functions import proofofwork @@ -849,7 +850,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): inventoryHash = calculateInventoryHash(encryptedPayload) objectType = 2 TTL = 2.5 * 24 * 60 * 60 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) @@ -896,7 +897,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType = 1 #todo: support v4 pubkeys TTL = 28 * 24 * 60 * 60 - shared.inventory[inventoryHash] = ( + Inventory()[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) -- 2.45.1 From b4703ec6ce37fda706e5f296ec30038944b9e275 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:19:57 +0100 Subject: [PATCH 0536/1102] Make objectHashHolder into a list - was a dict --- src/class_objectHashHolder.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 30d27ea8..24c2438d 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -17,11 +17,11 @@ class objectHashHolder(threading.Thread): threading.Thread.__init__(self, name="objectHashHolder") 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(self.size): - self.collectionOfHashLists[i] = [] - self.collectionOfPeerLists[i] = [] + self.collectionOfHashLists = [] + self.collectionOfPeerLists = [] + for i in range(objectHashHolder.size): + self.collectionOfHashLists.append([]) + self.collectionOfPeerLists.append([]) def run(self): iterator = 0 @@ -33,11 +33,11 @@ class objectHashHolder(threading.Thread): self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) self.collectionOfPeerLists[iterator] = [] iterator += 1 - iterator %= self.size + iterator %= objectHashHolder.size time.sleep(1) def holdHash(self,hash): - self.collectionOfHashLists[random.randrange(0, self.size)].append(hash) + self.collectionOfHashLists[random.randrange(0, objectHashHolder.size)].append(hash) def hasHash(self, hash): if hash in (hashlist for hashlist in self.collectionOfHashLists): @@ -46,7 +46,7 @@ class objectHashHolder(threading.Thread): return False def holdPeer(self,peerDetails): - self.collectionOfPeerLists[random.randrange(0, self.size)].append(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]) -- 2.45.1 From 75090abaaf1d9190ac250326108ca1882b6f3c45 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:20:49 +0100 Subject: [PATCH 0537/1102] Advanced dispatcher class - generic class the new asyncore-based network subsystem that handles buffered data transfer --- src/network/advanceddispatcher.py | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/network/advanceddispatcher.py diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py new file mode 100644 index 00000000..47eacc5a --- /dev/null +++ b/src/network/advanceddispatcher.py @@ -0,0 +1,50 @@ +class AdvancedDispatcher(asyncore.dispatcher): + _buf_len = 131072 + + def __init__(self, sock): + asyncore.dispatcher.__init__(self, sock) + self.read_buf = "" + self.write_buf = "" + self.state = "init" + + def slice_read_buf(length=0): + self.read_buf = self.read_buf[length:] + + def slice_write_buf(length=0): + self.write_buf = self.read_buf[length:] + + def read_buf_sufficient(length=0): + if len(self.read_buf) < length: + return False + else: + return True + + def process(self): + if len(self.read_buf) == 0: + return + while True: + try: + if getattr(self, "state_" + str(self.state))() is False: + break + except AttributeError: + # missing state + raise + + def set_state(self, state, length): + self.slice_read_buf(length) + self.state = state + + def writable(self): + return len(self.write_buf) > 0 + + def readable(self): + return len(self.read_buf) < AdvancedDispatcher._buf_len + + def handle_read(self): + self.read_buf += self.recv(AdvancedDispatcher._buf_len) + self.process() + + def handle_write(self): + written = self.send(self.write_buf) + self.slice_write_buf(written) +# self.process() -- 2.45.1 From 085e33596998665fbe0bf93daa8bdd227a9dfac5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 10 Jan 2017 21:22:22 +0100 Subject: [PATCH 0538/1102] Proxy update (for the new network subsystem) --- src/network/proxy.py | 195 ++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 123 deletions(-) diff --git a/src/network/proxy.py b/src/network/proxy.py index aab28c50..d9830431 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -4,13 +4,13 @@ import asyncore import socket import struct +from advanceddispatcher import AdvancedDispatcher -class Proxy(asyncore.dispatcher): +class Proxy(AdvancedDispatcher): # these are global, and if you change config during runtime, all active/new # instances should change too _proxy = ["", 1080] _auth = None - _buf_len = 131072 _remote_dns = True @property @@ -34,46 +34,17 @@ class Proxy(asyncore.dispatcher): def __init__(self, address=None): if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): raise - asyncore.dispatcher.__init__(self, self.sock) + AdvancedDispatcher.__init__(self, self.sock) self.destination = address - self.read_buf = "" - self.write_buf = "" - self.stage = "init" self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.sslSocket.setblocking(0) self.connect(self.proxy) - def process(self): - try: - getattr(self, "state_" + str(self.stage))() - except AttributeError: - # missing stage - raise - - def set_state(self, state): - self.state = state - self.read_buf = "" - - def writable(self): - return len(self.write_buf) > 0 - - def readable(self): - return len(self.read_buf) < Proxy._buf_len - - def handle_read(self): - self.read_buf += self.recv(Proxy._buf_len) - self.process() - - def handle_write(self): - written = self.send(self.write_buf) - self.write_buf = self.write_buf[written:] - self.process() - class SOCKS5(Proxy): def __init__(self, address=None, sock=None): Proxy.__init__(self, address) - self.state = 0 + self.state = "init" def handle_connect(self): self.process() @@ -83,11 +54,11 @@ class SOCKS5(Proxy): self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) else: self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) - self.set_state("auth_1") + self.set_state("auth_1", 0) def state_auth_1(self): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False ret = struct.unpack('BB', self.read_buf) self.read_buf = self.read_buf[2:] if ret[0] != 5: @@ -95,13 +66,13 @@ class SOCKS5(Proxy): raise elif ret[1] == 0: # no auth required - self.set_state("auth_done") + self.set_state("auth_done", 2) elif ret[1] == 2: # username/password self.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_1") + self.set_state("auth_1", 2) else: if ret[1] == 0xff: # auth error @@ -111,8 +82,8 @@ class SOCKS5(Proxy): raise def state_auth_needed(self): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False ret = struct.unpack('BB', self.read_buf) if ret[0] != 1: # general error @@ -121,37 +92,11 @@ class SOCKS5(Proxy): # auth error raise # all ok - self.set_state = ("auth_done") - - -class SOCKS5Connection(SOCKS5): - def __init__(self, address): - SOCKS5.__init__(self, address) - - def state_auth_done(self): - # Now we can request the actual connection - self.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: - ipaddr = socket.inet_aton(self.destination[0]) - self.write_buf += chr(0x01).encode() + ipaddr - except socket.error: - # Well it's not an IP number, so it's probably a DNS name. - if Proxy._remote_dns: - # Resolve remotely - ipaddr = None - self.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0] - else: - # Resolve locally - ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) - self.write_buf += chr(0x01).encode() + ipaddr - self.write_buf += struct.pack(">H", self.destination[1]) - self.set_state = ("pre_connect") + self.set_state = ("auth_done", 2) def state_pre_connect(self): - if len(self.read_buf) < 4: - return + if not self.read_buf_sufficient(4): + return False # Get the response if self.read_buf[0:1] != chr(0x05).encode(): # general error @@ -168,74 +113,78 @@ class SOCKS5Connection(SOCKS5): raise #raise Socks5Error((9, _socks5errors[9])) # Get the bound address/port - elif self_read_buf[3:4] == chr(0x01).encode(): - self.set_state("proxy_addr_long") - elif resp[3:4] == chr(0x03).encode(): - self.set_state("proxy_addr_short") + elif self.read_buf[3:4] == chr(0x01).encode(): + self.set_state("proxy_addr_1", 4) + elif self.read_buf[3:4] == chr(0x03).encode(): + self.set_state("proxy_addr_2_1", 4) else: self.close() raise GeneralProxyError((1,_generalerrors[1])) - boundport = struct.unpack(">H", self.__recvall(2))[0] - self.__proxysockname = (boundaddr, boundport) - if ipaddr != None: - self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) - else: - self.__proxypeername = (destaddr, destport) - def state_proxy_addr_long(self): - if len(self.read_buf) < 4: - return + def state_proxy_addr_1(self): + if not self.read_buf_sufficient(4): + return False self.boundaddr = self.read_buf[0:4] - self.set_state("proxy_port") + self.set_state("proxy_port", 4) - def state_proxy_addr_short(self): - if len(self.read_buf) < 1: - return - self.boundaddr = self.read_buf[0:1] - self.set_state("proxy_port") + def state_proxy_addr_2_1(self): + if not self.read_buf_sufficient(1): + return False + self.address_length = ord(self.read_buf[0:1]) + self.set_state("proxy_addr_2_2", 1) + + def state_proxy_addr_2_2(self): + if not self.read_buf_sufficient(self.address_length): + return False + self.boundaddr = read_buf + self.set_state("proxy_port", self.address_length) def state_proxy_port(self): - if len(self.read_buf) < 2: - return + if not self.read_buf_sufficient(2): + return False self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] self.__proxysockname = (self.boundaddr, self.boundport) - if ipaddr != None: - self.__proxypeername = (socket.inet_ntoa(ipaddr), destport) + if self.ipaddr != None: + self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: - self.__proxypeername = (destaddr, destport) + self.__proxypeername = (self.destination[1], destport) -class SOCKS5Resolver(SOCKS5): - def __init__(self, destpair): - SOCKS5.__init__(self, destpair) +class SOCKS5Connection(SOCKS5): + def __init__(self, address): + SOCKS5.__init__(self, address) def state_auth_done(self): # 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])])) + self.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.write_buf += chr(0x01).encode() + 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.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0] 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 + # Resolve locally + self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) + self.write_buf += chr(0x01).encode() + ipaddr + self.write_buf += struct.pack(">H", self.destination[1]) + self.set_state = ("pre_connect", 0) + + +class SOCKS5Resolver(SOCKS5): + def __init__(self, host): + self.host = host + self.port = 8444 + SOCKS5.__init__(self, [self.host, self.port]) + + def state_auth_done(self): + # Now we can request the actual connection + self.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00) + self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + self.host + self.write_buf += struct.pack(">H", self.port) + self.state = "pre_connect" -- 2.45.1 From 2654b61bd721b97dd17e7bc4a4f71a55ea3e546f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:21:53 +0100 Subject: [PATCH 0539/1102] Compiletest for non-Windows systems --- build/compiletest.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 build/compiletest.py diff --git a/build/compiletest.py b/build/compiletest.py old mode 100644 new mode 100755 index 91df6c5e..fdbf7db1 --- a/build/compiletest.py +++ b/build/compiletest.py @@ -16,5 +16,8 @@ for filename in matches: try: compile(source, filename, 'exec') except Exception as e: - ctypes.windll.user32.MessageBoxA(0, traceback.format_exc(), "Exception in " + filename, 1) - sys.exit(1) \ No newline at end of file + 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) -- 2.45.1 From 8bcfe80ad0a33bd2f724697eefef8c9ac336ca2a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:27:19 +0100 Subject: [PATCH 0540/1102] Refactoring of config parser and shared.py - got rid of shared config parser and made it into a singleton - refactored safeConfigGetBoolean as a method of the config singleton - refactored safeConfigGet as a method of the config singleton - moved softwareVersion from shared.py into version.py - moved some global variables from shared.py into state.py - moved some protocol-specific functions from shared.py into protocol.py --- src/api.py | 66 ++--- src/bitmessagecli.py | 133 ++++----- src/bitmessagecurses/__init__.py | 56 ++-- src/bitmessagemain.py | 29 +- src/bitmessageqt/__init__.py | 288 ++++++++++---------- src/bitmessageqt/account.py | 25 +- src/bitmessageqt/bitmessageui.py | 5 +- src/bitmessageqt/blacklist.py | 23 +- src/bitmessageqt/foldertree.py | 31 ++- src/bitmessageqt/languagebox.py | 5 +- src/bitmessageqt/support.py | 12 +- src/bitmessageqt/utils.py | 7 +- src/class_addressGenerator.py | 45 +-- src/class_objectProcessor.py | 51 ++-- src/class_outgoingSynSender.py | 41 +-- src/class_receiveDataThread.py | 67 ++--- src/class_sendDataThread.py | 22 +- src/class_singleCleaner.py | 10 +- src/class_singleListener.py | 24 +- src/class_singleWorker.py | 107 ++++---- src/class_smtpDeliver.py | 5 +- src/class_smtpServer.py | 16 +- src/class_sqlThread.py | 145 +++++----- src/configparser.py | 18 ++ src/helper_bootstrap.py | 21 +- src/helper_generic.py | 3 +- src/helper_startup.py | 87 +++--- src/l10n.py | 9 +- src/namecoin.py | 31 ++- src/openclpow.py | 5 +- src/proofofwork.py | 3 +- src/protocol.py | 454 ++++++++++++++++++++++++++++++- src/shared.py | 131 +-------- src/state.py | 7 + src/tr.py | 6 +- src/upnp.py | 11 +- src/version.py | 1 + 37 files changed, 1187 insertions(+), 813 deletions(-) create mode 100644 src/state.py create mode 100644 src/version.py diff --git a/src/api.py b/src/api.py index 0a76ff1b..276e397f 100644 --- a/src/api.py +++ b/src/api.py @@ -19,6 +19,7 @@ from binascii import hexlify import shared import time from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError +from configparser import BMConfigParser import helper_inbox import helper_sent import hashlib @@ -30,6 +31,7 @@ from struct import pack from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger from inventory import Inventory +from version import softwareVersion # Helper Functions import proofofwork @@ -120,7 +122,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): # handle Basic authentication (enctype, encstr) = self.headers.get('Authorization').split() (emailid, password) = encstr.decode('base64').split(':') - if emailid == shared.config.get('bitmessagesettings', 'apiusername') and password == shared.config.get('bitmessagesettings', 'apipassword'): + if emailid == BMConfigParser().get('bitmessagesettings', 'apiusername') and password == BMConfigParser().get('bitmessagesettings', 'apipassword'): return True else: return False @@ -163,22 +165,22 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleListAddresses(self, method): data = '{"addresses":[' - configSections = shared.config.sections() + configSections = BMConfigParser().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') + if BMConfigParser().has_option(addressInKeysFile, 'chan'): + chan = BMConfigParser().getboolean(addressInKeysFile, 'chan') else: chan = False - label = shared.config.get(addressInKeysFile, 'label') + label = BMConfigParser().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=(',', ': ')) + streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -236,21 +238,21 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 1: label, = params eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: label, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params @@ -280,45 +282,45 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 2: passphrase, numberOfAddresses = params addressVersionNumber = 0 streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 3: passphrase, numberOfAddresses, addressVersionNumber = params streamNumber = 0 eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: passphrase, numberOfAddresses, addressVersionNumber, streamNumber = params eighteenByteRipe = False - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 5: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe = params - nonceTrialsPerByte = shared.config.get( + nonceTrialsPerByte = BMConfigParser().get( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) - payloadLengthExtraBytes = shared.config.get( + payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params @@ -443,13 +445,13 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) - if not shared.config.has_section(address): + if not BMConfigParser().has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') - if not shared.safeConfigGetBoolean(address, 'chan'): + if not BMConfigParser().safeGetBoolean(address, 'chan'): raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') - shared.config.remove_section(address) + BMConfigParser().remove_section(address) with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) return 'success' def HandleDeleteAddress(self, params): @@ -459,11 +461,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(address) address = addBMIfNotPresent(address) - if not shared.config.has_section(address): + if not BMConfigParser().has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') - shared.config.remove_section(address) + BMConfigParser().remove_section(address) with open(shared.appdata + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.reloadMyAddressHashes() @@ -659,7 +661,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(toAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = shared.config.getboolean( + fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') except: raise APIError(13, 'Could not find your fromAddress in the keys.dat file.') @@ -723,7 +725,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): fromAddress = addBMIfNotPresent(fromAddress) self._verifyAddress(fromAddress) try: - fromAddressEnabled = shared.config.getboolean( + fromAddressEnabled = BMConfigParser().getboolean( fromAddress, 'enabled') except: raise APIError(13, 'could not find your fromAddress in the keys.dat file.') @@ -946,7 +948,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: networkStatus = 'connectedAndReceivingIncomingConnections' - 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=(',', ': ')) + return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':softwareVersion}, indent=4, separators=(',', ': ')) def HandleDecodeAddress(self, params): # Return a meaningful decoding of an address. diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index c7d8b5cd..79272aee 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -45,16 +45,6 @@ def restartBmNotify(): #Prompts the user to restart Bitmessage. print ' WARNING: If Bitmessage is running locally, you must restart it now.' print ' *******************************************************************\n' -def safeConfigGetBoolean(section,field): - global keysPath - config = BMConfigParser() - config.read(keysPath) - - try: - return config.getboolean(section,field) - except: - return False - #Begin keys.dat interactions def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py APPNAME = "PyBitmessage" @@ -74,14 +64,13 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe def configInit(): global keysName - config = BMConfigParser() - config.add_section('bitmessagesettings') - config.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. - config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat + 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: - config.write(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' @@ -89,8 +78,7 @@ def configInit(): def apiInit(apiEnabled): global keysPath global usrPrompt - config = BMConfigParser() - config.read(keysPath) + BMConfigParser().read(keysPath) @@ -98,9 +86,9 @@ def apiInit(apiEnabled): uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower() if uInput == "y": # - config.set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat + BMConfigParser().set('bitmessagesettings','apienabled','true') #Sets apienabled to true in keys.dat with open(keysPath, 'wb') as configfile: - config.write(configfile) + BMConfigParser().write(configfile) print 'Done' restartBmNotify() @@ -143,15 +131,15 @@ def apiInit(apiEnabled): print ' -----------------------------------\n' - config.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. - config.set('bitmessagesettings','apienabled','true') - config.set('bitmessagesettings', 'apiport', apiPort) - config.set('bitmessagesettings', 'apiinterface', '127.0.0.1') - config.set('bitmessagesettings', 'apiusername', apiUsr) - config.set('bitmessagesettings', 'apipassword', apiPwd) - config.set('bitmessagesettings', 'daemon', daemon) + 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: - config.write(configfile) + BMConfigParser().write(configfile) print '\n Finished configuring the keys.dat file with API information.\n' restartBmNotify() @@ -174,21 +162,19 @@ def apiData(): global keysPath global usrPrompt - config = BMConfigParser() - config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory + BMConfigParser().read(keysPath) #First try to load the config file (the keys.dat file) from the program directory try: - config.get('bitmessagesettings','port') + 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 - config = BMConfigParser() - config.read(keysPath) + BMConfigParser().read(keysPath) try: - config.get('bitmessagesettings','port') + BMConfigParser().get('bitmessagesettings','port') except: #keys.dat was not there either, something is wrong. print '\n ******************************************************************' @@ -215,21 +201,21 @@ def apiData(): main() try: #checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after - config.get('bitmessagesettings', 'apiport') - config.get('bitmessagesettings', 'apiinterface') - config.get('bitmessagesettings', 'apiusername') - config.get('bitmessagesettings', 'apipassword') + 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(safeConfigGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true + apiEnabled = apiInit(BMConfigParser().safeGetBoolean('bitmessagesettings','apienabled')) #if false it will prompt the user, if true it will return true - config.read(keysPath)#read again since changes have been made - apiPort = int(config.get('bitmessagesettings', 'apiport')) - apiInterface = config.get('bitmessagesettings', 'apiinterface') - apiUsername = config.get('bitmessagesettings', 'apiusername') - apiPassword = config.get('bitmessagesettings', 'apipassword') + 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' @@ -253,31 +239,30 @@ def apiTest(): #Tests the API connection to bitmessage. Returns true if it is co def bmSettings(): #Allows the viewing and modification of keys.dat settings. global keysPath global usrPrompt - config = BMConfigParser() keysPath = 'keys.dat' - config.read(keysPath)#Read the keys.dat + BMConfigParser().read(keysPath)#Read the keys.dat try: - port = config.get('bitmessagesettings', 'port') + port = BMConfigParser().get('bitmessagesettings', 'port') except: print '\n File not found.\n' usrPrompt = 0 main() - startonlogon = safeConfigGetBoolean('bitmessagesettings', 'startonlogon') - minimizetotray = safeConfigGetBoolean('bitmessagesettings', 'minimizetotray') - showtraynotifications = safeConfigGetBoolean('bitmessagesettings', 'showtraynotifications') - startintray = safeConfigGetBoolean('bitmessagesettings', 'startintray') - defaultnoncetrialsperbyte = config.get('bitmessagesettings', 'defaultnoncetrialsperbyte') - defaultpayloadlengthextrabytes = config.get('bitmessagesettings', 'defaultpayloadlengthextrabytes') - daemon = safeConfigGetBoolean('bitmessagesettings', 'daemon') + 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 = config.get('bitmessagesettings', 'socksproxytype') - sockshostname = config.get('bitmessagesettings', 'sockshostname') - socksport = config.get('bitmessagesettings', 'socksport') - socksauthentication = safeConfigGetBoolean('bitmessagesettings', 'socksauthentication') - socksusername = config.get('bitmessagesettings', 'socksusername') - sockspassword = config.get('bitmessagesettings', 'sockspassword') + 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 -----------------------------------' @@ -313,60 +298,60 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings. if uInput == "port": print ' Current port number: ' + port uInput = userInput("Enter the new port number.") - config.set('bitmessagesettings', 'port', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'port', str(uInput)) elif uInput == "startonlogon": print ' Current status: ' + str(startonlogon) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'startonlogon', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'startonlogon', str(uInput)) elif uInput == "minimizetotray": print ' Current status: ' + str(minimizetotray) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'minimizetotray', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(uInput)) elif uInput == "showtraynotifications": print ' Current status: ' + str(showtraynotifications) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'showtraynotifications', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(uInput)) elif uInput == "startintray": print ' Current status: ' + str(startintray) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'startintray', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'startintray', str(uInput)) elif uInput == "defaultnoncetrialsperbyte": print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte uInput = userInput("Enter the new defaultnoncetrialsperbyte.") - config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) elif uInput == "defaultpayloadlengthextrabytes": print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") - config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) elif uInput == "daemon": print ' Current status: ' + str(daemon) uInput = userInput("Enter the new status.").lower() - config.set('bitmessagesettings', 'daemon', str(uInput)) + 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.") - config.set('bitmessagesettings', 'socksproxytype', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(uInput)) elif uInput == "sockshostname": print ' Current socks host name: ' + sockshostname uInput = userInput("Enter the new sockshostname.") - config.set('bitmessagesettings', 'sockshostname', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'sockshostname', str(uInput)) elif uInput == "socksport": print ' Current socks port number: ' + socksport uInput = userInput("Enter the new socksport.") - config.set('bitmessagesettings', 'socksport', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksport', str(uInput)) elif uInput == "socksauthentication": print ' Current status: ' + str(socksauthentication) uInput = userInput("Enter the new status.") - config.set('bitmessagesettings', 'socksauthentication', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(uInput)) elif uInput == "socksusername": print ' Current socks username: ' + socksusername uInput = userInput("Enter the new socksusername.") - config.set('bitmessagesettings', 'socksusername', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'socksusername', str(uInput)) elif uInput == "sockspassword": print ' Current socks password: ' + sockspassword uInput = userInput("Enter the new password.") - config.set('bitmessagesettings', 'sockspassword', str(uInput)) + BMConfigParser().set('bitmessagesettings', 'sockspassword', str(uInput)) else: print "\n Invalid input. Please try again.\n" invalidInput = True @@ -377,7 +362,7 @@ def bmSettings(): #Allows the viewing and modification of keys.dat settings. if uInput != "y": print '\n Changes Made.\n' with open(keysPath, 'wb') as configfile: - config.write(configfile) + BMConfigParser().write(configfile) restartBmNotify() break diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 1d667b2b..165873b5 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -22,7 +22,7 @@ from dialog import Dialog from helper_sql import * import shared -import ConfigParser +from configparser import BMConfigParser from addresses import * from pyelliptic.openssl import OpenSSL import l10n @@ -482,19 +482,19 @@ def handlech(c, stdscr): r, t = d.inputbox("New address label", init=label) if r == d.DIALOG_OK: label = t - shared.config.set(a, "label", label) + BMConfigParser().set(a, "label", label) # Write config shared.writeKeysFile() addresses[addrcur][0] = label elif t == "4": # Enable address a = addresses[addrcur][2] - shared.config.set(a, "enabled", "true") # Set config + BMConfigParser().set(a, "enabled", "true") # Set config # Write config shared.writeKeysFile() # Change color - if shared.safeConfigGetBoolean(a, 'chan'): + if BMConfigParser().safeGetBoolean(a, 'chan'): addresses[addrcur][3] = 9 # orange - elif shared.safeConfigGetBoolean(a, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(a, 'mailinglist'): addresses[addrcur][3] = 5 # magenta else: addresses[addrcur][3] = 0 # black @@ -502,7 +502,7 @@ def handlech(c, stdscr): shared.reloadMyAddressHashes() # Reload address hashes elif t == "5": # Disable address a = addresses[addrcur][2] - shared.config.set(a, "enabled", "false") # Set config + BMConfigParser().set(a, "enabled", "false") # Set config addresses[addrcur][3] = 8 # Set color to gray # Write config shared.writeKeysFile() @@ -511,36 +511,36 @@ def handlech(c, stdscr): 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": - shared.config.remove_section(addresses[addrcur][2]) + BMConfigParser().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 shared.safeConfigGetBoolean(a, "chan"): + if BMConfigParser().safeGetBoolean(a, "chan"): scrollbox(d, unicode("This is a chan address. You cannot use it as a pseudo-mailing list.")) else: - m = shared.safeConfigGetBoolean(a, "mailinglist") + m = BMConfigParser().safeGetBoolean(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: - shared.config.set(a, "mailinglist", "false") + BMConfigParser().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 = shared.config.get(a, "mailinglistname") + mn = BMConfigParser().get(a, "mailinglistname") except ConfigParser.NoOptionError: mn = "" r, t = d.inputbox("Mailing list name", init=mn) if r == d.DIALOG_OK: mn = t - shared.config.set(a, "mailinglist", "true") - shared.config.set(a, "mailinglistname", mn) + BMConfigParser().set(a, "mailinglist", "true") + BMConfigParser().set(a, "mailinglistname", mn) addresses[addrcur][3] = 6 # Set color to magenta # Write config shared.writeKeysFile() @@ -793,7 +793,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", 2, # encodingType - shared.config.getint('bitmessagesettings', 'ttl')) + BMConfigParser().getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(("sendmessage", addr)) else: # Broadcast if recv == "": @@ -819,7 +819,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F 0, # retryNumber "sent", # folder 2, # encodingType - shared.config.getint('bitmessagesettings', 'ttl')) + BMConfigParser().getint('bitmessagesettings', 'ttl')) shared.workerQueue.put(('sendbroadcast', '')) def loadInbox(): @@ -843,7 +843,7 @@ def loadInbox(): if toaddr == BROADCAST_STR: tolabel = BROADCAST_STR else: - tolabel = shared.config.get(toaddr, "label") + tolabel = BMConfigParser().get(toaddr, "label") except: tolabel = "" if tolabel == "": @@ -852,8 +852,8 @@ def loadInbox(): # Set label for from address fromlabel = "" - if shared.config.has_section(fromaddr): - fromlabel = shared.config.get(fromaddr, "label") + if BMConfigParser().has_section(fromaddr): + fromlabel = BMConfigParser().get(fromaddr, "label") if fromlabel == "": # Check Address Book qr = sqlQuery("SELECT label FROM addressbook WHERE address=?", fromaddr) if qr != []: @@ -900,15 +900,15 @@ def loadSent(): for r in qr: tolabel, = r if tolabel == "": - if shared.config.has_section(toaddr): - tolabel = shared.config.get(toaddr, "label") + if BMConfigParser().has_section(toaddr): + tolabel = BMConfigParser().get(toaddr, "label") if tolabel == "": tolabel = toaddr # Set label for from address fromlabel = "" - if shared.config.has_section(fromaddr): - fromlabel = shared.config.get(fromaddr, "label") + if BMConfigParser().has_section(fromaddr): + fromlabel = BMConfigParser().get(fromaddr, "label") if fromlabel == "": fromlabel = fromaddr @@ -969,7 +969,7 @@ def loadSubscriptions(): subscriptions.reverse() def loadBlackWhiteList(): global bwtype - bwtype = shared.config.get("bitmessagesettings", "blackwhitelist") + bwtype = BMConfigParser().get("bitmessagesettings", "blackwhitelist") if bwtype == "black": ret = sqlQuery("SELECT label, address, enabled FROM blacklist") else: @@ -1025,17 +1025,17 @@ def run(stdscr): curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish # Init list of address in 'Your Identities' tab - configSections = shared.config.sections() + configSections = BMConfigParser().sections() for addressInKeysFile in configSections: if addressInKeysFile != "bitmessagesettings": - isEnabled = shared.config.getboolean(addressInKeysFile, "enabled") - addresses.append([shared.config.get(addressInKeysFile, "label"), isEnabled, addressInKeysFile]) + 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 shared.safeConfigGetBoolean(addressInKeysFile, 'chan'): + elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan'): addresses[len(addresses)-1].append(9) # orange - elif shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist'): addresses[len(addresses)-1].append(5) # magenta else: addresses[len(addresses)-1].append(0) # black diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 3b2d1aae..dd71488d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -40,6 +40,7 @@ from class_singleWorker import singleWorker from class_addressGenerator import addressGenerator from class_smtpDeliver import smtpDeliver from class_smtpServer import smtpServer +from configparser import BMConfigParser from debug import logger # Helper Functions @@ -58,7 +59,7 @@ def connectToStream(streamNumber): maximumNumberOfHalfOpenConnections = 64 try: # don't overload Tor - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': maximumNumberOfHalfOpenConnections = 4 except: pass @@ -128,7 +129,7 @@ class singleAPI(threading.Thread, StoppableThread): super(singleAPI, self).stopThread() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: - s.connect((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + s.connect((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( 'bitmessagesettings', 'apiport'))) s.shutdown(socket.SHUT_RDWR) s.close() @@ -136,7 +137,7 @@ class singleAPI(threading.Thread, StoppableThread): pass def run(self): - se = StoppableXMLRPCServer((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( 'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) se.register_introspection_functions() se.serve_forever() @@ -188,12 +189,12 @@ class Main: sqlLookup.start() # SMTP delivery thread - if daemon and shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') != '': + if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': smtpDeliveryThread = smtpDeliver() smtpDeliveryThread.start() # SMTP daemon thread - if daemon and shared.safeConfigGetBoolean("bitmessagesettings", "smtpd"): + if daemon and BMConfigParser().safeGetBoolean("bitmessagesettings", "smtpd"): smtpServerThread = smtpServer() smtpServerThread.start() @@ -210,9 +211,9 @@ class Main: shared.reloadMyAddressHashes() shared.reloadBroadcastSendersForWhichImWatching() - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -232,12 +233,12 @@ class Main: singleListenerThread.daemon = True # close the main program even if there are threads left singleListenerThread.start() - if shared.safeConfigGetBoolean('bitmessagesettings','upnp'): + if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'): import upnp upnpThread = upnp.uPnPThread() upnpThread.start() - if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False: + if daemon == False and BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') == False: if shared.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') @@ -253,7 +254,7 @@ class Main: import bitmessagecurses bitmessagecurses.runwrapper() else: - shared.config.remove_option('bitmessagesettings', 'dontconnect') + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') while True: time.sleep(20) @@ -290,15 +291,15 @@ class Main: #TODO: nice function but no one is using this def getApiAddress(self): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): return None - address = shared.config.get('bitmessagesettings', 'apiinterface') - port = shared.config.getint('bitmessagesettings', 'apiport') + address = BMConfigParser().get('bitmessagesettings', 'apiinterface') + port = BMConfigParser().getint('bitmessagesettings', 'apiport') return {'address':address,'port':port} if __name__ == "__main__": mainprogram = Main() - mainprogram.start(shared.safeConfigGetBoolean('bitmessagesettings', 'daemon')) + mainprogram.start(BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')) # So far, the creation of and management of the Bitmessage protocol and this diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4e3366c7..9869d734 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -29,6 +29,7 @@ except AttributeError: from addresses import * import shared from bitmessageui import * +from configparser import BMConfigParser from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newaddresswizard import * @@ -77,6 +78,7 @@ from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize from proofofwork import getPowType from statusbar import BMStatusBar +from version import softwareVersion def _translate(context, text, disambiguation = None, encoding = None, number = None): if number is None: @@ -490,11 +492,11 @@ class MyForm(settingsmixin.SMainWindow): enabled = {} for toAddress in getSortedAccounts(): - isEnabled = shared.config.getboolean( + isEnabled = BMConfigParser().getboolean( toAddress, 'enabled') - isChan = shared.safeConfigGetBoolean( + isChan = BMConfigParser().safeGetBoolean( toAddress, 'chan') - isMaillinglist = shared.safeConfigGetBoolean( + isMaillinglist = BMConfigParser().safeGetBoolean( toAddress, 'mailinglist') if treeWidget == self.ui.treeWidgetYourIdentities: @@ -603,7 +605,7 @@ class MyForm(settingsmixin.SMainWindow): reply = QtGui.QMessageBox.question( self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: - shared.config.remove_section(addressInKeysFile) + BMConfigParser().remove_section(addressInKeysFile) shared.writeKeysFile() # Configure Bitmessage to start on startup (or remove the @@ -614,7 +616,7 @@ class MyForm(settingsmixin.SMainWindow): 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 shared.config.getboolean('bitmessagesettings', 'startonlogon'): + if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) elif 'darwin' in sys.platform: # startup for mac @@ -783,7 +785,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFromBroadcast() # Put the TTL slider in the correct spot - TTL = shared.config.getint('bitmessagesettings', 'ttl') + TTL = BMConfigParser().getint('bitmessagesettings', 'ttl') if TTL < 3600: # an hour TTL = 3600 elif TTL > 28*24*60*60: # 28 days @@ -799,11 +801,11 @@ class MyForm(settingsmixin.SMainWindow): # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} - 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') + 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') nc = namecoinConnection(options) if nc.test()[0] == 'failed': self.ui.pushButtonFetchNamecoinID.hide() @@ -814,7 +816,7 @@ class MyForm(settingsmixin.SMainWindow): def updateTTL(self, sliderPosition): TTL = int(sliderPosition ** 3.199 + 3600) self.updateHumanFriendlyTTLDescription(TTL) - shared.config.set('bitmessagesettings', 'ttl', str(TTL)) + BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) shared.writeKeysFile() def updateHumanFriendlyTTLDescription(self, TTL): @@ -1161,7 +1163,7 @@ class MyForm(settingsmixin.SMainWindow): # show bitmessage self.actionShow = QtGui.QAction(_translate( "MainWindow", "Show Bitmessage"), m, checkable=True) - self.actionShow.setChecked(not shared.config.getboolean( + self.actionShow.setChecked(not BMConfigParser().getboolean( 'bitmessagesettings', 'startintray')) self.actionShow.triggered.connect(self.appIndicatorShowOrHideWindow) if not sys.platform[0:3] == 'win': @@ -1250,7 +1252,7 @@ class MyForm(settingsmixin.SMainWindow): if toAddress == str_broadcast_subscribers: toLabel = str_broadcast_subscribers else: - toLabel = shared.config.get(toAddress, 'label') + toLabel = BMConfigParser().get(toAddress, 'label') except: toLabel = '' if toLabel == '': @@ -1595,7 +1597,7 @@ class MyForm(settingsmixin.SMainWindow): self.connectDialogInstance = connectDialog(self) if self.connectDialogInstance.exec_(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): - shared.config.remove_option('bitmessagesettings', 'dontconnect') + BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') shared.writeKeysFile() else: self.click_actionSettings() @@ -1619,7 +1621,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.blackwhitelist.init_blacklist_popup_menu(False) if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: - if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: + if BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: QTimer.singleShot(0, self.appIndicatorHide) elif event.oldState() & QtCore.Qt.WindowMinimized: # The window state has just been changed to @@ -1644,7 +1646,7 @@ class MyForm(settingsmixin.SMainWindow): QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # if the connection is lost then show a notification - if self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): + if self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): self.notifierShow('Bitmessage', unicode(_translate( "MainWindow", "Connection lost").toUtf8(),'utf-8'), self.SOUND_DISCONNECTED, None) @@ -1661,7 +1663,7 @@ class MyForm(settingsmixin.SMainWindow): ":/newPrefix/images/yellowicon.png")) shared.statusIconColor = 'yellow' # if a new connection has been established then show a notification - if not self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): + if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): self.notifierShow('Bitmessage', unicode(_translate( "MainWindow", "Connected").toUtf8(),'utf-8'), self.SOUND_CONNECTED, None) @@ -1677,7 +1679,7 @@ class MyForm(settingsmixin.SMainWindow): self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/greenicon.png")) shared.statusIconColor = 'green' - if not self.connected and not shared.config.getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): + if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): self.notifierShow('Bitmessage', unicode(_translate( "MainWindow", "Connected").toUtf8(),'utf-8'), self.SOUND_CONNECTION_GREEN, None) @@ -1856,7 +1858,7 @@ class MyForm(settingsmixin.SMainWindow): addresses = getSortedAccounts() for address in addresses: account = accountClass(address) - if (account.type == AccountMixin.CHAN and shared.safeConfigGetBoolean(address, 'enabled')): + if (account.type == AccountMixin.CHAN and BMConfigParser().safeGetBoolean(address, 'enabled')): newRows[address] = [account.getLabel(), AccountMixin.CHAN] # normal accounts queryreturn = sqlQuery('SELECT * FROM addressbook') @@ -1952,8 +1954,8 @@ class MyForm(settingsmixin.SMainWindow): email = ''.join(random.SystemRandom().choice(string.ascii_lowercase) for _ in range(12)) + "@mailchuck.com" acct = MailchuckAccount(fromAddress) acct.register(email) - shared.config.set(fromAddress, 'label', email) - shared.config.set(fromAddress, 'gateway', 'mailchuck') + BMConfigParser().set(fromAddress, 'label', email) + BMConfigParser().set(fromAddress, 'gateway', 'mailchuck') shared.writeKeysFile() self.statusBar().showMessage(_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), 10000) @@ -2027,7 +2029,7 @@ class MyForm(settingsmixin.SMainWindow): 0, # retryNumber 'sent', # folder encoding, # encodingtype - shared.config.getint('bitmessagesettings', 'ttl') + BMConfigParser().getint('bitmessagesettings', 'ttl') ) toLabel = '' @@ -2080,7 +2082,7 @@ class MyForm(settingsmixin.SMainWindow): 0, # retryNumber 'sent', # folder encoding, # encoding type - shared.config.getint('bitmessagesettings', 'ttl') + BMConfigParser().getint('bitmessagesettings', 'ttl') ) sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) @@ -2125,7 +2127,7 @@ class MyForm(settingsmixin.SMainWindow): def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. - if shared.safeConfigGetBoolean(str(address), 'mailinglist'): + if BMConfigParser().safeGetBoolean(str(address), 'mailinglist'): self.ui.tabWidgetSend.setCurrentIndex(1) else: self.ui.tabWidgetSend.setCurrentIndex(0) @@ -2133,11 +2135,11 @@ class MyForm(settingsmixin.SMainWindow): def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() for addressInKeysFile in getSortedAccounts(): - isEnabled = shared.config.getboolean( + 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 = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + isMaillinglist = BMConfigParser().safeGetBoolean(addressInKeysFile, 'mailinglist') if isEnabled and not isMaillinglist: - label = unicode(shared.config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() + label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() if label == "": label = addressInKeysFile self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) @@ -2154,11 +2156,11 @@ class MyForm(settingsmixin.SMainWindow): def rerenderComboBoxSendFromBroadcast(self): self.ui.comboBoxSendFromBroadcast.clear() for addressInKeysFile in getSortedAccounts(): - isEnabled = shared.config.getboolean( + 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 = shared.safeConfigGetBoolean(addressInKeysFile, 'chan') + isChan = BMConfigParser().safeGetBoolean(addressInKeysFile, 'chan') if isEnabled and not isChan: - label = unicode(shared.config.get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() + label = unicode(BMConfigParser().get(addressInKeysFile, 'label'), 'utf-8', 'ignore').strip() if label == "": label = addressInKeysFile self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), label, addressInKeysFile) @@ -2221,7 +2223,7 @@ class MyForm(settingsmixin.SMainWindow): else: acct = ret self.propagateUnreadCount(acct.address) - if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): + if BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications'): self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) 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 @@ -2235,8 +2237,8 @@ class MyForm(settingsmixin.SMainWindow): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) # register resets address variables acct.register(email) - shared.config.set(acct.fromAddress, 'label', email) - shared.config.set(acct.fromAddress, 'gateway', 'mailchuck') + BMConfigParser().set(acct.fromAddress, 'label', email) + BMConfigParser().set(acct.fromAddress, 'gateway', 'mailchuck') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) @@ -2323,113 +2325,113 @@ class MyForm(settingsmixin.SMainWindow): def click_actionSettings(self): self.settingsDialogInstance = settingsDialog(self) if self.settingsDialogInstance.exec_(): - shared.config.set('bitmessagesettings', 'startonlogon', str( + BMConfigParser().set('bitmessagesettings', 'startonlogon', str( self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) - shared.config.set('bitmessagesettings', 'minimizetotray', str( + BMConfigParser().set('bitmessagesettings', 'minimizetotray', str( self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) - shared.config.set('bitmessagesettings', 'trayonclose', str( + BMConfigParser().set('bitmessagesettings', 'trayonclose', str( self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) - shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', str( + BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', str( self.settingsDialogInstance.ui.checkBoxHideTrayConnectionNotifications.isChecked())) - shared.config.set('bitmessagesettings', 'showtraynotifications', str( + BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str( self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) - shared.config.set('bitmessagesettings', 'startintray', str( + BMConfigParser().set('bitmessagesettings', 'startintray', str( self.settingsDialogInstance.ui.checkBoxStartInTray.isChecked())) - shared.config.set('bitmessagesettings', 'willinglysendtomobile', str( + BMConfigParser().set('bitmessagesettings', 'willinglysendtomobile', str( self.settingsDialogInstance.ui.checkBoxWillinglySendToMobile.isChecked())) - shared.config.set('bitmessagesettings', 'useidenticons', str( + BMConfigParser().set('bitmessagesettings', 'useidenticons', str( self.settingsDialogInstance.ui.checkBoxUseIdenticons.isChecked())) - shared.config.set('bitmessagesettings', 'replybelow', str( + BMConfigParser().set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) - shared.config.set('bitmessagesettings', 'userlocale', lang) + BMConfigParser().set('bitmessagesettings', 'userlocale', lang) change_translation(l10n.getTranslationLanguage()) - if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( "MainWindow", "You must restart Bitmessage for the port number change to take effect.")) - shared.config.set('bitmessagesettings', 'port', str( + BMConfigParser().set('bitmessagesettings', 'port', str( self.settingsDialogInstance.ui.lineEditTCPPort.text())) - if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): - shared.config.set('bitmessagesettings', 'upnp', str(self.settingsDialogInstance.ui.checkBoxUPnP.isChecked())) + 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 shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': if shared.statusIconColor != 'red': 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 shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] != 'SOCKS': self.statusBar().clearMessage() if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': - shared.config.set('bitmessagesettings', 'socksproxytype', str( + BMConfigParser().set('bitmessagesettings', 'socksproxytype', str( self.settingsDialogInstance.ui.comboBoxProxyType.currentText())) else: - shared.config.set('bitmessagesettings', 'socksproxytype', 'none') - shared.config.set('bitmessagesettings', 'socksauthentication', str( + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') + BMConfigParser().set('bitmessagesettings', 'socksauthentication', str( self.settingsDialogInstance.ui.checkBoxAuthentication.isChecked())) - shared.config.set('bitmessagesettings', 'sockshostname', str( + BMConfigParser().set('bitmessagesettings', 'sockshostname', str( self.settingsDialogInstance.ui.lineEditSocksHostname.text())) - shared.config.set('bitmessagesettings', 'socksport', str( + BMConfigParser().set('bitmessagesettings', 'socksport', str( self.settingsDialogInstance.ui.lineEditSocksPort.text())) - shared.config.set('bitmessagesettings', 'socksusername', str( + BMConfigParser().set('bitmessagesettings', 'socksusername', str( self.settingsDialogInstance.ui.lineEditSocksUsername.text())) - shared.config.set('bitmessagesettings', 'sockspassword', str( + BMConfigParser().set('bitmessagesettings', 'sockspassword', str( self.settingsDialogInstance.ui.lineEditSocksPassword.text())) - shared.config.set('bitmessagesettings', 'sockslisten', str( + BMConfigParser().set('bitmessagesettings', 'sockslisten', str( self.settingsDialogInstance.ui.checkBoxSocksListen.isChecked())) try: # Rounding to integers just for aesthetics - shared.config.set('bitmessagesettings', 'maxdownloadrate', str( + BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text())))) - shared.config.set('bitmessagesettings', 'maxuploadrate', str( + BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) except: QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) - shared.config.set('bitmessagesettings', 'namecoinrpctype', + BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) - shared.config.set('bitmessagesettings', 'namecoinrpchost', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str( self.settingsDialogInstance.ui.lineEditNamecoinHost.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcport', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcport', str( self.settingsDialogInstance.ui.lineEditNamecoinPort.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcuser', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcuser', str( self.settingsDialogInstance.ui.lineEditNamecoinUser.text())) - shared.config.set('bitmessagesettings', 'namecoinrpcpassword', str( + BMConfigParser().set('bitmessagesettings', 'namecoinrpcpassword', str( self.settingsDialogInstance.ui.lineEditNamecoinPassword.text())) # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: - shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: - shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != shared.safeConfigGet("bitmessagesettings", "opencl"): - shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) + if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): + BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) acceptableDifficultyChanged = False if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: - if shared.config.get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( + if BMConfigParser().get('bitmessagesettings','maxacceptablenoncetrialsperbyte') != str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True - shared.config.set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( + BMConfigParser().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 shared.config.get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( + if BMConfigParser().get('bitmessagesettings','maxacceptablepayloadlengthextrabytes') != str(int(float( self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True - shared.config.set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( + BMConfigParser().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. @@ -2442,8 +2444,8 @@ class MyForm(settingsmixin.SMainWindow): #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 - shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '') - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '') shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') try: float(self.settingsDialogInstance.ui.lineEditDays.text()) @@ -2465,13 +2467,13 @@ class MyForm(settingsmixin.SMainWindow): 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. 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.")) - shared.config.set('bitmessagesettings', 'stopresendingafterxdays', '0') - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', '0') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', '0') + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', '0') shared.maximumLengthOfTimeToBotherResendingMessages = 0 else: - shared.config.set('bitmessagesettings', 'stopresendingafterxdays', str(float( + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxdays', str(float( self.settingsDialogInstance.ui.lineEditDays.text()))) - shared.config.set('bitmessagesettings', 'stopresendingafterxmonths', str(float( + BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float( self.settingsDialogInstance.ui.lineEditMonths.text()))) shared.writeKeysFile() @@ -2480,7 +2482,7 @@ class MyForm(settingsmixin.SMainWindow): # Auto-startup for Windows RUN_PATH = "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run" self.settings = QSettings(RUN_PATH, QSettings.NativeFormat) - if shared.config.getboolean('bitmessagesettings', 'startonlogon'): + if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) else: self.settings.remove("PyBitmessage") @@ -2495,7 +2497,7 @@ class MyForm(settingsmixin.SMainWindow): # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() output = open(shared.lookupExeFolder() + 'knownnodes.dat', 'wb') @@ -2540,21 +2542,21 @@ class MyForm(settingsmixin.SMainWindow): # For Modal dialogs if self.dialog.exec_(): addressAtCurrentRow = self.getCurrentAccount() - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): + if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): return if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): - shared.config.set(str( + BMConfigParser().set(str( addressAtCurrentRow), 'mailinglist', 'false') # Set the color to either black or grey - if shared.config.getboolean(addressAtCurrentRow, 'enabled'): + if BMConfigParser().getboolean(addressAtCurrentRow, 'enabled'): self.setCurrentItemColor(QApplication.palette() .text().color()) else: self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) else: - shared.config.set(str( + BMConfigParser().set(str( addressAtCurrentRow), 'mailinglist', 'true') - shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( + BMConfigParser().set(str(addressAtCurrentRow), 'mailinglistname', str( self.dialog.ui.lineEditMailingListName.text().toUtf8())) self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta self.rerenderComboBoxSendFrom() @@ -2573,7 +2575,7 @@ class MyForm(settingsmixin.SMainWindow): return if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): acct.unregister() - shared.config.remove_option(addressAtCurrentRow, 'gateway') + BMConfigParser().remove_option(addressAtCurrentRow, 'gateway') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway unregistration request"), 10000) @@ -2599,8 +2601,8 @@ class MyForm(settingsmixin.SMainWindow): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) acct.register(email) - shared.config.set(addressAtCurrentRow, 'label', email) - shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') + BMConfigParser().set(addressAtCurrentRow, 'label', email) + BMConfigParser().set(addressAtCurrentRow, 'gateway', 'mailchuck') shared.writeKeysFile() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) @@ -2818,7 +2820,7 @@ class MyForm(settingsmixin.SMainWindow): trayonclose = False try: - trayonclose = shared.config.getboolean( + trayonclose = BMConfigParser().getboolean( 'bitmessagesettings', 'trayonclose') except Exception: pass @@ -2893,7 +2895,7 @@ class MyForm(settingsmixin.SMainWindow): # Format predefined text on message reply. def quoted_text(self, message): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow'): return '\n\n------------------------------------------------------\n' + message quoteWrapper = textwrap.TextWrapper(replace_whitespace = False, @@ -2964,10 +2966,10 @@ class MyForm(settingsmixin.SMainWindow): if toAddressAtCurrentInboxRow == str_broadcast_subscribers: self.ui.tabWidgetSend.setCurrentIndex(0) # toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow - elif not shared.config.has_section(toAddressAtCurrentInboxRow): + elif not BMConfigParser().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), QMessageBox.Ok) - elif not shared.config.getboolean(toAddressAtCurrentInboxRow, 'enabled'): + elif not BMConfigParser().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."), QMessageBox.Ok) else: @@ -3041,7 +3043,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + shared.config.get(recipientAddress, "label") + label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + BMConfigParser().get(recipientAddress, "label") sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', label, addressAtCurrentInboxRow, True) @@ -3533,7 +3535,7 @@ class MyForm(settingsmixin.SMainWindow): 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?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: - shared.config.remove_section(str(account.address)) + BMConfigParser().remove_section(str(account.address)) else: return else: @@ -3553,7 +3555,7 @@ class MyForm(settingsmixin.SMainWindow): account.setEnabled(True) def enableIdentity(self, address): - shared.config.set(address, 'enabled', 'true') + BMConfigParser().set(address, 'enabled', 'true') shared.writeKeysFile() shared.reloadMyAddressHashes() self.rerenderAddressBook() @@ -3565,7 +3567,7 @@ class MyForm(settingsmixin.SMainWindow): account.setEnabled(False) def disableIdentity(self, address): - shared.config.set(str(address), 'enabled', 'false') + BMConfigParser().set(str(address), 'enabled', 'false') shared.writeKeysFile() shared.reloadMyAddressHashes() self.rerenderAddressBook() @@ -3981,7 +3983,7 @@ class aboutDialog(QtGui.QDialog): self.ui = Ui_aboutDialog() self.ui.setupUi(self) self.parent = parent - self.ui.labelVersion.setText('version ' + shared.softwareVersion) + self.ui.labelVersion.setText('version ' + softwareVersion) class regenerateAddressesDialog(QtGui.QDialog): @@ -4001,23 +4003,23 @@ class settingsDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent self.ui.checkBoxStartOnLogon.setChecked( - shared.config.getboolean('bitmessagesettings', 'startonlogon')) + BMConfigParser().getboolean('bitmessagesettings', 'startonlogon')) self.ui.checkBoxMinimizeToTray.setChecked( - shared.config.getboolean('bitmessagesettings', 'minimizetotray')) + BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray')) self.ui.checkBoxTrayOnClose.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'trayonclose')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'trayonclose')) self.ui.checkBoxHideTrayConnectionNotifications.setChecked( - shared.config.getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) + BMConfigParser().getboolean("bitmessagesettings", "hidetrayconnectionnotifications")) self.ui.checkBoxShowTrayNotifications.setChecked( - shared.config.getboolean('bitmessagesettings', 'showtraynotifications')) + BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications')) self.ui.checkBoxStartInTray.setChecked( - shared.config.getboolean('bitmessagesettings', 'startintray')) + BMConfigParser().getboolean('bitmessagesettings', 'startintray')) self.ui.checkBoxWillinglySendToMobile.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'willinglysendtomobile')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'willinglysendtomobile')) self.ui.checkBoxUseIdenticons.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons')) self.ui.checkBoxReplyBelow.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow')) + BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) if shared.appdata == shared.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) @@ -4045,14 +4047,14 @@ class settingsDialog(QtGui.QDialog): "MainWindow", "Start-on-login not yet supported on your OS.")) # On the Network settings tab: self.ui.lineEditTCPPort.setText(str( - shared.config.get('bitmessagesettings', 'port'))) + BMConfigParser().get('bitmessagesettings', 'port'))) self.ui.checkBoxUPnP.setChecked( - shared.safeConfigGetBoolean('bitmessagesettings', 'upnp')) - self.ui.checkBoxAuthentication.setChecked(shared.config.getboolean( + BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp')) + self.ui.checkBoxAuthentication.setChecked(BMConfigParser().getboolean( 'bitmessagesettings', 'socksauthentication')) - self.ui.checkBoxSocksListen.setChecked(shared.config.getboolean( + self.ui.checkBoxSocksListen.setChecked(BMConfigParser().getboolean( 'bitmessagesettings', 'sockslisten')) - if str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'none': + if str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'none': self.ui.comboBoxProxyType.setCurrentIndex(0) self.ui.lineEditSocksHostname.setEnabled(False) self.ui.lineEditSocksPort.setEnabled(False) @@ -4060,38 +4062,38 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditSocksPassword.setEnabled(False) self.ui.checkBoxAuthentication.setEnabled(False) self.ui.checkBoxSocksListen.setEnabled(False) - elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': + elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': self.ui.comboBoxProxyType.setCurrentIndex(1) self.ui.lineEditTCPPort.setEnabled(False) - elif str(shared.config.get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': + elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': self.ui.comboBoxProxyType.setCurrentIndex(2) self.ui.lineEditTCPPort.setEnabled(False) self.ui.lineEditSocksHostname.setText(str( - shared.config.get('bitmessagesettings', 'sockshostname'))) + BMConfigParser().get('bitmessagesettings', 'sockshostname'))) self.ui.lineEditSocksPort.setText(str( - shared.config.get('bitmessagesettings', 'socksport'))) + BMConfigParser().get('bitmessagesettings', 'socksport'))) self.ui.lineEditSocksUsername.setText(str( - shared.config.get('bitmessagesettings', 'socksusername'))) + BMConfigParser().get('bitmessagesettings', 'socksusername'))) self.ui.lineEditSocksPassword.setText(str( - shared.config.get('bitmessagesettings', 'sockspassword'))) + BMConfigParser().get('bitmessagesettings', 'sockspassword'))) QtCore.QObject.connect(self.ui.comboBoxProxyType, QtCore.SIGNAL( "currentIndexChanged(int)"), self.comboBoxProxyTypeChanged) self.ui.lineEditMaxDownloadRate.setText(str( - shared.config.get('bitmessagesettings', 'maxdownloadrate'))) + BMConfigParser().get('bitmessagesettings', 'maxdownloadrate'))) self.ui.lineEditMaxUploadRate.setText(str( - shared.config.get('bitmessagesettings', 'maxuploadrate'))) + BMConfigParser().get('bitmessagesettings', 'maxuploadrate'))) # Demanded difficulty tab - self.ui.lineEditTotalDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditSmallMessageDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab - self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) - self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( + self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) # OpenCL @@ -4104,20 +4106,20 @@ class settingsDialog(QtGui.QDialog): 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) == shared.safeConfigGet('bitmessagesettings', 'opencl'): + if self.ui.comboBoxOpenCL.itemText(i) == BMConfigParser().safeGet('bitmessagesettings', 'opencl'): self.ui.comboBoxOpenCL.setCurrentIndex(i) break # Namecoin integration tab - nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') + nmctype = BMConfigParser().get('bitmessagesettings', 'namecoinrpctype') self.ui.lineEditNamecoinHost.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpchost'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpchost'))) self.ui.lineEditNamecoinPort.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcport'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcport'))) self.ui.lineEditNamecoinUser.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcuser'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcuser'))) self.ui.lineEditNamecoinPassword.setText(str( - shared.config.get('bitmessagesettings', 'namecoinrpcpassword'))) + BMConfigParser().get('bitmessagesettings', 'namecoinrpcpassword'))) if nmctype == "namecoind": self.ui.radioButtonNamecoinNamecoind.setChecked(True) @@ -4139,14 +4141,14 @@ class settingsDialog(QtGui.QDialog): #Message Resend tab self.ui.lineEditDays.setText(str( - shared.config.get('bitmessagesettings', 'stopresendingafterxdays'))) + BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays'))) self.ui.lineEditMonths.setText(str( - shared.config.get('bitmessagesettings', 'stopresendingafterxmonths'))) + BMConfigParser().get('bitmessagesettings', 'stopresendingafterxmonths'))) #'System' tab removed for now. """try: - maxCores = shared.config.getint('bitmessagesettings', 'maxcores') + maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if maxCores <= 1: @@ -4235,13 +4237,13 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): self.ui.setupUi(self) self.parent = parent addressAtCurrentRow = parent.getCurrentAccount() - if not shared.safeConfigGetBoolean(addressAtCurrentRow, 'chan'): - if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'): + if not BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): + if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'mailinglist'): self.ui.radioButtonBehaviorMailingList.click() else: self.ui.radioButtonBehaveNormalAddress.click() try: - mailingListName = shared.config.get( + mailingListName = BMConfigParser().get( addressAtCurrentRow, 'mailinglistname') except: mailingListName = '' @@ -4272,7 +4274,7 @@ class EmailGatewayDialog(QtGui.QDialog): self.ui.radioButtonStatus.setEnabled(False) self.ui.radioButtonSettings.setEnabled(False) self.ui.radioButtonUnregister.setEnabled(False) - label = shared.config.get(addressAtCurrentRow, 'label') + label = BMConfigParser().get(addressAtCurrentRow, 'label') if label.find("@mailchuck.com") > -1: self.ui.lineEditEmail.setText(label) @@ -4377,7 +4379,7 @@ class iconGlossaryDialog(QtGui.QDialog): 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')))) + "MainWindow", "You are using TCP port %1. (This can be changed in the settings).").arg(str(BMConfigParser().getint('bitmessagesettings', 'port')))) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) @@ -4462,17 +4464,17 @@ def run(): myapp.appIndicatorInit(app) myapp.ubuntuMessagingMenuInit() myapp.notifierInit() - if shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): myapp.showConnectDialog() # ask the user if we may connect # try: -# if shared.config.get('bitmessagesettings', 'mailchuck') < 1: -# myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) +# 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 shared.config.getboolean('bitmessagesettings', 'startintray'): + if not BMConfigParser().getboolean('bitmessagesettings', 'startintray'): myapp.show() sys.exit(app.exec_()) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index dc6bf6b8..6e830b38 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -6,15 +6,16 @@ import sys import inspect from helper_sql import * from addresses import decodeAddress +from configparser import BMConfigParser from foldertree import AccountMixin from pyelliptic.openssl import OpenSSL from utils import str_broadcast_subscribers import time def getSortedAccounts(): - configSections = filter(lambda x: x != 'bitmessagesettings', shared.config.sections()) + configSections = filter(lambda x: x != 'bitmessagesettings', BMConfigParser().sections()) configSections.sort(cmp = - lambda x,y: cmp(unicode(shared.config.get(x, 'label'), 'utf-8').lower(), unicode(shared.config.get(y, 'label'), 'utf-8').lower()) + lambda x,y: cmp(unicode(BMConfigParser().get(x, 'label'), 'utf-8').lower(), unicode(BMConfigParser().get(y, 'label'), 'utf-8').lower()) ) return configSections @@ -44,7 +45,7 @@ def getSortedSubscriptions(count = False): return ret def accountClass(address): - if not shared.config.has_section(address): + if not BMConfigParser().has_section(address): # FIXME: This BROADCAST section makes no sense if address == str_broadcast_subscribers: subscription = BroadcastAccount(address) @@ -56,7 +57,7 @@ def accountClass(address): return None return subscription try: - gateway = shared.config.get(address, "gateway") + 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: @@ -75,9 +76,9 @@ class AccountColor(AccountMixin): if type is None: if address is None: self.type = AccountMixin.ALL - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = AccountMixin.MAILINGLIST - elif shared.safeConfigGetBoolean(self.address, 'chan'): + elif BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN elif sqlQuery( '''select label from subscriptions where address=?''', self.address): @@ -92,10 +93,10 @@ class BMAccount(object): def __init__(self, address = None): self.address = address self.type = AccountMixin.NORMAL - if shared.config.has_section(address): - if shared.safeConfigGetBoolean(self.address, 'chan'): + if BMConfigParser().has_section(address): + if BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = AccountMixin.MAILINGLIST elif self.address == str_broadcast_subscribers: self.type = AccountMixin.BROADCAST @@ -109,8 +110,8 @@ class BMAccount(object): if address is None: address = self.address label = address - if shared.config.has_section(address): - label = shared.config.get(address, 'label') + if BMConfigParser().has_section(address): + label = BMConfigParser().get(address, 'label') queryreturn = sqlQuery( '''select label from addressbook where address=?''', address) if queryreturn != []: @@ -168,7 +169,7 @@ class GatewayAccount(BMAccount): 0, # retryNumber 'sent', # folder 2, # encodingtype - min(shared.config.getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days + min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days ) shared.workerQueue.put(('sendmessage', self.toAddress)) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index b1587335..e480258c 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +from configparser import BMConfigParser from foldertree import AddressBookCompleter from messageview import MessageView from messagecompose import MessageCompose @@ -556,7 +557,7 @@ class Ui_MainWindow(object): self.blackwhitelist = Blacklist() self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "") # Initialize the Blacklist or Whitelist - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': self.blackwhitelist.radioButtonWhitelist.click() self.blackwhitelist.rerenderBlackWhiteList() @@ -680,7 +681,7 @@ class Ui_MainWindow(object): self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) hours = 48 try: - hours = int(shared.config.getint('bitmessagesettings', 'ttl')/60/60) + hours = int(BMConfigParser().getint('bitmessagesettings', 'ttl')/60/60) except: pass self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "%n hour(s)", None, QtCore.QCoreApplication.CodecForTr, hours)) diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 1e4be35a..6fcb8f11 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -5,6 +5,7 @@ import l10n from uisignaler import UISignaler import widgets from addresses import addBMIfNotPresent +from configparser import BMConfigParser from dialogs import AddAddressDialog from helper_sql import sqlExecute, sqlQuery from retranslateui import RetranslateMixin @@ -39,16 +40,16 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) def click_radioButtonBlacklist(self): - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': - shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') shared.writeKeysFile() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) self.rerenderBlackWhiteList() def click_radioButtonWhitelist(self): - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': - shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'white') shared.writeKeysFile() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) @@ -64,7 +65,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): # 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': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''select * from blacklist where address=?''' else: sql = '''select * from whitelist where address=?''' @@ -82,7 +83,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): self.tableWidgetBlacklist.setItem(0, 1, newItem) self.tableWidgetBlacklist.setSortingEnabled(True) t = (str(self.NewBlacklistDialogInstance.ui.newAddressLabel.text().toUtf8()), address, True) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sql = '''INSERT INTO blacklist VALUES (?,?,?)''' else: sql = '''INSERT INTO whitelist VALUES (?,?,?)''' @@ -147,12 +148,12 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): def rerenderBlackWhiteList(self): tabs = self.parent().parent() - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + 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 = shared.config.get('bitmessagesettings', 'blackwhitelist') + listType = BMConfigParser().get('bitmessagesettings', 'blackwhitelist') if listType == 'black': queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') else: @@ -184,7 +185,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).text().toUtf8() addressAtCurrentRow = self.tableWidgetBlacklist.item( currentRow, 1).text() - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''DELETE FROM blacklist WHERE label=? AND address=?''', str(labelAtCurrentRow), str(addressAtCurrentRow)) @@ -213,7 +214,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).setTextColor(QtGui.QApplication.palette().text().color()) self.tableWidgetBlacklist.item( currentRow, 1).setTextColor(QtGui.QApplication.palette().text().color()) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''UPDATE blacklist SET enabled=1 WHERE address=?''', str(addressAtCurrentRow)) @@ -230,7 +231,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): currentRow, 0).setTextColor(QtGui.QColor(128, 128, 128)) self.tableWidgetBlacklist.item( currentRow, 1).setTextColor(QtGui.QColor(128, 128, 128)) - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': sqlExecute( '''UPDATE blacklist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) else: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 1204b7ca..8b0e519b 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,6 +1,7 @@ from PyQt4 import QtCore, QtGui from string import find, rfind, rstrip, lstrip +from configparser import BMConfigParser from helper_sql import * from utils import * import shared @@ -69,9 +70,9 @@ class AccountMixin (object): if self.address is None: self.type = self.ALL self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable) - elif shared.safeConfigGetBoolean(self.address, 'chan'): + elif BMConfigParser().safeGetBoolean(self.address, 'chan'): self.type = self.CHAN - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + elif BMConfigParser().safeGetBoolean(self.address, 'mailinglist'): self.type = self.MAILINGLIST elif sqlQuery( '''select label from subscriptions where address=?''', self.address): @@ -84,7 +85,7 @@ class AccountMixin (object): retval = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: - retval = unicode(shared.config.get(self.address, 'label'), 'utf-8') + retval = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8') except Exception as e: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) @@ -161,7 +162,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): super(QtGui.QTreeWidgetItem, self).__init__() parent.insertTopLevelItem(pos, self) # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) self.setAddress(address) self.setEnabled(enabled) self.setUnreadCount(unreadCount) @@ -172,7 +173,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): return unicode(QtGui.QApplication.translate("MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') else: try: - return unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') + return unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: return unicode(self.address, 'utf-8') @@ -211,9 +212,9 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def setData(self, column, role, value): if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: if isinstance(value, QtCore.QVariant): - shared.config.set(str(self.address), 'label', str(value.toString().toUtf8())) + BMConfigParser().set(str(self.address), 'label', str(value.toString().toUtf8())) else: - shared.config.set(str(self.address), 'label', str(value)) + BMConfigParser().set(str(self.address), 'label', str(value)) shared.writeKeysFile() return super(Ui_AddressWidget, self).setData(column, role, value) @@ -250,7 +251,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): super(QtGui.QTreeWidgetItem, self).__init__() parent.insertTopLevelItem(pos, self) # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) self.setAddress(address) self.setEnabled(enabled) self.setType() @@ -287,7 +288,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi super(QtGui.QTableWidgetItem, self).__init__() #parent.insertTopLevelItem(pos, self) # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) self.isEnabled = True self.setAddress(address) self.setLabel(label) @@ -302,7 +303,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi queryreturn = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: - newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') + newLabel = unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') except: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) @@ -330,7 +331,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi elif role == QtCore.Qt.ToolTipRole: return self.label + " (" + self.address + ")" elif role == QtCore.Qt.DecorationRole: - if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): if self.address is None: return avatarize(self.label) else: @@ -362,7 +363,7 @@ class MessageList_SubjectWidget(QtGui.QTableWidgetItem, SettingsMixin): super(QtGui.QTableWidgetItem, self).__init__() #parent.insertTopLevelItem(pos, self) # only set default when creating - #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + #super(QtGui.QTreeWidgetItem, self).setExpanded(BMConfigParser().getboolean(self.address, 'enabled')) self.setSubject(subject) self.setLabel(label) self.setUnread(unread) @@ -418,7 +419,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): elif role == QtCore.Qt.ToolTipRole: return self.label + " (" + self.address + ")" elif role == QtCore.Qt.DecorationRole: - if shared.safeConfigGetBoolean('bitmessagesettings', 'useidenticons'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'useidenticons'): if self.address is None: return avatarize(self.label) else: @@ -440,8 +441,8 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): self.label = str(value) if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): try: - a = shared.config.get(self.address, 'label') - shared.config.set(self.address, 'label', self.label) + a = BMConfigParser().get(self.address, 'label') + BMConfigParser().set(self.address, 'label', self.label) except: sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address) elif self.type == AccountMixin.SUBSCRIPTION: diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 2a8cb865..4ece7d83 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -2,7 +2,8 @@ import glob import os from PyQt4 import QtCore, QtGui -from shared import codePath, config +from configparser import BMConfigParser +from shared import codePath class LanguageBox(QtGui.QComboBox): languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} @@ -16,7 +17,7 @@ class LanguageBox(QtGui.QComboBox): localesPath = os.path.join (codePath(), 'translations') configuredLocale = "system" try: - configuredLocale = config.get('bitmessagesettings', 'userlocale', "system") + configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system") except: pass self.addItem(QtGui.QApplication.translate("settingsDialog", "System Settings", "system"), "system") diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 0f52ec04..92658a17 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -5,6 +5,7 @@ import sys import time import account +from configparser import BMConfigParser from debug import logger from foldertree import AccountMixin from helper_sql import * @@ -13,6 +14,7 @@ from openclpow import openclAvailable, openclEnabled from proofofwork import bmpow from pyelliptic.openssl import OpenSSL import shared +from version import softwareVersion # this is BM support address going to Peter Surda SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' @@ -55,7 +57,7 @@ def checkAddressBook(myapp): def checkHasNormalAddress(): for address in account.getSortedAccounts(): acct = account.accountClass(address) - if acct.type == AccountMixin.NORMAL and shared.safeConfigGetBoolean(address, 'enabled'): + if acct.type == AccountMixin.NORMAL and BMConfigParser().safeGetBoolean(address, 'enabled'): return address return False @@ -80,7 +82,7 @@ def createSupportMessage(myapp): myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) - version = shared.softwareVersion + version = softwareVersion os = sys.platform if os == "win32": windowsversion = sys.getwindowsversion() @@ -107,15 +109,15 @@ def createSupportMessage(myapp): portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" cpow = "True" if bmpow else "False" #cpow = QtGui.QApplication.translate("Support", cpow) - openclpow = str(shared.safeConfigGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" + openclpow = str(BMConfigParser().safeGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" #openclpow = QtGui.QApplication.translate("Support", openclpow) locale = getTranslationLanguage() try: - socks = shared.config.get('bitmessagesettings', 'socksproxytype') + socks = BMConfigParser().get('bitmessagesettings', 'socksproxytype') except: socks = "N/A" try: - upnp = shared.config.get('bitmessagesettings', 'upnp') + upnp = BMConfigParser().get('bitmessagesettings', 'upnp') except: upnp = "N/A" connectedhosts = len(shared.connectedHostsList) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 6f592a63..7361f37d 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -3,6 +3,7 @@ import hashlib import os import shared from addresses import addBMIfNotPresent +from configparser import BMConfigParser str_broadcast_subscribers = '[Broadcast subscribers]' str_chan = '[chan]' @@ -15,7 +16,7 @@ def identiconize(address): # 3fd4bf901b9d4ea1394f0fb358725b28 try: - identicon_lib = shared.config.get('bitmessagesettings', 'identiconlib') + identicon_lib = BMConfigParser().get('bitmessagesettings', 'identiconlib') except: # default to qidenticon_two_x identicon_lib = 'qidenticon_two_x' @@ -23,9 +24,9 @@ def identiconize(address): # 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') + identiconsuffix = BMConfigParser().get('bitmessagesettings', 'identiconsuffix') - if not shared.config.getboolean('bitmessagesettings', 'useidenticons'): + if not BMConfigParser().getboolean('bitmessagesettings', 'useidenticons'): idcon = QtGui.QIcon() return idcon diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 8a5945fd..c215fa3c 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -7,6 +7,7 @@ import ctypes import hashlib import highlevelcrypto from addresses import * +from configparser import BMConfigParser from debug import logger from helper_threading import * from pyelliptic import arithmetic @@ -48,7 +49,7 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 7: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: @@ -58,7 +59,7 @@ class addressGenerator(threading.Thread, StoppableThread): elif len(queueValue) == 9: command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes = queueValue try: - numberOfNullBytesDemandedOnFrontOfRipeHash = shared.config.getint( + numberOfNullBytesDemandedOnFrontOfRipeHash = BMConfigParser().getint( 'bitmessagesettings', 'numberofnullbytesonaddress') except: if eighteenByteRipe: @@ -74,12 +75,12 @@ 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 = shared.config.getint( + nonceTrialsPerByte = BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: - payloadLengthExtraBytes = shared.config.getint( + payloadLengthExtraBytes = BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes @@ -128,17 +129,17 @@ class addressGenerator(threading.Thread, StoppableThread): privEncryptionKeyWIF = arithmetic.changebase( privEncryptionKey + checksum, 256, 58) - 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( + BMConfigParser().add_section(address) + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set(address, 'decoy', 'false') + BMConfigParser().set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - shared.config.set(address, 'payloadlengthextrabytes', str( + BMConfigParser().set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - shared.config.set( + BMConfigParser().set( address, 'privSigningKey', privSigningKeyWIF) - shared.config.set( + BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) shared.writeKeysFile() @@ -233,7 +234,7 @@ class addressGenerator(threading.Thread, StoppableThread): try: - shared.config.add_section(address) + BMConfigParser().add_section(address) addressAlreadyExists = False except: addressAlreadyExists = True @@ -244,18 +245,18 @@ class addressGenerator(threading.Thread, StoppableThread): 'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) else: logger.debug('label: %s' % label) - shared.config.set(address, 'label', label) - shared.config.set(address, 'enabled', 'true') - shared.config.set(address, 'decoy', 'false') + BMConfigParser().set(address, 'label', label) + BMConfigParser().set(address, 'enabled', 'true') + BMConfigParser().set(address, 'decoy', 'false') if command == 'joinChan' or command == 'createChan': - shared.config.set(address, 'chan', 'true') - shared.config.set(address, 'noncetrialsperbyte', str( + BMConfigParser().set(address, 'chan', 'true') + BMConfigParser().set(address, 'noncetrialsperbyte', str( nonceTrialsPerByte)) - shared.config.set(address, 'payloadlengthextrabytes', str( + BMConfigParser().set(address, 'payloadlengthextrabytes', str( payloadLengthExtraBytes)) - shared.config.set( + BMConfigParser().set( address, 'privSigningKey', privSigningKeyWIF) - shared.config.set( + BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) shared.writeKeysFile() @@ -278,7 +279,7 @@ class addressGenerator(threading.Thread, StoppableThread): 'sendOutOrStoreMyV4Pubkey', address)) shared.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Done generating address"))) - elif saveAddressToDisk and not live and not shared.config.has_section(address): + elif saveAddressToDisk and not live and not BMConfigParser().has_section(address): listOfNewAddressesToSendOutThroughTheAPI.append(address) # Done generating addresses. diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index c85b58a1..9170ae5b 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -13,6 +13,7 @@ from binascii import hexlify from pyelliptic.openssl import OpenSSL import highlevelcrypto from addresses import * +from configparser import BMConfigParser import helper_generic from helper_generic import addDataPadding import helper_bitcoin @@ -20,6 +21,8 @@ import helper_inbox import helper_msgcoding import helper_sent from helper_sql import * +import protocol +from state import neededPubkeys import tr from debug import logger import l10n @@ -130,11 +133,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 shared.safeConfigGetBoolean(myAddress, 'chan'): + if BMConfigParser().safeGetBoolean(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(shared.config.get( + lastPubkeySendTime = int(BMConfigParser().get( myAddress, 'lastpubkeysendtime')) except: lastPubkeySendTime = 0 @@ -283,12 +286,12 @@ class objectProcessor(threading.Thread): return tag = data[readPosition:readPosition + 32] - if tag not in shared.neededPubkeys: + if tag not in 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 = shared.neededPubkeys[tag] + toAddress, cryptorObject = 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 @@ -458,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 shared.safeConfigGetBoolean(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 BMConfigParser().safeGetBoolean(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 = shared.config.getint( + requiredNonceTrialsPerByte = BMConfigParser().getint( toAddress, 'noncetrialsperbyte') - requiredPayloadLengthExtraBytes = shared.config.getint( + requiredPayloadLengthExtraBytes = BMConfigParser().getint( toAddress, 'payloadlengthextrabytes') 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 shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist + if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': # If we are using a blacklist queryreturn = sqlQuery( '''SELECT label FROM blacklist where address=? and enabled='1' ''', fromAddress) @@ -484,7 +487,7 @@ class objectProcessor(threading.Thread): logger.info('Message ignored because address not in whitelist.') blockMessage = True - toLabel = shared.config.get(toAddress, 'label') + toLabel = BMConfigParser().get(toAddress, 'label') if toLabel == '': toLabel = toAddress @@ -508,9 +511,9 @@ class objectProcessor(threading.Thread): # 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 shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -519,9 +522,9 @@ class objectProcessor(threading.Thread): # Let us now check and see whether our receiving address is # behaving as a mailing list - if shared.safeConfigGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: + if BMConfigParser().safeGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: try: - mailingListName = shared.config.get( + mailingListName = BMConfigParser().get( toAddress, 'mailinglistname') except: mailingListName = '' @@ -566,8 +569,8 @@ class objectProcessor(threading.Thread): if self.ackDataHasAValidHeader(ackData) and \ not blockMessage and \ messageEncodingType != 0 and \ - not shared.safeConfigGetBoolean(toAddress, 'dontsendack') and \ - not shared.safeConfigGetBoolean(toAddress, 'chan'): + not BMConfigParser().safeGetBoolean(toAddress, 'dontsendack') and \ + not BMConfigParser().safeGetBoolean(toAddress, 'chan'): shared.checkAndShareObjectWithPeers(ackData[24:]) # Display timing data @@ -756,9 +759,9 @@ class objectProcessor(threading.Thread): # 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 shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -780,8 +783,8 @@ class objectProcessor(threading.Thread): # stream number, and RIPE hash. status, addressVersion, streamNumber, ripe = decodeAddress(address) if addressVersion <=3: - if address in shared.neededPubkeys: - del shared.neededPubkeys[address] + if address in neededPubkeys: + del 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) @@ -791,8 +794,8 @@ class objectProcessor(threading.Thread): elif addressVersion >= 4: tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] - if tag in shared.neededPubkeys: - del shared.neededPubkeys[tag] + if tag in neededPubkeys: + del neededPubkeys[tag] self.sendMessages(address) def sendMessages(self, address): @@ -808,15 +811,15 @@ class objectProcessor(threading.Thread): shared.workerQueue.put(('sendmessage', '')) def ackDataHasAValidHeader(self, ackData): - if len(ackData) < shared.Header.size: + if len(ackData) < protocol.Header.size: logger.info('The length of ackData is unreasonably short. Not sending ackData.') return False - magic,command,payloadLength,checksum = shared.Header.unpack(ackData[:shared.Header.size]) + magic,command,payloadLength,checksum = protocol.Header.unpack(ackData[:protocol.Header.size]) if magic != 0xE9BEB4D9: logger.info('Ackdata magic bytes were wrong. Not sending ackData.') return False - payload = ackData[shared.Header.size:] + payload = ackData[protocol.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_outgoingSynSender.py b/src/class_outgoingSynSender.py index bca56b33..caa14aa0 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -10,6 +10,7 @@ import tr from class_sendDataThread import * from class_receiveDataThread import * +from configparser import BMConfigParser from helper_threading import * # For each stream to which we connect, several outgoingSynSender threads @@ -45,12 +46,12 @@ class outgoingSynSender(threading.Thread, StoppableThread): continue priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours shared.knownNodesLock.release() - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': + 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 == shared.config.get('bitmessagesettings', 'onionhostname') and peer.port == shared.config.getint("bitmessagesettings", "onionport"): + 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 @@ -72,9 +73,9 @@ class outgoingSynSender(threading.Thread, StoppableThread): pass def run(self): - while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: self.stop.wait(2) - while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: @@ -110,8 +111,8 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator address_family = socket.AF_INET # Proxy IP is IPv6. Unlikely but possible - if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': - if ":" in shared.config.get('bitmessagesettings', 'sockshostname'): + 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 : @@ -140,44 +141,44 @@ class outgoingSynSender(threading.Thread, StoppableThread): # can rebind faster self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.settimeout(20) - if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: logger.debug('Trying an outgoing connection to ' + str(peer)) # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': if shared.verbose >= 2: logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS4 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + 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 shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: self.sock.setproxy( proxytype, sockshostname, socksport, rdns) - elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': if shared.verbose >= 2: logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + 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 shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) @@ -254,7 +255,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): except socks.Socks4Error as err: logger.error('Socks4Error: ' + str(err)) except socket.error as err: - if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) else: if shared.verbose >= 1: diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index f29b1f4c..fb25db4c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -23,12 +23,15 @@ from binascii import hexlify #import highlevelcrypto from addresses import * +from configparser import BMConfigParser from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +import protocol from inventory import Inventory import tr +from version import softwareVersion # This thread is created either by the synSenderThread(for outgoing # connections) or the singleListenerThread(for incoming connections). @@ -59,7 +62,7 @@ class receiveDataThread(threading.Thread): 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 shared.config.get('bitmessagesettings', 'onionhostname') and shared.checkSocksIP(self.peer.host) else self.peer.host + 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.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. @@ -77,10 +80,10 @@ class receiveDataThread(threading.Thread): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) while True: - if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0: + if BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') == 0: downloadRateLimitBytes = float("inf") else: - downloadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxdownloadrate') * 1000 + downloadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') * 1000 with shared.receiveDataLock: while shared.numberOfBytesReceivedLastSecond >= downloadRateLimitBytes: if int(time.time()) == shared.lastTimeWeResetBytesReceived: @@ -93,9 +96,9 @@ class receiveDataThread(threading.Thread): dataLen = len(self.data) try: ssl = False - if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and - shared.haveSSL(not self.initiatedConnection)): + protocol.haveSSL(not self.initiatedConnection)): ssl = True dataRecv = self.sslSock.recv(1024) else: @@ -106,7 +109,7 @@ class receiveDataThread(threading.Thread): except socket.timeout: logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break - except Exception as err: + except socket.error as err: if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): if ssl: select.select([self.sslSock], [], []) @@ -165,25 +168,25 @@ class receiveDataThread(threading.Thread): shared.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) < shared.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) < protocol.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 = shared.Header.unpack(self.data[:shared.Header.size]) + magic,command,payloadLength,checksum = protocol.Header.unpack(self.data[:protocol.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 + shared.Header.size:] + self.data = self.data[payloadLength + protocol.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 + shared.Header.size: # check if the whole message has arrived yet. + if len(self.data) < payloadLength + protocol.Header.size: # check if the whole message has arrived yet. return - payload = self.data[shared.Header.size:payloadLength + shared.Header.size] + payload = self.data[protocol.Header.size:payloadLength + protocol.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 + shared.Header.size:] + self.data = self.data[payloadLength + protocol.Header.size:] del magic,command,payloadLength,checksum,payload # better to clean up before the recursive call self.processData() return @@ -227,7 +230,7 @@ class receiveDataThread(threading.Thread): logger.critical("Critical error in a receiveDataThread: \n%s" % traceback.format_exc()) del payload - self.data = self.data[payloadLength + shared.Header.size:] # take this message out and then process the next message + self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: @@ -267,7 +270,7 @@ class receiveDataThread(threading.Thread): def sendpong(self): logger.debug('Sending pong') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong'))) def recverack(self): @@ -285,8 +288,8 @@ class receiveDataThread(threading.Thread): shared.timeOffsetWrongCount = 0 self.sslSock = self.sock - if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and - shared.haveSSL(not self.initiatedConnection)): + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') if hasattr(self.sslSock, "context"): @@ -361,7 +364,7 @@ class receiveDataThread(threading.Thread): 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', shared.CreatePacket('inv', payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('inv', payload))) def _sleepForTimingAttackMitigation(self, sleepTime): # We don't need to do the timing attack mitigation if we are @@ -471,7 +474,7 @@ class receiveDataThread(threading.Thread): def sendgetdata(self, hash): logger.debug('sending getdata to retrieve object with hash: ' + hexlify(hash)) payload = '\x01' + hash - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('getdata', payload))) # We have received a getdata request from our peer @@ -499,7 +502,7 @@ class receiveDataThread(threading.Thread): # Our peer has requested (in a getdata message) that we send an object. def sendObject(self, payload): logger.debug('sending an object.') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('object',payload))) def _checkIPAddress(self, host): if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': @@ -622,15 +625,15 @@ class receiveDataThread(threading.Thread): sentOwn = False for i in range(500): # if current connection is over a proxy, sent our own onion address at a random position - if ownPosition == i and ".onion" in shared.config.get("bitmessagesettings", "onionhostname") and \ + if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \ hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: - peer = shared.Peer(shared.config.get("bitmessagesettings", "onionhostname"), shared.config.getint("bitmessagesettings", "onionport")) + peer = shared.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) else: # still may contain own onion address, but we don't change it peer, = random.sample(shared.knownNodes[self.streamNumber], 1) if isHostInPrivateIPRange(peer.host): continue - if peer.host == shared.config.get("bitmessagesettings", "onionhostname") and peer.port == shared.config.getint("bitmessagesettings", "onionport") : + if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") : sentOwn = True addrsInMyStream[peer] = shared.knownNodes[ self.streamNumber][peer] @@ -662,7 +665,7 @@ class receiveDataThread(threading.Thread): payload += pack('>I', self.streamNumber) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port for (HOST, PORT), value in addrsInChildStreamLeft.items(): timeLastReceivedMessageFromThisNode = value @@ -673,7 +676,7 @@ class receiveDataThread(threading.Thread): payload += pack('>I', self.streamNumber * 2) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port for (HOST, PORT), value in addrsInChildStreamRight.items(): timeLastReceivedMessageFromThisNode = value @@ -684,11 +687,11 @@ class receiveDataThread(threading.Thread): payload += pack('>I', (self.streamNumber * 2) + 1) payload += pack( '>q', 1) # service bit flags offered by this node - payload += shared.encodeHost(HOST) + payload += protocol.encodeHost(HOST) payload += pack('>H', PORT) # remote port payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('addr', payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload))) # We have received a version message @@ -714,14 +717,14 @@ class receiveDataThread(threading.Thread): timestamp, = unpack('>Q', data[12:20]) 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."))) + 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, timeOffset)) shared.timeOffsetWrongCount += 1 time.sleep(2) self.sendDataThreadQueue.put((0, 'shutdown','no data')) return elif 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."))) + 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, timeOffset)) shared.timeOffsetWrongCount += 1 time.sleep(2) @@ -747,7 +750,7 @@ class receiveDataThread(threading.Thread): userAgentName = useragent userAgentVersion = "0.0.0" if userAgentName == "PyBitmessage": - myVersion = [int(n) for n in shared.softwareVersion.split(".")] + myVersion = [int(n) for n in softwareVersion.split(".")] try: remoteVersion = [int(n) for n in userAgentVersion.split(".")] except: @@ -778,7 +781,7 @@ class receiveDataThread(threading.Thread): # 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: + if data[72:80] == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: self.sendDataThreadQueue.put((0, 'shutdown','no data')) logger.debug('Closing connection to myself: ' + str(self.peer)) return @@ -801,14 +804,14 @@ class receiveDataThread(threading.Thread): # Sends a version message def sendversion(self): logger.debug('Sending version message') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleVersionMessage( + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage( self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection))) # Sends a verack message def sendverack(self): logger.debug('Sending verack') - self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('verack'))) self.verackSent = True if self.verackReceived: self.connectionFullyEstablished() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 9c048d32..0a49e95c 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -8,10 +8,12 @@ import random import sys import socket +from configparser import BMConfigParser from helper_generic import addDataPadding from class_objectHashHolder import * from addresses import * from debug import logger +import protocol # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). @@ -53,7 +55,7 @@ class sendDataThread(threading.Thread): def sendVersionMessage(self): - datatosend = shared.assembleVersionMessage( + datatosend = protocol.assembleVersionMessage( self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. logger.debug('Sending version packet: ' + repr(datatosend)) @@ -67,10 +69,10 @@ class sendDataThread(threading.Thread): self.versionSent = 1 def sendBytes(self, data): - if shared.config.getint('bitmessagesettings', 'maxuploadrate') == 0: + if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: - uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 + uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 with shared.sendDataLock: while data: while shared.numberOfBytesSentLastSecond >= uploadRateLimitBytes: @@ -83,11 +85,11 @@ class sendDataThread(threading.Thread): # 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: + if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: - uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 - if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and + uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and shared.haveSSL(not self.initiatedConnection)): amountSent = self.sslSock.send(data[:1000]) @@ -134,11 +136,11 @@ class sendDataThread(threading.Thread): payload += pack('>I', streamNumber) payload += pack( '>q', services) # service bit flags offered by this node - payload += shared.encodeHost(host) + payload += protocol.encodeHost(host) payload += pack('>H', port) payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - packet = shared.CreatePacket('addr', payload) + packet = protocol.CreatePacket('addr', payload) try: self.sendBytes(packet) except: @@ -154,7 +156,7 @@ class sendDataThread(threading.Thread): payload += hash if payload != '': payload = encodeVarint(len(payload)/32) + payload - packet = shared.CreatePacket('inv', payload) + packet = protocol.CreatePacket('inv', payload) try: self.sendBytes(packet) except: @@ -165,7 +167,7 @@ class sendDataThread(threading.Thread): 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 = shared.CreatePacket('pong') + packet = protocol.CreatePacket('pong') try: self.sendBytes(packet) except: diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 533184d3..0c25c5ec 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -6,10 +6,12 @@ import os import pickle import tr#anslate +from configparser import BMConfigParser from helper_sql import * from helper_threading import * from inventory import Inventory from debug import logger +from state import neededPubkeys """ The singleCleaner class is a timer-driven thread that cleans data structures @@ -40,7 +42,7 @@ class singleCleaner(threading.Thread, StoppableThread): def run(self): timeWeLastClearedInventoryAndPubkeysTables = 0 try: - shared.maximumLengthOfTimeToBotherResendingMessages = (float(shared.config.get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(shared.config.get('bitmessagesettings', 'stopresendingafterxmonths')) * (60 * 60 * 24 *365)/12) + shared.maximumLengthOfTimeToBotherResendingMessages = (float(BMConfigParser().get('bitmessagesettings', 'stopresendingafterxdays')) * 24 * 60 * 60) + (float(BMConfigParser().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') @@ -56,7 +58,7 @@ class singleCleaner(threading.Thread, StoppableThread): # 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.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) @@ -114,8 +116,8 @@ class singleCleaner(threading.Thread, StoppableThread): 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 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. + del neededPubkeys[ + address] # We need to take this entry out of the 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 diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 0a093d0e..896a34bc 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -1,10 +1,12 @@ import threading import shared import socket +from configparser import BMConfigParser from class_sendDataThread import * from class_receiveDataThread import * import helper_bootstrap from helper_threading import * +import protocol import errno import re @@ -28,9 +30,9 @@ class singleListener(threading.Thread, StoppableThread): def _createListenSocket(self, family): HOST = '' # Symbolic name meaning all available interfaces # If not sockslisten, but onionhostname defined, only listen on localhost - if not shared.safeConfigGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): - HOST = shared.config.get('bitmessagesettings', 'onionbindip') - PORT = shared.config.getint('bitmessagesettings', 'port') + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'sockslisten') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): + HOST = BMConfigParser().get('bitmessagesettings', 'onionbindip') + PORT = BMConfigParser().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. @@ -46,9 +48,9 @@ class singleListener(threading.Thread, StoppableThread): def stopThread(self): super(singleListener, self).stopThread() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - for ip in ('127.0.0.1', shared.config.get('bitmessagesettings', 'onionbindip')): + for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')): try: - s.connect((ip, shared.config.getint('bitmessagesettings', 'port'))) + s.connect((ip, BMConfigParser().getint('bitmessagesettings', 'port'))) s.shutdown(socket.SHUT_RDWR) s.close() break @@ -61,7 +63,7 @@ class singleListener(threading.Thread, StoppableThread): if shared.trustedPeer: return - while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: self.stop.wait(1) helper_bootstrap.dns() # We typically don't want to accept incoming connections if the user is using a @@ -69,9 +71,9 @@ class singleListener(threading.Thread, StoppableThread): # 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 shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ - (not shared.config.getboolean('bitmessagesettings', 'sockslisten') and \ - ".onion" not in shared.config.get('bitmessagesettings', 'onionhostname')) and \ + while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ + (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ + ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')) and \ shared.shutdown == 0: self.stop.wait(5) @@ -100,7 +102,7 @@ class singleListener(threading.Thread, StoppableThread): # 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 shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in shared.config.get('bitmessagesettings', 'onionhostname') and shared.shutdown == 0: + while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') and shared.shutdown == 0: self.stop.wait(10) while len(shared.connectedHostsList) > 220 and shared.shutdown == 0: logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') @@ -123,7 +125,7 @@ class singleListener(threading.Thread, StoppableThread): # 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 shared.config.get('bitmessagesettings', 'onionhostname') or not shared.checkSocksIP(HOST)): + if HOST in shared.connectedHostsList and (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)): socketObject.close() logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') else: diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index ea1fbf3d..94dc0f9a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -11,6 +11,7 @@ import highlevelcrypto import proofofwork import sys import tr +from configparser import BMConfigParser from debug import logger from helper_sql import * import helper_inbox @@ -19,7 +20,8 @@ import helper_msgcoding from helper_threading import * from inventory import Inventory import l10n -from protocol import * +import protocol +from state import neededPubkeys from binascii import hexlify, unhexlify # This thread, of which there is only one, does the heavy lifting: @@ -55,13 +57,13 @@ class singleWorker(threading.Thread, StoppableThread): toAddress, = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) if toAddressVersionNumber <= 3 : - shared.neededPubkeys[toAddress] = 0 + 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:] - shared.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. + 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. # Initialize the shared.ackdataForWhichImWatching data structure queryreturn = sqlQuery( @@ -139,12 +141,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). + payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki). try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().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) @@ -181,7 +183,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except: @@ -199,7 +201,7 @@ class singleWorker(threading.Thread, StoppableThread): except: #The address has been deleted. return - if shared.safeConfigGetBoolean(myAddress, 'chan'): + if BMConfigParser().safeGetBoolean(myAddress, 'chan'): logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( @@ -219,12 +221,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). + payload += protocol.getBitfield(myAddress) # bitfield of features supported by me (see the wiki). try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().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) @@ -243,9 +245,9 @@ class singleWorker(threading.Thread, StoppableThread): payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( myAddress, 'noncetrialsperbyte')) - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( myAddress, 'payloadlengthextrabytes')) signature = highlevelcrypto.sign(payload, privSigningKeyHex) @@ -271,7 +273,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except: @@ -282,10 +284,10 @@ 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 shared.config.has_section(myAddress): + if not BMConfigParser().has_section(myAddress): #The address has been deleted. return - if shared.safeConfigGetBoolean(myAddress, 'chan'): + if shared.BMConfigParser().safeGetBoolean(myAddress, 'chan'): logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( @@ -297,12 +299,12 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - dataToEncrypt = getBitfield(myAddress) + dataToEncrypt = protocol.getBitfield(myAddress) try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( myAddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().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) @@ -319,9 +321,9 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] - dataToEncrypt += encodeVarint(shared.config.getint( + dataToEncrypt += encodeVarint(BMConfigParser().getint( myAddress, 'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(shared.config.getint( + dataToEncrypt += encodeVarint(BMConfigParser().getint( myAddress, 'payloadlengthextrabytes')) # When we encrypt, we'll use a hash of the data @@ -361,7 +363,7 @@ class singleWorker(threading.Thread, StoppableThread): streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: - shared.config.set( + BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) shared.writeKeysFile() except Exception as err: @@ -384,9 +386,9 @@ class singleWorker(threading.Thread, StoppableThread): # We need to convert our private keys to public keys in order # to include them. try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( @@ -432,12 +434,12 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt += encodeVarint(streamNumber) - dataToEncrypt += getBitfield(fromaddress) # behavior bitfield + dataToEncrypt += protocol.getBitfield(fromaddress) # behavior bitfield dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] if addressVersionNumber >= 3: - dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'noncetrialsperbyte')) - dataToEncrypt += encodeVarint(shared.config.getint(fromaddress,'payloadlengthextrabytes')) + 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) @@ -525,7 +527,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 shared.config.has_section(toaddress): + elif BMConfigParser().has_section(toaddress): sqlExecute( '''UPDATE sent SET status='doingmsgpow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) @@ -551,7 +553,7 @@ class singleWorker(threading.Thread, StoppableThread): toTag = '' else: toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:] - if toaddress in shared.neededPubkeys or toTag in shared.neededPubkeys: + if toaddress in neededPubkeys or toTag in neededPubkeys: # We already sent a request for the pubkey sqlExecute( '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', @@ -575,7 +577,7 @@ 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. - shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) + neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) 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. @@ -583,7 +585,7 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', toaddress) - del shared.neededPubkeys[tag] + del neededPubkeys[tag] break #else: # There was something wrong with this pubkey object even # though it had the correct tag- almost certainly because @@ -609,7 +611,7 @@ class singleWorker(threading.Thread, StoppableThread): TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL embeddedTime = int(time.time() + TTL) - if not shared.config.has_section(toaddress): # if we aren't sending this to ourselves or a chan + if not BMConfigParser().has_section(toaddress): # if we aren't sending this to ourselves or a chan shared.ackdataForWhichImWatching[ackdata] = 0 shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Looking up the receiver\'s public key")))) @@ -643,7 +645,7 @@ 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.safeConfigGetBoolean('bitmessagesettings','willinglysendtomobile'): # if we are Not willing to include the receiver's RIPE hash on the message.. + if not shared.BMConfigParser().safeGetBoolean('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.') shared.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())))) # if the human changes their setting and then sends another message or restarts their client, this one will send at that time. @@ -676,7 +678,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("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 > 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): + if (requiredAverageProofOfWorkNonceTrialsPerByte > BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') != 0) or (requiredPayloadLengthExtraBytes > BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') and BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') != 0): # The demanded difficulty is more than we are willing # to do. sqlExecute( @@ -688,10 +690,10 @@ class singleWorker(threading.Thread, StoppableThread): 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 = getBitfield(fromaddress) + behaviorBitfield = protocol.getBitfield(fromaddress) try: - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( toaddress, 'privencryptionkey') except Exception as err: shared.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())))) @@ -709,14 +711,15 @@ class singleWorker(threading.Thread, StoppableThread): # Now we can start to assemble our message. payload = encodeVarint(fromAddressVersionNumber) payload += encodeVarint(fromStreamNumber) - payload += getBitfield(fromaddress) # Bitfield of features and behaviors that can be expected from me. (See https://bitmessage.org/wiki/Protocol_specification#Pubkey_bitfield_features ) + 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 ) + print("Going to do PoW 4") # We need to convert our private keys to public keys in order # to include them. try: - privSigningKeyBase58 = shared.config.get( + privSigningKeyBase58 = BMConfigParser().get( fromaddress, 'privsigningkey') - privEncryptionKeyBase58 = shared.config.get( + privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( @@ -748,9 +751,9 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint( shared.networkDefaultPayloadLengthExtraBytes) else: - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().getint( fromaddress, 'noncetrialsperbyte')) - payload += encodeVarint(shared.config.getint( + payload += encodeVarint(BMConfigParser().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. @@ -758,10 +761,10 @@ class singleWorker(threading.Thread, StoppableThread): encodedMessage = helper_msgcoding.MsgEncode({"subject": subject, "body": message}, encoding) payload += encodeVarint(encodedMessage.length) payload += encodedMessage.data - if shared.config.has_section(toaddress): + if BMConfigParser().has_section(toaddress): logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') fullAckPayload = '' - elif not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): + 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.') fullAckPayload = '' else: @@ -811,7 +814,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 2 Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') - if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): + if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) else: # not sending to a chan or one of my addresses @@ -821,7 +824,7 @@ class singleWorker(threading.Thread, StoppableThread): toStreamNumber, 'advertiseobject', inventoryHash)) # Update the sent message in the sent table with the necessary information. - if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): + if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' @@ -839,7 +842,7 @@ class singleWorker(threading.Thread, StoppableThread): # If we are sending to ourselves or a chan, let's put the message in # our own inbox. - if shared.config.has_section(toaddress): + if BMConfigParser().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) @@ -851,9 +854,9 @@ class singleWorker(threading.Thread, StoppableThread): # 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 shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'apienabled'): try: - apiNotifyPath = shared.config.get( + apiNotifyPath = BMConfigParser().get( 'bitmessagesettings', 'apinotifypath') except: apiNotifyPath = '' @@ -877,15 +880,15 @@ class singleWorker(threading.Thread, StoppableThread): retryNumber = queryReturn[0][0] if addressVersionNumber <= 3: - shared.neededPubkeys[toAddress] = 0 + 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 shared.neededPubkeys: - shared.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 neededPubkeys: + 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 retryNumber == 0: TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. @@ -976,4 +979,4 @@ class singleWorker(threading.Thread, StoppableThread): pass payload = pack('>Q', nonce) + payload - return shared.CreatePacket('object', payload) + return protocol.CreatePacket('object', payload) diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 42baf989..ca51946f 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -5,6 +5,7 @@ import sys import threading import urlparse +from configparser import BMConfigParser from debug import logger from helper_threading import * import shared @@ -47,7 +48,7 @@ class smtpDeliver(threading.Thread, StoppableThread): pass elif command == 'displayNewInboxMessage': inventoryHash, toAddress, fromAddress, subject, body = data - dest = shared.safeConfigGet("bitmessagesettings", "smtpdeliver", '') + dest = BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') if dest == '': continue try: @@ -57,7 +58,7 @@ class smtpDeliver(threading.Thread, StoppableThread): msg = MIMEText(body, 'plain', 'utf-8') msg['Subject'] = Header(subject, 'utf-8') msg['From'] = fromAddress + '@' + SMTPDOMAIN - toLabel = map (lambda y: shared.safeConfigGet(y, "label"), filter(lambda x: x == toAddress, shared.config.sections())) + toLabel = map (lambda y: BMConfigParser().safeGet(y, "label"), filter(lambda x: x == toAddress, BMConfigParser().sections())) if len(toLabel) > 0: msg['To'] = "\"%s\" <%s>" % (Header(toLabel[0], 'utf-8'), toAddress + '@' + SMTPDOMAIN) else: diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index af3056be..4043600c 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -10,11 +10,13 @@ import threading import time from addresses import decodeAddress +from configparser import BMConfigParser from debug import logger from helper_sql import sqlExecute from helper_threading import StoppableThread from pyelliptic.openssl import OpenSSL import shared +from version import softwareVersion SMTPDOMAIN = "bmaddr.lan" LISTENPORT = 8425 @@ -24,7 +26,7 @@ class smtpServerChannel(smtpd.SMTPChannel): if not arg: self.push('501 Syntax: HELO hostname') return - self.push('250-PyBitmessage %s' % shared.softwareVersion) + self.push('250-PyBitmessage %s' % softwareVersion) self.push('250 AUTH PLAIN') def smtp_AUTH(self, arg): @@ -34,8 +36,8 @@ class smtpServerChannel(smtpd.SMTPChannel): authstring = arg[6:] try: decoded = base64.b64decode(authstring) - correctauth = "\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdusername", "") + \ - "\x00" + shared.safeConfigGet("bitmessagesettings", "smtpdpassword", "") + correctauth = "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdusername", "") + \ + "\x00" + BMConfigParser().safeGet("bitmessagesettings", "smtpdpassword", "") logger.debug("authstring: %s / %s", correctauth, decoded) if correctauth == decoded: self.auth = True @@ -80,7 +82,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): 0, # retryNumber 'sent', # folder 2, # encodingtype - min(shared.config.getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days + min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days ) shared.workerQueue.put(('sendmessage', toAddress)) @@ -112,7 +114,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = p.sub(r'\1', mailfrom).split("@") if domain != SMTPDOMAIN: raise Exception("Bad domain %s", domain) - if sender not in shared.config.sections(): + if sender not in BMConfigParser().sections(): raise Exception("Nonexisting user %s", sender) except Exception as err: logger.debug("Bad envelope from %s: %s", mailfrom, repr(err)) @@ -122,7 +124,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = msg_from.split("@") if domain != SMTPDOMAIN: raise Exception("Bad domain %s", domain) - if sender not in shared.config.sections(): + if sender not in BMConfigParser().sections(): raise Exception("Nonexisting user %s", sender) except Exception as err: logger.error("Bad headers from %s: %s", msg_from, repr(err)) @@ -163,7 +165,7 @@ class smtpServer(threading.Thread, StoppableThread): self.server.close() return s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -# for ip in ('127.0.0.1', shared.config.get('bitmessagesettings', 'onionbindip')): +# for ip in ('127.0.0.1', BMConfigParser().get('bitmessagesettings', 'onionbindip')): for ip in ('127.0.0.1'): try: s.connect((ip, LISTENPORT)) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 9d45cdcf..320f6315 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,4 +1,5 @@ import threading +from configparser import BMConfigParser import shared import sqlite3 import time @@ -65,35 +66,35 @@ class sqlThread(threading.Thread): 'ERROR trying to create database file (message.dat). Error message: %s\n' % str(err)) os._exit(0) - if shared.config.getint('bitmessagesettings', 'settingsversion') == 1: - shared.config.set('bitmessagesettings', 'settingsversion', '2') + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 1: + BMConfigParser().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. - 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') + 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') # People running earlier versions of PyBitmessage do not have the # usedpersonally field in their pubkeys table. Let's add it. - if shared.config.getint('bitmessagesettings', 'settingsversion') == 2: + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 2: item = '''ALTER TABLE pubkeys ADD usedpersonally text DEFAULT 'no' ''' parameters = '' self.cur.execute(item, parameters) self.conn.commit() - shared.config.set('bitmessagesettings', 'settingsversion', '3') + BMConfigParser().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 shared.config.getint('bitmessagesettings', 'settingsversion') == 3: + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 3: item = '''ALTER TABLE inbox ADD encodingtype int DEFAULT '2' ''' parameters = '' self.cur.execute(item, parameters) @@ -107,21 +108,21 @@ class sqlThread(threading.Thread): self.cur.execute(item, parameters) self.conn.commit() - shared.config.set('bitmessagesettings', 'settingsversion', '4') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '4') - if shared.config.getint('bitmessagesettings', 'settingsversion') == 4: - shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( shared.networkDefaultPayloadLengthExtraBytes)) - shared.config.set('bitmessagesettings', 'settingsversion', '5') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') - if shared.config.getint('bitmessagesettings', 'settingsversion') == 5: - shared.config.set( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') - shared.config.set('bitmessagesettings', 'settingsversion', '6') + BMConfigParser().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 @@ -174,8 +175,8 @@ class sqlThread(threading.Thread): '''update sent set status='broadcastqueued' where status='broadcastpending' ''') self.conn.commit() - if not shared.config.has_option('bitmessagesettings', 'sockslisten'): - shared.config.set('bitmessagesettings', 'sockslisten', 'false') + if not BMConfigParser().has_option('bitmessagesettings', 'sockslisten'): + BMConfigParser().set('bitmessagesettings', 'sockslisten', 'false') ensureNamecoinOptions() @@ -226,18 +227,18 @@ class sqlThread(threading.Thread): parameters = (4,) self.cur.execute(item, parameters) - 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') + if not BMConfigParser().has_option('bitmessagesettings', 'userlocale'): + BMConfigParser().set('bitmessagesettings', 'userlocale', 'system') + if not BMConfigParser().has_option('bitmessagesettings', 'sendoutgoingconnections'): + BMConfigParser().set('bitmessagesettings', 'sendoutgoingconnections', 'True') # Raise the default required difficulty from 1 to 2 # With the change to protocol v3, this is obsolete. - if shared.config.getint('bitmessagesettings', 'settingsversion') == 6: + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 6: """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte: shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) """ - shared.config.set('bitmessagesettings', 'settingsversion', '7') + BMConfigParser().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. @@ -255,18 +256,18 @@ class sqlThread(threading.Thread): parameters = (5,) self.cur.execute(item, parameters) - 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 + 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 #Add settings to support no longer resending messages after a certain period of time even if we never get an ack - if shared.config.getint('bitmessagesettings', 'settingsversion') == 7: - shared.config.set( + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 7: + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxdays', '') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - shared.config.set('bitmessagesettings', 'settingsversion', '8') + BMConfigParser().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. @@ -300,39 +301,39 @@ 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 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') + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 8: + BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.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') # Adjust the required POW values for each of this user's addresses to conform to protocol v3 norms. - if shared.config.getint('bitmessagesettings', 'settingsversion') == 9: - for addressInKeysFile in shared.config.sections(): + if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 9: + for addressInKeysFile in BMConfigParser().sections(): try: - previousTotalDifficulty = float(shared.config.getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 - previousSmallMessageDifficulty = float(shared.config.getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 + previousTotalDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 + previousSmallMessageDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 if previousTotalDifficulty <= 2: previousTotalDifficulty = 1 if previousSmallMessageDifficulty < 1: previousSmallMessageDifficulty = 1 - shared.config.set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) - shared.config.set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) + BMConfigParser().set(addressInKeysFile,'noncetrialsperbyte', str(int(previousTotalDifficulty * 1000))) + BMConfigParser().set(addressInKeysFile,'payloadlengthextrabytes', str(int(previousSmallMessageDifficulty * 1000))) except: continue - shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') - shared.config.set('bitmessagesettings', 'maxuploadrate', '0') - shared.config.set('bitmessagesettings', 'settingsversion', '10') + BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') + BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') shared.writeKeysFile() # sanity check - if shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - if shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) + if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) # 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. @@ -371,8 +372,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 shared.config.has_option('bitmessagesettings', 'ttl'): - shared.config.set('bitmessagesettings', 'ttl', '367200') + if not BMConfigParser().has_option('bitmessagesettings', 'ttl'): + BMConfigParser().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';''' @@ -419,16 +420,16 @@ 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 shared.config.has_option('bitmessagesettings', 'onionhostname'): - shared.config.set('bitmessagesettings', 'onionhostname', '') - if not shared.config.has_option('bitmessagesettings', 'onionport'): - shared.config.set('bitmessagesettings', 'onionport', '8444') - if not shared.config.has_option('bitmessagesettings', 'onionbindip'): - shared.config.set('bitmessagesettings', 'onionbindip', '127.0.0.1') - if not shared.config.has_option('bitmessagesettings', 'smtpdeliver'): - shared.config.set('bitmessagesettings', 'smtpdeliver', '') - if not shared.config.has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): - shared.config.set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') + 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') shared.writeKeysFile() # Are you hoping to add a new option to the keys.dat file of existing diff --git a/src/configparser.py b/src/configparser.py index 900bef50..7a4258be 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -1,5 +1,9 @@ import ConfigParser +from singleton import Singleton + + +@Singleton class BMConfigParser(ConfigParser.SafeConfigParser): def set(self, section, option, value=None): if self._optcre is self.OPTCRE or value: @@ -15,6 +19,20 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return ConfigParser.ConfigParser.get(self, section, option, True, vars) return ConfigParser.ConfigParser.get(self, section, option, True, vars) + def safeGetBoolean(self, section, field): + if self.has_option(section, field): + try: + return self.getboolean(section, field) + except ValueError: + return False + return False + + def safeGet(self, section, option, default = None): + if self.has_option(section, option): + return self.get(section, option) + else: + return default + def items(self, section, raw=False, vars=None): return ConfigParser.ConfigParser.items(self, section, True, vars) diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 82f5b5bc..44bd190a 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -4,6 +4,7 @@ import defaultKnownNodes import pickle import time +from configparser import BMConfigParser from debug import logger import socks @@ -29,9 +30,9 @@ def knownNodes(): except: shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) # your own onion address, if setup - if shared.config.has_option('bitmessagesettings', 'onionhostname') and ".onion" in shared.config.get('bitmessagesettings', 'onionhostname'): - shared.knownNodes[1][shared.Peer(shared.config.get('bitmessagesettings', 'onionhostname'), shared.config.getint('bitmessagesettings', 'onionport'))] = int(time.time()) - if shared.config.getint('bitmessagesettings', 'settingsversion') > 10: + if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): + shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) + 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.') raise SystemExit @@ -41,7 +42,7 @@ def dns(): # 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. - if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': + if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none': try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') @@ -54,7 +55,7 @@ def dns(): shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) except: logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') - elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") for port in [8080, 8444]: @@ -64,15 +65,15 @@ def dns(): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.settimeout(20) proxytype = socks.PROXY_TYPE_SOCKS5 - sockshostname = shared.config.get( + sockshostname = BMConfigParser().get( 'bitmessagesettings', 'sockshostname') - socksport = shared.config.getint( + 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 shared.config.getboolean('bitmessagesettings', 'socksauthentication'): - socksusername = shared.config.get( + if BMConfigParser().getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = BMConfigParser().get( 'bitmessagesettings', 'socksusername') - sockspassword = shared.config.get( + sockspassword = BMConfigParser().get( 'bitmessagesettings', 'sockspassword') sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) diff --git a/src/helper_generic.py b/src/helper_generic.py index 5997a8ca..a36c273e 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -5,6 +5,7 @@ from binascii import hexlify, unhexlify from multiprocessing import current_process from threading import current_thread, enumerate +from configparser import BMConfigParser from debug import logger import shared @@ -51,7 +52,7 @@ def signal_handler(signal, frame): if current_thread().name != "MainThread": return logger.error("Got signal %i", signal) - if shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): shared.doCleanShutdown() else: print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' diff --git a/src/helper_startup.py b/src/helper_startup.py index cc74649a..d685882e 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,5 +1,6 @@ -import shared import ConfigParser +import shared +from configparser import BMConfigParser import sys import os import locale @@ -14,7 +15,7 @@ storeConfigFilesInSameDirectoryAsProgramByDefault = False # The user may de-sel def _loadTrustedPeer(): try: - trustedPeer = shared.config.get('bitmessagesettings', 'trustedpeer') + trustedPeer = BMConfigParser().get('bitmessagesettings', 'trustedpeer') except ConfigParser.Error: # This probably means the trusted peer wasn't specified so we # can just leave it as None @@ -25,19 +26,19 @@ def _loadTrustedPeer(): def loadConfig(): if shared.appdata: - shared.config.read(shared.appdata + 'keys.dat') + BMConfigParser().read(shared.appdata + 'keys.dat') #shared.appdata must have been specified as a startup option. try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from directory specified on startup: ' + shared.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True else: - shared.config.read(shared.lookupExeFolder() + 'keys.dat') + BMConfigParser().read(shared.lookupExeFolder() + 'keys.dat') try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False shared.appdata = shared.lookupExeFolder() @@ -45,9 +46,9 @@ def loadConfig(): # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. shared.appdata = shared.lookupAppdataFolder() - shared.config.read(shared.appdata + 'keys.dat') + BMConfigParser().read(shared.appdata + 'keys.dat') try: - shared.config.get('bitmessagesettings', 'settingsversion') + BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading existing config files from', shared.appdata needToCreateKeysFile = False except: @@ -56,62 +57,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. - shared.config.add_section('bitmessagesettings') - shared.config.set('bitmessagesettings', 'settingsversion', '10') - shared.config.set('bitmessagesettings', 'port', '8444') - shared.config.set( + BMConfigParser().add_section('bitmessagesettings') + BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') + BMConfigParser().set('bitmessagesettings', 'port', '8444') + BMConfigParser().set( 'bitmessagesettings', 'timeformat', '%%c') - shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') - shared.config.set('bitmessagesettings', 'startonlogon', 'false') + BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') + BMConfigParser().set('bitmessagesettings', 'startonlogon', 'false') if 'linux' in sys.platform: - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'minimizetotray', 'false') # This isn't implimented yet and when True on # Ubuntu causes Bitmessage to disappear while # running when minimized. else: - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'minimizetotray', 'true') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'showtraynotifications', 'true') - shared.config.set('bitmessagesettings', 'startintray', 'false') - shared.config.set('bitmessagesettings', 'socksproxytype', 'none') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'startintray', 'false') + BMConfigParser().set('bitmessagesettings', 'socksproxytype', 'none') + BMConfigParser().set( 'bitmessagesettings', 'sockshostname', 'localhost') - shared.config.set('bitmessagesettings', 'socksport', '9050') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'socksport', '9050') + BMConfigParser().set( 'bitmessagesettings', 'socksauthentication', 'false') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'sockslisten', 'false') - shared.config.set('bitmessagesettings', 'socksusername', '') - shared.config.set('bitmessagesettings', 'sockspassword', '') - shared.config.set('bitmessagesettings', 'keysencrypted', 'false') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'socksusername', '') + BMConfigParser().set('bitmessagesettings', 'sockspassword', '') + BMConfigParser().set('bitmessagesettings', 'keysencrypted', 'false') + BMConfigParser().set( 'bitmessagesettings', 'messagesencrypted', 'false') - shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( + BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( + BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( shared.networkDefaultPayloadLengthExtraBytes)) - shared.config.set('bitmessagesettings', 'minimizeonclose', 'false') - shared.config.set( + BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0') - 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') + 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', 'ttl', '367200') #start:UI setting to stop trying to send messages after X days/months - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxdays', '') - shared.config.set( + BMConfigParser().set( 'bitmessagesettings', 'stopresendingafterxmonths', '') - #shared.config.set( + #BMConfigParser().set( # 'bitmessagesettings', 'timeperiod', '-1') #end diff --git a/src/l10n.py b/src/l10n.py index 0300085a..f8b72650 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -3,6 +3,7 @@ import logging import os import time +from configparser import BMConfigParser import shared @@ -48,8 +49,8 @@ except: logger.exception('Could not determine language or encoding') -if shared.config.has_option('bitmessagesettings', 'timeformat'): - time_format = shared.config.get('bitmessagesettings', 'timeformat') +if BMConfigParser().has_option('bitmessagesettings', 'timeformat'): + time_format = BMConfigParser().get('bitmessagesettings', 'timeformat') #Test the format string try: time.strftime(time_format) @@ -112,8 +113,8 @@ def formatTimestamp(timestamp = None, as_unicode = True): def getTranslationLanguage(): userlocale = None - if shared.config.has_option('bitmessagesettings', 'userlocale'): - userlocale = shared.config.get('bitmessagesettings', 'userlocale') + if BMConfigParser().has_option('bitmessagesettings', 'userlocale'): + userlocale = BMConfigParser().get('bitmessagesettings', 'userlocale') if userlocale in [None, '', 'system']: return language diff --git a/src/namecoin.py b/src/namecoin.py index 5b50bb67..7fca0162 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -26,6 +26,7 @@ import socket import sys import os +from configparser import BMConfigParser import shared import tr # translate @@ -63,11 +64,11 @@ class namecoinConnection (object): # actually changing the values (yet). def __init__ (self, options = None): if options is None: - self.nmctype = shared.config.get (configSection, "namecoinrpctype") - self.host = shared.config.get (configSection, "namecoinrpchost") - self.port = int(shared.config.get (configSection, "namecoinrpcport")) - self.user = shared.config.get (configSection, "namecoinrpcuser") - self.password = shared.config.get (configSection, + 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, "namecoinrpcpassword") else: self.nmctype = options["type"] @@ -261,14 +262,14 @@ def lookupNamecoinFolder (): # Ensure all namecoin options are set, by setting those to default values # that aren't there. def ensureNamecoinOptions (): - 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") + if not BMConfigParser().has_option (configSection, "namecoinrpctype"): + BMConfigParser().set (configSection, "namecoinrpctype", "namecoind") + if not BMConfigParser().has_option (configSection, "namecoinrpchost"): + BMConfigParser().set (configSection, "namecoinrpchost", "localhost") - hasUser = shared.config.has_option (configSection, "namecoinrpcuser") - hasPass = shared.config.has_option (configSection, "namecoinrpcpassword") - hasPort = shared.config.has_option (configSection, "namecoinrpcport") + hasUser = BMConfigParser().has_option (configSection, "namecoinrpcuser") + hasPass = BMConfigParser().has_option (configSection, "namecoinrpcpassword") + hasPort = BMConfigParser().has_option (configSection, "namecoinrpcport") # Try to read user/password from .namecoin configuration file. defaultUser = "" @@ -302,11 +303,11 @@ def ensureNamecoinOptions (): # If still nothing found, set empty at least. if (not hasUser): - shared.config.set (configSection, "namecoinrpcuser", defaultUser) + BMConfigParser().set (configSection, "namecoinrpcuser", defaultUser) if (not hasPass): - shared.config.set (configSection, "namecoinrpcpassword", defaultPass) + BMConfigParser().set (configSection, "namecoinrpcpassword", defaultPass) # Set default port now, possibly to found value. if (not hasPort): - shared.config.set (configSection, "namecoinrpcport", + BMConfigParser().set (configSection, "namecoinrpcport", shared.namecoinDefaultRpcPort) diff --git a/src/openclpow.py b/src/openclpow.py index 641db324..766cbffe 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,7 +5,8 @@ import hashlib import random import os -from shared import codePath, safeConfigGetBoolean, safeConfigGet, shutdown +from configparser import BMConfigParser +from shared import codePath, shutdown from debug import logger libAvailable = True @@ -30,7 +31,7 @@ def initCL(): try: for platform in cl.get_platforms(): gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if safeConfigGet("bitmessagesettings", "opencl") == platform.vendor: + 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) diff --git a/src/proofofwork.py b/src/proofofwork.py index 4bb02fd7..244f268c 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -6,6 +6,7 @@ from struct import unpack, pack from subprocess import call import sys import time +from configparser import BMConfigParser from debug import logger import shared import openclpow @@ -58,7 +59,7 @@ def _doFastPoW(target, initialHash): except: pool_size = 4 try: - maxCores = shared.config.getint('bitmessagesettings', 'maxcores') + maxCores = BMConfigParser().getint('bitmessagesettings', 'maxcores') except: maxCores = 99999 if pool_size > maxCores: diff --git a/src/protocol.py b/src/protocol.py index 40feaaf4..ecc0f8cc 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,14 +1,454 @@ -import struct -import shared +import base64 +import hashlib +import random +import socket +import ssl +from struct import pack, unpack, Struct +import sys +import time + +from addresses import encodeVarint, decodeVarint +from configparser import BMConfigParser +from state import neededPubkeys, extPort, socksIP +from version import softwareVersion + +#Service flags +NODE_NETWORK = 1 +NODE_SSL = 2 + +#Bitfield flags +BITFIELD_DOESACK = 1 + +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') + +# Bitfield def getBitfield(address): # bitfield of features supported by me (see the wiki). bitfield = 0 # send ack - if not shared.safeConfigGetBoolean(address, 'dontsendack'): - bitfield |= shared.BITFIELD_DOESACK - return struct.pack('>I', bitfield) + if not BMConfigParser().safeGetBoolean(address, 'dontsendack'): + bitfield |= BITFIELD_DOESACK + return pack('>I', bitfield) def checkBitfield(bitfieldBinary, flags): - bitfield, = struct.unpack('>I', bitfieldBinary) - return (bitfield & flags) == flags \ No newline at end of file + 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 + +# data handling + +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) + +# 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 sslProtocolVersion(): + if sys.version_info >= (2,7,13): + # in the future once TLS is mandatory, change this to ssl.PROTOCOL_TLS1.2 + return ssl.PROTOCOL_TLS + elif sys.version_info >= (2,7,9): + # once TLS is mandatory, add "ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1.1" + return ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 + else: + return ssl.PROTOCOL_TLS1 + +def checkSocksIP(host): + try: + if socksIP is None or not socksIP: + socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + except NameError: + socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + return socksIP == host + +# 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, myStreamNumber, server = False): + payload = '' + payload += pack('>L', 3) # protocol version. + payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # 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. + 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 + + 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. + # we have a separate extPort and + # incoming over clearnet or + # outgoing through clearnet + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and extPort \ + and ((server and not checkSocksIP(remoteHost)) or \ + (BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none" and not server)): + payload += pack('>H', 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() + payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf + userAgent = '/PyBitmessage:' + 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) + +# 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 = 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 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 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 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 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 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)) + diff --git a/src/shared.py b/src/shared.py index 6bbb28ae..7f8aca53 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,5 @@ from __future__ import division -softwareVersion = '0.6.1' 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. @@ -24,7 +23,6 @@ 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 @@ -40,7 +38,6 @@ from helper_threading import * from inventory import Inventory -config = BMConfigParser() myECCryptorObjects = {} MyECSubscriptionCryptorObjects = {} myAddressesByHash = {} #The key in this dictionary is the RIPE hash which is encoded in an address and value is the address itself. @@ -68,9 +65,6 @@ 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( @@ -125,109 +119,6 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = None -# For UPnP -extPort = None - -# for Tor hidden service -socksIP = None - -#Compiled struct for packing/unpacking headers -#New code should use CreatePacket instead of Header.pack -Header = Struct('!L12sL4s') - -#Service flags -NODE_NETWORK = 1 -NODE_SSL = 2 - -#Bitfield flags -BITFIELD_DOESACK = 1 - -#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 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 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 socksIP is None or not socksIP: - socksIP = socket.gethostbyname(config.get("bitmessagesettings", "sockshostname")) - except NameError: - socksIP = socket.gethostbyname(config.get("bitmessagesettings", "sockshostname")) - return socksIP == host - -def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = False): - payload = '' - payload += pack('>L', 3) # protocol version. - payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # 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. - 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 - - 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. - # we have a separate extPort and - # incoming over clearnet or - # outgoing through clearnet - if safeConfigGetBoolean('bitmessagesettings', 'upnp') and extPort \ - and ((server and not checkSocksIP(remoteHost)) or \ - (config.get("bitmessagesettings", "socksproxytype") == "none" and not server)): - payload += pack('>H', extPort) - elif checkSocksIP(remoteHost) and server: # incoming connection over Tor - payload += pack('>H', shared.config.getint('bitmessagesettings', 'onionport')) - else: # no extPort and not incoming over Tor - 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 lookupExeFolder(): if frozen: if frozen == "macosx_app": @@ -318,18 +209,6 @@ def isAddressInMyAddressBookSubscriptionsListOrWhitelist(address): return True return False -def safeConfigGetBoolean(section,field): - try: - return config.getboolean(section,field) - except Exception, err: - return False - -def safeConfigGet(section, option, default = None): - if config.has_option (section, option): - return config.get(section, option) - else: - return default - def decodeWalletImportFormat(WIFstring): fullString = arithmetic.changebase(WIFstring,58,256) privkey = fullString[:-4] @@ -358,11 +237,11 @@ def reloadMyAddressHashes(): #myPrivateKeys.clear() keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') - configSections = config.sections() + configSections = BMConfigParser().sections() hasEnabledKeys = False for addressInKeysFile in configSections: if addressInKeysFile <> 'bitmessagesettings': - isEnabled = config.getboolean(addressInKeysFile, 'enabled') + isEnabled = BMConfigParser().getboolean(addressInKeysFile, 'enabled') if isEnabled: hasEnabledKeys = True status,addressVersionNumber,streamNumber,hash = decodeAddress(addressInKeysFile) @@ -370,7 +249,7 @@ def reloadMyAddressHashes(): # Returns a simple 32 bytes of information encoded in 64 Hex characters, # or null if there was an error. privEncryptionKey = hexlify(decodeWalletImportFormat( - config.get(addressInKeysFile, 'privencryptionkey'))) + BMConfigParser().get(addressInKeysFile, 'privencryptionkey'))) if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) @@ -473,7 +352,7 @@ def doCleanShutdown(): logger.debug("Waiting for thread %s", thread.name) thread.join() - if safeConfigGetBoolean('bitmessagesettings','daemon'): + if BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'): logger.info('Clean shutdown complete.') thisapp.cleanup() os._exit(0) @@ -881,7 +760,7 @@ def writeKeysFile(): fileNameExisted = False # write the file with open(fileName, 'wb') as configfile: - shared.config.write(configfile) + BMConfigParser().write(configfile) # delete the backup if fileNameExisted: os.remove(fileNameBak) diff --git a/src/state.py b/src/state.py new file mode 100644 index 00000000..e3ff6289 --- /dev/null +++ b/src/state.py @@ -0,0 +1,7 @@ +neededPubkeys = {} + +# For UPnP +extPort = None + +# for Tor hidden service +socksIP = None diff --git a/src/tr.py b/src/tr.py index d61d6c34..b7a8e6f0 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,6 +1,8 @@ -import shared import os +from configparser import BMConfigParser +import shared + # 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: def __init__(self, context, text): @@ -16,7 +18,7 @@ def _translate(context, text, disambiguation = None, encoding = None, n = None): return translateText(context, text, n) def translateText(context, text, n = None): - if not shared.safeConfigGetBoolean('bitmessagesettings', 'daemon'): + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): try: from PyQt4 import QtCore, QtGui except Exception as err: diff --git a/src/upnp.py b/src/upnp.py index 50b25b8e..fd6f3852 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -6,6 +6,7 @@ import socket from struct import unpack, pack import threading import time +from configparser import BMConfigParser from helper_threading import * import shared import tr @@ -175,9 +176,9 @@ class uPnPThread(threading.Thread, StoppableThread): def __init__ (self): threading.Thread.__init__(self, name="uPnPThread") - self.localPort = shared.config.getint('bitmessagesettings', 'port') + self.localPort = BMConfigParser().getint('bitmessagesettings', 'port') try: - self.extPort = shared.config.getint('bitmessagesettings', 'extport') + self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') except: self.extPort = None self.localIP = self.getLocalIP() @@ -195,7 +196,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Starting UPnP thread") logger.debug("Local IP: %s", self.localIP) lastSent = 0 - while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): + while shared.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: try: self.sendSearchRouter() @@ -203,7 +204,7 @@ class uPnPThread(threading.Thread, StoppableThread): pass lastSent = time.time() try: - while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): + while shared.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): resp,(ip,port) = self.sock.recvfrom(1000) if resp is None: continue @@ -279,7 +280,7 @@ class uPnPThread(threading.Thread, StoppableThread): router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage') shared.extPort = extPort self.extPort = extPort - shared.config.set('bitmessagesettings', 'extport', str(extPort)) + BMConfigParser().set('bitmessagesettings', 'extport', str(extPort)) break except UPnPError: logger.debug("UPnP error: ", exc_info=True) diff --git a/src/version.py b/src/version.py new file mode 100644 index 00000000..85210f5f --- /dev/null +++ b/src/version.py @@ -0,0 +1 @@ +softwareVersion = '0.6.1' -- 2.45.1 From 5d2bebae28bb26d3ed9a02f4531d822d293848b3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 14:46:10 +0100 Subject: [PATCH 0541/1102] Add IPv4 multicast range to ignored addresses --- src/helper_generic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/helper_generic.py b/src/helper_generic.py index a36c273e..9e2eb9ba 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -67,7 +67,7 @@ def isHostInPrivateIPRange(host): if (ord(hostAddr[0]) & 0xfe) == 0xfc: return False pass - else: + elif ".onion" not in host: if host[:3] == '10.': return True if host[:4] == '172.': @@ -76,6 +76,9 @@ def isHostInPrivateIPRange(host): return True if host[:8] == '192.168.': return True + # Multicast + if host[:3] >= 224 and host[:3] <= 239 and host[4] == '.': + return True return False def addDataPadding(data, desiredMsgLength = 12, paddingChar = '\x00'): -- 2.45.1 From ac348e4e6b90fb6df85cbc6733020b6128555c66 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:00:00 +0100 Subject: [PATCH 0542/1102] Fixes and refactoring - fixes errors introduced in the earlier refactoring - more variables moved to state.py - path finding functions moved to paths.py - remembers IPv6 network unreachable (in the future can be used to skip IPv6 for a while) --- src/api.py | 27 +++--- src/bitmessagecurses/__init__.py | 1 + src/bitmessagemain.py | 11 +-- src/bitmessageqt/__init__.py | 99 +++++++++++----------- src/bitmessageqt/bitmessageui.py | 1 - src/bitmessageqt/languagebox.py | 4 +- src/bitmessageqt/support.py | 10 ++- src/bitmessageqt/utils.py | 9 +- src/bitmessageqt/widgets.py | 4 +- src/class_addressGenerator.py | 8 +- src/class_objectProcessor.py | 2 +- src/class_outgoingSynSender.py | 6 ++ src/class_receiveDataThread.py | 10 ++- src/class_sendDataThread.py | 9 +- src/class_singleCleaner.py | 9 +- src/class_singleWorker.py | 40 ++++----- src/class_sqlThread.py | 28 ++++--- src/debug.py | 11 +-- src/helper_bootstrap.py | 5 +- src/helper_startup.py | 32 +++---- src/l10n.py | 1 - src/message_data_reader.py | 3 +- src/network/https.py | 3 +- src/openclpow.py | 5 +- src/paths.py | 70 ++++++++++++++++ src/proofofwork.py | 15 ++-- src/protocol.py | 59 +++++++++---- src/shared.py | 138 +++++-------------------------- src/singleinstance.py | 3 +- src/state.py | 7 ++ src/tr.py | 1 - 31 files changed, 334 insertions(+), 297 deletions(-) create mode 100644 src/paths.py diff --git a/src/api.py b/src/api.py index 276e397f..a3c80283 100644 --- a/src/api.py +++ b/src/api.py @@ -24,6 +24,7 @@ import helper_inbox import helper_sent import hashlib +import state from pyelliptic.openssl import OpenSSL from struct import pack @@ -251,15 +252,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -319,15 +320,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if len(passphrase) == 0: @@ -450,7 +451,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not BMConfigParser().safeGetBoolean(address, 'chan'): raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.') BMConfigParser().remove_section(address) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: + with open(state.appdata + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) return 'success' @@ -464,7 +465,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not BMConfigParser().has_section(address): raise APIError(13, 'Could not find this address in your keys.dat file.') BMConfigParser().remove_section(address) - with open(shared.appdata + 'keys.dat', 'wb') as configfile: + with open(state.appdata + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) @@ -837,7 +838,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) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes + print '(For msg message via API) Doing proof of work. Total required difficulty:', float(requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -856,7 +857,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): @@ -879,8 +880,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ((len(payload) + shared.networkDefaultPayloadLengthExtraBytes + - 8) * shared.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / ((len(payload) + protocol.networkDefaultPayloadLengthExtraBytes + + 8) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -903,7 +904,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 165873b5..a8840f2f 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -22,6 +22,7 @@ from dialog import Dialog from helper_sql import * import shared +import ConfigParser from configparser import BMConfigParser from addresses import * from pyelliptic.openssl import OpenSSL diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index dd71488d..5c41e4e5 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -28,6 +28,7 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import shared from helper_sql import sqlQuery +import state import threading # Classes @@ -49,7 +50,7 @@ import helper_generic from helper_threading import * def connectToStream(streamNumber): - shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' + state.streamsInWhichIAmParticipating[streamNumber] = 'no data' selfInitiatedConnections[streamNumber] = {} if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): @@ -146,10 +147,10 @@ class singleAPI(threading.Thread, StoppableThread): selfInitiatedConnections = {} if shared.useVeryEasyProofOfWorkForTesting: - shared.networkDefaultProofOfWorkNonceTrialsPerByte = int( - shared.networkDefaultProofOfWorkNonceTrialsPerByte / 100) - shared.networkDefaultPayloadLengthExtraBytes = int( - shared.networkDefaultPayloadLengthExtraBytes / 100) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte = int( + protocol.networkDefaultProofOfWorkNonceTrialsPerByte / 100) + protocol.networkDefaultPayloadLengthExtraBytes = int( + protocol.networkDefaultPayloadLengthExtraBytes / 100) class Main: def start(self, daemon=False): diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9869d734..91424c86 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -76,7 +76,10 @@ from dialogs import AddAddressDialog from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize +import paths from proofofwork import getPowType +import protocol +import state from statusbar import BMStatusBar from version import softwareVersion @@ -100,13 +103,13 @@ def change_translation(newlocale): pass qmytranslator = QtCore.QTranslator() - translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + newlocale) + translationpath = os.path.join (paths.codePath(), 'translations', 'bitmessage_' + newlocale) qmytranslator.load(translationpath) QtGui.QApplication.installTranslator(qmytranslator) qsystranslator = QtCore.QTranslator() - if shared.frozen: - translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + newlocale) + 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) @@ -1360,9 +1363,9 @@ class MyForm(settingsmixin.SMainWindow): # if the address had a known label in the address book if label is not None: # Does a sound file exist for this particular contact? - if (os.path.isfile(shared.appdata + 'sounds/' + label + '.wav') or - os.path.isfile(shared.appdata + 'sounds/' + label + '.mp3')): - soundFilename = shared.appdata + 'sounds/' + label + if (os.path.isfile(state.appdata + 'sounds/' + label + '.wav') or + os.path.isfile(state.appdata + 'sounds/' + label + '.mp3')): + soundFilename = state.appdata + 'sounds/' + label # Avoid making sounds more frequently than the threshold. # This suppresses playing sounds repeatedly when there @@ -1378,19 +1381,19 @@ class MyForm(settingsmixin.SMainWindow): if soundFilename is None: # the sound is for an address which exists in the address book if category is self.SOUND_KNOWN: - soundFilename = shared.appdata + 'sounds/known' + soundFilename = state.appdata + 'sounds/known' # the sound is for an unknown address elif category is self.SOUND_UNKNOWN: - soundFilename = shared.appdata + 'sounds/unknown' + soundFilename = state.appdata + 'sounds/unknown' # initial connection sound elif category is self.SOUND_CONNECTED: - soundFilename = shared.appdata + 'sounds/connected' + soundFilename = state.appdata + 'sounds/connected' # disconnected sound elif category is self.SOUND_DISCONNECTED: - soundFilename = shared.appdata + 'sounds/disconnected' + soundFilename = state.appdata + 'sounds/disconnected' # sound when the connection status becomes green elif category is self.SOUND_CONNECTION_GREEN: - soundFilename = shared.appdata + 'sounds/green' + soundFilename = state.appdata + 'sounds/green' if soundFilename is not None and play is True: if not self.isConnectionSound(category): @@ -1526,7 +1529,7 @@ class MyForm(settingsmixin.SMainWindow): # menu button 'manage keys' def click_actionManageKeys(self): if 'darwin' in sys.platform or 'linux' in sys.platform: - if shared.appdata == '': + if state.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 @@ -1536,14 +1539,14 @@ class MyForm(settingsmixin.SMainWindow): 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(shared.appdata), 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(state.appdata), QMessageBox.Ok) elif sys.platform == 'win32' or sys.platform == 'win64': - if shared.appdata == '': + if state.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(shared.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(state.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: shared.openKeysFile() @@ -2409,10 +2412,10 @@ class MyForm(settingsmixin.SMainWindow): # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) + self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes))) if self.settingsDialogInstance.ui.comboBoxOpenCL.currentText().toUtf8() != BMConfigParser().safeGet("bitmessagesettings", "opencl"): BMConfigParser().set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.comboBoxOpenCL.currentText())) @@ -2421,18 +2424,18 @@ class MyForm(settingsmixin.SMainWindow): 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()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte)): + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * protocol.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()) * shared.networkDefaultPayloadLengthExtraBytes)): + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.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 @@ -2493,21 +2496,21 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux pass - if shared.appdata != shared.lookupExeFolder() and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... + 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... # Write the keys.dat file to disk in the new location sqlStoredProcedure('movemessagstoprog') - with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: + with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() - output = open(shared.lookupExeFolder() + 'knownnodes.dat', 'wb') + output = open(paths.lookupExeFolder() + '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 = shared.lookupExeFolder() + os.remove(state.appdata + 'keys.dat') + os.remove(state.appdata + 'knownnodes.dat') + previousAppdataLocation = state.appdata + state.appdata = paths.lookupExeFolder() debug.restartLoggingInUpdatedAppdataLocation() try: os.remove(previousAppdataLocation + 'debug.log') @@ -2515,25 +2518,25 @@ class MyForm(settingsmixin.SMainWindow): except: pass - if shared.appdata == shared.lookupExeFolder() 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) + 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) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location shared.writeKeysFile() # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() - output = open(shared.appdata + 'knownnodes.dat', 'wb') + output = open(state.appdata + 'knownnodes.dat', 'wb') pickle.dump(shared.knownNodes, output) output.close() shared.knownNodesLock.release() - os.remove(shared.lookupExeFolder() + 'keys.dat') - os.remove(shared.lookupExeFolder() + 'knownnodes.dat') + os.remove(paths.lookupExeFolder() + 'keys.dat') + os.remove(paths.lookupExeFolder() + 'knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() try: - os.remove(shared.lookupExeFolder() + 'debug.log') - os.remove(shared.lookupExeFolder() + 'debug.log.1') + os.remove(paths.lookupExeFolder() + 'debug.log') + os.remove(paths.lookupExeFolder() + 'debug.log.1') except: pass @@ -3621,8 +3624,8 @@ class MyForm(settingsmixin.SMainWindow): currentRow, 0).setIcon(avatarize(addressAtCurrentRow)) def setAvatar(self, addressAtCurrentRow): - if not os.path.exists(shared.appdata + 'avatars/'): - os.makedirs(shared.appdata + 'avatars/') + 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 @@ -3633,8 +3636,8 @@ class MyForm(settingsmixin.SMainWindow): for ext in extensions: filters += [ names[ext] + ' (*.' + ext.lower() + ')' ] all_images_filter += [ '*.' + ext.lower() ] - upper = shared.appdata + 'avatars/' + hash + '.' + ext.upper() - lower = shared.appdata + 'avatars/' + hash + '.' + ext.lower() + upper = state.appdata + 'avatars/' + hash + '.' + ext.upper() + lower = state.appdata + 'avatars/' + hash + '.' + ext.lower() if os.path.isfile(lower): current_files += [lower] elif os.path.isfile(upper): @@ -3643,7 +3646,7 @@ class MyForm(settingsmixin.SMainWindow): filters[1:1] = ['All files (*.*)'] sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters)) # determine the correct filename (note that avatars don't use the suffix) - destination = shared.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1] + destination = state.appdata + 'avatars/' + hash + '.' + sourcefile.split('.')[-1] exists = QtCore.QFile.exists(destination) if sourcefile == '': # ask for removal of avatar @@ -4021,12 +4024,12 @@ class settingsDialog(QtGui.QDialog): self.ui.checkBoxReplyBelow.setChecked( BMConfigParser().safeGetBoolean('bitmessagesettings', 'replybelow')) - if shared.appdata == shared.lookupExeFolder(): + if state.appdata == paths.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) else: try: import tempfile - file = tempfile.NamedTemporaryFile(dir=shared.lookupExeFolder(), delete=True) + file = tempfile.NamedTemporaryFile(dir=paths.lookupExeFolder(), delete=True) file.close # should autodelete except: self.ui.checkBoxPortableMode.setDisabled(True) @@ -4086,15 +4089,15 @@ class settingsDialog(QtGui.QDialog): # Demanded difficulty tab self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / shared.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) # OpenCL if openclpow.openclAvailable(): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index e480258c..668fbffd 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -15,7 +15,6 @@ from messagecompose import MessageCompose import settingsmixin from networkstatus import NetworkStatus from blacklist import Blacklist -import shared try: _fromUtf8 = QtCore.QString.fromUtf8 diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 4ece7d83..8cce1e03 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -3,7 +3,7 @@ import os from PyQt4 import QtCore, QtGui from configparser import BMConfigParser -from shared import codePath +import paths class LanguageBox(QtGui.QComboBox): languageName = {"system": "System Settings", "eo": "Esperanto", "en_pirate": "Pirate English"} @@ -14,7 +14,7 @@ class LanguageBox(QtGui.QComboBox): def populate(self): self.languages = [] self.clear() - localesPath = os.path.join (codePath(), 'translations') + localesPath = os.path.join (paths.codePath(), 'translations') configuredLocale = "system" try: configuredLocale = BMConfigParser().get('bitmessagesettings', 'userlocale', "system") diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 92658a17..aae5134f 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -11,9 +11,11 @@ from foldertree import AccountMixin from helper_sql import * from l10n import getTranslationLanguage from openclpow import openclAvailable, openclEnabled +import paths from proofofwork import bmpow from pyelliptic.openssl import OpenSSL import shared +import state from version import softwareVersion # this is BM support address going to Peter Surda @@ -63,7 +65,7 @@ def checkHasNormalAddress(): def createAddressIfNeeded(myapp): if not checkHasNormalAddress(): - shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, shared.networkDefaultProofOfWorkNonceTrialsPerByte, shared.networkDefaultPayloadLengthExtraBytes)) + shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes)) while shared.shutdown == 0 and not checkHasNormalAddress(): time.sleep(.2) myapp.rerenderComboBoxSendFrom() @@ -104,9 +106,9 @@ def createSupportMessage(myapp): opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) frozen = "N/A" - if shared.frozen: - frozen = shared.frozen - portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" + if paths.frozen: + frozen = paths.frozen + portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False" cpow = "True" if bmpow else "False" #cpow = QtGui.QApplication.translate("Support", cpow) openclpow = str(BMConfigParser().safeGet('bitmessagesettings', 'opencl')) if openclEnabled() else "None" diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 7361f37d..1a5b67d7 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -4,6 +4,7 @@ import os import shared from addresses import addBMIfNotPresent from configparser import BMConfigParser +import state str_broadcast_subscribers = '[Broadcast subscribers]' str_chan = '[chan]' @@ -82,8 +83,8 @@ def avatarize(address): 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() + 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) @@ -94,8 +95,8 @@ def avatarize(address): 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() + 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) diff --git a/src/bitmessageqt/widgets.py b/src/bitmessageqt/widgets.py index 02394296..8ef807f2 100644 --- a/src/bitmessageqt/widgets.py +++ b/src/bitmessageqt/widgets.py @@ -1,10 +1,10 @@ from PyQt4 import uic import os.path +import paths import sys -from shared import codePath def resource_path(resFile): - baseDir = codePath() + 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) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c215fa3c..ff5eb25e 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -77,13 +77,13 @@ class addressGenerator(threading.Thread, StoppableThread): if nonceTrialsPerByte == 0: nonceTrialsPerByte = BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - if nonceTrialsPerByte < shared.networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte + if nonceTrialsPerByte < protocol.networkDefaultProofOfWorkNonceTrialsPerByte: + nonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: payloadLengthExtraBytes = BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - if payloadLengthExtraBytes < shared.networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + if payloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: + payloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': shared.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Generating one new address"))) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 9170ae5b..4d0b7be0 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -467,7 +467,7 @@ class objectProcessor(threading.Thread): toAddress, 'noncetrialsperbyte') requiredPayloadLengthExtraBytes = BMConfigParser().getint( toAddress, 'payloadlengthextrabytes') - if not shared.isProofOfWorkSufficient(data, requiredNonceTrialsPerByte, requiredPayloadLengthExtraBytes): + if not protocol.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. diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index caa14aa0..1754962e 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -1,3 +1,4 @@ +import errno import threading import time import random @@ -12,6 +13,7 @@ from class_sendDataThread import * from class_receiveDataThread import * from configparser import BMConfigParser from helper_threading import * +import state # For each stream to which we connect, several outgoingSynSender threads # will exist and will collectively create 8 connections with peers. @@ -252,12 +254,16 @@ class outgoingSynSender(threading.Thread, StoppableThread): 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.networkProtocolLastFailed['IPv6'] = time.time() except socks.Socks4Error as err: logger.error('Socks4Error: ' + str(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)) else: + if ":" in peer.host and err[0] == errno.ENETUNREACH: + state.networkProtocolLastFailed['IPv6'] = time.time() if shared.verbose >= 1: logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index fb25db4c..cf43f7b3 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -28,8 +28,10 @@ from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger +import paths import protocol from inventory import Inventory +import state import tr from version import softwareVersion @@ -291,7 +293,7 @@ class receiveDataThread(threading.Thread): if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") - self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') + 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') if hasattr(self.sslSock, "context"): self.sslSock.context.set_ecdh_curve("secp256k1") while True: @@ -320,12 +322,12 @@ class receiveDataThread(threading.Thread): shared.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(shared.sendDataQueues)) + "\n" + \ + 'The length of sendDataQueues is now: ' + str(len(state.sendDataQueues)) + "\n" + \ 'broadcasting addr from within connectionFullyEstablished function.') # Let all of our peers know about this new node. dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( self.streamNumber, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. @@ -594,7 +596,7 @@ class receiveDataThread(threading.Thread): hostDetails = ( timeSomeoneElseReceivedMessageFromThisNode, recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( self.streamNumber, 'advertisepeer', hostDetails)) else: timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 0a49e95c..60babb1f 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -14,6 +14,7 @@ from class_objectHashHolder import * from addresses import * from debug import logger import protocol +import state # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). @@ -22,7 +23,7 @@ class sendDataThread(threading.Thread): def __init__(self, sendDataThreadQueue): threading.Thread.__init__(self, name="sendData") self.sendDataThreadQueue = sendDataThreadQueue - shared.sendDataQueues.append(self.sendDataThreadQueue) + state.sendDataQueues.append(self.sendDataThreadQueue) self.data = '' self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) self.objectHashHolderInstance.start() @@ -102,7 +103,7 @@ class sendDataThread(threading.Thread): def run(self): - logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) + logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) while True: deststream, command, data = self.sendDataThreadQueue.get() @@ -190,6 +191,6 @@ class sendDataThread(threading.Thread): self.sock.close() except: pass - shared.sendDataQueues.remove(self.sendDataThreadQueue) - logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) + state.sendDataQueues.remove(self.sendDataThreadQueue) + logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) self.objectHashHolderInstance.close() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 0c25c5ec..03ebc633 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -11,7 +11,8 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from debug import logger -from state import neededPubkeys +import protocol +import state """ The singleCleaner class is a timer-driven thread that cleans data structures @@ -53,7 +54,7 @@ class singleCleaner(threading.Thread, StoppableThread): Inventory().flush() shared.UISignalQueue.put(('updateStatusBar', '')) - shared.broadcastToSendDataQueues(( + protocol.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 @@ -98,7 +99,7 @@ class singleCleaner(threading.Thread, StoppableThread): # 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') + output = open(state.appdata + 'knownnodes.dat', 'wb') try: pickle.dump(shared.knownNodes, output) output.close() @@ -116,7 +117,7 @@ class singleCleaner(threading.Thread, StoppableThread): 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 neededPubkeys[ + del state.neededPubkeys[ address] # We need to take this entry out of the 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 diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 94dc0f9a..c27a9cbb 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -165,7 +165,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += pubEncryptionKey[1:] # Do the POW for this pubkey message - target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -255,7 +255,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += signature # Do the POW for this pubkey message - target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -345,7 +345,7 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt, hexlify(pubEncryptionKey)) # Do the POW for this pubkey message - target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -466,7 +466,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += highlevelcrypto.encrypt( dataToEncrypt, hexlify(pubEncryptionKey)) - target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For broadcast message) Doing proof of work...') shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast...")))) @@ -659,8 +659,8 @@ class singleWorker(threading.Thread, StoppableThread): # Let us fetch the amount of work required by the recipient. if toAddressVersionNumber == 2: - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nThere is no required difficulty for version 2 addresses like this.")))) elif toAddressVersionNumber >= 3: @@ -670,13 +670,13 @@ class singleWorker(threading.Thread, StoppableThread): requiredPayloadLengthExtraBytes, varintLength = decodeVarint( pubkeyPayload[readPosition:readPosition + 10]) readPosition += varintLength - 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 + if requiredAverageProofOfWorkNonceTrialsPerByte < protocol.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 = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + if requiredPayloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes logger.debug('Using averageProofOfWorkNonceTrialsPerByte: %s and payloadLengthExtraBytes: %s.' % (requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes)) shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("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))))) + requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / protocol.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): # The demanded difficulty is more than we are willing @@ -684,8 +684,8 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', ackdata) - shared.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) / shared.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( - requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) + shared.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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( + requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. logger.info('Sending a message.') @@ -703,8 +703,8 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58)) pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( privEncryptionKeyHex))[1:] - requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes + requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) @@ -747,9 +747,9 @@ class singleWorker(threading.Thread, StoppableThread): # the receiver is in any of those lists. if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress): payload += encodeVarint( - shared.networkDefaultProofOfWorkNonceTrialsPerByte) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte) payload += encodeVarint( - shared.networkDefaultPayloadLengthExtraBytes) + protocol.networkDefaultPayloadLengthExtraBytes) else: payload += encodeVarint(BMConfigParser().getint( fromaddress, 'noncetrialsperbyte')) @@ -790,7 +790,7 @@ 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) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes) + logger.info('(For msg message) Doing proof of work. Total required difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() @@ -913,7 +913,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.')))) - target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.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)) @@ -966,7 +966,7 @@ class singleWorker(threading.Thread, StoppableThread): 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)))) + target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For ack message) Doing proof of work. TTL set to ' + str(TTL)) powStartTime = time.time() diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 320f6315..2beb50dc 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -8,7 +8,9 @@ import sys import os from debug import logger from namecoin import ensureNamecoinOptions +import paths import random +import state import string import tr#anslate @@ -23,7 +25,7 @@ class sqlThread(threading.Thread): threading.Thread.__init__(self, name="SQL") def run(self): - self.conn = sqlite3.connect(shared.appdata + 'messages.dat') + self.conn = sqlite3.connect(state.appdata + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() @@ -112,9 +114,9 @@ class sqlThread(threading.Thread): if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - shared.networkDefaultPayloadLengthExtraBytes)) + protocol.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: @@ -235,8 +237,8 @@ class sqlThread(threading.Thread): # 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')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte: - shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) + """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == protocol.networkDefaultProofOfWorkNonceTrialsPerByte: + shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) """ BMConfigParser().set('bitmessagesettings', 'settingsversion', '7') @@ -302,8 +304,8 @@ class sqlThread(threading.Thread): # 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(shared.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(shared.networkDefaultPayloadLengthExtraBytes)) + BMConfigParser().set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(protocol.networkDefaultPayloadLengthExtraBytes)) previousTotalDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / 320 previousSmallMessageDifficulty = int(BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / 14000 BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(previousTotalDifficulty * 1000)) @@ -331,9 +333,9 @@ class sqlThread(threading.Thread): # sanity check if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * protocol.networkDefaultPayloadLengthExtraBytes)) # 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. @@ -507,8 +509,8 @@ class sqlThread(threading.Thread): os._exit(0) self.conn.close() shutil.move( - shared.lookupAppdataFolder() + 'messages.dat', shared.lookupExeFolder() + 'messages.dat') - self.conn = sqlite3.connect(shared.lookupExeFolder() + 'messages.dat') + paths.lookupAppdataFolder() + 'messages.dat', paths.lookupExeFolder() + 'messages.dat') + self.conn = sqlite3.connect(paths.lookupExeFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'movemessagstoappdata': @@ -523,8 +525,8 @@ class sqlThread(threading.Thread): os._exit(0) self.conn.close() shutil.move( - shared.lookupExeFolder() + 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') - self.conn = sqlite3.connect(shared.lookupAppdataFolder() + 'messages.dat') + paths.lookupExeFolder() + 'messages.dat', paths.lookupAppdataFolder() + 'messages.dat') + self.conn = sqlite3.connect(paths.lookupAppdataFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'deleteandvacuume': diff --git a/src/debug.py b/src/debug.py index cdf8d8cb..24e43332 100644 --- a/src/debug.py +++ b/src/debug.py @@ -23,6 +23,7 @@ import shared import sys import traceback import helper_startup +import state helper_startup.loadConfig() # Now can be overriden from a config file, which uses standard python logging.config.fileConfig interface @@ -36,12 +37,12 @@ def log_uncaught_exceptions(ex_cls, ex, tb): def configureLogging(): have_logging = False try: - logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) + logging.config.fileConfig(os.path.join (state.appdata, 'logging.dat')) have_logging = True - print "Loaded logger configuration from %s" % (os.path.join(shared.appdata, 'logging.dat')) + print "Loaded logger configuration from %s" % (os.path.join(state.appdata, 'logging.dat')) except: - if os.path.isfile(os.path.join(shared.appdata, 'logging.dat')): - print "Failed to load logger configuration from %s, using default logging config" % (os.path.join(shared.appdata, 'logging.dat')) + 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 @@ -70,7 +71,7 @@ def configureLogging(): 'class': 'logging.handlers.RotatingFileHandler', 'formatter': 'default', 'level': log_level, - 'filename': shared.appdata + 'debug.log', + 'filename': state.appdata + 'debug.log', 'maxBytes': 2097152, # 2 MiB 'backupCount': 1, 'encoding': 'UTF-8', diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 44bd190a..4acf7105 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -7,12 +7,13 @@ import time from configparser import BMConfigParser from debug import logger import socks +import state def knownNodes(): try: # 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') + pickleFile = open(state.appdata + 'knownnodes.dat', 'rb') loadedKnownNodes = pickle.load(pickleFile) pickleFile.close() # The old format of storing knownNodes was as a 'host: (port, time)' @@ -28,7 +29,7 @@ def knownNodes(): peer, lastseen = node_tuple shared.knownNodes[stream][peer] = lastseen except: - shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(shared.appdata) + shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata) # your own onion address, if setup if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) diff --git a/src/helper_startup.py b/src/helper_startup.py index d685882e..c0f84635 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -10,6 +10,8 @@ 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. @@ -25,31 +27,31 @@ def _loadTrustedPeer(): shared.trustedPeer = shared.Peer(host, int(port)) def loadConfig(): - if shared.appdata: - BMConfigParser().read(shared.appdata + 'keys.dat') - #shared.appdata must have been specified as a startup option. + if state.appdata: + BMConfigParser().read(state.appdata + 'keys.dat') + #state.appdata must have been specified as a startup option. try: BMConfigParser().get('bitmessagesettings', 'settingsversion') - print 'Loading config files from directory specified on startup: ' + shared.appdata + print 'Loading config files from directory specified on startup: ' + state.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True else: - BMConfigParser().read(shared.lookupExeFolder() + 'keys.dat') + BMConfigParser().read(paths.lookupExeFolder() + 'keys.dat') try: BMConfigParser().get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False - shared.appdata = shared.lookupExeFolder() + state.appdata = paths.lookupExeFolder() except: # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. - shared.appdata = shared.lookupAppdataFolder() - BMConfigParser().read(shared.appdata + 'keys.dat') + state.appdata = paths.lookupAppdataFolder() + BMConfigParser().read(state.appdata + 'keys.dat') try: BMConfigParser().get('bitmessagesettings', 'settingsversion') - print 'Loading existing config files from', shared.appdata + print 'Loading existing config files from', state.appdata needToCreateKeysFile = False except: needToCreateKeysFile = True @@ -90,9 +92,9 @@ def loadConfig(): BMConfigParser().set( 'bitmessagesettings', 'messagesencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - shared.networkDefaultPayloadLengthExtraBytes)) + protocol.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') @@ -127,12 +129,12 @@ def loadConfig(): if storeConfigFilesInSameDirectoryAsProgramByDefault: # Just use the same directory as the program and forget about # the appdata folder - shared.appdata = '' + state.appdata = '' print 'Creating new config files in same directory as program.' else: - print 'Creating new config files in', shared.appdata - if not os.path.exists(shared.appdata): - os.makedirs(shared.appdata) + print 'Creating new config files in', state.appdata + if not os.path.exists(state.appdata): + os.makedirs(state.appdata) if not sys.platform.startswith('win'): os.umask(0o077) shared.writeKeysFile() diff --git a/src/l10n.py b/src/l10n.py index f8b72650..31df0656 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -4,7 +4,6 @@ import os import time from configparser import BMConfigParser -import shared #logger = logging.getLogger(__name__) diff --git a/src/message_data_reader.py b/src/message_data_reader.py index a99be336..0c38a291 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -6,10 +6,11 @@ import sqlite3 from time import strftime, localtime import sys import shared +import state import string from binascii import hexlify -appdata = shared.lookupAppdataFolder() +appdata = paths.lookupAppdataFolder() conn = sqlite3.connect( appdata + 'messages.dat' ) conn.text_factory = str diff --git a/src/network/https.py b/src/network/https.py index 9744a6dc..151efcb8 100644 --- a/src/network/https.py +++ b/src/network/https.py @@ -1,9 +1,10 @@ import asyncore from http import HTTPClient +import paths from tls import TLSHandshake -# self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') +# 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): diff --git a/src/openclpow.py b/src/openclpow.py index 766cbffe..7181c077 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -6,7 +6,8 @@ import random import os from configparser import BMConfigParser -from shared import codePath, shutdown +import paths +from shared import shutdown from debug import logger libAvailable = True @@ -40,7 +41,7 @@ def initCL(): if (len(enabledGpus) > 0): ctx = cl.Context(devices=enabledGpus) queue = cl.CommandQueue(ctx) - f = open(os.path.join(codePath(), "bitmsghash", 'bitmsghash.cl'), 'r') + 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") diff --git a/src/paths.py b/src/paths.py new file mode 100644 index 00000000..6b0baf15 --- /dev/null +++ b/src/paths.py @@ -0,0 +1,70 @@ +from os import environ, path +import sys + +# 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 [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 codePath(): + if frozen == "macosx_app": + codePath = environ.get("RESOURCEPATH") + elif frozen: # windows + codePath = sys._MEIPASS + else: + codePath = path.dirname(__file__) + return codePath + diff --git a/src/proofofwork.py b/src/proofofwork.py index 244f268c..ca48e28b 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -8,6 +8,7 @@ import sys import time from configparser import BMConfigParser from debug import logger +import paths import shared import openclpow import tr @@ -169,15 +170,15 @@ def buildCPoW(): if bmpow is not None: return - if shared.frozen is not None: + if paths.frozen is not None: notifyBuild(False) return if sys.platform in ["win32", "win64"]: notifyBuild(False) return try: - call(["make", "-C", os.path.join(shared.codePath(), "bitmsghash")]) - if os.path.exists(os.path.join(shared.codePath(), "bitmsghash", "bitmsghash.so")): + 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: @@ -208,7 +209,7 @@ def run(target, initialHash): raise except: pass # fallback - if shared.frozen == "macosx_app" or not shared.frozen: + 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 @@ -238,7 +239,7 @@ def init(): bitmsglib = 'bitmsghash64.dll' try: # MSVS - bso = ctypes.WinDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) + 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 @@ -248,7 +249,7 @@ def init(): logger.error("C PoW test fail.", exc_info=True) try: # MinGW - bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) + 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 @@ -259,7 +260,7 @@ def init(): bso = None else: try: - bso = ctypes.CDLL(os.path.join(shared.codePath(), "bitmsghash", bitmsglib)) + bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) logger.info("Loaded C PoW DLL %s", bitmsglib) except: bso = None diff --git a/src/protocol.py b/src/protocol.py index ecc0f8cc..cb6726e3 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -1,4 +1,5 @@ import base64 +from binascii import hexlify import hashlib import random import socket @@ -7,9 +8,13 @@ from struct import pack, unpack, Struct import sys import time -from addresses import encodeVarint, decodeVarint +from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError from configparser import BMConfigParser -from state import neededPubkeys, extPort, socksIP +from debug import logger +from helper_sql import sqlExecute +import highlevelcrypto +from inventory import Inventory +import state from version import softwareVersion #Service flags @@ -22,6 +27,10 @@ BITFIELD_DOESACK = 1 eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( '>Q', random.randrange(1, 18446744073709551615)) +#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. + #Compiled struct for packing/unpacking headers #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') @@ -79,11 +88,26 @@ def sslProtocolVersion(): def checkSocksIP(host): try: - if socksIP is None or not socksIP: - socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + if state.socksIP is None or not state.socksIP: + state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) except NameError: - socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) - return socksIP == host + state.socksIP = socket.gethostbyname(BMConfigParser().get("bitmessagesettings", "sockshostname")) + return state.socksIP == host + +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)))) # Packet creation @@ -117,10 +141,10 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = Fals # we have a separate extPort and # incoming over clearnet or # outgoing through clearnet - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and extPort \ + 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', extPort) + 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 @@ -178,7 +202,7 @@ def decryptAndCheckPubkeyPayload(data, address): encryptedData = data[readPosition:] # Let us try to decrypt the pubkey - toAddress, cryptorObject = neededPubkeys[tag] + 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. @@ -308,7 +332,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return @@ -331,7 +355,7 @@ def _checkAndShareMsgWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength @@ -362,7 +386,7 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += addressVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 10]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength @@ -393,7 +417,7 @@ def _checkAndSharePubkeyWithPeers(data): streamNumber, varintLength = decodeVarint( data[readPosition:readPosition + 10]) readPosition += varintLength - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if addressVersion >= 4: @@ -430,7 +454,7 @@ def _checkAndShareBroadcastWithPeers(data): if broadcastVersion >= 2: streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) readPosition += streamNumberLength - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if broadcastVersion >= 3: @@ -452,3 +476,10 @@ def _checkAndShareBroadcastWithPeers(data): # 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) diff --git a/src/shared.py b/src/shared.py index 7f8aca53..d55b3b78 100644 --- a/src/shared.py +++ b/src/shared.py @@ -8,14 +8,11 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. -import base64 import collections import os import pickle import Queue -import random from multiprocessing import active_children, Queue as mpQueue, Lock as mpLock -import socket import sys import stat import threading @@ -36,6 +33,8 @@ import shared from helper_sql import * from helper_threading import * from inventory import Inventory +import protocol +import state myECCryptorObjects = {} @@ -52,9 +51,7 @@ parserLock = mpLock() addressGeneratorQueue = Queue.Queue() knownNodesLock = threading.Lock() knownNodes = {} -sendDataQueues = [] #each sendData thread puts its queue in this list. printLock = threading.Lock() -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. shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. @@ -86,27 +83,17 @@ daemon = False needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. -streamsInWhichIAmParticipating = {} timeOffsetWrongCount = 0 # sanity check, prevent doing ridiculous PoW # 20 million PoWs equals approximately 2 days on dev's dual R9 290 ridiculousDifficulty = 20000000 -#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 @@ -119,68 +106,6 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = 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 [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 codePath(): - if frozen == "macosx_app": - codePath = os.environ.get("RESOURCEPATH") - elif frozen: # windows - codePath = sys._MEIPASS - else: - codePath = os.path.dirname(__file__) - return codePath - def isAddressInMyAddressBook(address): queryreturn = sqlQuery( '''select address from addressbook where address=?''', @@ -236,7 +161,7 @@ def reloadMyAddressHashes(): myAddressesByTag.clear() #myPrivateKeys.clear() - keyfileSecure = checkSensitiveFilePermissions(appdata + 'keys.dat') + keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') configSections = BMConfigParser().sections() hasEnabledKeys = False for addressInKeysFile in configSections: @@ -262,7 +187,7 @@ def reloadMyAddressHashes(): logger.error('Error in reloadMyAddressHashes: Can\'t handle address versions other than 2, 3, or 4.\n') if not keyfileSecure: - fixSensitiveFilePermissions(appdata + 'keys.dat', hasEnabledKeys) + fixSensitiveFilePermissions(state.appdata + 'keys.dat', hasEnabledKeys) def reloadBroadcastSendersForWhichImWatching(): broadcastSendersForWhichImWatching.clear() @@ -286,21 +211,6 @@ def reloadBroadcastSendersForWhichImWatching(): privEncryptionKey = doubleHashOfAddressData[:32] MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) -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, thisapp shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. @@ -308,7 +218,7 @@ def doCleanShutdown(): parserInputQueue.put(None, False) except Queue.Full: pass - broadcastToSendDataQueues((0, 'shutdown', 'no data')) + protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): @@ -316,7 +226,7 @@ def doCleanShutdown(): knownNodesLock.acquire() UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) - output = open(appdata + 'knownnodes.dat', 'wb') + output = open(state.appdata + 'knownnodes.dat', 'wb') logger.info('finished opening knownnodes.dat. Now pickle.dump') pickle.dump(knownNodes, output) logger.info('Completed pickle.dump. Closing output...') @@ -359,14 +269,6 @@ def doCleanShutdown(): else: logger.info('Core shutdown complete.') -# 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 fixPotentiallyInvalidUTF8Data(text): try: unicode(text,'utf-8') @@ -554,7 +456,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 isProofOfWorkSufficient(data): + if not protocol.isProofOfWorkSufficient(data): logger.info('Proof of work is insufficient.') return 0 @@ -597,7 +499,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return @@ -609,7 +511,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) def _checkAndShareMsgWithPeers(data): @@ -620,7 +522,7 @@ def _checkAndShareMsgWithPeers(data): readPosition += objectVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 9]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength @@ -633,7 +535,7 @@ def _checkAndShareMsgWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) - broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. objectProcessorQueue.put((objectType,data)) @@ -651,7 +553,7 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += addressVersionLength streamNumber, streamNumberLength = decodeVarint( data[readPosition:readPosition + 10]) - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return readPosition += streamNumberLength @@ -666,7 +568,7 @@ def _checkAndShareGetpubkeyWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. objectProcessorQueue.put((objectType,data)) @@ -682,7 +584,7 @@ def _checkAndSharePubkeyWithPeers(data): streamNumber, varintLength = decodeVarint( data[readPosition:readPosition + 10]) readPosition += varintLength - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if addressVersion >= 4: @@ -700,7 +602,7 @@ def _checkAndSharePubkeyWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. @@ -719,7 +621,7 @@ def _checkAndShareBroadcastWithPeers(data): if broadcastVersion >= 2: streamNumber, streamNumberLength = decodeVarint(data[readPosition:readPosition + 10]) readPosition += streamNumberLength - if not streamNumber in streamsInWhichIAmParticipating: + if not streamNumber in state.streamsInWhichIAmParticipating: logger.debug('The streamNumber %s isn\'t one we are interested in.' % streamNumber) return if broadcastVersion >= 3: @@ -736,19 +638,19 @@ def _checkAndShareBroadcastWithPeers(data): 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)) + protocol.broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. objectProcessorQueue.put((objectType,data)) def openKeysFile(): if 'linux' in sys.platform: - subprocess.call(["xdg-open", shared.appdata + 'keys.dat']) + subprocess.call(["xdg-open", state.appdata + 'keys.dat']) else: - os.startfile(shared.appdata + 'keys.dat') + os.startfile(state.appdata + 'keys.dat') def writeKeysFile(): - fileName = shared.appdata + 'keys.dat' + fileName = 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: diff --git a/src/singleinstance.py b/src/singleinstance.py index 8bf7ed01..1fd2ff20 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -6,6 +6,7 @@ from multiprocessing import Process import os import sys import shared +import state try: import fcntl # @UnresolvedImport @@ -24,7 +25,7 @@ class singleinstance: self.counter = 0 self.daemon = daemon self.lockPid = None - self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) + self.lockfile = os.path.normpath(os.path.join(state.appdata, 'singleton%s.lock' % flavor_id)) if not self.daemon and not shared.curses: # Tells the already running (if any) application to get focus. diff --git a/src/state.py b/src/state.py index e3ff6289..f3fb8a53 100644 --- a/src/state.py +++ b/src/state.py @@ -1,7 +1,14 @@ neededPubkeys = {} +streamsInWhichIAmParticipating = {} +sendDataQueues = [] #each sendData thread puts its queue in this list. # For UPnP extPort = None # for Tor hidden service socksIP = None + +# Network protocols last check failed +networkProtocolLastFailed = {'IPv4': 0, 'IPv6': 0, 'onion': 0} + +appdata = '' #holds the location of the application data storage directory diff --git a/src/tr.py b/src/tr.py index b7a8e6f0..5146a162 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,7 +1,6 @@ import os from configparser import BMConfigParser -import shared # 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: -- 2.45.1 From fa0a3135e78d033530cd48a5048262b97cebe50b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:26:25 +0100 Subject: [PATCH 0543/1102] Fixes pointed out by landscape.io - missing/wrong/obsolete imports - logger formatting --- src/api.py | 1 + src/bitmessagemain.py | 1 + src/bitmessageqt/support.py | 1 + src/bitmessageqt/utils.py | 1 - src/class_addressGenerator.py | 1 + src/class_sqlThread.py | 1 + src/debug.py | 1 - src/helper_startup.py | 1 + src/message_data_reader.py | 2 +- src/paths.py | 6 +++--- src/protocol.py | 39 +++++++++++++++++------------------ src/shared.py | 2 +- 12 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/api.py b/src/api.py index a3c80283..18b2dd20 100644 --- a/src/api.py +++ b/src/api.py @@ -24,6 +24,7 @@ import helper_inbox import helper_sent import hashlib +import protocol import state from pyelliptic.openssl import OpenSSL from struct import pack diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 5c41e4e5..cd7205e8 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -29,6 +29,7 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import shared from helper_sql import sqlQuery import state +import protocol import threading # Classes diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index aae5134f..07d0ab3a 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -13,6 +13,7 @@ from l10n import getTranslationLanguage from openclpow import openclAvailable, openclEnabled import paths from proofofwork import bmpow +import protocol from pyelliptic.openssl import OpenSSL import shared import state diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 1a5b67d7..fd18183d 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -1,7 +1,6 @@ from PyQt4 import QtGui import hashlib import os -import shared from addresses import addBMIfNotPresent from configparser import BMConfigParser import state diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index ff5eb25e..ebedf2f9 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -10,6 +10,7 @@ from addresses import * from configparser import BMConfigParser from debug import logger from helper_threading import * +import protocol from pyelliptic import arithmetic import tr from binascii import hexlify diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 2beb50dc..df747aea 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -9,6 +9,7 @@ import os from debug import logger from namecoin import ensureNamecoinOptions import paths +import protocol import random import state import string diff --git a/src/debug.py b/src/debug.py index 24e43332..663bbeeb 100644 --- a/src/debug.py +++ b/src/debug.py @@ -19,7 +19,6 @@ 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 traceback import helper_startup diff --git a/src/helper_startup.py b/src/helper_startup.py index c0f84635..86d3de42 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -11,6 +11,7 @@ from distutils.version import StrictVersion from namecoin import ensureNamecoinOptions import paths +import protocol 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. diff --git a/src/message_data_reader.py b/src/message_data_reader.py index 0c38a291..79a3a607 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -6,8 +6,8 @@ import sqlite3 from time import strftime, localtime import sys import shared +import paths import state -import string from binascii import hexlify appdata = paths.lookupAppdataFolder() diff --git a/src/paths.py b/src/paths.py index 6b0baf15..e92116c0 100644 --- a/src/paths.py +++ b/src/paths.py @@ -23,11 +23,11 @@ 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 + if dataFolder[-1] not in [path.sep, path.altsep]: + dataFolder += path.sep elif sys.platform == 'darwin': if "HOME" in environ: - dataFolder = path.join(os.environ["HOME"], "Library/Application Support/", APPNAME) + '/' + 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(): diff --git a/src/protocol.py b/src/protocol.py index cb6726e3..cf0d65d4 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -204,7 +204,7 @@ def decryptAndCheckPubkeyPayload(data, address): # 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)) + 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' @@ -260,12 +260,11 @@ def decryptAndCheckPubkeyPayload(data, address): logger.info('within decryptAndCheckPubkeyPayload, addressVersion: %s, streamNumber: %s \n\ ripe %s\n\ publicSigningKey in hex: %s\n\ - publicEncryptionKey in hex: %s' % (addressVersion, + publicEncryptionKey in hex: %s', addressVersion, streamNumber, hexlify(ripe), hexlify(publicSigningKey), hexlify(publicEncryptionKey) - ) ) t = (address, addressVersion, storedData, int(time.time()), 'yes') @@ -275,7 +274,7 @@ def decryptAndCheckPubkeyPayload(data, address): 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()) + 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): @@ -286,7 +285,7 @@ def checkAndShareObjectWithPeers(data): 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)) + 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): @@ -295,10 +294,10 @@ def checkAndShareObjectWithPeers(data): 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) + 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) + 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: @@ -318,9 +317,9 @@ def checkAndShareObjectWithPeers(data): _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) + 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()) + 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 @@ -333,7 +332,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return inventoryHash = calculateInventoryHash(data) @@ -343,7 +342,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): objectType, = unpack('>I', data[16:20]) Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -356,7 +355,7 @@ def _checkAndShareMsgWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) @@ -367,7 +366,7 @@ def _checkAndShareMsgWithPeers(data): objectType = 2 Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. @@ -387,7 +386,7 @@ def _checkAndShareGetpubkeyWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return readPosition += streamNumberLength @@ -400,7 +399,7 @@ def _checkAndShareGetpubkeyWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') # This getpubkey request is valid. Forward to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. @@ -418,11 +417,11 @@ def _checkAndSharePubkeyWithPeers(data): 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) + 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', hexlify(tag)) else: tag = '' @@ -434,7 +433,7 @@ def _checkAndSharePubkeyWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -455,7 +454,7 @@ def _checkAndShareBroadcastWithPeers(data): 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) + logger.debug('The streamNumber %s isn\'t one we are interested in.', streamNumber) return if broadcastVersion >= 3: tag = data[readPosition:readPosition+32] @@ -470,7 +469,7 @@ def _checkAndShareBroadcastWithPeers(data): Inventory()[inventoryHash] = ( objectType, streamNumber, data, embeddedTime, tag) # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) + logger.debug('advertising inv with hash: %s', hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. diff --git a/src/shared.py b/src/shared.py index d55b3b78..11058fd7 100644 --- a/src/shared.py +++ b/src/shared.py @@ -19,7 +19,6 @@ import threading import time import shutil # used for moving the data folder and copying keys.dat import datetime -from os import path, environ import traceback from binascii import hexlify @@ -645,6 +644,7 @@ def _checkAndShareBroadcastWithPeers(data): def openKeysFile(): if 'linux' in sys.platform: + import subprocess subprocess.call(["xdg-open", state.appdata + 'keys.dat']) else: os.startfile(state.appdata + 'keys.dat') -- 2.45.1 From cdcdf11d59d47d4c21eb21dce12f5fb3b46e6dc3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 17:46:33 +0100 Subject: [PATCH 0544/1102] Missing import fix --- src/protocol.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/protocol.py b/src/protocol.py index cf0d65d4..970b63b0 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -7,6 +7,7 @@ import ssl from struct import pack, unpack, Struct import sys import time +import traceback from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError from configparser import BMConfigParser -- 2.45.1 From c738d93056b0f1b04c723ab5ac3bc82a9521fc37 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 18:13:00 +0100 Subject: [PATCH 0545/1102] Assorted fixes - landscape.io was complaining, this fixes most easily fixable errors --- src/bitmessageqt/__init__.py | 12 ++---------- src/bitmessageqt/account.py | 8 ++++---- src/bitmessageqt/blacklist.py | 1 - src/bitmessageqt/newaddresswizard.py | 10 +++++----- src/class_objectHashHolder.py | 1 - src/class_receiveDataThread.py | 4 ++-- src/class_smtpDeliver.py | 1 + src/class_smtpServer.py | 3 ++- src/openclpow.py | 4 ---- src/proofofwork.py | 3 +-- src/shared.py | 2 +- src/upnp.py | 15 ++++++++------- 12 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 91424c86..008647ab 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -19,6 +19,7 @@ try: 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) + import sys sys.exit() try: @@ -1214,8 +1215,6 @@ class MyForm(settingsmixin.SMainWindow): # 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 @@ -1315,8 +1314,6 @@ class MyForm(settingsmixin.SMainWindow): # 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 @@ -1440,14 +1437,11 @@ class MyForm(settingsmixin.SMainWindow): # initialise the message notifier def notifierInit(self): - 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: @@ -1642,7 +1636,6 @@ class MyForm(settingsmixin.SMainWindow): connected = False def setStatusIcon(self, color): - global withMessagingMenu # print 'setting status icon color' if color == 'red': self.pushButtonStatusIcon.setIcon( @@ -3057,7 +3050,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want."), 10000) - def deleteRowFromMessagelist(row = None, inventoryHash = None, ackData = None, messageLists = None): + 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): @@ -4447,7 +4440,6 @@ class MySingleApplication(QApplication): self.server.close() def on_new_connection(self): - global myapp if myapp: myapp.appIndicatorShow() diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 6e830b38..bdfeaed3 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -147,7 +147,7 @@ class GatewayAccount(BMAccount): ALL_OK = 0 REGISTRATION_DENIED = 1 def __init__(self, address): - super(BMAccount, self).__init__(address) + super(GatewayAccount, self).__init__(address) def send(self): status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) @@ -175,7 +175,7 @@ class GatewayAccount(BMAccount): shared.workerQueue.put(('sendmessage', self.toAddress)) def parseMessage(self, toAddress, fromAddress, subject, message): - super(BMAccount, self).parseMessage(toAddress, fromAddress, subject, message) + super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) class MailchuckAccount(GatewayAccount): # set "gateway" in keys.dat to this @@ -186,7 +186,7 @@ class MailchuckAccount(GatewayAccount): regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") regExpOutgoing = re.compile("(\S+) (.*)") def __init__(self, address): - super(GatewayAccount, self).__init__(address) + super(MailchuckAccount, self).__init__(address) self.feedback = self.ALL_OK def createMessage(self, toAddress, fromAddress, subject, message): @@ -262,7 +262,7 @@ class MailchuckAccount(GatewayAccount): self.fromAddress = self.address def parseMessage(self, toAddress, fromAddress, subject, message): - super(GatewayAccount, self).parseMessage(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: diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 6fcb8f11..94844da5 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -2,7 +2,6 @@ from PyQt4 import QtCore, QtGui import shared from tr import _translate import l10n -from uisignaler import UISignaler import widgets from addresses import addBMIfNotPresent from configparser import BMConfigParser diff --git a/src/bitmessageqt/newaddresswizard.py b/src/bitmessageqt/newaddresswizard.py index e54b18c3..2311239c 100644 --- a/src/bitmessageqt/newaddresswizard.py +++ b/src/bitmessageqt/newaddresswizard.py @@ -316,19 +316,19 @@ class NewAddressThread(QtCore.QThread): def __del__(self): self.wait() - def createDeterministic(): + def createDeterministic(self): pass - def createPassphrase(): + def createPassphrase(self): pass - def broadcastAddress(): + def broadcastAddress(self): pass - def registerMailchuck(): + def registerMailchuck(self): pass - def waitRegistration(): + def waitRegistration(self): pass def run(self): diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 24c2438d..2e456d8c 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -41,7 +41,6 @@ class objectHashHolder(threading.Thread): def hasHash(self, hash): if hash in (hashlist for hashlist in self.collectionOfHashLists): - logger.debug("Hash in hashHolder") return True return False diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index cf43f7b3..3112575a 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -270,9 +270,9 @@ class receiveDataThread(threading.Thread): self.processData() - def sendpong(self): + def sendpong(self, payload): logger.debug('Sending pong') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong'))) + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('pong', payload))) def recverack(self): diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index ca51946f..18206065 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -8,6 +8,7 @@ import urlparse from configparser import BMConfigParser from debug import logger from helper_threading import * +from bitmessageqt.uisignaler import UISignaler import shared SMTPDOMAIN = "bmaddr.lan" diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 4043600c..65a7e1fc 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -6,6 +6,7 @@ from email.header import decode_header import re import signal import smtpd +import socket import threading import time @@ -43,7 +44,7 @@ class smtpServerChannel(smtpd.SMTPChannel): self.auth = True self.push('235 2.7.0 Authentication successful') else: - raise Error("Auth fail") + raise Exception("Auth fail") except: self.push('501 Authentication fail') diff --git a/src/openclpow.py b/src/openclpow.py index 7181c077..001333e5 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -53,16 +53,12 @@ def initCL(): enabledGpus = [] def openclAvailable(): - global gpus return (len(gpus) > 0) def openclEnabled(): - global enabledGpus return (len(enabledGpus) > 0) def do_opencl_pow(hash, target): - global ctx, queue, program, enabledGpus, hash_dt - output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) if (len(enabledGpus) == 0): return output[0][0] diff --git a/src/proofofwork.py b/src/proofofwork.py index ca48e28b..78188777 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -19,8 +19,7 @@ bitmsglib = 'bitmsghash.so' def _set_idle(): if 'linux' in sys.platform: - import os - os.nice(20) # @UndefinedVariable + os.nice(20) else: try: sys.getwindowsversion() diff --git a/src/shared.py b/src/shared.py index 11058fd7..d5438b1c 100644 --- a/src/shared.py +++ b/src/shared.py @@ -211,7 +211,7 @@ def reloadBroadcastSendersForWhichImWatching(): MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) def doCleanShutdown(): - global shutdown, thisapp + global shutdown shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. try: parserInputQueue.put(None, False) diff --git a/src/upnp.py b/src/upnp.py index fd6f3852..69f89233 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -11,7 +11,7 @@ from helper_threading import * import shared import tr -def createRequestXML(service, action, arguments=[]): +def createRequestXML(service, action, arguments=None): from xml.dom.minidom import Document doc = Document() @@ -37,11 +37,12 @@ def createRequestXML(service, action, arguments=[]): # iterate over arguments, create nodes, create text nodes, # append text nodes to nodes, and finally add the ready product # to argument_list - 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) + 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) # append the prepared argument nodes to the function element for arg in argument_list: @@ -140,7 +141,7 @@ class Router: dom = parseString(resp) return dom.getElementsByTagName('NewExternalIPAddress')[0].childNodes[0].data - def soapRequest(self, service, action, arguments=[]): + def soapRequest(self, service, action, arguments=None): from xml.dom.minidom import parseString from debug import logger conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) -- 2.45.1 From 5ceb920bd69b2abbe125be44a3b46e82d3494a93 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 20:47:27 +0100 Subject: [PATCH 0546/1102] TLS tuning - allow TLS > 1.0 with python >= 2.7.9 - tune ssl_context with python >= 2.7.9 --- src/class_receiveDataThread.py | 14 +++++++++++--- src/network/tls.py | 15 +++++++++++++-- src/protocol.py | 24 ++++++++++++++---------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 3112575a..3ce3b35e 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -293,9 +293,17 @@ class receiveDataThread(threading.Thread): if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") - 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') - if hasattr(self.sslSock, "context"): - self.sslSock.context.set_ecdh_curve("secp256k1") + if sys.version_info >= (2,7,9): + context = ssl.create_default_context(purpose = ssl.Purpose.CLIENT_AUTH if self.initiatedConnection else ssl.Purpose.SERVER_AUTH) + context.set_ciphers("AECDH-AES256-SHA") + 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_NO_SSLv2 | ssl.OP_NO_SSLv3 + 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='AECDH-AES256-SHA') while True: try: self.sslSock.do_handshake() diff --git a/src/network/tls.py b/src/network/tls.py index f690acc9..855bcd93 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -6,6 +6,7 @@ import asyncore import socket import ssl +import protocol class TLSHandshake(asyncore.dispatcher): """ @@ -42,9 +43,19 @@ class TLSHandshake(asyncore.dispatcher): def handle_connect(self): # Once the connection has been established, it's safe to wrap the # socket. - self.sslSocket = ssl.wrap_socket(self.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(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_NOSSLv2 | ssl.OP_NOSSLv3 + self.sslSock = context.wrap_socket(self.sock, 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=ssl.PROTOCOL_TLSv1, + ssl_version=protocol.sslProtocolVersion, certfile=self.certfile, keyfile=self.keyfile, ciphers=self.ciphers, diff --git a/src/protocol.py b/src/protocol.py index 970b63b0..da0cd3aa 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -77,16 +77,6 @@ def haveSSL(server = False): return True return False -def sslProtocolVersion(): - if sys.version_info >= (2,7,13): - # in the future once TLS is mandatory, change this to ssl.PROTOCOL_TLS1.2 - return ssl.PROTOCOL_TLS - elif sys.version_info >= (2,7,9): - # once TLS is mandatory, add "ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1.1" - return ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 - else: - return ssl.PROTOCOL_TLS1 - def checkSocksIP(host): try: if state.socksIP is None or not state.socksIP: @@ -483,3 +473,17 @@ 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 -- 2.45.1 From e7470a4757e39002f3521cee97374a393f7f25c8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 12 Jan 2017 06:57:17 +0100 Subject: [PATCH 0547/1102] Remove leftover from debugging --- src/class_singleWorker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index c27a9cbb..86efbc1a 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -713,7 +713,6 @@ class singleWorker(threading.Thread, StoppableThread): 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 ) - print("Going to do PoW 4") # We need to convert our private keys to public keys in order # to include them. try: -- 2.45.1 From bd520a340f78c1255d6fc6fb1818b4d090174893 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 12 Jan 2017 06:58:35 +0100 Subject: [PATCH 0548/1102] Trustedpeer fix and more refactoring - fixed trustedPeer (thanks to anonymous bug reporter) - moved trustedPeer and Peer into state.py --- src/class_outgoingSynSender.py | 8 ++++---- src/class_receiveDataThread.py | 16 ++++++++-------- src/class_sendDataThread.py | 2 +- src/class_singleListener.py | 4 +++- src/defaultKnownNodes.py | 21 +++++++++++---------- src/helper_bootstrap.py | 12 ++++++------ src/helper_startup.py | 2 +- src/shared.py | 14 -------------- src/state.py | 16 ++++++++++++++++ 9 files changed, 50 insertions(+), 45 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 1754962e..b2e0f984 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -32,9 +32,9 @@ 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 shared.trustedPeer: + if state.trustedPeer: shared.knownNodesLock.acquire() - peer = shared.trustedPeer + peer = state.trustedPeer shared.knownNodes[self.streamNumber][peer] = time.time() shared.knownNodesLock.release() else: @@ -65,7 +65,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): try: return peer except NameError: - return shared.Peer('127.0.0.1', 8444) + return state.Peer('127.0.0.1', 8444) def stopThread(self): super(outgoingSynSender, self).stopThread() @@ -79,7 +79,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.stop.wait(2) while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" - maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 + maximumConnections = 1 if state.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: self.stop.wait(10) if shared.shutdown: diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 3ce3b35e..396b9b8c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -58,7 +58,7 @@ class receiveDataThread(threading.Thread): objectHashHolderInstance): self.sock = sock - self.peer = shared.Peer(HOST, port) + self.peer = state.Peer(HOST, port) self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator self.streamNumber = streamNumber self.objectsThatWeHaveYetToGetFromThisPeer = {} @@ -380,7 +380,7 @@ class receiveDataThread(threading.Thread): # 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 shared.trustedPeer == None: + if sleepTime > 0 and doTimingAttackMitigation and state.trustedPeer == None: logger.debug('Timing attack mitigation: Sleeping for ' + str(sleepTime) + ' seconds.') time.sleep(sleepTime) @@ -450,7 +450,7 @@ class receiveDataThread(threading.Thread): logger.info('inv message doesn\'t contain enough data. Ignoring.') return if numberOfItemsInInv == 1: # we'll just request this data from the person who advertised the object. - if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and state.trustedPeer == None: # inv flooding attack mitigation logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over 1000 from this node in particular. Ignoring this inv message.') return self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ @@ -470,7 +470,7 @@ class receiveDataThread(threading.Thread): objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(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 and shared.trustedPeer == None: # inv flooding attack mitigation + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and state.trustedPeer == None: # inv flooding attack mitigation logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over ' + str(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 @@ -593,7 +593,7 @@ class receiveDataThread(threading.Thread): 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) + peerFromAddrMessage = state.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: @@ -637,7 +637,7 @@ class receiveDataThread(threading.Thread): # if current connection is over a proxy, sent our own onion address at a random position if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \ hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: - peer = shared.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) + peer = state.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) else: # still may contain own onion address, but we don't change it peer, = random.sample(shared.knownNodes[self.streamNumber], 1) @@ -802,9 +802,9 @@ class receiveDataThread(threading.Thread): if not isHostInPrivateIPRange(self.peer.host): with shared.knownNodesLock: - shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) + shared.knownNodes[self.streamNumber][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) if not self.initiatedConnection: - shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours + shared.knownNodes[self.streamNumber][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours shared.needToWriteKnownNodesToDisk = True self.sendverack() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 60babb1f..f6d15c26 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -38,7 +38,7 @@ class sendDataThread(threading.Thread): streamNumber, someObjectsOfWhichThisRemoteNodeIsAlreadyAware): self.sock = sock - self.peer = shared.Peer(HOST, PORT) + self.peer = state.Peer(HOST, PORT) self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator self.streamNumber = streamNumber self.services = 0 diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 896a34bc..0ad82333 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -10,6 +10,8 @@ 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 @@ -60,7 +62,7 @@ class singleListener(threading.Thread, StoppableThread): 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 shared.trustedPeer: + if state.trustedPeer: return while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index f91e6fe6..986fbf6d 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -6,21 +6,22 @@ import random import sys from time import strftime, localtime import shared +import state def createDefaultKnownNodes(appdata): ############## Stream 1 ################ stream1 = {} - #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()) + #stream1[state.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) + stream1[state.Peer('5.45.99.75', 8444)] = int(time.time()) + stream1[state.Peer('75.167.159.54', 8444)] = int(time.time()) + stream1[state.Peer('95.165.168.168', 8444)] = int(time.time()) + stream1[state.Peer('85.180.139.241', 8444)] = int(time.time()) + stream1[state.Peer('158.222.211.81', 8080)] = int(time.time()) + stream1[state.Peer('178.62.12.187', 8448)] = int(time.time()) + stream1[state.Peer('24.188.198.204', 8111)] = int(time.time()) + stream1[state.Peer('109.147.204.113', 1195)] = int(time.time()) + stream1[state.Peer('178.11.46.221', 8444)] = int(time.time()) ############# Stream 2 ################# stream2 = {} diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 4acf7105..5361b9be 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -24,7 +24,7 @@ def knownNodes(): for node_tuple in nodes.items(): try: host, (port, lastseen) = node_tuple - peer = shared.Peer(host, port) + peer = state.Peer(host, port) except: peer, lastseen = node_tuple shared.knownNodes[stream][peer] = lastseen @@ -32,7 +32,7 @@ def knownNodes(): shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata) # your own onion address, if setup if BMConfigParser().has_option('bitmessagesettings', 'onionhostname') and ".onion" in BMConfigParser().get('bitmessagesettings', 'onionhostname'): - shared.knownNodes[1][shared.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) + shared.knownNodes[1][state.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) 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.') raise SystemExit @@ -47,17 +47,17 @@ def dns(): try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) + shared.knownNodes[1][state.Peer(item[4][0], 8080)] = int(time.time()) except: logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') try: for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) + shared.knownNodes[1][state.Peer(item[4][0], 8444)] = int(time.time()) except: logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': - shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) + shared.knownNodes[1][state.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") for port in [8080, 8444]: logger.debug("Resolving %i through SOCKS...", port) @@ -90,7 +90,7 @@ def dns(): else: if ip is not None: logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') - shared.knownNodes[1][shared.Peer(ip, port)] = time.time() + shared.knownNodes[1][state.Peer(ip, port)] = time.time() else: logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') diff --git a/src/helper_startup.py b/src/helper_startup.py index 86d3de42..a07bffb8 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -25,7 +25,7 @@ def _loadTrustedPeer(): return host, port = trustedPeer.split(':') - shared.trustedPeer = shared.Peer(host, int(port)) + state.trustedPeer = state.Peer(host, int(port)) def loadConfig(): if state.appdata: diff --git a/src/shared.py b/src/shared.py index d5438b1c..f67a2d07 100644 --- a/src/shared.py +++ b/src/shared.py @@ -93,18 +93,6 @@ ridiculousDifficulty = 20000000 # namecoin integration to "namecoind". namecoinDefaultRpcPort = "8336" -# 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 - def isAddressInMyAddressBook(address): queryreturn = sqlQuery( '''select address from addressbook where address=?''', @@ -442,8 +430,6 @@ 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 diff --git a/src/state.py b/src/state.py index f3fb8a53..9e546b51 100644 --- a/src/state.py +++ b/src/state.py @@ -1,3 +1,5 @@ +import collections + neededPubkeys = {} streamsInWhichIAmParticipating = {} sendDataQueues = [] #each sendData thread puts its queue in this list. @@ -12,3 +14,17 @@ socksIP = None networkProtocolLastFailed = {'IPv4': 0, 'IPv6': 0, 'onion': 0} appdata = '' #holds the location of the application data storage directory + +# 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 + +Peer = collections.namedtuple('Peer', ['host', 'port']) -- 2.45.1 From 2cf2188bc3abeaa99849db88b55f766cfde56618 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 12 Jan 2017 07:22:34 +0100 Subject: [PATCH 0549/1102] Object sending fix - forgot to move broadcastToSendDataQueues in class_singleWorker.py --- src/class_singleWorker.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 86efbc1a..fc4d324d 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -179,7 +179,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: @@ -269,7 +269,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: @@ -359,7 +359,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateStatusBar', '')) try: @@ -488,7 +488,7 @@ class singleWorker(threading.Thread, StoppableThread): Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) @@ -819,7 +819,7 @@ class singleWorker(threading.Thread, StoppableThread): # not sending to a chan or one of my addresses shared.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)) - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) # Update the sent message in the sent table with the necessary information. @@ -923,7 +923,7 @@ class singleWorker(threading.Thread, StoppableThread): Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') logger.info('sending inv (for the getpubkey message)') - shared.broadcastToSendDataQueues(( + protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) if retryNumber == 0: -- 2.45.1 From 810e50a0409551c5287da983762d964d8455c9ad Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 12 Jan 2017 07:26:04 +0100 Subject: [PATCH 0550/1102] Fix minor issues - landscape.io complained - obsolete imports - ciphers -> self.ciphers --- src/defaultKnownNodes.py | 1 - src/network/tls.py | 3 ++- src/shared.py | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index 986fbf6d..4557c2e9 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -5,7 +5,6 @@ import time import random import sys from time import strftime, localtime -import shared import state def createDefaultKnownNodes(appdata): diff --git a/src/network/tls.py b/src/network/tls.py index 855bcd93..8f104c55 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -5,6 +5,7 @@ SSL/TLS negotiation. import asyncore import socket import ssl +import sys import protocol @@ -45,7 +46,7 @@ class TLSHandshake(asyncore.dispatcher): # 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(ciphers) + context.set_ciphers(self.ciphers) # context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE diff --git a/src/shared.py b/src/shared.py index f67a2d07..f58a1cd6 100644 --- a/src/shared.py +++ b/src/shared.py @@ -8,7 +8,6 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. -import collections import os import pickle import Queue -- 2.45.1 From ff8deebf603d2a8a1f9b12fabe8fe912b9bf14f8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 12 Jan 2017 19:18:56 +0100 Subject: [PATCH 0551/1102] Keep track of network protocol status --- src/bitmessageqt/__init__.py | 1 + src/class_outgoingSynSender.py | 6 +++--- src/class_receiveDataThread.py | 3 +++ src/protocol.py | 8 ++++++++ src/state.py | 10 ++++++++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 008647ab..91d62564 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2364,6 +2364,7 @@ class MyForm(settingsmixin.SMainWindow): "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 self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': BMConfigParser().set('bitmessagesettings', 'socksproxytype', str( self.settingsDialogInstance.ui.comboBoxProxyType.currentText())) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index b2e0f984..ef63d770 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -255,15 +255,15 @@ class outgoingSynSender(threading.Thread, StoppableThread): else: logger.error('SOCKS5 error: %s', str(err)) if err[0][0] == 4 or err[0][0] == 2: - state.networkProtocolLastFailed['IPv6'] = time.time() + state.networkProtocolAvailability[protocol.networkType(peer.host)] = False except socks.Socks4Error as err: logger.error('Socks4Error: ' + str(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)) else: - if ":" in peer.host and err[0] == errno.ENETUNREACH: - state.networkProtocolLastFailed['IPv6'] = time.time() + 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)) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 396b9b8c..5dac4b19 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -333,6 +333,9 @@ class receiveDataThread(threading.Thread): '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 + # Let all of our peers know about this new node. dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) protocol.broadcastToSendDataQueues(( diff --git a/src/protocol.py b/src/protocol.py index da0cd3aa..ae04740b 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -67,6 +67,14 @@ def encodeHost(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' + # checks def haveSSL(server = False): diff --git a/src/state.py b/src/state.py index 9e546b51..f8af54c7 100644 --- a/src/state.py +++ b/src/state.py @@ -10,8 +10,8 @@ extPort = None # for Tor hidden service socksIP = None -# Network protocols last check failed -networkProtocolLastFailed = {'IPv4': 0, 'IPv6': 0, 'onion': 0} +# Network protocols availability, initialised below +networkProtocolAvailability = None appdata = '' #holds the location of the application data storage directory @@ -28,3 +28,9 @@ appdata = '' #holds the location of the application data storage directory trustedPeer = None Peer = collections.namedtuple('Peer', ['host', 'port']) + +def resetNetworkProtocolAvailability(): + global networkProtocolAvailability + networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} + +resetNetworkProtocolAvailability() -- 2.45.1 From 65701e59975ccb199694c3168b61913f9fcc24e4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 09:30:23 +0100 Subject: [PATCH 0552/1102] neededPubkeys fix - was still using shared.neededPubkeys --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index f58a1cd6..54a9e750 100644 --- a/src/shared.py +++ b/src/shared.py @@ -353,7 +353,7 @@ def decryptAndCheckPubkeyPayload(data, address): encryptedData = data[readPosition:] # Let us try to decrypt the pubkey - toAddress, cryptorObject = shared.neededPubkeys[tag] + 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. -- 2.45.1 From 59cf33c9a15a3d449efcb233404b12d119436f46 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 12:01:38 +0100 Subject: [PATCH 0553/1102] Remove obsolete import --- src/shared.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 54a9e750..b185e7e9 100644 --- a/src/shared.py +++ b/src/shared.py @@ -26,7 +26,6 @@ from addresses import * from class_objectProcessorQueue import ObjectProcessorQueue from configparser import BMConfigParser import highlevelcrypto -import shared #import helper_startup from helper_sql import * from helper_threading import * -- 2.45.1 From 6778d6046f941c0123a309df7cd06a2f2714a23c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 12:02:34 +0100 Subject: [PATCH 0554/1102] Add OpenSSL 1.1.0 compatibility - thanks to Wolfgang Frisch --- src/bitmessageqt/support.py | 6 +- src/depends.py | 21 +++--- src/highlevelcrypto.py | 4 +- src/pyelliptic/cipher.py | 5 +- src/pyelliptic/ecc.py | 42 ++++++++--- src/pyelliptic/openssl.py | 134 ++++++++++++++++++++++++++++-------- 6 files changed, 153 insertions(+), 59 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 07d0ab3a..83d34e74 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -100,11 +100,7 @@ def createSupportMessage(myapp): architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" pythonversion = sys.version - SSLEAY_VERSION = 0 - OpenSSL._lib.SSLeay.restype = ctypes.c_long - OpenSSL._lib.SSLeay_version.restype = ctypes.c_char_p - OpenSSL._lib.SSLeay_version.argtypes = [ctypes.c_int] - opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) + opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL()._version) frozen = "N/A" if paths.frozen: diff --git a/src/depends.py b/src/depends.py index 294c6a22..3e207f61 100755 --- a/src/depends.py +++ b/src/depends.py @@ -1,6 +1,7 @@ #! python import sys +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 @@ -106,8 +107,9 @@ def check_openssl(): except: pass - SSLEAY_VERSION = 0 - SSLEAY_CFLAGS = 2 + openssl_version = None + openssl_hexversion = None + openssl_cflags = None cflags_regex = re.compile(r'(?:OPENSSL_NO_)(AES|EC|ECDH|ECDSA)(?!\w)') @@ -118,23 +120,18 @@ def check_openssl(): except OSError: continue logger.info('OpenSSL Name: ' + library._name) - try: - library.SSLeay.restype = ctypes.c_long - library.SSLeay_version.restype = ctypes.c_char_p - library.SSLeay_version.argtypes = [ctypes.c_int] - except AttributeError: + openssl_version, openssl_hexversion, openssl_cflags = pyelliptic.openssl.get_version(library) + if not openssl_version: logger.error('Cannot determine version of this OpenSSL library.') return False - 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() + logger.info('OpenSSL Version: ' + openssl_version) + logger.info('OpenSSL Compile Options: ' + openssl_cflags) #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(compile_options) + matches = cflags_regex.findall(openssl_cflags) 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 diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index c8b67e77..50f13cce 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -35,7 +35,7 @@ def sign(msg,hexPrivkey): # upgrade PyBitmessage gracefully. # https://github.com/yann2192/pyelliptic/pull/33 # More discussion: https://github.com/yann2192/pyelliptic/issues/32 - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_ecdsa) # SHA1 + return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) # 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): @@ -44,7 +44,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.EVP_ecdsa) # old SHA1 algorithm. + sigVerifyPassed = makePubCryptor(hexPubkey).verify(sig,msg,digest_alg=OpenSSL.digest_ecdsa_sha1) # old SHA1 algorithm. except: sigVerifyPassed = False if sigVerifyPassed: diff --git a/src/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index fb8d0d46..4d932210 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -77,5 +77,8 @@ class Cipher: return buff + self.final() def __del__(self): - OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EVP_CIPHER_CTX_reset(self.ctx) + else: + 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 269db952..7b5a07d2 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -223,7 +223,10 @@ class ECC: if (OpenSSL.EC_KEY_set_private_key(own_key, own_priv_key)) == 0: raise Exception("[OpenSSL] EC_KEY_set_private_key FAIL ...") - OpenSSL.ECDH_set_method(own_key, OpenSSL.ECDH_OpenSSL()) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EC_KEY_set_method(own_key, OpenSSL.EC_KEY_OpenSSL()) + else: + OpenSSL.ECDH_set_method(own_key, OpenSSL.ECDH_OpenSSL()) ecdh_keylen = OpenSSL.ECDH_compute_key( ecdh_keybuffer, 32, other_pub_key, own_key, 0) @@ -299,7 +302,7 @@ class ECC: if privkey is not None: OpenSSL.BN_free(priv_key) - def sign(self, inputb, digest_alg=OpenSSL.EVP_ecdsa): + def sign(self, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): """ Sign the input with ECDSA method and returns the signature """ @@ -307,7 +310,10 @@ class ECC: size = len(inputb) buff = OpenSSL.malloc(inputb, size) digest = OpenSSL.malloc(0, 64) - md_ctx = OpenSSL.EVP_MD_CTX_create() + if OpenSSL._hexversion > 0x10100000: + md_ctx = OpenSSL.EVP_MD_CTX_new() + else: + 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) @@ -337,7 +343,10 @@ class ECC: if (OpenSSL.EC_KEY_check_key(key)) == 0: raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - OpenSSL.EVP_MD_CTX_init(md_ctx) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EVP_MD_CTX_new(md_ctx) + else: + 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: @@ -356,9 +365,13 @@ class ECC: OpenSSL.BN_free(pub_key_y) OpenSSL.BN_free(priv_key) OpenSSL.EC_POINT_free(pub_key) - OpenSSL.EVP_MD_CTX_destroy(md_ctx) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EVP_MD_CTX_free(md_ctx) + else: + OpenSSL.EVP_MD_CTX_destroy(md_ctx) + pass - def verify(self, sig, inputb, digest_alg=OpenSSL.EVP_ecdsa): + def verify(self, sig, inputb, digest_alg=OpenSSL.digest_ecdsa_sha1): """ Verify the signature with the input and the local public key. Returns a boolean @@ -368,8 +381,10 @@ class ECC: binputb = OpenSSL.malloc(inputb, len(inputb)) digest = OpenSSL.malloc(0, 64) dgst_len = OpenSSL.pointer(OpenSSL.c_int(0)) - md_ctx = OpenSSL.EVP_MD_CTX_create() - + if OpenSSL._hexversion > 0x10100000: + md_ctx = OpenSSL.EVP_MD_CTX_new() + else: + md_ctx = OpenSSL.EVP_MD_CTX_create() key = OpenSSL.EC_KEY_new_by_curve_name(self.curve) if key == 0: @@ -390,8 +405,10 @@ 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 ...") - - OpenSSL.EVP_MD_CTX_init(md_ctx) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EVP_MD_CTX_new(md_ctx) + else: + 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 ...") @@ -414,7 +431,10 @@ class ECC: OpenSSL.BN_free(pub_key_x) OpenSSL.BN_free(pub_key_y) OpenSSL.EC_POINT_free(pub_key) - OpenSSL.EVP_MD_CTX_destroy(md_ctx) + if OpenSSL._hexversion > 0x10100000: + OpenSSL.EVP_MD_CTX_free(md_ctx) + else: + 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 be2f2afc..db9e7d24 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -31,6 +31,37 @@ 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 @@ -40,6 +71,7 @@ class _OpenSSL: Build the wrapper """ self._lib = ctypes.CDLL(library) + self._version, self._hexversion, self._cflags = get_version(self._lib) self.pointer = ctypes.pointer self.c_int = ctypes.c_int @@ -138,18 +170,27 @@ class _OpenSSL: self.EC_KEY_set_private_key.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 = [] + if self._hexversion > 0x10100000: + 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.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, @@ -208,10 +249,15 @@ class _OpenSSL: self.EVP_rc4 = self._lib.EVP_rc4 self.EVP_rc4.restype = ctypes.c_void_p self.EVP_rc4.argtypes = [] - - 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] + + if self._hexversion > 0x10100000: + 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_free = self._lib.EVP_CIPHER_CTX_free self.EVP_CIPHER_CTX_free.restype = None @@ -250,10 +296,6 @@ 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, @@ -264,23 +306,47 @@ 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] - 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 = [] + if self._hexversion > 0x10100000: + 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_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_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_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_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.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 = [] @@ -437,7 +503,11 @@ def loadOpenSSL(): if 'darwin' in sys.platform: libdir.extend([ path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.dylib'), - path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.0.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')) @@ -445,8 +515,16 @@ def loadOpenSSL(): 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']) @@ -455,7 +533,7 @@ def loadOpenSSL(): else: libdir.append('libcrypto.so') libdir.append('libssl.so') - if 'linux' in sys.platform or 'darwin' in sys.platform or 'freebsd' in sys.platform: + 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')) @@ -467,4 +545,4 @@ def loadOpenSSL(): pass raise Exception("Couldn't find and load the OpenSSL library. You must install it.") -loadOpenSSL() \ No newline at end of file +loadOpenSSL() -- 2.45.1 From 5ae676f2ad5a3e6b692dd3bb7415fd164a14a598 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 12:05:39 +0100 Subject: [PATCH 0555/1102] Minor support fix --- src/bitmessageqt/support.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 83d34e74..ee573f05 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -100,7 +100,7 @@ def createSupportMessage(myapp): 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) + opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._version) frozen = "N/A" if paths.frozen: -- 2.45.1 From d0b1cbfe1ff1a426e3407e1129fa842762cda22f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 12:29:14 +0100 Subject: [PATCH 0556/1102] Add current git HEAD info to support request --- src/bitmessageqt/support.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index ee573f05..a1c5977a 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,5 +1,6 @@ import ctypes from PyQt4 import QtCore, QtGui +from os import path import ssl import sys import time @@ -86,6 +87,15 @@ def createSupportMessage(myapp): myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) version = softwareVersion + githeadfile = path.join(paths.codePath(), '..', '.git', 'ORIG_HEAD') + print "GITHEADFILE %s" % (githeadfile) + if (path.isfile(githeadfile)): + try: + with open(githeadfile, 'rt') as githead: + version += " GIT " + githead.readline().rstrip() + except IOError: + pass + os = sys.platform if os == "win32": windowsversion = sys.getwindowsversion() -- 2.45.1 From 93bdc3c800af291c2f6cb9c79a460eddebef0403 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 12:32:26 +0100 Subject: [PATCH 0557/1102] Remove extra print --- src/bitmessageqt/support.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index a1c5977a..7e9fec78 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -88,7 +88,6 @@ def createSupportMessage(myapp): version = softwareVersion githeadfile = path.join(paths.codePath(), '..', '.git', 'ORIG_HEAD') - print "GITHEADFILE %s" % (githeadfile) if (path.isfile(githeadfile)): try: with open(githeadfile, 'rt') as githead: -- 2.45.1 From 8d278182a7da9aa4f012fa7decf348322ab323f6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 13 Jan 2017 15:53:47 +0100 Subject: [PATCH 0558/1102] Indentation --- src/bitmessageqt/support.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 7e9fec78..86068542 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -90,8 +90,8 @@ def createSupportMessage(myapp): githeadfile = path.join(paths.codePath(), '..', '.git', 'ORIG_HEAD') if (path.isfile(githeadfile)): try: - with open(githeadfile, 'rt') as githead: - version += " GIT " + githead.readline().rstrip() + with open(githeadfile, 'rt') as githead: + version += " GIT " + githead.readline().rstrip() except IOError: pass -- 2.45.1 From cc4c07025b46f25496a3b49bea01b54d9bc7dcf9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 12:35:08 +0100 Subject: [PATCH 0559/1102] Sending thread fix --- src/class_sendDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index f6d15c26..2fed7071 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -92,7 +92,7 @@ class sendDataThread(threading.Thread): uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and - shared.haveSSL(not self.initiatedConnection)): + protocol.haveSSL(not self.initiatedConnection)): amountSent = self.sslSock.send(data[:1000]) else: amountSent = self.sock.send(data[:1000]) -- 2.45.1 From fa2f87743e8780493922a01d187d07d3fbc32761 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 13:22:46 +0100 Subject: [PATCH 0560/1102] SSL handshake fix - SSL handshake would often fail, because verack packet was being sent at the same time as the do_handshake was executed in a different thread. This makes it so that do_handshake waits until verack is done sending. - also minor modifications in SSLContext initialisation --- src/class_receiveDataThread.py | 7 ++++--- src/class_sendDataThread.py | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 5dac4b19..821eedc2 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -294,16 +294,17 @@ class receiveDataThread(threading.Thread): protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") if sys.version_info >= (2,7,9): - context = ssl.create_default_context(purpose = ssl.Purpose.CLIENT_AUTH if self.initiatedConnection else ssl.Purpose.SERVER_AUTH) + context = ssl.SSLContext(protocol.sslProtocolVersion) context.set_ciphers("AECDH-AES256-SHA") 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_NO_SSLv2 | ssl.OP_NO_SSLv3 + 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='AECDH-AES256-SHA') + self.sendDataThreadQueue.join() while True: try: self.sslSock.do_handshake() @@ -316,7 +317,7 @@ class receiveDataThread(threading.Thread): logger.debug("Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) except: - logger.debug("SSL socket handhake failed, shutting down connection") + logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) return # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 2fed7071..e1c03c98 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -185,6 +185,8 @@ class sendDataThread(threading.Thread): self.services, self.sslSock = data else: logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) + self.sendDataThreadQueue.task_done() + self.sendDataThreadQueue.task_done() try: self.sock.shutdown(socket.SHUT_RDWR) -- 2.45.1 From ff593273bf5f405dad6b0ed020fefdba639847a4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 13:51:44 +0100 Subject: [PATCH 0561/1102] Add ssltest.py for developers/debugging --- dev/ssltest.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 dev/ssltest.py diff --git a/dev/ssltest.py b/dev/ssltest.py new file mode 100644 index 00000000..0ad5026f --- /dev/null +++ b/dev/ssltest.py @@ -0,0 +1,83 @@ +import select +import socket +import ssl +import sys + +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 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("AECDH-AES256-SHA") + 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(self.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([self.sslSock], [], [], 10) + except ssl.SSLWantWriteError: + print "Waiting for SSL socket handhake write" + select.select([], [self.sslSock], [], 10) + except Exception as e: + print "SSL socket handhake failed, shutting down connection: %s" % (e) + 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) + sslSock.shutdown(socket.SHUT_RDWR) + sslSock.close() + elif sys.argv[1] == "client": + sock = connect() + sslSock = sslHandshake(sock, False) + sslSock.shutdown(socket.SHUT_RDWR) + sslSock.close() + else: + print "Usage: ssltest.py client|server" + sys.exit(0) -- 2.45.1 From 6247e1d3ea1de46ad57b3e65f2871151a20a44e7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 13:55:57 +0100 Subject: [PATCH 0562/1102] Add more debug info and error handling to ssltest --- dev/ssltest.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/dev/ssltest.py b/dev/ssltest.py index 0ad5026f..101a3bef 100644 --- a/dev/ssltest.py +++ b/dev/ssltest.py @@ -2,6 +2,7 @@ import select import socket import ssl import sys +import traceback HOST = "127.0.0.1" PORT = 8912 @@ -55,7 +56,8 @@ def sslHandshake(sock, server=False): print "Waiting for SSL socket handhake write" select.select([], [self.sslSock], [], 10) except Exception as e: - print "SSL socket handhake failed, shutting down connection: %s" % (e) + print "SSL socket handhake failed, shutting down connection" + traceback.print_exc() return print "Success!" return sslSock @@ -71,13 +73,15 @@ if __name__ == "__main__": sock, addr = serversock.accept() print "Got connection from %s:%i" % (addr[0], addr[1]) sslSock = sslHandshake(sock, True) - sslSock.shutdown(socket.SHUT_RDWR) - sslSock.close() + if sslSock: + sslSock.shutdown(socket.SHUT_RDWR) + sslSock.close() elif sys.argv[1] == "client": sock = connect() sslSock = sslHandshake(sock, False) - sslSock.shutdown(socket.SHUT_RDWR) - sslSock.close() + if sslSock: + sslSock.shutdown(socket.SHUT_RDWR) + sslSock.close() else: print "Usage: ssltest.py client|server" sys.exit(0) -- 2.45.1 From 59b5ac3a61fcfb1fd55812198ffe208243c3c160 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 17:47:57 +0100 Subject: [PATCH 0563/1102] OpenSSL 1.1.0 compatibility fixes - function check missed 1.1.0 release - TLS didn't work with anonymous ciphers --- src/protocol.py | 6 ++++++ src/pyelliptic/openssl.py | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/protocol.py b/src/protocol.py index ae04740b..3a3ccebe 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -495,3 +495,9 @@ 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 + sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0" +else: + sslProtocolCiphers = "AECDH-AES256-SHA" diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index db9e7d24..a26339ce 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -170,7 +170,7 @@ class _OpenSSL: self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - if self._hexversion > 0x10100000: + if self._hexversion >= 0x10100000: 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 = [] @@ -250,7 +250,7 @@ class _OpenSSL: self.EVP_rc4.restype = ctypes.c_void_p self.EVP_rc4.argtypes = [] - if self._hexversion > 0x10100000: + if self._hexversion >= 0x10100000: 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] @@ -306,7 +306,7 @@ 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: + if self._hexversion >= 0x10100000: 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 = [] -- 2.45.1 From 02a7c59de8326df573f1aa00abc45f3a1808b5d0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 17:50:49 +0100 Subject: [PATCH 0564/1102] OpenSSL 1.1.0 compatibility fixes - part 2, continued from previous commit --- src/class_receiveDataThread.py | 4 ++-- src/protocol.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 821eedc2..ca4430ab 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -295,7 +295,7 @@ class receiveDataThread(threading.Thread): logger.debug("Initialising TLS") if sys.version_info >= (2,7,9): context = ssl.SSLContext(protocol.sslProtocolVersion) - context.set_ciphers("AECDH-AES256-SHA") + context.set_ciphers(protocol.sslProtocolCiphers) context.set_ecdh_curve("secp256k1") context.check_hostname = False context.verify_mode = ssl.CERT_NONE @@ -303,7 +303,7 @@ class receiveDataThread(threading.Thread): 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='AECDH-AES256-SHA') + 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: diff --git a/src/protocol.py b/src/protocol.py index 3a3ccebe..816b2c1d 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -497,7 +497,7 @@ else: sslProtocolVersion = ssl.PROTOCOL_TLSv1 # ciphers -if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000 +if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000: sslProtocolCiphers = "AECDH-AES256-SHA@SECLEVEL=0" else: sslProtocolCiphers = "AECDH-AES256-SHA" -- 2.45.1 From bcc7692e14b7b695f08dfb39aaccf3dbfa67d857 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 23:18:06 +0100 Subject: [PATCH 0565/1102] Add safeGetInt to BMConfigParser --- src/configparser.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/configparser.py b/src/configparser.py index 7a4258be..ac70cee4 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -27,6 +27,14 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return False return False + def safeGetInt(self, section, field): + if self.has_option(section, field): + try: + return self.getint(section, field) + except ValueError: + return 0 + return 0 + def safeGet(self, section, option, default = None): if self.has_option(section, option): return self.get(section, option) -- 2.45.1 From ad75552b5c0ea173798e62fd756e79c46c59c2fa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 23:20:15 +0100 Subject: [PATCH 0566/1102] Move shutdown from shared.py to state.py --- src/api.py | 3 ++- src/bitmessageqt/support.py | 4 ++-- src/class_addressGenerator.py | 3 ++- src/class_objectProcessor.py | 18 +++++++++--------- src/class_outgoingSynSender.py | 8 ++++---- src/class_singleCleaner.py | 2 +- src/class_singleListener.py | 12 ++++++------ src/class_singleWorker.py | 22 +++++++++++----------- src/class_smtpDeliver.py | 3 ++- src/openclpow.py | 2 +- src/proofofwork.py | 14 ++++++++------ src/shared.py | 6 ++---- src/state.py | 2 ++ src/upnp.py | 5 +++-- 14 files changed, 55 insertions(+), 49 deletions(-) diff --git a/src/api.py b/src/api.py index 18b2dd20..cf02f69b 100644 --- a/src/api.py +++ b/src/api.py @@ -33,6 +33,7 @@ from struct import pack from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger from inventory import Inventory +import state from version import softwareVersion # Helper Functions @@ -52,7 +53,7 @@ class APIError(Exception): class StoppableXMLRPCServer(SimpleXMLRPCServer): def serve_forever(self): - while shared.shutdown == 0: + while state.shutdown == 0: self.handle_request() diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 86068542..fc132453 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -68,7 +68,7 @@ def checkHasNormalAddress(): def createAddressIfNeeded(myapp): if not checkHasNormalAddress(): shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes)) - while shared.shutdown == 0 and not checkHasNormalAddress(): + while state.shutdown == 0 and not checkHasNormalAddress(): time.sleep(.2) myapp.rerenderComboBoxSendFrom() return checkHasNormalAddress() @@ -76,7 +76,7 @@ def createAddressIfNeeded(myapp): def createSupportMessage(myapp): checkAddressBook(myapp) address = createAddressIfNeeded(myapp) - if shared.shutdown: + if state.shutdown: return myapp.ui.lineEditSubject.setText(str(QtGui.QApplication.translate("Support", SUPPORT_SUBJECT))) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index ebedf2f9..00957594 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -14,6 +14,7 @@ import protocol from pyelliptic import arithmetic import tr from binascii import hexlify +import state class addressGenerator(threading.Thread, StoppableThread): @@ -30,7 +31,7 @@ class addressGenerator(threading.Thread, StoppableThread): super(addressGenerator, self).stopThread() def run(self): - while shared.shutdown == 0: + while state.shutdown == 0: queueValue = shared.addressGeneratorQueue.get() nonceTrialsPerByte = 0 payloadLengthExtraBytes = 0 diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 4d0b7be0..00e5fbd4 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -22,7 +22,7 @@ import helper_msgcoding import helper_sent from helper_sql import * import protocol -from state import neededPubkeys +import state import tr from debug import logger import l10n @@ -73,7 +73,7 @@ class objectProcessor(threading.Thread): except Exception as e: logger.critical("Critical error within objectProcessorThread: \n%s" % traceback.format_exc()) - if shared.shutdown: + if state.shutdown: time.sleep(.5) # Wait just a moment for most of the connections to close numberOfObjectsThatWereInTheObjectProcessorQueue = 0 with SqlBulkExecute() as sql: @@ -83,7 +83,7 @@ class objectProcessor(threading.Thread): objectType,data) numberOfObjectsThatWereInTheObjectProcessorQueue += 1 logger.debug('Saved %s objects from the objectProcessorQueue to disk. objectProcessorThread exiting.' % str(numberOfObjectsThatWereInTheObjectProcessorQueue)) - shared.shutdown = 2 + state.shutdown = 2 break def processgetpubkey(self, data): @@ -286,12 +286,12 @@ class objectProcessor(threading.Thread): return tag = data[readPosition:readPosition + 32] - if tag not in neededPubkeys: + if tag not in state.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 = neededPubkeys[tag] + toAddress, cryptorObject = state.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 @@ -783,8 +783,8 @@ class objectProcessor(threading.Thread): # stream number, and RIPE hash. status, addressVersion, streamNumber, ripe = decodeAddress(address) if addressVersion <=3: - if address in neededPubkeys: - del neededPubkeys[address] + if address in state.neededPubkeys: + del state.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) @@ -794,8 +794,8 @@ class objectProcessor(threading.Thread): elif addressVersion >= 4: tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest()[32:] - if tag in neededPubkeys: - del neededPubkeys[tag] + if tag in state.neededPubkeys: + del state.neededPubkeys[tag] self.sendMessages(address) def sendMessages(self, address): diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index ef63d770..9ea361cc 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -38,7 +38,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.knownNodes[self.streamNumber][peer] = time.time() shared.knownNodesLock.release() else: - while not shared.shutdown: + while not state.shutdown: shared.knownNodesLock.acquire() try: peer, = random.sample(shared.knownNodes[self.streamNumber], 1) @@ -82,7 +82,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): maximumConnections = 1 if state.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: self.stop.wait(10) - if shared.shutdown: + if state.shutdown: break random.seed() peer = self._getPeer() @@ -93,7 +93,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): random.seed() peer = self._getPeer() self.stop.wait(1) - if shared.shutdown: + if state.shutdown: break # Clear out the shared.alreadyAttemptedConnectionsList every half # hour so that this program will again attempt a connection @@ -108,7 +108,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.alreadyAttemptedConnectionsListLock.release() except threading.ThreadError as e: pass - if shared.shutdown: + if state.shutdown: break self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator address_family = socket.AF_INET diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 03ebc633..a4177986 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -48,7 +48,7 @@ class singleCleaner(threading.Thread, StoppableThread): # Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file. shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') - while shared.shutdown == 0: + while state.shutdown == 0: shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) Inventory().flush() diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 0ad82333..49acc71c 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -65,7 +65,7 @@ class singleListener(threading.Thread, StoppableThread): if state.trustedPeer: return - while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: + while BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect') and state.shutdown == 0: self.stop.wait(1) helper_bootstrap.dns() # We typically don't want to accept incoming connections if the user is using a @@ -76,7 +76,7 @@ class singleListener(threading.Thread, StoppableThread): while BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')) and \ - shared.shutdown == 0: + state.shutdown == 0: self.stop.wait(5) logger.info('Listening for incoming connections.') @@ -99,19 +99,19 @@ 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 shared.shutdown == 0: + while state.shutdown == 0: # 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 shared.shutdown == 0: + 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) > 220 and shared.shutdown == 0: + while len(shared.connectedHostsList) > 220 and state.shutdown == 0: logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') self.stop.wait(10) - while shared.shutdown == 0: + while state.shutdown == 0: socketObject, sockaddr = sock.accept() (HOST, PORT) = sockaddr[0:2] diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index fc4d324d..b09bb6fd 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -21,7 +21,7 @@ from helper_threading import * from inventory import Inventory import l10n import protocol -from state import neededPubkeys +import state from binascii import hexlify, unhexlify # This thread, of which there is only one, does the heavy lifting: @@ -57,13 +57,13 @@ class singleWorker(threading.Thread, StoppableThread): toAddress, = row toStatus, toAddressVersionNumber, toStreamNumber, toRipe = decodeAddress(toAddress) if toAddressVersionNumber <= 3 : - neededPubkeys[toAddress] = 0 + state.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:] - 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. + 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. # Initialize the shared.ackdataForWhichImWatching data structure queryreturn = sqlQuery( @@ -76,7 +76,7 @@ class singleWorker(threading.Thread, StoppableThread): self.stop.wait( 10) # give some time for the GUI to start before we start on existing POW tasks. - if shared.shutdown == 0: + if state.shutdown == 0: # just in case there are any pending tasks for msg # messages that have yet to be sent. shared.workerQueue.put(('sendmessage', '')) @@ -84,7 +84,7 @@ class singleWorker(threading.Thread, StoppableThread): # that have yet to be sent. shared.workerQueue.put(('sendbroadcast', '')) - while shared.shutdown == 0: + while state.shutdown == 0: self.busy = 0 command, data = shared.workerQueue.get() self.busy = 1 @@ -553,7 +553,7 @@ class singleWorker(threading.Thread, StoppableThread): toTag = '' else: toTag = hashlib.sha512(hashlib.sha512(encodeVarint(toAddressVersionNumber)+encodeVarint(toStreamNumber)+toRipe).digest()).digest()[32:] - if toaddress in neededPubkeys or toTag in neededPubkeys: + if toaddress in state.neededPubkeys or toTag in state.neededPubkeys: # We already sent a request for the pubkey sqlExecute( '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', @@ -577,7 +577,7 @@ 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. - neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) + state.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) 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. @@ -585,7 +585,7 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='msgqueued' or status='awaitingpubkey' or status='doingpubkeypow')''', toaddress) - del neededPubkeys[tag] + del state.neededPubkeys[tag] break #else: # There was something wrong with this pubkey object even # though it had the correct tag- almost certainly because @@ -879,15 +879,15 @@ class singleWorker(threading.Thread, StoppableThread): retryNumber = queryReturn[0][0] if addressVersionNumber <= 3: - neededPubkeys[toAddress] = 0 + state.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 neededPubkeys: - 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 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 retryNumber == 0: TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 18206065..2314238f 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -10,6 +10,7 @@ from debug import logger from helper_threading import * from bitmessageqt.uisignaler import UISignaler import shared +import state SMTPDOMAIN = "bmaddr.lan" @@ -34,7 +35,7 @@ class smtpDeliver(threading.Thread, StoppableThread): return cls._instance def run(self): - while shared.shutdown == 0: + while state.shutdown == 0: command, data = shared.UISignalQueue.get() if command == 'writeNewAddressToTable': label, address, streamNumber = data diff --git a/src/openclpow.py b/src/openclpow.py index 001333e5..168f963f 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -7,7 +7,7 @@ import os from configparser import BMConfigParser import paths -from shared import shutdown +from state import shutdown from debug import logger libAvailable = True diff --git a/src/proofofwork.py b/src/proofofwork.py index 78188777..da9282f2 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -15,6 +15,8 @@ import tr import os import ctypes +import state + bitmsglib = 'bitmsghash.so' def _set_idle(): @@ -43,10 +45,10 @@ def _doSafePoW(target, initialHash): logger.debug("Safe PoW start") nonce = 0 trialValue = float('inf') - while trialValue > target and shared.shutdown == 0: + while trialValue > target and state.shutdown == 0: nonce += 1 trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) - if shared.shutdown != 0: + if state.shutdown != 0: raise StopIteration("Interrupted") logger.debug("Safe PoW done") return [trialValue, nonce] @@ -71,7 +73,7 @@ def _doFastPoW(target, initialHash): result.append(pool.apply_async(_pool_worker, args=(i, initialHash, target, pool_size))) while True: - if shared.shutdown > 0: + if state.shutdown > 0: try: pool.terminate() pool.join() @@ -101,7 +103,7 @@ def _doCPoW(target, initialHash): 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 shared.shutdown != 0: + if state.shutdown != 0: raise StopIteration("Interrupted") logger.debug("C PoW done") return [trialValue, nonce] @@ -117,7 +119,7 @@ def _doGPUPoW(target, initialHash): 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 shared.shutdown != 0: + if state.shutdown != 0: raise StopIteration("Interrupted") logger.debug("GPU PoW done") return [trialValue, nonce] @@ -186,7 +188,7 @@ def buildCPoW(): notifyBuild(True) def run(target, initialHash): - if shared.shutdown != 0: + if state.shutdown != 0: raise target = int(target) if openclpow.openclEnabled(): diff --git a/src/shared.py b/src/shared.py index b185e7e9..82d08d35 100644 --- a/src/shared.py +++ b/src/shared.py @@ -51,7 +51,6 @@ knownNodes = {} printLock = threading.Lock() 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. -shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. thisapp = None # singleton lock instance alreadyAttemptedConnectionsList = { } # This is a list of nodes to which we have already attempted a connection @@ -197,8 +196,7 @@ def reloadBroadcastSendersForWhichImWatching(): MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) def doCleanShutdown(): - global shutdown - shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. + state.shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. try: parserInputQueue.put(None, False) except Queue.Full: @@ -228,7 +226,7 @@ def doCleanShutdown(): # 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: + while state.shutdown == 1: time.sleep(.1) # This one last useless query will guarantee that the previous flush committed and that the diff --git a/src/state.py b/src/state.py index f8af54c7..6ae563c4 100644 --- a/src/state.py +++ b/src/state.py @@ -15,6 +15,8 @@ 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. + # 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 diff --git a/src/upnp.py b/src/upnp.py index 69f89233..b8d41f4b 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -9,6 +9,7 @@ import time from configparser import BMConfigParser from helper_threading import * import shared +import state import tr def createRequestXML(service, action, arguments=None): @@ -197,7 +198,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Starting UPnP thread") logger.debug("Local IP: %s", self.localIP) lastSent = 0 - while shared.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): + while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: try: self.sendSearchRouter() @@ -205,7 +206,7 @@ class uPnPThread(threading.Thread, StoppableThread): pass lastSent = time.time() try: - while shared.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): + while state.shutdown == 0 and BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp'): resp,(ip,port) = self.sock.recvfrom(1000) if resp is None: continue -- 2.45.1 From 689d697a407599214e06fa312ee9e389b6848ce8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 14 Jan 2017 23:21:00 +0100 Subject: [PATCH 0567/1102] Refactor bandwidth limit and speed calculator - also fixes potential deadlocks --- src/bitmessageqt/__init__.py | 3 ++ src/bitmessageqt/networkstatus.py | 12 ++---- src/class_receiveDataThread.py | 21 ++-------- src/class_sendDataThread.py | 58 +++++++++++++--------------- src/shared.py | 8 ---- src/throttle.py | 64 +++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 65 deletions(-) create mode 100644 src/throttle.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 91d62564..ad89be30 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -82,6 +82,7 @@ from proofofwork import getPowType import protocol import state from statusbar import BMStatusBar +import throttle from version import softwareVersion def _translate(context, text, disambiguation = None, encoding = None, number = None): @@ -2391,6 +2392,8 @@ class MyForm(settingsmixin.SMainWindow): except: QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) + throttle.SendThrottle.resetLimit() + throttle.ReceiveThrottle.resetLimit() BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index c792f81c..2fe493ac 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -7,6 +7,7 @@ import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler import widgets +import throttle class NetworkStatus(QtGui.QWidget, RetranslateMixin): @@ -28,9 +29,6 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "updateNetworkStatusTab()"), self.updateNetworkStatusTab) - self.totalNumberOfBytesReceived = 0 - self.totalNumberOfBytesSent = 0 - self.timer = QtCore.QTimer() self.timer.start(2000) # milliseconds QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) @@ -70,13 +68,9 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): sent and received by 2. """ self.labelBytesRecvCount.setText(_translate( - "networkstatus", "Down: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesReceived/2), self.formatBytes(self.totalNumberOfBytesReceived))) + "networkstatus", "Down: %1/s Total: %2").arg(self.formatByteRate(throttle.ReceiveThrottle().getSpeed()), self.formatBytes(throttle.ReceiveThrottle().total))) self.labelBytesSentCount.setText(_translate( - "networkstatus", "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 + "networkstatus", "Up: %1/s Total: %2").arg(self.formatByteRate(throttle.SendThrottle().getSpeed()), self.formatBytes(throttle.SendThrottle().total))) def updateNetworkStatusTab(self): 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). diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index ca4430ab..deb1e05b 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -32,6 +32,7 @@ import paths import protocol from inventory import Inventory import state +import throttle import tr from version import softwareVersion @@ -82,19 +83,6 @@ class receiveDataThread(threading.Thread): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) while True: - if BMConfigParser().getint('bitmessagesettings', 'maxdownloadrate') == 0: - downloadRateLimitBytes = float("inf") - else: - downloadRateLimitBytes = BMConfigParser().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: ssl = False @@ -102,12 +90,11 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): ssl = True - dataRecv = self.sslSock.recv(1024) + dataRecv = self.sslSock.recv(4096) else: - dataRecv = self.sock.recv(1024) + dataRecv = self.sock.recv(4096) self.data += 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 + throttle.ReceiveThrottle().wait(len(dataRecv)) except socket.timeout: logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index e1c03c98..d619d451 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -1,3 +1,4 @@ +import errno import time import threading import shared @@ -15,6 +16,7 @@ from addresses import * from debug import logger import protocol import state +import throttle # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). @@ -70,36 +72,30 @@ class sendDataThread(threading.Thread): self.versionSent = 1 def sendBytes(self, data): - if BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: - uploadRateLimitBytes = 999999999 # float("inf") doesn't work - else: - uploadRateLimitBytes = BMConfigParser().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 BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') == 0: - uploadRateLimitBytes = 999999999 # float("inf") doesn't work - else: - uploadRateLimitBytes = BMConfigParser().getint('bitmessagesettings', 'maxuploadrate') * 1000 - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - self.connectionIsOrWasFullyEstablished and - protocol.haveSSL(not self.initiatedConnection)): - amountSent = self.sslSock.send(data[:1000]) - else: - 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 data: + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + protocol.haveSSL(not self.initiatedConnection)): + while state.shutdown == 0: + try: + amountSent = self.sslSock.send(data[:4096]) + break + except socket.error as e: + if e.errno == errno.EAGAIN: + continue + raise + else: + while True: + try: + amountSent = self.sock.send(data[:4096]) + break + except socket.error as e: + if e.errno == errno.EAGAIN: + continue + raise + throttle.SendThrottle().wait(amountSent) + self.lastTimeISentData = int(time.time()) + data = data[amountSent:] def run(self): @@ -178,7 +174,7 @@ class sendDataThread(threading.Thread): try: self.sendBytes(data) except: - logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.') + logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True) break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True diff --git a/src/shared.py b/src/shared.py index 82d08d35..be291a75 100644 --- a/src/shared.py +++ b/src/shared.py @@ -67,14 +67,6 @@ clientHasReceivedIncomingConnections = False #used by API command clientStatus numberOfMessagesProcessed = 0 numberOfBroadcastsProcessed = 0 numberOfPubkeysProcessed = 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 needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 diff --git a/src/throttle.py b/src/throttle.py new file mode 100644 index 00000000..5b503e1e --- /dev/null +++ b/src/throttle.py @@ -0,0 +1,64 @@ +import threading +import time + +from configparser import BMConfigParser +from singleton import Singleton +import state + +class Throttle(object): + def __init__(self, limit=0): + self.limit = limit + self.speed = 0 + self.txTime = int(time.time()) + self.txLen = 0 + self.total = 0 + self.timer = threading.Event() + self.lock = threading.RLock() + + def recalculate(self): + with self.lock: + now = int(time.time()) + if now > 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.waiting = True + 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) + with self.lock: + self.waiting = False + + def getSpeed(self): + self.recalculate() + return self.speed + +@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 + +@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 -- 2.45.1 From 5ca8a52662af9518bf09ea0b099e2c9ed97e5ca8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 10:48:29 +0100 Subject: [PATCH 0568/1102] Typos, extra imports and similar - pointed out by landscape.io - also updated dev/ssltest.py to work the same way as the main program --- dev/ssltest.py | 16 +++++++++++----- src/api.py | 1 - src/bitmessageqt/__init__.py | 4 ++-- src/class_sendDataThread.py | 2 -- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/dev/ssltest.py b/dev/ssltest.py index 101a3bef..538801f5 100644 --- a/dev/ssltest.py +++ b/dev/ssltest.py @@ -22,6 +22,12 @@ def sslProtocolVersion(): # "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 @@ -36,14 +42,14 @@ def listen(): def sslHandshake(sock, server=False): if sys.version_info >= (2,7,9): context = ssl.SSLContext(sslProtocolVersion()) - context.set_ciphers("AECDH-AES256-SHA") + 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(self.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') + 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: @@ -51,11 +57,11 @@ def sslHandshake(sock, server=False): break except ssl.SSLWantReadError: print "Waiting for SSL socket handhake read" - select.select([self.sslSock], [], [], 10) + select.select([sslSock], [], [], 10) except ssl.SSLWantWriteError: print "Waiting for SSL socket handhake write" - select.select([], [self.sslSock], [], 10) - except Exception as e: + select.select([], [sslSock], [], 10) + except Exception: print "SSL socket handhake failed, shutting down connection" traceback.print_exc() return diff --git a/src/api.py b/src/api.py index cf02f69b..f25972aa 100644 --- a/src/api.py +++ b/src/api.py @@ -33,7 +33,6 @@ from struct import pack from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure from debug import logger from inventory import Inventory -import state from version import softwareVersion # Helper Functions diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ad89be30..560c1c0b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2392,8 +2392,8 @@ class MyForm(settingsmixin.SMainWindow): except: QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) - throttle.SendThrottle.resetLimit() - throttle.ReceiveThrottle.resetLimit() + throttle.SendThrottle().resetLimit() + throttle.ReceiveThrottle().resetLimit() BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index d619d451..76409050 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -1,7 +1,6 @@ import errno import time import threading -import shared import Queue from struct import unpack, pack import hashlib @@ -9,7 +8,6 @@ import random import sys import socket -from configparser import BMConfigParser from helper_generic import addDataPadding from class_objectHashHolder import * from addresses import * -- 2.45.1 From 8cb095340169345e2597e8ad9c4bd1b18626dfe0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 10:50:02 +0100 Subject: [PATCH 0569/1102] Moved writeKeysFile into configparser - shared.writeKeysFile -> BMConfigParser().save - makes it easier to get rid of circular imports --- src/bitmessagecurses/__init__.py | 10 +++++----- src/bitmessageqt/__init__.py | 26 +++++++++++++------------- src/bitmessageqt/blacklist.py | 5 ++--- src/bitmessageqt/foldertree.py | 3 +-- src/class_addressGenerator.py | 4 ++-- src/class_singleWorker.py | 6 +++--- src/class_sqlThread.py | 4 ++-- src/configparser.py | 21 +++++++++++++++++++++ src/helper_startup.py | 3 +-- src/shared.py | 18 ------------------ 10 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index a8840f2f..029f1725 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -485,13 +485,13 @@ def handlech(c, stdscr): label = t BMConfigParser().set(a, "label", label) # Write config - shared.writeKeysFile() + BMConfigParser().save() addresses[addrcur][0] = label elif t == "4": # Enable address a = addresses[addrcur][2] BMConfigParser().set(a, "enabled", "true") # Set config # Write config - shared.writeKeysFile() + BMConfigParser().save() # Change color if BMConfigParser().safeGetBoolean(a, 'chan'): addresses[addrcur][3] = 9 # orange @@ -506,14 +506,14 @@ def handlech(c, stdscr): BMConfigParser().set(a, "enabled", "false") # Set config addresses[addrcur][3] = 8 # Set color to gray # Write config - shared.writeKeysFile() + BMConfigParser().save() 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]) - shared.writeKeysFile() + BMConfigParser().save() del addresses[addrcur] elif t == "7": # Special address behavior a = addresses[addrcur][2] @@ -544,7 +544,7 @@ def handlech(c, stdscr): BMConfigParser().set(a, "mailinglistname", mn) addresses[addrcur][3] = 6 # Set color to magenta # Write config - shared.writeKeysFile() + BMConfigParser().save() elif menutab == 5: set_background_title(d, "Subscriptions Dialog Box") if len(subscriptions) <= subcur: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 560c1c0b..5f1a65e6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -611,7 +611,7 @@ class MyForm(settingsmixin.SMainWindow): self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: BMConfigParser().remove_section(addressInKeysFile) - shared.writeKeysFile() + BMConfigParser().save() # Configure Bitmessage to start on startup (or remove the # configuration) based on the setting in the keys.dat file @@ -822,7 +822,7 @@ class MyForm(settingsmixin.SMainWindow): TTL = int(sliderPosition ** 3.199 + 3600) self.updateHumanFriendlyTTLDescription(TTL) BMConfigParser().set('bitmessagesettings', 'ttl', str(TTL)) - shared.writeKeysFile() + BMConfigParser().save() def updateHumanFriendlyTTLDescription(self, TTL): numberOfHours = int(round(TTL / (60*60))) @@ -1596,7 +1596,7 @@ class MyForm(settingsmixin.SMainWindow): if self.connectDialogInstance.exec_(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') - shared.writeKeysFile() + BMConfigParser().save() else: self.click_actionSettings() @@ -1953,7 +1953,7 @@ class MyForm(settingsmixin.SMainWindow): acct.register(email) BMConfigParser().set(fromAddress, 'label', email) BMConfigParser().set(fromAddress, 'gateway', 'mailchuck') - shared.writeKeysFile() + BMConfigParser().save() self.statusBar().showMessage(_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), 10000) return @@ -2236,7 +2236,7 @@ class MyForm(settingsmixin.SMainWindow): acct.register(email) BMConfigParser().set(acct.fromAddress, 'label', email) BMConfigParser().set(acct.fromAddress, 'gateway', 'mailchuck') - shared.writeKeysFile() + BMConfigParser().save() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) @@ -2476,7 +2476,7 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().set('bitmessagesettings', 'stopresendingafterxmonths', str(float( self.settingsDialogInstance.ui.lineEditMonths.text()))) - shared.writeKeysFile() + BMConfigParser().save() if 'win32' in sys.platform or 'win64' in sys.platform: # Auto-startup for Windows @@ -2521,7 +2521,7 @@ class MyForm(settingsmixin.SMainWindow): os.makedirs(state.appdata) sqlStoredProcedure('movemessagstoappdata') # Write the keys.dat file to disk in the new location - shared.writeKeysFile() + BMConfigParser().save() # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() output = open(state.appdata + 'knownnodes.dat', 'wb') @@ -2561,7 +2561,7 @@ class MyForm(settingsmixin.SMainWindow): self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - shared.writeKeysFile() + BMConfigParser().save() self.rerenderMessagelistToLabels() def on_action_EmailGatewayDialog(self): @@ -2576,7 +2576,7 @@ class MyForm(settingsmixin.SMainWindow): if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): acct.unregister() BMConfigParser().remove_option(addressAtCurrentRow, 'gateway') - shared.writeKeysFile() + BMConfigParser().save() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway unregistration request"), 10000) elif self.dialog.ui.radioButtonStatus.isChecked() and isinstance(acct, GatewayAccount): @@ -2603,7 +2603,7 @@ class MyForm(settingsmixin.SMainWindow): acct.register(email) BMConfigParser().set(addressAtCurrentRow, 'label', email) BMConfigParser().set(addressAtCurrentRow, 'gateway', 'mailchuck') - shared.writeKeysFile() + BMConfigParser().save() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) else: @@ -3540,7 +3540,7 @@ class MyForm(settingsmixin.SMainWindow): return else: return - shared.writeKeysFile() + BMConfigParser().save() shared.reloadMyAddressHashes() self.rerenderAddressBook() if account.type == AccountMixin.NORMAL: @@ -3556,7 +3556,7 @@ class MyForm(settingsmixin.SMainWindow): def enableIdentity(self, address): BMConfigParser().set(address, 'enabled', 'true') - shared.writeKeysFile() + BMConfigParser().save() shared.reloadMyAddressHashes() self.rerenderAddressBook() @@ -3568,7 +3568,7 @@ class MyForm(settingsmixin.SMainWindow): def disableIdentity(self, address): BMConfigParser().set(str(address), 'enabled', 'false') - shared.writeKeysFile() + BMConfigParser().save() shared.reloadMyAddressHashes() self.rerenderAddressBook() diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 94844da5..29a324c0 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -1,5 +1,4 @@ from PyQt4 import QtCore, QtGui -import shared from tr import _translate import l10n import widgets @@ -41,7 +40,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): def click_radioButtonBlacklist(self): if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'white': BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'black') - shared.writeKeysFile() + BMConfigParser().save() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) self.rerenderBlackWhiteList() @@ -49,7 +48,7 @@ class Blacklist(QtGui.QWidget, RetranslateMixin): def click_radioButtonWhitelist(self): if BMConfigParser().get('bitmessagesettings', 'blackwhitelist') == 'black': BMConfigParser().set('bitmessagesettings', 'blackwhitelist', 'white') - shared.writeKeysFile() + BMConfigParser().save() # self.tableWidgetBlacklist.clearContents() self.tableWidgetBlacklist.setRowCount(0) self.rerenderBlackWhiteList() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 8b0e519b..821efdb4 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -4,7 +4,6 @@ from string import find, rfind, rstrip, lstrip from configparser import BMConfigParser from helper_sql import * from utils import * -import shared from settingsmixin import SettingsMixin class AccountMixin (object): @@ -215,7 +214,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): BMConfigParser().set(str(self.address), 'label', str(value.toString().toUtf8())) else: BMConfigParser().set(str(self.address), 'label', str(value)) - shared.writeKeysFile() + BMConfigParser().save() return super(Ui_AddressWidget, self).setData(column, role, value) def setAddress(self, address): diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 00957594..c3dfac3e 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -143,7 +143,7 @@ class addressGenerator(threading.Thread, StoppableThread): address, 'privSigningKey', privSigningKeyWIF) BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) - shared.writeKeysFile() + BMConfigParser().save() # The API and the join and create Chan functionality # both need information back from the address generator. @@ -260,7 +260,7 @@ class addressGenerator(threading.Thread, StoppableThread): address, 'privSigningKey', privSigningKeyWIF) BMConfigParser().set( address, 'privEncryptionKey', privEncryptionKeyWIF) - shared.writeKeysFile() + BMConfigParser().save() shared.UISignalQueue.put(('writeNewAddressToTable', ( label, address, str(streamNumber)))) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index b09bb6fd..e124c7f5 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -185,7 +185,7 @@ class singleWorker(threading.Thread, StoppableThread): try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - shared.writeKeysFile() + BMConfigParser().save() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -275,7 +275,7 @@ class singleWorker(threading.Thread, StoppableThread): try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - shared.writeKeysFile() + BMConfigParser().save() except: # The user deleted the address out of the keys.dat file before this # finished. @@ -365,7 +365,7 @@ class singleWorker(threading.Thread, StoppableThread): try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) - shared.writeKeysFile() + BMConfigParser().save() except Exception as err: logger.error('Error: Couldn\'t add the lastpubkeysendtime to the keys.dat file. Error message: %s' % err) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index df747aea..9b0ba696 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -330,7 +330,7 @@ class sqlThread(threading.Thread): BMConfigParser().set('bitmessagesettings', 'maxdownloadrate', '0') BMConfigParser().set('bitmessagesettings', 'maxuploadrate', '0') BMConfigParser().set('bitmessagesettings', 'settingsversion', '10') - shared.writeKeysFile() + BMConfigParser().save() # sanity check if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: @@ -433,7 +433,7 @@ class sqlThread(threading.Thread): BMConfigParser().set('bitmessagesettings', 'smtpdeliver', '') if not BMConfigParser().has_option('bitmessagesettings', 'hidetrayconnectionnotifications'): BMConfigParser().set('bitmessagesettings', 'hidetrayconnectionnotifications', 'false') - shared.writeKeysFile() + 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! diff --git a/src/configparser.py b/src/configparser.py index ac70cee4..4d49e6f4 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -1,6 +1,10 @@ import ConfigParser +import datetime +import shutil +import os from singleton import Singleton +import state @Singleton @@ -44,3 +48,20 @@ class BMConfigParser(ConfigParser.SafeConfigParser): def items(self, section, raw=False, vars=None): return ConfigParser.ConfigParser.items(self, section, True, vars) + 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: + # 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) diff --git a/src/helper_startup.py b/src/helper_startup.py index a07bffb8..a0f4c913 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,5 +1,4 @@ import ConfigParser -import shared from configparser import BMConfigParser import sys import os @@ -138,7 +137,7 @@ def loadConfig(): os.makedirs(state.appdata) if not sys.platform.startswith('win'): os.umask(0o077) - shared.writeKeysFile() + BMConfigParser().save() _loadTrustedPeer() diff --git a/src/shared.py b/src/shared.py index be291a75..57ff7908 100644 --- a/src/shared.py +++ b/src/shared.py @@ -623,22 +623,4 @@ def openKeysFile(): else: os.startfile(state.appdata + 'keys.dat') -def writeKeysFile(): - fileName = 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: - # The backup failed. This can happen if the file didn't exist before. - fileNameExisted = False - # write the file - with open(fileName, 'wb') as configfile: - BMConfigParser().write(configfile) - # delete the backup - if fileNameExisted: - os.remove(fileNameBak) - from debug import logger -- 2.45.1 From 9bf17b34d16d13f5686d4c2ed4b244040f2d0b70 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 11:40:31 +0100 Subject: [PATCH 0570/1102] Remove obsolete imports and code - landscape.io pointed out obsolete imports - there is also an obsolete variable and lock in throttle.py - add Exception type to BMConfigParser().save --- src/configparser.py | 2 +- src/shared.py | 2 -- src/throttle.py | 4 ---- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/configparser.py b/src/configparser.py index 4d49e6f4..72fb5f20 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -56,7 +56,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): shutil.copyfile(fileName, fileNameBak) # The backup succeeded. fileNameExisted = True - except: + except IOError, Error: # The backup failed. This can happen if the file didn't exist before. fileNameExisted = False # write the file diff --git a/src/shared.py b/src/shared.py index 57ff7908..f4956add 100644 --- a/src/shared.py +++ b/src/shared.py @@ -16,8 +16,6 @@ import sys import stat import threading import time -import shutil # used for moving the data folder and copying keys.dat -import datetime import traceback from binascii import hexlify diff --git a/src/throttle.py b/src/throttle.py index 5b503e1e..e58ca11a 100644 --- a/src/throttle.py +++ b/src/throttle.py @@ -26,8 +26,6 @@ class Throttle(object): self.txLen = 0 def wait(self, dataLen): - with self.lock: - self.waiting = True with self.lock: self.txLen += dataLen self.total += dataLen @@ -38,8 +36,6 @@ class Throttle(object): if self.txLen < self.limit: break self.timer.wait(0.2) - with self.lock: - self.waiting = False def getSpeed(self): self.recalculate() -- 2.45.1 From 869417f506fbcd1db8629188677f89cdf66ab596 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 11:42:20 +0100 Subject: [PATCH 0571/1102] Missing import --- dev/ssltest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/ssltest.py b/dev/ssltest.py index 538801f5..4ddca8ca 100644 --- a/dev/ssltest.py +++ b/dev/ssltest.py @@ -1,3 +1,4 @@ +import os import select import socket import ssl -- 2.45.1 From c3fef7bc4edecb905bc4c582d3d295d8b6c5f63c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 12:41:19 +0100 Subject: [PATCH 0572/1102] Syntax fix --- src/configparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/configparser.py b/src/configparser.py index 72fb5f20..37a35868 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -56,7 +56,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): shutil.copyfile(fileName, fileNameBak) # The backup succeeded. fileNameExisted = True - except IOError, Error: + except (IOError, Error): # The backup failed. This can happen if the file didn't exist before. fileNameExisted = False # write the file -- 2.45.1 From 6d2a75bfc9a1124ccd05a0e9d1ad07b858897c6d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 15:08:03 +0100 Subject: [PATCH 0573/1102] Transfer speed improvements - send buffer to send multiple commands in one TCP packet - recv/send operation size now based on bandwith limit - send queue limited to 100 entries - buffer getdata commands to fill send queue, instead of waiting for the data packet to arrive first (i.e. allow getdata to work asynchronously) --- src/class_outgoingSynSender.py | 2 +- src/class_receiveDataThread.py | 7 +++--- src/class_sendDataThread.py | 43 ++++++++++++++++------------------ src/class_singleListener.py | 2 +- src/throttle.py | 21 +++++++++++++++++ 5 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 9ea361cc..b8e3193f 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -191,7 +191,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): try: self.sock.connect((peer.host, peer.port)) 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. + sendDataThreadQueue = Queue.Queue(100) # 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, diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index deb1e05b..1abb8e74 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -90,9 +90,9 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): ssl = True - dataRecv = self.sslSock.recv(4096) + dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) else: - dataRecv = self.sock.recv(4096) + dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) self.data += dataRecv throttle.ReceiveThrottle().wait(len(dataRecv)) except socket.timeout: @@ -222,7 +222,7 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0: + while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0 and not self.sendDataThreadQueue.full(): objectHash, = random.sample( self.objectsThatWeHaveYetToGetFromThisPeer, 1) if objectHash in Inventory(): @@ -240,7 +240,6 @@ class receiveDataThread(threading.Thread): 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. logger.debug('(concerning' + str(self.peer) + ') number of objectsThatWeHaveYetToGetFromThisPeer is now 0') diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 76409050..55e674cb 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -42,6 +42,7 @@ class sendDataThread(threading.Thread): self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator self.streamNumber = streamNumber self.services = 0 + self.buffer = "" self.initiatedConnection = False self.remoteProtocolVersion = - \ 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.sendDataThreadQueue queue. @@ -69,36 +70,32 @@ class sendDataThread(threading.Thread): self.versionSent = 1 - def sendBytes(self, data): - while data: - if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and - self.connectionIsOrWasFullyEstablished and - protocol.haveSSL(not self.initiatedConnection)): - while state.shutdown == 0: - try: - amountSent = self.sslSock.send(data[:4096]) - break - except socket.error as e: - if e.errno == errno.EAGAIN: - continue - raise - else: - while True: - try: - amountSent = self.sock.send(data[:4096]) - break - except socket.error as e: - if e.errno == errno.EAGAIN: - continue - raise + def sendBytes(self, data = ""): + self.buffer += data + if len(self.buffer) < throttle.SendThrottle().chunkSize and self.sendDataThreadQueue.qsize() > 1: + return + + while self.buffer and state.shutdown == 0: + try: + if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + protocol.haveSSL(not self.initiatedConnection)): + amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) + else: + amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) + except socket.error as e: + if e.errno == errno.EAGAIN: + continue + raise throttle.SendThrottle().wait(amountSent) self.lastTimeISentData = int(time.time()) - data = data[amountSent:] + self.buffer = self.buffer[amountSent:] def run(self): logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(state.sendDataQueues))) while True: + self.sendBytes() deststream, command, data = self.sendDataThreadQueue.get() if deststream == self.streamNumber or deststream == 0: diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 49acc71c..65c0a8a8 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -134,7 +134,7 @@ class singleListener(threading.Thread, StoppableThread): 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. + sendDataThreadQueue = Queue.Queue(100) # Used to submit information to the send data thread for this connection. socketObject.settimeout(20) sd = sendDataThread(sendDataThreadQueue) diff --git a/src/throttle.py b/src/throttle.py index e58ca11a..9578adc5 100644 --- a/src/throttle.py +++ b/src/throttle.py @@ -1,3 +1,4 @@ +import math import threading import time @@ -6,14 +7,19 @@ from singleton import Singleton import state class Throttle(object): + minChunkSize = 4096 + maxChunkSize = 131072 + def __init__(self, limit=0): self.limit = limit self.speed = 0 + self.chunkSize = Throttle.maxChunkSize self.txTime = int(time.time()) self.txLen = 0 self.total = 0 self.timer = threading.Event() self.lock = threading.RLock() + self.resetChunkSize() def recalculate(self): with self.lock: @@ -41,6 +47,19 @@ class Throttle(object): 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): @@ -49,6 +68,7 @@ class SendThrottle(Throttle): def resetLimit(self): with self.lock: self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxuploadrate')*1024 + Throttle.resetChunkSize() @Singleton class ReceiveThrottle(Throttle): @@ -58,3 +78,4 @@ class ReceiveThrottle(Throttle): def resetLimit(self): with self.lock: self.limit = BMConfigParser().safeGetInt('bitmessagesettings', 'maxdownloadrate')*1024 + Throttle.resetChunkSize() -- 2.45.1 From f079ff5b99034bf6db8ed709d9bd859d73da4d4d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 19:21:24 +0100 Subject: [PATCH 0574/1102] Refactor objects to be downloaded - moved logic into a Missing singleton - shouldn't try to download duplicates anymore, only requests a hash once every 5 minutes and not from the same host - removed obsoleted variables - the "Objects to be synced" in the Network tab should now be correct - removed some checks which aren't necessary anymore in my opinion - fix missing self in Throttle (thanks landscape.io) --- src/bitmessageqt/__init__.py | 9 ++-- src/bitmessageqt/networkstatus.py | 4 +- src/class_receiveDataThread.py | 86 ++++++------------------------- src/inventory.py | 85 ++++++++++++++++++++++++------ src/shared.py | 8 ++- src/throttle.py | 4 +- 6 files changed, 99 insertions(+), 97 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5f1a65e6..4cdcae30 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -77,6 +77,7 @@ from dialogs import AddAddressDialog from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from helper_generic import powQueueSize, invQueueSize +from inventory import Missing import paths from proofofwork import getPowType import protocol @@ -2712,11 +2713,9 @@ class MyForm(settingsmixin.SMainWindow): elif reply == QtGui.QMessage.Cancel: return - toBeDownloaded = sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues()) - - if toBeDownloaded > 0: + if Missing().len() > 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, toBeDownloaded), + _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, Missing().len()), QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.Yes: waitForSync = True @@ -2747,7 +2746,7 @@ class MyForm(settingsmixin.SMainWindow): if waitForSync: self.statusBar().showMessage(_translate( "MainWindow", "Waiting for finishing synchronisation...")) - while sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues()) > 0: + while Missing().len() > 0: time.sleep(0.5) QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 2fe493ac..3eeae392 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -2,7 +2,7 @@ from PyQt4 import QtCore, QtGui import time import shared from tr import _translate -from inventory import Inventory +from inventory import Inventory, Missing import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler @@ -45,7 +45,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): return "%4.0f kB" % num def updateNumberOfObjectsToBeSynced(self): - self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues()))) + self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, Missing().len())) def updateNumberOfMessagesProcessed(self): self.updateNumberOfObjectsToBeSynced() diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 1abb8e74..40add534 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -30,7 +30,7 @@ from helper_sql import sqlQuery from debug import logger import paths import protocol -from inventory import Inventory +from inventory import Inventory, Missing import state import throttle import tr @@ -62,7 +62,6 @@ class receiveDataThread(threading.Thread): self.peer = state.Peer(HOST, port) self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator 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 @@ -129,11 +128,7 @@ class receiveDataThread(threading.Thread): except Exception as err: logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) - try: - del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ - self.peer] - except: - pass + Missing().threadEnd() shared.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))) @@ -222,37 +217,16 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - while len(self.objectsThatWeHaveYetToGetFromThisPeer) > 0 and not self.sendDataThreadQueue.full(): - objectHash, = random.sample( - self.objectsThatWeHaveYetToGetFromThisPeer, 1) + while Missing().len() > 0 and not self.sendDataThreadQueue.full(): + objectHash = Missing().pull() + if objectHash is None: + break if objectHash in Inventory(): logger.debug('Inventory already has object listed in inv message.') - del self.objectsThatWeHaveYetToGetFromThisPeer[objectHash] + Missing().delete(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: - logger.debug('(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: - # We had objectsThatWeHaveYetToGetFromThisPeer but the loop ran, they were all in our inventory, and now we don't have any to get anymore. - logger.debug('(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: - logger.debug('(concerning' + str(self.peer) + ') number of objectsThatWeHaveYetToGetFromThisPeer is now ' + str(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() @@ -425,13 +399,6 @@ 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 - logger.debug('number of keys(hosts) in shared.numberOfObjectsThatWeHaveYetToGetPerPeer: ' + str(len(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)) + "\n" + \ - 'totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers = ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers)) - numberOfItemsInInv, lengthOfVarint = decodeVarint(data[:10]) if numberOfItemsInInv > 50000: sys.stderr.write('Too many items in inv message!') @@ -439,35 +406,16 @@ class receiveDataThread(threading.Thread): if len(data) < lengthOfVarint + (numberOfItemsInInv * 32): logger.info('inv message doesn\'t contain enough data. Ignoring.') return - if numberOfItemsInInv == 1: # we'll just request this data from the person who advertised the object. - if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and state.trustedPeer == None: # inv flooding attack mitigation - logger.debug('We already have ' + str(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 - if data[lengthOfVarint:32 + lengthOfVarint] in Inventory(): - logger.debug('Inventory 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 - Inventory().hashes_by_stream(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 and state.trustedPeer == None: # inv flooding attack mitigation - logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over ' + str(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) + + startTime = time.time() + advertisedSet = set() + for i in range(numberOfItemsInInv): + advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) + objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(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: + Missing().add(item) + self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[item] = 0 # helps us keep from sending inv messages to peers that already know about the objects listed therein # Send a getdata message to our peer to request the object with the given # hash diff --git a/src/inventory.py b/src/inventory.py index 83a9ce82..3e00822a 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,13 +1,11 @@ import collections -from threading import RLock +import random +from threading import current_thread, RLock import time from helper_sql import * from singleton import Singleton -inventoryLock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) -InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') - @Singleton class Inventory(collections.MutableMapping): @@ -16,26 +14,28 @@ class Inventory(collections.MutableMapping): self._inventory = {} #of objects (like msg payloads and pubkey payloads) Does not include protocol headers (the first 24 bytes of each packet). self.numberOfInventoryLookupsPerformed = 0 self._streams = collections.defaultdict(set) # 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. + self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) + self.InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') def __contains__(self, hash): - with inventoryLock: + with self.lock: self.numberOfInventoryLookupsPerformed += 1 if hash in self._inventory: return True return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) def __getitem__(self, hash): - with inventoryLock: + with self.lock: if hash in self._inventory: return self._inventory[hash] rows = sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE hash=?', hash) if not rows: raise KeyError(hash) - return InventoryItem(*rows[0]) + return self.InventoryItem(*rows[0]) def __setitem__(self, hash, value): - with inventoryLock: - value = InventoryItem(*value) + with self.lock: + value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) @@ -43,42 +43,93 @@ class Inventory(collections.MutableMapping): raise NotImplementedError def __iter__(self): - with inventoryLock: + with self.lock: hashes = self._inventory.keys()[:] hashes += (hash for hash, in sqlQuery('SELECT hash FROM inventory')) return hashes.__iter__() def __len__(self): - with inventoryLock: + with self.lock: return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0] def by_type_and_tag(self, type, tag): - with inventoryLock: + with self.lock: values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] - values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) + values += (self.InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) return values def hashes_by_stream(self, stream): - with inventoryLock: + with self.lock: return self._streams[stream] def unexpired_hashes_by_stream(self, stream): - with inventoryLock: + with self.lock: t = int(time.time()) hashes = [hash for hash, value in self._inventory.items() if value.stream == stream and value.expires > t] hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) return hashes def flush(self): - with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + 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 hash, value in self._inventory.items(): sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value) self._inventory.clear() def clean(self): - with inventoryLock: + with self.lock: sqlExecute('DELETE FROM inventory WHERE expirestime Date: Sun, 15 Jan 2017 19:50:28 +0100 Subject: [PATCH 0575/1102] Objects to be downloaded fixes - tries to avoid calling senddata it it would block receiveDataThread, allowing fore more asynchronous operation - request objects in chunks of 100 (CPU performance optimisation) --- src/class_receiveDataThread.py | 20 ++++++++++---------- src/inventory.py | 28 +++++++++++++++++----------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 40add534..c3373efe 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -217,16 +217,16 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - while Missing().len() > 0 and not self.sendDataThreadQueue.full(): - objectHash = Missing().pull() - if objectHash is None: - break - if objectHash in Inventory(): - logger.debug('Inventory already has object listed in inv message.') - Missing().delete(objectHash) - else: - # We don't have the object in our inventory. Let's request it. - self.sendgetdata(objectHash) + if Missing().len() > 0 and self.sendDataThreadQueue.qsize() < 10: + for objectHash in Missing().pull(100): + if self.sendDataThreadQueue.full(): + break + if objectHash in Inventory(): + logger.debug('Inventory already has object listed in inv message.') + Missing().delete(objectHash) + else: + # We don't have the object in our inventory. Let's request it. + self.sendgetdata(objectHash) self.processData() diff --git a/src/inventory.py b/src/inventory.py index 3e00822a..e2a3eb01 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -101,23 +101,29 @@ class Missing(object): with self.lock: return len(self.hashes) - def pull(self): + def pull(self, count=1): + if count < 1: + raise ValueError("Must be at least one") with self.lock: now = time.time() since = now - 300 # once every 5 minutes try: - objectHash = random.choice({k:v for k, v in self.hashes.iteritems() if current_thread().peer in self.hashes[k]['peers'] and self.hashes[k]['requested'] < since}.keys()) + matchingHashes = {k:v for k, v in self.hashes.iteritems() if current_thread().peer in self.hashes[k]['peers'] and self.hashes[k]['requested'] < since} + if count > len(matchingHashes): + count = len(matchingHashes) + objectHashes = random.sample(matchingHashes, count) except (IndexError, KeyError): # list is empty return None - try: - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except ValueError: - pass - if len(self.hashes[objectHash]['peers']) == 0: - self.delete(objectHash) - else: - self.hashes[objectHash]['requested'] = now - return objectHash + for objectHash in objectHashes: + try: + self.hashes[objectHash]['peers'].remove(current_thread().peer) + except ValueError: + pass + if len(self.hashes[objectHash]['peers']) == 0: + self.delete(objectHash) + else: + self.hashes[objectHash]['requested'] = now + return objectHashes def delete(self, objectHash): with self.lock: -- 2.45.1 From 79893fdc23ed4d0f970a676c306cba8f09e639fa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 20:47:33 +0100 Subject: [PATCH 0576/1102] Performance tuning objects to be downloaded - rely on dict quasi-random order instead of an additional shuffle - request an object once per minute - stop check after count objects have been found --- src/inventory.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index e2a3eb01..b4fcce6d 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -106,23 +106,15 @@ class Missing(object): raise ValueError("Must be at least one") with self.lock: now = time.time() - since = now - 300 # once every 5 minutes - try: - matchingHashes = {k:v for k, v in self.hashes.iteritems() if current_thread().peer in self.hashes[k]['peers'] and self.hashes[k]['requested'] < since} - if count > len(matchingHashes): - count = len(matchingHashes) - objectHashes = random.sample(matchingHashes, count) - except (IndexError, KeyError): # list is empty - return None - for objectHash in objectHashes: - try: + since = now - 60 # once every minute + objectHashes = [] + for objectHash in self.hashes.keys(): + if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < since: + objectHashes.append(objectHash) self.hashes[objectHash]['peers'].remove(current_thread().peer) - except ValueError: - pass - if len(self.hashes[objectHash]['peers']) == 0: - self.delete(objectHash) - else: self.hashes[objectHash]['requested'] = now + if len(objectHashes) >= count: + break return objectHashes def delete(self, objectHash): -- 2.45.1 From 94f0bdc731315dda348534395be83c83d9960f0d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 22:01:10 +0100 Subject: [PATCH 0577/1102] Objects to be downloaded optimising - treat requested but never arrived objects as expired. This is how it worked before the refactoring. Without this, the list won't go to zero. --- src/inventory.py | 26 +++++++++++++++----------- src/shared.py | 7 +------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index b4fcce6d..77291a5c 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,5 +1,4 @@ import collections -import random from threading import current_thread, RLock import time @@ -38,6 +37,7 @@ class Inventory(collections.MutableMapping): value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) + Missing().delete(hash) def __delitem__(self, hash): raise NotImplementedError @@ -101,18 +101,27 @@ class Missing(object): with self.lock: return len(self.hashes) + def removeObjectFromCurrentThread(self, objectHash): + with self.lock: + try: + self.hashes[objectHash]['peers'].remove(current_thread().peer) + except ValueError: + pass + if len(self.hashes[objectHash]['peers']) == 0: + self.delete(objectHash) + else: + self.hashes[objectHash]['requested'] = time.time() + def pull(self, count=1): if count < 1: raise ValueError("Must be at least one") with self.lock: - now = time.time() - since = now - 60 # once every minute + since = time.time() - 60 # once every minute objectHashes = [] for objectHash in self.hashes.keys(): if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < since: objectHashes.append(objectHash) - self.hashes[objectHash]['peers'].remove(current_thread().peer) - self.hashes[objectHash]['requested'] = now + self.removeObjectFromCurrentThread(objectHash) if len(objectHashes) >= count: break return objectHashes @@ -125,9 +134,4 @@ class Missing(object): def threadEnd(self): with self.lock: for objectHash in self.hashes: - try: - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except ValueError: - pass - -# current_thread().peer + self.removeObjectFromCurrentThread(objectHash) diff --git a/src/shared.py b/src/shared.py index 33b1dc33..022fa4b3 100644 --- a/src/shared.py +++ b/src/shared.py @@ -27,7 +27,7 @@ import highlevelcrypto #import helper_startup from helper_sql import * from helper_threading import * -from inventory import Inventory, Missing +from inventory import Inventory import protocol import state @@ -474,7 +474,6 @@ def _checkAndShareUndefinedObjectWithPeers(data): return inventoryHash = calculateInventoryHash(data) - Missing().delete(inventoryHash) if inventoryHash in Inventory(): logger.debug('We have already received this undefined object. Ignoring.') return @@ -498,7 +497,6 @@ def _checkAndShareMsgWithPeers(data): return readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) - Missing().delete(inventoryHash) if inventoryHash in Inventory(): logger.debug('We have already received this msg message. Ignoring.') return @@ -531,7 +529,6 @@ def _checkAndShareGetpubkeyWithPeers(data): readPosition += streamNumberLength inventoryHash = calculateInventoryHash(data) - Missing().delete(inventoryHash) if inventoryHash in Inventory(): logger.debug('We have already received this getpubkey request. Ignoring it.') return @@ -567,7 +564,6 @@ def _checkAndSharePubkeyWithPeers(data): tag = '' inventoryHash = calculateInventoryHash(data) - Missing().delete(inventoryHash) if inventoryHash in Inventory(): logger.debug('We have already received this pubkey. Ignoring it.') return @@ -603,7 +599,6 @@ def _checkAndShareBroadcastWithPeers(data): else: tag = '' inventoryHash = calculateInventoryHash(data) - Missing().delete(inventoryHash) if inventoryHash in Inventory(): logger.debug('We have already received this broadcast object. Ignoring.') return -- 2.45.1 From 805f72e0981dcced272806da6a90cf88d4fa19b7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 22:21:19 +0100 Subject: [PATCH 0578/1102] Make objects to be send stoppable if not empty --- src/bitmessageqt/__init__.py | 2 ++ src/inventory.py | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4cdcae30..04562fe6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2721,6 +2721,8 @@ class MyForm(settingsmixin.SMainWindow): waitForSync = True elif reply == QtGui.QMessageBox.Cancel: return + else: + Missing().stop() if shared.statusIconColor == 'red': reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Not connected"), diff --git a/src/inventory.py b/src/inventory.py index 77291a5c..0e81e756 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -90,8 +90,11 @@ class Missing(object): super(self.__class__, self).__init__() self.lock = RLock() self.hashes = {} + self.stopped = False def add(self, objectHash): + if self.stopped: + return with self.lock: if not objectHash in self.hashes: self.hashes[objectHash] = {'peers':[], 'requested':0} @@ -105,6 +108,8 @@ class Missing(object): with self.lock: try: self.hashes[objectHash]['peers'].remove(current_thread().peer) + except KeyError: + return except ValueError: pass if len(self.hashes[objectHash]['peers']) == 0: @@ -131,6 +136,10 @@ class Missing(object): if objectHash in self.hashes: del self.hashes[objectHash] + def stop(self): + with self.lock: + self.hashes = {} + def threadEnd(self): with self.lock: for objectHash in self.hashes: -- 2.45.1 From b750e67bfbd741ebf415067c2e58953d34679e67 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 22:25:09 +0100 Subject: [PATCH 0579/1102] Handle exception in iterator --- src/inventory.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index 0e81e756..b8b29fea 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -123,12 +123,16 @@ class Missing(object): with self.lock: since = time.time() - 60 # once every minute objectHashes = [] - for objectHash in self.hashes.keys(): - if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < since: - objectHashes.append(objectHash) - self.removeObjectFromCurrentThread(objectHash) - if len(objectHashes) >= count: - break + try: + for objectHash in self.hashes.keys(): + if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < since: + objectHashes.append(objectHash) + self.removeObjectFromCurrentThread(objectHash) + if len(objectHashes) >= count: + break + except RuntimeError: + # the for cycle sometimes breaks if you remove elements + pass return objectHashes def delete(self, objectHash): -- 2.45.1 From d04c0e78e44b1269de1008a24bc129a2ee95f800 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 22:36:12 +0100 Subject: [PATCH 0580/1102] Better handling of pending downloading objects --- src/inventory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index b8b29fea..fcc1ac94 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -86,6 +86,7 @@ class Inventory(collections.MutableMapping): @Singleton class Missing(object): + frequency = 60 def __init__(self): super(self.__class__, self).__init__() self.lock = RLock() @@ -112,7 +113,7 @@ class Missing(object): return except ValueError: pass - if len(self.hashes[objectHash]['peers']) == 0: + if len(self.hashes[objectHash]['peers']) == 0 and self.hashes[objectHash]['requested'] < time.time() - Missing.frequency: self.delete(objectHash) else: self.hashes[objectHash]['requested'] = time.time() @@ -121,11 +122,10 @@ class Missing(object): if count < 1: raise ValueError("Must be at least one") with self.lock: - since = time.time() - 60 # once every minute objectHashes = [] try: for objectHash in self.hashes.keys(): - if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < since: + if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < time.time() - Missing.frequency: objectHashes.append(objectHash) self.removeObjectFromCurrentThread(objectHash) if len(objectHashes) >= count: -- 2.45.1 From bd1aead46ee8046c0c108b117399a702a72ef468 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 22:41:12 +0100 Subject: [PATCH 0581/1102] More fixes for objects to be downloaded --- src/inventory.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index fcc1ac94..d9fefdad 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -86,12 +86,12 @@ class Inventory(collections.MutableMapping): @Singleton class Missing(object): - frequency = 60 def __init__(self): super(self.__class__, self).__init__() self.lock = RLock() self.hashes = {} self.stopped = False + self.frequency = 60 def add(self, objectHash): if self.stopped: @@ -113,7 +113,7 @@ class Missing(object): return except ValueError: pass - if len(self.hashes[objectHash]['peers']) == 0 and self.hashes[objectHash]['requested'] < time.time() - Missing.frequency: + if len(self.hashes[objectHash]['peers']) == 0 and self.hashes[objectHash]['requested'] < time.time() - self.frequency: self.delete(objectHash) else: self.hashes[objectHash]['requested'] = time.time() @@ -125,11 +125,15 @@ class Missing(object): objectHashes = [] try: for objectHash in self.hashes.keys(): - if current_thread().peer in self.hashes[objectHash]['peers'] and self.hashes[objectHash]['requested'] < time.time() - Missing.frequency: - objectHashes.append(objectHash) - self.removeObjectFromCurrentThread(objectHash) - if len(objectHashes) >= count: - break + if self.hashes[objectHash]['requested'] < time.time() - self.frequency: + if len(self.hashes[objectHash]['peers']) == 0: + self.removeObjectFromCurrentThread(objectHash) + continue + if current_thread().peer in self.hashes[objectHash]['peers']: + objectHashes.append(objectHash) + self.removeObjectFromCurrentThread(objectHash) + if len(objectHashes) >= count: + break except RuntimeError: # the for cycle sometimes breaks if you remove elements pass -- 2.45.1 From 12205ee7baba3c1e8353deadedbc1b311721c5dd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 23:07:11 +0100 Subject: [PATCH 0582/1102] More fixes in objects to be downloaded --- src/inventory.py | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index d9fefdad..5e54f52b 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -121,23 +121,22 @@ class Missing(object): def pull(self, count=1): if count < 1: raise ValueError("Must be at least one") - with self.lock: - objectHashes = [] - try: - for objectHash in self.hashes.keys(): - if self.hashes[objectHash]['requested'] < time.time() - self.frequency: - if len(self.hashes[objectHash]['peers']) == 0: - self.removeObjectFromCurrentThread(objectHash) - continue - if current_thread().peer in self.hashes[objectHash]['peers']: - objectHashes.append(objectHash) - self.removeObjectFromCurrentThread(objectHash) - if len(objectHashes) >= count: - break - except RuntimeError: - # the for cycle sometimes breaks if you remove elements - pass - return objectHashes + objectHashes = [] + try: + for objectHash in self.hashes.keys(): + if self.hashes[objectHash]['requested'] < time.time() - self.frequency: + if len(self.hashes[objectHash]['peers']) == 0: + self.removeObjectFromCurrentThread(objectHash) + continue + if current_thread().peer in self.hashes[objectHash]['peers']: + objectHashes.append(objectHash) + self.removeObjectFromCurrentThread(objectHash) + if len(objectHashes) >= count: + break + except (RuntimeError, KeyError, ValueError): + # the for cycle sometimes breaks if you remove elements + pass + return objectHashes def delete(self, objectHash): with self.lock: -- 2.45.1 From 8dfa0faca954aad0535f660938dc883c53ab0b97 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 15 Jan 2017 23:10:44 +0100 Subject: [PATCH 0583/1102] More objects to be downloaded fixes --- src/inventory.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/inventory.py b/src/inventory.py index 5e54f52b..8530a44f 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -130,6 +130,7 @@ class Missing(object): continue if current_thread().peer in self.hashes[objectHash]['peers']: objectHashes.append(objectHash) + self.hashes[objectHash]['requested'] = time.time() self.removeObjectFromCurrentThread(objectHash) if len(objectHashes) >= count: break -- 2.45.1 From ca6bc9981c9493d176b1874b948de2ef60f098d8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 15:17:23 +0100 Subject: [PATCH 0584/1102] Better tracking in downloading objects - remember what was requested from which node - remember if it was received - re-request object if we haven't received any new object for more than a minute --- src/class_receiveDataThread.py | 19 ++++++------ src/inventory.py | 53 +++++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c3373efe..622c71ca 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -217,16 +217,15 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - if Missing().len() > 0 and self.sendDataThreadQueue.qsize() < 10: - for objectHash in Missing().pull(100): - if self.sendDataThreadQueue.full(): - break - if objectHash in Inventory(): - logger.debug('Inventory already has object listed in inv message.') - Missing().delete(objectHash) - else: - # We don't have the object in our inventory. Let's request it. - self.sendgetdata(objectHash) + for objectHash in Missing().pull(100): + if self.sendDataThreadQueue.full(): + break + if objectHash in Inventory(): + logger.debug('Inventory already has object listed in inv message.') + Missing().delete(objectHash) + else: + # We don't have the object in our inventory. Let's request it. + self.sendgetdata(objectHash) self.processData() diff --git a/src/inventory.py b/src/inventory.py index 8530a44f..8b2f6e26 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -37,7 +37,7 @@ class Inventory(collections.MutableMapping): value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) - Missing().delete(hash) + Missing().delete(hash, True) def __delitem__(self, hash): raise NotImplementedError @@ -92,15 +92,25 @@ class Missing(object): self.hashes = {} self.stopped = False self.frequency = 60 + self.pending = {} def add(self, objectHash): if self.stopped: return with self.lock: - if not objectHash in self.hashes: + if objectHash not in self.hashes: self.hashes[objectHash] = {'peers':[], 'requested':0} self.hashes[objectHash]['peers'].append(current_thread().peer) + def addPending(self, objectHash=None): + if self.stopped: + return + if current_thread().peer not in self.pending: + self.pending[current_thread().peer] = {'objects':[], 'requested':0, 'received':0} + if objectHash not in self.pending[current_thread().peer]['objects'] and not objectHash is None: + self.pending[current_thread().peer]['objects'].append(objectHash) + self.pending[current_thread().peer]['requested'] = time.time() + def len(self): with self.lock: return len(self.hashes) @@ -122,33 +132,54 @@ class Missing(object): if count < 1: raise ValueError("Must be at least one") objectHashes = [] + if self.stopped: + return objectHashes try: for objectHash in self.hashes.keys(): + if len(objectHashes) >= count: + break + if current_thread().peer not in self.pending: + self.addPending() + if (self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or \ + self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ + len(self.pending[current_thread().peer]['objects']) >= count: + break + # requested too long ago or not at all if self.hashes[objectHash]['requested'] < time.time() - self.frequency: - if len(self.hashes[objectHash]['peers']) == 0: - self.removeObjectFromCurrentThread(objectHash) + # already requested from this thread but haven't received yet + if objectHash in self.pending[current_thread().peer]['objects']: + if self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or self.pending[current_thread().peer]['received'] >= time.time() - self.frequency: + continue + elif current_thread().peer not in self.hashes[objectHash]['peers']: continue - if current_thread().peer in self.hashes[objectHash]['peers']: - objectHashes.append(objectHash) - self.hashes[objectHash]['requested'] = time.time() - self.removeObjectFromCurrentThread(objectHash) - if len(objectHashes) >= count: - break + objectHashes.append(objectHash) + self.hashes[objectHash]['requested'] = time.time() + self.pending[current_thread().peer]['requested'] = time.time() + self.addPending(objectHash) except (RuntimeError, KeyError, ValueError): # the for cycle sometimes breaks if you remove elements pass return objectHashes - def delete(self, objectHash): + def delete(self, objectHash, justReceived=False): with self.lock: if objectHash in self.hashes: del self.hashes[objectHash] + if objectHash in self.pending[current_thread().peer]['objects']: + self.pending[current_thread().peer]['objects'].remove(objectHash) + if justReceived: + self.pending[current_thread().peer]['received'] = time.time() def stop(self): with self.lock: self.hashes = {} + self.pending = {} def threadEnd(self): with self.lock: for objectHash in self.hashes: self.removeObjectFromCurrentThread(objectHash) + try: + del self.pending[current_thread().peer] + except KeyError: + pass -- 2.45.1 From 9f89df6d1cbcafc5feaf4271cfacb4abdc6d740c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 17:08:47 +0100 Subject: [PATCH 0585/1102] Expire objects that we're unable to receive - sometimes a node would send an "inv" about an object but then not provide it when requested. This could be that it expired in the meantime or it was an attack or a bug. This patch will forget that the object exists if was requested too many times and not received. --- src/inventory.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index 8b2f6e26..8a747d4b 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -91,7 +91,10 @@ class Missing(object): self.lock = RLock() self.hashes = {} self.stopped = False + # don't request the same object more frequently than this self.frequency = 60 + # after requesting and not receiving an object more than this times, consider it expired + self.maxRequestCount = 6 self.pending = {} def add(self, objectHash): @@ -99,7 +102,7 @@ class Missing(object): return with self.lock: if objectHash not in self.hashes: - self.hashes[objectHash] = {'peers':[], 'requested':0} + self.hashes[objectHash] = {'peers':[], 'requested':0, 'requestedCount':0} self.hashes[objectHash]['peers'].append(current_thread().peer) def addPending(self, objectHash=None): @@ -144,16 +147,31 @@ class Missing(object): self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ len(self.pending[current_thread().peer]['objects']) >= count: break - # requested too long ago or not at all + # requested too long ago or not at all from any thread if self.hashes[objectHash]['requested'] < time.time() - self.frequency: - # already requested from this thread but haven't received yet + # ready requested from this thread but haven't received yet if objectHash in self.pending[current_thread().peer]['objects']: - if self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or self.pending[current_thread().peer]['received'] >= time.time() - self.frequency: + # if still sending or receiving, request next + if self.pending[current_thread().peer]['received'] >= time.time() - self.frequency or \ + self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency: continue + # haven't requested or received anything recently, re-request (i.e. continue) + # the current node doesn't have the object elif current_thread().peer not in self.hashes[objectHash]['peers']: continue + # already requested too many times, remove all signs of this object + if self.hashes[objectHash]['requestedCount'] >= self.maxRequestCount: + with self.lock: + del self.hashes[objectHash] + for thread in self.pending.keys(): + if objectHash in self.pending[thread]['objects']: + self.pending[thread]['objects'].remove(objectHash) + continue + # all ok, request objectHashes.append(objectHash) self.hashes[objectHash]['requested'] = time.time() + with self.lock: + self.hashes[objectHash]['requestedCount'] += 1 self.pending[current_thread().peer]['requested'] = time.time() self.addPending(objectHash) except (RuntimeError, KeyError, ValueError): -- 2.45.1 From d652dc864d3324bb5495c5554bba92109d3c153d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 19:36:58 +0100 Subject: [PATCH 0586/1102] Downloading fixes - able to request more objects with one command - fixes to logic and error handling --- src/class_receiveDataThread.py | 22 ++++---- src/inventory.py | 94 ++++++++++++++++++---------------- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 622c71ca..304068fb 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -9,6 +9,7 @@ import threading import shared import hashlib import os +import Queue import select import socket import random @@ -217,15 +218,10 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages - for objectHash in Missing().pull(100): - if self.sendDataThreadQueue.full(): - break - if objectHash in Inventory(): - logger.debug('Inventory already has object listed in inv message.') - Missing().delete(objectHash) - else: - # We don't have the object in our inventory. Let's request it. - self.sendgetdata(objectHash) + try: + self.sendgetdata(Missing().pull(100)) + except Queue.full: + pass self.processData() @@ -418,10 +414,10 @@ class receiveDataThread(threading.Thread): # Send a getdata message to our peer to request the object with the given # hash - def sendgetdata(self, hash): - logger.debug('sending getdata to retrieve object with hash: ' + hexlify(hash)) - payload = '\x01' + hash - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('getdata', payload))) + def sendgetdata(self, hashes): + 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) # We have received a getdata request from our peer diff --git a/src/inventory.py b/src/inventory.py index 8a747d4b..e10c822e 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -37,7 +37,7 @@ class Inventory(collections.MutableMapping): value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) - Missing().delete(hash, True) + Missing().delete(hash) def __delitem__(self, hash): raise NotImplementedError @@ -126,10 +126,8 @@ class Missing(object): return except ValueError: pass - if len(self.hashes[objectHash]['peers']) == 0 and self.hashes[objectHash]['requested'] < time.time() - self.frequency: - self.delete(objectHash) - else: - self.hashes[objectHash]['requested'] = time.time() + if len(self.hashes[objectHash]['peers']) == 0: + del self.hashes[objectHash] def pull(self, count=1): if count < 1: @@ -139,41 +137,40 @@ class Missing(object): return objectHashes try: for objectHash in self.hashes.keys(): - if len(objectHashes) >= count: - break - if current_thread().peer not in self.pending: - self.addPending() - if (self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or \ - self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ - len(self.pending[current_thread().peer]['objects']) >= count: - break - # requested too long ago or not at all from any thread - if self.hashes[objectHash]['requested'] < time.time() - self.frequency: - # ready requested from this thread but haven't received yet - if objectHash in self.pending[current_thread().peer]['objects']: - # if still sending or receiving, request next - if self.pending[current_thread().peer]['received'] >= time.time() - self.frequency or \ - self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency: + with self.lock: + if len(objectHashes) >= count: + break + if current_thread().peer not in self.pending: + self.addPending() + if (self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or \ + self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ + len(self.pending[current_thread().peer]['objects']) >= count: + break + # requested too long ago or not at all from any thread + if self.hashes[objectHash]['requested'] < time.time() - self.frequency: + # ready requested from this thread but haven't received yet + if objectHash in self.pending[current_thread().peer]['objects']: + # if still sending or receiving, request next + if self.pending[current_thread().peer]['received'] >= time.time() - self.frequency or \ + self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency: + continue + # haven't requested or received anything recently, re-request (i.e. continue) + # the current node doesn't have the object + elif current_thread().peer not in self.hashes[objectHash]['peers']: continue - # haven't requested or received anything recently, re-request (i.e. continue) - # the current node doesn't have the object - elif current_thread().peer not in self.hashes[objectHash]['peers']: - continue - # already requested too many times, remove all signs of this object - if self.hashes[objectHash]['requestedCount'] >= self.maxRequestCount: - with self.lock: + # already requested too many times, remove all signs of this object + if self.hashes[objectHash]['requestedCount'] >= self.maxRequestCount: del self.hashes[objectHash] for thread in self.pending.keys(): if objectHash in self.pending[thread]['objects']: self.pending[thread]['objects'].remove(objectHash) - continue - # all ok, request - objectHashes.append(objectHash) - self.hashes[objectHash]['requested'] = time.time() - with self.lock: + continue + # all ok, request + objectHashes.append(objectHash) + self.hashes[objectHash]['requested'] = time.time() self.hashes[objectHash]['requestedCount'] += 1 - self.pending[current_thread().peer]['requested'] = time.time() - self.addPending(objectHash) + self.pending[current_thread().peer]['requested'] = time.time() + self.addPending(objectHash) except (RuntimeError, KeyError, ValueError): # the for cycle sometimes breaks if you remove elements pass @@ -183,10 +180,18 @@ class Missing(object): with self.lock: if objectHash in self.hashes: del self.hashes[objectHash] - if objectHash in self.pending[current_thread().peer]['objects']: - self.pending[current_thread().peer]['objects'].remove(objectHash) - if justReceived: - self.pending[current_thread().peer]['received'] = time.time() + self.pending[current_thread().peer]['received'] = time.time() + while True: + try: + for thread in self.pending.keys(): + with self.lock: + if objectHash in self.pending[thread]['objects']: + self.pending[thread]['objects'].remove(objectHash) + except (KeyError, RuntimeError): + pass + else: + break + def stop(self): with self.lock: @@ -194,10 +199,13 @@ class Missing(object): self.pending = {} def threadEnd(self): - with self.lock: - for objectHash in self.hashes: - self.removeObjectFromCurrentThread(objectHash) + while True: try: - del self.pending[current_thread().peer] - except KeyError: + for objectHash in self.hashes: + self.removeObjectFromCurrentThread(objectHash) + with self.lock: + del self.pending[current_thread().peer] + except (KeyError, RuntimeError): pass + else: + break -- 2.45.1 From 4f920fe64141d2d15ccaadd7aae70b0f752fdc41 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 23:17:56 +0100 Subject: [PATCH 0587/1102] Fix infinite loop --- src/inventory.py | 56 +++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index e10c822e..579c1159 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -118,23 +118,14 @@ class Missing(object): with self.lock: return len(self.hashes) - def removeObjectFromCurrentThread(self, objectHash): - with self.lock: - try: - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except KeyError: - return - except ValueError: - pass - if len(self.hashes[objectHash]['peers']) == 0: - del self.hashes[objectHash] - def pull(self, count=1): if count < 1: raise ValueError("Must be at least one") objectHashes = [] + unreachableObjects = [] if self.stopped: return objectHashes + start = time.time() try: for objectHash in self.hashes.keys(): with self.lock: @@ -146,6 +137,9 @@ class Missing(object): self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ len(self.pending[current_thread().peer]['objects']) >= count: break + if len(self.hashes[objectHash]['peers']) == 0: + unreachableObjects.append(objectHash) + continue # requested too long ago or not at all from any thread if self.hashes[objectHash]['requested'] < time.time() - self.frequency: # ready requested from this thread but haven't received yet @@ -174,24 +168,26 @@ class Missing(object): except (RuntimeError, KeyError, ValueError): # the for cycle sometimes breaks if you remove elements pass + for objectHash in unreachableObjects: + with self.lock: + del self.hashes[objectHash] +# logger.debug("Pull took %.3f seconds", time.time() - start) return objectHashes - def delete(self, objectHash, justReceived=False): + def delete(self, objectHash): with self.lock: if objectHash in self.hashes: del self.hashes[objectHash] self.pending[current_thread().peer]['received'] = time.time() - while True: - try: - for thread in self.pending.keys(): - with self.lock: - if objectHash in self.pending[thread]['objects']: - self.pending[thread]['objects'].remove(objectHash) - except (KeyError, RuntimeError): - pass - else: - break - + toDelete = [] + for thread in self.pending.keys(): + with self.lock: + if objectHash in self.pending[thread]['objects']: + toDelete.append(objectHash) + for thread in toDelete: + with self.lock: + if thread in self.pending: + self.pending[thread]['objects'].remove(objectHash) def stop(self): with self.lock: @@ -201,11 +197,17 @@ class Missing(object): def threadEnd(self): while True: try: - for objectHash in self.hashes: - self.removeObjectFromCurrentThread(objectHash) with self.lock: - del self.pending[current_thread().peer] - except (KeyError, RuntimeError): + if current_thread().peer in self.pending: + for objectHash in self.pending[current_thread().peer]['objects']: + if objectHash in self.hashes: + self.hashes[objectHash]['peers'].remove(current_thread().peer) + except (KeyError): pass else: break + with self.lock: + try: + del self.pending[current_thread().peer] + except KeyError: + pass -- 2.45.1 From 749bb628c021d0c0b3171283993cdce86b510137 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 23:37:03 +0100 Subject: [PATCH 0588/1102] Typo --- src/class_receiveDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 304068fb..2cdd91e6 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -220,7 +220,7 @@ class receiveDataThread(threading.Thread): if self.data == '': # if there are no more messages try: self.sendgetdata(Missing().pull(100)) - except Queue.full: + except Queue.Full: pass self.processData() -- 2.45.1 From ca8550a206d8c1eed26910573eaeb3fd10e032ae Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 23:37:25 +0100 Subject: [PATCH 0589/1102] Don't send requests for 0 objects --- src/class_receiveDataThread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 2cdd91e6..a569e2d8 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -415,6 +415,8 @@ class receiveDataThread(threading.Thread): # 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) -- 2.45.1 From 9ed59dd8250ceaf7131009b7fad5e21e7eff4385 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Jan 2017 23:38:18 +0100 Subject: [PATCH 0590/1102] Shutdown procedure cleanup --- src/bitmessageqt/__init__.py | 14 ++++++++++++++ src/class_outgoingSynSender.py | 8 ++++++-- src/class_sendDataThread.py | 3 +++ src/shared.py | 11 +++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 04562fe6..b5f036a7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -636,6 +636,9 @@ class MyForm(settingsmixin.SMainWindow): # switch back to this when replying self.replyFromTab = None + + # so that quit won't loop + self.quitAccepted = False self.init_file_menu() self.init_inbox_popup_menu() @@ -2693,6 +2696,9 @@ class MyForm(settingsmixin.SMainWindow): return ''' + if self.quitAccepted: + return + self.show() self.raise_() self.activateWindow() @@ -2734,6 +2740,8 @@ class MyForm(settingsmixin.SMainWindow): elif reply == QtGui.QMessageBox.Cancel: return + self.quitAccepted = True + self.statusBar().showMessage(_translate( "MainWindow", "Shutting down PyBitmessage... %1%").arg(str(0))) @@ -2813,6 +2821,8 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate("MainWindow", "Shutdown imminent... %1%").arg(str(100))) shared.thisapp.cleanup() logger.info("Shutdown complete") + super(MyForm, myapp).close() + #return os._exit(0) # window close event @@ -2827,6 +2837,10 @@ class MyForm(settingsmixin.SMainWindow): pass # always ignore, it shuts down by itself + if self.quitAccepted: + event.accept() + return + event.ignore() if not trayonclose: # quit the application diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index b8e3193f..11f755de 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -44,7 +44,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): peer, = random.sample(shared.knownNodes[self.streamNumber], 1) except ValueError: # no known nodes shared.knownNodesLock.release() - time.sleep(1) + self.stop.wait(1) continue priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours shared.knownNodesLock.release() @@ -61,7 +61,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): priority = 0.001 if (random.random() <= priority): break - time.sleep(0.01) # prevent CPU hogging if something is broken + self.stop.wait(0.01) # prevent CPU hogging if something is broken try: return peer except NameError: @@ -190,6 +190,10 @@ class outgoingSynSender(threading.Thread, StoppableThread): try: self.sock.connect((peer.host, peer.port)) + if self._stopped: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + return someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. sendDataThreadQueue = Queue.Queue(100) # Used to submit information to the send data thread for this connection. diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 55e674cb..2ea03e22 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -26,6 +26,7 @@ class sendDataThread(threading.Thread): state.sendDataQueues.append(self.sendDataThreadQueue) self.data = '' self.objectHashHolderInstance = objectHashHolder(self.sendDataThreadQueue) + self.objectHashHolderInstance.daemon = True self.objectHashHolderInstance.start() self.connectionIsOrWasFullyEstablished = False @@ -83,6 +84,8 @@ class sendDataThread(threading.Thread): amountSent = self.sslSock.send(self.buffer[:throttle.SendThrottle().chunkSize]) else: amountSent = self.sock.send(self.buffer[:throttle.SendThrottle().chunkSize]) + except socket.timeout: + continue except socket.error as e: if e.errno == errno.EAGAIN: continue diff --git a/src/shared.py b/src/shared.py index 022fa4b3..cd70d6c8 100644 --- a/src/shared.py +++ b/src/shared.py @@ -234,12 +234,23 @@ def doCleanShutdown(): 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 BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'): logger.info('Clean shutdown complete.') thisapp.cleanup() os._exit(0) else: logger.info('Core shutdown complete.') + for thread in threading.enumerate(): + logger.debug("Thread %s still running", thread.name) def fixPotentiallyInvalidUTF8Data(text): try: -- 2.45.1 From 9197c425d228468f13b1599508b157e4993386bd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 17 Jan 2017 00:32:05 +0100 Subject: [PATCH 0591/1102] Object requesting fix --- src/inventory.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index 579c1159..0a102d0a 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -178,15 +178,11 @@ class Missing(object): with self.lock: if objectHash in self.hashes: del self.hashes[objectHash] - self.pending[current_thread().peer]['received'] = time.time() - toDelete = [] + if current_thread().peer in self.pending: + self.pending[current_thread().peer]['received'] = time.time() for thread in self.pending.keys(): with self.lock: if objectHash in self.pending[thread]['objects']: - toDelete.append(objectHash) - for thread in toDelete: - with self.lock: - if thread in self.pending: self.pending[thread]['objects'].remove(objectHash) def stop(self): -- 2.45.1 From 5708a38be0b6c96043e39a16f2f3430aa1d4114d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 17 Jan 2017 01:07:39 +0100 Subject: [PATCH 0592/1102] Fix sending messages crashing --- src/inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inventory.py b/src/inventory.py index 0a102d0a..1036d07e 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -178,7 +178,7 @@ class Missing(object): with self.lock: if objectHash in self.hashes: del self.hashes[objectHash] - if current_thread().peer in self.pending: + if hasattr(current_thread(), 'peer') and current_thread().peer in self.pending: self.pending[current_thread().peer]['received'] = time.time() for thread in self.pending.keys(): with self.lock: -- 2.45.1 From 5ae1327edcea61b9d532f8866b2166f3c3844925 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Jan 2017 19:48:12 +0100 Subject: [PATCH 0593/1102] Download/upload shutdown fixes - Missing renamed to PendingDownload - PendingDownload now only retries 3 times rather than 6 to dowload an object - Added PendingUpload, replacing invQueueSize - PendingUpload has both the "len" method (number of objects not uploaded) as well as "progress" method, which is a float from 0 (nothing done) to 1 (all uploaded) which considers not only objects but also how many nodes they are uploaded to - PendingUpload tracks when the object is successfully uploaded to the remote node instead of just adding an arbitrary time after they have been send the corresponding "inv" - Network status tab's "Objects to be synced" shows the sum of PendingUpload and PendingDownload sizes --- src/bitmessageqt/__init__.py | 33 +++++------- src/bitmessageqt/networkstatus.py | 4 +- src/class_receiveDataThread.py | 17 +++--- src/class_sendDataThread.py | 6 +++ src/class_singleWorker.py | 8 ++- src/helper_generic.py | 10 ---- src/inventory.py | 90 +++++++++++++++++++++++++++++-- 7 files changed, 125 insertions(+), 43 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b5f036a7..adcae53c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -76,8 +76,8 @@ from account import * from dialogs import AddAddressDialog from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker -from helper_generic import powQueueSize, invQueueSize -from inventory import Missing +from helper_generic import powQueueSize +from inventory import PendingDownload, PendingUpload, PendingUploadDeadlineException import paths from proofofwork import getPowType import protocol @@ -2708,10 +2708,10 @@ class MyForm(settingsmixin.SMainWindow): waitForSync = False # C PoW currently doesn't support interrupting and OpenCL is untested - if getPowType() == "python" and (powQueueSize() > 0 or invQueueSize() > 0): + 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, invQueueSize()) + "\n\n" + + _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: @@ -2719,16 +2719,16 @@ class MyForm(settingsmixin.SMainWindow): elif reply == QtGui.QMessage.Cancel: return - if Missing().len() > 0: + if PendingDownload().len() > 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, Missing().len()), + _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, PendingDownload().len()), 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: - Missing().stop() + PendingDownload().stop() if shared.statusIconColor == 'red': reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Not connected"), @@ -2756,7 +2756,7 @@ class MyForm(settingsmixin.SMainWindow): if waitForSync: self.statusBar().showMessage(_translate( "MainWindow", "Waiting for finishing synchronisation...")) - while Missing().len() > 0: + while PendingDownload().len() > 0: time.sleep(0.5) QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) @@ -2781,22 +2781,17 @@ class MyForm(settingsmixin.SMainWindow): time.sleep(0.5) # a bit of time so that the hashHolder is populated QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) - # check if objectHashHolder empty + # check if upload (of objects created locally) pending self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(50))) - maxWaitingObjects = 0 - curWaitingObjects = invQueueSize() - while curWaitingObjects > 0: - curWaitingObjects = invQueueSize() - if curWaitingObjects > maxWaitingObjects: - maxWaitingObjects = curWaitingObjects - if curWaitingObjects > 0: - self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(50 + 20 * (maxWaitingObjects - curWaitingObjects) / maxWaitingObjects))) + try: + while PendingUpload().progress() < 1: + self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(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) - if maxWorkerQueue > 0 or maxWaitingObjects > 0: - time.sleep(10) # a bit of time so that the other nodes retrieve the objects QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) # save state and geometry self and all widgets diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 3eeae392..7506b652 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -2,7 +2,7 @@ from PyQt4 import QtCore, QtGui import time import shared from tr import _translate -from inventory import Inventory, Missing +from inventory import Inventory, PendingDownload, PendingUpload import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler @@ -45,7 +45,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): return "%4.0f kB" % num def updateNumberOfObjectsToBeSynced(self): - self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, Missing().len())) + self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, PendingDownload().len() + PendingUpload().len())) def updateNumberOfMessagesProcessed(self): self.updateNumberOfObjectsToBeSynced() diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index a569e2d8..70418f8d 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -31,7 +31,7 @@ from helper_sql import sqlQuery from debug import logger import paths import protocol -from inventory import Inventory, Missing +from inventory import Inventory, PendingDownload, PendingUpload import state import throttle import tr @@ -129,7 +129,7 @@ class receiveDataThread(threading.Thread): except Exception as err: logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) - Missing().threadEnd() + PendingDownload().threadEnd() shared.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))) @@ -219,7 +219,7 @@ class receiveDataThread(threading.Thread): if self.data == '': # if there are no more messages try: - self.sendgetdata(Missing().pull(100)) + self.sendgetdata(PendingDownload().pull(100)) except Queue.Full: pass self.processData() @@ -292,6 +292,9 @@ class receiveDataThread(threading.Thread): if self.initiatedConnection: state.networkProtocolAvailability[protocol.networkType(self.peer.host)] = True + # we need to send our own objects to this node + PendingUpload().add() + # Let all of our peers know about this new node. dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) protocol.broadcastToSendDataQueues(( @@ -409,7 +412,7 @@ class receiveDataThread(threading.Thread): objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(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: - Missing().add(item) + PendingDownload().add(item) self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[item] = 0 # helps us keep from sending inv messages to peers that already know about the objects listed therein # Send a getdata message to our peer to request the object with the given @@ -439,15 +442,15 @@ class receiveDataThread(threading.Thread): self.antiIntersectionDelay() else: if hash in Inventory(): - self.sendObject(Inventory()[hash].payload) + self.sendObject(hash, Inventory()[hash].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, payload): + def sendObject(self, hash, payload): logger.debug('sending an object.') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('object',payload))) + self.sendDataThreadQueue.put((0, 'sendRawData', (hash, protocol.CreatePacket('object',payload)))) def _checkIPAddress(self, host): if host[0:12] == '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF': diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 2ea03e22..79510f5a 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -12,6 +12,7 @@ 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 @@ -169,8 +170,12 @@ class sendDataThread(threading.Thread): logger.error('send pong failed') break elif command == 'sendRawData': + hash = None + if type(data) in [list, tuple]: + hash, data = data try: self.sendBytes(data) + PendingUpload().delete(hash) except: logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True) break @@ -188,5 +193,6 @@ class sendDataThread(threading.Thread): 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))) self.objectHashHolderInstance.close() diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index e124c7f5..ac36e0b7 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -18,7 +18,7 @@ import helper_inbox from helper_generic import addDataPadding import helper_msgcoding from helper_threading import * -from inventory import Inventory +from inventory import Inventory, PendingUpload import l10n import protocol import state @@ -176,6 +176,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -266,6 +267,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -356,6 +358,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) + PendingUpload().add(inventoryHash) logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) @@ -487,6 +490,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 3 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) + PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -813,6 +817,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 2 Inventory()[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') + PendingUpload().add(inventoryHash) if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) else: @@ -922,6 +927,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 1 Inventory()[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') + PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) diff --git a/src/helper_generic.py b/src/helper_generic.py index 9e2eb9ba..d710f429 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -19,16 +19,6 @@ def powQueueSize(): pass return curWorkerQueue -def invQueueSize(): - curInvQueue = 0 - for thread in enumerate(): - try: - if thread.name == "objectHashHolder": - curInvQueue += thread.hashCount() - except: - pass - return curInvQueue - def convertIntToString(n): a = __builtins__.hex(n) if a[-1:] == 'L': diff --git a/src/inventory.py b/src/inventory.py index 1036d07e..dfe35b8b 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,5 +1,6 @@ import collections -from threading import current_thread, RLock +import pprint +from threading import current_thread, enumerate as threadingEnumerate, RLock import time from helper_sql import * @@ -37,7 +38,7 @@ class Inventory(collections.MutableMapping): value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) - Missing().delete(hash) + PendingDownload().delete(hash) def __delitem__(self, hash): raise NotImplementedError @@ -85,7 +86,8 @@ class Inventory(collections.MutableMapping): @Singleton -class Missing(object): +class PendingDownload(object): +# keep a track of objects that have been advertised to us but we haven't downloaded them yet def __init__(self): super(self.__class__, self).__init__() self.lock = RLock() @@ -94,7 +96,7 @@ class Missing(object): # don't request the same object more frequently than this self.frequency = 60 # after requesting and not receiving an object more than this times, consider it expired - self.maxRequestCount = 6 + self.maxRequestCount = 3 self.pending = {} def add(self, objectHash): @@ -207,3 +209,83 @@ class Missing(object): del self.pending[current_thread().peer] except KeyError: pass + + +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 + + 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] = [] + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'peer') and \ + thread.peer not in self.hashes[objectHash]: + self.hashes[objectHash].append(thread.peer) + # add all objects into the current thread + else: + for hash in self.hashes: + if current_thread().peer not in self.hashes[hash]: + self.hashes[hash].append(current_thread().peer) + + + def len(self): + with self.lock: + return sum(len(self.hashes[x]) > 0 for x in self.hashes) + + def _progress(self): + with self.lock: + return float(sum(len(self.hashes[x]) for x in self.hashes)) + + def progress(self, throwDeadline=True): + if self.maxLen < self._progress(): + self.maxLen = self._progress() + if self.deadline < time.time(): + if self.deadline > 0 and throwDeadline: + raise PendingUploadDeadlineException + self.deadline = time.time() + 20 + try: + return 1.0 - self._progress() / self.maxLen + except ZeroDivisionError: + return 1.0 + + def delete(self, objectHash): + if not hasattr(current_thread(), 'peer'): + return + with self.lock: + if objectHash in self.hashes and current_thread().peer in self.hashes[objectHash]: + self.hashes[objectHash].remove(current_thread().peer) + if len(self.hashes[objectHash]) == 0: + del self.hashes[objectHash] + + def stop(self): + with self.lock: + self.hashes = {} + + def threadEnd(self): + while True: + try: + with self.lock: + for objectHash in self.hashes: + if current_thread().peer in self.hashes[objectHash]: + self.hashes[objectHash].remove(current_thread().peer) + if len(self.hashes[objectHash]) == 0: + del self.hashes[objectHash] + except (KeyError, RuntimeError): + pass + else: + break -- 2.45.1 From 582802190378dc1b2cfe9297e24b21487a02deb6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Jan 2017 19:50:40 +0100 Subject: [PATCH 0594/1102] Fix false error about wrong stream - sendinv and sendaddress are sometimes being sent to connections that haven't been established yet, resulting in complaints about stream mismatch. The error should only be displayed once the connection has been established and the remote node provides its stream number --- src/class_sendDataThread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 79510f5a..5268138d 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -182,8 +182,8 @@ class sendDataThread(threading.Thread): elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True self.services, self.sslSock = data - else: - logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) + elif self.connectionIsOrWasFullyEstablished: + logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream ' + str(deststream)) self.sendDataThreadQueue.task_done() self.sendDataThreadQueue.task_done() -- 2.45.1 From 01a9124b7dc9d0f45d65b1610dfb64e40400efd4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Jan 2017 19:52:54 +0100 Subject: [PATCH 0595/1102] Less verbose SSL handshake reporting - if SSL handshake fails, we don't need to stack trace because we know where it's happening. Only report the error string. --- src/class_receiveDataThread.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 70418f8d..250ae355 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -271,6 +271,10 @@ class receiveDataThread(threading.Thread): except ssl.SSLWantWriteError: logger.debug("Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) + except ssl.SSLError as e: + logger.error("SSL socket handhake failed: %s, shutting down connection", str(e)) + self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) + return except: logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) -- 2.45.1 From f3849eeb484bf2a43f6e262b962a88972d387919 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Jan 2017 20:04:45 +0100 Subject: [PATCH 0596/1102] Unused imports, problematic variable names --- src/inventory.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/inventory.py b/src/inventory.py index dfe35b8b..d175035d 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,5 +1,4 @@ import collections -import pprint from threading import current_thread, enumerate as threadingEnumerate, RLock import time @@ -46,7 +45,7 @@ class Inventory(collections.MutableMapping): def __iter__(self): with self.lock: hashes = self._inventory.keys()[:] - hashes += (hash for hash, in sqlQuery('SELECT hash FROM inventory')) + hashes += (x for x, in sqlQuery('SELECT hash FROM inventory')) return hashes.__iter__() def __len__(self): @@ -66,23 +65,23 @@ class Inventory(collections.MutableMapping): def unexpired_hashes_by_stream(self, stream): with self.lock: t = int(time.time()) - hashes = [hash for hash, value in self._inventory.items() if value.stream == stream and value.expires > t] + hashes = [x for x, value in self._inventory.items() if value.stream == stream and value.expires > t] hashes += (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 hash, value in self._inventory.items(): - sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value) + for objectHash, value in self._inventory.items(): + sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', objectHash, *value) self._inventory.clear() def clean(self): with self.lock: sqlExecute('DELETE FROM inventory WHERE expirestime Date: Thu, 2 Feb 2017 15:48:56 +0100 Subject: [PATCH 0597/1102] Fix curses mode --- src/bitmessagemain.py | 5 ++--- src/singleinstance.py | 3 +-- src/state.py | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index cd7205e8..ecc2c64e 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -160,9 +160,8 @@ class Main: shared.daemon = daemon # get curses flag - shared.curses = False if '-c' in sys.argv: - shared.curses = True + state.curses = True # is the application already running? If yes then exit. shared.thisapp = singleinstance("", daemon) @@ -241,7 +240,7 @@ class Main: upnpThread.start() if daemon == False and BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') == False: - if shared.curses == False: + if state.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.') diff --git a/src/singleinstance.py b/src/singleinstance.py index 1fd2ff20..a6ac4552 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -5,7 +5,6 @@ import errno from multiprocessing import Process import os import sys -import shared import state try: @@ -27,7 +26,7 @@ class singleinstance: self.lockPid = None self.lockfile = os.path.normpath(os.path.join(state.appdata, 'singleton%s.lock' % flavor_id)) - if not self.daemon and not shared.curses: + if not self.daemon and not state.curses: # Tells the already running (if any) application to get focus. import bitmessageqt bitmessageqt.init() diff --git a/src/state.py b/src/state.py index 6ae563c4..05beab24 100644 --- a/src/state.py +++ b/src/state.py @@ -17,6 +17,8 @@ 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 + # 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 -- 2.45.1 From ba130e03e5165dc0eee060b08112b0a4043bd698 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 2 Feb 2017 15:52:32 +0100 Subject: [PATCH 0598/1102] Network subsystem freezing fixes - queues were too short - some error handling was missing - remove nonblocking repeats in receive data thread - singleCleaner shouldn't wait unnecessarily --- src/class_outgoingSynSender.py | 2 +- src/class_receiveDataThread.py | 15 ++++++++------- src/class_singleCleaner.py | 3 ++- src/class_singleListener.py | 2 +- src/inventory.py | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 11f755de..f154f455 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -195,7 +195,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.sock.close() return someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. - sendDataThreadQueue = Queue.Queue(100) # Used to submit information to the send data thread for this connection. + 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, diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 250ae355..6004de5c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -82,7 +82,7 @@ class receiveDataThread(threading.Thread): def run(self): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) - while True: + while state.shutdown == 0: dataLen = len(self.data) try: ssl = False @@ -99,12 +99,13 @@ class receiveDataThread(threading.Thread): logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break except socket.error as err: - if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): - if ssl: - select.select([self.sslSock], [], []) - else: - select.select([self.sock], [], []) - continue +# if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): +# if ssl: +# select.select([self.sslSock], [], []) +# else: +# select.select([self.sock], [], []) +# logger.error('sock.recv retriable error') +# continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: shared.timeOffsetWrongCount += 1 diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index a4177986..ab16e985 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -111,7 +111,8 @@ class singleCleaner(threading.Thread, StoppableThread): os._exit(0) shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False - self.stop.wait(300) + if state.shutdown == 0: + self.stop.wait(300) def resendPubkeyRequest(address): diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 65c0a8a8..49acc71c 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -134,7 +134,7 @@ class singleListener(threading.Thread, StoppableThread): break someObjectsOfWhichThisRemoteNodeIsAlreadyAware = {} # This is not necessairly a complete list; we clear it from time to time to save memory. - sendDataThreadQueue = Queue.Queue(100) # Used to submit information to the send data thread for this connection. + sendDataThreadQueue = Queue.Queue() # Used to submit information to the send data thread for this connection. socketObject.settimeout(20) sd = sendDataThread(sendDataThreadQueue) diff --git a/src/inventory.py b/src/inventory.py index d175035d..2bdb3629 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -171,7 +171,8 @@ class PendingDownload(object): pass for objectHash in unreachableObjects: with self.lock: - del self.hashes[objectHash] + if objectHash in self.hashes: + del self.hashes[objectHash] # logger.debug("Pull took %.3f seconds", time.time() - start) return objectHashes -- 2.45.1 From c979481564d0f4580244d3eec72ebeadd7d137aa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 3 Feb 2017 09:43:47 +0100 Subject: [PATCH 0599/1102] Unhandled missing peer --- src/inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inventory.py b/src/inventory.py index 2bdb3629..99b4ca4d 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -184,7 +184,7 @@ class PendingDownload(object): self.pending[current_thread().peer]['received'] = time.time() for thread in self.pending.keys(): with self.lock: - if objectHash in self.pending[thread]['objects']: + if thread in self.pending and objectHash in self.pending[thread]['objects']: self.pending[thread]['objects'].remove(objectHash) def stop(self): -- 2.45.1 From 23fcf2cdec2c9ffbed89453952ea4c29f97ff865 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 3 Feb 2017 10:05:35 +0100 Subject: [PATCH 0600/1102] SSL handshake python version compatibility - error handling should now work with < 2.7.9 --- src/class_receiveDataThread.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 6004de5c..764ad0ba 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -266,17 +266,29 @@ class receiveDataThread(threading.Thread): self.sslSock.do_handshake() logger.debug("TLS handshake success") break - except ssl.SSLWantReadError: - logger.debug("Waiting for SSL socket handhake read") - select.select([self.sslSock], [], [], 10) - except ssl.SSLWantWriteError: - logger.debug("Waiting for SSL socket handhake write") - select.select([], [self.sslSock], [], 10) 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: %s, shutting down connection", str(e)) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) return - except: + except Exception: logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) return -- 2.45.1 From e434825bb2cdf7b2b5efbe4e9b5dfd37f4308f5a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 6 Feb 2017 11:02:03 +0100 Subject: [PATCH 0601/1102] Pending download counter fix - handles expired objects better - counts objects that failed download more accurately --- src/class_singleCleaner.py | 3 +++ src/inventory.py | 3 +-- src/shared.py | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index ab16e985..733e4607 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -111,6 +111,9 @@ class singleCleaner(threading.Thread, StoppableThread): os._exit(0) shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False + + # TODO: cleanup pending upload / download + if state.shutdown == 0: self.stop.wait(300) diff --git a/src/inventory.py b/src/inventory.py index 99b4ca4d..4424942f 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -117,7 +117,7 @@ class PendingDownload(object): def len(self): with self.lock: - return len(self.hashes) + return sum(1 for x in self.hashes.values() if len(x) > 0) def pull(self, count=1): if count < 1: @@ -242,7 +242,6 @@ class PendingUpload(object): if current_thread().peer not in self.hashes[objectHash]: self.hashes[objectHash].append(current_thread().peer) - def len(self): with self.lock: return sum(len(self.hashes[x]) > 0 for x in self.hashes) diff --git a/src/shared.py b/src/shared.py index cd70d6c8..5582a961 100644 --- a/src/shared.py +++ b/src/shared.py @@ -27,7 +27,7 @@ import highlevelcrypto #import helper_startup from helper_sql import * from helper_threading import * -from inventory import Inventory +from inventory import Inventory, PendingDownload import protocol import state @@ -435,18 +435,22 @@ def checkAndShareObjectWithPeers(data): """ if len(data) > 2 ** 18: logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data)) + PendingDownload().delete(calculateInventoryHash(data)) return 0 # Let us check to make sure that the proof of work is sufficient. if not protocol.isProofOfWorkSufficient(data): logger.info('Proof of work is insufficient.') + PendingDownload().delete(calculateInventoryHash(data)) 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) + PendingDownload().delete(calculateInventoryHash(data)) 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) + PendingDownload().delete(calculateInventoryHash(data)) return 0 intObjectType, = unpack('>I', data[16:20]) try: -- 2.45.1 From 79b566a90753bb9d019e21d966fc233516790ede Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 6 Feb 2017 17:39:42 +0100 Subject: [PATCH 0602/1102] Fix bitflags in version packet --- src/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/protocol.py b/src/protocol.py index 816b2c1d..32f3afca 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -134,7 +134,7 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = Fals payload += encodeHost(remoteHost) payload += pack('>H', remotePort) # remote IPv6 and port - payload += pack('>q', 1) # bitflags of the services I offer. + payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # 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. # we have a separate extPort and -- 2.45.1 From f6bdad18a36df91a681c5827e2e877f91bea6ce2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 6 Feb 2017 17:47:05 +0100 Subject: [PATCH 0603/1102] Improved stream handling - version command sends list of all participating streams - biginv sends lists of hosts for all streams the peer wants (plus immediate children) - objects will spread to all peers that advertise the associated stream - please note these are just network subsystem adjustments, streams aren't actually usable yet --- src/bitmessagemain.py | 2 +- src/class_receiveDataThread.py | 235 ++++++++++++++++++--------------- src/class_sendDataThread.py | 14 +- src/protocol.py | 15 ++- src/state.py | 2 +- 5 files changed, 146 insertions(+), 122 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index ecc2c64e..fd91d699 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -51,7 +51,7 @@ import helper_generic from helper_threading import * def connectToStream(streamNumber): - state.streamsInWhichIAmParticipating[streamNumber] = 'no data' + state.streamsInWhichIAmParticipating.append(streamNumber) selfInitiatedConnections[streamNumber] = {} if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 764ad0ba..e72d48dc 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -62,7 +62,8 @@ class receiveDataThread(threading.Thread): self.sock = sock self.peer = state.Peer(HOST, port) self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator - self.streamNumber = streamNumber + self.streamNumber = state.streamsInWhichIAmParticipating + self.remoteStreams = [] 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 @@ -70,7 +71,7 @@ class receiveDataThread(threading.Thread): 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.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 self.streamNumber == -1: # This was an incoming connection. Send out a version message if we accept the other node's version message. + if 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 @@ -120,7 +121,11 @@ class receiveDataThread(threading.Thread): self.processData() try: - del self.selfInitiatedConnections[self.streamNumber][self] + for stream in self.remoteStreams: + try: + del self.selfInitiatedConnections[stream][self] + except KeyError: + pass logger.debug('removed self (a receiveDataThread) from selfInitiatedConnections') except: pass @@ -137,7 +142,8 @@ class receiveDataThread(threading.Thread): def antiIntersectionDelay(self, initial = False): # estimated time for a small object to propagate across the whole network - delay = math.ceil(math.log(len(shared.knownNodes[self.streamNumber]) + 2, 20)) * (0.2 + objectHashHolder.size/2) + delay = math.ceil(math.log(max(len(shared.knownNodes[x]) for x in shared.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 @@ -182,7 +188,8 @@ class receiveDataThread(threading.Thread): # 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 shared.knownNodesLock: - shared.knownNodes[self.streamNumber][self.peer] = int(time.time()) + for stream in self.streamNumber: + shared.knownNodes[stream][self.peer] = int(time.time()) #Strip the nulls command = command.rstrip('\x00') @@ -313,9 +320,10 @@ class receiveDataThread(threading.Thread): PendingUpload().add() # Let all of our peers know about this new node. - dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) - protocol.broadcastToSendDataQueues(( - self.streamNumber, 'advertisepeer', dataToSend)) + for stream in self.remoteStreams: + dataToSend = (int(time.time()), stream, self.services, self.peer.host, self.remoteNodeIncomingPort) + protocol.broadcastToSendDataQueues(( + stream, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. if not self.initiatedConnection and len(shared.connectedHostsList) > 200: @@ -328,9 +336,10 @@ class receiveDataThread(threading.Thread): def sendBigInv(self): # Select all hashes for objects in this stream. bigInvList = {} - for hash in Inventory().unexpired_hashes_by_stream(self.streamNumber): - if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): - bigInvList[hash] = 0 + for stream in self.streamNumber: + for hash in Inventory().unexpired_hashes_by_stream(stream): + if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): + bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' # Now let us start appending all of these hashes together. They will be @@ -426,7 +435,9 @@ class receiveDataThread(threading.Thread): advertisedSet = set() for i in range(numberOfItemsInInv): advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) - objectsNewToMe = advertisedSet - Inventory().hashes_by_stream(self.streamNumber) + 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 objectsNewToMe: PendingDownload().add(item) @@ -532,7 +543,7 @@ class receiveDataThread(threading.Thread): 38 * i):12 + lengthOfNumberOfAddresses + (38 * i)]) if recaddrStream == 0: continue - 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. + 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. continue recaddrServices, = unpack('>Q', data[12 + lengthOfNumberOfAddresses + ( 38 * i):20 + lengthOfNumberOfAddresses + (38 * i)]) @@ -560,7 +571,7 @@ class receiveDataThread(threading.Thread): timeSomeoneElseReceivedMessageFromThisNode, recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) protocol.broadcastToSendDataQueues(( - self.streamNumber, 'advertisepeer', hostDetails)) + self.recaddrStream, 'advertisepeer', hostDetails)) else: timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ peerFromAddrMessage] @@ -568,7 +579,8 @@ class receiveDataThread(threading.Thread): with shared.knownNodesLock: shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode - logger.debug('knownNodes currently has ' + str(len(shared.knownNodes[self.streamNumber])) + ' nodes for this stream.') + for stream in self.streamNumber: + logger.debug('knownNodes currently has %i nodes for stream %i', len(shared.knownNodes[stream]), stream) # Send a huge addr message to our peer. This is only used @@ -576,87 +588,87 @@ class receiveDataThread(threading.Thread): # peer (with the full exchange of version and verack # messages). def sendaddr(self): - 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. + for stream in self.streamNumber: + addrsInMyStream = {} + addrsInChildStreamLeft = {} + addrsInChildStreamRight = {} - # 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: - ownPosition = random.randint(0, 499) - sentOwn = False - for i in range(500): - # if current connection is over a proxy, sent our own onion address at a random position - if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \ - hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: - peer = state.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) - else: - # still may contain own onion address, but we don't change it - peer, = random.sample(shared.knownNodes[self.streamNumber], 1) - if isHostInPrivateIPRange(peer.host): - continue - if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") : - sentOwn = True - 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 += protocol.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 += protocol.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 += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port - - payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload))) + with shared.knownNodesLock: + if len(shared.knownNodes[stream]) > 0: + ownPosition = random.randint(0, 499) + sentOwn = False + for i in range(500): + # if current connection is over a proxy, sent our own onion address at a random position + if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \ + hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: + peer = state.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) + else: + # still may contain own onion address, but we don't change it + peer, = random.sample(shared.knownNodes[stream], 1) + if isHostInPrivateIPRange(peer.host): + continue + if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") : + sentOwn = True + addrsInMyStream[peer] = shared.knownNodes[ + stream][peer] + # sent 250 only if the remote isn't interested in it + if len(shared.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber: + for i in range(250): + peer, = random.sample(shared.knownNodes[ + stream * 2], 1) + if isHostInPrivateIPRange(peer.host): + continue + addrsInChildStreamLeft[peer] = shared.knownNodes[ + stream * 2][peer] + if len(shared.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: + for i in range(250): + peer, = random.sample(shared.knownNodes[ + (stream * 2) + 1], 1) + if isHostInPrivateIPRange(peer.host): + continue + addrsInChildStreamRight[peer] = shared.knownNodes[ + (stream * 2) + 1][peer] + numberOfAddressesInAddrMessage = 0 + payload = '' + 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', stream) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.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', stream * 2) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.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', (stream * 2) + 1) + payload += pack( + '>q', 1) # service bit flags offered by this node + payload += protocol.encodeHost(HOST) + payload += pack('>H', PORT) # remote port + + payload = encodeVarint(numberOfAddressesInAddrMessage) + payload + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload))) # We have received a version message @@ -732,20 +744,24 @@ class receiveDataThread(threading.Thread): numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( data[readPosition:]) readPosition += lengthOfNumberOfStreamsInVersionMessage - self.streamNumber, lengthOfRemoteStreamNumber = decodeVarint( - data[readPosition:]) - logger.debug('Remote node useragent: ' + useragent + ' stream number:' + str(self.streamNumber) + ' time offset: ' + str(timeOffset) + ' seconds.') + 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.', useragent, ', '.join(str(x) for x in self.remoteStreams), timeOffset) - if self.streamNumber != 1: + # find shared streams + self.streamNumber = sorted(set(state.streamsInWhichIAmParticipating).intersection(self.remoteStreams)) + + if len(self.streamNumber) == 0: self.sendDataThreadQueue.put((0, 'shutdown','no data')) - logger.debug ('Closed connection to ' + str(self.peer) + ' because they are interested in stream ' + str(self.streamNumber) + '.') + logger.debug ('Closed connection to ' + str(self.peer) + ' because there is no overlapping interest in streams.') return + 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. - # 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)) + self.sendDataThreadQueue.put((0, 'setStreamNumber', self.remoteStreams)) if data[72:80] == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: self.sendDataThreadQueue.put((0, 'shutdown','no data')) logger.debug('Closing connection to myself: ' + str(self.peer)) @@ -757,10 +773,11 @@ class receiveDataThread(threading.Thread): if not isHostInPrivateIPRange(self.peer.host): with shared.knownNodesLock: - shared.knownNodes[self.streamNumber][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) - if not self.initiatedConnection: - shared.knownNodes[self.streamNumber][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours - shared.needToWriteKnownNodesToDisk = True + for stream in self.remoteStreams: + shared.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) + if not self.initiatedConnection: + shared.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours + shared.needToWriteKnownNodesToDisk = True self.sendverack() if self.initiatedConnection == False: @@ -770,7 +787,7 @@ class receiveDataThread(threading.Thread): def sendversion(self): logger.debug('Sending version message') self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage( - self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection))) + self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection))) # Sends a verack message diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 5268138d..64b29530 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -42,7 +42,7 @@ class sendDataThread(threading.Thread): self.sock = sock self.peer = state.Peer(HOST, PORT) self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator - self.streamNumber = streamNumber + self.streamNumber = [] self.services = 0 self.buffer = "" self.initiatedConnection = False @@ -51,16 +51,16 @@ class sendDataThread(threading.Thread): self.lastTimeISentData = int( time.time()) # If this value increases beyond five minutes ago, we'll send a pong message to keep the connection alive. self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware - if self.streamNumber == -1: # This was an incoming connection. + 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)) + #logger.debug('The streamNumber of this sendDataThread (ID: ' + str(id(self)) + ') at setup() is' + str(self.streamNumber)) def sendVersionMessage(self): datatosend = protocol.assembleVersionMessage( - self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. + self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. logger.debug('Sending version packet: ' + repr(datatosend)) @@ -102,7 +102,7 @@ class sendDataThread(threading.Thread): self.sendBytes() deststream, command, data = self.sendDataThreadQueue.get() - if deststream == self.streamNumber or deststream == 0: + if deststream == 0 or deststream in self.streamNumber: if command == 'shutdown': logger.debug('sendDataThread (associated with ' + str(self.peer) + ') ID: ' + str(id(self)) + ' shutting down now.') break @@ -114,7 +114,7 @@ class sendDataThread(threading.Thread): # streamNumber of this send data thread here: elif command == 'setStreamNumber': self.streamNumber = data - logger.debug('setting the stream number in the sendData thread (ID: ' + str(id(self)) + ') to ' + str(self.streamNumber)) + logger.debug('setting the stream number to %s', ', '.join(str(x) for x in 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)) @@ -183,7 +183,7 @@ class sendDataThread(threading.Thread): 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)) + 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() self.sendDataThreadQueue.task_done() diff --git a/src/protocol.py b/src/protocol.py index 32f3afca..60e270bc 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -119,7 +119,7 @@ def CreatePacket(command, payload=''): b[Header.size:] = payload return bytes(b) -def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = False): +def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server = False): payload = '' payload += pack('>L', 3) # protocol version. payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer. @@ -154,9 +154,16 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = Fals userAgent = '/PyBitmessage:' + 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) + + # 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) diff --git a/src/state.py b/src/state.py index 05beab24..3d5209c4 100644 --- a/src/state.py +++ b/src/state.py @@ -1,7 +1,7 @@ import collections neededPubkeys = {} -streamsInWhichIAmParticipating = {} +streamsInWhichIAmParticipating = [] sendDataQueues = [] #each sendData thread puts its queue in this list. # For UPnP -- 2.45.1 From 61770ba89ac604abb9967c3f5c74e073c9a5e115 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 6 Feb 2017 19:34:38 +0100 Subject: [PATCH 0604/1102] Typo --- src/class_receiveDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index e72d48dc..43a48fc7 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -571,7 +571,7 @@ class receiveDataThread(threading.Thread): timeSomeoneElseReceivedMessageFromThisNode, recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) protocol.broadcastToSendDataQueues(( - self.recaddrStream, 'advertisepeer', hostDetails)) + recaddrStream, 'advertisepeer', hostDetails)) else: timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ peerFromAddrMessage] -- 2.45.1 From ddc0ca5ede66ae8c74115e590f133e6e2027a82e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 6 Feb 2017 19:41:25 +0100 Subject: [PATCH 0605/1102] Retry for certain non-blocking operations - sometimes on read, EWOULDBLOCK is returned. It should retry. A timeout is handled separately --- src/class_receiveDataThread.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 43a48fc7..efa0092a 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -100,13 +100,13 @@ class receiveDataThread(threading.Thread): logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break except socket.error as err: -# if err.errno == 2 or (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): -# if ssl: -# select.select([self.sslSock], [], []) -# else: -# select.select([self.sock], [], []) -# logger.error('sock.recv retriable error') -# continue + if err.errno == errno.EWOULDBLOCK: + if ssl: + select.select([self.sslSock], [], [], 10) + else: + select.select([self.sock], [], [], 10) + logger.error('sock.recv retriable error') + continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: shared.timeOffsetWrongCount += 1 -- 2.45.1 From 15c620dcc21909daab35c9873a16822e6dcb3d02 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 13:00:24 +0100 Subject: [PATCH 0606/1102] SSL socket blocking error handling --- src/class_receiveDataThread.py | 24 ++++++++++++++++-------- src/class_sendDataThread.py | 20 ++++++++++++++++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index efa0092a..9ed0a311 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -86,11 +86,11 @@ class receiveDataThread(threading.Thread): while state.shutdown == 0: dataLen = len(self.data) try: - ssl = False + isSSL = False if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and self.connectionIsOrWasFullyEstablished and protocol.haveSSL(not self.initiatedConnection)): - ssl = True + isSSL = True dataRecv = self.sslSock.recv(throttle.ReceiveThrottle().chunkSize) else: dataRecv = self.sock.recv(throttle.ReceiveThrottle().chunkSize) @@ -99,13 +99,21 @@ class receiveDataThread(threading.Thread): except socket.timeout: logger.error ('Timeout occurred waiting for data from ' + str(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 + logger.error ('SSL error: %i/%s', err.errno, str(err)) + break except socket.error as err: - if err.errno == errno.EWOULDBLOCK: - if ssl: - select.select([self.sslSock], [], [], 10) - else: - select.select([self.sock], [], [], 10) - logger.error('sock.recv retriable error') + if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK): + select.select([self.sslSock if isSSL else self.sock], [], [], 10) + logger.debug('sock.recv retriable error') + continue + if sys.platform.startswith('win') and err.errno in (errno.WSAEAGAIN, 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 (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 64b29530..e403de61 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -5,8 +5,10 @@ import Queue from struct import unpack, pack import hashlib import random -import sys +import select import socket +from ssl import SSLError, SSL_ERROR_WANT_WRITE +import sys from helper_generic import addDataPadding from class_objectHashHolder import * @@ -78,17 +80,31 @@ class sendDataThread(threading.Thread): return 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 + raise except socket.error as e: - if e.errno == errno.EAGAIN: + if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK): + select.select([], [self.sslSock if isSSL else self.sock], [], 10) + logger.debug('sock.recv retriable error') + continue + if sys.platform.startswith('win') and e.errno in (errno.WSAEAGAIN, errno.WSAEWOULDBLOCK): + select.select([], [self.sslSock if isSSL else self.sock], [], 10) + logger.debug('sock.recv retriable error') continue raise throttle.SendThrottle().wait(amountSent) -- 2.45.1 From 413419c8586d2452bb2795bf7a11c27174e9398d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 16:06:24 +0100 Subject: [PATCH 0607/1102] Timeout handling and ping - timeouts after the connection is established will trigger a ping - previously they were handled as unrecoverable errors --- src/class_receiveDataThread.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 9ed0a311..b7bc50ad 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -97,14 +97,21 @@ class receiveDataThread(threading.Thread): self.data += dataRecv throttle.ReceiveThrottle().wait(len(dataRecv)) except socket.timeout: - logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') + if self.connectionIsOrWasFullyEstablished: + self.sendping("Still around!") + continue + logger.error("Timeout during protocol initialisation") 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 - logger.error ('SSL error: %i/%s', err.errno, str(err)) + 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): @@ -223,8 +230,10 @@ class receiveDataThread(threading.Thread): self.recobject(payload) elif command == 'ping': self.sendpong(payload) - #elif command == 'pong': - # pass + elif command == 'pong': + pass + else: + logger.info("Unknown command %s, ignoring", command) 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: @@ -240,11 +249,13 @@ class receiveDataThread(threading.Thread): pass 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 recverack(self): logger.debug('verack received') @@ -314,7 +325,7 @@ class receiveDataThread(threading.Thread): shared.clientHasReceivedIncomingConnections = True shared.UISignalQueue.put(('setStatusIcon', 'green')) self.sock.settimeout( - 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. + 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. shared.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" + \ -- 2.45.1 From 6b65dfeeec3eb1cd01fc74e272fb7a0dd7912f64 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 16:38:02 +0100 Subject: [PATCH 0608/1102] MarkAllUnread sqlite argument limit - shouldn't crash anymore if there are too many messages to mark read --- src/bitmessageqt/__init__.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index adcae53c..e944033f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2617,6 +2617,16 @@ class MyForm(settingsmixin.SMainWindow): # self.rerenderInboxToLabels() def on_action_MarkAllRead(self): + def partialUpdate(folder, msgids): + if len(msgids) == 0: + return 0 + if folder == 'sent': + return sqlExecute( + "UPDATE sent SET read = 1 WHERE ackdata IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) + else: + return sqlExecute( + "UPDATE inbox SET read = 1 WHERE msgid IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) + if QtGui.QMessageBox.question(self, "Marking all messages as read?", _translate("MainWindow", "Are you sure you would like to mark all messages read?"), QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: return addressAtCurrentRow = self.getCurrentAccount() @@ -2630,6 +2640,8 @@ class MyForm(settingsmixin.SMainWindow): font = QFont() font.setBold(False) + markread = 0 + for i in range(0, tableWidget.rowCount()): msgids.append(str(tableWidget.item( i, 3).data(Qt.UserRole).toPyObject())) @@ -2637,14 +2649,13 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(i, 1).setUnread(False) tableWidget.item(i, 2).setUnread(False) tableWidget.item(i, 3).setFont(font) + # sqlite default limit, unfortunately getting/setting isn't exposed to python + if i % 999 == 999: + markread += partialUpdate(self.getCurrentFolder(), msgids) + msgids = [] - markread = 0 - if self.getCurrentFolder() == 'sent': - markread = sqlExecute( - "UPDATE sent SET read = 1 WHERE ackdata IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) - else: - markread = sqlExecute( - "UPDATE inbox SET read = 1 WHERE msgid IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) + if len(msgids) > 0: + markread += partialUpdate(self.getCurrentFolder(), msgids) if markread > 0: self.propagateUnreadCount(addressAtCurrentRow, self.getCurrentFolder(), None, 0) -- 2.45.1 From 8515f9a9fc8705d0bd6f3d9beff7b9841efd6fff Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 16:42:02 +0100 Subject: [PATCH 0609/1102] Set SSL socket to blocking - otherwise the error handling gets too complicated --- src/class_receiveDataThread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index b7bc50ad..6e592304 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -318,6 +318,8 @@ class receiveDataThread(threading.Thread): logger.error("SSL socket handhake failed, shutting down connection", exc_info=True) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail')) return + # SSL in the background should be blocking, otherwise the error handling is difficult + self.sslSock.settimeout(None) # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) -- 2.45.1 From 07722fb606192b88fd76f6a0422e60cb224f100a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 19:38:52 +0100 Subject: [PATCH 0610/1102] Node negotiation error handling - complete the version and SSL handshake first, and only then feed errors into the stream and close connection - this allows more accurate error handling on both sides - also the timeOffset error trigger is now more accurate, but requires more nodes to upgrade --- src/class_receiveDataThread.py | 93 ++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 6e592304..6129aa7f 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -123,14 +123,10 @@ class receiveDataThread(threading.Thread): logger.debug('sock.recv retriable error') continue logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) - if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: - shared.timeOffsetWrongCount += 1 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. (ID: ' + str(id(self)) + ')') - if self.initiatedConnection and not self.connectionIsOrWasFullyEstablished: - shared.timeOffsetWrongCount += 1 break else: self.processData() @@ -264,13 +260,7 @@ class receiveDataThread(threading.Thread): # We have thus both sent and received a verack. self.connectionFullyEstablished() - def connectionFullyEstablished(self): - if self.connectionIsOrWasFullyEstablished: - # there is no reason to run this function a second time - return - self.connectionIsOrWasFullyEstablished = True - shared.timeOffsetWrongCount = 0 - + def sslHandshake(self): self.sslSock = self.sock if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): @@ -320,6 +310,46 @@ class receiveDataThread(threading.Thread): return # SSL in the background should be blocking, otherwise the error handling is difficult self.sslSock.settimeout(None) + + 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 + + self.sslHandshake() + 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))) @@ -349,7 +379,7 @@ class receiveDataThread(threading.Thread): self.sendaddr() # This is one large addr message to this one peer. if not self.initiatedConnection and len(shared.connectedHostsList) > 200: logger.info ('We are connected to too many people. Closing connection.') - + self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) self.sendDataThreadQueue.put((0, 'shutdown','no data')) return self.sendBigInv() @@ -706,31 +736,12 @@ 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')) - logger.debug ('Closing connection to old protocol version ' + str(self.remoteProtocolVersion) + ' node: ' + str(self.peer)) - return + timestamp, = unpack('>Q', data[12:20]) - timeOffset = timestamp - int(time.time()) - if 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, timeOffset)) - shared.timeOffsetWrongCount += 1 - time.sleep(2) - self.sendDataThreadQueue.put((0, 'shutdown','no data')) - return - elif 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, timeOffset)) - shared.timeOffsetWrongCount += 1 - time.sleep(2) - self.sendDataThreadQueue.put((0, 'shutdown','no data')) - return - else: - shared.timeOffsetWrongCount = 0 - self.checkTimeOffsetNotification() + self.timeOffset = timestamp - int(time.time()) self.myExternalIP = socket.inet_ntoa(data[40:44]) # print 'myExternalIP', self.myExternalIP @@ -739,13 +750,13 @@ class receiveDataThread(threading.Thread): useragentLength, lengthOfUseragentVarint = decodeVarint( data[80:84]) readPosition = 80 + lengthOfUseragentVarint - useragent = data[readPosition:readPosition + useragentLength] + self.userAgent = data[readPosition:readPosition + useragentLength] # version check try: - userAgentName, userAgentVersion = useragent[1:-1].split(":", 2) + userAgentName, userAgentVersion = userAgent[1:-1].split(":", 2) except: - userAgentName = useragent + userAgentName = self.userAgent userAgentVersion = "0.0.0" if userAgentName == "PyBitmessage": myVersion = [int(n) for n in softwareVersion.split(".")] @@ -770,16 +781,11 @@ class receiveDataThread(threading.Thread): newStreamNumber, lengthOfRemoteStreamNumber = decodeVarint(data[readPosition:]) readPosition += lengthOfRemoteStreamNumber self.remoteStreams.append(newStreamNumber) - logger.debug('Remote node useragent: %s, streams: (%s), time offset: %is.', useragent, ', '.join(str(x) for x in self.remoteStreams), timeOffset) + logger.debug('Remote node useragent: %s, streams: (%s), time offset: %is.', self.userAgent, ', '.join(str(x) for x in self.remoteStreams), self.timeOffset) # find shared streams self.streamNumber = sorted(set(state.streamsInWhichIAmParticipating).intersection(self.remoteStreams)) - if len(self.streamNumber) == 0: - self.sendDataThreadQueue.put((0, 'shutdown','no data')) - logger.debug ('Closed connection to ' + str(self.peer) + ' because there is no overlapping interest in streams.') - return - 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)) @@ -810,7 +816,6 @@ class receiveDataThread(threading.Thread): self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleVersionMessage( self.peer.host, self.peer.port, state.streamsInWhichIAmParticipating, not self.initiatedConnection))) - # Sends a verack message def sendverack(self): logger.debug('Sending verack') -- 2.45.1 From 2c72b337c189d56fb5034902c641b2859636830f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 20:09:11 +0100 Subject: [PATCH 0611/1102] Typos and formatting --- src/class_receiveDataThread.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 6129aa7f..2793f612 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -313,24 +313,28 @@ class receiveDataThread(threading.Thread): 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."))) + 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)) + 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)) + 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."))) + 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 @@ -754,7 +758,7 @@ class receiveDataThread(threading.Thread): # version check try: - userAgentName, userAgentVersion = userAgent[1:-1].split(":", 2) + userAgentName, userAgentVersion = self.userAgent[1:-1].split(":", 2) except: userAgentName = self.userAgent userAgentVersion = "0.0.0" @@ -781,7 +785,8 @@ class receiveDataThread(threading.Thread): 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) + logger.debug('Remote node useragent: %s, streams: (%s), time offset: %is.', + self.userAgent, ', '.join(str(x) for x in self.remoteStreams), self.timeOffset) # find shared streams self.streamNumber = sorted(set(state.streamsInWhichIAmParticipating).intersection(self.remoteStreams)) -- 2.45.1 From a381f75b4b6cdd0acd58b50353028e4b4a2836cb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 20:46:30 +0100 Subject: [PATCH 0612/1102] Git head information in version - About dialog now shows the git head - git head check has been improved to point to the head rather than the previous commit --- src/bitmessageqt/__init__.py | 3 ++- src/bitmessageqt/about.py | 7 ++++--- src/bitmessageqt/support.py | 10 +++------- src/paths.py | 37 ++++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e944033f..32f29eaf 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4004,7 +4004,8 @@ class aboutDialog(QtGui.QDialog): self.ui = Ui_aboutDialog() self.ui.setupUi(self) self.parent = parent - self.ui.labelVersion.setText('version ' + softwareVersion) + self.ui.label.setText("PyBitmessage " + softwareVersion) + self.ui.labelVersion.setText(paths.lastCommit()) class regenerateAddressesDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/about.py b/src/bitmessageqt/about.py index 3f4cc670..a3483675 100644 --- a/src/bitmessageqt/about.py +++ b/src/bitmessageqt/about.py @@ -34,16 +34,17 @@ class Ui_aboutDialog(object): 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)) + self.label.setGeometry(QtCore.QRect(10, 106, 341, 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.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignVCenter) self.label.setObjectName(_fromUtf8("label")) self.labelVersion = QtGui.QLabel(aboutDialog) - self.labelVersion.setGeometry(QtCore.QRect(190, 126, 161, 20)) + self.labelVersion.setGeometry(QtCore.QRect(10, 116, 341, 41)) self.labelVersion.setObjectName(_fromUtf8("labelVersion")) + self.labelVersion.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignVCenter) self.label_2 = QtGui.QLabel(aboutDialog) self.label_2.setGeometry(QtCore.QRect(10, 150, 341, 41)) self.label_2.setAlignment(QtCore.Qt.AlignCenter) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index fc132453..ba750423 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -87,13 +87,9 @@ def createSupportMessage(myapp): myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) version = softwareVersion - githeadfile = path.join(paths.codePath(), '..', '.git', 'ORIG_HEAD') - if (path.isfile(githeadfile)): - try: - with open(githeadfile, 'rt') as githead: - version += " GIT " + githead.readline().rstrip() - except IOError: - pass + commit = paths.lastCommit() + if commit: + version += " GIT " + commit os = sys.platform if os == "win32": diff --git a/src/paths.py b/src/paths.py index e92116c0..0f843edf 100644 --- a/src/paths.py +++ b/src/paths.py @@ -68,3 +68,40 @@ def codePath(): 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') + version = "" + if (path.isfile(githeadfile)): + try: + with open(githeadfile, 'rt') as githead: + version = tail(githead, 1).split()[1] + except IOError: + pass + return version -- 2.45.1 From 7da36eccbd92a34a1cb47b95d21c30f0969c0a82 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 7 Feb 2017 20:47:28 +0100 Subject: [PATCH 0613/1102] Signal sender threads to close on shutdown - when shutdown is running, add a shutdown command to the queues of all sender threads --- src/shared.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 5582a961..d84ec191 100644 --- a/src/shared.py +++ b/src/shared.py @@ -227,9 +227,12 @@ def doCleanShutdown(): # 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) - + from class_outgoingSynSender import outgoingSynSender + from class_sendDataThread import sendDataThread for thread in threading.enumerate(): + if isinstance(thread, sendDataThread): + thread.sendDataThreadQueue.put((0, 'shutdown','no data')) if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): logger.debug("Waiting for thread %s", thread.name) thread.join() -- 2.45.1 From 59f3a2fbe7c1278e4ee073c5122c3908a096e8ab Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 13:41:56 +0100 Subject: [PATCH 0614/1102] Reduce cyclic dependencies - rearranged code to reduce cyclic dependencies - doCleanShutdown is separated in shutdown.py - shared queues are separated in queues.py - some default values were moved to defaults.py - knownnodes partially moved to knownnodes.py --- src/api.py | 67 ++++++++++---------- src/bitmessagecurses/__init__.py | 20 +++--- src/bitmessagemain.py | 3 +- src/bitmessageqt/__init__.py | 40 ++++++------ src/bitmessageqt/account.py | 4 +- src/bitmessageqt/addressvalidator.py | 2 +- src/bitmessageqt/newchandialog.py | 2 +- src/bitmessageqt/safehtmlparser.py | 2 +- src/bitmessageqt/support.py | 4 +- src/bitmessageqt/uisignaler.py | 5 +- src/class_addressGenerator.py | 35 ++++++----- src/class_objectProcessor.py | 33 +++++----- src/class_objectProcessorQueue.py | 2 - src/class_outgoingSynSender.py | 62 +++++++++--------- src/class_receiveDataThread.py | 66 +++++++++---------- src/class_singleCleaner.py | 40 ++++++------ src/class_singleWorker.py | 59 ++++++++--------- src/class_smtpDeliver.py | 6 +- src/class_smtpServer.py | 4 +- src/class_sqlThread.py | 30 ++++----- src/defaults.py | 8 +++ src/helper_bootstrap.py | 19 +++--- src/helper_generic.py | 7 ++- src/helper_inbox.py | 8 +-- src/knownnodes.py | 5 ++ src/message_data_reader.py | 4 +- src/namecoin.py | 6 +- src/proofofwork.py | 10 +-- src/queues.py | 16 +++++ src/shared.py | 94 +--------------------------- src/shutdown.py | 87 +++++++++++++++++++++++++ src/state.py | 1 + src/upnp.py | 5 +- 33 files changed, 401 insertions(+), 355 deletions(-) create mode 100644 src/defaults.py create mode 100644 src/knownnodes.py create mode 100644 src/queues.py create mode 100644 src/shutdown.py diff --git a/src/api.py b/src/api.py index f25972aa..101241ec 100644 --- a/src/api.py +++ b/src/api.py @@ -27,6 +27,7 @@ import hashlib import protocol import state from pyelliptic.openssl import OpenSSL +import queues from struct import pack # Classes @@ -217,9 +218,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You already have this address in your address book.') sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) - shared.UISignalQueue.put(('rerenderAddressBook','')) + queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) + queues.UISignalQueue.put(('rerenderAddressBook','')) return "Added address %s to address book" % address def HandleDeleteAddressBookEntry(self, params): @@ -229,9 +230,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) self._verifyAddress(address) sqlExecute('DELETE FROM addressbook WHERE address=?', address) - shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) - shared.UISignalQueue.put(('rerenderAddressBook','')) + queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) + queues.UISignalQueue.put(('rerenderAddressBook','')) return "Deleted address book entry for %s if it existed" % address def HandleCreateRandomAddress(self, params): @@ -269,11 +270,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): unicode(label, 'utf-8') except: raise APIError(17, 'Label is not valid UTF-8 data.') - shared.apiAddressGeneratorReturnQueue.queue.clear() + queues.apiAddressGeneratorReturnQueue.queue.clear() streamNumberForAddress = 1 - shared.addressGeneratorQueue.put(( + queues.addressGeneratorQueue.put(( 'createRandomAddress', 4, streamNumberForAddress, label, 1, "", eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) - return shared.apiAddressGeneratorReturnQueue.get() + return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateDeterministicAddresses(self, params): if len(params) == 0: @@ -349,13 +350,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.') - shared.apiAddressGeneratorReturnQueue.queue.clear() + queues.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) - shared.addressGeneratorQueue.put( + queues.addressGeneratorQueue.put( ('createDeterministicAddresses', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes)) data = '{"addresses":[' - queueReturn = shared.apiAddressGeneratorReturnQueue.get() + queueReturn = queues.apiAddressGeneratorReturnQueue.get() for item in queueReturn: if len(data) > 20: data += ',' @@ -376,12 +377,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.') - shared.apiAddressGeneratorReturnQueue.queue.clear() + queues.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create %s addresses.', numberOfAddresses) - shared.addressGeneratorQueue.put( + queues.addressGeneratorQueue.put( ('getDeterministicAddress', addressVersionNumber, streamNumber, 'unused API address', numberOfAddresses, passphrase, eighteenByteRipe)) - return shared.apiAddressGeneratorReturnQueue.get() + return queues.apiAddressGeneratorReturnQueue.get() def HandleCreateChan(self, params): if len(params) == 0: @@ -401,10 +402,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): addressVersionNumber = 4 streamNumber = 1 - shared.apiAddressGeneratorReturnQueue.queue.clear() + queues.apiAddressGeneratorReturnQueue.queue.clear() logger.debug('Requesting that the addressGenerator create chan %s.', passphrase) - shared.addressGeneratorQueue.put(('createChan', addressVersionNumber, streamNumber, label, passphrase, True)) - queueReturn = shared.apiAddressGeneratorReturnQueue.get() + queues.addressGeneratorQueue.put(('createChan', addressVersionNumber, streamNumber, label, passphrase, True)) + queueReturn = queues.apiAddressGeneratorReturnQueue.get() if len(queueReturn) == 0: raise APIError(24, 'Chan address is already present.') address = queueReturn[0] @@ -428,9 +429,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): status, addressVersionNumber, streamNumber, toRipe = self._verifyAddress(suppliedAddress) suppliedAddress = addBMIfNotPresent(suppliedAddress) - shared.apiAddressGeneratorReturnQueue.queue.clear() - shared.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase, True)) - addressGeneratorReturnValue = shared.apiAddressGeneratorReturnQueue.get() + queues.apiAddressGeneratorReturnQueue.queue.clear() + queues.addressGeneratorQueue.put(('joinChan', suppliedAddress, label, passphrase, True)) + addressGeneratorReturnValue = queues.apiAddressGeneratorReturnQueue.get() if addressGeneratorReturnValue[0] == 'chan name does not match address': raise APIError(18, 'Chan name does not match address.') @@ -468,8 +469,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): BMConfigParser().remove_section(address) with open(state.appdata + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) - shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) - shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) + queues.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + queues.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.reloadMyAddressHashes() return 'success' @@ -514,7 +515,7 @@ 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) - shared.UISignalQueue.put(('changedInboxUnread', None)) + queues.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: @@ -695,10 +696,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): for row in queryreturn: toLabel, = row # apiSignalQueue.put(('displayNewSentMessage',(toAddress,toLabel,fromAddress,subject,message,ackdata))) - shared.UISignalQueue.put(('displayNewSentMessage', ( + queues.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) - shared.workerQueue.put(('sendmessage', toAddress)) + queues.workerQueue.put(('sendmessage', toAddress)) return hexlify(ackdata) @@ -753,9 +754,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): helper_sent.insert(t) toLabel = '[Broadcast subscribers]' - shared.UISignalQueue.put(('displayNewSentMessage', ( + queues.UISignalQueue.put(('displayNewSentMessage', ( toAddress, toLabel, fromAddress, subject, message, ackdata))) - shared.workerQueue.put(('sendbroadcast', '')) + queues.workerQueue.put(('sendbroadcast', '')) return hexlify(ackdata) @@ -799,8 +800,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You are already subscribed to that address.') sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',label, address, True) shared.reloadBroadcastSendersForWhichImWatching() - shared.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) - shared.UISignalQueue.put(('rerenderSubscriptions', '')) + queues.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) + queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Added subscription.' def HandleDeleteSubscription(self, params): @@ -810,8 +811,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) sqlExecute('''DELETE FROM subscriptions WHERE address=?''', address) shared.reloadBroadcastSendersForWhichImWatching() - shared.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) - shared.UISignalQueue.put(('rerenderSubscriptions', '')) + queues.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) + queues.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' def ListSubscriptions(self, params): @@ -972,7 +973,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleStatusBar(self, params): message, = params - shared.UISignalQueue.put(('updateStatusBar', message)) + queues.UISignalQueue.put(('updateStatusBar', message)) def HandleDeleteAndVacuum(self, params): sqlStoredProcedure('deleteandvacuume') diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 029f1725..61e2466a 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -21,13 +21,15 @@ import dialog from dialog import Dialog from helper_sql import * -import shared +from addresses import * import ConfigParser from configparser import BMConfigParser -from addresses import * -from pyelliptic.openssl import OpenSSL -import l10n from inventory import Inventory +import l10n +from pyelliptic.openssl import OpenSSL +import queues +import shared +import shutdown quit = False menutab = 1 @@ -446,7 +448,7 @@ def handlech(c, stdscr): choices=[("1", "Spend time shortening the address", 1 if shorten else 0)]) if r == d.DIALOG_OK and "1" in t: shorten = True - shared.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) + queues.addressGeneratorQueue.put(("createRandomAddress", 4, stream, label, 1, "", shorten)) elif t == "2": set_background_title(d, "Make deterministic addresses") r, t = d.passwordform("Enter passphrase", @@ -469,7 +471,7 @@ def handlech(c, stdscr): scrollbox(d, 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))) - shared.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) + queues.addressGeneratorQueue.put(('createDeterministicAddresses', 4, stream, "unused deterministic address", number, str(passphrase), shorten)) else: scrollbox(d, unicode("Passphrases do not match")) elif t == "2": # Send a message @@ -795,7 +797,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F "sent", 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) - shared.workerQueue.put(("sendmessage", addr)) + queues.workerQueue.put(("sendmessage", addr)) else: # Broadcast if recv == "": set_background_title(d, "Empty sender error") @@ -821,7 +823,7 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F "sent", # folder 2, # encodingType BMConfigParser().getint('bitmessagesettings', 'ttl')) - shared.workerQueue.put(('sendbroadcast', '')) + queues.workerQueue.put(('sendbroadcast', '')) def loadInbox(): sys.stdout = sys.__stdout__ @@ -1052,7 +1054,7 @@ def shutdown(): sys.stdout = sys.__stdout__ print("Shutting down...") sys.stdout = printlog - shared.doCleanShutdown() + shutdown.doCleanShutdown() sys.stdout = sys.__stdout__ sys.stderr = sys.__stderr__ diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index fd91d699..59d70cb5 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -30,6 +30,7 @@ import shared from helper_sql import sqlQuery import state import protocol +import shutdown import threading # Classes @@ -287,7 +288,7 @@ class Main: def stop(self): with shared.printLock: print('Stopping Bitmessage Deamon.') - shared.doCleanShutdown() + shutdown.doCleanShutdown() #TODO: nice function but no one is using this diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 32f29eaf..7360fc05 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -73,14 +73,18 @@ import types from utils import * from collections import OrderedDict from account import * -from dialogs import AddAddressDialog from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker +import defaults +from dialogs import AddAddressDialog from helper_generic import powQueueSize from inventory import PendingDownload, PendingUpload, PendingUploadDeadlineException +import knownnodes import paths from proofofwork import getPowType import protocol +import queues +import shutdown import state from statusbar import BMStatusBar import throttle @@ -1587,7 +1591,7 @@ class MyForm(settingsmixin.SMainWindow): QMessageBox.about(self, _translate("MainWindow", "Bad address version number"), _translate( "MainWindow", "Your address version number must be either 3 or 4.")) return - shared.addressGeneratorQueue.put(('createDeterministicAddresses', addressVersionNumber, streamNumberForAddress, "regenerated deterministic address", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value( + queues.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) @@ -2042,7 +2046,7 @@ class MyForm(settingsmixin.SMainWindow): self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) - shared.workerQueue.put(('sendmessage', toAddress)) + queues.workerQueue.put(('sendmessage', toAddress)) self.ui.comboBoxSendFrom.setCurrentIndex(0) self.ui.lineEditTo.setText('') @@ -2093,7 +2097,7 @@ class MyForm(settingsmixin.SMainWindow): self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) - shared.workerQueue.put(('sendbroadcast', '')) + queues.workerQueue.put(('sendbroadcast', '')) self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) self.ui.lineEditSubjectBroadcast.setText('') @@ -2304,7 +2308,7 @@ class MyForm(settingsmixin.SMainWindow): addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() tag = doubleHashOfAddressData[32:] for value in shared.inventory.by_type_and_tag(3, tag): - shared.objectProcessorQueue.put((value.type, value.payload)) + queues.objectProcessorQueue.put((value.type, value.payload)) def click_pushButtonStatusIcon(self): logger.debug('click_pushButtonStatusIcon') @@ -2443,7 +2447,7 @@ class MyForm(settingsmixin.SMainWindow): # 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' ''') - shared.workerQueue.put(('sendmessage', '')) + queues.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. @@ -2503,11 +2507,11 @@ class MyForm(settingsmixin.SMainWindow): with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() output = open(paths.lookupExeFolder() + 'knownnodes.dat', 'wb') - pickle.dump(shared.knownNodes, output) + pickle.dump(knownnodes.knownNodes, output) output.close() - shared.knownNodesLock.release() + knownnodes.knownNodesLock.release() os.remove(state.appdata + 'keys.dat') os.remove(state.appdata + 'knownnodes.dat') previousAppdataLocation = state.appdata @@ -2527,11 +2531,11 @@ class MyForm(settingsmixin.SMainWindow): # Write the keys.dat file to disk in the new location BMConfigParser().save() # Write the knownnodes.dat file to disk in the new location - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() output = open(state.appdata + 'knownnodes.dat', 'wb') - pickle.dump(shared.knownNodes, output) + pickle.dump(knownnodes.knownNodes, output) output.close() - shared.knownNodesLock.release() + knownnodes.knownNodesLock.release() os.remove(paths.lookupExeFolder() + 'keys.dat') os.remove(paths.lookupExeFolder() + 'knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() @@ -2681,7 +2685,7 @@ class MyForm(settingsmixin.SMainWindow): # address.' streamNumberForAddress = decodeAddress( self.dialog.ui.comboBoxExisting.currentText())[2] - shared.addressGeneratorQueue.put(('createRandomAddress', 4, streamNumberForAddress, str( + queues.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(): @@ -2692,7 +2696,7 @@ class MyForm(settingsmixin.SMainWindow): "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( + queues.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: logger.debug('new address dialog box rejected') @@ -2817,7 +2821,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate("MainWindow", "Shutting down core... %1%").arg(str(80))) QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) - shared.doCleanShutdown() + shutdown.doCleanShutdown() self.statusBar().showMessage(_translate("MainWindow", "Stopping notifications... %1%").arg(str(90))) self.tray.hide() # unregister the messaging system @@ -3217,9 +3221,9 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select ackdata FROM sent WHERE status='forcepow' ''') for row in queryreturn: ackdata, = row - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, 'Overriding maximum-difficulty setting. Work queued.'))) - shared.workerQueue.put(('sendmessage', '')) + queues.workerQueue.put(('sendmessage', '')) def on_action_SentClipboard(self): currentRow = self.ui.tableWidgetInbox.currentRow() @@ -4228,7 +4232,7 @@ class settingsDialog(QtGui.QDialog): self.ui.labelNamecoinPassword.setEnabled(isNamecoind) if isNamecoind: - self.ui.lineEditNamecoinPort.setText(shared.namecoinDefaultRpcPort) + self.ui.lineEditNamecoinPort.setText(defaults.namecoinDefaultRpcPort) else: self.ui.lineEditNamecoinPort.setText("9000") diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index bdfeaed3..897cddef 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -1,6 +1,6 @@ from PyQt4 import QtCore, QtGui -import shared +import queues import re import sys import inspect @@ -172,7 +172,7 @@ class GatewayAccount(BMAccount): min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days ) - shared.workerQueue.put(('sendmessage', self.toAddress)) + queues.workerQueue.put(('sendmessage', self.toAddress)) def parseMessage(self, toAddress, fromAddress, subject, message): super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) diff --git a/src/bitmessageqt/addressvalidator.py b/src/bitmessageqt/addressvalidator.py index c2c686f7..56352b72 100644 --- a/src/bitmessageqt/addressvalidator.py +++ b/src/bitmessageqt/addressvalidator.py @@ -3,7 +3,7 @@ from Queue import Empty from addresses import decodeAddress, addBMIfNotPresent from account import getSortedAccounts -from shared import apiAddressGeneratorReturnQueue, addressGeneratorQueue +from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue from tr import _translate from utils import str_chan diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index d9f70f87..64ed3a8c 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -2,7 +2,7 @@ from PyQt4 import QtCore, QtGui from addresses import addBMIfNotPresent from addressvalidator import AddressValidator, PassPhraseValidator -from shared import apiAddressGeneratorReturnQueue, addressGeneratorQueue, UISignalQueue +from queues import apiAddressGeneratorReturnQueue, addressGeneratorQueue, UISignalQueue from retranslateui import RetranslateMixin from tr import _translate from utils import str_chan diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 8009f02c..1692844e 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -6,7 +6,7 @@ import Queue from urllib import quote, quote_plus from urlparse import urlparse from debug import logger -from shared import parserInputQueue, parserOutputQueue, parserProcess, parserLock +from queues import parserInputQueue, parserOutputQueue, parserProcess, parserLock def regexpSubprocess(parserInputQueue, parserOutputQueue): for data in iter(parserInputQueue.get, None): diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index ba750423..041d50cc 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,6 +1,5 @@ import ctypes from PyQt4 import QtCore, QtGui -from os import path import ssl import sys import time @@ -16,6 +15,7 @@ import paths from proofofwork import bmpow import protocol from pyelliptic.openssl import OpenSSL +import queues import shared import state from version import softwareVersion @@ -67,7 +67,7 @@ def checkHasNormalAddress(): def createAddressIfNeeded(myapp): if not checkHasNormalAddress(): - shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes)) + queues.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes)) while state.shutdown == 0 and not checkHasNormalAddress(): time.sleep(.2) myapp.rerenderComboBoxSendFrom() diff --git a/src/bitmessageqt/uisignaler.py b/src/bitmessageqt/uisignaler.py index ea18f0b0..aabfaf68 100644 --- a/src/bitmessageqt/uisignaler.py +++ b/src/bitmessageqt/uisignaler.py @@ -1,8 +1,9 @@ from PyQt4.QtCore import QThread, SIGNAL -import shared import sys +import queues + class UISignaler(QThread): _instance = None @@ -18,7 +19,7 @@ class UISignaler(QThread): def run(self): while True: - command, data = shared.UISignalQueue.get() + command, data = queues.UISignalQueue.get() if command == 'writeNewAddressToTable': label, address, streamNumber = data self.emit(SIGNAL( diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c3dfac3e..a3498694 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -14,6 +14,7 @@ import protocol from pyelliptic import arithmetic import tr from binascii import hexlify +import queues import state class addressGenerator(threading.Thread, StoppableThread): @@ -25,14 +26,14 @@ class addressGenerator(threading.Thread, StoppableThread): def stopThread(self): try: - shared.addressGeneratorQueue.put(("stopThread", "data")) + queues.addressGeneratorQueue.put(("stopThread", "data")) except: pass super(addressGenerator, self).stopThread() def run(self): while state.shutdown == 0: - queueValue = shared.addressGeneratorQueue.get() + queueValue = queues.addressGeneratorQueue.get() nonceTrialsPerByte = 0 payloadLengthExtraBytes = 0 live = True @@ -87,7 +88,7 @@ class addressGenerator(threading.Thread, StoppableThread): if payloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: payloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("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, @@ -147,18 +148,18 @@ class addressGenerator(threading.Thread, StoppableThread): # The API and the join and create Chan functionality # both need information back from the address generator. - shared.apiAddressGeneratorReturnQueue.put(address) + queues.apiAddressGeneratorReturnQueue.put(address) - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Done generating address. Doing work necessary to broadcast it..."))) - shared.UISignalQueue.put(('writeNewAddressToTable', ( + queues.UISignalQueue.put(('writeNewAddressToTable', ( label, address, streamNumber))) shared.reloadMyAddressHashes() if addressVersionNumber == 3: - shared.workerQueue.put(( + queues.workerQueue.put(( 'sendOutOrStoreMyV3Pubkey', ripe.digest())) elif addressVersionNumber == 4: - shared.workerQueue.put(( + queues.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', address)) elif command == 'createDeterministicAddresses' or command == 'getDeterministicAddress' or command == 'createChan' or command == 'joinChan': @@ -166,7 +167,7 @@ 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': - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow","Generating %1 new addresses.").arg(str(numberOfAddressesToMake)))) signingKeyNonce = 0 encryptionKeyNonce = 1 @@ -243,7 +244,7 @@ class addressGenerator(threading.Thread, StoppableThread): if addressAlreadyExists: logger.info('%s already exists. Not adding it again.' % address) - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow","%1 is already in 'Your Identities'. Not adding it again.").arg(address))) else: logger.debug('label: %s' % label) @@ -262,7 +263,7 @@ class addressGenerator(threading.Thread, StoppableThread): address, 'privEncryptionKey', privEncryptionKeyWIF) BMConfigParser().save() - shared.UISignalQueue.put(('writeNewAddressToTable', ( + queues.UISignalQueue.put(('writeNewAddressToTable', ( label, address, str(streamNumber)))) listOfNewAddressesToSendOutThroughTheAPI.append( address) @@ -273,24 +274,24 @@ class addressGenerator(threading.Thread, StoppableThread): addressVersionNumber) + encodeVarint(streamNumber) + ripe.digest()).digest()).digest()[32:] shared.myAddressesByTag[tag] = address if addressVersionNumber == 3: - shared.workerQueue.put(( + queues.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: - shared.workerQueue.put(( + queues.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', address)) - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Done generating address"))) elif saveAddressToDisk and not live and not BMConfigParser().has_section(address): listOfNewAddressesToSendOutThroughTheAPI.append(address) # Done generating addresses. if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': - shared.apiAddressGeneratorReturnQueue.put( + queues.apiAddressGeneratorReturnQueue.put( listOfNewAddressesToSendOutThroughTheAPI) elif command == 'getDeterministicAddress': - shared.apiAddressGeneratorReturnQueue.put(address) + queues.apiAddressGeneratorReturnQueue.put(address) else: raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) - shared.addressGeneratorQueue.task_done() + queues.addressGeneratorQueue.task_done() diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 00e5fbd4..b9969d9e 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -22,6 +22,7 @@ import helper_msgcoding import helper_sent from helper_sql import * import protocol +import queues import state import tr from debug import logger @@ -46,14 +47,14 @@ class objectProcessor(threading.Thread): '''SELECT objecttype, data FROM objectprocessorqueue''') for row in queryreturn: objectType, data = row - shared.objectProcessorQueue.put((objectType,data)) + queues.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 = shared.objectProcessorQueue.get() + objectType, data = queues.objectProcessorQueue.get() try: if objectType == 0: # getpubkey @@ -77,8 +78,8 @@ class objectProcessor(threading.Thread): time.sleep(.5) # Wait just a moment for most of the connections to close numberOfObjectsThatWereInTheObjectProcessorQueue = 0 with SqlBulkExecute() as sql: - while shared.objectProcessorQueue.curSize > 0: - objectType, data = shared.objectProcessorQueue.get() + while queues.objectProcessorQueue.curSize > 0: + objectType, data = queues.objectProcessorQueue.get() sql.execute('''INSERT INTO objectprocessorqueue VALUES (?,?)''', objectType,data) numberOfObjectsThatWereInTheObjectProcessorQueue += 1 @@ -146,19 +147,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: - shared.workerQueue.put(( + queues.workerQueue.put(( 'doPOWForMyV2Pubkey', requestedHash)) elif requestedAddressVersionNumber == 3: - shared.workerQueue.put(( + queues.workerQueue.put(( 'sendOutOrStoreMyV3Pubkey', requestedHash)) elif requestedAddressVersionNumber == 4: - shared.workerQueue.put(( + queues.workerQueue.put(( 'sendOutOrStoreMyV4Pubkey', myAddress)) def processpubkey(self, data): pubkeyProcessingStartTime = time.time() shared.numberOfPubkeysProcessed += 1 - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateNumberOfPubkeysProcessed', 'no data')) embeddedTime, = unpack('>Q', data[8:16]) readPosition = 20 # bypass the nonce, time, and object type @@ -307,7 +308,7 @@ class objectProcessor(threading.Thread): def processmsg(self, data): messageProcessingStartTime = time.time() shared.numberOfMessagesProcessed += 1 - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateNumberOfMessagesProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9]) @@ -329,7 +330,7 @@ class objectProcessor(threading.Thread): 'ackreceived', int(time.time()), data[-32:]) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr._translate("MainWindow",'Acknowledgement of the message received %1').arg(l10n.formatTimestamp())))) + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr._translate("MainWindow",'Acknowledgement of the message received %1').arg(l10n.formatTimestamp())))) return else: logger.info('This was NOT an acknowledgement bound for me.') @@ -505,7 +506,7 @@ class objectProcessor(threading.Thread): time.time()), body, 'inbox', messageEncodingType, 0, sigHash) helper_inbox.insert(t) - shared.UISignalQueue.put(('displayNewInboxMessage', ( + queues.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toAddress, fromAddress, subject, body))) # If we are behaving as an API then we might need to run an @@ -561,9 +562,9 @@ class objectProcessor(threading.Thread): TTL) helper_sent.insert(t) - shared.UISignalQueue.put(('displayNewSentMessage', ( + queues.UISignalQueue.put(('displayNewSentMessage', ( toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdataForBroadcast))) - shared.workerQueue.put(('sendbroadcast', '')) + queues.workerQueue.put(('sendbroadcast', '')) # Don't send ACK if invalid, blacklisted senders, invisible messages, disabled or chan if self.ackDataHasAValidHeader(ackData) and \ @@ -590,7 +591,7 @@ class objectProcessor(threading.Thread): def processbroadcast(self, data): messageProcessingStartTime = time.time() shared.numberOfBroadcastsProcessed += 1 - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateNumberOfBroadcastsProcessed', 'no data')) inventoryHash = calculateInventoryHash(data) readPosition = 20 # bypass the nonce, time, and object type @@ -753,7 +754,7 @@ class objectProcessor(threading.Thread): time.time()), body, 'inbox', messageEncodingType, 0, sigHash) helper_inbox.insert(t) - shared.UISignalQueue.put(('displayNewInboxMessage', ( + queues.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toAddress, fromAddress, subject, body))) # If we are behaving as an API then we might need to run an @@ -808,7 +809,7 @@ class objectProcessor(threading.Thread): sqlExecute( '''UPDATE sent SET status='doingmsgpow', retrynumber=0 WHERE toaddress=? AND (status='awaitingpubkey' or status='doingpubkeypow') AND folder='sent' ''', address) - shared.workerQueue.put(('sendmessage', '')) + queues.workerQueue.put(('sendmessage', '')) def ackDataHasAValidHeader(self, ackData): if len(ackData) < protocol.Header.size: diff --git a/src/class_objectProcessorQueue.py b/src/class_objectProcessorQueue.py index 9bf3f82a..6309e994 100644 --- a/src/class_objectProcessorQueue.py +++ b/src/class_objectProcessorQueue.py @@ -1,5 +1,3 @@ -import shared - import Queue import threading import time diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index f154f455..85e9fa50 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -13,6 +13,8 @@ from class_sendDataThread import * from class_receiveDataThread import * from configparser import BMConfigParser from helper_threading import * +import knownnodes +import queues import state # For each stream to which we connect, several outgoingSynSender threads @@ -33,21 +35,21 @@ class outgoingSynSender(threading.Thread, StoppableThread): # ever connect to that. Otherwise we'll pick a random one from # the known nodes if state.trustedPeer: - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() peer = state.trustedPeer - shared.knownNodes[self.streamNumber][peer] = time.time() - shared.knownNodesLock.release() + knownnodes.knownNodes[self.streamNumber][peer] = time.time() + knownnodes.knownNodesLock.release() else: while not state.shutdown: - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() try: - peer, = random.sample(shared.knownNodes[self.streamNumber], 1) + peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) except ValueError: # no known nodes - shared.knownNodesLock.release() + knownnodes.knownNodesLock.release() self.stop.wait(1) continue - priority = (183600 - (time.time() - shared.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours - shared.knownNodesLock.release() + priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours + knownnodes.knownNodesLock.release() if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': if peer.host.find(".onion") == -1: priority /= 10 # hidden services have 10x priority over plain net @@ -131,13 +133,13 @@ class outgoingSynSender(threading.Thread, StoppableThread): So let us remove the offending address from our knownNodes file. """ - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() try: - del shared.knownNodes[self.streamNumber][peer] + del knownnodes.knownNodes[self.streamNumber][peer] except: pass - shared.knownNodesLock.release() - logger.debug('deleting ' + str(peer) + ' from shared.knownNodes because it caused a socks.socksocket exception. We must not be 64-bit compatible.') + knownnodes.knownNodesLock.release() + logger.debug('deleting ' + str(peer) + ' from knownnodes.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 @@ -220,7 +222,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): except socks.GeneralProxyError as err: if err[0][0] in [7, 8, 9]: logger.error('Error communicating with proxy: %s', str(err)) - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate( "MainWindow", "Problem communicating with proxy: %1. Please check your network settings.").arg(str(err[0][1])) @@ -231,25 +233,25 @@ class outgoingSynSender(threading.Thread, StoppableThread): logger.debug('Could NOT connect to ' + str(peer) + ' during outgoing attempt. ' + str(err)) deletedPeer = None - with shared.knownNodesLock: + with knownnodes.knownNodesLock: """ - It is remotely possible that peer is no longer in shared.knownNodes. + It is remotely possible that peer is no longer in knownnodes.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 shared.knownNodes. This is unlikely because of the + it from knownnodes.knownNodes. This is unlikely because of the alreadyAttemptedConnectionsList but because we clear that list once every half hour, it can happen. """ - 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] + 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] deletedPeer = peer if deletedPeer: - str ('deleting ' + str(peer) + ' from shared.knownNodes because it is more than 48 hours old and we could not connect to it.') + str ('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') except socks.Socks5AuthError as err: - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate( "MainWindow", "SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings.").arg(str(err)))) except socks.Socks5Error as err: @@ -272,22 +274,22 @@ class outgoingSynSender(threading.Thread, StoppableThread): logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) deletedPeer = None - with shared.knownNodesLock: + with knownnodes.knownNodesLock: """ - It is remotely possible that peer is no longer in shared.knownNodes. + It is remotely possible that peer is no longer in knownnodes.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 shared.knownNodes. This is unlikely because of the + it from knownnodes.knownNodes. This is unlikely because of the alreadyAttemptedConnectionsList but because we clear that list once every half hour, it can happen. """ - 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] + 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] deletedPeer = peer if deletedPeer: - logger.debug('deleting ' + str(peer) + ' from shared.knownNodes because it is more than 48 hours old and we could not connect to it.') + logger.debug('deleting ' + str(peer) + ' from knownnodes.knownNodes because it is more than 48 hours old and we could not connect to it.') except Exception as err: import traceback diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 2793f612..ef7e32e3 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -28,10 +28,12 @@ from configparser 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, PendingDownload, PendingUpload +import queues import state import throttle import tr @@ -147,13 +149,13 @@ class receiveDataThread(threading.Thread): logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) PendingDownload().threadEnd() - shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + 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))) def antiIntersectionDelay(self, initial = False): # estimated time for a small object to propagate across the whole network - delay = math.ceil(math.log(max(len(shared.knownNodes[x]) for x in shared.knownNodes) + 2, 20)) * (0.2 + objectHashHolder.size/2) + 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 @@ -168,7 +170,7 @@ class receiveDataThread(threading.Thread): def checkTimeOffsetNotification(self): if shared.timeOffsetWrongCount >= 4 and not self.connectionIsOrWasFullyEstablished: - shared.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")))) + 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. @@ -198,9 +200,9 @@ 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 shared.knownNodesLock: + with knownnodes.knownNodesLock: for stream in self.streamNumber: - shared.knownNodes[stream][self.peer] = int(time.time()) + knownnodes.knownNodes[stream][self.peer] = int(time.time()) #Strip the nulls command = command.rstrip('\x00') @@ -359,10 +361,10 @@ class receiveDataThread(threading.Thread): if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True - shared.UISignalQueue.put(('setStatusIcon', 'green')) + queues.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. - shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + 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" + \ @@ -611,14 +613,14 @@ class receiveDataThread(threading.Thread): 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 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] = {} + 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 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 + if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: + if len(knownnodes.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 knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) shared.needToWriteKnownNodesToDisk = True @@ -628,14 +630,14 @@ class receiveDataThread(threading.Thread): protocol.broadcastToSendDataQueues(( recaddrStream, 'advertisepeer', hostDetails)) else: - timeLastReceivedMessageFromThisNode = shared.knownNodes[recaddrStream][ + timeLastReceivedMessageFromThisNode = knownnodes.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 shared.knownNodesLock: - shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode for stream in self.streamNumber: - logger.debug('knownNodes currently has %i nodes for stream %i', len(shared.knownNodes[stream]), stream) + logger.debug('knownNodes currently has %i nodes for stream %i', len(knownnodes.knownNodes[stream]), stream) # Send a huge addr message to our peer. This is only used @@ -651,8 +653,8 @@ class receiveDataThread(threading.Thread): addrsInChildStreamLeft = {} addrsInChildStreamRight = {} - with shared.knownNodesLock: - if len(shared.knownNodes[stream]) > 0: + with knownnodes.knownNodesLock: + if len(knownnodes.knownNodes[stream]) > 0: ownPosition = random.randint(0, 499) sentOwn = False for i in range(500): @@ -662,29 +664,29 @@ class receiveDataThread(threading.Thread): peer = state.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) else: # still may contain own onion address, but we don't change it - peer, = random.sample(shared.knownNodes[stream], 1) + peer, = random.sample(knownnodes.knownNodes[stream], 1) if isHostInPrivateIPRange(peer.host): continue if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") : sentOwn = True - addrsInMyStream[peer] = shared.knownNodes[ + addrsInMyStream[peer] = knownnodes.knownNodes[ stream][peer] # sent 250 only if the remote isn't interested in it - if len(shared.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber: + if len(knownnodes.knownNodes[stream * 2]) > 0 and stream not in self.streamNumber: for i in range(250): - peer, = random.sample(shared.knownNodes[ + peer, = random.sample(knownnodes.knownNodes[ stream * 2], 1) if isHostInPrivateIPRange(peer.host): continue - addrsInChildStreamLeft[peer] = shared.knownNodes[ + addrsInChildStreamLeft[peer] = knownnodes.knownNodes[ stream * 2][peer] - if len(shared.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: + if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: for i in range(250): - peer, = random.sample(shared.knownNodes[ + peer, = random.sample(knownnodes.knownNodes[ (stream * 2) + 1], 1) if isHostInPrivateIPRange(peer.host): continue - addrsInChildStreamRight[peer] = shared.knownNodes[ + addrsInChildStreamRight[peer] = knownnodes.knownNodes[ (stream * 2) + 1][peer] numberOfAddressesInAddrMessage = 0 payload = '' @@ -772,7 +774,7 @@ class receiveDataThread(threading.Thread): try: if cmp(remoteVersion, myVersion) > 0 and \ (myVersion[1] % 2 == remoteVersion[1] % 2): - shared.UISignalQueue.put(('newVersionAvailable', remoteVersion)) + queues.UISignalQueue.put(('newVersionAvailable', remoteVersion)) except: pass @@ -804,11 +806,11 @@ class receiveDataThread(threading.Thread): self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion)) if not isHostInPrivateIPRange(self.peer.host): - with shared.knownNodesLock: + with knownnodes.knownNodesLock: for stream in self.remoteStreams: - shared.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) if not self.initiatedConnection: - shared.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours shared.needToWriteKnownNodesToDisk = True self.sendverack() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 733e4607..648646a7 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -11,6 +11,8 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from debug import logger +import knownnodes +import queues import protocol import state @@ -49,10 +51,10 @@ class singleCleaner(threading.Thread, StoppableThread): shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') while state.shutdown == 0: - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) Inventory().flush() - shared.UISignalQueue.put(('updateStatusBar', '')) + queues.UISignalQueue.put(('updateStatusBar', '')) protocol.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. @@ -60,7 +62,7 @@ class singleCleaner(threading.Thread, StoppableThread): # queue which will never be handled by a UI. We should clear it to # save memory. if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): - shared.UISignalQueue.queue.clear() + queues.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) Inventory().clean() @@ -88,28 +90,28 @@ class singleCleaner(threading.Thread, StoppableThread): # cleanup old nodes now = int(time.time()) toDelete = [] - shared.knownNodesLock.acquire() - for stream in shared.knownNodes: - for node in shared.knownNodes[stream].keys(): - if now - shared.knownNodes[stream][node] > 2419200: # 28 days + knownnodes.knownNodesLock.acquire() + for stream in knownnodes.knownNodes: + for node in knownnodes.knownNodes[stream].keys(): + if now - knownnodes.knownNodes[stream][node] > 2419200: # 28 days shared.needToWriteKownNodesToDisk = True - del shared.knownNodes[stream][node] - shared.knownNodesLock.release() + del knownnodes.knownNodes[stream][node] + knownnodes.knownNodesLock.release() # Let us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: - shared.knownNodesLock.acquire() + knownnodes.knownNodesLock.acquire() output = open(state.appdata + 'knownnodes.dat', 'wb') try: - pickle.dump(shared.knownNodes, output) + pickle.dump(knownnodes.knownNodes, output) output.close() except Exception as err: if "Errno 28" in str(err): - logger.fatal('(while receiveDataThread shared.needToWriteKnownNodesToDisk) Alert: Your disk or data storage volume is full. ') - shared.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))) + 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.daemon: os._exit(0) - shared.knownNodesLock.release() + knownnodes.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False # TODO: cleanup pending upload / download @@ -122,22 +124,22 @@ 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 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. + 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. except: pass - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to request a public key...')) sqlExecute( '''UPDATE sent SET status='msgqueued' WHERE toaddress=?''', address) - shared.workerQueue.put(('sendmessage', '')) + queues.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) - shared.workerQueue.put(('sendmessage', '')) - shared.UISignalQueue.put(( + queues.workerQueue.put(('sendmessage', '')) + queues.UISignalQueue.put(( 'updateStatusBar', 'Doing work necessary to again attempt to deliver a message...')) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index ac36e0b7..cd5cf283 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -21,6 +21,7 @@ from helper_threading import * from inventory import Inventory, PendingUpload import l10n import protocol +import queues import state from binascii import hexlify, unhexlify @@ -43,7 +44,7 @@ class singleWorker(threading.Thread, StoppableThread): def stopThread(self): try: - shared.workerQueue.put(("stopThread", "data")) + queues.workerQueue.put(("stopThread", "data")) except: pass super(singleWorker, self).stopThread() @@ -79,14 +80,14 @@ class singleWorker(threading.Thread, StoppableThread): if state.shutdown == 0: # just in case there are any pending tasks for msg # messages that have yet to be sent. - shared.workerQueue.put(('sendmessage', '')) + queues.workerQueue.put(('sendmessage', '')) # just in case there are any tasks for Broadcasts # that have yet to be sent. - shared.workerQueue.put(('sendbroadcast', '')) + queues.workerQueue.put(('sendbroadcast', '')) while state.shutdown == 0: self.busy = 0 - command, data = shared.workerQueue.get() + command, data = queues.workerQueue.get() self.busy = 1 if command == 'sendmessage': try: @@ -119,7 +120,7 @@ class singleWorker(threading.Thread, StoppableThread): else: logger.error('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) - shared.workerQueue.task_done() + queues.workerQueue.task_done() logger.info("Quitting...") def doPOWForMyV2Pubkey(self, hash): # This function also broadcasts out the pubkey message once it is done with the POW @@ -182,7 +183,7 @@ class singleWorker(threading.Thread, StoppableThread): protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateStatusBar', '')) + queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) @@ -273,7 +274,7 @@ class singleWorker(threading.Thread, StoppableThread): protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateStatusBar', '')) + queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) @@ -364,7 +365,7 @@ class singleWorker(threading.Thread, StoppableThread): protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateStatusBar', '')) + queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( myAddress, 'lastpubkeysendtime', str(int(time.time()))) @@ -394,7 +395,7 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue @@ -471,7 +472,7 @@ class singleWorker(threading.Thread, StoppableThread): target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For broadcast message) Doing proof of work...') - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send broadcast...")))) initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -495,7 +496,7 @@ class singleWorker(threading.Thread, StoppableThread): protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) # Update the status of the message in the 'sent' table to have # a 'broadcastsent' status @@ -563,7 +564,7 @@ class singleWorker(threading.Thread, StoppableThread): '''UPDATE sent SET status='awaitingpubkey', sleeptill=? WHERE toaddress=? AND status='msgqueued' ''', int(time.time()) + 2.5*24*60*60, toaddress) - shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( toaddress, tr._translate("MainWindow",'Encryption key was requested earlier.')))) continue #on with the next msg on which we can do some work else: @@ -600,7 +601,7 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='doingpubkeypow' WHERE toaddress=? AND status='msgqueued' ''', toaddress) - shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( toaddress, tr._translate("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 @@ -617,7 +618,7 @@ class singleWorker(threading.Thread, StoppableThread): if not BMConfigParser().has_section(toaddress): # if we aren't sending this to ourselves or a chan shared.ackdataForWhichImWatching[ackdata] = 0 - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + 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])) @@ -651,7 +652,7 @@ class singleWorker(threading.Thread, StoppableThread): 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.. 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.') - shared.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())))) + 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())))) # 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 @@ -665,7 +666,7 @@ class singleWorker(threading.Thread, StoppableThread): if toAddressVersionNumber == 2: requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + 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.")))) elif toAddressVersionNumber >= 3: requiredAverageProofOfWorkNonceTrialsPerByte, varintLength = decodeVarint( @@ -679,7 +680,7 @@ class singleWorker(threading.Thread, StoppableThread): if requiredPayloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes logger.debug('Using averageProofOfWorkNonceTrialsPerByte: %s and payloadLengthExtraBytes: %s.' % (requiredAverageProofOfWorkNonceTrialsPerByte, requiredPayloadLengthExtraBytes)) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Doing work necessary to send message.\nReceiver\'s required difficulty: %1 and %2").arg(str(float( + 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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / protocol.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): @@ -688,7 +689,7 @@ class singleWorker(threading.Thread, StoppableThread): sqlExecute( '''UPDATE sent SET status='toodifficult' WHERE ackdata=? ''', ackdata) - shared.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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( + 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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. @@ -700,7 +701,7 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58 = BMConfigParser().get( toaddress, 'privencryptionkey') except Exception as err: - shared.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())))) + 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) continue privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( @@ -709,7 +710,7 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyHex))[1:] requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) # Now we can start to assemble our message. @@ -725,7 +726,7 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58 = BMConfigParser().get( fromaddress, 'privencryptionkey') except: - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue @@ -785,7 +786,7 @@ class singleWorker(threading.Thread, StoppableThread): encrypted = highlevelcrypto.encrypt(payload,"04"+hexlify(pubEncryptionKeyBase256)) except: sqlExecute('''UPDATE sent SET status='badkey' WHERE ackdata=?''', ackdata) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata',(ackdata,tr._translate("MainWindow",'Problem: The recipient\'s encryption key is no good. Could not encrypt message. %1').arg(l10n.formatTimestamp())))) + 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())))) continue encryptedPayload = pack('>Q', embeddedTime) @@ -819,10 +820,10 @@ class singleWorker(threading.Thread, StoppableThread): objectType, toStreamNumber, encryptedPayload, embeddedTime, '') PendingUpload().add(inventoryHash) if BMConfigParser().has_section(toaddress) or not protocol.checkBitfield(behaviorBitfield, protocol.BITFIELD_DOESACK): - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) else: # not sending to a chan or one of my addresses - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) + 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)) protocol.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) @@ -852,7 +853,7 @@ class singleWorker(threading.Thread, StoppableThread): time.time()), message, 'inbox', encoding, 0, sigHash) helper_inbox.insert(t) - shared.UISignalQueue.put(('displayNewInboxMessage', ( + queues.UISignalQueue.put(('displayNewInboxMessage', ( inventoryHash, toaddress, fromaddress, subject, message))) # If we are behaving as an API then we might need to run an @@ -913,8 +914,8 @@ class singleWorker(threading.Thread, StoppableThread): # print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' - shared.UISignalQueue.put(('updateStatusBar', statusbar)) - shared.UISignalQueue.put(('updateSentItemStatusByToAddress', ( + queues.UISignalQueue.put(('updateStatusBar', statusbar)) + queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.')))) target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) @@ -943,9 +944,9 @@ class singleWorker(threading.Thread, StoppableThread): sleeptill, toAddress) - shared.UISignalQueue.put(( + queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow",'Broadcasting the public key request. This program will auto-retry if they are offline.'))) - shared.UISignalQueue.put(('updateSentItemStatusByToAddress', (toAddress, tr._translate("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) + queues.UISignalQueue.put(('updateSentItemStatusByToAddress', (toAddress, tr._translate("MainWindow",'Sending public key request. Waiting for reply. Requested at %1').arg(l10n.formatTimestamp())))) def generateFullAckMessage(self, ackdata, toStreamNumber, TTL): diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 2314238f..5c320f51 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -9,7 +9,7 @@ from configparser import BMConfigParser from debug import logger from helper_threading import * from bitmessageqt.uisignaler import UISignaler -import shared +import queues import state SMTPDOMAIN = "bmaddr.lan" @@ -23,7 +23,7 @@ class smtpDeliver(threading.Thread, StoppableThread): def stopThread(self): try: - shared.UISignallerQueue.put(("stopThread", "data")) + queues.UISignallerQueue.put(("stopThread", "data")) except: pass super(smtpDeliver, self).stopThread() @@ -36,7 +36,7 @@ class smtpDeliver(threading.Thread, StoppableThread): def run(self): while state.shutdown == 0: - command, data = shared.UISignalQueue.get() + command, data = queues.UISignalQueue.get() if command == 'writeNewAddressToTable': label, address, streamNumber = data pass diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 65a7e1fc..359c8625 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -16,7 +16,7 @@ from debug import logger from helper_sql import sqlExecute from helper_threading import StoppableThread from pyelliptic.openssl import OpenSSL -import shared +import queues from version import softwareVersion SMTPDOMAIN = "bmaddr.lan" @@ -86,7 +86,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): min(BMConfigParser().getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days ) - shared.workerQueue.put(('sendmessage', toAddress)) + queues.workerQueue.put(('sendmessage', toAddress)) def decode_header(self, hdr): ret = [] diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 9b0ba696..b438bc15 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,15 +1,17 @@ import threading from configparser 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 protocol +import queues import random import state import string @@ -334,9 +336,9 @@ class sqlThread(threading.Thread): # sanity check if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * protocol.networkDefaultPayloadLengthExtraBytes)) + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * protocol.networkDefaultPayloadLengthExtraBytes)) # 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. @@ -457,7 +459,7 @@ 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.') - shared.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))) + 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) else: logger.error(err) @@ -477,21 +479,21 @@ class sqlThread(threading.Thread): 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.') - shared.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))) + 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) item = '''update settings set value=? WHERE key='lastvacuumtime';''' parameters = (int(time.time()),) self.cur.execute(item, parameters) while True: - item = shared.sqlSubmitQueue.get() + item = helper_sql.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.') - shared.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))) + 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) elif item == 'exit': self.conn.close() @@ -506,7 +508,7 @@ 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.') - shared.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))) + 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) self.conn.close() shutil.move( @@ -522,7 +524,7 @@ 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.') - shared.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))) + 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) self.conn.close() shutil.move( @@ -539,10 +541,10 @@ 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.') - shared.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))) + 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) else: - parameters = shared.sqlSubmitQueue.get() + parameters = helper_sql.sqlSubmitQueue.get() rowcount = 0 # print 'item', item # print 'parameters', parameters @@ -552,7 +554,7 @@ class sqlThread(threading.Thread): 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.') - shared.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))) + 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) 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)) @@ -560,5 +562,5 @@ class sqlThread(threading.Thread): os._exit(0) - shared.sqlReturnQueue.put((self.cur.fetchall(), rowcount)) - # shared.sqlSubmitQueue.task_done() + helper_sql.sqlReturnQueue.put((self.cur.fetchall(), rowcount)) + # helper_sql.sqlSubmitQueue.task_done() diff --git a/src/defaults.py b/src/defaults.py new file mode 100644 index 00000000..99982acd --- /dev/null +++ b/src/defaults.py @@ -0,0 +1,8 @@ +# 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" diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 5361b9be..a3f74288 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -6,12 +6,13 @@ import time from configparser import BMConfigParser from debug import logger +import knownnodes import socks import state def knownNodes(): try: - # We shouldn't have to use the shared.knownNodesLock because this had + # We shouldn't have to use the knownnodes.knownNodesLock because this had # better be the only thread accessing knownNodes right now. pickleFile = open(state.appdata + 'knownnodes.dat', 'rb') loadedKnownNodes = pickle.load(pickleFile) @@ -20,19 +21,19 @@ def knownNodes(): # 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] = {} + knownnodes.knownNodes[stream] = {} for node_tuple in nodes.items(): try: host, (port, lastseen) = node_tuple peer = state.Peer(host, port) except: peer, lastseen = node_tuple - shared.knownNodes[stream][peer] = lastseen + knownnodes.knownNodes[stream][peer] = lastseen except: - shared.knownNodes = defaultKnownNodes.createDefaultKnownNodes(state.appdata) + 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'): - shared.knownNodes[1][state.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) + knownnodes.knownNodes[1][state.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) 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.') raise SystemExit @@ -47,17 +48,17 @@ def dns(): try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][state.Peer(item[4][0], 8080)] = int(time.time()) + knownnodes.knownNodes[1][state.Peer(item[4][0], 8080)] = int(time.time()) except: logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') try: for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][state.Peer(item[4][0], 8444)] = int(time.time()) + knownnodes.knownNodes[1][state.Peer(item[4][0], 8444)] = int(time.time()) except: logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': - shared.knownNodes[1][state.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) + knownnodes.knownNodes[1][state.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) logger.debug("Adding quzwelsuziwqgpt2.onion:8444 to knownNodes.") for port in [8080, 8444]: logger.debug("Resolving %i through SOCKS...", port) @@ -90,7 +91,7 @@ def dns(): else: if ip is not None: logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') - shared.knownNodes[1][state.Peer(ip, port)] = time.time() + knownnodes.knownNodes[1][state.Peer(ip, port)] = time.time() else: logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') diff --git a/src/helper_generic.py b/src/helper_generic.py index d710f429..1e70b3e0 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -7,10 +7,11 @@ from threading import current_thread, enumerate from configparser import BMConfigParser from debug import logger -import shared +import queues +import shutdown def powQueueSize(): - curWorkerQueue = shared.workerQueue.qsize() + curWorkerQueue = queues.workerQueue.qsize() for thread in enumerate(): try: if thread.name == "singleWorker": @@ -43,7 +44,7 @@ def signal_handler(signal, frame): return logger.error("Got signal %i", signal) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): - shared.doCleanShutdown() + shutdown.doCleanShutdown() else: print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' diff --git a/src/helper_inbox.py b/src/helper_inbox.py index a3ad9755..3506150a 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -1,16 +1,16 @@ from helper_sql import * -import shared +import queues def insert(t): sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) #shouldn't emit changedInboxUnread and displayNewInboxMessage at the same time - #shared.UISignalQueue.put(('changedInboxUnread', None)) + #queues.UISignalQueue.put(('changedInboxUnread', None)) def trash(msgid): sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) - shared.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) + queues.UISignalQueue.put(('removeInboxRowByMsgid',msgid)) def isMessageAlreadyInInbox(sigHash): queryReturn = sqlQuery( '''SELECT COUNT(*) FROM inbox WHERE sighash=?''', sigHash) - return queryReturn[0][0] != 0 \ No newline at end of file + return queryReturn[0][0] != 0 diff --git a/src/knownnodes.py b/src/knownnodes.py new file mode 100644 index 00000000..051b2593 --- /dev/null +++ b/src/knownnodes.py @@ -0,0 +1,5 @@ +import threading + +knownNodesLock = threading.Lock() +knownNodes = {} + diff --git a/src/message_data_reader.py b/src/message_data_reader.py index 79a3a607..a0659807 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -5,8 +5,8 @@ import sqlite3 from time import strftime, localtime import sys -import shared import paths +import queues import state from binascii import hexlify @@ -87,7 +87,7 @@ def markAllInboxMessagesAsUnread(): cur.execute(item, parameters) output = cur.fetchall() conn.commit() - shared.UISignalQueue.put(('changedInboxUnread', None)) + queues.UISignalQueue.put(('changedInboxUnread', None)) print 'done' def vacuum(): diff --git a/src/namecoin.py b/src/namecoin.py index 7fca0162..1834458c 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -27,7 +27,7 @@ import sys import os from configparser import BMConfigParser -import shared +import defaults import tr # translate # FIXME: from debug import logger crashes PyBitmessage due to a circular @@ -293,7 +293,7 @@ def ensureNamecoinOptions (): if key == "rpcpassword" and not hasPass: defaultPass = val if key == "rpcport": - shared.namecoinDefaultRpcPort = val + defaults.namecoinDefaultRpcPort = val nmc.close () except IOError: @@ -310,4 +310,4 @@ def ensureNamecoinOptions (): # Set default port now, possibly to found value. if (not hasPort): BMConfigParser().set (configSection, "namecoinrpcport", - shared.namecoinDefaultRpcPort) + defaults.namecoinDefaultRpcPort) diff --git a/src/proofofwork.py b/src/proofofwork.py index da9282f2..8cb6e7e8 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -9,8 +9,8 @@ import time from configparser import BMConfigParser from debug import logger import paths -import shared import openclpow +import queues import tr import os import ctypes @@ -115,7 +115,7 @@ def _doGPUPoW(target, initialHash): #print "{} - value {} < {}".format(nonce, trialValue, target) if trialValue > target: deviceNames = ", ".join(gpu.name for gpu in openclpow.enabledGpus) - shared.UISignalQueue.put(('updateStatusBar', (tr._translate("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'), 1))) + 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.") @@ -160,11 +160,11 @@ def notifyBuild(tried=False): global bmpow if bmpow: - shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1))) + queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1))) elif tried: - shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1))) + queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "Failed to build C PoW module. Please build it manually."), 1))) else: - shared.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1))) + queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1))) def buildCPoW(): global bmpow diff --git a/src/queues.py b/src/queues.py new file mode 100644 index 00000000..f50a0f1c --- /dev/null +++ b/src/queues.py @@ -0,0 +1,16 @@ +import Queue +from multiprocessing import Queue as mpQueue, Lock as mpLock +from class_objectProcessorQueue import ObjectProcessorQueue + +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() +apiAddressGeneratorReturnQueue = Queue.Queue( + ) # The address generator thread uses this queue to get information back to the API thread. + +parserProcess = None +parserLock = mpLock() +parserInputQueue = mpQueue() +parserOutputQueue = mpQueue() diff --git a/src/shared.py b/src/shared.py index d84ec191..a41271bc 100644 --- a/src/shared.py +++ b/src/shared.py @@ -21,13 +21,13 @@ from binascii import hexlify # Project imports. from addresses import * -from class_objectProcessorQueue import ObjectProcessorQueue from configparser import BMConfigParser import highlevelcrypto #import helper_startup from helper_sql import * from helper_threading import * from inventory import Inventory, PendingDownload +from queues import objectProcessorQueue import protocol import state @@ -37,15 +37,6 @@ 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() -parserInputQueue = mpQueue() -parserOutputQueue = mpQueue() -parserProcess = None -parserLock = mpLock() -addressGeneratorQueue = Queue.Queue() -knownNodesLock = threading.Lock() -knownNodes = {} printLock = threading.Lock() 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. @@ -57,8 +48,6 @@ 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. 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 @@ -67,18 +56,8 @@ numberOfPubkeysProcessed = 0 daemon = False needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 -objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. timeOffsetWrongCount = 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" - def isAddressInMyAddressBook(address): queryreturn = sqlQuery( '''select address from addressbook where address=?''', @@ -184,77 +163,6 @@ def reloadBroadcastSendersForWhichImWatching(): privEncryptionKey = doubleHashOfAddressData[:32] MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) -def doCleanShutdown(): - state.shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. - try: - parserInputQueue.put(None, False) - except Queue.Full: - pass - protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) - objectProcessorQueue.put(('checkShutdownVariable', 'no data')) - for thread in threading.enumerate(): - if thread.isAlive() and isinstance(thread, StoppableThread): - thread.stopThread() - - knownNodesLock.acquire() - UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) - output = open(state.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...')) - 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) - - from class_outgoingSynSender import outgoingSynSender - from class_sendDataThread import sendDataThread - for thread in threading.enumerate(): - if isinstance(thread, sendDataThread): - thread.sendDataThreadQueue.put((0, 'shutdown','no data')) - if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): - 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 BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'): - logger.info('Clean shutdown complete.') - thisapp.cleanup() - os._exit(0) - else: - logger.info('Core shutdown complete.') - for thread in threading.enumerate(): - logger.debug("Thread %s still running", thread.name) - def fixPotentiallyInvalidUTF8Data(text): try: unicode(text,'utf-8') diff --git a/src/shutdown.py b/src/shutdown.py new file mode 100644 index 00000000..3a6c1386 --- /dev/null +++ b/src/shutdown.py @@ -0,0 +1,87 @@ +import os +import pickle +import Queue +import threading +import time + +from class_outgoingSynSender import outgoingSynSender +from class_sendDataThread import sendDataThread +from configparser import BMConfigParser +from debug import logger +from helper_sql import sqlQuery, sqlStoredProcedure +from helper_threading import StoppableThread +from knownnodes import knownNodes, knownNodesLock +from inventory import Inventory +import protocol +from queues import addressGeneratorQueue, objectProcessorQueue, parserInputQueue, UISignalQueue, workerQueue +import shared +import state + +def doCleanShutdown(): + state.shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. + try: + parserInputQueue.put(None, False) + except Queue.Full: + pass + protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) + objectProcessorQueue.put(('checkShutdownVariable', 'no data')) + for thread in threading.enumerate(): + if thread.isAlive() and isinstance(thread, StoppableThread): + thread.stopThread() + + knownNodesLock.acquire() + UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) + output = open(state.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...')) + 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 isinstance(thread, sendDataThread): + thread.sendDataThreadQueue.put((0, 'shutdown','no data')) + if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): + 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 BMConfigParser().safeGetBoolean('bitmessagesettings','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/state.py b/src/state.py index 3d5209c4..e1a5adad 100644 --- a/src/state.py +++ b/src/state.py @@ -1,4 +1,5 @@ import collections +import threading neededPubkeys = {} streamsInWhichIAmParticipating = [] diff --git a/src/upnp.py b/src/upnp.py index b8d41f4b..fa969f36 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -8,6 +8,7 @@ import threading import time from configparser import BMConfigParser from helper_threading import * +import queues import shared import state import tr @@ -218,7 +219,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Found UPnP router at %s", ip) self.routers.append(newRouter) self.createPortMapping(newRouter) - shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort)))) + queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort)))) break except socket.timeout as e: pass @@ -242,7 +243,7 @@ class uPnPThread(threading.Thread, StoppableThread): self.deletePortMapping(router) shared.extPort = None if deleted: - shared.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping removed'))) + queues.UISignalQueue.put(('updateStatusBar', tr._translate("MainWindow",'UPnP port mapping removed'))) logger.debug("UPnP thread done") def getLocalIP(self): -- 2.45.1 From 2cc4435cfc6e139b441fc162830df9499c5b266a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 14:19:02 +0100 Subject: [PATCH 0615/1102] Imports, typos, syntax errors - remove obsolete imports - add missing imports - fix typos - fix syntax errors - thanks to landscape.io for report --- src/addresses.py | 2 +- src/api.py | 2 +- src/bitmessagecli.py | 5 ----- src/bitmessagecurses/__init__.py | 12 ++++-------- src/bitmessageqt/safehtmlparser.py | 2 +- src/configparser.py | 2 +- src/helper_bootstrap.py | 1 - src/messagetypes/message.py | 2 +- src/messagetypes/vote.py | 2 +- src/network/advanceddispatcher.py | 8 +++++--- src/openclpow.py | 2 +- src/proofofwork.py | 4 ---- src/protocol.py | 1 + src/shared.py | 4 ---- src/state.py | 1 - 15 files changed, 17 insertions(+), 33 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index fa87677a..c8caaf82 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -3,7 +3,7 @@ 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): diff --git a/src/api.py b/src/api.py index 101241ec..4de01092 100644 --- a/src/api.py +++ b/src/api.py @@ -907,7 +907,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + pubkeyStreamNumber, 'advertiseobject', inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): # Method will eventually be used by a particular Android app to diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 79272aee..74836877 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -63,8 +63,6 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe return dataFolder def configInit(): - global keysName - 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 @@ -76,7 +74,6 @@ def configInit(): print ' You will now need to configure the ' + str(keysName) + ' file.\n' def apiInit(apiEnabled): - global keysPath global usrPrompt BMConfigParser().read(keysPath) @@ -1144,8 +1141,6 @@ def delSentMsg(msgNum): #Deletes a specified message from the outbox return msgAck def getLabelForAddress(address): - global usrPrompt - if address in knownAddresses: return knownAddresses[address] else: diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 61e2466a..2cfb8c67 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -333,7 +333,6 @@ 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+"\"") @@ -572,7 +571,7 @@ def handlech(c, stdscr): subscriptions.append([label, addr, True]) subscriptions.reverse() - sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, address, True) + sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True) shared.reloadBroadcastSendersForWhichImWatching() elif t == "2": r, t = d.inpuxbox("Type in \"I want to delete this subscription\"") @@ -611,7 +610,7 @@ def handlech(c, stdscr): subscriptions.append([label, addr, True]) subscriptions.reverse() - sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, address, True) + sqlExecute("INSERT INTO subscriptions VALUES (?,?,?)", label, addr, True) shared.reloadBroadcastSendersForWhichImWatching() elif t == "3": r, t = d.inputbox("Input new address") @@ -836,7 +835,6 @@ 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)) @@ -886,7 +884,6 @@ 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)) @@ -958,7 +955,6 @@ 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) @@ -1003,7 +999,7 @@ def runwrapper(): stdscr.timeout(1000) curses.wrapper(run) - shutdown() + doShutdown() def run(stdscr): # Schedule inventory lookup data @@ -1050,7 +1046,7 @@ def run(stdscr): drawtab(stdscr) handlech(stdscr.getch(), stdscr) -def shutdown(): +def doShutdown(): sys.stdout = sys.__stdout__ print("Shutting down...") sys.stdout = printlog diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 1692844e..5fe5265c 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -110,7 +110,7 @@ class SafeHTMLParser(HTMLParser): self.sanitised += "&" + name + ";" def feed(self, data): - global parserLock, parserProcess, parserInputQueue, parserOutputQueue + global parserProcess HTMLParser.feed(self, data) tmp = SafeHTMLParser.multi_replace(data) tmp = unicode(tmp, 'utf-8', 'replace') diff --git a/src/configparser.py b/src/configparser.py index 37a35868..bc16b05a 100644 --- a/src/configparser.py +++ b/src/configparser.py @@ -56,7 +56,7 @@ class BMConfigParser(ConfigParser.SafeConfigParser): shutil.copyfile(fileName, fileNameBak) # The backup succeeded. fileNameExisted = True - except (IOError, Error): + except (IOError, Exception): # The backup failed. This can happen if the file didn't exist before. fileNameExisted = False # write the file diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index a3f74288..795b4d2a 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -1,4 +1,3 @@ -import shared import socket import defaultKnownNodes import pickle diff --git a/src/messagetypes/message.py b/src/messagetypes/message.py index 0ba97cd9..ab61e375 100644 --- a/src/messagetypes/message.py +++ b/src/messagetypes/message.py @@ -23,7 +23,7 @@ class Message(MsgBase): self.data["subject"] = data["subject"] self.data["body"] = data["body"] except KeyError as e: - logger.error("Missing key ", e.name) + logger.error("Missing key %s", e.name) return self.data def process(self): diff --git a/src/messagetypes/vote.py b/src/messagetypes/vote.py index 539aed8a..df8d267f 100644 --- a/src/messagetypes/vote.py +++ b/src/messagetypes/vote.py @@ -15,7 +15,7 @@ class Vote(MsgBase): self.data["msgid"] = data["msgid"] self.data["vote"] = data["vote"] except KeyError as e: - logger.error("Missing key ", e.name) + logger.error("Missing key %s", e.name) return self.data def process(self): diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 47eacc5a..8258412a 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,3 +1,5 @@ +import asyncore + class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 131072 @@ -7,13 +9,13 @@ class AdvancedDispatcher(asyncore.dispatcher): self.write_buf = "" self.state = "init" - def slice_read_buf(length=0): + def slice_read_buf(self, length=0): self.read_buf = self.read_buf[length:] - def slice_write_buf(length=0): + def slice_write_buf(self, length=0): self.write_buf = self.read_buf[length:] - def read_buf_sufficient(length=0): + def read_buf_sufficient(self, length=0): if len(self.read_buf) < length: return False else: diff --git a/src/openclpow.py b/src/openclpow.py index 168f963f..b8c73987 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -26,7 +26,7 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, gpus, enabledGpus, hash_dt, vendors + global ctx, queue, program, enabledGpus, hash_dt try: hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) try: diff --git a/src/proofofwork.py b/src/proofofwork.py index 8cb6e7e8..6ad790c0 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -157,8 +157,6 @@ def getPowType(): return "python" def notifyBuild(tried=False): - global bmpow - if bmpow: queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module built successfully."), 1))) elif tried: @@ -167,8 +165,6 @@ def notifyBuild(tried=False): queues.UISignalQueue.put(('updateStatusBar', (tr._translate("proofofwork", "C PoW module unavailable. Please build it."), 1))) def buildCPoW(): - global bmpow - if bmpow is not None: return if paths.frozen is not None: diff --git a/src/protocol.py b/src/protocol.py index 60e270bc..2993abdd 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -15,6 +15,7 @@ from debug import logger from helper_sql import sqlExecute import highlevelcrypto from inventory import Inventory +from queues import objectProcessorQueue import state from version import softwareVersion diff --git a/src/shared.py b/src/shared.py index a41271bc..4fefa0f8 100644 --- a/src/shared.py +++ b/src/shared.py @@ -9,9 +9,6 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. import os -import pickle -import Queue -from multiprocessing import active_children, Queue as mpQueue, Lock as mpLock import sys import stat import threading @@ -25,7 +22,6 @@ from configparser import BMConfigParser import highlevelcrypto #import helper_startup from helper_sql import * -from helper_threading import * from inventory import Inventory, PendingDownload from queues import objectProcessorQueue import protocol diff --git a/src/state.py b/src/state.py index e1a5adad..3d5209c4 100644 --- a/src/state.py +++ b/src/state.py @@ -1,5 +1,4 @@ import collections -import threading neededPubkeys = {} streamsInWhichIAmParticipating = [] -- 2.45.1 From 157881bc6369b67f559282fbdbbb9c8d7964ef0c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 20:37:42 +0100 Subject: [PATCH 0616/1102] Cyclic import fix - networkDefaultProofOfWorkNonceTrialsPerByte and networkDefaultPayloadLengthExtraBytes cyclic import fix - PyBitmessage should launch now when there's no keys.dat --- src/api.py | 19 ++++++++-------- src/bitmessagemain.py | 10 ++++----- src/bitmessageqt/__init__.py | 22 +++++++++---------- src/bitmessageqt/support.py | 4 ++-- src/class_addressGenerator.py | 10 ++++----- src/class_singleWorker.py | 41 ++++++++++++++++++----------------- src/class_sqlThread.py | 17 +++++++-------- src/defaults.py | 5 +++++ src/helper_startup.py | 6 ++--- src/protocol.py | 13 +++++------ 10 files changed, 75 insertions(+), 72 deletions(-) diff --git a/src/api.py b/src/api.py index 4de01092..27e2f7d6 100644 --- a/src/api.py +++ b/src/api.py @@ -20,6 +20,7 @@ import shared import time from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError from configparser import BMConfigParser +import defaults import helper_inbox import helper_sent import hashlib @@ -254,15 +255,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 3: label, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 4: label, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') label = self._decode(label, "base64") @@ -322,15 +323,15 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): elif len(params) == 6: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty = params nonceTrialsPerByte = int( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = BMConfigParser().get( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') elif len(params) == 7: passphrase, numberOfAddresses, addressVersionNumber, streamNumber, eighteenByteRipe, totalDifficulty, smallMessageDifficulty = params nonceTrialsPerByte = int( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty) payloadLengthExtraBytes = int( - protocol.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) + defaults.networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty) else: raise APIError(0, 'Too many parameters!') if len(passphrase) == 0: @@ -840,7 +841,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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, 'Required small message difficulty:', float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes + 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 powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -882,8 +883,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload = self._decode(payload, "hex") # Let us do the POW - target = 2 ** 64 / ((len(payload) + protocol.networkDefaultPayloadLengthExtraBytes + - 8) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte) + target = 2 ** 64 / ((len(payload) + defaults.networkDefaultPayloadLengthExtraBytes + + 8) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte) print '(For pubkey message via API) Doing proof of work...' initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 59d70cb5..49954643 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -26,10 +26,10 @@ import time from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections +import defaults import shared from helper_sql import sqlQuery import state -import protocol import shutdown import threading @@ -149,10 +149,10 @@ class singleAPI(threading.Thread, StoppableThread): selfInitiatedConnections = {} if shared.useVeryEasyProofOfWorkForTesting: - protocol.networkDefaultProofOfWorkNonceTrialsPerByte = int( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte / 100) - protocol.networkDefaultPayloadLengthExtraBytes = int( - protocol.networkDefaultPayloadLengthExtraBytes / 100) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte = int( + defaults.networkDefaultProofOfWorkNonceTrialsPerByte / 100) + defaults.networkDefaultPayloadLengthExtraBytes = int( + defaults.networkDefaultPayloadLengthExtraBytes / 100) class Main: def start(self, daemon=False): diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7360fc05..efad3391 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -31,6 +31,7 @@ from addresses import * import shared from bitmessageui import * from configparser import BMConfigParser +import defaults from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newaddresswizard import * @@ -82,7 +83,6 @@ from inventory import PendingDownload, PendingUpload, PendingUploadDeadlineExcep import knownnodes import paths from proofofwork import getPowType -import protocol import queues import shutdown import state @@ -2417,10 +2417,10 @@ class MyForm(settingsmixin.SMainWindow): # Demanded difficulty tab if float(self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.settingsDialogInstance.ui.lineEditTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) if float(self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) >= 1: BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes))) + 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())) @@ -2429,18 +2429,18 @@ class MyForm(settingsmixin.SMainWindow): 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()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)): + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)): # the user changed the max acceptable total difficulty acceptableDifficultyChanged = True BMConfigParser().set('bitmessagesettings', 'maxacceptablenoncetrialsperbyte', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) + self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) * defaults.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()) * protocol.networkDefaultPayloadLengthExtraBytes)): + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.networkDefaultPayloadLengthExtraBytes)): # the user changed the max acceptable small message difficulty acceptableDifficultyChanged = True BMConfigParser().set('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', str(int(float( - self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * protocol.networkDefaultPayloadLengthExtraBytes))) + self.settingsDialogInstance.ui.lineEditMaxAcceptableSmallMessageDifficulty.text()) * defaults.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 @@ -4112,15 +4112,15 @@ class settingsDialog(QtGui.QDialog): # Demanded difficulty tab self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'defaultnoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'defaultpayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) # Max acceptable difficulty tab self.ui.lineEditMaxAcceptableTotalDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte))) + 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte')) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte))) self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(BMConfigParser().getint( - 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / protocol.networkDefaultPayloadLengthExtraBytes))) + 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / defaults.networkDefaultPayloadLengthExtraBytes))) # OpenCL if openclpow.openclAvailable(): diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 041d50cc..60e9fa58 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -7,13 +7,13 @@ import time import account from configparser 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 from proofofwork import bmpow -import protocol from pyelliptic.openssl import OpenSSL import queues import shared @@ -67,7 +67,7 @@ def checkHasNormalAddress(): def createAddressIfNeeded(myapp): if not checkHasNormalAddress(): - queues.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, protocol.networkDefaultProofOfWorkNonceTrialsPerByte, protocol.networkDefaultPayloadLengthExtraBytes)) + 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() diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index a3498694..d938a43b 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -9,8 +9,8 @@ import highlevelcrypto from addresses import * from configparser import BMConfigParser from debug import logger +import defaults from helper_threading import * -import protocol from pyelliptic import arithmetic import tr from binascii import hexlify @@ -80,13 +80,13 @@ class addressGenerator(threading.Thread, StoppableThread): if nonceTrialsPerByte == 0: nonceTrialsPerByte = BMConfigParser().getint( 'bitmessagesettings', 'defaultnoncetrialsperbyte') - if nonceTrialsPerByte < protocol.networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte + if nonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte: + nonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte if payloadLengthExtraBytes == 0: payloadLengthExtraBytes = BMConfigParser().getint( 'bitmessagesettings', 'defaultpayloadlengthextrabytes') - if payloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes + if payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes: + payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes if command == 'createRandomAddress': queues.UISignalQueue.put(( 'updateStatusBar', tr._translate("MainWindow", "Generating one new address"))) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index cd5cf283..fc2ecebe 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -13,6 +13,7 @@ import sys import tr from configparser import BMConfigParser from debug import logger +import defaults from helper_sql import * import helper_inbox from helper_generic import addDataPadding @@ -166,7 +167,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += pubEncryptionKey[1:] # Do the POW for this pubkey message - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -257,7 +258,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += signature # Do the POW for this pubkey message - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -348,7 +349,7 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt, hexlify(pubEncryptionKey)) # Do the POW for this pubkey message - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + 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...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) @@ -470,7 +471,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += highlevelcrypto.encrypt( dataToEncrypt, hexlify(pubEncryptionKey)) - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + 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...")))) @@ -664,8 +665,8 @@ class singleWorker(threading.Thread, StoppableThread): # Let us fetch the amount of work required by the recipient. if toAddressVersionNumber == 2: - requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes + 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.")))) elif toAddressVersionNumber >= 3: @@ -675,13 +676,13 @@ class singleWorker(threading.Thread, StoppableThread): requiredPayloadLengthExtraBytes, varintLength = decodeVarint( pubkeyPayload[readPosition:readPosition + 10]) readPosition += varintLength - if requiredAverageProofOfWorkNonceTrialsPerByte < protocol.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 = protocol.networkDefaultProofOfWorkNonceTrialsPerByte - if requiredPayloadLengthExtraBytes < protocol.networkDefaultPayloadLengthExtraBytes: - requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes + 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 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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes))))) + requiredAverageProofOfWorkNonceTrialsPerByte) / defaults.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float(requiredPayloadLengthExtraBytes) / defaults.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): # The demanded difficulty is more than we are willing @@ -689,8 +690,8 @@ class singleWorker(threading.Thread, StoppableThread): 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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte)).arg(str(float( - requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) + 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())))) continue else: # if we are sending a message to ourselves or a chan.. logger.info('Sending a message.') @@ -708,8 +709,8 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKeyBase58)) pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( privEncryptionKeyHex))[1:] - requiredAverageProofOfWorkNonceTrialsPerByte = protocol.networkDefaultProofOfWorkNonceTrialsPerByte - requiredPayloadLengthExtraBytes = protocol.networkDefaultPayloadLengthExtraBytes + requiredAverageProofOfWorkNonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte + requiredPayloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes queues.UISignalQueue.put(('updateSentItemStatusByAckdata', ( ackdata, tr._translate("MainWindow", "Doing work necessary to send message.")))) @@ -751,9 +752,9 @@ class singleWorker(threading.Thread, StoppableThread): # the receiver is in any of those lists. if shared.isAddressInMyAddressBookSubscriptionsListOrWhitelist(toaddress): payload += encodeVarint( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte) payload += encodeVarint( - protocol.networkDefaultPayloadLengthExtraBytes) + defaults.networkDefaultPayloadLengthExtraBytes) else: payload += encodeVarint(BMConfigParser().getint( fromaddress, 'noncetrialsperbyte')) @@ -794,7 +795,7 @@ 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) / protocol.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / protocol.networkDefaultPayloadLengthExtraBytes) + 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) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() @@ -918,7 +919,7 @@ class singleWorker(threading.Thread, StoppableThread): queues.UISignalQueue.put(('updateSentItemStatusByToAddress', ( toAddress, tr._translate("MainWindow",'Doing work necessary to request encryption key.')))) - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + target = 2 ** 64 / (defaults.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + defaults.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+defaults.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)) @@ -972,7 +973,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint(1) # msg version payload += encodeVarint(toStreamNumber) + ackdata - target = 2 ** 64 / (protocol.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + protocol.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+protocol.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) + 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)) powStartTime = time.time() diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index b438bc15..3a8b1bed 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -10,7 +10,6 @@ import defaults import helper_sql from namecoin import ensureNamecoinOptions import paths -import protocol import queues import random import state @@ -117,9 +116,9 @@ class sqlThread(threading.Thread): if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 4: BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - protocol.networkDefaultPayloadLengthExtraBytes)) + defaults.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'settingsversion', '5') if BMConfigParser().getint('bitmessagesettings', 'settingsversion') == 5: @@ -240,8 +239,8 @@ class sqlThread(threading.Thread): # 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')) == protocol.networkDefaultProofOfWorkNonceTrialsPerByte: - shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(protocol.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) + """if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == defaults.networkDefaultProofOfWorkNonceTrialsPerByte: + shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(defaults.networkDefaultProofOfWorkNonceTrialsPerByte * 2)) """ BMConfigParser().set('bitmessagesettings', 'settingsversion', '7') @@ -307,8 +306,8 @@ class sqlThread(threading.Thread): # 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(protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) - BMConfigParser().set('bitmessagesettings','defaultpayloadlengthextrabytes', str(protocol.networkDefaultPayloadLengthExtraBytes)) + 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)) @@ -336,9 +335,9 @@ class sqlThread(threading.Thread): # sanity check if BMConfigParser().getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + BMConfigParser().set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(defaults.ridiculousDifficulty * defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) if BMConfigParser().getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: - BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * protocol.networkDefaultPayloadLengthExtraBytes)) + BMConfigParser().set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(defaults.ridiculousDifficulty * defaults.networkDefaultPayloadLengthExtraBytes)) # 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. diff --git a/src/defaults.py b/src/defaults.py index 99982acd..8401bf2e 100644 --- a/src/defaults.py +++ b/src/defaults.py @@ -6,3 +6,8 @@ ridiculousDifficulty = 20000000 # 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/helper_startup.py b/src/helper_startup.py index a0f4c913..3841e1ed 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,5 +1,6 @@ import ConfigParser from configparser import BMConfigParser +import defaults import sys import os import locale @@ -10,7 +11,6 @@ from distutils.version import StrictVersion from namecoin import ensureNamecoinOptions import paths -import protocol 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. @@ -92,9 +92,9 @@ def loadConfig(): BMConfigParser().set( 'bitmessagesettings', 'messagesencrypted', 'false') BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str( - protocol.networkDefaultProofOfWorkNonceTrialsPerByte)) + defaults.networkDefaultProofOfWorkNonceTrialsPerByte)) BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str( - protocol.networkDefaultPayloadLengthExtraBytes)) + defaults.networkDefaultPayloadLengthExtraBytes)) BMConfigParser().set('bitmessagesettings', 'minimizeonclose', 'false') BMConfigParser().set( 'bitmessagesettings', 'maxacceptablenoncetrialsperbyte', '0') diff --git a/src/protocol.py b/src/protocol.py index 2993abdd..2268ac9d 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -12,6 +12,7 @@ import traceback from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError from configparser import BMConfigParser from debug import logger +import defaults from helper_sql import sqlExecute import highlevelcrypto from inventory import Inventory @@ -29,10 +30,6 @@ BITFIELD_DOESACK = 1 eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( '>Q', random.randrange(1, 18446744073709551615)) -#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. - #Compiled struct for packing/unpacking headers #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') @@ -97,10 +94,10 @@ def checkSocksIP(host): def isProofOfWorkSufficient(data, nonceTrialsPerByte=0, payloadLengthExtraBytes=0): - if nonceTrialsPerByte < networkDefaultProofOfWorkNonceTrialsPerByte: - nonceTrialsPerByte = networkDefaultProofOfWorkNonceTrialsPerByte - if payloadLengthExtraBytes < networkDefaultPayloadLengthExtraBytes: - payloadLengthExtraBytes = networkDefaultPayloadLengthExtraBytes + 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: -- 2.45.1 From 35a712d11da1a8c9df856a3ed593c68366e46daa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 20:48:22 +0100 Subject: [PATCH 0617/1102] KnownNodes missing init - init knownnodes when connecting to a stream --- src/bitmessagemain.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 49954643..e0da839d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -29,6 +29,7 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import defaults import shared from helper_sql import sqlQuery +import knownnodes import state import shutdown import threading @@ -66,6 +67,11 @@ def connectToStream(streamNumber): maximumNumberOfHalfOpenConnections = 4 except: pass + + with knownnodes.knownNodesLock: + if streamNumber not in knownnodes.knownNodes: + knownnodes.knownNodes[streamNumber] = {} + for i in range(maximumNumberOfHalfOpenConnections): a = outgoingSynSender() a.setup(streamNumber, selfInitiatedConnections) -- 2.45.1 From b0539f5cb47b4d22478a660de986fecabe2425da Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 20:49:14 +0100 Subject: [PATCH 0618/1102] SSL handshake fewer errors - don't unnecessarily raise exceptions if SSL handshake fails --- src/class_receiveDataThread.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index ef7e32e3..987d7573 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -305,13 +305,16 @@ class receiveDataThread(threading.Thread): continue logger.error("SSL socket handhake failed: %s, shutting down connection", str(e)) self.sendDataThreadQueue.put((0, 'shutdown','tls handshake fail %s' % (str(e)))) - return + 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 + 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: @@ -346,7 +349,9 @@ class receiveDataThread(threading.Thread): # there is no reason to run this function a second time return - self.sslHandshake() + if not self.sslHandshake(): + return + if self.peerValidityChecks() == False: time.sleep(2) self.sendDataThreadQueue.put((0, 'shutdown','no data')) -- 2.45.1 From e664746f043f1e1f39c56e5c97935670cbcbffbd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 8 Feb 2017 20:52:18 +0100 Subject: [PATCH 0619/1102] More knownNodes init - also init children if they are missing --- src/bitmessagemain.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index e0da839d..3f28cd87 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -71,6 +71,10 @@ def connectToStream(streamNumber): 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] = {} for i in range(maximumNumberOfHalfOpenConnections): a = outgoingSynSender() -- 2.45.1 From c778b81427fb1f46e52df869ed80246513ee3232 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 9 Feb 2017 11:53:33 +0100 Subject: [PATCH 0620/1102] knownNodes refactoring and shutdown fixes - saveKnownNodes replaced the repeated pickle.dump - with knownNodesLock instead of acquire/release - outgoingSynSender had an unnecessary loop during shutdown causing excessive CPU usage / GUI freezing --- src/bitmessageqt/__init__.py | 13 ++--------- src/class_outgoingSynSender.py | 42 +++++++++++++++------------------- src/class_singleCleaner.py | 20 ++++++---------- src/knownnodes.py | 9 ++++++++ src/shutdown.py | 15 ++++-------- 5 files changed, 41 insertions(+), 58 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index efad3391..c9c2166f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -76,7 +76,6 @@ from collections import OrderedDict from account import * from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker -import defaults from dialogs import AddAddressDialog from helper_generic import powQueueSize from inventory import PendingDownload, PendingUpload, PendingUploadDeadlineException @@ -2507,11 +2506,7 @@ class MyForm(settingsmixin.SMainWindow): with open(paths.lookupExeFolder() + 'keys.dat', 'wb') as configfile: BMConfigParser().write(configfile) # Write the knownnodes.dat file to disk in the new location - knownnodes.knownNodesLock.acquire() - output = open(paths.lookupExeFolder() + 'knownnodes.dat', 'wb') - pickle.dump(knownnodes.knownNodes, output) - output.close() - knownnodes.knownNodesLock.release() + knownnodes.saveKnownNodes(paths.lookupExeFolder()) os.remove(state.appdata + 'keys.dat') os.remove(state.appdata + 'knownnodes.dat') previousAppdataLocation = state.appdata @@ -2531,11 +2526,7 @@ class MyForm(settingsmixin.SMainWindow): # Write the keys.dat file to disk in the new location BMConfigParser().save() # Write the knownnodes.dat file to disk in the new location - knownnodes.knownNodesLock.acquire() - output = open(state.appdata + 'knownnodes.dat', 'wb') - pickle.dump(knownnodes.knownNodes, output) - output.close() - knownnodes.knownNodesLock.release() + knownnodes.saveKnownNodes(state.appdata) os.remove(paths.lookupExeFolder() + 'keys.dat') os.remove(paths.lookupExeFolder() + 'knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 85e9fa50..5045d43b 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -35,21 +35,18 @@ class outgoingSynSender(threading.Thread, StoppableThread): # ever connect to that. Otherwise we'll pick a random one from # the known nodes if state.trustedPeer: - knownnodes.knownNodesLock.acquire() - peer = state.trustedPeer - knownnodes.knownNodes[self.streamNumber][peer] = time.time() - knownnodes.knownNodesLock.release() + with knownnodes.knownNodesLock: + peer = state.trustedPeer + knownnodes.knownNodes[self.streamNumber][peer] = time.time() else: - while not state.shutdown: - knownnodes.knownNodesLock.acquire() - try: - peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) - except ValueError: # no known nodes - knownnodes.knownNodesLock.release() - self.stop.wait(1) - continue - priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours - knownnodes.knownNodesLock.release() + while not self._stopped: + with knownnodes.knownNodesLock: + try: + peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) + except ValueError: # no known nodes + self.stop.wait(1) + continue + priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': if peer.host.find(".onion") == -1: priority /= 10 # hidden services have 10x priority over plain net @@ -82,7 +79,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" maximumConnections = 1 if state.trustedPeer else 8 # maximum number of outgoing connections = 8 - while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: + while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections and not self._stopped: self.stop.wait(10) if state.shutdown: break @@ -95,7 +92,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): random.seed() peer = self._getPeer() self.stop.wait(1) - if state.shutdown: + if self._stopped: break # Clear out the shared.alreadyAttemptedConnectionsList every half # hour so that this program will again attempt a connection @@ -110,7 +107,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.alreadyAttemptedConnectionsListLock.release() except threading.ThreadError as e: pass - if state.shutdown: + if self._stopped: break self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator address_family = socket.AF_INET @@ -133,12 +130,11 @@ class outgoingSynSender(threading.Thread, StoppableThread): So let us remove the offending address from our knownNodes file. """ - knownnodes.knownNodesLock.acquire() - try: - del knownnodes.knownNodes[self.streamNumber][peer] - except: - pass - knownnodes.knownNodesLock.release() + with knownnodes.knownNodesLock: + try: + del knownnodes.knownNodes[self.streamNumber][peer] + except: + pass logger.debug('deleting ' + str(peer) + ' from knownnodes.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 diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 648646a7..3be3ef21 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -3,7 +3,6 @@ import shared import time import sys import os -import pickle import tr#anslate from configparser import BMConfigParser @@ -90,28 +89,23 @@ class singleCleaner(threading.Thread, StoppableThread): # cleanup old nodes now = int(time.time()) toDelete = [] - knownnodes.knownNodesLock.acquire() - for stream in knownnodes.knownNodes: - for node in knownnodes.knownNodes[stream].keys(): - if now - knownnodes.knownNodes[stream][node] > 2419200: # 28 days - shared.needToWriteKownNodesToDisk = True - del knownnodes.knownNodes[stream][node] - knownnodes.knownNodesLock.release() + with knownnodes.knownNodesLock: + for stream in knownnodes.knownNodes: + for node in knownnodes.knownNodes[stream].keys(): + if now - knownnodes.knownNodes[stream][node] > 2419200: # 28 days + shared.needToWriteKownNodesToDisk = True + del knownnodes.knownNodes[stream][node] # Let us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: - knownnodes.knownNodesLock.acquire() - output = open(state.appdata + 'knownnodes.dat', 'wb') try: - pickle.dump(knownnodes.knownNodes, output) - output.close() + knownnodes.saveKnownNodes() 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.daemon: os._exit(0) - knownnodes.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False # TODO: cleanup pending upload / download diff --git a/src/knownnodes.py b/src/knownnodes.py index 051b2593..b68f135f 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -1,5 +1,14 @@ +import pickle import threading +import state + knownNodesLock = threading.Lock() knownNodes = {} +def saveKnownNodes(dirName = None): + if dirName is None: + dirName = state.appdata + with knownNodesLock: + with open(dirName + 'knownnodes.dat', 'wb') as output: + pickle.dump(knownNodes, output) diff --git a/src/shutdown.py b/src/shutdown.py index 3a6c1386..8a219237 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -1,5 +1,4 @@ import os -import pickle import Queue import threading import time @@ -10,7 +9,7 @@ from configparser import BMConfigParser from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure from helper_threading import StoppableThread -from knownnodes import knownNodes, knownNodesLock +from knownnodes import saveKnownNodes from inventory import Inventory import protocol from queues import addressGeneratorQueue, objectProcessorQueue, parserInputQueue, UISignalQueue, workerQueue @@ -29,17 +28,11 @@ def doCleanShutdown(): if thread.isAlive() and isinstance(thread, StoppableThread): thread.stopThread() - knownNodesLock.acquire() UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) - output = open(state.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.') + 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', -- 2.45.1 From d8ae44f9eeb33402e2599b9d4b6e994faa2f0273 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 9 Feb 2017 21:04:07 +0100 Subject: [PATCH 0621/1102] Obsolete imports, missing exception type --- src/bitmessageqt/__init__.py | 1 - src/class_outgoingSynSender.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c9c2166f..c44339f8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -58,7 +58,6 @@ import time import os import hashlib from pyelliptic.openssl import OpenSSL -import pickle import platform import textwrap import debug diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 5045d43b..91cd660a 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -133,7 +133,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): with knownnodes.knownNodesLock: try: del knownnodes.knownNodes[self.streamNumber][peer] - except: + 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.') continue -- 2.45.1 From 965f3548ac75620889068d785161f562fc183814 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Feb 2017 01:33:16 +0100 Subject: [PATCH 0622/1102] Depends checking updates - checks for msgpack - can distinguish OS and make a recommendation with respect to the relevant package manager --- src/depends.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/src/depends.py b/src/depends.py index 3e207f61..49c5c7a8 100755 --- a/src/depends.py +++ b/src/depends.py @@ -1,6 +1,7 @@ #! python import sys +import os import pyelliptic.openssl #Only really old versions of Python don't have sys.hexversion. We don't support @@ -41,6 +42,8 @@ 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 @@ -167,6 +170,24 @@ 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) @@ -179,6 +200,33 @@ def check_pyqt(): passed = False return passed +def check_msgpack(): + try: + import msgpack + except ImportError: + logger.error('The msgpack package is not available. PyBitmessage requires msgpack.') + 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 False + return True + def check_dependencies(verbose = False, optional = False): if verbose: logger.setLevel(logging.INFO) @@ -195,7 +243,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_functions = [check_hashlib, check_sqlite, check_openssl, check_msgpack] if optional: check_functions.extend([check_pyqt, check_curses]) -- 2.45.1 From a4b1a781ce00f2c8608449eaf043b8be17040a30 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Feb 2017 01:35:32 +0100 Subject: [PATCH 0623/1102] Minor UI fixes - "new" folder consistently appears in chans and "All accounts" - "Sent" message list sorting fix - When editing a label, keys.dat is saved and the lineEdit completer is updated - addressbook is updated when adding/deleting a new chan --- src/bitmessageqt/__init__.py | 13 +++++++++++-- src/bitmessageqt/foldertree.py | 1 + src/bitmessageqt/newchandialog.py | 1 - 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c44339f8..3917f7d7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -571,6 +571,8 @@ class MyForm(settingsmixin.SMainWindow): 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 @@ -585,7 +587,7 @@ class MyForm(settingsmixin.SMainWindow): j = 0 unread = 0 for folder in folders: - if toAddress is not None and folder == "new": + 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"]: @@ -1115,8 +1117,8 @@ class MyForm(settingsmixin.SMainWindow): toAddress, fromAddress, subject, status, ackdata, lastactiontime = row self.addMessageListItemSent(tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime) - tableWidget.setSortingEnabled(False) tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) + tableWidget.setSortingEnabled(True) tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Sent", None)) tableWidget.setUpdatesEnabled(True) @@ -3558,6 +3560,7 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().save() shared.reloadMyAddressHashes() self.rerenderAddressBook() + self.rerenderComboBoxSendFrom() if account.type == AccountMixin.NORMAL: self.rerenderTabTreeMessages() elif account.type == AccountMixin.CHAN: @@ -3937,6 +3940,11 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderMessagelistFromLabels() self.rerenderMessagelistToLabels() + completerList = self.ui.lineEditTo.completer().model().stringList() + for i in range(len(completerList)): + if str(completerList[i]).endswith(" <" + item.address + ">"): + completerList[i] = item.label + " <" + item.address + ">" + stringList = self.ui.lineEditTo.completer().model().setStringList(completerList) def writeNewAddressToTable(self, label, address, streamNumber): self.rerenderTabTreeMessages() @@ -3944,6 +3952,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderTabTreeChans() self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() + self.rerenderAddressBook() def updateStatusBar(self, data): if type(data) is tuple or type(data) is list: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 821efdb4..4392495d 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -442,6 +442,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): 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: diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index 64ed3a8c..a7784206 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -39,7 +39,6 @@ class NewChanDialog(QtGui.QDialog, RetranslateMixin): if len(addressGeneratorReturnValue) > 0 and addressGeneratorReturnValue[0] != 'chan name does not match address': UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Successfully created / joined chan %1").arg(str(self.chanPassPhrase.text().toUtf8())))) self.parent.ui.tabWidget.setCurrentIndex(3) - self.parent.rerenderAddressBook() self.done(QtGui.QDialog.Accepted) else: UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Chan creation / joining failed"))) -- 2.45.1 From f94b2d2d4b61fd7a74882d4cb70740dafdf142b1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Feb 2017 01:38:58 +0100 Subject: [PATCH 0624/1102] Windows compatibility fixes - there is no errno.WSAEAGAIN, only errno.WSAEWOULDBLOCK --- src/class_receiveDataThread.py | 8 +++----- src/class_sendDataThread.py | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 987d7573..c3b37865 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -116,11 +116,9 @@ class receiveDataThread(threading.Thread): 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): - select.select([self.sslSock if isSSL else self.sock], [], [], 10) - logger.debug('sock.recv retriable error') - continue - if sys.platform.startswith('win') and err.errno in (errno.WSAEAGAIN, errno.WSAEWOULDBLOCK): + if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + err.errno in (errno.WSAEWOULDBLOCK)): select.select([self.sslSock if isSSL else self.sock], [], [], 10) logger.debug('sock.recv retriable error') continue diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index e403de61..667850cd 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -98,11 +98,9 @@ class sendDataThread(threading.Thread): continue raise except socket.error as e: - if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK): - select.select([], [self.sslSock if isSSL else self.sock], [], 10) - logger.debug('sock.recv retriable error') - continue - if sys.platform.startswith('win') and e.errno in (errno.WSAEAGAIN, errno.WSAEWOULDBLOCK): + if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + e.errno in (errno.WSAEWOULDBLOCK)): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue -- 2.45.1 From f499a3b1d852893ca1d7314a5f5a91ccbebcf4f7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Feb 2017 13:57:20 +0100 Subject: [PATCH 0625/1102] Typo --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3917f7d7..9862a373 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3944,7 +3944,7 @@ class MyForm(settingsmixin.SMainWindow): for i in range(len(completerList)): if str(completerList[i]).endswith(" <" + item.address + ">"): completerList[i] = item.label + " <" + item.address + ">" - stringList = self.ui.lineEditTo.completer().model().setStringList(completerList) + self.ui.lineEditTo.completer().model().setStringList(completerList) def writeNewAddressToTable(self, label, address, streamNumber): self.rerenderTabTreeMessages() -- 2.45.1 From 6c907e204635be845e0b3f32a613c86ca3aafa35 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Feb 2017 21:14:39 +0100 Subject: [PATCH 0626/1102] Windows socket typo --- src/class_receiveDataThread.py | 2 +- src/class_sendDataThread.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c3b37865..56373458 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -118,7 +118,7 @@ class receiveDataThread(threading.Thread): except socket.error as err: if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ - err.errno in (errno.WSAEWOULDBLOCK)): + err.errno == errno.WSAEWOULDBLOCK): select.select([self.sslSock if isSSL else self.sock], [], [], 10) logger.debug('sock.recv retriable error') continue diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 667850cd..7defb634 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -100,7 +100,7 @@ class sendDataThread(threading.Thread): except socket.error as e: if e.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ - e.errno in (errno.WSAEWOULDBLOCK)): + e.errno == errno.WSAEWOULDBLOCK): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue -- 2.45.1 From 75f715bfe47f835639d811971515cc289f284ec0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 18 Feb 2017 17:20:09 +0100 Subject: [PATCH 0627/1102] BSD compatibility - separate Makefile for BSD make - auto-compile will detect BSD and pass the correct parameters to make - C PoW builds on OpenBSD and detects number of cores --- src/bitmsghash/Makefile.bsd | 14 ++++++++++++++ src/bitmsghash/bitmsghash.cpp | 10 ++++++++++ src/proofofwork.py | 7 ++++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/bitmsghash/Makefile.bsd diff --git a/src/bitmsghash/Makefile.bsd b/src/bitmsghash/Makefile.bsd new file mode 100644 index 00000000..6e680c86 --- /dev/null +++ b/src/bitmsghash/Makefile.bsd @@ -0,0 +1,14 @@ +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/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index f4979702..3c06b218 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -75,6 +75,10 @@ void getnumthreads() 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; @@ -86,6 +90,12 @@ void getnumthreads() 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; diff --git a/src/proofofwork.py b/src/proofofwork.py index 6ad790c0..dfae42fe 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -174,7 +174,12 @@ def buildCPoW(): notifyBuild(False) return try: - call(["make", "-C", os.path.join(paths.codePath(), "bitmsghash")]) + 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) -- 2.45.1 From a95f4aa2550315ca8c4ac6cdb7b453dff4a35ffa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 18 Feb 2017 17:22:17 +0100 Subject: [PATCH 0628/1102] LibreSSL compatibility - code distinguishes between OpenSSL 1.1.x and LibreSSL and works with both --- src/protocol.py | 2 +- src/pyelliptic/cipher.py | 2 +- src/pyelliptic/ecc.py | 14 +++++++------- src/pyelliptic/openssl.py | 7 ++++--- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/protocol.py b/src/protocol.py index 2268ac9d..4b1c67ff 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -502,7 +502,7 @@ else: sslProtocolVersion = ssl.PROTOCOL_TLSv1 # ciphers -if ssl.OPENSSL_VERSION_NUMBER >= 0x10100000: +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/pyelliptic/cipher.py b/src/pyelliptic/cipher.py index 4d932210..b597cafa 100644 --- a/src/pyelliptic/cipher.py +++ b/src/pyelliptic/cipher.py @@ -77,7 +77,7 @@ class Cipher: return buff + self.final() def __del__(self): - if OpenSSL._hexversion > 0x10100000: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_CIPHER_CTX_reset(self.ctx) else: OpenSSL.EVP_CIPHER_CTX_cleanup(self.ctx) diff --git a/src/pyelliptic/ecc.py b/src/pyelliptic/ecc.py index 7b5a07d2..bea645db 100644 --- a/src/pyelliptic/ecc.py +++ b/src/pyelliptic/ecc.py @@ -223,7 +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: + 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()) @@ -310,7 +310,7 @@ class ECC: size = len(inputb) buff = OpenSSL.malloc(inputb, size) digest = OpenSSL.malloc(0, 64) - if OpenSSL._hexversion > 0x10100000: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: md_ctx = OpenSSL.EVP_MD_CTX_new() else: md_ctx = OpenSSL.EVP_MD_CTX_create() @@ -343,7 +343,7 @@ class ECC: if (OpenSSL.EC_KEY_check_key(key)) == 0: raise Exception("[OpenSSL] EC_KEY_check_key FAIL ...") - if OpenSSL._hexversion > 0x10100000: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_MD_CTX_new(md_ctx) else: OpenSSL.EVP_MD_CTX_init(md_ctx) @@ -365,7 +365,7 @@ class ECC: OpenSSL.BN_free(pub_key_y) OpenSSL.BN_free(priv_key) OpenSSL.EC_POINT_free(pub_key) - if OpenSSL._hexversion > 0x10100000: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_MD_CTX_free(md_ctx) else: OpenSSL.EVP_MD_CTX_destroy(md_ctx) @@ -381,7 +381,7 @@ 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: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: md_ctx = OpenSSL.EVP_MD_CTX_new() else: md_ctx = OpenSSL.EVP_MD_CTX_create() @@ -405,7 +405,7 @@ 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: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_MD_CTX_new(md_ctx) else: OpenSSL.EVP_MD_CTX_init(md_ctx) @@ -431,7 +431,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: + if OpenSSL._hexversion > 0x10100000 and not OpenSSL._libreSSL: OpenSSL.EVP_MD_CTX_free(md_ctx) else: OpenSSL.EVP_MD_CTX_destroy(md_ctx) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index a26339ce..7af4fd18 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -72,6 +72,7 @@ class _OpenSSL: """ 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 @@ -170,7 +171,7 @@ class _OpenSSL: self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, ctypes.c_void_p] - if self._hexversion >= 0x10100000: + 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 = [] @@ -250,7 +251,7 @@ class _OpenSSL: self.EVP_rc4.restype = ctypes.c_void_p self.EVP_rc4.argtypes = [] - if self._hexversion >= 0x10100000: + 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] @@ -306,7 +307,7 @@ 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: + 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 = [] -- 2.45.1 From 67c8966a21c21ea3496aec4ccc1017047a12f238 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Feb 2017 14:48:53 +0100 Subject: [PATCH 0629/1102] Windows compatibility fixes - spec file for pyinstaller detects architecture (32 or 64bit) - spec file uses os.path.join - spec file creates and adds the list of messagetypes - added MinGW/MSyS support in Makefile - separate Makefile.msvc for MCVC - bitmsghash.cpp minor adjustments to build also on MSVC/MinGW - if frozen mode, messagetypes loads the list of files from a text file generated during archive building rather than from a directory --- packages/pyinstaller/bitmessagemain.spec | 47 ++++++++++++++++++------ src/bitmsghash/Makefile | 9 ++++- src/bitmsghash/Makefile.msvc | 2 + src/bitmsghash/bitmsghash.cpp | 8 ++++ src/messagetypes/__init__.py | 12 +++++- 5 files changed, 63 insertions(+), 15 deletions(-) create mode 100644 src/bitmsghash/Makefile.msvc diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index 0b41bb00..bb16b911 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -1,15 +1,30 @@ +import ctypes +import os + srcPath = "C:\\src\\PyBitmessage\\src\\" -qtPath = "C:\\Qt\\4.8.6\\" -openSSLPath = "C:\\OpenSSL-1.0.2e\\" -outPath = "C:\\src\\PyInstaller\\bitmessagemain" +qtPath = "C:\\Qt-4.8.7\\" +openSSLPath = "C:\\OpenSSL-1.0.2j\\" +outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" # -*- mode: python -*- a = Analysis([srcPath + 'bitmessagemain.py'], pathex=[outPath], - hiddenimports=[], + hiddenimports=['messagetypes'], hookspath=None, runtime_hooks=None) - + +# manually add messagetypes directory and its listing +with open(os.path.join(srcPath, 'messagetypes.txt'), 'wt') as f: + for mt in os.listdir(os.path.join(srcPath, 'messagetypes')): + if mt == "__init__.py": + continue + splitted = os.path.splitext(mt) + if splitted[1] != ".py": + continue + f.write(mt + "\n") + a.scripts.append((os.path.join('messagetypes', mt), os.path.join(srcPath, 'messagetypes', mt), 'PYMODULE')) +a.datas.append(('messagetypes.txt', os.path.join(srcPath, 'messagetypes.txt'), 'DATA')) + # fix duplicates for d in a.datas: if 'pyconfig' in d[0]: @@ -22,11 +37,11 @@ def addTranslations(): for file in os.listdir(srcPath + 'translations'): if file[-3:] != ".qm": continue - extraDatas.append(('translations\\'+file, srcPath + 'translations\\' + file, 'DATA')) + 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(('translations\\'+file, qtPath + 'translations\\' + file, 'DATA')) + extraDatas.append((os.path.join('translations', file), os.path.join(qtPath, 'translations', file), 'DATA')) return extraDatas def addUIs(): @@ -35,14 +50,24 @@ def addUIs(): for file in os.listdir(srcPath + 'bitmessageqt'): if file[-3:] != ".ui": continue - extraDatas.append(('ui\\'+file, srcPath + 'bitmessageqt\\' + file, 'DATA')) + 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() -a.binaries.append(('msvcr120.dll', 'C:\\WINDOWS\\system32\\msvcr120.dll', 'BINARY')) +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') + ] pyz = PYZ(a.pure) exe = EXE(pyz, @@ -50,9 +75,9 @@ exe = EXE(pyz, a.binaries, a.zipfiles, a.datas, - a.binaries + [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), ('bitmsghash\\bitmsghash32.dll', srcPath + 'bitmsghash\\bitmsghash32.dll', 'BINARY'), ('bitmsghash\\bitmsghash.cl', srcPath + 'bitmsghash\\bitmsghash.cl', 'BINARY'), ('sslkeys\\cert.pem', srcPath + 'sslkeys\\cert.pem', 'BINARY'), ('sslkeys\\key.pem', srcPath + 'sslkeys\\key.pem', 'BINARY')], + a.binaries, name='Bitmessage.exe', debug=False, strip=None, upx=False, - console=False, icon= srcPath + 'images\\can-icon.ico') + console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico') diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile index 88744524..3d0f5d0a 100644 --- a/src/bitmsghash/Makefile +++ b/src/bitmsghash/Makefile @@ -2,6 +2,11 @@ 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 bigmsghash.so endif all: bitmsghash.so @@ -10,11 +15,11 @@ powtest: ./testpow.py bitmsghash.so: bitmsghash.o - g++ bitmsghash.o -shared -fPIC -lpthread -lcrypto $(LDFLAGS) -o bitmsghash.so + g++ bitmsghash.o -shared -fPIC -lcrypto $(LDFLAGS) bitmsghash.o: g++ -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp clean: - rm -f bitmsghash.o bitmsghash.so + rm -f bitmsghash.o bitmsghash.so bitmsghash*.dll diff --git a/src/bitmsghash/Makefile.msvc b/src/bitmsghash/Makefile.msvc new file mode 100644 index 00000000..63482c34 --- /dev/null +++ b/src/bitmsghash/Makefile.msvc @@ -0,0 +1,2 @@ +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.cpp b/src/bitmsghash/bitmsghash.cpp index 3c06b218..2d0d4b50 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -66,7 +66,11 @@ void * threadfunc(void* param) { successval = tmpnonce; } } +#ifdef _WIN32 + return 0; +#else return NULL; +#endif } void getnumthreads() @@ -104,7 +108,11 @@ void getnumthreads() #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 diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index 16d97ae7..e22be925 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -3,7 +3,7 @@ from os import path, listdir from string import lower from debug import logger - +import paths class MsgBase(object): def encode(self): @@ -28,7 +28,15 @@ def constructObject(data): else: return returnObj -for mod in listdir(path.dirname(__file__)): +mods = [] +if paths.frozen is not None: + with open(path.join(path.dirname(path.dirname(__file__)), 'messagetypes.txt'), 'rt') as f: + for m in f.readline(): + mods.append(m.rstrip()) +else: + mods = listdir(path.dirname(__file__)) + +for mod in mods: if mod == "__init__.py": continue splitted = path.splitext(mod) -- 2.45.1 From 46a2c361dea30c7ef1ed9abd127185c0214d0c07 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Feb 2017 19:48:45 +0100 Subject: [PATCH 0630/1102] Building and msgpack fixes - Makefile typo - pyinstaller rewritten and fixed including and initialisation of messagetypes - msgpack decoding new message display fix --- packages/pyinstaller/bitmessagemain.spec | 26 ++++++++++++++++-------- src/bitmessageqt/account.py | 5 ++++- src/bitmsghash/Makefile | 2 +- src/messagetypes/__init__.py | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index bb16b911..c26325c3 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -6,12 +6,8 @@ qtPath = "C:\\Qt-4.8.7\\" openSSLPath = "C:\\OpenSSL-1.0.2j\\" outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" -# -*- mode: python -*- -a = Analysis([srcPath + 'bitmessagemain.py'], - pathex=[outPath], - hiddenimports=['messagetypes'], - hookspath=None, - runtime_hooks=None) +messagetypes = [] +hiddenimports= [] # manually add messagetypes directory and its listing with open(os.path.join(srcPath, 'messagetypes.txt'), 'wt') as f: @@ -22,7 +18,19 @@ with open(os.path.join(srcPath, 'messagetypes.txt'), 'wt') as f: if splitted[1] != ".py": continue f.write(mt + "\n") - a.scripts.append((os.path.join('messagetypes', mt), os.path.join(srcPath, 'messagetypes', mt), 'PYMODULE')) + hiddenimports.append('messagetypes.' + splitted[0]) + messagetypes.append(mt) + +# -*- mode: python -*- +a = Analysis([srcPath + 'bitmessagemain.py'], + pathex=[outPath], + hiddenimports=hiddenimports, + hookspath=None, + runtime_hooks=None) + +for mt in messagetypes: + a.scripts.append((os.path.join('messagetypes', mt), os.path.join(srcPath, 'messagetypes', mt), 'PYMODULE')) + a.datas.append(('messagetypes.txt', os.path.join(srcPath, 'messagetypes.txt'), 'DATA')) # fix duplicates @@ -37,7 +45,7 @@ def addTranslations(): 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')) + 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 @@ -80,4 +88,4 @@ exe = EXE(pyz, debug=False, strip=None, upx=False, - console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico') + console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 897cddef..03a22be0 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -128,7 +128,10 @@ class BMAccount(object): def parseMessage(self, toAddress, fromAddress, subject, message): self.toAddress = toAddress self.fromAddress = fromAddress - self.subject = subject + 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) diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile index 3d0f5d0a..56a6a3a9 100644 --- a/src/bitmsghash/Makefile +++ b/src/bitmsghash/Makefile @@ -6,7 +6,7 @@ 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 bigmsghash.so + LDFLAGS += -lpthread -o bitmsghash.so endif all: bitmsghash.so diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index e22be925..e455c61b 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -31,7 +31,7 @@ def constructObject(data): mods = [] if paths.frozen is not None: with open(path.join(path.dirname(path.dirname(__file__)), 'messagetypes.txt'), 'rt') as f: - for m in f.readline(): + for m in f.readlines(): mods.append(m.rstrip()) else: mods = listdir(path.dirname(__file__)) -- 2.45.1 From 249a513630b15cb277efb3d1f3c454233e2efa72 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Feb 2017 21:53:32 +0100 Subject: [PATCH 0631/1102] Pyinstaller warning - remove unnecessary includes --- packages/pyinstaller/bitmessagemain.spec | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index c26325c3..1f568f33 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -6,7 +6,6 @@ qtPath = "C:\\Qt-4.8.7\\" openSSLPath = "C:\\OpenSSL-1.0.2j\\" outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" -messagetypes = [] hiddenimports= [] # manually add messagetypes directory and its listing @@ -19,7 +18,6 @@ with open(os.path.join(srcPath, 'messagetypes.txt'), 'wt') as f: continue f.write(mt + "\n") hiddenimports.append('messagetypes.' + splitted[0]) - messagetypes.append(mt) # -*- mode: python -*- a = Analysis([srcPath + 'bitmessagemain.py'], @@ -28,9 +26,6 @@ a = Analysis([srcPath + 'bitmessagemain.py'], hookspath=None, runtime_hooks=None) -for mt in messagetypes: - a.scripts.append((os.path.join('messagetypes', mt), os.path.join(srcPath, 'messagetypes', mt), 'PYMODULE')) - a.datas.append(('messagetypes.txt', os.path.join(srcPath, 'messagetypes.txt'), 'DATA')) # fix duplicates -- 2.45.1 From ea448c44961755c44e8ceef351be556a813082fc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Feb 2017 12:15:51 +0100 Subject: [PATCH 0632/1102] SOCKS error handler winsock compatibility - now it can detect WSA errors as well, allowing more accurate error feedback --- src/socks/__init__.py | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/socks/__init__.py b/src/socks/__init__.py index ca1336b9..e77c129d 100644 --- a/src/socks/__init__.py +++ b/src/socks/__init__.py @@ -406,11 +406,14 @@ class socksocket(socket.socket): try: _orgsocket.connect(self, (self.__proxy[1], portnum)) except socket.error as e: - if e[0] == 101: + # ENETUNREACH, WSAENETUNREACH + if e[0] in [101, 10051]: raise GeneralProxyError((7, _generalerrors[7])) - if e[0] == 111: + # ECONNREFUSED, WSAECONNREFUSED + if e[0] in [111, 10061]: raise GeneralProxyError((8, _generalerrors[8])) - if e[0] == 113: + # EHOSTUNREACH, WSAEHOSTUNREACH + if e[0] in [113, 10065]: raise GeneralProxyError((9, _generalerrors[9])) raise self.__negotiatesocks5() @@ -427,10 +430,34 @@ class socksocket(socket.socket): portnum = self.__proxy[2] else: portnum = 8080 - _orgsocket.connect(self,(self.__proxy[1], portnum)) + 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.__negotiatehttp(destpair[0], destpair[1]) elif self.__proxy[0] == None: - _orgsocket.connect(self, (destpair[0], destpair[1])) + try: + _orgsocket.connect(self, (destpair[0], destpair[1])) + 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 else: raise GeneralProxyError((4, _generalerrors[4])) -- 2.45.1 From 9c4366ffa6b404d5ef8b80331bdb0f295d9256e9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Feb 2017 12:34:55 +0100 Subject: [PATCH 0633/1102] Don't report direct network errors as proxy errors - last commit reported network errors that happened when proxy was off as network errors --- src/socks/__init__.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/socks/__init__.py b/src/socks/__init__.py index e77c129d..0bfa18f5 100644 --- a/src/socks/__init__.py +++ b/src/socks/__init__.py @@ -445,19 +445,7 @@ class socksocket(socket.socket): raise self.__negotiatehttp(destpair[0], destpair[1]) elif self.__proxy[0] == None: - try: - _orgsocket.connect(self, (destpair[0], destpair[1])) - 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, (destpair[0], destpair[1])) else: raise GeneralProxyError((4, _generalerrors[4])) -- 2.45.1 From 579ba49f38ed5d5283abac9cec9530bbe4ee2bc5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Feb 2017 20:53:50 +0100 Subject: [PATCH 0634/1102] Deamon mode without PyQt4 - daemon mode shouldn't require PyQt4 --- src/class_smtpDeliver.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 5c320f51..b3be09c0 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -8,7 +8,6 @@ import urlparse from configparser import BMConfigParser from debug import logger from helper_threading import * -from bitmessageqt.uisignaler import UISignaler import queues import state @@ -31,7 +30,7 @@ class smtpDeliver(threading.Thread, StoppableThread): @classmethod def get(cls): if not cls._instance: - cls._instance = UISignaler() + cls._instance = smtpDeliver() return cls._instance def run(self): -- 2.45.1 From ea9f10a8bb7e756171994ebbe7afca332e2fd2eb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Feb 2017 22:32:49 +0100 Subject: [PATCH 0635/1102] Simplify and fix list of addresses to send - it didn't always send the maximum possible amount - it probably was slow --- src/class_receiveDataThread.py | 106 +++++++++++++-------------------- 1 file changed, 43 insertions(+), 63 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 56373458..10befd06 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -658,74 +658,54 @@ class receiveDataThread(threading.Thread): with knownnodes.knownNodesLock: if len(knownnodes.knownNodes[stream]) > 0: - ownPosition = random.randint(0, 499) - sentOwn = False - for i in range(500): - # if current connection is over a proxy, sent our own onion address at a random position - if ownPosition == i and ".onion" in BMConfigParser().get("bitmessagesettings", "onionhostname") and \ - hasattr(self.sock, "getproxytype") and self.sock.getproxytype() != "none" and not sentOwn: - peer = state.Peer(BMConfigParser().get("bitmessagesettings", "onionhostname"), BMConfigParser().getint("bitmessagesettings", "onionport")) - else: - # still may contain own onion address, but we don't change it - peer, = random.sample(knownnodes.knownNodes[stream], 1) - if isHostInPrivateIPRange(peer.host): - continue - if peer.host == BMConfigParser().get("bitmessagesettings", "onionhostname") and peer.port == BMConfigParser().getint("bitmessagesettings", "onionport") : - sentOwn = True - addrsInMyStream[peer] = knownnodes.knownNodes[ - stream][peer] + filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + elemCount = len(filtered) + if elemCount > 500: + elemCount = 500 + # 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: - for i in range(250): - peer, = random.sample(knownnodes.knownNodes[ - stream * 2], 1) - if isHostInPrivateIPRange(peer.host): - continue - addrsInChildStreamLeft[peer] = knownnodes.knownNodes[ - stream * 2][peer] + filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + elemCount = len(filtered) + if elemCount > 250: + elemCount = 250 + addrsInMyStreamLeft = random.sample(filtered.items(), elemCount) if len(knownnodes.knownNodes[(stream * 2) + 1]) > 0 and stream not in self.streamNumber: - for i in range(250): - peer, = random.sample(knownnodes.knownNodes[ - (stream * 2) + 1], 1) - if isHostInPrivateIPRange(peer.host): - continue - addrsInChildStreamRight[peer] = knownnodes.knownNodes[ - (stream * 2) + 1][peer] + 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 > 250: + elemCount = 250 + addrsInMyStreamRight = random.sample(filtered.items(), elemCount) numberOfAddressesInAddrMessage = 0 payload = '' - 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', stream) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.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', stream * 2) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.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', (stream * 2) + 1) - payload += pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port + 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 + 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 + 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 payload = encodeVarint(numberOfAddressesInAddrMessage) + payload self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload))) -- 2.45.1 From fef6126a74c296aa796af80b97eddd65cec93bdb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 21 Feb 2017 09:58:28 +0100 Subject: [PATCH 0636/1102] Error handling improvement in sendDataThread - don't uncecessarily report EPIPE as a big error, just close the connection --- src/class_sendDataThread.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 7defb634..320cb932 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -77,7 +77,7 @@ class sendDataThread(threading.Thread): def sendBytes(self, data = ""): self.buffer += data if len(self.buffer) < throttle.SendThrottle().chunkSize and self.sendDataThreadQueue.qsize() > 1: - return + return True while self.buffer and state.shutdown == 0: isSSL = False @@ -104,16 +104,18 @@ class sendDataThread(threading.Thread): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue + if e.errno in (errno.EPIPE): + logger.debug('Connection broken') + 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 True: - self.sendBytes() + while self.sendBytes(): deststream, command, data = self.sendDataThreadQueue.get() if deststream == 0 or deststream in self.streamNumber: -- 2.45.1 From c8429365e358115fb11add3cc99b3763f2eca5dc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 21 Feb 2017 10:25:59 +0100 Subject: [PATCH 0637/1102] Typo - typo in last commit --- src/class_sendDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 320cb932..3d35c48a 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -104,7 +104,7 @@ class sendDataThread(threading.Thread): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue - if e.errno in (errno.EPIPE): + if e.errno == errno.EPIPE: logger.debug('Connection broken') return False raise -- 2.45.1 From fd95f8f519d9c06ad2cdac4016901c76ec03a657 Mon Sep 17 00:00:00 2001 From: Justin Ramos Date: Fri, 13 Jan 2017 01:12:11 +0000 Subject: [PATCH 0638/1102] allowing for max outbound connection configuration Signed-off-by: Justin Ramos --- .gitignore | 4 +++- src/bitmessageqt/__init__.py | 6 ++++++ src/bitmessageqt/settings.py | 14 ++++++++++++++ src/bitmessageqt/settings.ui | 23 +++++++++++++++++++++++ src/class_outgoingSynSender.py | 2 +- src/class_sqlThread.py | 10 ++++++++++ src/helper_startup.py | 1 + 7 files changed, 58 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b0bf5ae4..f3eb161c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ src/dist src/.project src/.pydevproject src/.settings/ -*.dll \ No newline at end of file +src/**/.dll +src/**/*.o +src/**/*.so diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9862a373..cbf6217f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2400,6 +2400,10 @@ class MyForm(settingsmixin.SMainWindow): except: QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( "MainWindow", "Your maximum download and upload rate must be numbers. Ignoring what you typed.")) + + BMConfigParser().set('bitmessagesettings', 'maxoutboundconnections', str( + int(float(self.settingsDialogInstance.ui.lineEditMaxOutboundConnections.text())))) + throttle.SendThrottle().resetLimit() throttle.ReceiveThrottle().resetLimit() @@ -4108,6 +4112,8 @@ class settingsDialog(QtGui.QDialog): BMConfigParser().get('bitmessagesettings', 'maxdownloadrate'))) self.ui.lineEditMaxUploadRate.setText(str( BMConfigParser().get('bitmessagesettings', 'maxuploadrate'))) + self.ui.lineEditMaxOutboundConnections.setText(str( + BMConfigParser().get('bitmessagesettings', 'maxoutboundconnections'))) # Demanded difficulty tab self.ui.lineEditTotalDifficulty.setText(str((float(BMConfigParser().getint( diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 33b4c29d..300c3544 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -154,6 +154,19 @@ 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, 4096, 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")) @@ -459,6 +472,7 @@ class Ui_settingsDialog(object): 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)) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index 475821f8..4aeba3ce 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -317,6 +317,29 @@ + + + + Maximum outbound connections: [0: none] + + + + + + + + 0 + 0 + + + + + 60 + 16777215 + + + + diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 91cd660a..a41ae75a 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -78,7 +78,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.stop.wait(2) while BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" - maximumConnections = 1 if state.trustedPeer else 8 # maximum number of outgoing connections = 8 + 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: diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 3a8b1bed..332a40ec 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -434,6 +434,16 @@ class sqlThread(threading.Thread): 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 diff --git a/src/helper_startup.py b/src/helper_startup.py index 3841e1ed..ca89d111 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -107,6 +107,7 @@ def loadConfig(): 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') #start:UI setting to stop trying to send messages after X days/months -- 2.45.1 From 266d8eba1f9e2d666332e2ab9cd76bda55b20c87 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 09:05:05 +0100 Subject: [PATCH 0639/1102] SafeHTMLParser unicode / subprocess - don't do subprocess in SafeHTMLParser, it doesn't work in frozen mode and an attempt to fix it would take too much refactoring and I'm not even sure it would work - instead, make it handle broken unicode correctly - I think the previous reports of freezes were caused by trying to interpret data as unicode, causing a crash - it does about 1MB/s on my machine, so a timeout is not a big problem --- src/bitmessageqt/safehtmlparser.py | 58 ++++++------------------------ src/queues.py | 5 --- src/shutdown.py | 6 +--- 3 files changed, 12 insertions(+), 57 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 5fe5265c..1ff12c8e 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -1,28 +1,9 @@ from HTMLParser import HTMLParser import inspect -import multiprocessing import re -import Queue from urllib import quote, quote_plus from urlparse import urlparse from debug import logger -from queues import parserInputQueue, parserOutputQueue, parserProcess, parserLock - -def regexpSubprocess(parserInputQueue, parserOutputQueue): - for data in iter(parserInputQueue.get, None): - if data is None: - break; - try: - result = SafeHTMLParser.uriregex1.sub( - r'\1', - data) - result = SafeHTMLParser.uriregex2.sub(r'\1', result) - parserOutputQueue.put(result) - except SystemExit: - break; - except: - break; class SafeHTMLParser(HTMLParser): # from html5lib.sanitiser @@ -82,7 +63,7 @@ class SafeHTMLParser(HTMLParser): val == "" self.sanitised += " " + quote_plus(attr) if not (val is None): - self.sanitised += "=\"" + (val if isinstance(val, unicode) else unicode(val, 'utf-8', 'replace')) + "\"" + self.sanitised += "=\"" + val + "\"" if inspect.stack()[1][3] == "handle_startendtag": self.sanitised += "/" self.sanitised += ">" @@ -101,7 +82,7 @@ class SafeHTMLParser(HTMLParser): self.add_if_acceptable(tag, attrs) def handle_data(self, data): - self.sanitised += unicode(data, 'utf-8', 'replace') + self.sanitised += data def handle_charref(self, name): self.sanitised += "&#" + name + ";" @@ -110,34 +91,17 @@ class SafeHTMLParser(HTMLParser): self.sanitised += "&" + name + ";" def feed(self, data): - global parserProcess + try: + data = unicode(data, 'utf-8') + except UnicodeDecodeError: + data = unicode(data, 'utf-8', errors='replace') HTMLParser.feed(self, data) tmp = SafeHTMLParser.multi_replace(data) - tmp = unicode(tmp, 'utf-8', 'replace') - - parserLock.acquire() - if parserProcess is None: - parserProcess = multiprocessing.Process(target=regexpSubprocess, name="RegExParser", args=(parserInputQueue, parserOutputQueue)) - parserProcess.start() - parserLock.release() - # flush queue - try: - while True: - tmp = parserOutputQueue.get(False) - except Queue.Empty: - logger.debug("Parser queue flushed") - pass - parserInputQueue.put(tmp) - try: - tmp = parserOutputQueue.get(True, 1) - except Queue.Empty: - logger.error("Regular expression parsing timed out, not displaying links") - parserLock.acquire() - parserProcess.terminate() - parserProcess = multiprocessing.Process(target=regexpSubprocess, name="RegExParser", args=(parserInputQueue, parserOutputQueue)) - parserProcess.start() - parserLock.release() - + tmp = SafeHTMLParser.uriregex1.sub( + r'\1', + tmp) + tmp = SafeHTMLParser.uriregex2.sub(r'\1', tmp) self.raw += tmp def is_html(self, text = None, allow_picture = False): diff --git a/src/queues.py b/src/queues.py index f50a0f1c..c7dab16f 100644 --- a/src/queues.py +++ b/src/queues.py @@ -9,8 +9,3 @@ addressGeneratorQueue = Queue.Queue() objectProcessorQueue = ObjectProcessorQueue() apiAddressGeneratorReturnQueue = Queue.Queue( ) # The address generator thread uses this queue to get information back to the API thread. - -parserProcess = None -parserLock = mpLock() -parserInputQueue = mpQueue() -parserOutputQueue = mpQueue() diff --git a/src/shutdown.py b/src/shutdown.py index 8a219237..bf1a4d12 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -12,16 +12,12 @@ from helper_threading import StoppableThread from knownnodes import saveKnownNodes from inventory import Inventory import protocol -from queues import addressGeneratorQueue, objectProcessorQueue, parserInputQueue, UISignalQueue, workerQueue +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. - try: - parserInputQueue.put(None, False) - except Queue.Full: - pass protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) for thread in threading.enumerate(): -- 2.45.1 From 6062277d60abb82e7bcf5cb77882c6f81b721332 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 09:34:54 +0100 Subject: [PATCH 0640/1102] Rename configparser.py to bmconfigparser.py - it was causing problems with py2app because the source of python's own CongigParser is also configparser.py --- src/api.py | 2 +- src/bitmessagecli.py | 2 +- src/bitmessagecurses/__init__.py | 2 +- src/bitmessagemain.py | 2 +- src/bitmessageqt/__init__.py | 2 +- src/bitmessageqt/account.py | 2 +- src/bitmessageqt/bitmessageui.py | 2 +- src/bitmessageqt/blacklist.py | 2 +- src/bitmessageqt/foldertree.py | 2 +- src/bitmessageqt/languagebox.py | 2 +- src/bitmessageqt/support.py | 2 +- src/bitmessageqt/utils.py | 2 +- src/{configparser.py => bmconfigparser.py} | 0 src/class_addressGenerator.py | 2 +- src/class_objectProcessor.py | 2 +- src/class_outgoingSynSender.py | 2 +- src/class_receiveDataThread.py | 2 +- src/class_singleCleaner.py | 2 +- src/class_singleListener.py | 2 +- src/class_singleWorker.py | 2 +- src/class_smtpDeliver.py | 2 +- src/class_smtpServer.py | 2 +- src/class_sqlThread.py | 2 +- src/helper_bootstrap.py | 2 +- src/helper_generic.py | 2 +- src/helper_startup.py | 2 +- src/l10n.py | 2 +- src/namecoin.py | 2 +- src/openclpow.py | 2 +- src/proofofwork.py | 2 +- src/protocol.py | 2 +- src/shared.py | 2 +- src/shutdown.py | 2 +- src/throttle.py | 2 +- src/tr.py | 2 +- src/upnp.py | 2 +- 36 files changed, 35 insertions(+), 35 deletions(-) rename src/{configparser.py => bmconfigparser.py} (100%) diff --git a/src/api.py b/src/api.py index 27e2f7d6..d6d0b266 100644 --- a/src/api.py +++ b/src/api.py @@ -19,7 +19,7 @@ from binascii import hexlify import shared import time from addresses import decodeAddress,addBMIfNotPresent,decodeVarint,calculateInventoryHash,varintDecodeError -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import defaults import helper_inbox import helper_sent diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 74836877..068a5597 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -16,7 +16,7 @@ import time import sys import os -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser api = '' keysName = 'keys.dat' diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 2cfb8c67..d710720f 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -23,7 +23,7 @@ from helper_sql import * from addresses import * import ConfigParser -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from inventory import Inventory import l10n from pyelliptic.openssl import OpenSSL diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 3f28cd87..707b6b62 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -44,7 +44,7 @@ from class_singleWorker import singleWorker from class_addressGenerator import addressGenerator from class_smtpDeliver import smtpDeliver from class_smtpServer import smtpServer -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger # Helper Functions diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cbf6217f..18bd70ed 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -30,7 +30,7 @@ except AttributeError: from addresses import * import shared from bitmessageui import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import defaults from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 03a22be0..7db5fa5a 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -6,7 +6,7 @@ import sys import inspect from helper_sql import * from addresses import decodeAddress -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from foldertree import AccountMixin from pyelliptic.openssl import OpenSSL from utils import str_broadcast_subscribers diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 668fbffd..f001487e 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,7 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from foldertree import AddressBookCompleter from messageview import MessageView from messagecompose import MessageCompose diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 29a324c0..e07f9469 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -3,7 +3,7 @@ from tr import _translate import l10n import widgets from addresses import addBMIfNotPresent -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from dialogs import AddAddressDialog from helper_sql import sqlExecute, sqlQuery from retranslateui import RetranslateMixin diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 4392495d..7cc42229 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,7 +1,7 @@ from PyQt4 import QtCore, QtGui from string import find, rfind, rstrip, lstrip -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from helper_sql import * from utils import * from settingsmixin import SettingsMixin diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 8cce1e03..552e0350 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -2,7 +2,7 @@ import glob import os from PyQt4 import QtCore, QtGui -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import paths class LanguageBox(QtGui.QComboBox): diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 60e9fa58..67e46500 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -5,7 +5,7 @@ import sys import time import account -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import defaults from foldertree import AccountMixin diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index fd18183d..73367586 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -2,7 +2,7 @@ from PyQt4 import QtGui import hashlib import os from addresses import addBMIfNotPresent -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import state str_broadcast_subscribers = '[Broadcast subscribers]' diff --git a/src/configparser.py b/src/bmconfigparser.py similarity index 100% rename from src/configparser.py rename to src/bmconfigparser.py diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index d938a43b..bd377c1d 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -7,7 +7,7 @@ import ctypes import hashlib import highlevelcrypto from addresses import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import defaults from helper_threading import * diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index b9969d9e..446e09ab 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -13,7 +13,7 @@ from binascii import hexlify from pyelliptic.openssl import OpenSSL import highlevelcrypto from addresses import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import helper_generic from helper_generic import addDataPadding import helper_bitcoin diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index a41ae75a..254caabb 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -11,7 +11,7 @@ import tr from class_sendDataThread import * from class_receiveDataThread import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from helper_threading import * import knownnodes import queues diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 10befd06..d3bcd689 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -24,7 +24,7 @@ from binascii import hexlify #import highlevelcrypto from addresses import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 3be3ef21..921e84ed 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -5,7 +5,7 @@ import sys import os import tr#anslate -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from helper_sql import * from helper_threading import * from inventory import Inventory diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 49acc71c..0a8c4a93 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -1,7 +1,7 @@ import threading import shared import socket -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from class_sendDataThread import * from class_receiveDataThread import * import helper_bootstrap diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index fc2ecebe..863fbde9 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -11,7 +11,7 @@ import highlevelcrypto import proofofwork import sys import tr -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import defaults from helper_sql import * diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index b3be09c0..9492f123 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -5,7 +5,7 @@ import sys import threading import urlparse -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger from helper_threading import * import queues diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 359c8625..13882a94 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -11,7 +11,7 @@ import threading import time from addresses import decodeAddress -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlExecute from helper_threading import StoppableThread diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 332a40ec..b46a570f 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -1,5 +1,5 @@ import threading -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import sqlite3 import time import shutil # used for moving the messages.dat file diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 795b4d2a..33a533ca 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -3,7 +3,7 @@ import defaultKnownNodes import pickle import time -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import knownnodes import socks diff --git a/src/helper_generic.py b/src/helper_generic.py index 1e70b3e0..f2a293cd 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -5,7 +5,7 @@ from binascii import hexlify, unhexlify from multiprocessing import current_process from threading import current_thread, enumerate -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import queues import shutdown diff --git a/src/helper_startup.py b/src/helper_startup.py index ca89d111..6402ee89 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -1,5 +1,5 @@ import ConfigParser -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import defaults import sys import os diff --git a/src/l10n.py b/src/l10n.py index 31df0656..b3b16341 100644 --- a/src/l10n.py +++ b/src/l10n.py @@ -3,7 +3,7 @@ import logging import os import time -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser #logger = logging.getLogger(__name__) diff --git a/src/namecoin.py b/src/namecoin.py index 1834458c..2cfa5a1d 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -26,7 +26,7 @@ import socket import sys import os -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import defaults import tr # translate diff --git a/src/openclpow.py b/src/openclpow.py index b8c73987..50de80ab 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,7 +5,7 @@ import hashlib import random import os -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import paths from state import shutdown from debug import logger diff --git a/src/proofofwork.py b/src/proofofwork.py index dfae42fe..e20d6cff 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -6,7 +6,7 @@ from struct import unpack, pack from subprocess import call import sys import time -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import paths import openclpow diff --git a/src/protocol.py b/src/protocol.py index 4b1c67ff..82edbd15 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -10,7 +10,7 @@ import time import traceback from addresses import calculateInventoryHash, encodeVarint, decodeVarint, decodeAddress, varintDecodeError -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger import defaults from helper_sql import sqlExecute diff --git a/src/shared.py b/src/shared.py index 4fefa0f8..c28392f6 100644 --- a/src/shared.py +++ b/src/shared.py @@ -18,7 +18,7 @@ from binascii import hexlify # Project imports. from addresses import * -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser import highlevelcrypto #import helper_startup from helper_sql import * diff --git a/src/shutdown.py b/src/shutdown.py index bf1a4d12..a066104c 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -5,7 +5,7 @@ import time from class_outgoingSynSender import outgoingSynSender from class_sendDataThread import sendDataThread -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure from helper_threading import StoppableThread diff --git a/src/throttle.py b/src/throttle.py index 6ed154ee..6e53f217 100644 --- a/src/throttle.py +++ b/src/throttle.py @@ -2,7 +2,7 @@ import math import threading import time -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from singleton import Singleton import state diff --git a/src/tr.py b/src/tr.py index 5146a162..c185690c 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,6 +1,6 @@ import os -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser # 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: diff --git a/src/upnp.py b/src/upnp.py index fa969f36..29f1c937 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -6,7 +6,7 @@ import socket from struct import unpack, pack import threading import time -from configparser import BMConfigParser +from bmconfigparser import BMConfigParser from helper_threading import * import queues import shared -- 2.45.1 From 56384a353ab26a9038e1c25a1f0f755c27acf612 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 11:18:16 +0100 Subject: [PATCH 0641/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 63540 -> 63662 bytes src/translations/bitmessage_ja.ts | 541 +++++++++++++++--------------- 2 files changed, 273 insertions(+), 268 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index f01e2060090fb13b7ee7a3949eac3a3a313cc585..9e051b5684045496429532f7030c316955770e81 100644 GIT binary patch delta 434 zcmV;j0Zsn2@B^;#1CSH}n2{AW0_#wbO-35xBLD@si2wlQSpWv90{{T)cmM}hMF0Tn z(UGk|2Q11R007%ck?n6GkN{U{dH?|3_5fJ5J^%nCK>%8FIsgFWwg6lPiU0uRhLe2( zzX5=gJpxVwlMMr28r@9-+74j=0JmiV<^*#90G?d~42%T;0OmK7g#%9k zwv*KZE&|;TlLZ8C0ilz11l9uIag$92R{`adr3D`mrUr<1egFVI00x{&N9 zHVWP*2HjRJ007*?lNAO>0oIdU24(`}4wJvll=yV z0qm272lokv3TR}W0081plZ6N;0lt&12&MwuKa*7nM*((|oe5t7yp#P29|3-o9ST1I z>yupyF9GPYjS3b52jCiM008U!lkurAv)T+E+gd1R09hw6qA;c~$S}|_rZDp`$z!E` zngBWgAOKqcFaSCLATVk$R{&iI000001^@s6Crx2^X>E0FAa8YaVsCYBWFTX2Zf<2` cbZKvHb2=bfFghS^Z*FB>ld<9$v-syc5N{@yF8}}l delta 331 zcmV-R0krb|Qi2wlP=Kuz&0{{T)1^@?EMF0Tn zUy-drk@jvO9spNqdH?|3gaBBzJ^%nCK>%8FIsgFWL;zd{iU0uR6qAJkzX1-DMFLI& z(!aS8wc diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 1d058390..5c41b62c 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -83,7 +83,7 @@ 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: @@ -168,122 +168,122 @@ Please type the desired email address (including @mailchuck.com) below: 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. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,217 +588,217 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1101,57 +1101,57 @@ Are you sure you want to delete the channel? ズーム レベル %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% @@ -1161,42 +1161,42 @@ Are you sure you want to delete the channel? %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 アドレスの生成を完了しました @@ -1206,231 +1206,231 @@ Are you sure you want to delete the channel? - + Disk full ディスクがいっぱいです - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %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 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました - + UPnP port mapping established on port %1 ポート%1でUPnPポートマッピングが確立しました - + 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 PoW(証明)を待っています - + %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 は間違っている可能性があります。 設定を確認してください。 - + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... @@ -1626,27 +1626,27 @@ The 'Random Number' option is selected by default but deterministic ad 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> <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. このソフトウェアはベータ版です。 @@ -1656,7 +1656,7 @@ The 'Random Number' option is selected by default but deterministic ad - + <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> @@ -1689,12 +1689,12 @@ The 'Random Number' option is selected by default but deterministic ad アドレス - + Blacklist ブラックリスト - + Whitelist ホワイトリスト @@ -1816,27 +1816,27 @@ The 'Random Number' option is selected by default but deterministic ad 接続 - + 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 @@ -1856,27 +1856,27 @@ The 'Random Number' option is selected by default but deterministic ad ネットワークの状態 - + 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 件の公開鍵を処理しました。 @@ -1962,12 +1962,12 @@ The 'Random Number' option is selected by default but deterministic ad チャンネル %1 を正常に作成 / 参加しました - + Chan creation / joining failed チャンネルの作成 / 参加に失敗しました - + Chan creation / joining cancelled チャンネルの作成 / 参加をキャンセルしました @@ -1975,17 +1975,17 @@ The 'Random Number' option is selected by default but deterministic ad 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 モジュールが利用できません。ビルドしてください。 @@ -2046,218 +2046,218 @@ 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 - + 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で済むように通知します。 - + 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 許可する最大の難易度 @@ -2267,82 +2267,87 @@ The 'Random Number' option is selected by default but deterministic ad - + <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): -- 2.45.1 From bda5b0211898a8bb3a93231b904d9af333db96d1 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 11:27:17 +0100 Subject: [PATCH 0642/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 93645 -> 93851 bytes src/translations/bitmessage_de.ts | 545 +++++++++++++++--------------- 2 files changed, 275 insertions(+), 270 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 0187f1f5965e705f029df9bc7c9fa46e929c5053..07dee7af430a0cb6e9a4504bcc07b8d0cade754a 100644 GIT binary patch delta 509 zcmW-dUr1AN6vxl`-QC}|+X_l86^!A75y&bZG6oI;Q`&a7TI`RRY`1N;Mf+WHyCG70 zYW*Y0%c<5M^Cc1uL})}lM7G|tLQ?Wc`WvgI3lzexjZU zxvt8916is_Vf;&V$-@G(B-;ej3^Hu*@C~VQtSb`WsgWr_=?^aq3xG#euGhN&cFk~O z!ulo5`K2>ufRvq2`o91sUsGM~cCPZ3m#n=zzrG5!iZ%J3@E}0Ysy)O|9eqgYrt*Q<;`fj8N>EHSqE6*7CTgJG+!_Z nZrvyy*A05;8Lk@jsOOMU=XX?g$wOZEU*wLSm9a1a1OguakWQ*8vNYRRvZ8QH7JO1s)PkKn93*egFVq2L_x<P z-BvCD0ZN3E9R^1M43lLBW&%{=lg$Pu5>3+xIPvZP0F{pjQ$AGy0ZjRm1qX%#O=gpg z2lfg|Mha+To&W(-CX EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -83,7 +83,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -174,122 +174,122 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 - + 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -398,17 +398,17 @@ It is important that you back up this file. Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. - + 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 anlegen. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,217 +596,217 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. - + 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1109,57 +1109,57 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? 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. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1169,42 +1169,42 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Stunde%n Stunden - + %n day(s) %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet - + Generating one new address Neue Addresse wird erstellt - + Done generating address. Doing work necessary to broadcast it... Die Addresse wurde erstellt. Arbeit wird verrichtet, um sie zu versenden... - + Generating %1 new addresses. Erzeuge %1 neue Addressen. - + %1 is already in 'Your Identities'. Not adding it again. %1 befindet sich bereits unter Ihren Identitäten, wird nicht doppelt hinzugefügt. - + Done generating address Addresse fertiggestellt. @@ -1214,230 +1214,230 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? - + Disk full Datenträger voll - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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% + 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... - + 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. - + 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 - + UPnP port mapping established on port %1 UPnP Port-Mapping eingerichtet auf Port %1 - + UPnP port mapping removed UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? - + Problem communicating with proxy: %1. Please check your network settings. - Kommunikationsfehler mit dem Proxy: %s. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. + Kommunikationsfehler mit dem Proxy: %1. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. - + 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 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. - + 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. - + 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... @@ -1634,27 +1634,27 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi aboutDialog - + About Über - + 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>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> - + This is Beta software. Dies ist Beta-Software. @@ -1664,7 +1664,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - + <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 Die Bitmessage-Entwickler</p></body></html> @@ -1697,12 +1697,12 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Adresse - + Blacklist Blacklist (Liste gesperrter Adressen) - + Whitelist Whitelist (Liste zugelassener Adressen) @@ -1824,27 +1824,27 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Verbindungen - + 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 @@ -1864,27 +1864,27 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. @@ -1970,12 +1970,12 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Chan %1 erfolgreich erstellt/beigetreten - + Chan creation / joining failed Chan-erstellung/-beitritt fehlgeschlagen - + Chan creation / joining cancelled Chan-erstellung/-beitritt abgebrochen @@ -1983,17 +1983,17 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. @@ -2054,218 +2054,218 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 - + 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 - + 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 - + 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. - + 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. - + 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 @@ -2275,82 +2275,87 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - + <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 - + <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 Verfalldatum herunterlädt, zum Beisplel 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> - + Give up after Gib auf nach - + and und - + days Tagen - + months. Monaten. - + Resends Expire Verfall der erneuten Sendungen - + Hide connection notifications Verbindungsbenachrichtigungen nicht anzeigen - + + Maximum outbound connections: [0: none] + Maximale Anzahl der ausgehenden Verbindungen, 0 bedeutet keine + + + Hardware GPU acceleration (OpenCL): Hardwaregrafikkartenbeschleunigung (OpenCL): -- 2.45.1 From 72ed3e340fec4633afc770e8684ebf15ef9ebaf3 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 11:29:18 +0100 Subject: [PATCH 0643/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 86349 -> 86533 bytes src/translations/bitmessage_sk.ts | 541 +++++++++++++++--------------- 2 files changed, 273 insertions(+), 268 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 5613d6e62da13b807b564a1fee77182959a7073a..7980f261c4577a45dee18a0d8af48d0aa1c86924 100644 GIT binary patch delta 521 zcmWkqUr3X26g~I1eZT!_`cO_RGS-9kVD5h_Kb;ZHj9?XnOSBD_+i>B&PuwO}G@+Pe zBseZq54DGoK@UPuVsAmIdC}K56_kIsIEUp+;0-C%( zR{}=IFTmz|v*wmBA5^ zzl(R}qVPZBvgNPcQ?*Z}s-TmtT())#pWroXO?U!4VjHGk{LGdR?pfZo9TDM0?zEq# zEsopWVqosovb|kcf*o1oap&3Vi`;8EHkuB)+uM~v6iLh@iyXdV8X9iGg&FA7f;0-o zt|P^jKL;kVn8cKE=l5LPFkB4{sD?5Q?;cahNJ%1P=xM~QFh&|U7ER7)bH$uXFBY!r kMJ?r;)HN+VS;*>IUUiLoRhOn~>GsXm|;?wPe^KUk5;*Vkl=4 zsKJ2Q+XQO#htKQ6##C-L`X&}Zj&1ZuYk-Pm49>U{{vL*u?F2`8gYF32B-(}hl_O%6 ztZbEhnf52~nK}aey@|MK2KbCh+O7<$UgDtCK}8&sbYTy2ifNh(dD-+XoB{5Yy`u7s z&*khi=dH3ezXJ3RDhI9Kp!y4r$u8A#qr|*A$X>!(O0%e#WWO>dstkTs3eucima5+$ zAkb;)sp$ok&9Q9W6lHM^nhjO|QO8FQK`tK$Ed|2S%~8v#(ARl5sfFBplH|)Pz1L>H zJU~uFTNohV_(R)y2myvo+pEn?#J_XCT1&<3S9Rfeyo{(eVJ;t^NDSNO+<4= EmailGatewayRegistrationDialog - + Registration failed: Registrácia zlyhala: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: @@ -83,7 +83,7 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -171,122 +171,122 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: 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. @@ -296,17 +296,17 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -316,47 +316,47 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -366,12 +366,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Odoslať - + Subscribe Prihlásiť sa k odberu - + Channel Kanál @@ -381,12 +381,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -395,17 +395,17 @@ It is important that you back up this file. 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.) @@ -414,37 +414,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -514,22 +514,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +537,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,217 +592,217 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 Od - + Sending email gateway registration request Odosielam požiadavku o registráciu na e-mailovej bráne - + 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 Odosielam žiadosť o odhlásenie z e-mailovej brány - + Sending email gateway status request Odosielam požiadavku o stave e-mailovej brány - + 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. Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1105,57 +1105,57 @@ Ste si istý, že chcete kanál odstrániť? Ú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. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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% @@ -1165,42 +1165,42 @@ Ste si istý, že chcete kanál odstrániť? %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é @@ -1210,231 +1210,231 @@ Ste si istý, že chcete kanál odstrániť? - + 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. - + 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. - + 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. - + 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... @@ -1631,27 +1631,27 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr aboutDialog - + About O - + PyBitmessage PyBitmessage - + version ? verzia ? - + <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. @@ -1661,7 +1661,7 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - + <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 Vývojári Bitmessage</p></body></html> @@ -1694,12 +1694,12 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr Adresa - + Blacklist Zoznam zakázaných - + Whitelist Zoznam povolených @@ -1821,27 +1821,27 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr Spojenia - + 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 @@ -1861,27 +1861,27 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. @@ -1967,12 +1967,12 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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é @@ -1980,17 +1980,17 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. @@ -2051,218 +2051,218 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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ť @@ -2272,82 +2272,87 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - + <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): -- 2.45.1 From 57a3c35299457852eab12723dff29258731bf82f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 12:15:52 +0100 Subject: [PATCH 0644/1102] Context menu on messages to deleted accounts - messages from deleted chans still stay in global inbox - this crated problems with account detection - created NoAccount class for such accounts --- src/bitmessageqt/account.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 7db5fa5a..611f5039 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -54,7 +54,8 @@ def accountClass(address): else: subscription = SubscriptionAccount(address) if subscription.type != AccountMixin.SUBSCRIPTION: - return None + # e.g. deleted chan + return NoAccount(address) return subscription try: gateway = BMConfigParser().get(address, "gateway") @@ -87,7 +88,7 @@ class AccountColor(AccountMixin): self.type = AccountMixin.NORMAL else: self.type = type - + class BMAccount(object): def __init__(self, address = None): @@ -136,6 +137,17 @@ class BMAccount(object): 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 -- 2.45.1 From af1bed903429d811b168c0aaad649237e3ebcbfc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 12:30:14 +0100 Subject: [PATCH 0645/1102] MessageView Unicode HTML fix - the HTML on/off click label should be unicode rather than str --- src/bitmessageqt/messageview.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 36fe8320..40830a70 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -108,7 +108,7 @@ class MessageView(QtGui.QTextBrowser): self.mode = MessageView.MODE_PLAIN out = self.html.raw if self.html.has_html: - out = "

" + str(QtGui.QApplication.translate("MessageView", "HTML detected, click here to display")) + "

" + out + out = "
" + unicode(QtGui.QApplication.translate("MessageView", "HTML detected, click here to display")) + "

" + out self.out = out self.outpos = 0 self.setHtml("") @@ -117,7 +117,7 @@ class MessageView(QtGui.QTextBrowser): def showHTML(self): self.mode = MessageView.MODE_HTML out = self.html.sanitised - out = "
" + str(QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "

" + out + out = "
" + unicode(QtGui.QApplication.translate("MessageView", "Click here to disable HTML")) + "

" + out self.out = out self.outpos = 0 self.setHtml("") -- 2.45.1 From fa1fc2a031287298451890df045191028916680c Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 12:36:09 +0100 Subject: [PATCH 0646/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 83862 -> 84424 bytes src/translations/bitmessage_eo.ts | 725 +++++++++++++++--------------- 2 files changed, 365 insertions(+), 360 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 549329085d2870aa762888b4e3814b072b0e86f0..18d6184cdb1dc21e0df1dbe056f576cad088072d 100644 GIT binary patch delta 6188 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 C55W!q diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index ffdaa0d2..1bd101c8 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -32,7 +32,7 @@ Account status at email gateway - Stato de retpoŝta kluza konto + Stato de retpoŝt-kluza konto @@ -58,14 +58,14 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi kun alia. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: + La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -83,7 +83,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -142,13 +142,13 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 Malforviŝi - + View HTML code as formatted text - Montri HTML-n kiel aranĝita teksto + Montri HTML-n kiel aranĝitan tekston - + Save message as... Konservi mesaĝon kiel... - + Mark Unread - Marki kiel nelegita + 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... - + 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 - + 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 forviŝi ĝin? - + Waiting for their encryption key. Will request it again soon. - Atendante ilian ĉifroŝlosilon. Baldaŭ petos ĝin denove. + Atendado je ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. @@ -291,17 +291,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 - Mesaĝo sendita. Atendante konfirmon. Sendita je %1 + Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - + Message sent. Sent at %1 Mesaĝo sendita. Sendita je %1 @@ -311,47 +311,47 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -361,12 +361,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Sendi - + Subscribe Aboni - + Channel Kanalo @@ -376,70 +376,70 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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. + Vi povas administri viajn ŝlosilojn redaktante 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 redaktante la dosieron keys.dat en la dosierujo %1. -Estas grava ke vi faru savkopion de tiu dosiero. +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 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.) + Vi povas administri viajn ŝlosilojn redaktante 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 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.) +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 ne estas la prava formularo por vi. + Vi devas tajpi vian pasvorton. Se vi ne havas pasvorton, tiu ĉi ne estas la prava formularo por vi. - + Bad address version number - Malkorekta numero de adresversio + 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. @@ -509,22 +509,22 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - + 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 @@ -532,17 +532,17 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 pro %1 bitokoj. (La maksimumo estas 261644 bitokoj.) Bonvolu mallongigi ĝin antaŭ sendado. + 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. @@ -587,322 +587,322 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier - + 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. - Priaboranta adreson %1, Bitmesaĝo ne povas kompreni numerojn %2 de adresversioj. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. + 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. - Priaboranta adreson %1, Bitmesaĝo ne povas priservi %2 fluojn numerojn. Eble ĝisdatigu Bitmesaĝon al la plej nova versio. + 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 ero(j)n en via adresaro kaj elektu 'Sendi mesaĝon al tiu adreso'. + 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 De - + Sending email gateway registration request - Sendanta peton pri registrado je retpoŝta kluzo + Sendado de peto pri registrado je retpoŝta kluzo - + 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 jaman se vi volas. + 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 jaman se vi volas. + 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 vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn konektojn. + Bitmesaĝo uzos vian prokurilon (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 - Sendanta peton pri malregistrado de retpoŝta kluzo + Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request - Sendanta peton pri stato de retpoŝta kluzo + Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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 forviŝos 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. + Se vi forviŝos 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 forviŝi 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 forviŝos 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. + Se vi forviŝos 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 forviŝi la kanalon? - + Do you really want to remove this avatar? - Ĉu vi certe volas forviŝi tiun avataron? + Ĉ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 adreso. Ĉu vi vere volas superskribi ĝin? + 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... - Testante... + Testado... - + This is a chan address. You cannot use it as a pseudo-mailing list. - Tio estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. + Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. - Kelkaj datumoj kodita en la adreso estas tro mallongaj. + Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. - Kelkaj datumoj kodita en la adreso estas tro longaj. + Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. - + There are no recent broadcasts from this address to display. - Neniaj lastatempaj elsendoj de tiu adreso por montri. + Neniaj lastatempaj elsendoj de tiu ĉi adreso por montri. - + 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). + Vi estas uzanta TCP pordo %1 (Tio ĉi estas ŝanĝebla en la agordoj). @@ -1077,7 +1077,7 @@ Are you sure you want to delete the channel? Regenerate deterministic addresses - Regeneri determinisman adreson + Regeneri antaŭkalkuleblan adreson @@ -1100,59 +1100,59 @@ Are you sure you want to delete the channel? 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 la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% - Atendanta ĝis laborpruvo finos... %1% + Atendado ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% - Fermanta PyBitmessage... %1% + Fermado de PyBitmessage... %1% - + Waiting for objects to be sent... %1% - Atendanta ĝis objektoj estos senditaj... %1% + Atendado ĝis objektoj estos senditaj... %1% - + Saving settings... %1% - Konservanta agordojn... %1% + Konservado de agordoj... %1% - + Shutting down core... %1% - Fermanta kernon... %1% + Fermado de kerno... %1% - + Stopping notifications... %1% - Haltiganta sciigojn... %1% + Haltigado de sciigoj... %1% - + Shutdown imminent... %1% - Fermanta tuj... %1% + Fermado tuj... %1% @@ -1160,42 +1160,42 @@ Are you sure you want to delete the channel? %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% - Fermanta PyBitmessage... %1% + Fermado de PyBitmessage... %1% - + Sent Senditaj - + Generating one new address - Kreanta unu novan adreson + Kreado de unu nova adreso - + Done generating address. Doing work necessary to broadcast it... - Adreso kreita. Faranta laborpruvon endan por elsendi ĝin... + Adreso kreita. Kalkulado de laborpruvo, kiu endas por elsendi ĝin... - + Generating %1 new addresses. - Kreanta %1 novajn adresojn. + Kreado de %1 novaj adresoj. - + %1 is already in 'Your Identities'. Not adding it again. %1 jam estas en 'Viaj Identigoj'. Ĝi ne estos aldonita ree. - + Done generating address Ĉiuj adresoj estas kreitaj @@ -1205,233 +1205,233 @@ Are you sure you want to delete the channel? - + Disk full Disko plenplena - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... - Faranta laborpruvon endan por sendi elsendon... + Kalkulado de laborpruvo, kiu endas por sendi elsendon... - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. - Sendanta peton pri ĉifroŝlosilo de ricevonto. + Sendado de peto pri ĉifroŝlosilo de ricevonto. - + Looking up the receiver's public key - Serĉanta publikan ĉifroŝlosilon de ricevonto + 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 + 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. - Faranta laborpruvon endan por sendi mesaĝon. + 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 - Faranta laborpruvon endan por sendi mesaĝon. + 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. - Faranta laborpruvon endan por sendi mesaĝon. + Kalkulado de laborpruvo, kiu endas por sendi mesaĝon. - + Message sent. Waiting for acknowledgement. Sent on %1 - Mesaĝo sendita. Atendante konfirmon. Sendita je %1 + Mesaĝo sendita. Atendado je konfirmo. Sendita je %1 - + Doing work necessary to request encryption key. - Faranta laborpruvon endan por peti pri ĉifroŝlosilo. + Kalkulado de laborpruvo, kiu endas por peti pri ĉifroŝlosilo. - + Broadcasting the public key request. This program will auto-retry if they are offline. - Elsendanta peton pri publika ĉifroŝlosilo. La programo reprovos se ili estas eksterrete. + Elsendado de peto pri publika ĉifroŝlosilo. La programo reprovos se ili estas eksterrete. - + Sending public key request. Waiting for reply. Requested at %1 - Sendanta peton pri publika ĉifroŝlosilo. Atendanta respondon. Petis je %1 + Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 - + UPnP port mapping established on port %1 - UPnP pordo-mapigo farita je pordo %1 + UPnP pord-mapigo farita je pordo %1 - + UPnP port mapping removed - UPnP pordo-mapigo forigita + UPnP pord-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. - Faranta laborpruvon endan por sendi elsendon. + Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? - + Problem communicating with proxy: %1. Please check your network settings. Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. - + The time on your computer, %1, may be wrong. Please verify your settings. - La horloĝo de via komputilo, %1, eble malkorektas. Bonvolu kontroli viajn agordojn. + La horloĝo de via komputilo, %1, eble eraras. Bonvolu kontroli viajn agordojn. - + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. - Via(j) vidprocesoro(j) ne kalkulis korekte, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. + Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. - + 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. - + 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 liveradojn. Ĉu atendi ĝis la samtempigado finos?Bitmesaĝo ne estas samtempigita kun la reto, %n objektoj elŝutendas. Se vi eliros nun, tio povas igi malfruiĝojn de liveradojn. Ĉu atendi ĝis la samtempigado finos? + 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 liveradojn. Ĉu atendi ĝis ĝi konektos kaj la samtempigado finos? + 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... - Atendanta retkonekton... + Atendado je retkonekto... - + Waiting for finishing synchronisation... - Atendanta ĝis samtempigado finos... + Atendado ĝis samtempigado finiĝos...
@@ -1439,7 +1439,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Follow external link - Sekvi la ekstran ligilon + Sekvi la eksteran ligilon @@ -1483,13 +1483,13 @@ Eble vi devas ĝisdatigi Bitmesaĝon. 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 adresojn, kiom vi volas. Ververe kreado kaj forlasado de adresoj estas konsilinda. Vi povas krei adresojn uzante hazardajn nombrojn aŭ pasfrazon. Se vi uzos pasfrazon, la adreso estas nomita kiel 'determinisma' adreso. -La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adresoj havas kelkajn bonaĵojn kaj malbonaĵojn: + Tie ĉi vi povas generi tiom da adresoj, kiom vi volas. Ververe kreado kaj forlasado de adresoj 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 savkopion de keys.dat dosiero 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 nombro 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> + <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 keys.dat dosiero 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> @@ -1509,7 +1509,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Make deterministic addresses - Fari determinisman adreson + Fari antaŭkalkuleblan adreson @@ -1529,7 +1529,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Number of addresses to make based on your passphrase: - Kvanto de farotaj adresoj bazante sur via pasfrazo: + Nombro da farotaj adresoj bazante sur via pasfrazo: @@ -1559,12 +1559,12 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres (best if this is the first of many addresses you will create) - (plej bone se tiun estas la unuan de ĉiuj adresojn vi kreos) + (plej bone se tiun ĉi estas la unuan de ĉiuj adresojn vi kreos) Use the same stream as an existing address - Uzi saman fluon kiel jama adreso + Uzi saman fluon kiel ekzistan adreson @@ -1626,29 +1626,29 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres aboutDialog - + About Pri - + PyBitmessage PyBitmessage - + version ? versio ? - + <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 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> - + This is Beta software. - Tio estas beta-eldono. + Tio ĉi estas beta-eldono. @@ -1656,7 +1656,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres - + <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>Kopirajto &copy; 2012-2016 Jonathan WARREN<br/>Kopirajto &copy; 2013-2016 La programistoj de Bitmesaĝo</p></body></html> @@ -1666,12 +1666,12 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres 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) + Uzi nigran liston (permesas ĉiujn alvenajn mesaĝojn escepte tiujn en la nigra listo) 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) + Uzi blankan liston (blokas ĉiujn alvenajn mesaĝojn escepte tiujn en la blanka listo) @@ -1689,14 +1689,14 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Adreso - + Blacklist - Nigra Listo + Nigra listo - + Whitelist - Blanka Listo + Blanka listo @@ -1750,12 +1750,12 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres You have no connections with other peers. - Vi havas neniajn konektojn al aliaj samtavolanoj. + Vi havas neniujn konektojn al aliaj samtavolanoj. 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 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. + Vi konektis almenaŭ al unu samtavolano 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. @@ -1816,27 +1816,27 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Konektoj - + Since startup on %1 Ekde lanĉo de la programo je %1 - + Down: %1/s Total: %2 - Elŝuto: %1/s Entute: %2 + Elŝuto: %1/s Sume: %2 - + Up: %1/s Total: %2 - Alŝuto: %1/s Entute: %2 + Alŝuto: %1/s Sume: %2 - + Total Connections: %1 Ĉiuj konektoj: %1 - + Inventory lookups per second: %1 Petoj pri inventaro en sekundo: %1 @@ -1856,27 +1856,27 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres 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. @@ -1931,7 +1931,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres <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> + <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> @@ -1959,33 +1959,33 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres Successfully created / joined chan %1 - Sukcese kreis / aniĝis la kanalon %1 + Sukcese kreis / aniĝis al la kanalo %1 - + Chan creation / joining failed - Kreado / aniĝado de kanalo malsukcesis + Kreado / aniĝado al kanalo malsukcesis - + Chan creation / joining cancelled - Kreado / aniĝado de kanalo nuligita + 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. @@ -2040,224 +2040,224 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres 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 determinismajn adresojn sed perdis ilin akcidente (ekz. en diska paneo), vi povas regeneri ilin ĉi tie. Se vi uzis la generilo de hazardnombroj por krei vian adreson tiu formularo ne taŭgos por vi. + Se vi antaŭe kreis antaŭkalkuleblajn (determinismajn) adresojn sed perdis ilin akcidente (ekz. en diska paneo), vi povas regeneri ilin ĉi tie. Se vi uzis la generilo de hazardnombroj por krei vian adreson tiu formularo ne taŭgos por vi. settingsDialog - + Settings Agordoj - + Start Bitmessage on user login 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 - + Minimize to tray Plejetigi al taskopleto - + Close to tray Fermi al taskopleto - + Show notification when message received Montri sciigon kiam mesaĝo alvenas - + Run in Portable Mode 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. - + Willingly include unencrypted destination address when sending to a mobile device Volonte inkluzivi malĉifritan cel-adreson dum sendado al portebla aparato. - + Use Identicons Uzi ID-avatarojn - + Reply below Quote Respondi sub citaĵo - + Interface Language Fasada lingvo - + System Settings system Sistemaj agordoj - + User Interface Fasado - + Listening port Aŭskultanta pordo (port) - + Listen for connections on port: Aŭskulti pri konektoj ĉe pordo: - + UPnP: UPnP: - + Bandwidth limit Rettrafika limo - + Maximum download rate (kB/s): [0: unlimited] Maksimuma rapido de elŝuto (kB/s): [0: senlima] - + Maximum upload rate (kB/s): [0: unlimited] Maksimuma rapido de alŝuto (kB/s): [0: senlima] - + Proxy server / Tor Prokurila (proxy) servilo / Tor - + Type: Speco: - + 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 prokurilo - + 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 kiu 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 kiuj 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. + 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, kiuj 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 @@ -2267,82 +2267,87 @@ La 'hazardnombra' adreso estas antaŭagordita, sed determinismaj adres - + <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>Defaŭlte 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 eblas ŝanĝi kiam Bitmesaĝo devos rezigni je sendado.</p><p>Lasu tiujn kampojn malplenaj por antaŭagordita sinteno.</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] + Maksimume da eligaj konektoj: [0: none] + + + Hardware GPU acceleration (OpenCL): Aparatara GPU-a plirapidigo (OpenCL): -- 2.45.1 From 71ca2a761bfd9a88f2852f4f55ae66e11855cc27 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 12:36:43 +0100 Subject: [PATCH 0647/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 87399 -> 87571 bytes src/translations/bitmessage_pl.ts | 561 +++++++++++++++--------------- 2 files changed, 283 insertions(+), 278 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index f719f103ca0c5fba45da8977c3493f141274b6ca..467b9b08ea5badcf6a549f799dfd629a1458b82a 100644 GIT binary patch delta 471 zcmW-dT}YE*9L3N7dG|j1UiFx{4p-19d1qOPI~sh19%^E-D3&PG$`M|yQT-LADo z#L!|bF}Q0T`m-fad;{{K1{!({d-53QcxP>;-|m0o1qHin-_`E0z*znYD6DY$X$%OB zV7zF6`lfJJE?W%pReC`m_^=oj@d{VOb^60wv$HhG+RMn?+sb1TEo$*T)cD*I5R8nocID7%yLVQ zxWf13dNKeCb#t2>5C@KMT29kDekHp+(N0J2uOGm&%`p-i1x3bqQ!dadm+ilu-&`}< z2I!!h%Z@G)j_``(f!M#mqs{?gY~{Po33|($&JNM4BWX>Q6asjM$!DwWI3-00BQk00yZ800Br000&k@00BsU zk*z_I_H80GUI15VdH?}5$^clkJ^%nTQvh0XIsgGbz5rYXiU0vWj+2D}zX2|jMFLI& zKIxN{0)GKjlNAGB86yJP4q*TR06_xg1aklY-9G~ij0FGzKt+>{15N@!%9Gs#E&?;< zlMMuK0Y8&{1l9sJx06)`RsuQgldT0F5;p7xh<1Je09kAXoJ!>Y0Y<=+-32xZH2enL zRxSVmGlY{J21Wuno|9z;X8|gc%?2hCHh%~>@$LWsiUbH#K2-n#HM5fi2ZsR?lZ^-W z2}TNNWS#&4I%t!P2qpqFl9ROvrUEkKlU)f$0y%1vr3qglC=7JlI{*M6(+qi80RRA{ zoeYb`kN^Pr5Db(*8UO)6h?6A>KLI EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -83,7 +83,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -170,122 +170,122 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: 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. @@ -295,17 +295,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,47 +315,47 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -365,12 +365,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Wyślij - + Subscribe Subskrybuj - + Channel Kanał @@ -380,12 +380,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -394,17 +394,17 @@ It is important that you back up this file. 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.) @@ -413,37 +413,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,217 +594,217 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty - + 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1107,102 +1107,102 @@ Czy na pewno chcesz usunąć ten kanał? 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. Pokaż %1 ostatnich wiadomości przekazów 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 godzina%n godziny%n godzin%n godzin - + %n day(s) - %n dzień%n dni%n dni + %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 @@ -1212,231 +1212,231 @@ Czy na pewno chcesz usunąć ten kanał? - + 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 Przekaz wysłane o %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ów + 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 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. - + 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. - + 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. - + 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 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... @@ -1633,27 +1633,27 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ aboutDialog - + About O programie - + PyBitmessage PyBitmessage - + version ? wersja ? - + <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. @@ -1663,7 +1663,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - + <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>Prawa autorskie &copy; 2012-2016 Jonathan Warren<br/>Prawa autorskie &copy; 2013-2016 Programiści Bitmessage</p></body></html> @@ -1696,12 +1696,12 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Adres - + Blacklist Czarna lista - + Whitelist Biała lista @@ -1823,27 +1823,27 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Połączeń - + 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 @@ -1863,29 +1863,29 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Stan sieci - + byte(s) - bajtbajtówbajtów + bajtbajtówbajtówbajtów - + Object(s) to be synced: %n - Jeden obiekt do zsynchronizowaniaObieków do zsynchronizowania: %nObieków do zsynchronizowania: %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ść 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ść przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. + Przetworzono %n wiadomość przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. - + Processed %n public key(s). - Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. + Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. @@ -1969,12 +1969,12 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 @@ -1982,17 +1982,17 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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. @@ -2053,218 +2053,218 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 'Identiconó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ść @@ -2274,82 +2274,87 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - + <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 Nie wysyłaj ponownie 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: none] + + + Hardware GPU acceleration (OpenCL): Przyspieszenie sprzętowe GPU (OpenCL): -- 2.45.1 From e9899743eff2d6afaf1f97d3dcc83f76eb7ecef2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 15:09:36 +0100 Subject: [PATCH 0648/1102] Typos, formatting, obsolete imports --- src/bitmessageqt/safehtmlparser.py | 1 - src/class_receiveDataThread.py | 13 ++++++++----- src/queues.py | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 1ff12c8e..aa935785 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -3,7 +3,6 @@ import inspect import re from urllib import quote, quote_plus from urlparse import urlparse -from debug import logger class SafeHTMLParser(HTMLParser): # from html5lib.sanitiser diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index d3bcd689..64135bc7 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -658,7 +658,8 @@ class receiveDataThread(threading.Thread): 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)} + filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() + if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > 500: elemCount = 500 @@ -666,17 +667,19 @@ class receiveDataThread(threading.Thread): 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)} + filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() + if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > 250: elemCount = 250 - addrsInMyStreamLeft = random.sample(filtered.items(), elemCount) + 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)} + 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 > 250: elemCount = 250 - addrsInMyStreamRight = random.sample(filtered.items(), elemCount) + addrsInChildStreamRight = random.sample(filtered.items(), elemCount) numberOfAddressesInAddrMessage = 0 payload = '' for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream: diff --git a/src/queues.py b/src/queues.py index c7dab16f..335863e9 100644 --- a/src/queues.py +++ b/src/queues.py @@ -1,5 +1,4 @@ import Queue -from multiprocessing import Queue as mpQueue, Lock as mpLock from class_objectProcessorQueue import ObjectProcessorQueue workerQueue = Queue.Queue() -- 2.45.1 From d7076626c23c4c36b7f11b070fb374f2a4c7ee2a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 16:07:39 +0100 Subject: [PATCH 0649/1102] TTL label is in red and warning when too low - TTL to chans shouldn't be too low so the UI gives a feedback - warning when sending wouldn either require a lot of refactoring or wouldn't have good usability --- src/bitmessageqt/__init__.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 18bd70ed..1580cd8b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -834,11 +834,23 @@ class MyForm(settingsmixin.SMainWindow): 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)) + 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) 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) # Show or hide the application window after clicking an item within the # tray icon or, on Windows, the try icon itself. -- 2.45.1 From a6dbb1e37e70fffdf84b9932f1a7a9e8c5379dab Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Feb 2017 16:18:08 +0100 Subject: [PATCH 0650/1102] Less timestamp penalty for inbound connections - was over 2 days, but PyBM will only spread those with more recent than 3 hours. So it's now set to 2 hours --- src/class_receiveDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 64135bc7..3875957e 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -796,7 +796,7 @@ class receiveDataThread(threading.Thread): for stream in self.remoteStreams: knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) if not self.initiatedConnection: - knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 162000 # penalise inbound, 2 days minus 3 hours + knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 7200 # penalise inbound, 2 hours shared.needToWriteKnownNodesToDisk = True self.sendverack() -- 2.45.1 From 30952f91cfe236dfd9f8f59ab6d808521c4b4553 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 22 Feb 2017 17:11:30 +0100 Subject: [PATCH 0651/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 86021 -> 89972 bytes src/translations/bitmessage_ru.ts | 1016 +++++++++++++++++------------ 2 files changed, 611 insertions(+), 405 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 4c8b7a0f650857a705ebc17c60ccf4aa85180e55..d14f75ae2b0b208dfdfe7a3fec7f4a548b711453 100644 GIT binary patch delta 12236 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 delta 8710 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 diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 4484277a..15b2506a 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -1,5 +1,4 @@ - - + AddAddressDialog @@ -59,12 +58,12 @@ 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -84,7 +83,7 @@ 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: @@ -169,223 +168,223 @@ Please type the desired email address (including @mailchuck.com) below: 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. 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 Показать 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. Вы можете управлять Вашими ключами, отредактировав файл 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. @@ -394,19 +393,19 @@ 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.) @@ -416,122 +415,122 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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-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-у. + 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 @@ -542,272 +541,272 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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 - Ошибка: 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. - Ошибка: некоторые данные в адресе %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. Вы должны указать адрес в поле "От кого". Вы можете найти Ваш адрес во вкладе "Ваши Адреса". - + 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 проделает необходимые вычисления, чтобы отправить сообщение, но не отправит его до тех пор, пока Вы не подсоединитесь к сети. + Внимание: Вы не подключены к сети. 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 Отправка запроса на регистрацию на Email-шлюзе - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -816,7 +815,7 @@ 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? @@ -825,279 +824,279 @@ 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. Это адрес 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). Вы используете TCP порт %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 - Chan-ы + Чаны - + Add Chan - Добавить 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 - Подсоединиться или создать chan + Подключить или создать чан @@ -1105,236 +1104,386 @@ Are you sure you want to delete the channel? Все аккаунты - + 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 + Доступна новая версия 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 час(а/ов) - %n час(а/ов) - + %n час%n часа%n часов%n час(а/ов) - + %n day(s) - - %n день - %n дней - %n дней - + %n день%n дня%n дней%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 - Проблема аутентификации SOCKS5: %1 + - + Disk full Диск переполнен - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. - + Error! Could not find sender address (your address) in the keys.dat file. Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. - Выполнение задач, необходимых для отправки сообщения. + Выполнение работы, требуемой для отправки сообщения. Для адреса версии 2 (как этот), не требуется указание сложности. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - Проблема: вы пытаетесь отправить сообщение самому себе или в chan, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 + Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. - Выполнение задач, необходимых для отправки сообщения. + Выполнение работы, требуемой для отправки сообщения. - + Message sent. Waiting for acknowledgement. Sent on %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено на %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 Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %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 объекта в ожидании подтверждения работы%n объектов в ожидании подтверждения работы%n объектов в ожидании подтверждения работы + + + + %n object(s) waiting to be distributed + %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%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, возможно неправильное. Пожалуйста, проверьте ваши настройки. + + + + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. + Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. + + + + not recommended for chans + не рекомендовано для чанов + + + + 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. + + + + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? + + + + 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... + Ожидание окончания синхронизации... + + + + 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 + Нажмите здесь для отключения + + + + MsgDecode + + + The message has an unknown encoding. +Perhaps you should upgrade Bitmessage. + Сообщение в неизвестной кодировке. +Возможно, вам следует обновить Bitmessage. + + + + Unknown encoding + Неизвестная кодировка @@ -1487,46 +1636,42 @@ 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> <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>Все права защищены © 2012-2016 Jonathan Warren<br/>Все права защищены © 2013-2016 Разработчики Bitmessage</p></body></html> + + <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>Авторское право: &copy; 2012-2016 Джонатан Уоррен<br/>Авторское право: &copy; 2013-2016 Разработчики Bitmessage</p></body></html> @@ -1557,12 +1702,12 @@ The 'Random Number' option is selected by default but deterministic ad Адрес - + Blacklist Чёрный список - + Whitelist Белый список @@ -1684,27 +1829,27 @@ The 'Random Number' option is selected by default but deterministic ad Соединений - + 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 @@ -1719,54 +1864,34 @@ The 'Random Number' option is selected by default but deterministic ad Загрузка: 0 кБ/с - + Network Status - Статус сети + Состояние сети - + byte(s) - - байт - байт - байт - + байтбайтбайтбайт - + Object(s) to be synced: %n - - Несинхронизированные объекты: %n - Несинхронизированные объекты: %n - Несинхронизированные объекты: %n - + Несинхронизированные объекты: %nНесинхронизированные объекты: %nНесинхронизированные объекты: %nНесинхронизированные объекты: %n - + Processed %n person-to-person message(s). - - Обработано %n сообщение. - Обработано %n сообщений. - Обработано %n сообщений. - + Обработано %n сообщение.Обработано %n сообщений.Обработано %n сообщений.Обработано %n сообщений. - + Processed %n broadcast message(s). - - Обработана %n рассылка. - Обработано %n рассылок. - Обработано %n рассылок. - + Обработана %n рассылка.Обработано %n рассылок.Обработано %n рассылок.Обработано %n рассылок. - + Processed %n public key(s). - - Обработан %n открытый ключ. - Обработано %n открытых ключей. - Обработано %n открытых ключей. - + Обработан %n открытый ключ.Обработано %n открытых ключей.Обработано %n открытых ключей.Обработано %n открытых ключей. @@ -1774,42 +1899,108 @@ The 'Random Number' option is selected by default but deterministic ad 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> - <html><head/><body><p>Введите имя Вашего chan-a. Если Вы выберете достаточно сложное имя для 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 - это способ общения, когда набор ключей шифрования известен сразу целой группе людей. Ключи и 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 passhphrase/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 недоступен. Пожалуйста, соберите его. @@ -1868,295 +2059,310 @@ 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 Включить иконки адресов - + 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] Максимальная скорость загрузки (кБ/с): [0: не ограничено] - + Maximum upload rate (kB/s): [0: unlimited] Максимальная скорость отдачи (кБ/с): [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. Однако, есть одно исключение: если Вы специально добавите Вашего собеседника в адресную книгу, то 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) - Ускорение на графическом процессоре (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> <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 -- 2.45.1 From 93c881172ebe26c0c4c4ef222985d424f20ff814 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 23 Feb 2017 15:11:17 +0100 Subject: [PATCH 0652/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 63662 -> 63754 bytes src/translations/bitmessage_ja.ts | 267 +++++++++++++++--------------- 2 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 9e051b5684045496429532f7030c316955770e81..e8ed22368b613cafa942454d570ae80f66335d0b 100644 GIT binary patch delta 1796 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 Y+LOlr;3;#Mr=A>?(sNGM?~YFRA5K|A2LJ#7 diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 5c41b62c..1961c66b 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -83,7 +83,7 @@ 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: @@ -283,7 +283,7 @@ Please type the desired email address (including @mailchuck.com) below: %1は古いバージョン1のアドレスです。バージョン1のアドレスはサポートが終了しています。すぐに削除しますか? - + Waiting for their encryption key. Will request it again soon. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1161,17 +1161,17 @@ Are you sure you want to delete the channel? %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1275,7 +1275,7 @@ Receiver's required difficulty: %1 and %2 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 @@ -1285,7 +1285,7 @@ Receiver's required difficulty: %1 and %2 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 @@ -1315,32 +1315,32 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? - + Doing work necessary to send broadcast. 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1365,72 +1365,77 @@ Receiver's required difficulty: %1 and %2 GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + + not recommended for chans + チャンネルにはお勧めしません + + + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... -- 2.45.1 From 317d4d57cc6eb60c7c4ae977ddf3bb8bc3a375d8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 24 Feb 2017 16:49:53 +0100 Subject: [PATCH 0653/1102] Add setup.py (setuptools) - thanks to Lvl4Sword for the initial file --- setup.py | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..47516634 --- /dev/null +++ b/setup.py @@ -0,0 +1,161 @@ +import os +try: + from setuptools import setup, find_packages, Extension + haveSetuptools = True +except ImportError: + haveSetuptools = False +import sys + +from src.version import softwareVersion + +packageManager = { + "OpenBSD": "pkg_add", + "FreeBSD": "pkg_install", + "Debian": "apt-get install", + "Ubuntu": "apt-get install", + "openSUSE": "zypper install", + "Fedora": "dnf install", + "Guix": "guix package -i", +} + +packageName = { + "PyQt": { + "OpenBSD": "py-qt4", + "FreeBSD": "py27-qt4", + "Debian": "python-qt4", + "Ubuntu": "python-qt4", + "openSUSE": "python-qt", + "Fedora": "PyQt4", + "Guix": "python2-pyqt@4.11.4", + }, + "msgpack": { + "OpenBSD": "py-msgpack", + "FreeBSD": "py27-msgpack-python", + "Debian": "python-msgpack", + "Ubuntu": "python-msgpack", + "openSUSE": "python-msgpack-python", + "Fedora": "python2-msgpack", + "Guix": "python2-msgpack", + } +} + +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"): + with open("/etc/os-release", 'rt') as osRelease: + for line in osRelease: + if line.startswith("NAME="): + if "fedora" in line.lower(): + detectOS.result = "Fedora" + elif "opensuse" in line.lower(): + detectOS.result = "openSUSE" + elif "ubuntu" in line.lower(): + detectOS.result = "Ubuntu" + elif "debian" in line.lower(): + detectOS.result = "Debian" + else: + detectOS.result = None + return detectOS.result + +def detectPrereqs(missing=False): + available = [] + try: + import PyQt4.QtCore + if not missing: + available.append("PyQt") + except ImportError: + if missing: + available.append("PyQt") + try: + import msgpack + if not missing: + available.append("msgpack") + except ImportError: + if missing: + available.append("msgpack") + return available + +def prereqToPackages(): + print "You can install the requirements by running, as root:" + print "%s %s" % (packageManager[detectOS()], " ".join(packageName[x][detectOS()] for x in detectPrereqs(True))) + +if __name__ == "__main__": + detectOS.result = None + detectPrereqs.result = None + if "PyQt" in detectPrereqs(True): + print "You only need PyQt if you want to use the GUI. When only running as a daemon, this can be skipped." + print "However, you would have to install it manually because setuptools does not support pyqt." + if detectPrereqs(True) != [] and detectOS() in packageManager: + if detectOS() is not None: + print "It looks like you're using %s. It is highly recommended to use the package manager instead of setuptools." % (detectOS()) + prereqToPackages() + sys.exit() + if not haveSetuptools: + print "It looks like you're missing setuptools." + sys.exit() + + here = os.path.abspath(os.path.dirname(__file__)) + with open(os.path.join(here, 'README.md')) as f: + README = f.read() + with open(os.path.join(here, 'CHANGES.txt')) as f: + CHANGES = f.read() + + bitmsghash = Extension('bitmsghash.bitmsghash', + sources = ['src/bitmsghash/bitmsghash.cpp'], + libraries = ['pthread', 'crypto'], + ) + + dist = setup( + name='pybitmessage', + version=softwareVersion, + description='', + long_description=README, + license='MIT', + # TODO: add author info + #author='', + #author_email='', + url='https://github.com/Bitmessage/PyBitmessage/', + # TODO: add keywords + #keywords='', + install_requires = ['msgpack-python'], + classifiers = [ + "License :: OSI Approved :: MIT License" + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 2.7.3", + "Programming Language :: Python :: 2.7.4", + "Programming Language :: Python :: 2.7.5", + "Programming Language :: Python :: 2.7.6", + "Programming Language :: Python :: 2.7.7", + "Programming Language :: Python :: 2.7.8", + "Programming Language :: Python :: 2.7.9", + "Programming Language :: Python :: 2.7.10", + "Programming Language :: Python :: 2.7.11", + "Programming Language :: Python :: 2.7.12", + "Programming Language :: Python :: 2.7.13", + ], + package_dir={'':'src'}, + packages=['','bitmessageqt', 'bitmessagecurses', 'messagetypes', 'network', 'pyelliptic', 'socks'], + package_data={'': ['bitmessageqt/*.ui', 'bitmsghash/*.cl', 'keys/*.pem', 'translations/*.ts', 'translations/*.qm', 'images/*.png', 'images/*.ico', 'images/*.icns']}, + ext_modules = [bitmsghash], + zip_safe=False, + entry_points="""\ + [console_scripts] + bitmessage = bitmessagemain:Main.start + """, + ) + with open(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 'wt') as f: + f.write("#!/bin/sh\n") + f.write(dist.command_obj['build'].executable + " " + \ + os.path.join(dist.command_obj['install'].install_lib, + os.path.basename(dist.command_obj['bdist_egg'].egg_output), + 'bitmessagemain.py') + "\n") + os.chmod(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 0555) -- 2.45.1 From b50198afb5dbbed84e06d72155bed4a080913c83 Mon Sep 17 00:00:00 2001 From: Justin Ramos Date: Sat, 25 Feb 2017 04:43:09 +0000 Subject: [PATCH 0654/1102] changes needed to get current code to run --- .gitignore | 2 ++ setup.py | 17 ++++++++--------- src/__init__.py | 0 src/network/__init__.py | 0 4 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 src/__init__.py create mode 100644 src/network/__init__.py diff --git a/.gitignore b/.gitignore index f3eb161c..7da86d2f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ src/.settings/ src/**/.dll src/**/*.o src/**/*.so +build/lib.* +build/temp.* diff --git a/setup.py b/setup.py index 47516634..cb1658b8 100644 --- a/setup.py +++ b/setup.py @@ -104,8 +104,6 @@ if __name__ == "__main__": here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as f: README = f.read() - with open(os.path.join(here, 'CHANGES.txt')) as f: - CHANGES = f.read() bitmsghash = Extension('bitmsghash.bitmsghash', sources = ['src/bitmsghash/bitmsghash.cpp'], @@ -152,10 +150,11 @@ if __name__ == "__main__": bitmessage = bitmessagemain:Main.start """, ) - with open(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 'wt') as f: - f.write("#!/bin/sh\n") - f.write(dist.command_obj['build'].executable + " " + \ - os.path.join(dist.command_obj['install'].install_lib, - os.path.basename(dist.command_obj['bdist_egg'].egg_output), - 'bitmessagemain.py') + "\n") - os.chmod(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 0555) + if (dist.command_obj.get('install_scripts')): + with open(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 'wt') as f: + f.write("#!/bin/sh\n") + f.write(dist.command_obj['build'].executable + " " + \ + os.path.join(dist.command_obj['install'].install_lib, + os.path.basename(dist.command_obj['bdist_egg'].egg_output), + 'bitmessagemain.py') + "\n") + os.chmod(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 0555) diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/network/__init__.py b/src/network/__init__.py new file mode 100644 index 00000000..e69de29b -- 2.45.1 From 7ef91bd607bf06eff9f67a7266f84b5fe5c0d315 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 25 Feb 2017 22:33:31 +0100 Subject: [PATCH 0655/1102] Changed Makefile to use CXX instead of g++ - is more standardised - closes #882 --- src/bitmsghash/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile index 56a6a3a9..c4fb4ab5 100644 --- a/src/bitmsghash/Makefile +++ b/src/bitmsghash/Makefile @@ -15,10 +15,10 @@ powtest: ./testpow.py bitmsghash.so: bitmsghash.o - g++ bitmsghash.o -shared -fPIC -lcrypto $(LDFLAGS) + ${CXX} bitmsghash.o -shared -fPIC -lcrypto $(LDFLAGS) bitmsghash.o: - g++ -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp + ${CXX} -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp clean: rm -f bitmsghash.o bitmsghash.so bitmsghash*.dll -- 2.45.1 From 74c85b4a9e5a61450c23aeabca9b410b7b80ed8b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 25 Feb 2017 23:40:37 +0100 Subject: [PATCH 0656/1102] Retransmit timing changes - makes it behave more like in the description - partial for #847 --- src/class_singleWorker.py | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 863fbde9..0190e1c5 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -609,11 +609,9 @@ class singleWorker(threading.Thread, StoppableThread): # At this point we know that we have the necessary pubkey in the pubkeys table. - if retryNumber == 0: - if TTL > 28 * 24 * 60 * 60: - TTL = 28 * 24 * 60 * 60 - else: - TTL = 28 * 24 * 60 * 60 + TTL *= 2**retryNumber + if TTL > 28 * 24 * 60 * 60: + TTL = 28 * 24 * 60 * 60 TTL = int(TTL + random.randrange(-300, 300))# add some randomness to the TTL embeddedTime = int(time.time() + TTL) @@ -834,10 +832,8 @@ class singleWorker(threading.Thread, StoppableThread): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' - if retryNumber == 0: - sleepTill = int(time.time()) + TTL - else: - sleepTill = int(time.time()) + 28*24*60*60 * 2**retryNumber + # wait 10% past expiration + sleepTill = int(time.time() + TTL * 1.1) sqlExecute('''UPDATE sent SET msgid=?, status=?, retrynumber=?, sleeptill=?, lastactiontime=? WHERE ackdata=?''', inventoryHash, newStatus, @@ -896,9 +892,9 @@ class singleWorker(threading.Thread, StoppableThread): 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 retryNumber == 0: - TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. - else: + TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. + TTL *= 2**retryNumber + if TTL > 28*24*60*60: TTL = 28*24*60*60 TTL = TTL + random.randrange(-300, 300) # add some randomness to the TTL embeddedTime = int(time.time() + TTL) @@ -934,10 +930,8 @@ class singleWorker(threading.Thread, StoppableThread): protocol.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) - if retryNumber == 0: - sleeptill = int(time.time()) + TTL - else: - sleeptill = int(time.time()) + 28*24*60*60 * 2**retryNumber + # wait 10% past expiration + sleeptill = int(time.time() + TTL * 1.1) sqlExecute( '''UPDATE sent SET lastactiontime=?, status='awaitingpubkey', retrynumber=?, sleeptill=? WHERE toaddress=? AND (status='doingpubkeypow' OR status='awaitingpubkey') ''', int(time.time()), -- 2.45.1 From b1b0c46555f52ce343d0b83cdd9e792164d714c6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 12:42:18 +0100 Subject: [PATCH 0657/1102] Improve exception handling - there were reports of errors in FreeBSD (I could only reproduce some) and Gentoo without IPv4 support (I don't have a VM for testing ready) - adds an exception handler for double task_done in case sender thread has to close prematurely (I saw this triggered on FreeBSD 11) - listening socket opening error handler was broken (triggered if you can't open a socket with both IPv4 and IPv6 support) - error handler for socket.accept. Reported on FreeBSD 10.3 - fixes #854 --- src/class_sendDataThread.py | 6 +++++- src/class_singleListener.py | 12 ++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 3d35c48a..552cbffc 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -201,7 +201,11 @@ class sendDataThread(threading.Thread): 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() - self.sendDataThreadQueue.task_done() + # Flush if the cycle ended with break + try: + self.sendDataThreadQueue.task_done() + except ValueError + pass try: self.sock.shutdown(socket.SHUT_RDWR) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 0a8c4a93..f41a9724 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -86,7 +86,7 @@ class singleListener(threading.Thread, StoppableThread): # we'll fall back to IPv4-only. try: sock = self._createListenSocket(socket.AF_INET6) - except socket.error, e: + except socket.error as e: if (isinstance(e.args, tuple) and e.args[0] in (errno.EAFNOSUPPORT, errno.EPFNOSUPPORT, @@ -112,7 +112,15 @@ class singleListener(threading.Thread, StoppableThread): self.stop.wait(10) while state.shutdown == 0: - socketObject, sockaddr = sock.accept() + 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 + (HOST, PORT) = sockaddr[0:2] # If the address is an IPv4-mapped IPv6 address then -- 2.45.1 From 191650f5a4fa8a4e55ec0ad407104725d92ac86d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 12:52:28 +0100 Subject: [PATCH 0658/1102] Typos - previous commit contained typos --- src/class_sendDataThread.py | 2 +- src/class_singleListener.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 552cbffc..05dc5c34 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -204,7 +204,7 @@ class sendDataThread(threading.Thread): # Flush if the cycle ended with break try: self.sendDataThreadQueue.task_done() - except ValueError + except ValueError: pass try: diff --git a/src/class_singleListener.py b/src/class_singleListener.py index f41a9724..f6bc9156 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -115,7 +115,7 @@ class singleListener(threading.Thread, StoppableThread): try: socketObject, sockaddr = sock.accept() except socket.error as e: - if isinstance(e.args, tuple) and + if isinstance(e.args, tuple) and \ e.args[0] in (errno.EINTR,): continue time.wait(1) -- 2.45.1 From 0fa0599cd4b4c43f601fb897f27b780332b201b1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 12:55:43 +0100 Subject: [PATCH 0659/1102] IPv4 listen socket fix - on OpenBSD, you can't have a socket that supports both IPv4 and IPv6. This allows handling for this error, and then it will try IPv4 only, just like for other similar errors. --- src/class_singleListener.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index f6bc9156..fb736698 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -91,7 +91,8 @@ class singleListener(threading.Thread, StoppableThread): e.args[0] in (errno.EAFNOSUPPORT, errno.EPFNOSUPPORT, errno.EADDRNOTAVAIL, - errno.ENOPROTOOPT)): + errno.ENOPROTOOPT, + errno.EINVAL)): sock = self._createListenSocket(socket.AF_INET) else: raise -- 2.45.1 From 7ebe837eb0bf7b1f6658c07a494117f8c8b09af2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 17:46:02 +0100 Subject: [PATCH 0660/1102] Make some network parameters configurable - maxtotalconnections = maximum number of total full connections (incoming + outgoing) the node will allow. Default 200 as it was. - maxbootstrapconnections = number of additional (to total) connection that will act in bootstrap mode, closing after sending the list of addresses. Default 20 as it was. - maxaddrperstreamsend = initial address list maximum size, per participating stream. Default 500. Child streams get half. The response is chunked into pieces of max. 1000 addresses as that's the protocol limit. --- src/bmconfigparser.py | 6 ++-- src/class_receiveDataThread.py | 50 ++++++++++++++++++++++++++-------- src/class_singleListener.py | 5 +++- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index bc16b05a..412d2fa5 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -31,13 +31,13 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return False return False - def safeGetInt(self, section, field): + def safeGetInt(self, section, field, default=0): if self.has_option(section, field): try: return self.getint(section, field) except ValueError: - return 0 - return 0 + return default + return default def safeGet(self, section, option, default = None): if self.has_option(section, option): diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 3875957e..83941612 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -386,7 +386,8 @@ class receiveDataThread(threading.Thread): stream, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. - if not self.initiatedConnection and len(shared.connectedHostsList) > 200: + if not self.initiatedConnection and len(shared.connectedHostsList) > \ + BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200): logger.info ('We are connected to too many people. Closing connection.') self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) self.sendDataThreadQueue.put((0, 'shutdown','no data')) @@ -648,9 +649,25 @@ 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))) + # 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 + numberOfAddressesInAddrMessage = 0 + payload = '' + for stream in self.streamNumber: addrsInMyStream = {} addrsInChildStreamLeft = {} @@ -661,8 +678,8 @@ class receiveDataThread(threading.Thread): filtered = {k: v for k, v in knownnodes.knownNodes[stream].items() if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) - if elemCount > 500: - elemCount = 500 + 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 @@ -670,18 +687,16 @@ class receiveDataThread(threading.Thread): filtered = {k: v for k, v in knownnodes.knownNodes[stream*2].items() if v > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) - if elemCount > 250: - elemCount = 250 + 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 > 250: - elemCount = 250 + if elemCount > maxAddrCount / 2: + elemCount = int(maxAddrCount / 2) addrsInChildStreamRight = random.sample(filtered.items(), elemCount) - numberOfAddressesInAddrMessage = 0 - payload = '' for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream: numberOfAddressesInAddrMessage += 1 payload += pack( @@ -691,6 +706,10 @@ class receiveDataThread(threading.Thread): '>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( @@ -700,6 +719,10 @@ class receiveDataThread(threading.Thread): '>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( @@ -709,10 +732,13 @@ class receiveDataThread(threading.Thread): '>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 - payload = encodeVarint(numberOfAddressesInAddrMessage) + payload - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.CreatePacket('addr', payload))) - + # flush + sendChunk() # We have received a version message def recversion(self, data): diff --git a/src/class_singleListener.py b/src/class_singleListener.py index fb736698..322f4b67 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -107,7 +107,10 @@ class singleListener(threading.Thread, StoppableThread): # 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) > 220 and state.shutdown == 0: + 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.') self.stop.wait(10) -- 2.45.1 From 88658b074edbd412048ddedaaab6333ffddae00b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 20:03:14 +0100 Subject: [PATCH 0661/1102] Socks proxy hostname resolving error handling - if resolving fails, it wasn't handled --- src/protocol.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/protocol.py b/src/protocol.py index 82edbd15..9d66ec2f 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -87,8 +87,12 @@ 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, -- 2.45.1 From cff1af1b4fd2d828562b6391b74257b55a8bc2d2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 20:03:47 +0100 Subject: [PATCH 0662/1102] Subscription wrong tab - when subscribing from addressbook, it switched to blacklist tab instead of subscriptions --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1580cd8b..b067d9d3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3309,7 +3309,7 @@ class MyForm(settingsmixin.SMainWindow): continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) - self.ui.tabWidget.setCurrentIndex(4) + self.ui.tabWidget.setCurrentIndex(2) def on_context_menuAddressBook(self, point): self.popMenuAddressBook = QtGui.QMenu(self) -- 2.45.1 From d8301ff51261e6a37ec6ac103fb1d508d117091e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 20:29:07 +0100 Subject: [PATCH 0663/1102] Less verbose connection error reporting - don't print tracebacks on normal (timeout/reset) errors --- src/class_sendDataThread.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 05dc5c34..a59a628e 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -96,7 +96,8 @@ class sendDataThread(threading.Thread): select.select([], [self.sslSock], [], 10) logger.debug('sock.recv retriable SSL error') continue - raise + 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 \ @@ -104,8 +105,8 @@ class sendDataThread(threading.Thread): select.select([], [self.sslSock if isSSL else self.sock], [], 10) logger.debug('sock.recv retriable error') continue - if e.errno == errno.EPIPE: - logger.debug('Connection broken') + if e.errno in (errno.EPIPE, errno.ECONNRESET): + logger.debug('Connection error (EPIPE/ECONNRESET)') return False raise throttle.SendThrottle().wait(amountSent) -- 2.45.1 From 511b89ebbea1e5e85879dcf2d0d890a473756ad2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 20:44:56 +0100 Subject: [PATCH 0664/1102] PoW Worker should wait for sql thread to init - I think this was causing freezing queue on launch if not empty - I can't reproduce the bug anymore --- src/class_singleWorker.py | 5 +++++ src/class_sqlThread.py | 2 ++ src/state.py | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 0190e1c5..87034f7c 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -51,6 +51,11 @@ class singleWorker(threading.Thread, StoppableThread): super(singleWorker, self).stopThread() 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( diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index b46a570f..9bd7e8e7 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -494,6 +494,8 @@ class sqlThread(threading.Thread): parameters = (int(time.time()),) self.cur.execute(item, parameters) + state.sqlReady = True + while True: item = helper_sql.sqlSubmitQueue.get() if item == 'commit': diff --git a/src/state.py b/src/state.py index 3d5209c4..c7b79e07 100644 --- a/src/state.py +++ b/src/state.py @@ -19,6 +19,8 @@ shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof o curses = False +sqlReady = False # set to true by sqlTread when ready for processing + # 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 -- 2.45.1 From 484d4abb3c651e869c98b0fce7531acb7cdf3f4f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 26 Feb 2017 20:50:06 +0100 Subject: [PATCH 0665/1102] Frozen mode message type static - I can't get the dynamic loading to work on OSX in frozen mode - I think that if someone wants to build a frozen executable with custom messagetypes modules, he can edit the file - so now it lists the existing types manually (for frozen mode only) --- src/messagetypes/__init__.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index e455c61b..c3911dfd 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -28,23 +28,19 @@ def constructObject(data): else: return returnObj -mods = [] if paths.frozen is not None: - with open(path.join(path.dirname(path.dirname(__file__)), 'messagetypes.txt'), 'rt') as f: - for m in f.readlines(): - mods.append(m.rstrip()) + import messagetypes.message + import messagetypes.vote else: - mods = listdir(path.dirname(__file__)) - -for mod in mods: - 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) + 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) -- 2.45.1 From 8579d8b3b5a02929d4d53859d0ca9c6c460764d1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 13:02:37 +0100 Subject: [PATCH 0666/1102] PyInstaller spec file updates - file name based on architecture, version and date - workaround for __init__ in src - change to unix line endings --- packages/pyinstaller/bitmessagemain.spec | 165 +++++++++++------------ 1 file changed, 79 insertions(+), 86 deletions(-) diff --git a/packages/pyinstaller/bitmessagemain.spec b/packages/pyinstaller/bitmessagemain.spec index 1f568f33..06cf6e76 100644 --- a/packages/pyinstaller/bitmessagemain.spec +++ b/packages/pyinstaller/bitmessagemain.spec @@ -1,86 +1,79 @@ -import ctypes -import os - -srcPath = "C:\\src\\PyBitmessage\\src\\" -qtPath = "C:\\Qt-4.8.7\\" -openSSLPath = "C:\\OpenSSL-1.0.2j\\" -outPath = "C:\\src\\PyInstaller-3.2.1\\bitmessagemain" - -hiddenimports= [] - -# manually add messagetypes directory and its listing -with open(os.path.join(srcPath, 'messagetypes.txt'), 'wt') as f: - for mt in os.listdir(os.path.join(srcPath, 'messagetypes')): - if mt == "__init__.py": - continue - splitted = os.path.splitext(mt) - if splitted[1] != ".py": - continue - f.write(mt + "\n") - hiddenimports.append('messagetypes.' + splitted[0]) - -# -*- mode: python -*- -a = Analysis([srcPath + 'bitmessagemain.py'], - pathex=[outPath], - hiddenimports=hiddenimports, - hookspath=None, - runtime_hooks=None) - -a.datas.append(('messagetypes.txt', os.path.join(srcPath, 'messagetypes.txt'), 'DATA')) - -# fix duplicates -for d in a.datas: - if 'pyconfig' in d[0]: - a.datas.remove(d) - break - -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') - ] - -pyz = PYZ(a.pure) -exe = EXE(pyz, - a.scripts, - a.binaries, - a.zipfiles, - a.datas, - a.binaries, - name='Bitmessage.exe', - debug=False, - strip=None, - upx=False, - console=False, icon= os.path.join(srcPath, 'images', 'can-icon.ico')) +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')) -- 2.45.1 From 124b321b8c83d67fee5116529ba1544f86e04cce Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 15:27:46 +0100 Subject: [PATCH 0667/1102] Less verbose error handling - if socket sending results in EHOSTUNREACH or ETIMEDOUT, don't show backtrace --- src/class_sendDataThread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index a59a628e..5ddb3c11 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -105,8 +105,8 @@ class sendDataThread(threading.Thread): 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): - logger.debug('Connection error (EPIPE/ECONNRESET)') + if e.errno in (errno.EPIPE, errno.ECONNRESET, errno.EHOSTUNREACH, errno.ETIMEDOUT): + logger.debug('Connection error (EPIPE/ECONNRESET/EHOSTUNREACH/ETIMEDOUT)') return False raise throttle.SendThrottle().wait(amountSent) -- 2.45.1 From cd0972c0f3f884cbcacbc84bf1af61bf361b3c9c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 15:30:19 +0100 Subject: [PATCH 0668/1102] Recommend enabling UPnP on network problems - it looks like there aren't enough listening nodes - if connection is dropped, notify non-proxy users about the UPnP option --- src/bitmessageqt/__init__.py | 5 +++++ src/bitmessageqt/networkstatus.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b067d9d3..68eb0da0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1667,6 +1667,11 @@ class MyForm(settingsmixin.SMainWindow): self.notifierShow('Bitmessage', unicode(_translate( "MainWindow", "Connection lost").toUtf8(),'utf-8'), self.SOUND_DISCONNECTED, None) + if self.connected and \ + not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ + BMConfigParser().get('bitmessagesettings', 'socksproxytype') != "none": + self.statusBar().showMessage(_translate( + "MainWindow", "Problems connecting? Try enabling UPnP in the Network Settings"), 10000) self.connected = False if self.actionStatus is not None: diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 7506b652..074420b7 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -116,7 +116,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): "networkstatus", "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.window().setStatusIcon('yellow') - elif len(shared.connectedHostsList) == 0: + elif len(shared.connectedHostsList) == 0 and shared.statusIconColor != 'red': self.window().setStatusIcon('red') # timer driven -- 2.45.1 From e15d9e3e03faf3a565e90cf9c793394f43d8ffff Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 15:55:59 +0100 Subject: [PATCH 0669/1102] Save UPnP externa port after creating mapping --- src/upnp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/upnp.py b/src/upnp.py index 29f1c937..ae93de6a 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -284,6 +284,7 @@ class uPnPThread(threading.Thread, StoppableThread): shared.extPort = extPort self.extPort = extPort BMConfigParser().set('bitmessagesettings', 'extport', str(extPort)) + BMConfigParser().save() break except UPnPError: logger.debug("UPnP error: ", exc_info=True) -- 2.45.1 From ff786725edb8ed8c8fd11d14f6158e2cc5c7b7fe Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 16:12:19 +0100 Subject: [PATCH 0670/1102] Typo - UPnP / connectivity recommendation was active when on proxy rather than without --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 68eb0da0..17f391aa 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1669,7 +1669,7 @@ class MyForm(settingsmixin.SMainWindow): self.SOUND_DISCONNECTED, None) if self.connected and \ not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ - BMConfigParser().get('bitmessagesettings', 'socksproxytype') != "none": + BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": self.statusBar().showMessage(_translate( "MainWindow", "Problems connecting? Try enabling UPnP in the Network Settings"), 10000) self.connected = False -- 2.45.1 From 741ac5ca053d98f28460f56a3e73bf54a8b60255 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 16:18:22 +0100 Subject: [PATCH 0671/1102] UPnP recommendation notification fixes - notify also if no connections and no change --- src/bitmessageqt/__init__.py | 3 +-- src/bitmessageqt/networkstatus.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 17f391aa..48cff7e5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1667,8 +1667,7 @@ class MyForm(settingsmixin.SMainWindow): self.notifierShow('Bitmessage', unicode(_translate( "MainWindow", "Connection lost").toUtf8(),'utf-8'), self.SOUND_DISCONNECTED, None) - if self.connected and \ - not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ + if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": self.statusBar().showMessage(_translate( "MainWindow", "Problems connecting? Try enabling UPnP in the Network Settings"), 10000) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 074420b7..7506b652 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -116,7 +116,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): "networkstatus", "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.window().setStatusIcon('yellow') - elif len(shared.connectedHostsList) == 0 and shared.statusIconColor != 'red': + elif len(shared.connectedHostsList) == 0: self.window().setStatusIcon('red') # timer driven -- 2.45.1 From 5d068ec84a22cd4ffa8a613dbb3be004ddd827a1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 23:30:31 +0100 Subject: [PATCH 0672/1102] Unnecessary locking - there was a sleep inside a lock --- src/class_outgoingSynSender.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 254caabb..a2f12c4d 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -40,13 +40,13 @@ class outgoingSynSender(threading.Thread, StoppableThread): knownnodes.knownNodes[self.streamNumber][peer] = time.time() else: while not self._stopped: - with knownnodes.knownNodesLock: - try: + try: + with knownnodes.knownNodesLock: peer, = random.sample(knownnodes.knownNodes[self.streamNumber], 1) - except ValueError: # no known nodes - self.stop.wait(1) - continue - priority = (183600 - (time.time() - knownnodes.knownNodes[self.streamNumber][peer])) / 183600 # 2 days and 3 hours + 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 -- 2.45.1 From 339e375958e626fbcbb396e14ef569851b74ba0c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 23:31:12 +0100 Subject: [PATCH 0673/1102] Bootstrap provider mode and minor knownNodes changes - if knownNodes grows to 20000, instead of ignoring new nodes, forget the 1000 oldest ones - drop connection after sendaddr if too many connections, even if it's an outbound one - if maximum total connections are lower than maximum outbound connections, active bootstrap provider mode - in this mode, check all addresses received before announcing them - so basically it only annouces those addresses it successfully connected to --- src/class_receiveDataThread.py | 44 ++++++++++++++++++++++++---------- src/class_singleListener.py | 7 +++++- src/knownnodes.py | 11 +++++++++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 83941612..3b9e6ec9 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -386,10 +386,13 @@ class receiveDataThread(threading.Thread): stream, 'advertisepeer', dataToSend)) self.sendaddr() # This is one large addr message to this one peer. - if not self.initiatedConnection and len(shared.connectedHostsList) > \ + if len(shared.connectedHostsList) > \ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections", 200): logger.info ('We are connected to too many people. Closing connection.') - self.sendDataThreadQueue.put((0, 'sendRawData', protocol.assembleErrorMessage(fatal=2, errorText="Server full, please try again later."))) + 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."))) self.sendDataThreadQueue.put((0, 'shutdown','no data')) return self.sendBigInv() @@ -622,18 +625,28 @@ class receiveDataThread(threading.Thread): knownnodes.knownNodes[recaddrStream] = {} peerFromAddrMessage = state.Peer(hostStandardFormat, recaddrPort) if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: - if len(knownnodes.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 knownnodes.knownNodesLock: - knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + knownnodes.trimKnownNodes(recAddrStream) + # only if recent + if timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) - + # bootstrap provider? + if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = int(time.time()) - 10800 + # normal mode + else: + with knownnodes.knownNodesLock: + knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode + hostDetails = ( + timeSomeoneElseReceivedMessageFromThisNode, + recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) + protocol.broadcastToSendDataQueues(( + recaddrStream, 'advertisepeer', hostDetails)) shared.needToWriteKnownNodesToDisk = True - hostDetails = ( - timeSomeoneElseReceivedMessageFromThisNode, - recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) - protocol.broadcastToSendDataQueues(( - recaddrStream, 'advertisepeer', hostDetails)) - else: + # only update if normal mode + elif BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') < \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): timeLastReceivedMessageFromThisNode = knownnodes.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. @@ -822,7 +835,12 @@ class receiveDataThread(threading.Thread): for stream in self.remoteStreams: knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) if not self.initiatedConnection: - knownnodes.knownNodes[stream][state.Peer(self.peer.host, self.remoteNodeIncomingPort)] -= 7200 # penalise inbound, 2 hours + # 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 self.sendverack() diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 322f4b67..5fe202e9 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -139,7 +139,12 @@ class singleListener(threading.Thread, StoppableThread): # 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 and \ + (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)): + # bootstrap provider? Then accept, we'll most likely drop it a little bit later + if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ + BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): + break socketObject.close() logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') else: diff --git a/src/knownnodes.py b/src/knownnodes.py index b68f135f..4979d7da 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -6,9 +6,20 @@ import state knownNodesLock = threading.Lock() knownNodes = {} +knownNodesMax = 20000 +knownNodesTrimAmount = 2000 + def saveKnownNodes(dirName = None): if dirName is None: dirName = state.appdata with knownNodesLock: with open(dirName + 'knownnodes.dat', 'wb') as output: pickle.dump(knownNodes, output) + +def trimKnownNodes(recAddrStream = 1): + if len(knownNodes[recAddrStream]) < knownNodesMax: + return + with knownNodesLock: + oldestList = sorted(knownNodes[recAddrStream], key=knownNodes[recAddrStream].get)[:knownNodeTrimAmount] + for oldest in oldestList: + del knownNodes[recAddrStream][oldest] -- 2.45.1 From d9d2deee25e6782d6b6e1c55f9f9903a4974d750 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 23:35:48 +0100 Subject: [PATCH 0674/1102] Typo in last commit --- src/class_receiveDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 3b9e6ec9..ca372944 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -625,7 +625,7 @@ class receiveDataThread(threading.Thread): knownnodes.knownNodes[recaddrStream] = {} peerFromAddrMessage = state.Peer(hostStandardFormat, recaddrPort) if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: - knownnodes.trimKnownNodes(recAddrStream) + knownnodes.trimKnownNodes(recaddrStream) # only if recent if timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) -- 2.45.1 From af8957ed72c41487319a690af5cd68b43ce4763d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 27 Feb 2017 23:37:15 +0100 Subject: [PATCH 0675/1102] Typo in the second most recent commit --- src/knownnodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/knownnodes.py b/src/knownnodes.py index 4979d7da..ffb14edc 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -20,6 +20,6 @@ def trimKnownNodes(recAddrStream = 1): if len(knownNodes[recAddrStream]) < knownNodesMax: return with knownNodesLock: - oldestList = sorted(knownNodes[recAddrStream], key=knownNodes[recAddrStream].get)[:knownNodeTrimAmount] + oldestList = sorted(knownNodes[recAddrStream], key=knownNodes[recAddrStream].get)[:knownNodesTrimAmount] for oldest in oldestList: del knownNodes[recAddrStream][oldest] -- 2.45.1 From d0b0d15dc3932439b0fc5d7557802b6406690635 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 00:12:49 +0100 Subject: [PATCH 0676/1102] Fix potential deadlock - alreadyAttemptedConnectionsListLock probably deadlocked - removed locking where unnecessary and rewrote the important part with proper locking --- src/class_outgoingSynSender.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index a2f12c4d..924961fb 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -85,9 +85,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): 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() @@ -97,16 +95,12 @@ class outgoingSynSender(threading.Thread, StoppableThread): # 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. - if (time.time() - shared.alreadyAttemptedConnectionsListResetTime) > 1800: - shared.alreadyAttemptedConnectionsList.clear() - shared.alreadyAttemptedConnectionsListResetTime = int( - time.time()) - shared.alreadyAttemptedConnectionsListLock.acquire() + with shared.alreadyAttemptedConnectionsListLock: + if (time.time() - shared.alreadyAttemptedConnectionsListResetTime) > 1800: + shared.alreadyAttemptedConnectionsList.clear() + shared.alreadyAttemptedConnectionsListResetTime = int( + time.time()) shared.alreadyAttemptedConnectionsList[peer] = 0 - try: - shared.alreadyAttemptedConnectionsListLock.release() - except threading.ThreadError as e: - pass if self._stopped: break self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator -- 2.45.1 From 59e1739136e9bffa61d4665cabf38d7851f341d8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 00:20:34 +0100 Subject: [PATCH 0677/1102] Revert duplicate IP treatment for bootstrap - bootstrap provider mode shouldn't accept multiple connections from a single IP after all, it creates problems --- src/class_singleListener.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 5fe202e9..5332929c 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -141,10 +141,6 @@ class singleListener(threading.Thread, StoppableThread): # permit repeated connections from Tor if HOST in shared.connectedHostsList and \ (".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname') or not protocol.checkSocksIP(HOST)): - # bootstrap provider? Then accept, we'll most likely drop it a little bit later - if BMConfigParser().safeGetInt('bitmessagesettings', 'maxoutboundconnections') >= \ - BMConfigParser().safeGetInt('bitmessagesettings', 'maxtotalconnections', 200): - break socketObject.close() logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') else: -- 2.45.1 From 42246f83ef1bb055a5705659ffe0a3117703159a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 01:15:49 +0100 Subject: [PATCH 0678/1102] Reset connection list on UPnP - reset the already attempted connection list after UPnP port mapping is established. This allows to resubmit externally reachable port --- src/upnp.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/upnp.py b/src/upnp.py index ae93de6a..6c245345 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -220,6 +220,11 @@ class uPnPThread(threading.Thread, StoppableThread): 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 -- 2.45.1 From f5b430b56735db555e58a10ff9c7711ba5856b5f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 09:40:28 +0100 Subject: [PATCH 0679/1102] Excessive random seeding - outgoing thread was calling a seed reinit before each peer selection. This is not necessary, just init when the thread starts --- src/class_outgoingSynSender.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 924961fb..c4f385c3 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -25,6 +25,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): def __init__(self): threading.Thread.__init__(self, name="outgoingSynSender") self.initStop() + random.seed() def setup(self, streamNumber, selfInitiatedConnections): self.streamNumber = streamNumber @@ -83,11 +84,9 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.stop.wait(10) if state.shutdown: break - random.seed() peer = self._getPeer() while peer in shared.alreadyAttemptedConnectionsList or peer.host in shared.connectedHostsList: # print 'choosing new sample' - random.seed() peer = self._getPeer() self.stop.wait(1) if self._stopped: -- 2.45.1 From e7506b2ac0355a82b2f8e7018946252ca5ebcaac Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 09:43:09 +0100 Subject: [PATCH 0680/1102] Fix tracking of already attempted connections - it didn't delete the entries correctly, resulting in outgoing syn sender deadlocking --- src/class_receiveDataThread.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index ca372944..90364228 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -77,7 +77,8 @@ class receiveDataThread(threading.Thread): self.initiatedConnection = False else: self.initiatedConnection = True - self.selfInitiatedConnections[streamNumber][self] = 0 + for stream in self.streamNumber: + self.selfInitiatedConnections[stream][self] = 0 self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware self.objectHashHolderInstance = objectHashHolderInstance self.startTime = time.time() @@ -132,7 +133,7 @@ class receiveDataThread(threading.Thread): self.processData() try: - for stream in self.remoteStreams: + for stream in self.streamNumber: try: del self.selfInitiatedConnections[stream][self] except KeyError: -- 2.45.1 From 34084bbc8058011f6a59b187e9a3b2ac1415ee5e Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 28 Feb 2017 15:51:49 +0200 Subject: [PATCH 0681/1102] Total setup.py cleanup and simple script installation --- .gitignore | 2 + MANIFEST.in | 3 ++ setup.py | 117 ++++++++++++++++++++++++------------------ src/bitmessagemain.py | 21 +++++--- src/pybitmessage | 11 ++++ 5 files changed, 99 insertions(+), 55 deletions(-) create mode 100644 MANIFEST.in create mode 100644 src/pybitmessage diff --git a/.gitignore b/.gitignore index 7da86d2f..a11f6fad 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ src/**/*.o src/**/*.so build/lib.* build/temp.* +dist +*.egg-info diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..2d29971b --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +include COPYING +include README.md +recursive-include desktop * diff --git a/setup.py b/setup.py index cb1658b8..e5a0fb7d 100644 --- a/setup.py +++ b/setup.py @@ -1,10 +1,14 @@ +#!/usr/bin/env python2.7 + import os +import sys try: - from setuptools import setup, find_packages, Extension + from setuptools import setup, Extension haveSetuptools = True except ImportError: haveSetuptools = False -import sys + +from importlib import import_module from src.version import softwareVersion @@ -16,6 +20,7 @@ packageManager = { "openSUSE": "zypper install", "Fedora": "dnf install", "Guix": "guix package -i", + "Gentoo": "emerge" } packageName = { @@ -27,6 +32,7 @@ packageName = { "openSUSE": "python-qt", "Fedora": "PyQt4", "Guix": "python2-pyqt@4.11.4", + "Gentoo": "dev-python/PyQt4" }, "msgpack": { "OpenBSD": "py-msgpack", @@ -36,9 +42,11 @@ packageName = { "openSUSE": "python-msgpack-python", "Fedora": "python2-msgpack", "Guix": "python2-msgpack", + "Gentoo": "dev-python/msgpack" } } + def detectOS(): if detectOS.result is not None: return detectOS.result @@ -52,29 +60,33 @@ def detectOS(): with open("/etc/os-release", 'rt') as osRelease: for line in osRelease: if line.startswith("NAME="): - if "fedora" in line.lower(): + line = line.lower() + if "fedora" in line: detectOS.result = "Fedora" - elif "opensuse" in line.lower(): + elif "opensuse" in line: detectOS.result = "openSUSE" - elif "ubuntu" in line.lower(): + elif "ubuntu" in line: detectOS.result = "Ubuntu" - elif "debian" in line.lower(): + elif "debian" in line: detectOS.result = "Debian" + elif "gentoo" in line or "calculate" in line: + detectOS.result = "Gentoo" else: detectOS.result = None return detectOS.result + def detectPrereqs(missing=False): available = [] try: - import PyQt4.QtCore + import_module("PyQt4.QtCore") if not missing: available.append("PyQt") except ImportError: if missing: available.append("PyQt") try: - import msgpack + import_module("msgpack") if not missing: available.append("msgpack") except ImportError: @@ -82,19 +94,27 @@ def detectPrereqs(missing=False): available.append("msgpack") return available + def prereqToPackages(): print "You can install the requirements by running, as root:" - print "%s %s" % (packageManager[detectOS()], " ".join(packageName[x][detectOS()] for x in detectPrereqs(True))) + print "%s %s" % ( + packageManager[detectOS()], " ".join( + packageName[x][detectOS()] for x in detectPrereqs(True))) + if __name__ == "__main__": detectOS.result = None detectPrereqs.result = None if "PyQt" in detectPrereqs(True): - print "You only need PyQt if you want to use the GUI. When only running as a daemon, this can be skipped." - print "However, you would have to install it manually because setuptools does not support pyqt." + print "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." if detectPrereqs(True) != [] and detectOS() in packageManager: if detectOS() is not None: - print "It looks like you're using %s. It is highly recommended to use the package manager instead of setuptools." % (detectOS()) + print "It looks like you're using %s. " \ + "It is highly recommended to use the package manager " \ + "instead of setuptools." % (detectOS()) prereqToPackages() sys.exit() if not haveSetuptools: @@ -105,56 +125,55 @@ if __name__ == "__main__": with open(os.path.join(here, 'README.md')) as f: README = f.read() - bitmsghash = Extension('bitmsghash.bitmsghash', - sources = ['src/bitmsghash/bitmsghash.cpp'], - libraries = ['pthread', 'crypto'], + bitmsghash = Extension( + 'pybitmessage.bitmsghash.bitmsghash', + sources=['src/bitmsghash/bitmsghash.cpp'], + libraries=['pthread', 'crypto'], ) dist = setup( name='pybitmessage', version=softwareVersion, - description='', + description="Reference client for Bitmessage: " + "a P2P communications protocol", long_description=README, license='MIT', # TODO: add author info #author='', #author_email='', - url='https://github.com/Bitmessage/PyBitmessage/', + url='https://bitmessage.org', # TODO: add keywords #keywords='', - install_requires = ['msgpack-python'], - classifiers = [ + install_requires=['msgpack-python'], + classifiers=[ "License :: OSI Approved :: MIT License" - "Operating System :: MacOS :: MacOS X", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 2.7.3", - "Programming Language :: Python :: 2.7.4", - "Programming Language :: Python :: 2.7.5", - "Programming Language :: Python :: 2.7.6", - "Programming Language :: Python :: 2.7.7", - "Programming Language :: Python :: 2.7.8", - "Programming Language :: Python :: 2.7.9", - "Programming Language :: Python :: 2.7.10", - "Programming Language :: Python :: 2.7.11", - "Programming Language :: Python :: 2.7.12", - "Programming Language :: Python :: 2.7.13", + "Operating System :: OS Independent", + "Programming Language :: Python :: 2.7 :: Only", + "Topic :: Internet", + "Topic :: Security :: Cryptography", + "Topic :: Software Development :: Libraries :: Python Modules", ], - package_dir={'':'src'}, - packages=['','bitmessageqt', 'bitmessagecurses', 'messagetypes', 'network', 'pyelliptic', 'socks'], - package_data={'': ['bitmessageqt/*.ui', 'bitmsghash/*.cl', 'keys/*.pem', 'translations/*.ts', 'translations/*.qm', 'images/*.png', 'images/*.ico', 'images/*.icns']}, - ext_modules = [bitmsghash], + package_dir={'pybitmessage': 'src'}, + packages=[ + 'pybitmessage', + 'pybitmessage.bitmessageqt', + 'pybitmessage.bitmessagecurses', + 'pybitmessage.messagetypes', + 'pybitmessage.network', + 'pybitmessage.pyelliptic', + 'pybitmessage.socks', + ], + package_data={'': [ + 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', + 'translations/*.ts', 'translations/*.qm', + 'images/*.png', 'images/*.ico', 'images/*.icns' + ]}, + ext_modules=[bitmsghash], zip_safe=False, - entry_points="""\ - [console_scripts] - bitmessage = bitmessagemain:Main.start - """, + #entry_points={ + # 'console_scripts': [ + # 'pybitmessage = pybitmessage.bitmessagemain:main' + # ] + #}, + scripts=['src/pybitmessage'] ) - if (dist.command_obj.get('install_scripts')): - with open(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 'wt') as f: - f.write("#!/bin/sh\n") - f.write(dist.command_obj['build'].executable + " " + \ - os.path.join(dist.command_obj['install'].install_lib, - os.path.basename(dist.command_obj['bdist_egg'].egg_output), - 'bitmessagemain.py') + "\n") - os.chmod(os.path.join(dist.command_obj['install_scripts'].install_dir, 'bitmessage'), 0555) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 707b6b62..c98f7592 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -9,17 +9,22 @@ # 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 os import socket import ctypes from struct import pack -import sys from subprocess import call import time @@ -28,7 +33,6 @@ from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenCon import defaults import shared -from helper_sql import sqlQuery import knownnodes import state import shutdown @@ -45,13 +49,13 @@ from class_addressGenerator import addressGenerator from class_smtpDeliver import smtpDeliver from class_smtpServer import smtpServer from bmconfigparser import BMConfigParser -from debug import logger # Helper Functions import helper_bootstrap import helper_generic from helper_threading import * + def connectToStream(streamNumber): state.streamsInWhichIAmParticipating.append(streamNumber) selfInitiatedConnections[streamNumber] = {} @@ -309,9 +313,14 @@ class Main: port = BMConfigParser().getint('bitmessagesettings', 'apiport') return {'address':address,'port':port} -if __name__ == "__main__": + +def main(): mainprogram = Main() - mainprogram.start(BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')) + mainprogram.start( + BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')) + +if __name__ == "__main__": + main() # So far, the creation of and management of the Bitmessage protocol and this diff --git a/src/pybitmessage b/src/pybitmessage new file mode 100644 index 00000000..decebfff --- /dev/null +++ b/src/pybitmessage @@ -0,0 +1,11 @@ +#!/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) -- 2.45.1 From e55407ff4b44c2030d09ff478d8397d4fdf289c3 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 28 Feb 2017 14:47:58 +0100 Subject: [PATCH 0682/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 63754 -> 63931 bytes src/translations/bitmessage_ja.ts | 243 +++++++++++++++--------------- 2 files changed, 124 insertions(+), 119 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index e8ed22368b613cafa942454d570ae80f66335d0b..2f28764b49a278962b8b6ec52695070ec412fd6c 100644 GIT binary patch delta 2990 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∈~e2?G)-8PCR~$f!Y@mN)}FpA$`Il9 zh8tAyGvWDGT2ZKnR{h{GtuRz;y_~p|ovs}bcIHF6Mu=MbTq@w(qjfTt1AB9{&S{Or z>Of;VH_q^}Hs%GD*=*M859xs|leMviKsqzc+63>NXxFGI97cdfs|O z9Q~e|y73hqb@_mCJFhW7O!)N_Fy2kv!c@_@`bymSgx*=pin)h~9E>RD<&o~TTZ?ZF}*)j;6KQi)9~4ZTY$zx)=s z7$H@CL525ONcFZRIAgkAYFyJz$Kh`2^m`P)wUe&vDUnOGbbr!)^3l!G>kKN?sVDAt U%`+Z6HkA6iX?LI3~& diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 1961c66b..c000c254 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -318,7 +318,7 @@ Please type the desired email address (including @mailchuck.com) below: メッセージの確認を受け取りました %1 - + Broadcast queued. 配信がキューに入りました。 @@ -348,7 +348,7 @@ Please type the desired email address (including @mailchuck.com) below: 不明なステータス: %1 %2 - + Not Connected 未接続 @@ -512,17 +512,17 @@ It is important that you back up this file. Would you like to open the file now? 接続が切断されました - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1166,7 +1166,7 @@ Are you sure you want to delete the channel? %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% @@ -1206,71 +1206,71 @@ Are you sure you want to delete the channel? - + Disk full ディスクがいっぱいです - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 @@ -1280,7 +1280,7 @@ Receiver's required difficulty: %1 and %2 メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました @@ -1290,12 +1290,12 @@ Receiver's required difficulty: %1 and %2 暗号鍵のリクエストに必要な処理を行っています。 - + Broadcasting the public key request. This program will auto-retry if they are offline. 公開鍵のリクエストを配信しています。 このプログラムがオフラインの場合、自動的に再試行されます。 - + Sending public key request. Waiting for reply. Requested at %1 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました @@ -1305,7 +1305,7 @@ Receiver's required difficulty: %1 and %2 ポート%1でUPnPポートマッピングが確立しました - + UPnP port mapping removed UPnPポートマッピングを削除しました @@ -1315,7 +1315,7 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? @@ -1325,37 +1325,37 @@ Receiver's required difficulty: %1 and %2 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %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 は間違っている可能性があります。 設定を確認してください。 @@ -1370,72 +1370,77 @@ Receiver's required difficulty: %1 and %2 チャンネルにはお勧めしません - + + Problems connecting? Try enabling UPnP in the Network Settings + 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください + + + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... -- 2.45.1 From 97f803ccde265c343edf8120b2918c078a112730 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 27 Feb 2017 18:11:53 +0100 Subject: [PATCH 0683/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 84424 -> 84767 bytes src/translations/bitmessage_eo.ts | 302 +++++++++++++++--------------- 2 files changed, 156 insertions(+), 146 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 18d6184cdb1dc21e0df1dbe056f576cad088072d..85a6ed578ae0028f9d2c7bcbf4265de7c0cfc68d 100644 GIT binary patch delta 3292 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 delta 2983 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 b3w*j;g59SSDe}^oq8Z5 EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -281,7 +281,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Iu de viaj adresoj, %1, estas malnova versio 1 adreso. Versioj 1 adresoj ne estas jam subtenataj. Ĉu ni povas forviŝi ĝin? - + Waiting for their encryption key. Will request it again soon. Atendado je ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. @@ -291,17 +291,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -311,47 +311,47 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -361,12 +361,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Sendi - + Subscribe Aboni - + Channel Kanalo @@ -376,12 +376,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 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. @@ -390,17 +390,17 @@ It is important that you back up this file. 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 redaktante 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.) @@ -409,37 +409,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -509,22 +509,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 @@ -532,17 +532,17 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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. @@ -587,67 +587,67 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 De - + Sending email gateway registration request Sendado de peto pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (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 Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi 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. Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco 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). Vi estas uzanta TCP pordo %1 (Tio ĉi estas ŝanĝebla en la agordoj). @@ -1110,47 +1110,47 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage... %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj... %1% - + Saving settings... %1% Konservado de agordoj... %1% - + Shutting down core... %1% Fermado de kerno... %1% - + Stopping notifications... %1% Haltigado de sciigoj... %1% - + Shutdown imminent... %1% Fermado tuj... %1% @@ -1160,17 +1160,17 @@ Are you sure you want to delete the channel? %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage... %1% - + Sent Senditaj @@ -1205,96 +1205,96 @@ Are you sure you want to delete the channel? - + Disk full Disko plenplena - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... Kalkulado de laborpruvo, kiu endas por sendi elsendon... - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendado de peto pri ĉifroŝlosilo de ricevonto. - + 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. - + 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. - + Sending public key request. Waiting for reply. Requested at %1 Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 @@ -1314,32 +1314,32 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? @@ -1364,72 +1364,82 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. - + + not recommended for chans + malkonsilinda por kanaloj + + + + Problems connecting? Try enabling UPnP in the Network Settings + Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. + + + 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. - + 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... -- 2.45.1 From a90f35fe6d90fd0d3ddebee8aa48acc98e681b45 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 27 Feb 2017 18:13:13 +0100 Subject: [PATCH 0684/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 87571 -> 87912 bytes src/translations/bitmessage_pl.ts | 302 +++++++++++++++--------------- 2 files changed, 156 insertions(+), 146 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 467b9b08ea5badcf6a549f799dfd629a1458b82a..16f9595f4a01b87a27c4a7b7cbc718f396afb85f 100644 GIT binary patch delta 3266 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 delta 2981 zcmX9=dt6Ov7k=Ke&px-k&)F(`rhaoK(nTsn(xH;e$P8x&qjDJxGL@-Zavhfp(@==|iiR1KX%a?m4f+=S_5AkPXTNK$XFbna?}K9AQpjg?_t^|! z5SWz!$TNZ2ivj)skiQfNbOZV=0lv5Zd@~rB;Yz>f0O4c60+TW)>dlWb!KcZAgx=sc zcL3Rgz~_zul9CC(0Md7WFU$usG=eWr2J>%*qJX2Xe}Xb-EZBGlsK*|q)4zmnR~0at zgVorlK;0Brm3#-rnqeEW0oV}&IQ)M+8M|%w*hnYL18-a)RKoHUp>&;j;m4{@W2j@ zc9fXa2;3cg3=l@)`S~_rTO?EOXa{^3G3)I*;B_qf$d>s3nq$2O90haoWGz)Wu-_YO1G(uX6yVsoZZhIe+cxu64=PGsS)>BEjj zX7Zs5)337RFR8-gX>3zT1$Y(G2 z6a#a|u};}&pzkCZe?m)vH~lIT7c~RtH(MHIdUMh5vOzD`052}chTmBYEP5;(w~EkI zB?}+6XdT-oIZVOaHnJ_-TP``<#1# z<7wI6ne_kJt+Fy5%-X&$1bN0C;k>atO!?4|8vLMc#+KYXz+`yU=N>I;v ziRZuscW!7@JecD;&ev!U7GUB6X4eCUqqy;liTJ$+F8p;Kb>#C@Zp-Ugz;}*bO&%;AMBx((G(`*Z~jnpk}t%M0E10DgVsWx3sfAGXMk?e_zd zvgK!5`_cIpc}0vP4G(8|t@T-Y?_+r**PEZ$@rG~`%qC}kR6C__$l^b}bDad}%+HFa z25$)BLxYL`gk*lc*BRpR3LlkMMqxhVS9w-}+1v05tHQv%XYiYS`T@T*@;OhV!Fo>M zw4Tr8Ioy46KP#POPWr#Bs`?j5wg- zqB3mI0-6wU%7pFyz{tVM^%Fh-^BJYw;PpE&(N&qzb2sqPpv<^$ge67M+uVFh`D5B$ znqGlj=;Yspw`O)>bCL4Mr&L;Yk@Bop9++>H@=DMwK$WVzeSO@EYC7Gr=aomrJtX5U-qam@jMD?3lPp03lYFKXqGNM!sTj)6?UUjc= z7VVJ%s)rqUR7Xb_-uhnkd=2fLdUtjArYXRyOtsw)Wd5Ot)lR=Xp`oxs?YTL|QlPXo zABa#->(r3FqSetx3N@!lz53N#;LT2T+IR}#-Cu3#M)pc6S7$vO4164^&UsgR*5B&f z!v| zAktg=X@Zgqi5rC`G>5ozxS|Pbod7ntMH3!M0f&p4h&z;Mo$Y&MJ<>JtGh4u%S7~yZ zDc%`gQ|#AaCdCcalm%181+O$mg?6eeNprf2Dnq{J+$u86rbNw^^`xlz9hyI8-Um(x zYaV`2iMdz{Y+^B~BSKKekdpm61r2ub8&@0CTII9Jx_EUt{ z1ecSufbp}0feLdx@Uy?*7eX(lrVIWy9{_))3dT=TfZFNrk#(;SCUq82Wr@PP6#+!K zlaLylKnXq&GJbBLgv*7Tn$ciAs)bzj5OVxv;o_kOf8ixI5XT%kUu zjqVOQp&@V+C6XfCG4HgYU6CTRT9c>#z9+QW(~@*b5eL50d1j?J((N6E1>%@PGy>vU z#E`g!v4KgZ=}{A(XL$SM+M%{=KZe9!oCK|;OF$szZh zjnVCxF^q0+Yjiv9snFDyx=Xn}z@t;TssSW1pbPu9ci}Cr3!6>4dL!K)>i&I?tmm(~ zN0a)JNgQi+Z}mE`ZU$+9qb;EBC3%{bg1Hw;UKjOr?|Lc?x62~Y*GQipCZ-mjls?NR zMvg9)rvG#b_(ziFr%eHo*LmP z?Z5mM?1N6Jc$`58{Mjy*f0Re_=^yF%k~ZMS9@5z!gxiaxYbH7 EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -285,7 +285,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -295,17 +295,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,47 +315,47 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -365,12 +365,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Wyślij - + Subscribe Subskrybuj - + Channel Kanał @@ -380,12 +380,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -394,17 +394,17 @@ It is important that you back up this file. 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.) @@ -413,37 +413,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,47 +1117,47 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów 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% @@ -1167,17 +1167,17 @@ Czy na pewno chcesz usunąć ten kanał? %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 @@ -1212,96 +1212,96 @@ Czy na pewno chcesz usunąć ten kanał? - + 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 Przekaz wysłane o %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 @@ -1321,32 +1321,32 @@ Odbiorca wymaga trudności: %1 i %2 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? @@ -1371,72 +1371,82 @@ Odbiorca wymaga trudności: %1 i %2 Twoje procesory graficzne nie obliczyły poprawnie, wyłączam OpenCL. Prosimy zaraportować przypadek twórcom programu. - + + not recommended for chans + niezalecany dla kanałów + + + + Problems connecting? Try enabling UPnP in the Network Settings + Problem z połączeniem? Spróbuj włączyć UPnP w ustawieniach sieci. + + + 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. - + 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... -- 2.45.1 From e33c6023b37d5eb25bb4bd48bebcfa99df3d26e4 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 28 Feb 2017 19:21:29 +0100 Subject: [PATCH 0685/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 86533 -> 86876 bytes src/translations/bitmessage_sk.ts | 312 +++++++++++++++--------------- 2 files changed, 161 insertions(+), 151 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 7980f261c4577a45dee18a0d8af48d0aa1c86924..89a52107cdea3baef18e46e93b4e416079b0c4b0 100644 GIT binary patch delta 3279 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 Ar2qf` delta 2967 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 Vrs!w6HlZjvwU>91O~sg`e*wg_jYI$d diff --git a/src/translations/bitmessage_sk.ts b/src/translations/bitmessage_sk.ts index 1585463f..de2519dc 100644 --- a/src/translations/bitmessage_sk.ts +++ b/src/translations/bitmessage_sk.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrácia zlyhala: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: @@ -83,7 +83,7 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -286,7 +286,7 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -296,17 +296,17 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -316,47 +316,47 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -366,12 +366,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Odoslať - + Subscribe Prihlásiť sa k odberu - + Channel Kanál @@ -381,12 +381,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -395,17 +395,17 @@ It is important that you back up this file. 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.) @@ -414,37 +414,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -514,22 +514,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +537,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,67 +592,67 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 Od - + Sending email gateway registration request Odosielam požiadavku o registráciu na e-mailovej bráne @@ -667,142 +667,142 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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 Odosielam žiadosť o odhlásenie z e-mailovej brány - + Sending email gateway status request Odosielam požiadavku o stave e-mailovej brány - + 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. Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1115,47 +1115,47 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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% @@ -1165,17 +1165,17 @@ Ste si istý, že chcete kanál odstrániť? %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é @@ -1210,96 +1210,96 @@ Ste si istý, že chcete kanál odstrániť? - + 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 @@ -1309,7 +1309,7 @@ Priímcova požadovaná obtiažnosť: %1 a %2 Mapovanie portov UPnP vytvorené na porte %1 - + UPnP port mapping removed Mapovanie portov UPnP zrušené @@ -1319,47 +1319,47 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. @@ -1369,72 +1369,82 @@ Priímcova požadovaná obtiažnosť: %1 a %2 Vaša grafická karta vykonala nesprávny výpočet, deaktivujem OpenCL. Prosím, pošlite správu vývojárom. - + + not recommended for chans + nie je odporúčaná pre kanály + + + + Problems connecting? Try enabling UPnP in the Network Settings + Problémy so spojením? Skúste zapnúť UPnP v Nastaveniach siete + + + 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. - + 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... -- 2.45.1 From 2906bff6b46ae6b14cd0e3ce395d46a8f9d3714c Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 28 Feb 2017 19:23:37 +0100 Subject: [PATCH 0686/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 93851 -> 94230 bytes src/translations/bitmessage_de.ts | 312 +++++++++++++++--------------- 2 files changed, 161 insertions(+), 151 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 07dee7af430a0cb6e9a4504bcc07b8d0cade754a..3865eea84079c35a828b50b7f061a019fae15a40 100644 GIT binary patch delta 3296 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 diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 020dcd25..d8263551 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -83,7 +83,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -289,7 +289,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -398,17 +398,17 @@ It is important that you back up this file. Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. - + 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 anlegen. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1169,17 +1169,17 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Stunde%n Stunden - + %n day(s) %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1214,95 +1214,95 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? - + Disk full Datenträger voll - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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... - + 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. - + 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 @@ -1312,7 +1312,7 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping eingerichtet auf Port %1 - + UPnP port mapping removed UPnP Port-Mapping entfernt @@ -1322,47 +1322,47 @@ Receiver's required difficulty: %1 and %2 Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? - + Problem communicating with proxy: %1. Please check your network settings. Kommunikationsfehler mit dem Proxy: %1. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. - + 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. @@ -1372,72 +1372,82 @@ Receiver's required difficulty: %1 and %2 Ihre Grafikkarte hat inkorrekt berechnet, OpenCL wird deaktiviert. Bitte benachrichtigen Sie die Entwickler. - + + not recommended for chans + für Chans nicht empfohlen + + + + Problems connecting? Try enabling UPnP in the Network Settings + Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten + + + 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. - + 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... -- 2.45.1 From eaafb9efa549a305e22437b4bdcf5b3e32751b95 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 22:04:34 +0100 Subject: [PATCH 0687/1102] Listening port shouldn't be grey --- src/bitmessageqt/__init__.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 48cff7e5..ebcc351c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4109,10 +4109,8 @@ class settingsDialog(QtGui.QDialog): self.ui.checkBoxSocksListen.setEnabled(False) elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS4a': self.ui.comboBoxProxyType.setCurrentIndex(1) - self.ui.lineEditTCPPort.setEnabled(False) elif str(BMConfigParser().get('bitmessagesettings', 'socksproxytype')) == 'SOCKS5': self.ui.comboBoxProxyType.setCurrentIndex(2) - self.ui.lineEditTCPPort.setEnabled(False) self.ui.lineEditSocksHostname.setText(str( BMConfigParser().get('bitmessagesettings', 'sockshostname'))) @@ -4221,7 +4219,6 @@ 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) @@ -4230,7 +4227,6 @@ 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. -- 2.45.1 From b7e75b9bc51e7036045167ad6191fe339f1a9daa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 22:22:36 +0100 Subject: [PATCH 0688/1102] setup.py fixes, guix and pyopencl - detect GUIX - FreeBSD uses "pkg install", not "pkg_install" - add pyopencl dependency checking --- setup.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e5a0fb7d..078fbc2d 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from src.version import softwareVersion packageManager = { "OpenBSD": "pkg_add", - "FreeBSD": "pkg_install", + "FreeBSD": "pkg install", "Debian": "apt-get install", "Ubuntu": "apt-get install", "openSUSE": "zypper install", @@ -43,6 +43,13 @@ packageName = { "Fedora": "python2-msgpack", "Guix": "python2-msgpack", "Gentoo": "dev-python/msgpack" + }, + "pyopencl": { + "FreeBSD": "py27-pyopencl", + "Debian": "python-pyopencl", + "Ubuntu": "python-pyopencl", + "Fedora": "python2-pyopencl", + "Gentoo": "dev-python/pyopencl" } } @@ -73,6 +80,8 @@ def detectOS(): detectOS.result = "Gentoo" else: detectOS.result = None + elif os.path.isfile("/etc/config.scm"): + detectOS.result = "Guix" return detectOS.result @@ -92,6 +101,13 @@ def detectPrereqs(missing=False): except ImportError: if missing: available.append("msgpack") + try: + import_module("pyopencl") + if not missing: + available.append("pyopencl") + except ImportError: + if missing: + available.append("pyopencl") return available -- 2.45.1 From 171bc83ec0bde275602d6545255d83400a36093d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 22:47:56 +0100 Subject: [PATCH 0689/1102] HTML parser fix - URLs followed with space were broken --- src/bitmessageqt/safehtmlparser.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index aa935785..a78991d3 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -19,15 +19,22 @@ class SafeHTMLParser(HTMLParser): 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] - replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] + 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`!()\[\]{};:\'".,<>?]))') uriregex2 = re.compile(r' 1 and text[0] == " ": text = " " + text[1:] @@ -95,12 +102,13 @@ class SafeHTMLParser(HTMLParser): except UnicodeDecodeError: data = unicode(data, 'utf-8', errors='replace') HTMLParser.feed(self, data) - tmp = SafeHTMLParser.multi_replace(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): -- 2.45.1 From 8d829b587e06dd658f5ee1af8ae24152157f59bd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 22:59:44 +0100 Subject: [PATCH 0690/1102] Reset OpenCL when settings change - previously, changing the OpenCL vendor (or turning it on/off) required a restart and this wasn't clear --- src/bitmessageqt/__init__.py | 1 + src/class_singleWorker.py | 5 +++++ src/openclpow.py | 7 ++++++- src/proofofwork.py | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ebcc351c..fc9b4d9a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2444,6 +2444,7 @@ class MyForm(settingsmixin.SMainWindow): 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', '')) acceptableDifficultyChanged = False diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 87034f7c..b45c4aca 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -120,6 +120,11 @@ class singleWorker(threading.Thread, StoppableThread): self.sendOutOrStoreMyV4Pubkey(data) except: pass + elif command == 'resetPoW': + try: + proofofwork.resetPoW() + except: + pass elif command == 'stopThread': self.busy = 0 return diff --git a/src/openclpow.py b/src/openclpow.py index 50de80ab..3153c6b6 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -26,7 +26,12 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, enabledGpus, hash_dt + global ctx, queue, program, enabledGpus, hash_dt, vendors + gpus = [] + ctx = False + enabledGpus = [] + vendors = [] + hash_dt = None try: hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) try: diff --git a/src/proofofwork.py b/src/proofofwork.py index e20d6cff..493b8b0c 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -231,6 +231,9 @@ def run(target, initialHash): except: pass #fallback +def resetPoW(): + openclpow.initCL() + # init def init(): global bitmsglib, bso, bmpow -- 2.45.1 From 9263f53d860296291a29e95c2b7e3c5ff4c736e6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 28 Feb 2017 23:52:27 +0100 Subject: [PATCH 0691/1102] OpenCL PoW fix - previous commit created some problems, now it should work --- src/openclpow.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/openclpow.py b/src/openclpow.py index 3153c6b6..59375329 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -26,12 +26,11 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, enabledGpus, hash_dt, vendors - gpus = [] + global ctx, queue, program, hash_dt + del enabledGpus[:] + del vendors[:] + del gpus[:] ctx = False - enabledGpus = [] - vendors = [] - hash_dt = None try: hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) try: @@ -52,10 +51,10 @@ def initCL(): logger.info("Loaded OpenCL kernel") else: logger.info("No OpenCL GPUs found") - enabledGpus = [] + del enabledGpus[:] except Exception as e: logger.error("OpenCL fail: ", exc_info=True) - enabledGpus = [] + del enabledGpus[:] def openclAvailable(): return (len(gpus) > 0) -- 2.45.1 From 15077c9388d89d67d571ee612da4a0e35747fd41 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 1 Mar 2017 10:05:08 +0100 Subject: [PATCH 0692/1102] More accurate PendingUpload tracking - works correctly when starting offline - stops tracking after after 60 seconds but only if at least 1 successful upload --- src/class_sendDataThread.py | 6 +-- src/inventory.py | 83 +++++++++++++++++++++++++------------ 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 5ddb3c11..7de63a02 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -187,12 +187,12 @@ class sendDataThread(threading.Thread): logger.error('send pong failed') break elif command == 'sendRawData': - hash = None + objectHash = None if type(data) in [list, tuple]: - hash, data = data + objectHash, data = data try: self.sendBytes(data) - PendingUpload().delete(hash) + PendingUpload().delete(objectHash) except: logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.', exc_info=True) break diff --git a/src/inventory.py b/src/inventory.py index 4424942f..1087e655 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -225,36 +225,48 @@ class PendingUpload(object): # 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] = [] + 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]: - self.hashes[objectHash].append(thread.peer) + 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]: - self.hashes[objectHash].append(current_thread().peer) + 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(len(self.hashes[x]) > 0 for x in self.hashes) + 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]) for x in self.hashes)) + 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, throwDeadline=True): + def progress(self, raiseDeadline=True): if self.maxLen < self._progress(): self.maxLen = self._progress() if self.deadline < time.time(): - if self.deadline > 0 and throwDeadline: + if self.deadline > 0 and raiseDeadline: raise PendingUploadDeadlineException self.deadline = time.time() + 20 try: @@ -262,29 +274,48 @@ class PendingUpload(object): except ZeroDivisionError: return 1.0 - def delete(self, objectHash): + 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: - if objectHash in self.hashes and current_thread().peer in self.hashes[objectHash]: - self.hashes[objectHash].remove(current_thread().peer) - if len(self.hashes[objectHash]) == 0: - del self.hashes[objectHash] + 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): - while True: - try: - with self.lock: - for objectHash in self.hashes: - if current_thread().peer in self.hashes[objectHash]: - self.hashes[objectHash].remove(current_thread().peer) - if len(self.hashes[objectHash]) == 0: - del self.hashes[objectHash] - except (KeyError, RuntimeError): - pass - else: - break + 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() -- 2.45.1 From af5cb08093a24d9c64669a96ed71a360db569d17 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 1 Mar 2017 11:29:38 +0100 Subject: [PATCH 0693/1102] setup.py updates - parametrise module list - allow optional modules (pyopencl, PyQt4) - add setuptools - add compiler error detection - press return to continue --- setup.py | 187 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 76 deletions(-) diff --git a/setup.py b/setup.py index 078fbc2d..77434a78 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ packageManager = { } packageName = { - "PyQt": { + "PyQt4": { "OpenBSD": "py-qt4", "FreeBSD": "py27-qt4", "Debian": "python-qt4", @@ -32,7 +32,12 @@ packageName = { "openSUSE": "python-qt", "Fedora": "PyQt4", "Guix": "python2-pyqt@4.11.4", - "Gentoo": "dev-python/PyQt4" + "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", @@ -49,10 +54,34 @@ packageName = { "Debian": "python-pyopencl", "Ubuntu": "python-pyopencl", "Fedora": "python2-pyopencl", - "Gentoo": "dev-python/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", + "Fedora": "python2-setuptools", + "openSUSE": "python-setuptools", + "Guix": "python2-setuptools", + "Gentoo": "", } } +compiling = { + "Debian": "build-essential libssl-dev", + "Ubuntu": "build-essential libssl-dev", + "Fedora": "gcc-c++ redhat-rpm-config python-devel", + "openSUSE": "gcc-c++ libopenssl-devel python-devel", +} + def detectOS(): if detectOS.result is not None: @@ -87,27 +116,14 @@ def detectOS(): def detectPrereqs(missing=False): available = [] - try: - import_module("PyQt4.QtCore") - if not missing: - available.append("PyQt") - except ImportError: - if missing: - available.append("PyQt") - try: - import_module("msgpack") - if not missing: - available.append("msgpack") - except ImportError: - if missing: - available.append("msgpack") - try: - import_module("pyopencl") - if not missing: - available.append("pyopencl") - except ImportError: - if missing: - available.append("pyopencl") + for module in packageName.keys(): + try: + import_module(module) + if not missing: + available.append(module) + except ImportError: + if missing: + available.append(module) return available @@ -116,27 +132,40 @@ def prereqToPackages(): print "%s %s" % ( packageManager[detectOS()], " ".join( packageName[x][detectOS()] for x in detectPrereqs(True))) + for package in detectPrereqs(True): + if packageName[package]['optional']: + print packageName[package]['description'] +def compilerToPackages(): + if not detectOS() in compiling: + return + print "You can install the requirements by running, as root:" + print "%s %s" % ( + packageManager[detectOS()], compiling[detectOS()]) if __name__ == "__main__": detectOS.result = None detectPrereqs.result = None - if "PyQt" in detectPrereqs(True): - print "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." if detectPrereqs(True) != [] and detectOS() in packageManager: if detectOS() is not None: print "It looks like you're using %s. " \ "It is highly recommended to use the package manager " \ "instead of setuptools." % (detectOS()) prereqToPackages() - sys.exit() + for module in detectPrereqs(True): + if not packageName[module]['optional']: + sys.exit() if not haveSetuptools: print "It looks like you're missing setuptools." sys.exit() + if detectPrereqs(True) != []: + print "Press Return to continue" + try: + nothing = raw_input + except NameError: + pass + here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md')) as f: README = f.read() @@ -147,49 +176,55 @@ if __name__ == "__main__": libraries=['pthread', 'crypto'], ) - 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=['msgpack-python'], - 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=[ - 'pybitmessage', - 'pybitmessage.bitmessageqt', - 'pybitmessage.bitmessagecurses', - 'pybitmessage.messagetypes', - 'pybitmessage.network', - 'pybitmessage.pyelliptic', - 'pybitmessage.socks', - ], - package_data={'': [ - 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', - 'translations/*.ts', 'translations/*.qm', - 'images/*.png', 'images/*.ico', 'images/*.icns' - ]}, - ext_modules=[bitmsghash], - zip_safe=False, - #entry_points={ - # 'console_scripts': [ - # 'pybitmessage = pybitmessage.bitmessagemain:main' - # ] - #}, - scripts=['src/pybitmessage'] - ) + try: + 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=['msgpack-python'], + 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=[ + 'pybitmessage', + 'pybitmessage.bitmessageqt', + 'pybitmessage.bitmessagecurses', + 'pybitmessage.messagetypes', + 'pybitmessage.network', + 'pybitmessage.pyelliptic', + 'pybitmessage.socks', + ], + package_data={'': [ + 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', + 'translations/*.ts', 'translations/*.qm', + 'images/*.png', 'images/*.ico', 'images/*.icns' + ]}, + ext_modules=[bitmsghash], + zip_safe=False, + #entry_points={ + # 'console_scripts': [ + # 'pybitmessage = pybitmessage.bitmessagemain:main' + # ] + #}, + scripts=['src/pybitmessage'] + ) + except SystemExit: + print "It looks like building the package failed.\n" \ + "You may be missing a C++ compiler and the OpenSSL headers." + compilerToPackages() + -- 2.45.1 From 636ae17cc0025d7eeb1fe88b9f79ff5ff713a944 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 1 Mar 2017 11:44:58 +0100 Subject: [PATCH 0694/1102] setup.py fix and update - libssl dependency for Fedora - typo in waiting for keypress --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 77434a78..2c769a63 100644 --- a/setup.py +++ b/setup.py @@ -78,7 +78,7 @@ packageName = { compiling = { "Debian": "build-essential libssl-dev", "Ubuntu": "build-essential libssl-dev", - "Fedora": "gcc-c++ redhat-rpm-config python-devel", + "Fedora": "gcc-c++ redhat-rpm-config python-devel openssl-devel", "openSUSE": "gcc-c++ libopenssl-devel python-devel", } @@ -162,7 +162,7 @@ if __name__ == "__main__": if detectPrereqs(True) != []: print "Press Return to continue" try: - nothing = raw_input + nothing = raw_input() except NameError: pass -- 2.45.1 From b304872b6824bdca60c4679c052277291d4001c0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 1 Mar 2017 13:12:31 +0100 Subject: [PATCH 0695/1102] Version bump for 0.6.2 --- src/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.py b/src/version.py index 85210f5f..bd06ca9b 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1 @@ -softwareVersion = '0.6.1' +softwareVersion = '0.6.2' -- 2.45.1 From ab39541ef5da32a943336c055fe4c3e1b454875f Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 1 Mar 2017 17:06:12 +0100 Subject: [PATCH 0696/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 89972 -> 90153 bytes src/translations/bitmessage_ru.ts | 257 +++++++++++++++--------------- 2 files changed, 131 insertions(+), 126 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index d14f75ae2b0b208dfdfe7a3fec7f4a548b711453..9b7a09a9afb9c2cca2b14ccdf26cd57d8714c0cc 100644 GIT binary patch delta 3727 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 F{{^oGP$B>T delta 3590 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 sYj=!x4AqA_8=5vq(oedxb 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -76,7 +76,7 @@ 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-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только 1 шлюз Mailchuck (@mailchuck.com). + Email-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только шлюз Mailchuck (@mailchuck.com). Пожалуйста, введите желаемый адрес email (включая @mailchuck.com) ниже:
@@ -318,7 +318,7 @@ Please type the desired email address (including @mailchuck.com) below: Сообщение доставлено в %1 - + Broadcast queued. Рассылка ожидает очереди. @@ -348,7 +348,7 @@ Please type the desired email address (including @mailchuck.com) below: Неизвестный статус: %1 %2 - + Not Connected Не соединено @@ -520,17 +520,17 @@ It is important that you back up this file. Would you like to open the file now? Соединение потеряно - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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 байт). Пожалуйста, сократите сообщение перед отправкой. + Сообщение, которое вы пытаетесь отправить, длиннее максимально допустимого на %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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,67 +596,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1006,7 +1006,7 @@ Are you sure you want to delete the channel? Send ordinary Message - Отправить обыкновенное сообщение + Отправить обычное сообщение @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1174,7 +1174,7 @@ Are you sure you want to delete the channel? %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% @@ -1214,71 +1214,71 @@ Are you sure you want to delete the channel? - + Disk full Диск переполнен - + Alert: Your disk or data storage volume is full. Bitmessage will now exit. Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. - + Error! Could not find sender address (your address) in the keys.dat file. Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. Выполнение работы, требуемой для отправки сообщения. Для адреса версии 2 (как этот), не требуется указание сложности. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 @@ -1288,7 +1288,7 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для отправки сообщения. - + Message sent. Waiting for acknowledgement. Sent on %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено на %1 @@ -1298,12 +1298,12 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для запроса ключа шифрования. - + Broadcasting the public key request. This program will auto-retry if they are offline. Рассылка запросов открытого ключа шифрования. Программа будет повторять попытки, если они оффлайн. - + Sending public key request. Waiting for reply. Requested at %1 Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %1 @@ -1313,7 +1313,7 @@ Receiver's required difficulty: %1 and %2 Распределение портов UPnP завершилось выделением порта %1 - + UPnP port mapping removed Распределение портов UPnP отменено @@ -1323,7 +1323,7 @@ Receiver's required difficulty: %1 and %2 Отметить все сообщения прочтенные - + Are you sure you would like to mark all messages read? Вы уверены, что хотите отметить все сообщения как прочтенные? @@ -1333,37 +1333,37 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для отправки рассылки. - + Proof of work pending Ожидается доказательство работы - + %n object(s) pending proof of work - %n объект в ожидании подтверждения работы%n объекта в ожидании подтверждения работы%n объектов в ожидании подтверждения работы%n объектов в ожидании подтверждения работы + %n объект в ожидании доказательства работы%n объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%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, возможно неправильное. Пожалуйста, проверьте ваши настройки. @@ -1378,72 +1378,77 @@ Receiver's required difficulty: %1 and %2 не рекомендовано для чанов - + + Problems connecting? Try enabling UPnP in the Network Settings + Проблемы подключения? Попробуйте включить UPnP в сетевых настройках. + + + 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. - + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? - + 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... Ожидание окончания синхронизации... @@ -1679,7 +1684,7 @@ The 'Random Number' option is selected by default but deterministic ad Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Использовать чёрный список (Разрешить все входящие сообщения, кроме указанных в чёрном списке) + Использовать чёрный список (разрешить все входящие сообщения, кроме указанных в чёрном списке) @@ -2322,12 +2327,12 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <html><head/><body><p>По умолчанию, когда вы отправляете сообщение кому-либо, и адресат находится оффлайн несколько дней, ваш Bitmessage перепосылает сообщение. Это будет продолжаться с увеличивающимся по экспоненте интервалом; сообщение будет переотправляться, например, через 5, 10, 20 дней, пока адресат их запрашивает. Здесь вы можете изменить это поведение, заставив Bitmessage прекращать переотправку по прошествии указанного количества дней или месяцев.</p><p>Оставьте поля пустыми, чтобы вернуться к поведению по умолчанию.</p></body></html> Give up after - Отказ от переотправки через + Прекратить через -- 2.45.1 From 405a06c08a914e0e09632ae605a72cdfbb982f3f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 2 Mar 2017 15:02:51 +0100 Subject: [PATCH 0697/1102] Indentation --- src/inventory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/inventory.py b/src/inventory.py index 1087e655..f2e9b37b 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -303,7 +303,7 @@ class PendingUpload(object): self.hashes[objectHash]['sendCount'] += 1 self.hashes[objectHash]['peers'].remove(current_thread().peer) except KeyError: - pass + pass self.clearHashes(objectHash) def stop(self): -- 2.45.1 From 53657dba47c070763b7624513cf3aa059fde1bc7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 2 Mar 2017 15:03:08 +0100 Subject: [PATCH 0698/1102] Phase 1 of SHA256 support - new variable "digestalg" which defaults to "sha1", but allows "sha256" for those who want to sign using this - Addresses #953 --- src/highlevelcrypto.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 50f13cce..4a24fe20 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,4 +1,5 @@ from binascii import hexlify +from bmconfigparser import BMConfigParser import pyelliptic from pyelliptic import arithmetic as a, OpenSSL def makeCryptor(privkey): @@ -35,8 +36,17 @@ def sign(msg,hexPrivkey): # upgrade PyBitmessage gracefully. # https://github.com/yann2192/pyelliptic/pull/33 # More discussion: https://github.com/yann2192/pyelliptic/issues/32 - return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) # SHA1 - #return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) # SHA256. We should switch to this eventually. + digestAlg = BMConfigParser().safeGet('bitmessagesettings', 'digestalg', 'sha1') + if digestAlg == "sha1": + # SHA1, this will eventually be deprecated + print "sha1" + return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) + elif digestAlg == "sha256": + # SHA256. Eventually this will become the default + print "sha256" + return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) + else: + raise ValueError("Unknown digest algorithm %s" % (digestAlgo)) # Verifies with hex public key def verify(msg,sig,hexPubkey): # As mentioned above, we must upgrade gracefully to use SHA256. So -- 2.45.1 From bea675f9a6057719ce22777a7671cd27d7381794 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 2 Mar 2017 15:09:01 +0100 Subject: [PATCH 0699/1102] Remove unnecessary "print" from previous commit --- src/highlevelcrypto.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 4a24fe20..5e7f549c 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -39,11 +39,9 @@ def sign(msg,hexPrivkey): digestAlg = BMConfigParser().safeGet('bitmessagesettings', 'digestalg', 'sha1') if digestAlg == "sha1": # SHA1, this will eventually be deprecated - print "sha1" return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.digest_ecdsa_sha1) elif digestAlg == "sha256": # SHA256. Eventually this will become the default - print "sha256" return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) else: raise ValueError("Unknown digest algorithm %s" % (digestAlgo)) -- 2.45.1 From 983620640205d2bc82ef8e1b3181efeb416fcd97 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 5 Mar 2017 23:07:18 +0200 Subject: [PATCH 0700/1102] Missed translations: namecoin and welcom message --- src/bitmessageqt/__init__.py | 6 ++---- src/translations/bitmessage.pro | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fc9b4d9a..6b909164 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -659,14 +659,12 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderTabTreeMessages() # Set welcome message - self.ui.textEditInboxMessage.setText( - """ + 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 - """ - ) + """)) # Initialize the address book self.rerenderAddressBook() diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 22044d46..a4e9ff77 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -16,6 +16,7 @@ SOURCES = ../addresses.py\ ../helper_msgcoding.py\ ../helper_sent.py\ ../helper_startup.py\ + ../namecoin.py\ ../proofofwork.py\ ../shared.py\ ../upnp.py\ -- 2.45.1 From ee7e630694c68ecc1c10a189bc796e0dc4665d04 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 1 Mar 2017 16:46:13 +0200 Subject: [PATCH 0701/1102] Show a dialog with QR-code for selected bm-address --- setup.py | 12 +++- src/bitmessageqt/__init__.py | 14 ++++- src/plugins/__init__.py | 0 src/plugins/plugin.py | 12 ++++ src/plugins/qrcodeui.py | 101 ++++++++++++++++++++++++++++++++ src/translations/bitmessage.pro | 3 +- 6 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/plugins/__init__.py create mode 100644 src/plugins/plugin.py create mode 100644 src/plugins/qrcodeui.py diff --git a/setup.py b/setup.py index 2c769a63..1a273eaf 100644 --- a/setup.py +++ b/setup.py @@ -191,6 +191,9 @@ if __name__ == "__main__": # TODO: add keywords #keywords='', install_requires=['msgpack-python'], + extras_require={ + 'qrcode': ['qrcode'] + }, classifiers=[ "License :: OSI Approved :: MIT License" "Operating System :: OS Independent", @@ -208,6 +211,7 @@ if __name__ == "__main__": 'pybitmessage.network', 'pybitmessage.pyelliptic', 'pybitmessage.socks', + 'pybitmessage.plugins' ], package_data={'': [ 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', @@ -216,11 +220,15 @@ if __name__ == "__main__": ]}, ext_modules=[bitmsghash], zip_safe=False, - #entry_points={ + entry_points={ + 'gui.menu': [ + 'popMenuYourIdentities.qrcode = ' + 'pybitmessage.plugins.qrcodeui [qrcode]' + ], # 'console_scripts': [ # 'pybitmessage = pybitmessage.bitmessagemain:main' # ] - #}, + }, scripts=['src/pybitmessage'] ) except SystemExit: diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6b909164..feaf1c48 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -88,6 +88,12 @@ from statusbar import BMStatusBar import throttle from version import softwareVersion +try: + from plugins.plugin import get_plugins +except ImportError: + get_plugins = False + + def _translate(context, text, disambiguation = None, encoding = None, number = None): if number is None: return QtGui.QApplication.translate(context, text) @@ -3613,7 +3619,7 @@ class MyForm(settingsmixin.SMainWindow): address = self.getCurrentAccount() clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(address)) - + def on_action_ClipboardMessagelist(self): tableWidget = self.getCurrentMessagelist() currentColumn = tableWidget.currentColumn() @@ -3741,6 +3747,12 @@ class MyForm(settingsmixin.SMainWindow): 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)) diff --git a/src/plugins/__init__.py b/src/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py new file mode 100644 index 00000000..288be48a --- /dev/null +++ b/src/plugins/plugin.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +import pkg_resources + + +def get_plugins(group, point, name=None): + for plugin in pkg_resources.iter_entry_points(group): + if plugin.name.startswith(point): + try: + yield plugin.load().connect_plugin + except (AttributeError, pkg_resources.DistributionNotFound): + continue diff --git a/src/plugins/qrcodeui.py b/src/plugins/qrcodeui.py new file mode 100644 index 00000000..25b1e0b1 --- /dev/null +++ b/src/plugins/qrcodeui.py @@ -0,0 +1,101 @@ +# -*- 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/translations/bitmessage.pro b/src/translations/bitmessage.pro index a4e9ff77..818d799d 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -41,7 +41,8 @@ SOURCES = ../addresses.py\ ../bitmessageqt/regenerateaddresses.py\ ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py + ../bitmessageqt/specialaddressbehavior.py\ + ../plugins/qrcodeui.py FORMS = \ ../bitmessageqt/blacklist.ui\ -- 2.45.1 From bbf2264862a7b379b1b917c64c09f7f2225a8466 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 20:54:39 +0100 Subject: [PATCH 0702/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 84767 -> 86543 bytes src/translations/bitmessage_eo.ts | 430 +++++++++++++++++------------- 2 files changed, 246 insertions(+), 184 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 85a6ed578ae0028f9d2c7bcbf4265de7c0cfc68d..eddaf80806073c740d5119e830181d97b2877ddc 100644 GIT binary patch delta 5140 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 AVE_OC delta 3789 zcma)9d0dV88vp*zd)~9W?|aT6%N-ht)WlTMR4U4nWIeNpWT{Z3R4A0CBatmCN2N3+ zni*NL928}5X2^&JQO4X{S;kGHDKRq*_euA2|Go21&-uN}vwffM_kBt&n3o;YKBp;g3$%NyfZ^BC)u#ohu0+>kJAgM$=pDZu$SHx3P6cw=uLP3Aj^+VgG1?0n;1dQ@9>jumQfA6+qu_ zI&J+LjDI!-aFSti#!IR&8j~{xvf21Fd?i@lc6?X_*KM9+ z)w$1sjhR>-l>=twgpE`80-md|E6xIV{v8SyngNDIC@k$p39ZGUZPeO^vpDQY_n+KH zwJrtt*B7W=dJ9;63=hmHL1hUZd7lA9OSFA!XacfUG4-BSV5m7W%hv*}*I3`)gkAV) z)^G4>F!LkKR1*gc*FG#bfD)~{ z!{&ngMK`msc6zU+okh7*p_|It=GhLw$!eBiIM&f}TekZ!waobvD=XxH^_J}HCq;nl zV5c3mhFz0ffX(Ub%~up~_GR`?<_%c>D&xy3a9XlVihK&3ua79m(@fL03zdLch_778(1!@)6M~2`^lcjV}QH422M)h!CVDSQ+*t;cH(p!2&;Sj zxNgTE5nc9imbqS(c_nA%wh#DyGH35i^xV6EbG&to65P+ZNaUDRa<0({1l5O}r{0qM zZRAD;)dEKYx$#Tnz@8*7tesjv!J5myVFJo*x$O2pV4LANmlwE!GIZn4NEMV}0#}(u z=P<@qDMJCBWE*a&J9BdgGvc+;y6@nR0pP5eMSG=Wp@|ky=&XC|_i|lEmkP ze8pdc?bWC9#8-EK!o~7Uu7u%|dijoAVuc;#2U8ghYnJ@bKuU1W3;7|tujqV5Zp!Tr z6x7Sl9Pk2DaPo_d11a!5c}2W6FzQ=*joBr-zfN9vzJ-L!nP>MMi2qK>{Lq)XNNE1S zyH^s=Ul#HnVH}Y98$Y_0Dt5NuC)VEvTpsa(2_3UBiVyK8>=H8h`7Rd$$4Pv29<_An z@BCV)DzKgcpR_g<%r1rB|zk3tKN%G~3H}j+`&isj~990zf1Ak_L z17We8ui8rdwAS;_eLn?0`i5`gsPYA$@UO>oC6-hxx`vaZ!9Od4mlBr0{HlnYA4QUE zuZX_mL{QCFEK4I6*tn2qHuFTc~?!JoK2h2#pE-M~PBa8-`E1DD(XxC7sSsEq0bdYkWPzAJ& zQF_ez2w1aSIk}e3>l~HS($vv`XHL#3jaywl#SB%$gFs-Kzv{&w zdBEt^owlacplVyU1h{oh-TlcFlE`st^KUwY=&{=7S~JmbgW73VJh8%6J#^MQAhba3 z*2M!*&s0ysJ79maI^dlECNopV=qZ6&ebkA+za<(5t5e2PV8 zJ9SP+M^Z1Sb5D_ZldSG9)x+b0W19zr==GRUu#7#jkxRXF-2;vf&dQ=JBCX*oXNkX^KDw6U) zh5oF8B>OADCW)YU;wVhpe26+`=p}^YP)jZ63ZadYz-%7~VIdUIagGpPPnlM4eQ%lA zC?w2!4)$TQkn@xRmhBLVz5bvf^%hM2RPnyI!fCOUDw`u*sG`bVe=l5KOSDYW3pbN# z2kh*#Dw1P&I6SN>HD zWGol&X6wPUcf{KGCgT5iv2I)jC9*@TFCh9h`-_ccM8n4~#70Zfj}Ljtv19sEPD>;0 zsDnQ`NMlZNK%Ad6eN6-nXPXrADu_O6U8K-VLmnwqxfF4DG`(0PEgt_RtxVNY?EPUR z6a`Xz03(5EleT`FM$`VSv~vW_gsZQ#bM6F!xJD|9Yay2OkdB*?pFRtu77b55~EqYnjE#HX!7n=0q1_u)KoeU4Mj~u z>Rf`dujb8NN`Sr4{2n%vAo0-R0zsy-)v7+wlVaY}c3)&o`$L1)YBZfouNt(2dXS^g z7g{_0ZW^+WwBy>g5Y~y>l|Nhrd@{7jtQbi2(5C)M&wbgX%|1~?0VZj4a)_p9wc0&1 z-DtbjY6~o>Bgv1oKjab(f63BT4W?lPI&HtaPFv&GX&-LW*6L{!`q8lI{ST%Yt^M`$ z0kl8_Y2R9C>GOG5H`uy2N$3-uQ`9oB{*QDnS1iCR$LNNc@1#vAL^tsib!t(N?$bi* zh$&V#t1$^g^ z)g8G07OabxuGm)#Jm{q>?VCqR7NRSQZK8c$&|T_5Hv75m$0%|%s#W*clX$#7UH8Yf z^|XXW(wD|-w(;mMlT3jci$13Pc0+ob^uESkS+3Tsr|EU@NP+21ZV|kTDWIU38P|{Q zlC{`|$xY___9{)E9qy;~OvW@Uge5`|gILU=zm`~rmGmp>{n-+J@Wy9!bupr`6e0B2 z64vy8lO=48lUsWm)BbWdwUo_atfz5^d3R%%^Df<%lDiOc5%JzdhojJ}YG>BN=vXnp z)Oc3MSi|3X*4TJ9(fDV@UE{wmJYrsd=amHGg-h*B_`i>u94k`o_!ug6uBqbXIxSNf zecwguEGgw^syy_4>e0sU-}!T~h{)*2j%3_pH~-hbl5)medzILlvwW`WL@fVryE5JZLsm(2U#8+%Wma5&=8;v}pYI=%vTx_nnEMwntL@ND9{R)|{+%4`#27 s>Wp9FI*i4O?8B_1W7#rgM_LQ9ti;imi5&a6WcUQOgq0kb$buFB0r#7F EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -166,52 +166,52 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 Malforviŝi - + View HTML code as formatted text Montri HTML-n kiel aranĝitan tekston - + Save message as... Konservi mesaĝon kiel... - + Mark Unread Marki kiel nelegitan - + New Nova @@ -236,12 +236,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso... - + Email gateway Retpoŝta kluzo @@ -251,37 +251,37 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 - + 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 forviŝi ĝin? - + Waiting for their encryption key. Will request it again soon. Atendado je ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. @@ -291,17 +291,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -311,47 +311,47 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -361,12 +361,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Sendi - + Subscribe Aboni - + Channel Kanalo @@ -376,70 +376,70 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 sekurkopion de tiu dosiero. + 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 redaktante la dosieron keys.dat en la dosierujo + 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 redaktante 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.) + 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 redaktante la dosieron keys.dat en la dosierujo + 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. @@ -509,40 +509,40 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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. + 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. @@ -587,67 +587,67 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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. + Venigis adreson de namecoin-a identigo. - + New Message Nova mesaĝo - + From De - + Sending email gateway registration request Sendado de peto pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (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 Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,94 +815,94 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi 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. Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco 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). - Vi estas uzanta TCP pordo %1 (Tio ĉi estas ŝanĝebla en la agordoj). + Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). @@ -1110,47 +1110,47 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finos... %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage... %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj... %1% - + Saving settings... %1% Konservado de agordoj... %1% - + Shutting down core... %1% Fermado de kerno... %1% - + Stopping notifications... %1% Haltigado de sciigoj... %1% - + Shutdown imminent... %1% Fermado tuj... %1% @@ -1160,17 +1160,17 @@ Are you sure you want to delete the channel? %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage... %1% - + Sent Senditaj @@ -1215,86 +1215,86 @@ Are you sure you want to delete the channel? Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... Kalkulado de laborpruvo, kiu endas por sendi elsendon... - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendado de peto pri ĉifroŝlosilo de ricevonto. - + 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. - + 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. - + Sending public key request. Waiting for reply. Requested at %1 Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 @@ -1304,142 +1304,196 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pord-mapigo farita je pordo %1 - + UPnP port mapping removed UPnP pord-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? - + Problem communicating with proxy: %1. Please check your network settings. Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. - + 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. + + + The name %1 was not found. + La nomo %1 ne trovita. + + + + The namecoin query failed (%1) + La namecoin-peto fiaskis (%1) + + + + The namecoin query failed. + La namecoin-peto fiaskis. + + + + The name %1 has no valid JSON data. + La nomo %1 ne havas ĝustajn JSON-datumojn. + + + + The name %1 has no associated Bitmessage address. + La nomo %1 ne estas atribuita kun bitmesaĝa adreso. + + + + Success! Namecoind version %1 running. + Sukceso! Namecoind versio %1 funkcias. + + + + Success! NMControll is up and running. + Sukceso! NMControl funkcias ĝuste. + + + + Couldn't understand NMControl. + Ne povis kompreni NMControl. + 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. - + + + 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 + + + not recommended for chans malkonsilinda por kanaloj - + Problems connecting? Try enabling UPnP in the Network Settings Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + 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. + 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. - + 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... @@ -1653,7 +1707,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a <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 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> + <html><head/><body><p>Distribuata laŭ 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> @@ -1765,7 +1819,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a 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 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. + 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. @@ -2000,6 +2054,14 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a C PoW modulo nedisponebla. Bonvolu konstrui ĝin.
+ + qrcodeDialog + + + QR-code + QR-kodo + + regenerateAddressesDialog @@ -2020,7 +2082,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a Number of addresses to make based on your passphrase: - Kvanto de farotaj adresoj bazante sur via pasfrazo: + Nombro da farotaj adresoj bazante sur via pasfrazo: @@ -2045,7 +2107,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a 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 markobutono samkiel vi faris kiam vi generis vian adreson unuafoje. + Vi devas marki (aŭ ne marki) ĉi tiun markobutonon samkiel vi faris kiam vi generis vian adreson unuafoje. @@ -2229,7 +2291,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a 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 kiu la sendonto devos fari. Duobligo de tiu valoro, duobligas la kvanton de laboro. + 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. @@ -2239,7 +2301,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a 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, kiuj 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. + 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. @@ -2354,7 +2416,7 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a Maximum outbound connections: [0: none] - Maksimume da eligaj konektoj: [0: none] + Maksimumo de eligaj konektoj: [0: senlima] -- 2.45.1 From fe6f446d072263d87ea73216d279cb41f71bf271 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 20:54:51 +0100 Subject: [PATCH 0703/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 87912 -> 89786 bytes src/translations/bitmessage_pl.ts | 408 +++++++++++++++++------------- 2 files changed, 235 insertions(+), 173 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 16f9595f4a01b87a27c4a7b7cbc718f396afb85f..c02118e4fa3b0d749d8214ba77f336a17e84f342 100644 GIT binary patch delta 4842 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 NfTn2qDIF`3{vTBCQUd@0 delta 3400 zcmX9=c|c8h8-9NG-0j?R?!78wshLD6OC^yO6w0*FHI`DA3PoClnH0K`r4nVLl$40d zkRg;U#xmoxBwLha%m|H1!-OH*_olzzv%c%|Jn!$=Nm+A+EUT-&48UM8!|wp;Mj$v2 zknIO{O#!^Df&PnuDZc>=hXB(D(DMW!+yl(}3Z!*?fsmDuHp~QOU52#94w&QIX7(c{xXpUqj(P7R)Cc{Me%u zcqTMEY5{i+24mZRJ6m9I;72gd8pa75fZ}m5zwrr}VF62}E3mT&1C8nXg7dJx_zl>Q zXbk?9?h|gpeq$l9PY%cW6yV-g4Da3wJ!VE>Yzd_q6$j6pb3mWAPWyBlyqhNjPO0$S z{DLZMgKv%snEeeVL?nV)%Q0!m3F=-_r+qLM{^=25!#pu{KD{4SiGahD(9p@4w#bDF zEX53YI@x#xD=GkwyZFJhL=R+mAijt)8=Z!P9k#%v7g)NRp7(!=r8N_Q^%+oaZQ^6{1t+Rg*Ske zvAAzS2^uEjk^3<~7=t(G^{qhRIL2>(1&oYlhD93S<0;n5SPCrQSnokc!K~t0KhYex zZNcnAo&o=4v!O|pkV|*wVnCIoMzYZ}9D!}8n694w8!?N81X7}ZJY};%{=WBR;UDO~ z4}DmSGZnhwXO=e87B~^fHtP>i%X>Got^25Dqpq{#B^;2hVkd``1Cm{x*0X_K5*>id z6!vx(1)S~4K19pu40L+{M4L-&PM1(%USji*?BY`ryZDtr z#YxHFw`AXmlHm`N>AM#az2^$Lh^du?k9rN}=qib_IZS~bN}^L^fMKB${qk7A##oYG zZvdt}A<5`?pEXUgenBg6z)MmT(ggH9E!jPTz7KAZRB9-}Kj%uWgpgfbFR72VAP_&3 z++Kc`Fd<4BHM79j8p#vsBH+O)JttT3sqezu%;HO=aGEoXG_5z!@=Gb?Zf z_FHh~PCE(pTR9t=KgxN|?#2O1(3Eo!$+5VQ8y1@cW_ghtsWT&gmE7py2B1pEdB;hC z(w$tqDmB24eT;7KuAX{I{6$Y)Q3`@9U;yEyfTJB;l-ADb+)hfb(fgd|< ziy3z{RR`!Axo1a>UD*%7Mvpu+iy$!_vt5%6sT3rUrVFgFq5m;YJ_x7g*OV>;HTJHi}`$#Jbx&mcOq{sHSf_1qo z{iUTp1->Iam(Z8Q%t~5sc!u8hkT#xbBMjBZ*j-!VzcXZxFSY=2u`=h2#Phdb%Ur?< zggJ8Am{(M>%O=^lhc^k;Rij(Fjt4NcPu2jno`EgXyoVl`N^K5Ar0kYb4 z#LvM~WY0V&00T;8Z#b$v%1HK~hXG)2BR7a3N5kvoAq#1iFTLf_b7M%7i{-Jm>}gah z<=(^&mCH-+T_pvyl9y%ENX$g}zJXNOluUW$2E7r`ctu{- zG3%#yliU>fkrlwS>58Ias$h(}Vn@O%0#R?pPZ`7pcy(G!w@!P%xYIWOtEd`B z|L0~X&Nvi;xfvqm|9EdGD6i;96c$$<>@|V=9aHZbqWh)8J zBjsdQKjMFZGO%V7V0la#Kh~BMFiV-fa~g2XRJm~gq4zguW%g+eP_tWkB49LCa7}sQ zxGQy_LV2<59PvF%c}Z_d!c?SeToXeq(J34A=sqAx*>pdMHs~Pb^Y%ijqrKDKzo%Ee zSs6zoSjcyMG8t&E=S@mGgy=nQdFdr7)KcDlO9HWC3hy{$4iJ&aJ9TjZ_&k0*J_A2{ z^MRjL#Q$o3k&Y4w*~cfp`viP?!e@9>V8?-cb{8qIE|=f*d5Ree|!bw;hSOrcRc zk5T!j?FIC!9;-t0sio$1s<4*v1hzq{@K6dkVxlVIA!T|e_={!TuB(z}JOk@@UX}lp z0-o_vRk*ejNSCTAr&7gx?x>Cmuc)$ls?)Vp8T(6hb_LNgXRfMl4S{fOyXub_k4gE4 zsh;OjV*RHI%(sI0pX)8~350&v&w`4(Mi~teR85P)GLDl z>q5ViL4bFVU?)!kPMZp@0rcE&z2Iil6L?l9=zP*?TNZt>tQ#*({9Fz;^s+E#>1b+s zq_8eAg{+N`b*fQM8RrW5H{3}ex(WsSP!g8G!i5#{se_k<3x8J7NybIEou>oqSt>Ln zv=aX(3yofzDUo#HVKLG7?Ny=0kZAb4ztCbv`eAidwCh0skLBVh>y8e#iXMka(3U?F z1C~e9vT_weUk3x$E@D`YzK|5^S21$m7;5c2ae?IJ$|3fwh!Jb`Pm@R>eiQ2=bhP!3ir2KQw68yxJyv4;?%L)OP8|2_t9J z&TndHtEQ<(7`g)EOw=BM-gMBtsrDQGiP&&Ytq-z|0sN1sgUj-$16pO-7^UzRqAES$kBUab>W>_;C!{Z{-Q0d=XvU;%-J+b6ZPBMlmPo( z{VseI&=R7-X&RYft47&_M#z+!u2FsI{BToaK1K(eny1$c_=+4w+}2p@wvzC~YP{a0 z)2zKUiI-`)jPI^l!zzHacACt8=)00oP2Qn$3gDv2&nKFmt9pG-Ai272wF zzQ!apJ+$^Q--Fq{)H+-+rBknycDTtVItlgAjypn~iaV*DP(mF!_MLXx&ow~X6m3ZU zD%zHZwK18Lh}m3ioHbSYVY4>*Tl!x*LYvum07$&4Eir8XJR|M3d#-!}Gx5+?cxr$q zXKi(_LQ=ASwZ|8?(*A#?J@XaW?HStZG33Z=n)dNX;&FPiwtf97Fy}e6X?$`k4b`r_ zDv#J!nN~jWtqQ0tFKyy0Ll2pIv+C^BkI~ttpN&~)WuH$y`c=hPvhLkDTj;V&&RACE zk6?oYMGRsQgRrVPPiCa)YXLvD3<-#U8LZ%qP=wLj#h8ydU%qQYJglm^`Lhz`{{i|z B`fvaM diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index 0875084d..4b2b6371 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -170,52 +170,52 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: 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 @@ -240,12 +240,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Kopiuj adres do schowka - + Special address behavior... Specjalne zachowanie adresu... - + Email gateway Przekaźnik e-mail @@ -255,37 +255,37 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -295,17 +295,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,47 +315,47 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -365,12 +365,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Wyślij - + Subscribe Subskrybuj - + Channel Kanał @@ -380,12 +380,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -394,17 +394,17 @@ It is important that you back up this file. 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.) @@ -413,37 +413,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,47 +1117,47 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów 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% @@ -1167,17 +1167,17 @@ Czy na pewno chcesz usunąć ten kanał? %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 @@ -1222,86 +1222,86 @@ Czy na pewno chcesz usunąć ten kanał? 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 Przekaz wysłane o %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 @@ -1311,142 +1311,196 @@ Odbiorca wymaga trudności: %1 i %2 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. - + + + 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 - + Problems connecting? Try enabling UPnP in the Network Settings Problem z połączeniem? Spróbuj włączyć UPnP w ustawieniach sieci. - + 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. - + 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... @@ -1683,7 +1737,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Użyj czarnej listy (zezwala na wszystkie przychodzące z wyjątkiem od tych na czarnej liście) + Użyj czarnej listy (zezwala na wszystkie przychodzące wiadomości, z wyjątkiem tych na czarnej liście) @@ -2007,6 +2061,14 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Moduł C PoW niedostępny. Prosimy zbudować go. + + qrcodeDialog + + + QR-code + Kod QR + + regenerateAddressesDialog @@ -2115,7 +2177,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Use Identicons - Użyj 'Identiconów' + Użyj graficznych awatarów @@ -2331,7 +2393,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Give up after - Nie wysyłaj ponownie po + Poddaj się po @@ -2361,7 +2423,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Maximum outbound connections: [0: none] - Maksymalnych połączeń wychodzących: [0: none] + Maksymalnych połączeń wychodzących: [0: brak] -- 2.45.1 From 76ae62c1f0fa47483f0fe8d3e4162eaa938a376a Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 16:33:54 +0100 Subject: [PATCH 0704/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 63931 -> 65387 bytes src/translations/bitmessage_ja.ts | 347 +++++++++++++++++------------- 2 files changed, 201 insertions(+), 146 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 2f28764b49a278962b8b6ec52695070ec412fd6c..8bb153f722bb4e14ae205fea85013acba0c656ef 100644 GIT binary patch delta 4539 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 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 を含む) を次のように記入してください: @@ -283,7 +283,7 @@ Please type the desired email address (including @mailchuck.com) below: %1は古いバージョン1のアドレスです。バージョン1のアドレスはサポートが終了しています。すぐに削除しますか? - + Waiting for their encryption key. Will request it again soon. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1161,17 +1161,17 @@ Are you sure you want to delete the channel? %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1216,86 +1216,86 @@ Are you sure you want to delete the channel? アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %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 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました @@ -1315,32 +1315,32 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? - + Doing work necessary to send broadcast. 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1359,88 +1359,143 @@ Receiver's required difficulty: %1 and %2 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が無効になりました。 開発者に報告してください。 - + + + 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 チャンネルにはお勧めしません - + Problems connecting? Try enabling UPnP in the Network Settings 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください - + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... -- 2.45.1 From fd871fca8589fbee920fee8fa6ccf5051efd047f Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 11:26:48 +0100 Subject: [PATCH 0705/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 90153 -> 91853 bytes src/translations/bitmessage_ru.ts | 324 +++++++++++++++++------------- 2 files changed, 189 insertions(+), 135 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 9b7a09a9afb9c2cca2b14ccdf26cd57d8714c0cc..619e21fdf1089434e73f7438017fcfb0f55541d5 100644 GIT binary patch delta 4826 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 P%EL>-#PaC}qxSp{#TEF9 diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index c5cbbc69..a7115a1c 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -58,12 +58,12 @@ 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -283,7 +283,7 @@ Please type the desired email address (including @mailchuck.com) below: Один из Ваших адресов, %1, является устаревшим адресом версии 1. Адреса версии 1 больше не поддерживаются. Хотите ли Вы удалить его сейчас? - + Waiting for their encryption key. Will request it again soon. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: Отправить - + Subscribe Подписки - + Channel Канал @@ -378,13 +378,13 @@ Please type the desired email address (including @mailchuck.com) below: Выйти - + 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. @@ -393,19 +393,19 @@ 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.) @@ -415,37 +415,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,67 +596,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1169,17 +1169,17 @@ Are you sure you want to delete the channel? %n час%n часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправленные @@ -1283,7 +1283,7 @@ Receiver's required difficulty: %1 and %2 Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. @@ -1293,7 +1293,7 @@ Receiver's required difficulty: %1 and %2 Сообщение отправлено. Ожидаем подтверждения. Отправлено на %1 - + Doing work necessary to request encryption key. Выполнение работы, требуемой для запроса ключа шифрования. @@ -1320,35 +1320,35 @@ Receiver's required difficulty: %1 and %2 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1367,88 +1367,142 @@ Receiver's required difficulty: %1 and %2 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. + Успех! NMControl запущен и работает. + + + + Couldn't understand NMControl. + Не удалось разобрать ответ NMControl. + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + + + 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 не рекомендовано для чанов - + Problems connecting? Try enabling UPnP in the Network Settings Проблемы подключения? Попробуйте включить UPnP в сетевых настройках. - + 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. - + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? - + 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... Ожидание окончания синхронизации... -- 2.45.1 From f4caf5f6a4d17b9ffee6258ecb3a17957a41cb9b Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sat, 4 Mar 2017 14:14:22 +0100 Subject: [PATCH 0706/1102] Auto-updated language fr from transifex --- src/translations/bitmessage_fr.qm | Bin 94455 -> 95018 bytes src/translations/bitmessage_fr.ts | 551 +++++++++++++++--------------- 2 files changed, 283 insertions(+), 268 deletions(-) diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 1796355d71586cdaf7beb15f2417531d2eb82658..9e97aa12752666d4ea9e40057829d3cf7ffa880f 100644 GIT binary patch delta 3447 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 TH0Z+fdxo+uRYRt;b6x%i?rig7 delta 2983 zcmX9=d0b6-8~^_9x#uqDoO`Yo`#X2CC6v?*5~WmRyJTq*31t$(G^2&O#Y~h;y z08U^7GXP~4u%ry&zXvL90bhH-K>}u-1rn-&;KB6&G$6toY*9+qRD+4P2cND4G6TWy zcncKo1E1#&Y<){O3)oo%zO)!@Rs#5{RIs1}Q0?dF^g*coeZa!HLhDmaw?BqlSO-kl z0t=rPz@L_|IJ5<<+eY+?`v&;_OZ2d+e{C*kxn9Zd0qb5=f3 z^D{;^t_Pm|Zq_k_;vYA&12dSs9Wf*JI2Bshi7kiVpB4!=wHX0R;=zpZ2s}*JjvRqG z(XL=~hGDKMjnZwyd^Hg=aSB!&ih&$E#O$Uh<6RL~I1~ung*D%rh@@n!sr3VLOR+X8 z7i>Z_Hq0*kK;Vv8158X+h&@XzfvhwXS6P91?M3Nk;-{kn2iy!`icM(HrvvXSal1Dq zHt+=QdmRI$|DyFwGf?Wlv;{8#&(+Lww+v=+ntj}hcwZC2`Z!jDja|mk zV=(R^`!tafnW15>7G;!S_I>6#cO>xLE@o_`gC0f}8bles%3%v31Ia^KL>nFKvYkbZ zq6&9jVX5<|!i&q<)pg z9ti(-RMZ_QBxrnxW>d5RrxSX~SV2>}CAM!P2 zHj+Cg{Y07!=FV@Y-?1yXI(0bUSn~lHJh;mnjbug(?r{KBxZ9I!j!gv4bmQJsk@ix9 zmHLmq0ka~UPuiX2tL#=1M3S1PbUR9h^}VR{GE&F>xUclR@~o-wFy*llcd!Ai z%9Bq9flchL{3&h#FlC>z(ee~MSDN1`4JN6Kca0#y6s7ayUQ+t*Ui{=c*GPcf_>e?u zaNc}AEP(jWtl}3BKS?}x@GJ5wD9lDa$+-?}RO2zPtYX8gx zno9xdaHl0SA>OIi?;Zp#m^dzIMQ-3r3H(Q`OpY+nyQbf?YjEA zbdn$aMEEz zch@#%*%Jp|<=Q`HwE?561;I25th=8et|C3+H^FLZBH3W2U=?0R196qmmpvd3J`rr! zUjt*u1^?7i;%1Z(mP_0Xcp`*9nL@&;6e7YX;H*+1@(v~X`0NK{_Ax@@TpGk4SA^V0 z6z@ubQ0D&DM2d43DgxRmqgtU_d`THT6;9MqWnG8_ES<#s(3DG32@3uJa>;0Ea@xW$T5OB9usfI zHG|De5^wo#1qN4&cT9U|Y3de;Pb>!#rJspUY$9pt-IIpB*LeXidDs($e-=pIhiL?) zRY-veOM!uvQrN5cWbrpr__loDri--nz&N6IowRb|F0jcd(igvu2Kr5t;({1(c(JtU zOeV=tl(NT?CW39G?1htnN6#hG{@53^ZR@3SOS-7f4XNCXdU@oaRQ_J?2eYKA6^nr8 zwNed>rkU3N12Vs!(vRCbfz3;#x<`qCPm)w0X#`%(lN$8RK$4qu^VLT*sxL^tuDMFP zCro;|fm*b6icZsXn0oJ{>%EM$bhpJu*MHGz`py`kv(2FZF>`bd<`Up#yKY!o4XN72 zd|Mc5@))dJ+DdUQjMPO{Mv>9i>Qn5_Fd!UGIRGEPt@?0jTR59*9{q-?!x0QtIy+;5x_xO`h4 z+?DQG9V*)!calj4ak6hK?HiHaX)Ny;$BZ=Ty=lVM%gsF1hcT zom>#?0(|{Q-eW_B=G>Mq=8?Jh0J+YQBnEWiz!{zRS6U~wdCE79>wqVk56B!I%Fq1z zlS#%3a=SqWv)!k69MB68eD%&zU(&d>)(<~t0P|j?AKg2fJ|8&!d>8n1@r}-4Fulb^xmS>&*R9C{X68)7ZBW=fD^$*?1o!bZL-){a2 m%rB6ZLD+cng?9gn9=b^x70Y)iy(%8wX^K7i*&KGd$NvGuV2xk^ diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index 16d06f3d..0a041f2d 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -58,12 +58,12 @@ 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) : @@ -83,7 +83,7 @@ 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: @@ -173,122 +173,122 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : 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. @@ -298,17 +298,17 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -318,47 +318,47 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -368,12 +368,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Envoyer - + Subscribe S’abonner - + Channel Canal @@ -383,12 +383,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -396,54 +396,54 @@ It is important that you back up this file. 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. @@ -513,22 +513,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -537,17 +537,17 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -592,217 +592,217 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + 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 De - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? Ê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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? Ê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). @@ -1105,57 +1105,57 @@ Are you sure you want to delete the channel? 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% @@ -1165,42 +1165,42 @@ Are you sure you want to delete the channel? %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 - + 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… - + Generating %1 new addresses. Production de %1 nouvelles adresses. - + %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. - + Done generating address La production d’une adresse a été effectuée @@ -1210,231 +1210,241 @@ Are you sure you want to delete the channel? - + Disk full Disque plein - + 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. - + 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. - + Doing work necessary to send broadcast... Travail en cours afin d’envoyer le message de diffusion… - + Broadcast sent on %1 Message de diffusion envoyé %1 - + Encryption key was requested earlier. La clé de chiffrement a été demandée plus tôt. - + Sending a request for the recipient's encryption key. Envoi d’une demande de la clé de chiffrement du destinataire. - + Looking up the receiver's public key Recherche de la clé publique du récepteur - + 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 - + 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. - + 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 - + 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 - + 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 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. - + Message sent. Waiting for acknowledgement. Sent on %1 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. - + 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. - + 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 - + UPnP port mapping established on port %1 Transfert de port UPnP établi sur le port %1 - + UPnP port mapping removed Transfert de port UPnP retiré - + Mark all messages as read Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? - + Doing work necessary to send broadcast. Travail en cours afin d’envoyer la diffusion. - + 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 - + Wait until these tasks finish? Attendre jusqu'à ce que ces tâches se terminent ? - + 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. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Problème d’authentification SOCKS5 : %1. Veuillez vérifier vos réglages SOCKS5. - + 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. - + 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. - + + not recommended for chans + pas recommandé pour les canaux + + + + Problems connecting? Try enabling UPnP in the Network Settings + Des difficultés à se connecter ? Essayez de permettre UPnP dans les "Paramètres réseau" + + + 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 - + 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. - + 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. - + 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. - + 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. - + 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. - + 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: Something is wrong with the recipient address %1. Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. - + 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 ? - + Not connected Non connecté - + 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 ? - + Waiting for network connection... En attente de connexion réseau... - + Waiting for finishing synchronisation... En attente d'achèvement de la synchronisation... @@ -1630,27 +1640,27 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog - + About À propos - + 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>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. @@ -1660,7 +1670,7 @@ The 'Random Number' option is selected by default but deterministic ad - + <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> @@ -1693,12 +1703,12 @@ The 'Random Number' option is selected by default but deterministic ad Adresse - + Blacklist Liste noire - + Whitelist Liste blanche @@ -1820,27 +1830,27 @@ The 'Random Number' option is selected by default but deterministic ad Connexions - + 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 @@ -1860,27 +1870,27 @@ The 'Random Number' option is selected by default but deterministic ad 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. @@ -1966,12 +1976,12 @@ The 'Random Number' option is selected by default but deterministic ad 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 @@ -1979,17 +1989,17 @@ The 'Random Number' option is selected by default but deterministic ad 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. @@ -2050,218 +2060,218 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings Paramètres - + Start Bitmessage on user login 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 - + 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. - + 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 - + Listen for connections on 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 : - + 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 - + 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. - + 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é. - + Demanded difficulty Difficulté exigé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. - + Maximum acceptable total difficulty: Difficulté maximale acceptée : - + Maximum acceptable small message difficulty: Difficulté maximale acceptée pour les messages courts : - + Max acceptable difficulty Difficulté maximale acceptée @@ -2271,82 +2281,87 @@ The 'Random Number' option is selected by default but deterministic ad - + <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 - + <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) : -- 2.45.1 From 5c2af003060a479f2ac484fe6210520461e1854a Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 22:06:42 +0100 Subject: [PATCH 0707/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 94230 -> 96084 bytes src/translations/bitmessage_de.ts | 393 +++++++++++++++++------------- 2 files changed, 228 insertions(+), 165 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 3865eea84079c35a828b50b7f061a019fae15a40..4a74855d7a47ec4a283f69ca93a1174c3d40a899 100644 GIT binary patch delta 4736 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 EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -174,52 +174,52 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 @@ -244,12 +244,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + Email gateway E-Mail Schnittstelle @@ -259,37 +259,37 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 - + 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. - + You may manage your keys by editing the keys.dat file stored in %1 It is important that you back up this file. @@ -398,17 +398,17 @@ It is important that you back up this file. Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. - + 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 anlegen. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1169,17 +1169,17 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Stunde%n Stunden - + %n day(s) %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1224,85 +1224,85 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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... - + 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. - + 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 @@ -1317,37 +1317,37 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1366,88 +1366,143 @@ Receiver's required difficulty: %1 and %2 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. + + + The name %1 was not found. + Der Name %1 wurde nicht gefunden. + + + + The namecoin query failed (%1) + Namecoin-abfrage fehlgeschlagen (%1) + + + + The namecoin query failed. + Namecoin-abfrage fehlgeschlagen. + + + + The name %1 has no valid JSON data. + Der Name %1 beinhaltet keine gültige JSON-Daten. + + + + The name %1 has no associated Bitmessage address. + Der Name %1 hat keine zugewiesene Bitmessageaddresse. + + + + Success! Namecoind version %1 running. + Erfolg! Namecoind Version %1 läuft. + + + + Success! NMControll is up and running. + Erfolg! NMControl läuft. + + + + Couldn't understand NMControl. + Kann NMControl nicht verstehen. + 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. - + + + 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 + + +Wilkommen zu einfacher und sicherer Bitmessage +* senden Sie Nachrichten an andere Leute +* senden Sie Rundruf-Nachrichte wie bei Twitter oder +* diskutieren Sie mit anderen Leuten in Chans + + + + not recommended for chans für Chans nicht empfohlen - + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + 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. - + 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... @@ -2008,6 +2063,14 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi C-PoW-Modul nicht verfügbar. Bitte erstellen Sie es. + + qrcodeDialog + + + QR-code + QR-Code + + regenerateAddressesDialog -- 2.45.1 From 5d545dbcab5ec8920f380054088027d94cf4d6c9 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 6 Mar 2017 22:16:29 +0100 Subject: [PATCH 0708/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 86876 -> 88644 bytes src/translations/bitmessage_sk.ts | 393 +++++++++++++++++------------- 2 files changed, 228 insertions(+), 165 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 89a52107cdea3baef18e46e93b4e416079b0c4b0..9a3e3670bf05e692e2084bef71abbc91bd73c4c9 100644 GIT binary patch delta 4821 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 delta 3315 zcmX9=c|c8h8-9NGo^$U#_nv$2RLmGYX|&kdM_N#*5W2>em{cRpM4O#Nx27gZ6fG(# zOS0BTStB9Fpe#|ULGvj~L(JHHroNZ{dhhR?d*1bVp5I$t&i_%wr}fb91z-oJSqgBQ zfPf1C|0__q92jp23_1x+{|#8|4tzhDp6>xdJit6JfV*xE1ik>*I0u+J0o+qtAc&rS zvK z1kV!`I2@XtwZIrX3_M=~w?Dw3bTiPEjowikf$c#st?LB*@?fEG1$Gu=NN@Uoo((K7 z_XV>NV0V$uQ7y3Fln)%pfMb0;&}4++Uv)r_Io0qiOaQ{}V_a4>(7&|XwwA%`@if5k z6}&TFP=)dE&Qg*s#^eR7zy@-dy7CltZ)3M@u7FSS0xb=9s%+az{3j5jSKa_`qfxbK$(r6f~cL=z?4`-7t!;=S`1$Y>X#>I6& z+%w$mLkVhjRTN5rb<^4DZ}$O`;%+UW(4AY zBn@lMgV~*vG--YSI{zbi$SnbyKkB7o3J>PGSgO8p7#Qdx)&4@W`Xf$iboc?$r9oE2RVrr4AxFR#Z!eMaF>juab_`nSiBpu+LEp4Akm2R?=cC3s6%3es{9Vd{kzQt+#ZUjE=;j{sSa;sAA%l)$m zd{?-U$4DchmV6SC-cU*ptVd-0un| zzUIz89Yle%x#}o$V4M+GZ+MR0kKvlmyd$_x`6kOA#7|6<>$?$*~K5{e{?tt4D;Y4^Qon-JRfUc3)Xiv zA0HbGHZ+#cb{+&=DCcuuE&(%Y=C>wMoTO!Z$vPfzGULlSp%Cl^R?@V zpH>RKecWW?{}cX=lqwHf%fIz7AYp2d87v@2j#p)Yi)oe}(X#L#BS?~)Ws$e-fg$Cx zWog8sp+{s%%V{*evt@Y`+Q2+^%L@OvMhfUD+nY`!>32s~JcJ6HW*{rus5b)cc*%}^ znssZF?9v6-+!!$~G#Z|eZvKIK)MDFs#0O03p zxpyO-*DjX(q^$uOx5$I-=96G0%i{~&$lt&6#7SR+4GWTQbhrmh66I-M?jjn-%hU92 zI>74-d1f6|^xX-0ZfFTGt65&KgDM!^Cf^yAKp=9IA4nlKz^B`qKkK&52Hp0dOnz)4 zeV_G0e$F8u%;lN02aQA6`t0lfZG+xyJiy@4=OedCiGT6P^4FBfK#Uwr+i0K1$By3 z6|RJZUW&_mt4WGqD6Z&@0W&*AQ(^>=mZ)gTp|j6ZMeALExRWQW^!>Q;aJ zvn`aExr2&%mk|H6N>xG>q2Kj_N-4cT85yaRtxKu$29-LF77^jDs#h+}(xO;p@v0IS z@K`nQv_EY}gH^V&7@*Qp$7EsHmWII`>3#0s-S4X zOy_ge`c?5{PpHz)H0deh8dYwcI|;;hsytyRfhk^fDRw?kI!$%yza_xd{i=o>9oUyl z)fm-5{I^pzjnAY+wyRop5Pe@atDYJX4cnttPfbWaOwWk6pU}VQzBtN~I#?efdK{4g zYaWWeYeET}_2RtO0VM77#NaG_K5%ih7+O4rS{p1b^x8%%(+P2D^KifkD+i-G1T?Z3o@giDKhx+TE zv@)F*U#+DPC27=(hev3JyVZTd2uw8()Mi2FX-R#ow#cCXVQy-x^!>oSgKFF43c|=G zwey=wx>YmPBMe=E3B1~4mKQC$PY=e+7HgDSGlJWMxxcLSCgZ61J(I=YJu~G>iWypL_;HWYwBDYiQ_~~NoOGeT#&iswPe5j!ktJ37{(v@aEPancZE8~~uue@!RYS1Yw8<21mZ z^R>tO<&%(EWc@d#)$hf-3FJ2y!%Tg0^iW@p#>D+7BBNXbBCVn`Ufky48D+ kG9UFN EmailGatewayRegistrationDialog - + Registration failed: Registrácia zlyhala: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: @@ -171,52 +171,52 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: 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á @@ -241,12 +241,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Kopírovať adresu do clipboardu - + Special address behavior... Zvláštne správanie adresy... - + Email gateway E-mailová brána @@ -256,37 +256,37 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -296,17 +296,17 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -316,47 +316,47 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -366,12 +366,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Odoslať - + Subscribe Prihlásiť sa k odberu - + Channel Kanál @@ -381,12 +381,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -395,17 +395,17 @@ It is important that you back up this file. 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.) @@ -414,37 +414,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -514,22 +514,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +537,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,67 +592,67 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 Od - + Sending email gateway registration request Odosielam požiadavku o registráciu na e-mailovej bráne @@ -667,142 +667,142 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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 Odosielam žiadosť o odhlásenie z e-mailovej brány - + Sending email gateway status request Odosielam požiadavku o stave e-mailovej brány - + 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. Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1115,47 +1115,47 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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% @@ -1165,17 +1165,17 @@ Ste si istý, že chcete kanál odstrániť? %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é @@ -1220,86 +1220,86 @@ Ste si istý, že chcete kanál odstrániť? 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 @@ -1314,37 +1314,37 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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? @@ -1363,88 +1363,143 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. - + + + 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 - + Problems connecting? Try enabling UPnP in the Network Settings Problémy so spojením? Skúste zapnúť UPnP v Nastaveniach siete - + 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. - + 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... @@ -2005,6 +2060,14 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr C PoW modul nie je dostupný. Prosím, zostavte ho. + + qrcodeDialog + + + QR-code + QR kód + + regenerateAddressesDialog -- 2.45.1 From 964809bbd6a3896f343696dcd99a4d8a2cb1e3e9 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 7 Mar 2017 10:23:54 +0100 Subject: [PATCH 0709/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 91853 -> 91913 bytes src/translations/bitmessage_ru.ts | 312 +++++++++++++++--------------- 2 files changed, 160 insertions(+), 152 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 619e21fdf1089434e73f7438017fcfb0f55541d5..f6e79656161ac4b6782468ae110b55ca9d5fa6b8 100644 GIT binary patch delta 682 zcmW+!T}V>_6h7zvdhe#9WRl@-lD4GWFx{rBP4ZvK+0;2FibPIRQu8mcNCWA|Kx&+a z%uF9b(qaXHXoW9D5yX6`3?v3&j6lec9G0YZ>*4Ty95~;1INu2b_@M><)-LH60Hg!z z-un^_j3?e#R+vzl0Q}q#VEIcBrddEw4v5tSDo*+QMflqncH<_MVSLgSxLYm&=C?u3 zj2*zd7izn$fG3lnPPn1YuhA8>;3t|#1$!un21a2ik}+a0*%$?vsGcducJea=s$d%1 zfKxQg#^Y0(WQ(LZ*5=p;=yXz;&B0bOapkG^x!n&v02_UrZ8jg!u5fvdX@IYfxZ=P% zK;sbSePU1-RW-Q=)iRPFNOJIlm%V_6P5iLc05E3bN3v4^J_0}bvl}ougZ#W6muZn# zq&Gt4WLQ1MIE8s7=B{x4d_O?lfG}1X0(6HcMX*Q{LasA2GujJ8he*hK^%a84w>X9>umn@h~HmNzrt#Lfx2AFEoICrK2b9-n; zQgDP8B}H;+mikr!OH8z-_Fhw>Y>_&(=SuDY9)CvlvW{`GbV<&^6`GgzQkM4f#Sdy` zmGoV1V$5;m(zvmU{2C+fP*Bs6x)AllnGBe@6Sb|20!(}nZA?i3kj&9X+IsHw_<>eW^=2V*IqHH$_17Bz;@?O_&62dg4yt0J*RXViidDj_7>3{PY-jVFof$?nGTcd)iIfw=ZK-VYZ~mb!iJZoU1pXFcpad3aU{)(k z*B4Y`7J-n3mKSCOUK)j{7v)8WQOPQbtWXi8vO`x7eDFTs3vYN%oShZ>cSt`0q=T$O zkp#O?y&Neoj4$~F@mUz;zXrpI4pd`;vC5~hJu+HE(~E^D9Pxy@ zKcX7fXt;d369{%021}!$z&NKGT+&IyQkCY;Ti_OhD{h~$`>q$r`)IsawhL68#1n=F zp=^~CjP~um&6q>KR)D^>m?NH}Am3gN881k(cAw?wph6{ z_!Z>rlLtQk2IdaPW1dY={uY}h7m4hX8sluHisyfU2Q8+`tr4wD4o^uc)$x*~N{Obo z9V?&`Vo_Ep!b!3##jTtwxdY1WQQ8-?0o!qx#5im9iHbN*-KA( zT27Yq%HrAA+D+wkxj}Gz;E*Xm9-c6z(F{jTt 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 Новый адрес @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: Скопировать адрес в буфер обмена - + Special address behavior... Особое поведение адресов... - + Email gateway Email-шлюз @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: Удалить - + 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: Отправить - + Subscribe Подписки - + Channel Канал @@ -378,13 +378,13 @@ Please type the desired email address (including @mailchuck.com) below: Выйти - + 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. @@ -393,19 +393,19 @@ 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.) @@ -415,37 +415,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,67 +596,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1169,17 +1169,17 @@ Are you sure you want to delete the channel? %n час%n часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправленные @@ -1283,7 +1283,7 @@ Receiver's required difficulty: %1 and %2 Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. @@ -1293,7 +1293,7 @@ Receiver's required difficulty: %1 and %2 Сообщение отправлено. Ожидаем подтверждения. Отправлено на %1 - + Doing work necessary to request encryption key. Выполнение работы, требуемой для запроса ключа шифрования. @@ -1318,37 +1318,37 @@ Receiver's required difficulty: %1 and %2 Распределение портов 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1413,7 +1413,7 @@ Receiver's required difficulty: %1 and %2 Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1427,82 +1427,82 @@ Receiver's required difficulty: %1 and %2 * участвуйте в обсуждениях в чанах - + not recommended for chans не рекомендовано для чанов - + Problems connecting? Try enabling UPnP in the Network Settings Проблемы подключения? Попробуйте включить UPnP в сетевых настройках. - + 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. - + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? - + 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... Ожидание окончания синхронизации... @@ -2062,6 +2062,14 @@ The 'Random Number' option is selected by default but deterministic ad Модуль C для PoW недоступен. Пожалуйста, соберите его. + + qrcodeDialog + + + QR-code + QR-код + + regenerateAddressesDialog -- 2.45.1 From b28fe3a220a7ac1b8dd5a9c9e0baf54b9c6ce723 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 7 Mar 2017 12:08:19 +0100 Subject: [PATCH 0710/1102] Auto-updated language fr from transifex --- src/translations/bitmessage_fr.qm | Bin 95018 -> 97042 bytes src/translations/bitmessage_fr.ts | 365 ++++++++++++++++++------------ 2 files changed, 214 insertions(+), 151 deletions(-) diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 9e97aa12752666d4ea9e40057829d3cf7ffa880f..2eccb916105d2b8c6b91deea59a3f929ba821f02 100644 GIT binary patch delta 4894 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 CGh4O* delta 3315 zcmX9=c|c8h8-9NG+;i_e=bn47vSj&&s1TJz+Cyb6H$;gfOD0i?nHJG4S+i7@B#Fq3 zHA^)`CJckIBqCFo=^MLA2w6Vrd(~ghJ?GqWe((D}&-=XZrY8R26F$9zVLyO@V3t}y zo&n4&0QjRo@jzg-6<{p^lP&?vN`Yzp=>Ak7%nK|u5AsS2Ap8~NHPe9w-jLVZ0udKm zktq&=UoQtTW`ocA4D2fepW_8=;|V7LIR)Sk=Ytviv%r_G1)FvmiUS;d_$rkCBf#d` zLKtz94t@dco(f>pCK!!)3)E-8==dhE&PsHR-v}H_f>~8F5PAT;RqjBcDf)M%{~x*r zt1I7ujpH%!B3-YV0K1G_;Pg#6RHp!Mg5hG)00X}7f)V*EfY?Ti%DezrIJM!I(-`y2 z4{&*oaa&(ghKn#RQzXoRZ}<|h5e1kScbclVrw!lQ!ap?}Y`lPgdGvhzR!k|TfESAZGAa4XIQVC5kLs4Pvp%r1~zR)erbCO$Q*|^OafzxIO0an7dk;3jT(-cv7|87=i&zs0IHk!9%c20= zkFwNiBe32+vh}UccgZ#^Yyi%!lkEz51oZWi{S-w14<8^a)KY*S_R6k@5N_@-tBx=S z5)HDu%g%%O7RhS0Gr>Cf$)3m;18<`ZoV1=NQPgponYk%S)RbmKd znnNNwGl(;D+)JvDYV|J((LmqXxKa z!i|ZR110UaurE~l$6OQhl|TFX+1jP@Is*ekE=n zHp-LV-vP?J?+i!&dv~da}GQrvp_cN`C5~ zJ6N9|<>%@x>EKNHg?J0VXTQAK_&0j4lh>YkOGf3*vwJqw|E?=}hu2xa(nq}0mDgZe zYu-7GM3}#g_jpGcyL!mvNq-Yk!U?XyK!BsiYoj_$0du zFee3{k`xLyv4GEVvIJ_L^Vx3~gW25WcdVgvGAsFlwLIY3g)f@SQAQDO_*3880C{)# zignbV-Xi~ElrLZt$~SS8dF*cfgO?E*Q-s1OoId35p$J)&3#PPFM9d{Biq|Nj?${Ak zu8JSisf#8)RIG_1YC_g3a>hOen=@09fBy!sGE1?4Gf~p3NO7b;B{p@bqHv?3J@9J0 zqU0ObU*0G#PuBvTjf&d`jmg3OP(1J_j(jzW1_d2dAX6HrQ@|{M>F{|lJtqD=2ZV%B9U z(+!U)68!_^)~Z|};H)xxegQDcO1UeKG8kE_+!McoL^MfxXgzfU!rHL!jW%qIX~X88 z$`WsS|0fgWZ}wD~z@y4a|6o8kqWt>~`Nqke%BT8o6gDb9Sd;@5CMrk88>&={%Ha5> z0m#~|@^ha|{hzH0EZ+iHj#tHwupvz-RjGSv;ys$K%IHVxtua+?KC1;PndU5bqX`zqm%Ki&v#cxzs4c*C@o~mkBMFP9hRJGgbI{3Zn(Su-M_7m01&$+<3gf?s} zHmI7GM*|HXgbq*qz>Inb-F_w`nrI~SzWRn7N-Nl9#Zy;w6&!+Q12G*0$9B$uct-F+ z3vf0@2y79l{}YA9dJ15^sgV4sncC1%SU-jic8(M_x03_gBZVz52LWR*3EAH&l0RL@ z`NbK`#BfO1neqp4$4J=iN+0~XQaGMR;)}EruG@75Gy9)#{VSE!48o0v)Mk5KgCo-r?Q5{XH$6sRmaf#%Zuf+DD6=dbnVlVcHDl-#R8ot2F|^(XOn*ZRn?ncsUlPOXDAM|ot;npK#Ka&PA|4aO z?5A|#?H*!*`)3mAII%FGnF9JlJgI(10e%$ER#0Z0j)~`!s4e#~v2qoOa1j}t~s z)gr#!MuB-eRI_mf)c^bH)IvO|-!o1vayNnXrfTug4`AlSYE3dNB4!cl&e_DJ($;NO^5WY*uQC$t=(#HOfc zCy-`LJk;x!q!5bg^fR>v;-arQyULRcVyrqx7))Z?qQ0Co4><3tzWh%CZ8FyCyW90( z1D(`0@eN>;cc^PeZw2}lsq6A+?rZDR^~Qa`WKY!frsN;PXG*r;)SuT*8fHZmeAz?t zDkeiqEtIA#n-BCUlIFahL4NU33e7a+0<|U5{39Mz5+*Givy)b)Jn4sfE`XV@6dy=d z`%AR6?)P-CcB#^qp`?lFF4C4+V}a+<(t)_Qv?o+bCyePkJ?}~<+=$AOGU>#(E;ybe zl}3?hU;R%iV~fc-2ecyd8!Vm491d)lCsi1pCITapq{?tTO}+clOnN{**?%NxkkfffsZH zHqVqQlKo73Er;4rQLU{Q(1qF%ZP;gG8#W4U`1P!|Mo$~jOT+5cA8f!J?W+mqv_P!Y zHh0&8_3fh@V9}L~X0*;O@<&=eH|y*#cc&%uADv6LEnpVQb>6>FrIxwseDkTaS3Px8 zkClT7zPga?6=bzJy2vyq8a6GuXe-LxI6;>@lHTvqL6=s099TV5m*2gH*7}&=bqB9E zgW1*U3Px#xPm#LP9=YUXp}Mjk8fgC4=zi-+c(hn|D^gE${GRTy8})J4VBO~pE5Q5~ t)1;X@bF;03e_@zrMbE<0fqK)zbrXBcE)+`^iG|h|0^>_gyD@*a{{u@^;GqBj diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index 0a041f2d..43d46f40 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -58,12 +58,12 @@ 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) : @@ -173,52 +173,52 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : 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 @@ -243,12 +243,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Copier l’adresse dans le presse-papier - + Special address behavior... Comportement spécial de l’adresse… - + Email gateway Passerelle de courriel @@ -258,37 +258,37 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -298,17 +298,17 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -318,47 +318,47 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -368,12 +368,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Envoyer - + Subscribe S’abonner - + Channel Canal @@ -383,12 +383,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -396,54 +396,54 @@ It is important that you back up this file. 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. @@ -513,22 +513,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -537,17 +537,17 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -592,67 +592,67 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + 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 De - + Sending email gateway registration request Envoi de la demande d’inscription de la passerelle de courriel @@ -667,142 +667,142 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? Ê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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? Ê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). @@ -1115,47 +1115,47 @@ Are you sure you want to delete the channel? 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% @@ -1165,17 +1165,17 @@ Are you sure you want to delete the channel? %n heure%n heures - + %n day(s) %n jour%n jours - + Shutting down PyBitmessage... %1% PyBitmessage en cours d’arrêt… %1% - + Sent Envoyé @@ -1279,7 +1279,7 @@ Difficulté requise du destinataire : %1 et %2 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 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. @@ -1289,7 +1289,7 @@ Difficulté requise du destinataire : %1 et %2 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. @@ -1314,37 +1314,37 @@ Difficulté requise du destinataire : %1 et %2 Transfert de port UPnP retiré - + Mark all messages as read Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? - + Doing work necessary to send broadcast. Travail en cours afin d’envoyer la diffusion. - + 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 - + Wait until these tasks finish? Attendre jusqu'à ce que ces tâches se terminent ? @@ -1363,88 +1363,143 @@ Difficulté requise du destinataire : %1 et %2 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. + + + The name %1 was not found. + Le nom %1 n'a pas été trouvé. + + + + The namecoin query failed (%1) + La requête Namecoin a échouée (%1) + + + + The namecoin query failed. + La requête Namecoin a échouée. + + + + The name %1 has no valid JSON data. + Le nom %1 n'a aucune donnée JSON valide. + + + + The name %1 has no associated Bitmessage address. + Le nom %1 n'a aucune adresse Bitmessage d'associée. + + + + Success! Namecoind version %1 running. + Succès ! Namecoind version %1 en cours d'exécution. + + + + Success! NMControll is up and running. + Succès ! NMControll est debout et en cours d'exécution. + + + + Couldn't understand NMControl. + Ne pouvait pas comprendre NMControl. + 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. - + + + 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 + + + + not recommended for chans pas recommandé pour les canaux - + Problems connecting? Try enabling UPnP in the Network Settings Des difficultés à se connecter ? Essayez de permettre UPnP dans les "Paramètres réseau" - + 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 - + 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. - + 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. - + 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. - + 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. - + 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. - + 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: Something is wrong with the recipient address %1. Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. - + 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 ? - + Not connected Non connecté - + 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 ? - + Waiting for network connection... En attente de connexion réseau... - + Waiting for finishing synchronisation... En attente d'achèvement de la synchronisation... @@ -2004,6 +2059,14 @@ The 'Random Number' option is selected by default but deterministic ad Module PoW C non disponible. Veuillez le construire. + + qrcodeDialog + + + QR-code + QR-code + + regenerateAddressesDialog -- 2.45.1 From 4014b80b7cc0c9e80363455d75f050f1ec56ccb1 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 8 Mar 2017 17:25:19 +0100 Subject: [PATCH 0711/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 65387 -> 65447 bytes src/translations/bitmessage_ja.ts | 312 +++++++++++++++--------------- 2 files changed, 160 insertions(+), 152 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 8bb153f722bb4e14ae205fea85013acba0c656ef..da6c715b15c0b1ffea8a707e3fcbaa5d83dafa2c 100644 GIT binary patch delta 694 zcmXAnZAep57{~wT?%q4^-KGpGF>sSeOhGp-oek6=MT=6Vs1?2tIhInIiPGyb%w7c1 z@f3uV^+7R(S!7~}(pL?PFeEjWnfaEPs2LTeo$$lq_rQ5x&h!7Dg$+&HrlxV5@(VyT z@H*ZTY+>`Bqp3lCkY3&a7FHm)Yk(Cav^go9B_3}ooARvX*nJ{0FZA)ksx7wEBd4we z_!5rX;!B(jIM$sAgi1J3VF$itAWyF2G*c~$6DA_4pPAVU@-Yi5CWByMtCS#^gxMg< z7c$s0@(ONYT2GOhLN-J7nn3oJS~aOkwI(4w1X#?VHBAzGLa}0c#3U1UbQ}jd!^MQ2 zWMJaAcrd*kXzmfyhJFAk*F@*jDE@pqdBs9zCxhhPHDZ-&s-3`$D%IQh<=GMG{{C>_ zZk*J#S^>NXB(D_4>S#nVD{eWfb&V?|(wby8Cds#}+`xfI`N837V0kZv$~NVd?91VO zrt--t+l+2)&7&kBDpPy&NDwevMqb&)+GxAhVjT91U;YjhwfJQvW&_h{l&!tRYRRYl z88c;8PZu=zVT(hhsypv1FutTV&8`EDqS~4GhwGe6l44`!l%TkbQ@Zrt z4Q`1?=h)=?e;%c7#mt`5h+P5G)xSPZ1A zY7)Ca{c4y}p#O0B9rx=xEvhc&qHJ9*8z8UF!cxemD+|BkzvS2rjCK2OnEZi3XMiPi zCm;_8#FSP7A14E12TXu(A64peSqBa2ZE{yJH{l)?_FB8_hS5Qb9u8z8#M)(Dw+{O8 j&jgttts^t?R9TTz%VT}{`Tt>Z@yRn~t}es-f<6BL=eXn( delta 670 zcmXAmYexHbK_~T`6i*qKU3Fnwbs>6jP7_MY3!fVwqw& zjzNf7fe{8%Nrqx+pM(m8pe!$~#JP-Ssg-^RFTLQW1LyEO&pGG!bVKW3*R}+TivSJ) zZ#ieEnYo>rslg542W|uYVF+DXV95iWEd}@;=X9mA9_O+x{_{IzUwNqtD>rLrGi;5e zfOi==C0BvjJe+eU0TDdTm&XJ1A;=dRRZBnBvpCI{6&hkjR!bgcX0fE#nAs~z)P!li z`N*z0#j44racE}8DOy{=o>Q|nh_%xbZK{}|O|*ssKSO9)o6IUGma|4pk8(Sn_D_{cYdB^S#t9)H;5#amCH^-~PvN8Vt z5fjiF$G80{2S&Z*;v<=j#&{!3r#0SakcEay2XHi6XixV6iyIUzSi~m5V^j5B6O{=T zL%Oc+VKNYtt-F~K49q2vTPSAb6sj{DIsy(a{Q?R*1I{F!Rg(kBuDivu$fsL5IOCTt z7IpyN-BRgvEbvIbSx4g~NB$3B@`cnkw+ggyQg_ln^}l;aFIre4rHI9b9@#p$uA*?t zSsUuzGo3Uf8kvJUqS2HmPgJR)b5rtU+C3l)^7P~Fz`%k$zbz8zb<6YNDz}L>ijXX( zD&_LY2dcv^rD7@p2)?USoC9rx~}A~N*YrvLQRPZ=K>A) Q?(aLMAAi$l{gk`!KSWyMV*mgE diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index ba546c48..1757b887 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 新規 @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: アドレスをコピー - + Special address behavior... アドレスの特別な動作 - + Email gateway メールゲートウェイ @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: 削除 - + 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. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1161,17 +1161,17 @@ Are you sure you want to delete the channel? %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1275,7 +1275,7 @@ Receiver's required difficulty: %1 and %2 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 @@ -1285,7 +1285,7 @@ Receiver's required difficulty: %1 and %2 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 @@ -1310,37 +1310,37 @@ Receiver's required difficulty: %1 and %2 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 PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1405,7 +1405,7 @@ Receiver's required difficulty: %1 and %2 GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1420,82 +1420,82 @@ Receiver's required difficulty: %1 and %2 - + not recommended for chans チャンネルにはお勧めしません - + Problems connecting? Try enabling UPnP in the Network Settings 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください - + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... @@ -2055,6 +2055,14 @@ The 'Random Number' option is selected by default but deterministic ad C PoW モジュールが利用できません。ビルドしてください。 + + qrcodeDialog + + + QR-code + QR コード + + regenerateAddressesDialog -- 2.45.1 From 3ac67e5da7ddfe2d2f3579b1f5bea7b9231cddf5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 9 Mar 2017 11:26:44 +0100 Subject: [PATCH 0712/1102] Connection error reporting changes - fewer tracebacks - more standardised reports including errno --- src/class_receiveDataThread.py | 10 +++++++--- src/class_sendDataThread.py | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 90364228..124e06c0 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -123,11 +123,11 @@ class receiveDataThread(threading.Thread): 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 (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) + logger.error('sock.recv error. Closing receiveData thread, %s', str(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. (ID: ' + str(id(self)) + ')') + logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread') break else: self.processData() @@ -302,9 +302,13 @@ class receiveDataThread(threading.Thread): logger.debug("Waiting for SSL socket handhake write") select.select([], [self.sslSock], [], 10) continue - logger.error("SSL socket handhake failed: %s, shutting down connection", str(e)) + 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')) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 7de63a02..ac11c6b2 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -105,8 +105,8 @@ class sendDataThread(threading.Thread): 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): - logger.debug('Connection error (EPIPE/ECONNRESET/EHOSTUNREACH/ETIMEDOUT)') + 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) -- 2.45.1 From 998935be5f91b02279eaa343960298a68f415ce2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 10 Mar 2017 23:11:57 +0100 Subject: [PATCH 0713/1102] New network subsystem, WIP - finished proxy design - socks4a and socks5 implemented - authentication not tested - resolver for both socks4a and socks5 - http client example using the proxy --- src/network/advanceddispatcher.py | 23 +- src/network/asyncore_pollchoose.py | 723 +++++++++++++++++++++++++++++ src/network/http-old.py | 49 ++ src/network/http.py | 111 +++-- src/network/proxy.py | 173 +------ src/network/socks4a.py | 104 +++++ src/network/socks5.py | 170 +++++++ 7 files changed, 1146 insertions(+), 207 deletions(-) create mode 100644 src/network/asyncore_pollchoose.py create mode 100644 src/network/http-old.py create mode 100644 src/network/socks4a.py create mode 100644 src/network/socks5.py diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 8258412a..9ec7f496 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,12 +1,13 @@ -import asyncore +import asyncore_pollchoose as asyncore class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 131072 - def __init__(self, sock): - asyncore.dispatcher.__init__(self, sock) - self.read_buf = "" - self.write_buf = "" + def __init__(self): + if not hasattr(self, '_map'): + asyncore.dispatcher.__init__(self) + self.read_buf = b"" + self.write_buf = b"" self.state = "init" def slice_read_buf(self, length=0): @@ -22,7 +23,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return True def process(self): - if len(self.read_buf) == 0: + if self.state != "init" and len(self.read_buf) == 0: return while True: try: @@ -37,10 +38,10 @@ class AdvancedDispatcher(asyncore.dispatcher): self.state = state def writable(self): - return len(self.write_buf) > 0 + return self.connecting or len(self.write_buf) > 0 def readable(self): - return len(self.read_buf) < AdvancedDispatcher._buf_len + return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len def handle_read(self): self.read_buf += self.recv(AdvancedDispatcher._buf_len) @@ -49,4 +50,8 @@ class AdvancedDispatcher(asyncore.dispatcher): def handle_write(self): written = self.send(self.write_buf) self.slice_write_buf(written) -# self.process() + + def handle_connect(self): + self.process() + + diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py new file mode 100644 index 00000000..19ec9f42 --- /dev/null +++ b/src/network/asyncore_pollchoose.py @@ -0,0 +1,723 @@ +# -*- 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. +""" + +import select +import socket +import sys +import time +import warnings + +import os +from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ + ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ + errorcode + +_DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, + EBADF)) + +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) + +def read(obj): + try: + obj.handle_read_event() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +def write(obj): + try: + obj.handle_write_event() + except _reraised_exceptions: + raise + except: + obj.handle_error() + +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: + obj.handle_read_event() + if flags & select.POLLOUT: + 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 + + for fd in r: + obj = map.get(fd) + if obj is None: + continue + read(obj) + + for fd in 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) + +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) + pollster = select.poll() + if map: + for fd, obj in list(map.items()): + flags = 0 + if obj.readable(): + flags |= select.POLLIN | select.POLLPRI + # accepting sockets should not be writable + if obj.writable() and not obj.accepting: + flags |= select.POLLOUT + if flags: + pollster.register(fd, flags) + try: + r = pollster.poll(timeout) + except KeyboardInterrupt: + r = [] + for fd, flags in r: + obj = map.get(fd) + if obj is None: + continue + readwrite(obj, flags) + +# 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 + pollster = select.epoll() + if map: + for fd, obj in map.items(): + flags = 0 + if obj.readable(): + flags |= select.POLLIN | select.POLLPRI + if obj.writable(): + flags |= select.POLLOUT + if flags: + # Only check for exceptions if object was either readable + # or writable. + flags |= select.POLLERR | select.POLLHUP | select.POLLNVAL + pollster.register(fd, flags) + try: + r = pollster.poll(timeout) + except select.error, err: + if err.args[0] != EINTR: + raise + r = [] + for fd, flags in r: + obj = map.get(fd) + if obj is None: + continue + readwrite(obj, flags) + +def kqueue_poller(timeout=0.0, map=None): + """A poller which uses kqueue(), BSD specific.""" + if map is None: + map = socket_map + if map: + kqueue = select.kqueue() + flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE + selectables = 0 + for fd, obj in map.items(): + filter = 0 + if obj.readable(): + filter |= select.KQ_FILTER_READ + if obj.writable(): + filter |= select.KQ_FILTER_WRITE + if filter: + ev = select.kevent(fd, filter=filter, flags=flags) + kqueue.control([ev], 0) + selectables += 1 + + events = kqueue.control(None, selectables, timeout) + for event in events: + fd = event.ident + obj = map.get(fd) + if obj is None: + continue + if event.filter == select.KQ_FILTER_READ: + read(obj) + if event.filter == select.KQ_FILTER_WRITE: + write(obj) + kqueue.close() + + +def loop(timeout=30.0, use_poll=False, map=None, count=None, + poller=select_poller): + if map is None: + map = socket_map + # code which grants backward compatibility with "use_poll" + # argument which should no longer be used in favor of + # "poller" + if use_poll and hasattr(select, 'poll'): + poller = poll_poller + else: + poller = select_poller + + if count is None: + while map: + poller(timeout, map) + else: + while map and count > 0: + poller(timeout, map) + count = count - 1 + +class dispatcher: + + debug = False + connected = False + accepting = False + connecting = False + closing = False + addr = None + ignore_log_types = frozenset(['warning']) + + 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 + + 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] + self._fileno = None + + def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): + self.family_and_type = family, type + sock = socket.socket(family, 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): + return True + + def writable(self): + 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) \ + 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, ECONNABORTED, EAGAIN): + 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] == EWOULDBLOCK: + 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 _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, type='info'): + if type not in self.ignore_log_types: + print('%s: %s' % (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() + 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', '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 x: + if x.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/http-old.py b/src/network/http-old.py new file mode 100644 index 00000000..56d24915 --- /dev/null +++ b/src/network/http-old.py @@ -0,0 +1,49 @@ +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 index 56d24915..184213b0 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -1,49 +1,86 @@ -import asyncore import socket -import time -requestCount = 0 -parallel = 50 -duration = 60 +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 HTTPClient(asyncore.dispatcher): - port = 12345 +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 __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 state_init(self): + self.write_buf += "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (self.path, self.destination[0]) + print "\"%s\"" % (self.write_buf) + self.set_state("http_request_sent", 0) + return False - def handle_close(self): - global requestCount - requestCount += 1 - self.close() + def state_http_request_sent(self): + if len(self.read_buf) > 0: + print self.read_buf + self.read_buf = b"" + if not self.connected: + self.set_state("close", 0) + return False - def handle_read(self): -# print self.recv(8192) - self.recv(8192) - def writable(self): - return (len(self.buffer) > 0) +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 - 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) + + 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/proxy.py b/src/network/proxy.py index d9830431..e3b5acee 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -1,15 +1,15 @@ -# SOCKS5 only - -import asyncore import socket -import struct from advanceddispatcher import AdvancedDispatcher +import asyncore_pollchoose as asyncore + +class ProxyError(Exception): pass +class GeneralProxyError(ProxyError): pass class Proxy(AdvancedDispatcher): # these are global, and if you change config during runtime, all active/new # instances should change too - _proxy = ["", 1080] + _proxy = ("127.0.0.1", 9050) _auth = None _remote_dns = True @@ -19,8 +19,8 @@ class Proxy(AdvancedDispatcher): @proxy.setter def proxy(self, address): - if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): - raise + if type(address) != tuple or (len(address) < 2) or (type(str(address[0])) != type('')) or (type(address[1]) != int): + raise ValueError self.__class__._proxy = address @property @@ -31,160 +31,11 @@ class Proxy(AdvancedDispatcher): def auth(self, authTuple): self.__class__._auth = authTuple - def __init__(self, address=None): - if (not type(address) in (list,tuple)) or (len(address) < 2) or (type(address[0]) != type('')) or (type(address[1]) != int): - raise - AdvancedDispatcher.__init__(self, self.sock) + def __init__(self, address): + if type(address) != tuple or (len(address) < 2) or (type(str(address[0])) != type('')) or (type(address[1]) != int): + raise ValueError + AdvancedDispatcher.__init__(self) self.destination = address self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.sslSocket.setblocking(0) self.connect(self.proxy) - - -class SOCKS5(Proxy): - def __init__(self, address=None, sock=None): - Proxy.__init__(self, address) - self.state = "init" - - def handle_connect(self): - self.process() - - def state_init(self): - if self._auth: - self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) - else: - self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) - self.set_state("auth_1", 0) - - def state_auth_1(self): - if not self.read_buf_sufficient(2): - return False - ret = struct.unpack('BB', self.read_buf) - self.read_buf = self.read_buf[2:] - if ret[0] != 5: - # general error - raise - elif ret[1] == 0: - # no auth required - self.set_state("auth_done", 2) - elif ret[1] == 2: - # username/password - self.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_1", 2) - else: - if ret[1] == 0xff: - # auth error - raise - else: - # other error - raise - - def state_auth_needed(self): - if not self.read_buf_sufficient(2): - return False - ret = struct.unpack('BB', self.read_buf) - if ret[0] != 1: - # general error - raise - if ret[1] != 0: - # auth error - raise - # all ok - self.set_state = ("auth_done", 2) - - def state_pre_connect(self): - if not self.read_buf_sufficient(4): - return False - # Get the response - if self.read_buf[0:1] != chr(0x05).encode(): - # general error - self.close() - raise - elif self.read_buf[1:2] != chr(0x00).encode(): - # Connection failed - self.close() - if ord(self.read_buf[1:2])<=8: - # socks 5 erro - raise - #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) - else: - raise - #raise Socks5Error((9, _socks5errors[9])) - # Get the bound address/port - elif self.read_buf[3:4] == chr(0x01).encode(): - self.set_state("proxy_addr_1", 4) - elif self.read_buf[3:4] == chr(0x03).encode(): - self.set_state("proxy_addr_2_1", 4) - else: - self.close() - raise GeneralProxyError((1,_generalerrors[1])) - - def state_proxy_addr_1(self): - if not self.read_buf_sufficient(4): - return False - self.boundaddr = self.read_buf[0:4] - self.set_state("proxy_port", 4) - - def state_proxy_addr_2_1(self): - if not self.read_buf_sufficient(1): - return False - self.address_length = ord(self.read_buf[0:1]) - self.set_state("proxy_addr_2_2", 1) - - def state_proxy_addr_2_2(self): - if not self.read_buf_sufficient(self.address_length): - return False - self.boundaddr = read_buf - self.set_state("proxy_port", self.address_length) - - def state_proxy_port(self): - if not self.read_buf_sufficient(2): - return False - self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] - self.__proxysockname = (self.boundaddr, self.boundport) - if self.ipaddr != None: - self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) - else: - self.__proxypeername = (self.destination[1], destport) - - -class SOCKS5Connection(SOCKS5): - def __init__(self, address): - SOCKS5.__init__(self, address) - - def state_auth_done(self): - # Now we can request the actual connection - self.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.write_buf += chr(0x01).encode() + 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.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.write_buf += chr(0x01).encode() + ipaddr - self.write_buf += struct.pack(">H", self.destination[1]) - self.set_state = ("pre_connect", 0) - - -class SOCKS5Resolver(SOCKS5): - def __init__(self, host): - self.host = host - self.port = 8444 - SOCKS5.__init__(self, [self.host, self.port]) - - def state_auth_done(self): - # Now we can request the actual connection - self.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00) - self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + self.host - self.write_buf += struct.pack(">H", self.port) - self.state = "pre_connect" + print "connecting in background to %s:%i" % (self.proxy[0], self.proxy[1]) diff --git a/src/network/socks4a.py b/src/network/socks4a.py new file mode 100644 index 00000000..091e09a5 --- /dev/null +++ b/src/network/socks4a.py @@ -0,0 +1,104 @@ +import socket +import struct + +from advanceddispatcher import AdvancedDispatcher +import asyncore_pollchoose as asyncore +from proxy import Proxy, ProxyError, GeneralProxyError + +class Socks4aError(ProxyError): pass + + +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) + + def state_pre_connect(self): + if not self.read_buf_sufficient(8): + return False + # Get the response + if self.read_buf[0:1] != chr(0x00).encode(): + # bad data + self.close() + raise Socks4aError + 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 erro + raise Socks4aError + #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])-90])) + else: + raise Socks4aError + #raise Socks4aError((94, _socks4aerrors[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 != None: + self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) + else: + self.__proxypeername = (self.destination[0], self.destport) + self.set_state("socks_handshake_done", 8) + + def proxy_sock_name(self): + return socket.inet_ntoa(self.__proxysockname[0]) + + def state_socks_handshake_done(self): + return False + + +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.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.write_buf += 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.write_buf += struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01) + else: + # Resolve locally + self.ipaddr = socket.inet_aton(socket.gethostbyname(self.destination[0])) + self.write_buf += self.ipaddr + if self._auth: + self.write_buf += self._auth[0] + self.write_buf += chr(0x00).encode() + if rmtrslv: + self.write_buf += self.destination[0] + chr(0x00).encode() + self.set_state("pre_connect", 0) + + +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.write_buf += struct.pack('>BBH', 0x04, 0xF0, self.destination[1]) + self.write_buf += struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01) + if self._auth: + self.write_buf += self._auth[0] + self.write_buf += chr(0x00).encode() + self.write_buf += self.host + chr(0x00).encode() + self.set_state("pre_connect", 0) + + 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 new file mode 100644 index 00000000..5f3164ca --- /dev/null +++ b/src/network/socks5.py @@ -0,0 +1,170 @@ +import socket +import struct + +from advanceddispatcher import AdvancedDispatcher +import asyncore_pollchoose as asyncore +from proxy import Proxy, ProxyError, GeneralProxyError + +class Socks5AuthError(ProxyError): pass +class Socks5Error(ProxyError): pass + + +class Socks5(Proxy): + def __init__(self, address=None): + Proxy.__init__(self, address) + self.ipaddr = None + self.destport = address[1] + + def handle_connect(self): + self.process() + + def state_init(self): + if self._auth: + self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) + else: + self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) + self.set_state("auth_1", 0) + + def state_auth_1(self): + if not self.read_buf_sufficient(2): + return False + ret = struct.unpack('BB', self.read_buf) + self.read_buf = self.read_buf[2:] + if ret[0] != 5: + # general error + raise GeneralProxyError + elif ret[1] == 0: + # no auth required + self.set_state("auth_done", 2) + elif ret[1] == 2: + # username/password + self.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_1", 2) + else: + if ret[1] == 0xff: + # auth error + raise Socks5AuthError + else: + # other error + raise Socks5Error + + def state_auth_needed(self): + if not self.read_buf_sufficient(2): + return False + ret = struct.unpack('BB', self.read_buf) + if ret[0] != 1: + # general error + raise Socks5Error + if ret[1] != 0: + # auth error + raise Socks5AuthError + # all ok + self.set_state = ("auth_done", 2) + + def state_pre_connect(self): + if not self.read_buf_sufficient(4): + return False + # Get the response + if self.read_buf[0:1] != chr(0x05).encode(): + # general error + self.close() + raise Socks5Error + elif self.read_buf[1:2] != chr(0x00).encode(): + # Connection failed + self.close() + if ord(self.read_buf[1:2])<=8: + # socks 5 erro + raise Socks5Error + #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) + else: + raise Socks5Error + #raise Socks5Error((9, _socks5errors[9])) + # Get the bound address/port + elif self.read_buf[3:4] == chr(0x01).encode(): + self.set_state("proxy_addr_1", 4) + elif self.read_buf[3:4] == chr(0x03).encode(): + self.set_state("proxy_addr_2_1", 4) + else: + self.close() + #raise GeneralProxyError((1,_generalerrors[1])) + raise GeneralProxyError + + def state_proxy_addr_1(self): + if not self.read_buf_sufficient(4): + return False + self.boundaddr = self.read_buf[0:4] + self.set_state("proxy_port", 4) + + def state_proxy_addr_2_1(self): + if not self.read_buf_sufficient(1): + return False + self.address_length = ord(self.read_buf[0:1]) + self.set_state("proxy_addr_2_2", 1) + + def state_proxy_addr_2_2(self): + if not self.read_buf_sufficient(self.address_length): + return False + self.boundaddr = read_buf + self.set_state("proxy_port", self.address_length) + + def state_proxy_port(self): + if not self.read_buf_sufficient(2): + return False + self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] + self.__proxysockname = (self.boundaddr, self.boundport) + if self.ipaddr != None: + self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) + else: + self.__proxypeername = (self.destination[0], self.destport) + self.set_state("socks_handshake_done", 2) + + def proxy_sock_name(self): + return socket.inet_ntoa(self.__proxysockname[0]) + + def state_socks_handshake_done(self): + return False + + +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.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.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.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.write_buf += chr(0x01).encode() + self.ipaddr + self.write_buf += struct.pack(">H", self.destination[1]) + self.set_state("pre_connect", 0) + + +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.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00) + self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host) + self.write_buf += struct.pack(">H", self.port) + self.set_state("pre_connect", 0) + + def resolved(self): + print "Resolved %s as %s" % (self.host, self.proxy_sock_name()) -- 2.45.1 From a1d1114cb26fb9038eea38f7b41a2b7f7f5ce285 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 10 Mar 2017 23:56:38 +0100 Subject: [PATCH 0714/1102] New network subsystem updates - auto-select select/poll/epoll/kqueue depending on what's available --- src/network/asyncore_pollchoose.py | 43 ++++++++++++++++++++++++------ src/network/http.py | 4 +-- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 19ec9f42..fc562671 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -172,7 +172,10 @@ def poll_poller(timeout=0.0, map=None): if timeout is not None: # timeout is in milliseconds timeout = int(timeout*1000) - pollster = select.poll() + try: + poll_poller.pollster + except AttributeError: + poll_poller.pollster = select.poll() if map: for fd, obj in list(map.items()): flags = 0 @@ -182,9 +185,12 @@ def poll_poller(timeout=0.0, map=None): if obj.writable() and not obj.accepting: flags |= select.POLLOUT if flags: - pollster.register(fd, flags) + try: + poll_poller.pollster.modify(fd, flags) + except IOError: + poll_poller.pollster.register(fd, flags) try: - r = pollster.poll(timeout) + r = poll_poller.pollster.poll(timeout) except KeyboardInterrupt: r = [] for fd, flags in r: @@ -201,7 +207,10 @@ 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 - pollster = select.epoll() + try: + epoll_poller.pollster + except AttributeError: + epoll_poller.pollster = select.epoll() if map: for fd, obj in map.items(): flags = 0 @@ -213,9 +222,12 @@ def epoll_poller(timeout=0.0, map=None): # Only check for exceptions if object was either readable # or writable. flags |= select.POLLERR | select.POLLHUP | select.POLLNVAL - pollster.register(fd, flags) + try: + epoll_poller.pollster.register(fd, flags) + except IOError: + epoll_poller.pollster.modify(fd, flags) try: - r = pollster.poll(timeout) + r = epoll_poller.pollster.poll(timeout) except select.error, err: if err.args[0] != EINTR: raise @@ -265,9 +277,14 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, # code which grants backward compatibility with "use_poll" # argument which should no longer be used in favor of # "poller" - if use_poll and hasattr(select, 'poll'): + + if hasattr(select, 'epoll'): + poller = epoll_poller + elif hasattr(select, 'kqueue'): + poller = kqueue_poller + elif hasattr(select, 'poll'): poller = poll_poller - else: + elif hasattr(select, 'select'): poller = select_poller if count is None: @@ -349,6 +366,16 @@ class dispatcher: #self.log_info('closing channel %d:%s' % (fd, self)) del map[fd] self._fileno = None + try: + epoll_poller.pollster.unregister(fd) + except (AttributeError, KeyError): + # no epoll used, or not registered + pass + try: + poll_poller.pollster.unregister(fd) + except (AttributeError, KeyError): + # no poll used, or not registered + pass def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): self.family_and_type = family, type diff --git a/src/network/http.py b/src/network/http.py index 184213b0..93828c83 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -20,13 +20,13 @@ class HttpConnection(AdvancedDispatcher): def state_init(self): self.write_buf += "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (self.path, self.destination[0]) - print "\"%s\"" % (self.write_buf) + 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 self.read_buf + print "Received %ib" % (len(self.read_buf)) self.read_buf = b"" if not self.connected: self.set_state("close", 0) -- 2.45.1 From 49869d0b567d7deb05f3cc298ec0ce804fa6eb3f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 11 Mar 2017 11:12:08 +0100 Subject: [PATCH 0715/1102] Networking subsystem updates - version command struct for faster unpacking - increase read buffer to 2MB to allow a full command to fit - initial bitmessage protocol class (WIP) - error handling - remove duplicate method --- src/bmproto.py | 141 +++++++++++++++++++++++++++++ src/network/advanceddispatcher.py | 4 +- src/network/asyncore_pollchoose.py | 4 +- src/network/socks5.py | 3 - src/protocol.py | 2 + 5 files changed, 146 insertions(+), 8 deletions(-) create mode 100644 src/bmproto.py diff --git a/src/bmproto.py b/src/bmproto.py new file mode 100644 index 00000000..8bd90aff --- /dev/null +++ b/src/bmproto.py @@ -0,0 +1,141 @@ +import hashlib +import time +import socket + +from network.advanceddispatcher import AdvancedDispatcher +import network.asyncore_pollchoose as asyncore +from network.proxy import Proxy, ProxyError, GeneralProxyError +from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error +from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError + +import addresses +import protocol + +class BMProtoError(ProxyError): pass + + +class BMConnection(AdvancedDispatcher): + def __init__(self, address): + AdvancedDispatcher.__init__(self) + self.destination = address + self.payload = None + 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 bm_proto_len_sufficient(self): + if len(self.read_buf) < protocol.Header.size: + print "Length below header size" + return False + if not self.payload: + 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.payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. + return False + if len(self.read_buf) < self.payloadLength + protocol.Header.size: + print "Length below announced object length" + return False + self.payload = self.read_buf[protocol.Header.size:self.payloadLength + protocol.Header.size] + return True + + def bm_check_command(self): + if self.magic != 0xE9BEB4D9: + self.set_state("crap", protocol.Header.size) + print "Bad magic" + self.payload = None + return False + if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: + self.set_state("crap", protocol.Header.size) + self.payload = None + print "Bad checksum" + return False + print "received %s (%ib)" % (self.command, self.payloadLength) + return True + + def state_init(self): + self.write_buf += protocol.assembleVersionMessage(self.destination[0], self.destination[1], (1,), False) + if True: + print "Sending version (%ib)" % len(self.write_buf) + self.set_state("bm_reccommand", 0) + return False + + def state_bm_reccommand(self): + if not self.bm_proto_len_sufficient(): + return False + if not self.bm_check_command(): + return False + if self.command == "version": + self.bm_recversion() + elif self.command == "verack": + self.bm_recverack() + else: + print "unimplemented command %s" % (self.command) + self.set_state("bm_reccommand", protocol.Header.size + self.payloadLength) + self.payload = None + print "buffer length = %i" % (len(self.read_buf)) + return False + + def bm_recverack(self): + self.verackReceived = True + return False + + def bm_recversion(self): + self.remoteProtocolVersion, self.services, timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:82]) + print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) + print "services: %08X" % (self.services) + print "time offset: %i" % (timestamp - int(time.time())) + print "my external IP: %s" % (socket.inet_ntoa(self.myExternalIP)) + print "remote node incoming port: %i" % (self.remoteNodeIncomingPort) + useragentLength, lengthofUseragentVarint = addresses.decodeVarint(self.payload[80:84]) + readPosition = 80 + lengthOfUseragentVarint + self.userAgent = self.payload[readPosition:readPosition + useragentLength] + readPosition += useragentLength + print "user agent: %s" % (self.userAgent) + return False + + def state_http_request_sent(self): + if len(self.read_buf) > 0: + print self.read_buf + self.read_buf = b"" + if not self.connected: + self.set_state("close", 0) + return False + + +class Socks5BMConnection(Socks5Connection, BMConnection): + def __init__(self, address): + Socks5Connection.__init__(self, address=address) + + def state_socks_handshake_done(self): + BMConnection.state_init(self) + return False + + +class Socks4aBMConnection(Socks4aConnection, BMConnection): + def __init__(self, address): + Socks4aConnection.__init__(self, address=address) + + def state_socks_handshake_done(self): + BMConnection.state_init(self) + return False + + +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=1, count=1) + continue + + proxy = Socks5BMConnection(host) + while len(asyncore.socket_map) > 0: +# print "loop, state = %s" % (proxy.state) + asyncore.loop(timeout=1, count=1) + + proxy = Socks4aBMConnection(host) + while len(asyncore.socket_map) > 0: +# print "loop, state = %s" % (proxy.state) + asyncore.loop(timeout=1, count=1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 9ec7f496..c672f9f9 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,7 +1,7 @@ import asyncore_pollchoose as asyncore class AdvancedDispatcher(asyncore.dispatcher): - _buf_len = 131072 + _buf_len = 2097152 # 2MB def __init__(self): if not hasattr(self, '_map'): @@ -53,5 +53,3 @@ class AdvancedDispatcher(asyncore.dispatcher): def handle_connect(self): self.process() - - diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index fc562671..9f231e0e 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -368,12 +368,12 @@ class dispatcher: self._fileno = None try: epoll_poller.pollster.unregister(fd) - except (AttributeError, KeyError): + except (AttributeError, KeyError, TypeError): # no epoll used, or not registered pass try: poll_poller.pollster.unregister(fd) - except (AttributeError, KeyError): + except (AttributeError, KeyError, TypeError): # no poll used, or not registered pass diff --git a/src/network/socks5.py b/src/network/socks5.py index 5f3164ca..841c253b 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -15,9 +15,6 @@ class Socks5(Proxy): self.ipaddr = None self.destport = address[1] - def handle_connect(self): - self.process() - def state_init(self): if self._auth: self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) diff --git a/src/protocol.py b/src/protocol.py index 9d66ec2f..a889ab93 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -34,6 +34,8 @@ eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') +VersionPacket = Struct('>LqQ20sI36sH') + # Bitfield def getBitfield(address): -- 2.45.1 From 0529fe23131b1a9ee400392a8898386be7cd362f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 11 Mar 2017 12:14:40 +0100 Subject: [PATCH 0716/1102] Known node count updates - if too many nodes, only delete oldest nodes in bootstrap provider mode, in normal mode ignore new nodes as it used to before - in bootstrap provider mode, penalise nodes announced by others by 1 day instead of 3 hours --- src/class_receiveDataThread.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 124e06c0..0ddd5739 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -630,17 +630,18 @@ class receiveDataThread(threading.Thread): knownnodes.knownNodes[recaddrStream] = {} peerFromAddrMessage = state.Peer(hostStandardFormat, recaddrPort) if peerFromAddrMessage not in knownnodes.knownNodes[recaddrStream]: - knownnodes.trimKnownNodes(recaddrStream) # only if recent if timeSomeoneElseReceivedMessageFromThisNode > (int(time.time()) - 10800) and timeSomeoneElseReceivedMessageFromThisNode < (int(time.time()) + 10800): - logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) # 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()) - 10800 + 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 - else: + elif len(knownnodes.knownNodes[recaddrStream]) < 20000: with knownnodes.knownNodesLock: knownnodes.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode hostDetails = ( @@ -648,7 +649,8 @@ class receiveDataThread(threading.Thread): recaddrStream, recaddrServices, hostStandardFormat, recaddrPort) protocol.broadcastToSendDataQueues(( recaddrStream, 'advertisepeer', hostDetails)) - shared.needToWriteKnownNodesToDisk = True + 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): -- 2.45.1 From 13223887fc782f2171c78aaaaedf04df7247833f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Mar 2017 19:25:19 +0100 Subject: [PATCH 0717/1102] Setup.py updates - only waits for a prompt if running from a TTY - support for Ubuntu 12 and older (different msgpack package name) - fix crash for missing keys in the distro definition - accept alternative msgpack providers - add pyopencl as an extra --- setup.py | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 1a273eaf..95c7ffb5 100644 --- a/setup.py +++ b/setup.py @@ -17,6 +17,7 @@ packageManager = { "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", @@ -29,6 +30,7 @@ packageName = { "FreeBSD": "py27-qt4", "Debian": "python-qt4", "Ubuntu": "python-qt4", + "Ubuntu 12": "python-qt4", "openSUSE": "python-qt", "Fedora": "PyQt4", "Guix": "python2-pyqt@4.11.4", @@ -44,6 +46,7 @@ packageName = { "FreeBSD": "py27-msgpack-python", "Debian": "python-msgpack", "Ubuntu": "python-msgpack", + "Ubuntu 12": "msgpack-python", "openSUSE": "python-msgpack-python", "Fedora": "python2-msgpack", "Guix": "python2-msgpack", @@ -53,6 +56,7 @@ packageName = { "FreeBSD": "py27-pyopencl", "Debian": "python-pyopencl", "Ubuntu": "python-pyopencl", + "Ubuntu 12": "python-pyopencl", "Fedora": "python2-pyopencl", "openSUSE": "", "OpenBSD": "", @@ -68,6 +72,7 @@ packageName = { "FreeBSD": "py27-setuptools", "Debian": "python-setuptools", "Ubuntu": "python-setuptools", + "Ubuntu 12": "python-setuptools", "Fedora": "python2-setuptools", "openSUSE": "python-setuptools", "Guix": "python2-setuptools", @@ -94,6 +99,7 @@ def detectOS(): detectOS.result = "Windows" elif os.path.isfile("/etc/os-release"): with open("/etc/os-release", 'rt') as osRelease: + version = None for line in osRelease: if line.startswith("NAME="): line = line.lower() @@ -109,6 +115,13 @@ def detectOS(): detectOS.result = "Gentoo" else: detectOS.result = None + if line.startswith("VERSION_ID="): + try: + version = float(line.split("\"")[1]) + except ValueError: + pass + if detectOS.result == "Ubuntu" and version < 14: + detectOS.result = "Ubuntu 12" elif os.path.isfile("/etc/config.scm"): detectOS.result = "Guix" return detectOS.result @@ -133,8 +146,11 @@ def prereqToPackages(): packageManager[detectOS()], " ".join( packageName[x][detectOS()] for x in detectPrereqs(True))) for package in detectPrereqs(True): - if packageName[package]['optional']: - print packageName[package]['description'] + try: + if packageName[package]['optional']: + print packageName[package]['description'] + except KeyError: + pass def compilerToPackages(): if not detectOS() in compiling: @@ -159,7 +175,7 @@ if __name__ == "__main__": print "It looks like you're missing setuptools." sys.exit() - if detectPrereqs(True) != []: + if detectPrereqs(True) != [] and sys.stdin.isatty(): print "Press Return to continue" try: nothing = raw_input() @@ -176,6 +192,11 @@ if __name__ == "__main__": libraries=['pthread', 'crypto'], ) + installRequires = [] + # this will silently accept alternative providers of msgpack if they are already installed + if "msgpack" in detectPrereqs(True): + installRequires.append("msgpack-python") + try: dist = setup( name='pybitmessage', @@ -190,9 +211,10 @@ if __name__ == "__main__": url='https://bitmessage.org', # TODO: add keywords #keywords='', - install_requires=['msgpack-python'], + install_requires=[installRequires], extras_require={ - 'qrcode': ['qrcode'] + 'qrcode': ['qrcode'], + 'pyopencl': ['pyopencl'] }, classifiers=[ "License :: OSI Approved :: MIT License" -- 2.45.1 From 1af49a016592fa639a48225e085205f083b5e7dd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Mar 2017 22:08:00 +0100 Subject: [PATCH 0718/1102] Download tracking refactoring - replace PendingDownload singleton dict with a Queue - total memory and CPU requirements should be reduced - get rid of somObjectsOfWhichThisRemoteNodeIsAlearedyAware. It has very little practicle effect and only uses memory --- src/bitmessageqt/__init__.py | 10 +- src/bitmessageqt/networkstatus.py | 5 +- src/class_outgoingSynSender.py | 5 +- src/class_receiveDataThread.py | 26 ++++-- src/class_sendDataThread.py | 9 +- src/class_singleListener.py | 5 +- src/inventory.py | 148 ++++++------------------------ src/shared.py | 6 +- 8 files changed, 60 insertions(+), 154 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index feaf1c48..e861f767 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -77,7 +77,7 @@ from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from dialogs import AddAddressDialog from helper_generic import powQueueSize -from inventory import PendingDownload, PendingUpload, PendingUploadDeadlineException +from inventory import PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException import knownnodes import paths from proofofwork import getPowType @@ -2751,16 +2751,16 @@ class MyForm(settingsmixin.SMainWindow): elif reply == QtGui.QMessage.Cancel: return - if PendingDownload().len() > 0: + 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, PendingDownload().len()), + _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: - PendingDownload().stop() + PendingDownloadQueue.stop() if shared.statusIconColor == 'red': reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Not connected"), @@ -2788,7 +2788,7 @@ class MyForm(settingsmixin.SMainWindow): if waitForSync: self.statusBar().showMessage(_translate( "MainWindow", "Waiting for finishing synchronisation...")) - while PendingDownload().len() > 0: + while PendingDownloadQueue.totalSize() > 0: time.sleep(0.5) QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 7506b652..b5870a6b 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -1,8 +1,9 @@ from PyQt4 import QtCore, QtGui import time import shared + from tr import _translate -from inventory import Inventory, PendingDownload, PendingUpload +from inventory import Inventory, PendingDownloadQueue, PendingUpload import l10n from retranslateui import RetranslateMixin from uisignaler import UISignaler @@ -45,7 +46,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): return "%4.0f kB" % num def updateNumberOfObjectsToBeSynced(self): - self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, PendingDownload().len() + PendingUpload().len())) + self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, PendingDownloadQueue.totalSize() + PendingUpload().len())) def updateNumberOfMessagesProcessed(self): self.updateNumberOfObjectsToBeSynced() diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index c4f385c3..9b3eac14 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -185,12 +185,10 @@ class outgoingSynSender(threading.Thread, StoppableThread): self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() return - 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. sd = sendDataThread(sendDataThreadQueue) - sd.setup(self.sock, peer.host, peer.port, self.streamNumber, - someObjectsOfWhichThisRemoteNodeIsAlreadyAware) + sd.setup(self.sock, peer.host, peer.port, self.streamNumber) sd.start() rd = receiveDataThread() @@ -199,7 +197,6 @@ class outgoingSynSender(threading.Thread, StoppableThread): peer.host, peer.port, self.streamNumber, - someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 0ddd5739..df7d18b5 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -32,7 +32,7 @@ import knownnodes from debug import logger import paths import protocol -from inventory import Inventory, PendingDownload, PendingUpload +from inventory import Inventory, PendingDownloadQueue, PendingUpload import queues import state import throttle @@ -56,7 +56,6 @@ class receiveDataThread(threading.Thread): HOST, port, streamNumber, - someObjectsOfWhichThisRemoteNodeIsAlreadyAware, selfInitiatedConnections, sendDataThreadQueue, objectHashHolderInstance): @@ -79,8 +78,8 @@ class receiveDataThread(threading.Thread): self.initiatedConnection = True for stream in self.streamNumber: self.selfInitiatedConnections[stream][self] = 0 - self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware self.objectHashHolderInstance = objectHashHolderInstance + self.downloadQueue = PendingDownloadQueue() self.startTime = time.time() def run(self): @@ -147,7 +146,6 @@ class receiveDataThread(threading.Thread): except Exception as err: logger.error('Could not delete ' + str(self.hostIdent) + ' from shared.connectedHostsList.' + str(err)) - PendingDownload().threadEnd() 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))) @@ -240,10 +238,20 @@ class receiveDataThread(threading.Thread): self.data = self.data[payloadLength + protocol.Header.size:] # take this message out and then process the next message if self.data == '': # if there are no more messages + toRequest = [] try: - self.sendgetdata(PendingDownload().pull(100)) - except Queue.Full: + for i in range(self.downloadQueue.pendingSize, 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() + except Queue.Empty: pass + if len(toRequest) > 0: + self.sendgetdata(toRequest) self.processData() def sendpong(self, payload): @@ -407,7 +415,7 @@ class receiveDataThread(threading.Thread): bigInvList = {} for stream in self.streamNumber: for hash in Inventory().unexpired_hashes_by_stream(stream): - if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): + if not self.objectHashHolderInstance.hasHash(hash): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' @@ -476,6 +484,7 @@ class receiveDataThread(threading.Thread): def recobject(self, data): self.messageProcessingStartTime = time.time() lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(data) + self.downloadQueue.task_done() """ Sleeping will help guarantee that we can process messages faster than a @@ -509,8 +518,7 @@ class receiveDataThread(threading.Thread): 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 objectsNewToMe: - PendingDownload().add(item) - self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[item] = 0 # helps us keep from sending inv messages to peers that already know about the objects listed therein + self.downloadQueue.put(item) # Send a getdata message to our peer to request the object with the given # hash diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index ac11c6b2..792fedd0 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -39,8 +39,8 @@ class sendDataThread(threading.Thread): sock, HOST, PORT, - streamNumber, - someObjectsOfWhichThisRemoteNodeIsAlreadyAware): + streamNumber + ): self.sock = sock self.peer = state.Peer(HOST, PORT) self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator @@ -52,7 +52,6 @@ class sendDataThread(threading.Thread): 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. - self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware if streamNumber == -1: # This was an incoming connection. self.initiatedConnection = False else: @@ -165,8 +164,7 @@ 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: - if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: - payload += hash + payload += hash if payload != '': payload = encodeVarint(len(payload)/32) + payload packet = protocol.CreatePacket('inv', payload) @@ -176,7 +174,6 @@ class sendDataThread(threading.Thread): logger.error('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.') diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 5332929c..243a494a 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -146,19 +146,18 @@ class singleListener(threading.Thread, StoppableThread): 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, someObjectsOfWhichThisRemoteNodeIsAlreadyAware) + socketObject, HOST, PORT, -1) sd.start() rd = receiveDataThread() rd.daemon = True # close the main program even if there are threads left rd.setup( - socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) + socketObject, HOST, PORT, -1, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) rd.start() logger.info('connected to ' + HOST + ' during INCOMING request.') diff --git a/src/inventory.py b/src/inventory.py index f2e9b37b..1982dacf 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,5 +1,6 @@ import collections from threading import current_thread, enumerate as threadingEnumerate, RLock +import Queue import time from helper_sql import * @@ -37,7 +38,6 @@ class Inventory(collections.MutableMapping): value = self.InventoryItem(*value) self._inventory[hash] = value self._streams[value.stream].add(hash) - PendingDownload().delete(hash) def __delitem__(self, hash): raise NotImplementedError @@ -84,131 +84,39 @@ class Inventory(collections.MutableMapping): self._streams[value.stream].add(objectHash) -@Singleton -class PendingDownload(object): +class PendingDownloadQueue(Queue.Queue): # keep a track of objects that have been advertised to us but we haven't downloaded them yet - def __init__(self): - super(self.__class__, self).__init__() - self.lock = RLock() - self.hashes = {} + def __init__(self, maxsize=0): + Queue.Queue.__init__(self, maxsize) self.stopped = False - # don't request the same object more frequently than this - self.frequency = 60 - # after requesting and not receiving an object more than this times, consider it expired - self.maxRequestCount = 3 - self.pending = {} + self.pendingSize = 0 - def add(self, objectHash): - if self.stopped: - return - with self.lock: - if objectHash not in self.hashes: - self.hashes[objectHash] = {'peers':[], 'requested':0, 'requestedCount':0} - self.hashes[objectHash]['peers'].append(current_thread().peer) + def task_done(self): + Queue.Queue.task_done(self) + if self.pendingSize > 0: + self.pendingSize -= 1 - def addPending(self, objectHash=None): - if self.stopped: - return - if current_thread().peer not in self.pending: - self.pending[current_thread().peer] = {'objects':[], 'requested':0, 'received':0} - if objectHash not in self.pending[current_thread().peer]['objects'] and not objectHash is None: - self.pending[current_thread().peer]['objects'].append(objectHash) - self.pending[current_thread().peer]['requested'] = time.time() + def get(self, block=True, timeout=None): + retval = Queue.Queue.get(self, block, timeout) + # no exception was raised + if not self.stopped: + self.pendingSize += 1 + return retval - def len(self): - with self.lock: - return sum(1 for x in self.hashes.values() if len(x) > 0) + @staticmethod + def totalSize(): + size = 0 + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'downloadQueue'): + size += thread.downloadQueue.qsize() + thread.downloadQueue.pendingSize + return size - def pull(self, count=1): - if count < 1: - raise ValueError("Must be at least one") - objectHashes = [] - unreachableObjects = [] - if self.stopped: - return objectHashes - start = time.time() - try: - for objectHash in self.hashes.keys(): - with self.lock: - if len(objectHashes) >= count: - break - if current_thread().peer not in self.pending: - self.addPending() - if (self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency or \ - self.pending[current_thread().peer]['received'] >= time.time() - self.frequency) and \ - len(self.pending[current_thread().peer]['objects']) >= count: - break - if len(self.hashes[objectHash]['peers']) == 0: - unreachableObjects.append(objectHash) - continue - # requested too long ago or not at all from any thread - if self.hashes[objectHash]['requested'] < time.time() - self.frequency: - # ready requested from this thread but haven't received yet - if objectHash in self.pending[current_thread().peer]['objects']: - # if still sending or receiving, request next - if self.pending[current_thread().peer]['received'] >= time.time() - self.frequency or \ - self.pending[current_thread().peer]['requested'] >= time.time() - self.frequency: - continue - # haven't requested or received anything recently, re-request (i.e. continue) - # the current node doesn't have the object - elif current_thread().peer not in self.hashes[objectHash]['peers']: - continue - # already requested too many times, remove all signs of this object - if self.hashes[objectHash]['requestedCount'] >= self.maxRequestCount: - del self.hashes[objectHash] - for thread in self.pending.keys(): - if objectHash in self.pending[thread]['objects']: - self.pending[thread]['objects'].remove(objectHash) - continue - # all ok, request - objectHashes.append(objectHash) - self.hashes[objectHash]['requested'] = time.time() - self.hashes[objectHash]['requestedCount'] += 1 - self.pending[current_thread().peer]['requested'] = time.time() - self.addPending(objectHash) - except (RuntimeError, KeyError, ValueError): - # the for cycle sometimes breaks if you remove elements - pass - for objectHash in unreachableObjects: - with self.lock: - if objectHash in self.hashes: - del self.hashes[objectHash] -# logger.debug("Pull took %.3f seconds", time.time() - start) - return objectHashes - - def delete(self, objectHash): - with self.lock: - if objectHash in self.hashes: - del self.hashes[objectHash] - if hasattr(current_thread(), 'peer') and current_thread().peer in self.pending: - self.pending[current_thread().peer]['received'] = time.time() - for thread in self.pending.keys(): - with self.lock: - if thread in self.pending and objectHash in self.pending[thread]['objects']: - self.pending[thread]['objects'].remove(objectHash) - - def stop(self): - with self.lock: - self.hashes = {} - self.pending = {} - - def threadEnd(self): - while True: - try: - with self.lock: - if current_thread().peer in self.pending: - for objectHash in self.pending[current_thread().peer]['objects']: - if objectHash in self.hashes: - self.hashes[objectHash]['peers'].remove(current_thread().peer) - except (KeyError): - pass - else: - break - with self.lock: - try: - del self.pending[current_thread().peer] - except KeyError: - pass + @staticmethod + def stop(): + for thread in threadingEnumerate(): + if thread.isAlive() and hasattr(thread, 'downloadQueue'): + thread.downloadQueue.stopped = True + thread.downloadQueue.pendingSize = 0 class PendingUploadDeadlineException(Exception): diff --git a/src/shared.py b/src/shared.py index c28392f6..69794033 100644 --- a/src/shared.py +++ b/src/shared.py @@ -22,7 +22,7 @@ from bmconfigparser import BMConfigParser import highlevelcrypto #import helper_startup from helper_sql import * -from inventory import Inventory, PendingDownload +from inventory import Inventory from queues import objectProcessorQueue import protocol import state @@ -342,22 +342,18 @@ def checkAndShareObjectWithPeers(data): """ if len(data) > 2 ** 18: logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(data)) - PendingDownload().delete(calculateInventoryHash(data)) return 0 # Let us check to make sure that the proof of work is sufficient. if not protocol.isProofOfWorkSufficient(data): logger.info('Proof of work is insufficient.') - PendingDownload().delete(calculateInventoryHash(data)) 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) - PendingDownload().delete(calculateInventoryHash(data)) 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) - PendingDownload().delete(calculateInventoryHash(data)) return 0 intObjectType, = unpack('>I', data[16:20]) try: -- 2.45.1 From 9a5f7442a0555d9742e9c199438fe8f64f73dfc9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Mar 2017 00:27:11 +0100 Subject: [PATCH 0719/1102] Setup.py fix - handle missing "optional" key in package definition --- setup.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 95c7ffb5..5ea5a624 100644 --- a/setup.py +++ b/setup.py @@ -168,9 +168,12 @@ if __name__ == "__main__": "It is highly recommended to use the package manager " \ "instead of setuptools." % (detectOS()) prereqToPackages() - for module in detectPrereqs(True): - if not packageName[module]['optional']: - sys.exit() + try: + for module in detectPrereqs(True): + if not packageName[module]['optional']: + sys.exit() + except KeyError: + sys.exit() if not haveSetuptools: print "It looks like you're missing setuptools." sys.exit() -- 2.45.1 From 913b401dd0a01bc4b938a1088b73dd2ab04ee7c2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Mar 2017 01:22:37 +0100 Subject: [PATCH 0720/1102] PendingDownloadQueue updates - track pending hashId more accurately - add timeout and a cleanup so that the download queues don't get stuck and memory is freed - randomise download order (only works for inv commands with more than 1 entry) --- src/class_receiveDataThread.py | 8 ++++---- src/class_singleCleaner.py | 5 +++++ src/inventory.py | 30 +++++++++++++++++++++++------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index df7d18b5..aeb38e78 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -240,14 +240,14 @@ class receiveDataThread(threading.Thread): if self.data == '': # if there are no more messages toRequest = [] try: - for i in range(self.downloadQueue.pendingSize, 100): + 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() + self.downloadQueue.task_done(hashId) except Queue.Empty: pass if len(toRequest) > 0: @@ -484,7 +484,7 @@ class receiveDataThread(threading.Thread): def recobject(self, data): self.messageProcessingStartTime = time.time() lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(data) - self.downloadQueue.task_done() + self.downloadQueue.task_done(calculateInventoryHash(data)) """ Sleeping will help guarantee that we can process messages faster than a @@ -517,7 +517,7 @@ class receiveDataThread(threading.Thread): 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 objectsNewToMe: + for item in random.sample(objectsNewToMe, len(objectsNewToMe)): self.downloadQueue.put(item) # Send a getdata message to our peer to request the object with the given diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 921e84ed..1ed7a5e4 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -108,6 +108,11 @@ class singleCleaner(threading.Thread, StoppableThread): os._exit(0) shared.needToWriteKnownNodesToDisk = False + # clear download queues + for thread in threading.enumerate(): + if thread.isAlive() and hasattr(thread, 'downloadQueue'): + thread.downloadQueue.clear() + # TODO: cleanup pending upload / download if state.shutdown == 0: diff --git a/src/inventory.py b/src/inventory.py index 1982dacf..a796968a 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -86,29 +86,44 @@ class Inventory(collections.MutableMapping): 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.pendingSize = 0 + self.pending = {} + self.lock = RLock() - def task_done(self): + def task_done(self, hashId): Queue.Queue.task_done(self) - if self.pendingSize > 0: - self.pendingSize -= 1 + 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: - self.pendingSize += 1 + 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() + thread.downloadQueue.pendingSize + size += thread.downloadQueue.qsize() + len(thread.downloadQueue.pending) return size @staticmethod @@ -116,7 +131,8 @@ class PendingDownloadQueue(Queue.Queue): for thread in threadingEnumerate(): if thread.isAlive() and hasattr(thread, 'downloadQueue'): thread.downloadQueue.stopped = True - thread.downloadQueue.pendingSize = 0 + with thread.downloadQueue.lock: + thread.downloadQueue.pending = {} class PendingUploadDeadlineException(Exception): -- 2.45.1 From 46c9ea940324dcd56cd59b7d6257bfbcd11930b7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 20 Mar 2017 18:32:26 +0100 Subject: [PATCH 0721/1102] Async network updates (WIP) - cleaner command handling - separating into header and command handling - incoming connection handler - bugfixes and more debug information --- src/bmproto.py | 150 +++++++++++++++++------------ src/network/advanceddispatcher.py | 5 +- src/network/asyncore_pollchoose.py | 2 + src/protocol.py | 2 +- 4 files changed, 93 insertions(+), 66 deletions(-) diff --git a/src/bmproto.py b/src/bmproto.py index 8bd90aff..0a147d3e 100644 --- a/src/bmproto.py +++ b/src/bmproto.py @@ -15,91 +15,94 @@ class BMProtoError(ProxyError): pass class BMConnection(AdvancedDispatcher): - def __init__(self, address): - AdvancedDispatcher.__init__(self) - self.destination = address + # ~1.6 MB which is the maximum possible size of an inv message. + maxMessageSize = 1600100 + + def __init__(self, address=None, sock=None): + AdvancedDispatcher.__init__(self, sock) + self.verackReceived = False + self.verackSent = False + if address is None and sock is not None: + self.destination = self.addr() + self.isOutbound = False + print "received connection in background from %s:%i" % (self.destination[0], self.destination[1]) + else: + self.destination = address + self.isOutbound = True + 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 bm_proto_reset(self): + self.magic = None + self.command = None + self.payloadLength = None + self.checksum = None self.payload = None - 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 bm_proto_len_sufficient(self): - if len(self.read_buf) < protocol.Header.size: - print "Length below header size" - return False - if not self.payload: - 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.payloadLength > 1600100: # ~1.6 MB which is the maximum possible size of an inv message. - return False - if len(self.read_buf) < self.payloadLength + protocol.Header.size: - print "Length below announced object length" - return False - self.payload = self.read_buf[protocol.Header.size:self.payloadLength + protocol.Header.size] - return True - - def bm_check_command(self): - if self.magic != 0xE9BEB4D9: - self.set_state("crap", protocol.Header.size) - print "Bad magic" - self.payload = None - return False - if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: - self.set_state("crap", protocol.Header.size) - self.payload = None - print "Bad checksum" - return False - print "received %s (%ib)" % (self.command, self.payloadLength) - return True + self.invalid = False def state_init(self): + self.bm_proto_reset() self.write_buf += protocol.assembleVersionMessage(self.destination[0], self.destination[1], (1,), False) if True: print "Sending version (%ib)" % len(self.write_buf) - self.set_state("bm_reccommand", 0) + self.set_state("bm_header", 0) return False - def state_bm_reccommand(self): - if not self.bm_proto_len_sufficient(): + def state_bm_header(self): + if len(self.read_buf) < protocol.Header.size: + print "Length below header size" return False - if not self.bm_check_command(): + 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.bm_proto_reset() + self.set_state("bm_header", 1) + print "Bad magic" + if self.payloadLength > BMConnection.maxMessageSize: + self.invalid = True + self.set_state("bm_command", protocol.Header.size) + return True + + def state_bm_command(self): + if len(self.read_buf) < self.payloadLength: + print "Length below announced object length" return False - if self.command == "version": - self.bm_recversion() - elif self.command == "verack": - self.bm_recverack() + print "received %s (%ib)" % (self.command, self.payloadLength) + self.payload = self.read_buf[:self.payloadLength] + if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: + print "Bad checksum, ignoring" + self.invalid = True + if not self.invalid: + try: + getattr(self, "bm_command_" + str(self.command))() + except AttributeError: + # unimplemented command + print "unimplemented command %s" % (self.command) else: - print "unimplemented command %s" % (self.command) - self.set_state("bm_reccommand", protocol.Header.size + self.payloadLength) - self.payload = None - print "buffer length = %i" % (len(self.read_buf)) - return False + print "Skipping command %s due to invalid data" % (self.command) + self.set_state("bm_header", self.payloadLength) + self.bm_proto_reset() + return True - def bm_recverack(self): + def bm_command_verack(self): self.verackReceived = True - return False + return True - def bm_recversion(self): - self.remoteProtocolVersion, self.services, timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:82]) + def bm_command_version(self): + self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) print "services: %08X" % (self.services) - print "time offset: %i" % (timestamp - int(time.time())) + print "time offset: %i" % (self.timestamp - int(time.time())) print "my external IP: %s" % (socket.inet_ntoa(self.myExternalIP)) print "remote node incoming port: %i" % (self.remoteNodeIncomingPort) - useragentLength, lengthofUseragentVarint = addresses.decodeVarint(self.payload[80:84]) + useragentLength, lengthOfUseragentVarint = addresses.decodeVarint(self.payload[80:84]) readPosition = 80 + lengthOfUseragentVarint self.userAgent = self.payload[readPosition:readPosition + useragentLength] readPosition += useragentLength print "user agent: %s" % (self.userAgent) - return False - - def state_http_request_sent(self): - if len(self.read_buf) > 0: - print self.read_buf - self.read_buf = b"" - if not self.connected: - self.set_state("close", 0) - return False + return True class Socks5BMConnection(Socks5Connection, BMConnection): @@ -120,6 +123,27 @@ class Socks4aBMConnection(Socks4aConnection, BMConnection): return False +class BMServer(AdvancedDispatcher): + port = 8444 + + def __init__(self, port=None): + if not hasattr(self, '_map'): + AdvancedDispatcher.__init__(self) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.set_reuse_addr() + if port is None: + port = BMServer.port + self.bind(('127.0.0.1', port)) + self.connections = 0 + self.listen(5) + + def handle_accept(self): + pair = self.accept() + if pair is not None: + sock, addr = pair + BMConnection(sock=sock) + + if __name__ == "__main__": # initial fill diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index c672f9f9..df6e58ef 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -3,9 +3,9 @@ import asyncore_pollchoose as asyncore class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 2097152 # 2MB - def __init__(self): + def __init__(self, sock=None): if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self) + asyncore.dispatcher.__init__(self, sock) self.read_buf = b"" self.write_buf = b"" self.state = "init" @@ -27,6 +27,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return while True: try: + print "Trying to handle state \"%s\"" % (self.state) if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 9f231e0e..7fa19f4a 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -287,6 +287,8 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, elif hasattr(select, 'select'): poller = select_poller + print "Poll loop using %s" % (poller.__name__) + if count is None: while map: poller(timeout, map) diff --git a/src/protocol.py b/src/protocol.py index a889ab93..9698f917 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -34,7 +34,7 @@ eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') -VersionPacket = Struct('>LqQ20sI36sH') +VersionPacket = Struct('>LqQ20s4s36sH') # Bitfield -- 2.45.1 From e97df3ad4de58adffada3804866f8ede9ab8ef10 Mon Sep 17 00:00:00 2001 From: Justin Ramos Date: Wed, 22 Mar 2017 20:47:48 +0000 Subject: [PATCH 0722/1102] print SystemExit exception messages instead of using the current build failure text Signed-off-by: Justin Ramos --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5ea5a624..404c10fb 100644 --- a/setup.py +++ b/setup.py @@ -256,7 +256,9 @@ if __name__ == "__main__": }, scripts=['src/pybitmessage'] ) - except SystemExit: + except SystemExit as err: + print err.message + except: print "It looks like building the package failed.\n" \ "You may be missing a C++ compiler and the OpenSSL headers." compilerToPackages() -- 2.45.1 From 9aacef144b4147fb1590dcbae80b663184ecb875 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 25 Mar 2017 11:48:45 +0200 Subject: [PATCH 0723/1102] Moved OS and package detection care to setuptools install command --- setup.py | 62 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/setup.py b/setup.py index 404c10fb..67b2a525 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,10 @@ import os import sys try: from setuptools import setup, Extension + from setuptools.command.install import install haveSetuptools = True except ImportError: + install = object haveSetuptools = False from importlib import import_module @@ -127,7 +129,7 @@ def detectOS(): return detectOS.result -def detectPrereqs(missing=False): +def detectPrereqs(missing=True): available = [] for module in packageName.keys(): try: @@ -144,47 +146,51 @@ def prereqToPackages(): print "You can install the requirements by running, as root:" print "%s %s" % ( packageManager[detectOS()], " ".join( - packageName[x][detectOS()] for x in detectPrereqs(True))) - for package in detectPrereqs(True): - try: - if packageName[package]['optional']: - print packageName[package]['description'] - except KeyError: - pass + packageName[x][detectOS()] for x in detectPrereqs())) + for package in detectPrereqs(): + if packageName[package].get('optional'): + print packageName[package].get('description') + def compilerToPackages(): if not detectOS() in compiling: return print "You can install the requirements by running, as root:" print "%s %s" % ( - packageManager[detectOS()], compiling[detectOS()]) + packageManager[detectOS.result], compiling[detectOS.result]) -if __name__ == "__main__": - detectOS.result = None - detectPrereqs.result = None - if detectPrereqs(True) != [] and detectOS() in packageManager: - if detectOS() is not None: + +class InstallCmd(install): + def run(self): + detectOS.result = None + prereqs = detectPrereqs() + if prereqs and detectOS() in packageManager: print "It looks like you're using %s. " \ "It is highly recommended to use the package manager " \ - "instead of setuptools." % (detectOS()) + "instead of setuptools." % (detectOS.result) prereqToPackages() try: - for module in detectPrereqs(True): + for module in prereqs: if not packageName[module]['optional']: sys.exit() except KeyError: sys.exit() - if not haveSetuptools: - print "It looks like you're missing setuptools." - sys.exit() - if detectPrereqs(True) != [] and sys.stdin.isatty(): - print "Press Return to continue" - try: - nothing = raw_input() - except NameError: - pass + if not haveSetuptools: + print "It looks like you're missing setuptools." + sys.exit() + if prereqs and sys.stdin.isatty(): + print "Press Return to continue" + try: + raw_input() + except NameError: + pass + + 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() @@ -197,7 +203,7 @@ if __name__ == "__main__": installRequires = [] # this will silently accept alternative providers of msgpack if they are already installed - if "msgpack" in detectPrereqs(True): + if "msgpack" in detectPrereqs(): installRequires.append("msgpack-python") try: @@ -254,7 +260,8 @@ if __name__ == "__main__": # 'pybitmessage = pybitmessage.bitmessagemain:main' # ] }, - scripts=['src/pybitmessage'] + scripts=['src/pybitmessage'], + cmdclass={'install': InstallCmd} ) except SystemExit as err: print err.message @@ -262,4 +269,3 @@ if __name__ == "__main__": print "It looks like building the package failed.\n" \ "You may be missing a C++ compiler and the OpenSSL headers." compilerToPackages() - -- 2.45.1 From c1bdcc2aba3df3c554b624afee52b9263d0c14ed Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 4 Apr 2017 10:43:29 +0200 Subject: [PATCH 0724/1102] ACKdata handling changes - any type of object can now serve as ACKdata --- src/class_objectProcessor.py | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 446e09ab..e13c262c 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -56,6 +56,8 @@ class objectProcessor(threading.Thread): while True: objectType, data = queues.objectProcessorQueue.get() + self.checkackdata(data) + try: if objectType == 0: # getpubkey self.processgetpubkey(data) @@ -86,6 +88,22 @@ class objectProcessor(threading.Thread): logger.debug('Saved %s objects from the objectProcessorQueue to disk. objectProcessorThread exiting.' % str(numberOfObjectsThatWereInTheObjectProcessorQueue)) state.shutdown = 2 break + + def checkackdata(self, data): + # Let's check whether this is a message acknowledgement bound for us. + if len(data) < 32: + return + if data[-32:] in shared.ackdataForWhichImWatching: + logger.info('This object 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:]) + queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], 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): readPosition = 20 # bypass the nonce, time, and object type @@ -322,19 +340,6 @@ 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:]) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr._translate("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. -- 2.45.1 From fe93473fc5a7149015e1e68027a1e6ccd5507eae Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 4 Apr 2017 10:44:53 +0200 Subject: [PATCH 0725/1102] getpubkey length handling - don't try to process getpubkey that is too long --- src/class_objectProcessor.py | 3 +++ src/shared.py | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index e13c262c..ad78bd87 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -106,6 +106,9 @@ class objectProcessor(threading.Thread): 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]) diff --git a/src/shared.py b/src/shared.py index 69794033..4fd66610 100644 --- a/src/shared.py +++ b/src/shared.py @@ -432,8 +432,6 @@ 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( -- 2.45.1 From 51aeb284ca8b5a6f78d8eb6528c4e733bfc656fc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 4 Apr 2017 10:46:01 +0200 Subject: [PATCH 0726/1102] Async network IO updates - WIP --- src/bmproto.py | 192 ++++++++++++++++++++++++++++++++++++++++++++- src/network/tls.py | 70 ++++++++--------- 2 files changed, 222 insertions(+), 40 deletions(-) diff --git a/src/bmproto.py b/src/bmproto.py index 0a147d3e..5cd08779 100644 --- a/src/bmproto.py +++ b/src/bmproto.py @@ -9,14 +9,19 @@ from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, So from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError import addresses +from bmconfigparser import BMConfigParser import protocol class BMProtoError(ProxyError): pass -class BMConnection(AdvancedDispatcher): +class BMConnection(TLSDispatcher): # ~1.6 MB which is the maximum possible size of an inv message. maxMessageSize = 1600100 + # protocol specification says max 1000 addresses in one addr command + maxAddrCount = 1000 + # protocol specification says max 50000 objects in one inv command + maxObjectCount = 50000 def __init__(self, address=None, sock=None): AdvancedDispatcher.__init__(self, sock) @@ -25,12 +30,14 @@ class BMConnection(AdvancedDispatcher): if address is None and sock is not None: self.destination = self.addr() self.isOutbound = False + TLSHandshake.__init__(self, sock, server_side=True) print "received connection in background from %s:%i" % (self.destination[0], self.destination[1]) else: self.destination = address self.isOutbound = True self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.destination) + TLSHandshake.__init__(self, sock, server_side=False) print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) def bm_proto_reset(self): @@ -49,6 +56,11 @@ class BMConnection(AdvancedDispatcher): self.set_state("bm_header", 0) return False + def state_bm_ready(self): + self.sendAddr() + self.sendBigInv() + return True + def state_bm_header(self): if len(self.read_buf) < protocol.Header.size: print "Length below header size" @@ -74,18 +86,27 @@ class BMConnection(AdvancedDispatcher): if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: print "Bad checksum, ignoring" self.invalid = True + retval = True if not self.invalid: try: - getattr(self, "bm_command_" + str(self.command))() + retval = getattr(self, "bm_command_" + str(self.command).lower())() except AttributeError: # unimplemented command print "unimplemented command %s" % (self.command) else: print "Skipping command %s due to invalid data" % (self.command) - self.set_state("bm_header", self.payloadLength) - self.bm_proto_reset() + if retval: + self.set_state("bm_header", self.payloadLength) + self.bm_proto_reset() + # else assume the command requires a different state to follow return True + def bm_command_error(self): + def bm_command_getdata(self): + def bm_command_object(self): + def bm_command_ping(self): + def bm_command_pong(self): + def bm_command_verack(self): self.verackReceived = True return True @@ -102,8 +123,171 @@ class BMConnection(AdvancedDispatcher): self.userAgent = self.payload[readPosition:readPosition + useragentLength] readPosition += useragentLength print "user agent: %s" % (self.userAgent) + if not self.peerValidityChecks(): + # TODO ABORT + return True + self.write_buf += protocol.CreatePacket('verack') + self.verackSent = True + 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", self.payloadLength) + else: + self.set_state("bm_ready", self.payloadLength) + self.bm_proto_reset() + return False + + def peerValidityChecks(self): + if self.remoteProtocolVersion < 3: + self.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.peer)) + return False + if self.timeOffset > 3600: + self.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.peer, self.timeOffset) + shared.timeOffsetWrongCount += 1 + return False + elif self.timeOffset < -3600: + self.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.peer, self.timeOffset) + shared.timeOffsetWrongCount += 1 + return False + else: + shared.timeOffsetWrongCount = 0 + if len(self.streams) == 0: + self.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.peer)) + return False return True + def sendAddr(self): + def sendChunk(): + if numberOfAddressesInAddrMessage == 0: + return + self.write_buf += protocol.CreatePacket('addr', \ + addresses.encodeVarint(numberOfAddressesInAddrMessage) + payload))) + + # 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 = '' + + for stream in self.streams: + addrsInMyStream = {} + addrsInChildStreamLeft = {} + addrsInChildStreamRight = {} + + 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.streams: + 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.streams: + 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: + addressCount += 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 addressCount >= BMConnection.maxAddrCount: + sendChunk() + payload = '' + addressCount = 0 + for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft: + addressCount += 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 addressCount >= BMConnection.maxAddrCount: + sendChunk() + payload = '' + addressCount = 0 + for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight: + addressCount += 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 addressCount >= BMConnection.maxAddrCount: + sendChunk() + payload = '' + addressCount = 0 + + # flush + sendChunk() + + def sendBigInv(self): + def sendChunk(): + if objectCount == 0: + return + payload = encodeVarint(objectCount) + payload + logger.debug('Sending huge inv message with %i objects to just this one peer', + str(numberOfObjects)) + self.write_buf += protocol.CreatePacket('inv', payload) + + # Select all hashes for objects in this stream. + bigInvList = {} + for stream in self.streams: + for hash in Inventory().unexpired_hashes_by_stream(stream): + if not self.objectHashHolderInstance.hasHash(hash): + bigInvList[hash] = 0 + objectCount = 0 + payload = '' + # 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 >= BMConnection.maxObjectCount: + self.sendChunk() + payload = '' + objectCount = 0 + + # flush + sendChunk() + class Socks5BMConnection(Socks5Connection, BMConnection): def __init__(self, address): diff --git a/src/network/tls.py b/src/network/tls.py index 8f104c55..023f6cac 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -2,57 +2,45 @@ SSL/TLS negotiation. """ -import asyncore +from network.advanceddispatcher import AdvancedDispatcher +import network.asyncore_pollchoose as asyncore import socket import ssl import sys import protocol -class TLSHandshake(asyncore.dispatcher): - """ - Negotiates a SSL/TLS connection before handing itself spawning a - dispatcher that can deal with the overlying protocol as soon as the - handshake has been completed. - - `handoff` is a function/method called when the handshake has completed. - `address` is a tuple consisting of hostname/address and port to connect to - if nothing is passed in `sock`, which can take an already-connected socket. - `certfile` can take a path to a certificate bundle, and `server_side` - indicates whether the socket is intended to be a server-side or client-side - socket. - """ - +class TLSDispatcher(AdvancedDispatcher): def __init__(self, address=None, sock=None, - certfile=None, keyfile=None, server_side=False, ciphers=None, init_parent=True): - if not hasattr(self, '_map'): - asyncore.dispatcher.__init__(self, sock) + certfile=None, keyfile=None, server_side=False, ciphers=protocol.sslProtocolCiphers): self.want_read = self.want_write = True - self.certfile = certfile - self.keyfile = keyfile + 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 - if sock is None: - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) -# logger.info('Connecting to %s%d', address[0], address[1]) - self.connect(address) - elif self.connected: - # Initiate the handshake for an already-connected socket. - self.handle_connect() + self.isSSL = False - def handle_connect(self): + def state_tls_init(self): + self.isSSL = 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.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_NOSSLv2 | ssl.OP_NOSSLv3 - self.sslSock = context.wrap_socket(self.sock, server_side = self.server_side, do_handshake_on_connect=False) + 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.sock, server_side = self.server_side, do_handshake_on_connect=False) else: self.sslSocket = ssl.wrap_socket(self.socket, server_side=self.server_side, @@ -67,20 +55,30 @@ class TLSHandshake(asyncore.dispatcher): # self.socket.context.set_ecdh_curve("secp256k1") def writable(self): - return self.want_write + if self.tlsStarted and not self.tlsDone: + return self.want_write + else: + return AdvancedDispacher.writable(self) def readable(self): - return self.want_read + if self.tlsStarted and not self.tlsDone: + return self.want_read + else: + return AdvancedDispacher.readable(self) def handle_read(self): - if not self.tlsDone: + if self.tlsStarted and not self.tlsDone: self._handshake() + else: + return AdvancedDispacher.handle_read(self) def handle_write(self): - if not self.tlsDone: + if self.tlsStarted and not not self.tlsDone: self._handshake() + else: + return AdvancedDispacher.handle_write(self) - def _handshake(self): + def state_tls_handshake(self): """ Perform the handshake. """ -- 2.45.1 From e832ea168957ec04821aac9a886bd9e3a4779696 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 4 Apr 2017 12:31:52 +0200 Subject: [PATCH 0727/1102] setup.py fix nested list --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 67b2a525..fc9e367a 100644 --- a/setup.py +++ b/setup.py @@ -220,7 +220,7 @@ if __name__ == "__main__": url='https://bitmessage.org', # TODO: add keywords #keywords='', - install_requires=[installRequires], + install_requires=installRequires, extras_require={ 'qrcode': ['qrcode'], 'pyopencl': ['pyopencl'] -- 2.45.1 From e6f0b34f9b1574019623cb3b6ce8e4a0803a2a13 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 28 Mar 2017 17:38:05 +0300 Subject: [PATCH 0728/1102] Fixed some inconvenience on first run mainly in Ubuntu. - immediately return from initCL() if numpy or pyopencl is unevailable (no ImportError because of resetPoW() call) - use glob to find C extension even if it named like `bitmsghash.x86_64-linux-gnu.so` If user chooses to show the Settings dialog: - activate the "Network Settings" tab - remove option 'dontconnect' if settings have been saved --- src/bitmessageqt/__init__.py | 16 ++++++++++++---- src/openclpow.py | 7 ++++--- src/proofofwork.py | 11 ++++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e861f767..76f6e46d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1619,7 +1619,8 @@ class MyForm(settingsmixin.SMainWindow): self.connectDialogInstance = connectDialog(self) if self.connectDialogInstance.exec_(): if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): - BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + BMConfigParser().remove_option( + 'bitmessagesettings', 'dontconnect') BMConfigParser().save() else: self.click_actionSettings() @@ -2349,7 +2350,12 @@ class MyForm(settingsmixin.SMainWindow): 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( self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) BMConfigParser().set('bitmessagesettings', 'minimizetotray', str( @@ -4517,9 +4523,11 @@ def run(): myapp.appIndicatorInit(app) myapp.ubuntuMessagingMenuInit() myapp.notifierInit() - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): - myapp.showConnectDialog() # ask the user if we may connect - + myapp._firstrun = BMConfigParser().safeGetBoolean( + 'bitmessagesettings', 'dontconnect') + if myapp._firstrun: + myapp.showConnectDialog() # ask the user if we may connect + # try: # if BMConfigParser().get('bitmessagesettings', 'mailchuck') < 1: # myapp.showMigrationWizard(BMConfigParser().get('bitmessagesettings', 'mailchuck')) diff --git a/src/openclpow.py b/src/openclpow.py index 59375329..ca40e634 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -26,7 +26,9 @@ except: libAvailable = False def initCL(): - global ctx, queue, program, hash_dt + global ctx, queue, program, hash_dt, libAvailable + if libAvailable is False: + return del enabledGpus[:] del vendors[:] del gpus[:] @@ -98,8 +100,7 @@ def do_opencl_pow(hash, target): # logger.debug("Took %d tries.", progress) return output[0][0] -if libAvailable: - initCL() +initCL() if __name__ == "__main__": target = 54227212183L diff --git a/src/proofofwork.py b/src/proofofwork.py index 493b8b0c..eb845c25 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -266,9 +266,18 @@ def init(): else: try: bso = ctypes.CDLL(os.path.join(paths.codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL %s", 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 -- 2.45.1 From 96d58f3c1191098dc1b7a22e960dfc691e32bbfb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 16 Apr 2017 18:27:15 +0200 Subject: [PATCH 0729/1102] Asyncore update (WIP) --- src/bmproto.py | 159 ++++++++++++++++++++++++----- src/network/advanceddispatcher.py | 16 ++- src/network/asyncore_pollchoose.py | 42 ++++++-- src/network/http.py | 2 +- src/network/node.py | 66 ++++++++++++ src/network/socks4a.py | 24 ++--- src/network/socks5.py | 24 ++--- src/network/tls.py | 52 +++++++--- src/protocol.py | 5 + 9 files changed, 306 insertions(+), 84 deletions(-) create mode 100644 src/network/node.py diff --git a/src/bmproto.py b/src/bmproto.py index 5cd08779..c9160c3b 100644 --- a/src/bmproto.py +++ b/src/bmproto.py @@ -1,15 +1,20 @@ import hashlib import time +from pprint import pprint import socket +from struct import unpack from network.advanceddispatcher import AdvancedDispatcher +from network.node import Node import network.asyncore_pollchoose as asyncore from network.proxy import Proxy, ProxyError, GeneralProxyError 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 +import shared import protocol class BMProtoError(ProxyError): pass @@ -30,14 +35,14 @@ class BMConnection(TLSDispatcher): if address is None and sock is not None: self.destination = self.addr() self.isOutbound = False - TLSHandshake.__init__(self, sock, server_side=True) + TLSDispatcher.__init__(self, sock, server_side=True) print "received connection in background from %s:%i" % (self.destination[0], self.destination[1]) else: self.destination = address self.isOutbound = True self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.destination) - TLSHandshake.__init__(self, sock, server_side=False) + TLSDispatcher.__init__(self, sock, server_side=False) print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) def bm_proto_reset(self): @@ -47,19 +52,22 @@ class BMConnection(TLSDispatcher): self.checksum = None self.payload = None self.invalid = False + self.payloadOffset = 0 def state_init(self): self.bm_proto_reset() - self.write_buf += protocol.assembleVersionMessage(self.destination[0], self.destination[1], (1,), False) + self.append_write_buf(protocol.assembleVersionMessage(self.destination[0], self.destination[1], (1,), False)) if True: print "Sending version (%ib)" % len(self.write_buf) - self.set_state("bm_header", 0) + self.set_state("bm_header") return False def state_bm_ready(self): + print "doing bm ready" self.sendAddr() self.sendBigInv() - return True + self.set_state("bm_header") + return False def state_bm_header(self): if len(self.read_buf) < protocol.Header.size: @@ -101,32 +109,127 @@ class BMConnection(TLSDispatcher): # 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, address, port = self.decode_payload_content("Q16sH") + return Node(services, address, port) + + def decode_payload_content(self, pattern = "v"): + # 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 + + retval = [] + size = 0 + insideDigit = False + + for i in range(len(pattern)): + if pattern[i] in "0123456789": + size = size * 10 + int(pattern[i]) + continue + elif pattern[i] == "l": + size = self.decode_payload_varint() + continue + if size > 0: + innerval = [] + if pattern[i] == "s": + retval.append(self.payload[self.payloadOffset:self.payloadOffset + size]) + self.payloadOffset += size + else: + for j in range(size): + if "," in pattern[i:]: + retval.append(self.decode_payload_content(pattern[i:pattern.index(",")])) + else: + retval.append(self.decode_payload_content(pattern[i:])) + size = 0 + else: + if pattern[i] == "v": + retval.append(self.decode_payload_varint()) + if pattern[i] == "i": + retval.append(self.decode_payload_node()) + if pattern[i] == "H": + retval.append(unpack(">H", self.payload[self.payloadOffset:self.payloadOffset+2])[0]) + self.payloadOffset += 2 + if pattern[i] == "I": + retval.append(unpack(">I", self.payload[self.payloadOffset:self.payloadOffset+4])[0]) + self.payloadOffset += 4 + if pattern[i] == "Q": + retval.append(unpack(">Q", self.payload[self.payloadOffset:self.payloadOffset+8])[0]) + self.payloadOffset += 8 + return retval + def bm_command_error(self): + fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") + def bm_command_getdata(self): + items = self.decode_payload_content("l32s") + #self.antiIntersectionDelay(True) # only handle getdata requests if we have been connected long enough + for i in items: + logger.debug('received getdata request for item:' + hexlify(i)) + if self.objectHashHolderInstance.hasHash(i): + self.antiIntersectionDelay() + else: + if i in Inventory(): + self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].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,)) + def bm_command_object(self): + lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(self.payload) + self.downloadQueue.task_done(calculateInventoryHash(self.payload)) + + def bm_command_addr(self): + addresses = self.decode_payload_content("lQbQ16sH") + def bm_command_ping(self): + self.append_write_buf(protocol.CreatePacket('pong')) + def bm_command_pong(self): + # nothing really + pass def bm_command_verack(self): self.verackReceived = True - return True + if self.verackSent: + if self.isSSL: + self.set_state("tls_init", self.payloadLength) + else: + self.set_state("bm_ready", self.payloadLength) + else: + self.set_state("bm_header", self.payloadLength) + self.bm_proto_reset() + return False def bm_command_version(self): - self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) + #self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) + self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, self.userAgent, self.streams = self.decode_payload_content("IQQiiQlslv") + self.timeOffset = self.timestamp - int(time.time()) print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) print "services: %08X" % (self.services) print "time offset: %i" % (self.timestamp - int(time.time())) - print "my external IP: %s" % (socket.inet_ntoa(self.myExternalIP)) - print "remote node incoming port: %i" % (self.remoteNodeIncomingPort) - useragentLength, lengthOfUseragentVarint = addresses.decodeVarint(self.payload[80:84]) - readPosition = 80 + lengthOfUseragentVarint - self.userAgent = self.payload[readPosition:readPosition + useragentLength] - readPosition += useragentLength + print "my external IP: %s" % (self.sockNode.address) + print "remote node incoming port: %i" % (self.peerNode.port) print "user agent: %s" % (self.userAgent) if not self.peerValidityChecks(): # TODO ABORT return True - self.write_buf += protocol.CreatePacket('verack') + self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.isOutbound)): @@ -141,21 +244,21 @@ class BMConnection(TLSDispatcher): def peerValidityChecks(self): if self.remoteProtocolVersion < 3: - self.write_buf += protocol.assembleErrorMessage(fatal=2, - errorText="Your is using an old protocol. Closing connection.") + 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.peer)) return False if self.timeOffset > 3600: - self.write_buf += protocol.assembleErrorMessage(fatal=2, - errorText="Your time is too far in the future compared to mine. Closing connection.") + 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.peer, self.timeOffset) shared.timeOffsetWrongCount += 1 return False elif self.timeOffset < -3600: - self.write_buf += protocol.assembleErrorMessage(fatal=2, - errorText="Your time is too far in the past compared to mine. Closing connection.") + 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.peer, self.timeOffset) shared.timeOffsetWrongCount += 1 @@ -163,8 +266,8 @@ class BMConnection(TLSDispatcher): else: shared.timeOffsetWrongCount = 0 if len(self.streams) == 0: - self.write_buf += protocol.assembleErrorMessage(fatal=2, - errorText="We don't have shared stream interests. Closing connection."))) + 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.peer)) return False @@ -174,8 +277,8 @@ class BMConnection(TLSDispatcher): def sendChunk(): if numberOfAddressesInAddrMessage == 0: return - self.write_buf += protocol.CreatePacket('addr', \ - addresses.encodeVarint(numberOfAddressesInAddrMessage) + payload))) + self.append_write_buf(protocol.CreatePacket('addr', \ + addresses.encodeVarint(numberOfAddressesInAddrMessage) + payload)) # We are going to share a maximum number of 1000 addrs (per overlapping # stream) with our peer. 500 from overlapping streams, 250 from the @@ -265,7 +368,7 @@ class BMConnection(TLSDispatcher): payload = encodeVarint(objectCount) + payload logger.debug('Sending huge inv message with %i objects to just this one peer', str(numberOfObjects)) - self.write_buf += protocol.CreatePacket('inv', payload) + self.append_write_buf(protocol.CreatePacket('inv', payload)) # Select all hashes for objects in this stream. bigInvList = {} @@ -335,15 +438,15 @@ if __name__ == "__main__": direct = BMConnection(host) while len(asyncore.socket_map) > 0: print "loop, state = %s" % (direct.state) - asyncore.loop(timeout=1, count=1) + 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=1, count=1) + asyncore.loop(timeout=10, count=1) proxy = Socks4aBMConnection(host) while len(asyncore.socket_map) > 0: # print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=1, count=1) + asyncore.loop(timeout=10, count=1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index df6e58ef..dc7eedb0 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -10,11 +10,16 @@ class AdvancedDispatcher(asyncore.dispatcher): self.write_buf = b"" self.state = "init" - def slice_read_buf(self, length=0): - self.read_buf = self.read_buf[length:] + def append_write_buf(self, string = None): + self.write_buf += string def slice_write_buf(self, length=0): - self.write_buf = self.read_buf[length:] + if length > 0: + self.write_buf = self.write_buf[length:] + + def slice_read_buf(self, length=0): + if length > 0: + self.read_buf = self.read_buf[length:] def read_buf_sufficient(self, length=0): if len(self.read_buf) < length: @@ -23,7 +28,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return True def process(self): - if self.state != "init" and len(self.read_buf) == 0: + if self.state not in ["init", "tls_handshake"] and len(self.read_buf) == 0: return while True: try: @@ -34,7 +39,7 @@ class AdvancedDispatcher(asyncore.dispatcher): # missing state raise - def set_state(self, state, length): + def set_state(self, state, length=0): self.slice_read_buf(length) self.state = state @@ -45,6 +50,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len def handle_read(self): + print "handle_read" self.read_buf += self.recv(AdvancedDispatcher._buf_len) self.process() diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 7fa19f4a..4ccce7f9 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -60,6 +60,9 @@ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF)) +OP_READ = 1 +OP_WRITE = 2 + try: socket_map except NameError: @@ -178,17 +181,25 @@ def poll_poller(timeout=0.0, map=None): poll_poller.pollster = select.poll() if map: for fd, obj in list(map.items()): - flags = 0 + 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 - if flags: - try: + newflags |= OP_WRITE + else: + newflags &= ~ OP_WRITE + if newflags != obj.flags: + obj.flags = newflags + if obj.poller_registered: poll_poller.pollster.modify(fd, flags) - except IOError: + else: poll_poller.pollster.register(fd, flags) + obj.poller_registered = True try: r = poll_poller.pollster.poll(timeout) except KeyboardInterrupt: @@ -213,19 +224,28 @@ def epoll_poller(timeout=0.0, map=None): epoll_poller.pollster = select.epoll() if map: for fd, obj in map.items(): - flags = 0 + flags = newflags = 0 if obj.readable(): flags |= select.POLLIN | select.POLLPRI - if obj.writable(): + newflags |= OP_READ + else: + newflags &= ~ OP_READ + # accepting sockets should not be writable + if obj.writable() and not obj.accepting: flags |= select.POLLOUT - if flags: + newflags |= OP_WRITE + else: + newflags &= ~ OP_WRITE + if newflags != obj.flags: + obj.flags = newflags # Only check for exceptions if object was either readable # or writable. flags |= select.POLLERR | select.POLLHUP | select.POLLNVAL - try: - epoll_poller.pollster.register(fd, flags) - except IOError: + if obj.poller_registered: epoll_poller.pollster.modify(fd, flags) + else: + epoll_poller.pollster.register(fd, flags) + obj.poller_registered = True try: r = epoll_poller.pollster.poll(timeout) except select.error, err: @@ -306,6 +326,8 @@ class dispatcher: closing = False addr = None ignore_log_types = frozenset(['warning']) + poller_registered = False + flags = 0 def __init__(self, sock=None, map=None): if map is None: diff --git a/src/network/http.py b/src/network/http.py index 93828c83..55cb81a1 100644 --- a/src/network/http.py +++ b/src/network/http.py @@ -19,7 +19,7 @@ class HttpConnection(AdvancedDispatcher): print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) def state_init(self): - self.write_buf += "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n" % (self.path, self.destination[0]) + 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 diff --git a/src/network/node.py b/src/network/node.py new file mode 100644 index 00000000..904ff4d1 --- /dev/null +++ b/src/network/node.py @@ -0,0 +1,66 @@ +import socket +import protocol + +class Node (object): + TYPE_IPV4 = 1 + TYPE_IPV6 = 2 + TYPE_ONION = 3 + TYPE_LOCAL = 4 + TYPE_LOOPBACK = 8 + TYPE_UNDEF = 12 + + def __init__(self, services, address, port): + self.services = services + self.address, self.addressType = Node.decodeIPAddress(address) + self.port = port + + def isLocal(self): + return self.addressType | Node.TYPE_LOCAL > 0 + + def isGlobal(self): + return self.addressType <= Node.TYPE_ONION + + def isOnion(self): + return self.addressType | Node.TYPE_ONION > 0 + + def isLoopback(self): + return self.addressType | Node.TYPE_LOOPBACK > 0 + + @staticmethod + def decodeIPAddress(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 Node.decodeIPv4Address(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, Node.TYPE_ONION + 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 hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF + return Node.decodeIPv6Address(host, hostStandardFormat) + + @staticmethod + def decodeIPv4Address(host, hostStandardFormat): + if host[0] == '\x7F': # 127/8 + return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOOPBACK + if host[0] == '\x0A': # 10/8 + return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL + if host[0:2] == '\xC0\xA8': # 192.168/16 + return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL + if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 + return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL + return hostStandardFormat, Node.TYPE_IPV4 + + @staticmethod + def _checkIPv6Address(host, hostStandardFormat): + if host == ('\x00' * 15) + '\x01': + return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOOPBACK + if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: + return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOCAL + if (ord(host[0]) & 0xfe) == 0xfc: + return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF + return hostStandardFormat, Node.TYPE_IPV6 diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 091e09a5..02c8d4af 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -59,28 +59,28 @@ class Socks4aConnection(Socks4a): def state_auth_done(self): # Now we can request the actual connection rmtrslv = False - self.write_buf += struct.pack('>BBH', 0x04, 0x01, self.destination[1]) + 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.write_buf += ipaddr + 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.write_buf += struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01) + 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.write_buf += self.ipaddr + self.append_write_buf(self.ipaddr) if self._auth: - self.write_buf += self._auth[0] - self.write_buf += chr(0x00).encode() + self.append_write_buf(self._auth[0]) + self.append_write_buf(chr(0x00).encode()) if rmtrslv: - self.write_buf += self.destination[0] + chr(0x00).encode() + self.append_write_buf(self.destination[0] + chr(0x00).encode()) self.set_state("pre_connect", 0) @@ -92,12 +92,12 @@ class Socks4aResolver(Socks4a): def state_auth_done(self): # Now we can request the actual connection - self.write_buf += struct.pack('>BBH', 0x04, 0xF0, self.destination[1]) - self.write_buf += struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01) + 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.write_buf += self._auth[0] - self.write_buf += chr(0x00).encode() - self.write_buf += self.host + chr(0x00).encode() + 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", 0) def resolved(self): diff --git a/src/network/socks5.py b/src/network/socks5.py index 841c253b..5ba6f3e3 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -17,9 +17,9 @@ class Socks5(Proxy): def state_init(self): if self._auth: - self.write_buf += struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02) + self.append_write_buf(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) else: - self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) + self.append_write_buf(struct.pack('BBB', 0x05, 0x01, 0x00)) self.set_state("auth_1", 0) def state_auth_1(self): @@ -35,9 +35,9 @@ class Socks5(Proxy): self.set_state("auth_done", 2) elif ret[1] == 2: # username/password - self.write_buf += struct.pack('BB', 1, len(self._auth[0])) + \ + 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._auth[1]) self.set_state("auth_1", 2) else: if ret[1] == 0xff: @@ -130,23 +130,23 @@ class Socks5Connection(Socks5): def state_auth_done(self): # Now we can request the actual connection - self.write_buf += struct.pack('BBB', 0x05, 0x01, 0x00) + 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.write_buf += chr(0x01).encode() + self.ipaddr + 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.write_buf += chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0] + 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.write_buf += chr(0x01).encode() + self.ipaddr - self.write_buf += struct.pack(">H", self.destination[1]) + self.append_write_buf(chr(0x01).encode() + self.ipaddr) + self.append_write_buf(struct.pack(">H", self.destination[1])) self.set_state("pre_connect", 0) @@ -158,9 +158,9 @@ class Socks5Resolver(Socks5): def state_auth_done(self): # Now we can request the actual connection - self.write_buf += struct.pack('BBB', 0x05, 0xF0, 0x00) - self.write_buf += chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host) - self.write_buf += struct.pack(">H", self.port) + 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", 0) def resolved(self): diff --git a/src/network/tls.py b/src/network/tls.py index 023f6cac..c7554891 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -2,12 +2,14 @@ SSL/TLS negotiation. """ -from network.advanceddispatcher import AdvancedDispatcher -import network.asyncore_pollchoose as asyncore +import os import socket import ssl import sys +from network.advanceddispatcher import AdvancedDispatcher +import network.asyncore_pollchoose as asyncore +import paths import protocol class TLSDispatcher(AdvancedDispatcher): @@ -30,6 +32,7 @@ class TLSDispatcher(AdvancedDispatcher): 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): @@ -40,7 +43,7 @@ class TLSDispatcher(AdvancedDispatcher): 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.sock, server_side = self.server_side, do_handshake_on_connect=False) + 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, @@ -51,49 +54,66 @@ class TLSDispatcher(AdvancedDispatcher): do_handshake_on_connect=False) self.sslSocket.setblocking(0) self.want_read = self.want_write = True + self.set_state("tls_handshake") # if hasattr(self.socket, "context"): # self.socket.context.set_ecdh_curve("secp256k1") def writable(self): - if self.tlsStarted and not self.tlsDone: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + print "tls writable, %r" % (self.want_write) return self.want_write else: - return AdvancedDispacher.writable(self) + return AdvancedDispatcher.writable(self) def readable(self): - if self.tlsStarted and not self.tlsDone: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + print "tls readable, %r" % (self.want_read) return self.want_read else: - return AdvancedDispacher.readable(self) + return AdvancedDispatcher.readable(self) def handle_read(self): - if self.tlsStarted and not self.tlsDone: - self._handshake() + # wait for write buffer flush + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + print "handshaking (read)" + self.state_tls_handshake() else: - return AdvancedDispacher.handle_read(self) + print "not handshaking (read)" + return AdvancedDispatcher.handle_read(self) def handle_write(self): - if self.tlsStarted and not not self.tlsDone: - self._handshake() + # wait for write buffer flush + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + print "handshaking (write)" + self.state_tls_handshake() else: - return AdvancedDispacher.handle_write(self) + print "not handshaking (write)" + return AdvancedDispatcher.handle_write(self) def state_tls_handshake(self): - """ - Perform the handshake. - """ + # wait for flush + if len(self.write_buf) > 0: + return False + # Perform the handshake. try: + print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError, err: + print "handshake fail" self.want_read = self.want_write = False if err.args[0] == ssl.SSL_ERROR_WANT_READ: + print "want read" self.want_read = True elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + print "want write" self.want_write = True else: raise else: + print "handshake success" # The handshake has completed, so remove this channel and... self.del_channel() self.set_socket(self.sslSocket) self.tlsDone = True + self.state_bm_ready() + return False diff --git a/src/protocol.py b/src/protocol.py index 9698f917..9397cd8b 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -27,6 +27,11 @@ NODE_SSL = 2 #Bitfield flags BITFIELD_DOESACK = 1 +#Error types +STATUS_WARNING = 0 +STATUS_ERROR = 1 +STATUS_FATAL = 2 + eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( '>Q', random.randrange(1, 18446744073709551615)) -- 2.45.1 From bf76c7f6ec761eb10c4aece7068ac95f030d3ed8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 30 Apr 2017 10:39:48 +0200 Subject: [PATCH 0730/1102] Allow extended encoding in API --- src/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api.py b/src/api.py index d6d0b266..c8612d60 100644 --- a/src/api.py +++ b/src/api.py @@ -650,8 +650,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 4*24*60*60 elif len(params) == 6: toAddress, fromAddress, subject, message, encodingType, TTL = params - if encodingType != 2: - raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') + if encodingType not in [2, 3]: + raise APIError(6, 'The encoding type must be 2 or 3.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): -- 2.45.1 From 4c597d3f7cf9f83a763472aa165a1a4292019f20 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 30 Apr 2017 10:41:55 +0200 Subject: [PATCH 0731/1102] Error handling for non-interactive setup.py - thanks to @orlitzky #993 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fc9e367a..98b7fbd9 100644 --- a/setup.py +++ b/setup.py @@ -184,7 +184,7 @@ class InstallCmd(install): print "Press Return to continue" try: raw_input() - except NameError: + except EOFError, NameError: pass return install.run(self) -- 2.45.1 From 1c55bf7d4b0f050be13e020c996d9e4fb6b2d988 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 7 May 2017 20:15:16 +0200 Subject: [PATCH 0732/1102] Add umsgpack as fallback - if a "big" msgpack module isn't available, use bundled umsgpack --- src/fallback/__init__.py | 0 src/fallback/umsgpack/__init__.py | 0 src/fallback/umsgpack/umsgpack.py | 1057 +++++++++++++++++++++++++++++ src/helper_msgcoding.py | 5 +- 4 files changed, 1061 insertions(+), 1 deletion(-) create mode 100644 src/fallback/__init__.py create mode 100644 src/fallback/umsgpack/__init__.py create mode 100644 src/fallback/umsgpack/umsgpack.py diff --git a/src/fallback/__init__.py b/src/fallback/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/fallback/umsgpack/__init__.py b/src/fallback/umsgpack/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/fallback/umsgpack/umsgpack.py b/src/fallback/umsgpack/umsgpack.py new file mode 100644 index 00000000..cd7a2037 --- /dev/null +++ b/src/fallback/umsgpack/umsgpack.py @@ -0,0 +1,1057 @@ +# 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_msgcoding.py b/src/helper_msgcoding.py index 2ae44eea..2acdd6a4 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -1,6 +1,9 @@ #!/usr/bin/python2.7 -import msgpack +try: + import msgpack +except ImportError: + import fallback.umsgpack as msgpack import string import zlib -- 2.45.1 From 23b955592999038ab552e1f0444960a3773d65f1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 7 May 2017 20:15:57 +0200 Subject: [PATCH 0733/1102] Add TLS version debug info --- src/class_receiveDataThread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index aeb38e78..4e86196c 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -290,6 +290,8 @@ class receiveDataThread(threading.Thread): 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: -- 2.45.1 From d9d3515905a95852a7463e4c954c2449b91a06da Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 7 May 2017 20:16:49 +0200 Subject: [PATCH 0734/1102] Node class, WIP - for new network subsystem --- src/network/node.py | 114 ++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/network/node.py b/src/network/node.py index 904ff4d1..054d07d8 100644 --- a/src/network/node.py +++ b/src/network/node.py @@ -1,66 +1,66 @@ -import socket -import protocol +import time -class Node (object): - TYPE_IPV4 = 1 - TYPE_IPV6 = 2 - TYPE_ONION = 3 - TYPE_LOCAL = 4 - TYPE_LOOPBACK = 8 - TYPE_UNDEF = 12 +from inventory import PendingDownloadQueue - def __init__(self, services, address, port): - self.services = services - self.address, self.addressType = Node.decodeIPAddress(address) - self.port = port +try: + # pybloomfiltermmap + from pybloomfilter import BloomFilter +except ImportError: + try: + # pybloom + from pybloom import BloomFilter + except ImportError: + # bundled pybloom + from fallback.pybloom import BloomFilter - def isLocal(self): - return self.addressType | Node.TYPE_LOCAL > 0 - def isGlobal(self): - return self.addressType <= Node.TYPE_ONION +class Node(object): + invCleanPeriod = 300 + invInitialCapacity = 50000 + invErrorRate = 0.03 - def isOnion(self): - return self.addressType | Node.TYPE_ONION > 0 + def __init__(self): + self.initInvBloom() + self.initAddrBloom() - def isLoopback(self): - return self.addressType | Node.TYPE_LOOPBACK > 0 + def initInvBloom(self): + # lock? + self.invBloom = BloomFilter(capacity=Node.invInitialCapacity, + error_rate=Node.invErrorRate) - @staticmethod - def decodeIPAddress(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 Node.decodeIPv4Address(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, Node.TYPE_ONION - 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 hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF - return Node.decodeIPv6Address(host, hostStandardFormat) + def initAddrBloom(self): + # lock? + self.addrBloom = BloomFilter(capacity=Node.invInitialCapacity, + error_rate=Node.invErrorRate) - @staticmethod - def decodeIPv4Address(host, hostStandardFormat): - if host[0] == '\x7F': # 127/8 - return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOOPBACK - if host[0] == '\x0A': # 10/8 - return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL - if host[0:2] == '\xC0\xA8': # 192.168/16 - return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL - if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 - return hostStandardFormat, Node.TYPE_IPV4|Node.TYPE_LOCAL - return hostStandardFormat, Node.TYPE_IPV4 + def cleanBloom(self): + if self.lastcleaned < time.time() - Node.invCleanPeriod: + if PendingDownloadQueue().size() == 0: + self.initInvBloom() + self.initAddrBloom() + + def hasInv(self, hashid): + return hashid in self.invBloom + + def addInv(self, hashid): + self.invBloom.add(hashid) + + def hasAddr(self, hashid): + return hashid in self.invBloom + + def addInv(self, hashid): + self.invBloom.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 + +# 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 +# - @staticmethod - def _checkIPv6Address(host, hostStandardFormat): - if host == ('\x00' * 15) + '\x01': - return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOOPBACK - if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: - return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_LOCAL - if (ord(host[0]) & 0xfe) == 0xfc: - return hostStandardFormat, Node.TYPE_IPV6|Node.TYPE_UNDEF - return hostStandardFormat, Node.TYPE_IPV6 -- 2.45.1 From 90ef2d54e1b25f4d82f3c32390d5e65e93599f79 Mon Sep 17 00:00:00 2001 From: anryko Date: Tue, 9 May 2017 21:57:52 +0200 Subject: [PATCH 0735/1102] Fixed INSTALL.md markdown. --- INSTALL.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/INSTALL.md b/INSTALL.md index 823608fe..19a22f3d 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,13 +66,12 @@ 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. @@ -90,11 +89,12 @@ 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 -- 2.45.1 From fd2603247df24c5b35c496a3a2f5d7ad2e052334 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 10 May 2017 20:01:23 +0200 Subject: [PATCH 0736/1102] Fix onionbindip for some systems with IPv6 - in some cases when IPv6 stack is available and onionbindip is an IPv4 address, socket.bind doesn't change the bound address, ending up listening on everything --- src/class_singleListener.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 243a494a..7626542d 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -33,6 +33,10 @@ class singleListener(threading.Thread, StoppableThread): 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') sock = socket.socket(family, socket.SOCK_STREAM) -- 2.45.1 From 82c3c111b7acf64cacc7834042fd2233cbc3f9a3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 12 May 2017 14:39:25 +0200 Subject: [PATCH 0737/1102] Fix os-release open mode - thanks to @Lvl4Sword for reporting --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 98b7fbd9..a04c51d4 100644 --- a/setup.py +++ b/setup.py @@ -100,7 +100,7 @@ def detectOS(): elif sys.platform.startswith('win'): detectOS.result = "Windows" elif os.path.isfile("/etc/os-release"): - with open("/etc/os-release", 'rt') as osRelease: + with open("/etc/os-release", 'r') as osRelease: version = None for line in osRelease: if line.startswith("NAME="): -- 2.45.1 From 660997f8e77e192abf56230e062c70cc3a154b91 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 14 May 2017 15:40:35 +0200 Subject: [PATCH 0738/1102] Quick hack for excessively long messages - only process the first MB of a message for GUI purposes (parsing/rendering) --- src/bitmessageqt/messageview.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 40830a70..882dbb81 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -128,6 +128,7 @@ class MessageView(QtGui.QTextBrowser): self.html.reset() self.html.reset_safe() self.html.allow_picture = True - self.html.feed(data) + # quick hack to limit excessively compressed messages, limits viewing to first MB of data + self.html.feed(data[0:1048576]) self.html.close() self.showPlain() -- 2.45.1 From 9f4a1fa0a4792d3e50c5915fdd3079207ba158a0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 15 May 2017 12:18:07 +0200 Subject: [PATCH 0739/1102] Config file defaults and address unification - bmconfigpaser.py now allows to put default values for a specific option in the file - addresses as sections are now detected by "BM-" rather than just ignoring bitmessagesettings. There can now be other sections with a cleaner config file --- src/api.py | 30 ++++++++++----------- src/bitmessagecurses/__init__.py | 25 +++++++++-------- src/bitmessageqt/account.py | 2 +- src/bmconfigparser.py | 46 +++++++++++++++++++++----------- src/class_singleWorker.py | 2 +- src/class_smtpDeliver.py | 2 +- src/class_smtpServer.py | 4 +-- src/class_sqlThread.py | 2 +- src/shared.py | 38 +++++++++++++------------- 9 files changed, 81 insertions(+), 70 deletions(-) diff --git a/src/api.py b/src/api.py index c8612d60..82a56d40 100644 --- a/src/api.py +++ b/src/api.py @@ -169,22 +169,20 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def HandleListAddresses(self, method): data = '{"addresses":[' - configSections = BMConfigParser().sections() - for addressInKeysFile in configSections: - if addressInKeysFile != 'bitmessagesettings': - 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 = label.encode('base64') - data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': - streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) + 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 = label.encode('base64') + data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': + streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) data += ']}' return data diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index d710720f..903b7e68 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -1024,20 +1024,19 @@ def run(stdscr): curses.init_pair(9, curses.COLOR_YELLOW, curses.COLOR_BLACK) # orangish # Init list of address in 'Your Identities' tab - configSections = BMConfigParser().sections() + configSections = BMConfigParser().addressses() for addressInKeysFile in configSections: - if addressInKeysFile != "bitmessagesettings": - 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 + 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 addresses.reverse() stdscr.clear() diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 611f5039..eee6c7b4 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -13,7 +13,7 @@ from utils import str_broadcast_subscribers import time def getSortedAccounts(): - configSections = filter(lambda x: x != 'bitmessagesettings', BMConfigParser().sections()) + 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()) ) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 412d2fa5..448a9ffc 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -6,6 +6,17 @@ import os from singleton import Singleton import state +BMConfigDefaults = { + "bitmessagesettings": { + "maxaddrperstreamsend": 500, + "maxbootstrapconnections": 20, + "maxoutboundconnections": 8, + "maxtotalconnections": 200, + }, + "zlib": { + 'maxsize': 1048576 + } +} @Singleton class BMConfigParser(ConfigParser.SafeConfigParser): @@ -21,33 +32,38 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return ConfigParser.ConfigParser.get(self, section, option, raw, vars) except ConfigParser.InterpolationError: return ConfigParser.ConfigParser.get(self, section, option, True, vars) - return ConfigParser.ConfigParser.get(self, section, option, True, vars) + try: + return ConfigParser.ConfigParser.get(self, section, option, True, vars) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: + try: + return BMConfigDefaults[section][option] + except KeyError: + raise e def safeGetBoolean(self, section, field): - if self.has_option(section, field): - try: - return self.getboolean(section, field) - except ValueError: - return False - return False + try: + return self.getboolean(section, field) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError): + return False def safeGetInt(self, section, field, default=0): - if self.has_option(section, field): - try: - return self.getint(section, field) - except ValueError: - return default - return default + try: + return self.getint(section, field) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError): + return default def safeGet(self, section, option, default = None): - if self.has_option(section, option): + try: return self.get(section, option) - else: + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError): return default def items(self, section, raw=False, vars=None): return ConfigParser.ConfigParser.items(self, section, True, vars) + def addresses(self): + return filter(lambda x: x.startswith('BM-'), BMConfigParser().sections()) + def save(self): fileName = os.path.join(state.appdata, 'keys.dat') fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak' diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index b45c4aca..c2d16de4 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -136,7 +136,7 @@ class singleWorker(threading.Thread, StoppableThread): 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.sections() + """configSections = shared.config.addresses() for addressInKeysFile in configSections: if addressInKeysFile <> 'bitmessagesettings': status,addressVersionNumber,streamNumber,hashFromThisParticularAddress = decodeAddress(addressInKeysFile) diff --git a/src/class_smtpDeliver.py b/src/class_smtpDeliver.py index 9492f123..bb659ebe 100644 --- a/src/class_smtpDeliver.py +++ b/src/class_smtpDeliver.py @@ -59,7 +59,7 @@ class smtpDeliver(threading.Thread, StoppableThread): 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().sections())) + 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: diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 13882a94..3bc81a61 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -115,7 +115,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = p.sub(r'\1', mailfrom).split("@") if domain != SMTPDOMAIN: raise Exception("Bad domain %s", domain) - if sender not in BMConfigParser().sections(): + 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)) @@ -125,7 +125,7 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): sender, domain = msg_from.split("@") if domain != SMTPDOMAIN: raise Exception("Bad domain %s", domain) - if sender not in BMConfigParser().sections(): + 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)) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 9bd7e8e7..18606e74 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -316,7 +316,7 @@ class sqlThread(threading.Thread): # 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().sections(): + for addressInKeysFile in BMConfigParser().addressses(): try: previousTotalDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'noncetrialsperbyte')) / 320 previousSmallMessageDifficulty = float(BMConfigParser().getint(addressInKeysFile, 'payloadlengthextrabytes')) / 14000 diff --git a/src/shared.py b/src/shared.py index 4fd66610..34597c78 100644 --- a/src/shared.py +++ b/src/shared.py @@ -110,29 +110,27 @@ def reloadMyAddressHashes(): #myPrivateKeys.clear() keyfileSecure = checkSensitiveFilePermissions(state.appdata + 'keys.dat') - configSections = BMConfigParser().sections() hasEnabledKeys = False - for addressInKeysFile in configSections: - if addressInKeysFile <> 'bitmessagesettings': - 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 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'))) - 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) -- 2.45.1 From 183f509f094020f3a30810a99108623e16863c6d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 15 May 2017 12:23:16 +0200 Subject: [PATCH 0740/1102] Decompression limit - there is now a configurable decompression limit, default at 1MB. Oversize messages are trated as if they never arrived, just a log entry --- src/class_objectProcessor.py | 3 ++- src/helper_msgcoding.py | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index ad78bd87..253e6808 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -28,7 +28,6 @@ import tr from debug import logger import l10n - class objectProcessor(threading.Thread): """ The objectProcessor thread, of which there is only one, receives network @@ -71,6 +70,8 @@ class objectProcessor(threading.Thread): pass else: logger.critical('Error! Bug! The class_objectProcessor was passed an object type it doesn\'t recognize: %s' % str(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")) 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: diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index 2acdd6a4..a507685e 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -7,6 +7,7 @@ except ImportError: import string import zlib +from bmconfigparser import BMConfigParser import shared from debug import logger import messagetypes @@ -17,6 +18,10 @@ BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 +class DecompressionSizeException(Exception): + def __init__(self, size): + self.size = size + class MsgEncode(object): def __init__(self, message, encoding=BITMESSAGE_ENCODING_SIMPLE): @@ -65,11 +70,24 @@ class MsgDecode(object): 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 + else: + raise DecompressionSizeException(len(tmp)) + try: - tmp = msgpack.loads(zlib.decompress(data)) - except zlib.error: - logger.error("Error decompressing message") - raise + tmp = msgpack.loads(tmp) except (msgpack.exceptions.UnpackException, msgpack.exceptions.ExtraData): logger.error("Error msgunpacking message") -- 2.45.1 From 198470f734aa6cc8744d40af50fea5dc5ac3c815 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 15 May 2017 12:25:30 +0200 Subject: [PATCH 0741/1102] Revert parser/renderer max message size - it's now dealt with during decoding --- src/bitmessageqt/messageview.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 882dbb81..40830a70 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -128,7 +128,6 @@ class MessageView(QtGui.QTextBrowser): self.html.reset() self.html.reset_safe() self.html.allow_picture = True - # quick hack to limit excessively compressed messages, limits viewing to first MB of data - self.html.feed(data[0:1048576]) + self.html.feed(data) self.html.close() self.showPlain() -- 2.45.1 From d498f1c0aebe73394080cc0b254ee0eebf8bd058 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 24 May 2017 16:49:16 +0200 Subject: [PATCH 0742/1102] Configparser update - add default values for maxdownload/uploadrate, asyncore - rework error handler slightly --- src/bmconfigparser.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 448a9ffc..4e66c703 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -10,8 +10,13 @@ BMConfigDefaults = { "bitmessagesettings": { "maxaddrperstreamsend": 500, "maxbootstrapconnections": 20, + "maxdownloadrate": 0, "maxoutboundconnections": 8, "maxtotalconnections": 200, + "maxuploadrate": 0, + }, + "network": { + "asyncore": False }, "zlib": { 'maxsize': 1048576 @@ -27,35 +32,35 @@ class BMConfigParser(ConfigParser.SafeConfigParser): return ConfigParser.ConfigParser.set(self, section, option, value) def get(self, section, option, raw=False, vars=None): - if section == "bitmessagesettings" and option == "timeformat": - try: - return ConfigParser.ConfigParser.get(self, section, option, raw, vars) - except ConfigParser.InterpolationError: - return ConfigParser.ConfigParser.get(self, section, option, True, vars) try: - return ConfigParser.ConfigParser.get(self, section, option, True, vars) + if section == "bitmessagesettings" and option == "timeformat": + return ConfigParser.ConfigParser.get(self, section, option, raw, vars) + else: + return ConfigParser.ConfigParser.get(self, section, option, True, vars) + except ConfigParser.InterpolationError: + return ConfigParser.ConfigParser.get(self, section, option, True, vars) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: try: return BMConfigDefaults[section][option] - except KeyError: + except (KeyError, ValueError, AttributeError): raise e def safeGetBoolean(self, section, field): try: return self.getboolean(section, field) - except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError): + 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): + 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): + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError, AttributeError): return default def items(self, section, raw=False, vars=None): -- 2.45.1 From d635e515b965141e710a7d93137aa1942b2dc204 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 24 May 2017 16:51:49 +0200 Subject: [PATCH 0743/1102] Big Asyncore update - most of the stuff is done so it partially works - disabled pollers other than select (debugging necessary) - can switch in the settings, section network, option asyncore (defaults to False) --- src/bitmessagemain.py | 30 ++- src/network/advanceddispatcher.py | 29 ++- src/network/asyncore_pollchoose.py | 95 ++++++- src/network/bmobject.py | 94 +++++++ src/{ => network}/bmproto.py | 391 ++++++++++++++++++++++------- src/network/bmqueues.py | 95 +++++++ src/network/connectionchooser.py | 11 + src/network/connectionpool.py | 149 +++++++++++ src/network/downloadqueue.py | 12 + src/network/networkthread.py | 40 +++ src/network/node.py | 67 +---- src/network/tls.py | 29 +-- src/network/uploadqueue.py | 70 ++++++ src/protocol.py | 6 + 14 files changed, 928 insertions(+), 190 deletions(-) create mode 100644 src/network/bmobject.py rename src/{ => network}/bmproto.py (51%) create mode 100644 src/network/bmqueues.py create mode 100644 src/network/connectionchooser.py create mode 100644 src/network/connectionpool.py create mode 100644 src/network/downloadqueue.py create mode 100644 src/network/networkthread.py create mode 100644 src/network/uploadqueue.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c98f7592..e61675cf 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -50,6 +50,9 @@ from class_smtpDeliver import smtpDeliver from class_smtpServer import smtpServer from bmconfigparser import BMConfigParser +from network.connectionpool import BMConnectionPool +from network.networkthread import BMNetworkThread + # Helper Functions import helper_bootstrap import helper_generic @@ -80,10 +83,13 @@ def connectToStream(streamNumber): if streamNumber*2+1 not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber*2+1] = {} - for i in range(maximumNumberOfHalfOpenConnections): - a = outgoingSynSender() - a.setup(streamNumber, selfInitiatedConnections) - a.start() + if BMConfigParser().safeGetBoolean("network", "asyncore"): + BMConnectionPool().connectToStream(streamNumber) + else: + for i in range(maximumNumberOfHalfOpenConnections): + a = outgoingSynSender() + a.setup(streamNumber, selfInitiatedConnections) + a.start() def _fixWinsock(): if not ('win32' in sys.platform) and not ('win64' in sys.platform): @@ -242,13 +248,19 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() + if BMConfigParser().safeGetBoolean("network", "asyncore"): + asyncoreThread = BMNetworkThread() + asyncoreThread.daemon = False + asyncoreThread.start() + connectToStream(1) - singleListenerThread = singleListener() - singleListenerThread.setup(selfInitiatedConnections) - singleListenerThread.daemon = True # close the main program even if there are threads left - singleListenerThread.start() - + if not BMConfigParser().safeGetBoolean("network", "asyncore"): + singleListenerThread = singleListener() + singleListenerThread.setup(selfInitiatedConnections) + singleListenerThread.daemon = True # close the main program even if there are threads left + singleListenerThread.start() + if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'): import upnp upnpThread = upnp.uPnPThread() diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index dc7eedb0..f4ba120e 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,4 +1,7 @@ +import time + import asyncore_pollchoose as asyncore +from bmconfigparser import BMConfigParser class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 2097152 # 2MB @@ -9,6 +12,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.read_buf = b"" self.write_buf = b"" self.state = "init" + self.lastTx = time.time() def append_write_buf(self, string = None): self.write_buf += string @@ -32,7 +36,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return while True: try: - print "Trying to handle state \"%s\"" % (self.state) +# print "Trying to handle state \"%s\"" % (self.state) if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: @@ -50,13 +54,30 @@ class AdvancedDispatcher(asyncore.dispatcher): return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len def handle_read(self): - print "handle_read" - self.read_buf += self.recv(AdvancedDispatcher._buf_len) + self.lastTx = time.time() + if asyncore.maxDownloadRate > 0: + newData = self.recv(asyncore.downloadChunk) + asyncore.downloadBucket -= len(newData) + self.read_buf += newData + else: + self.read_buf += self.recv(AdvancedDispatcher._buf_len) self.process() def handle_write(self): - written = self.send(self.write_buf) + self.lastTx = time.time() + if asyncore.maxUploadRate > 0: + written = self.send(self.write_buf[0:asyncore.uploadChunk]) + asyncore.uploadBucket -= written + else: + written = self.send(self.write_buf) self.slice_write_buf(written) def handle_connect(self): + self.lastTx = time.time() self.process() + + def close(self): + self.read_buf = b"" + self.write_buf = b"" + self.state = "shutdown" + asyncore.dispatcher.close(self) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 4ccce7f9..b26d4cab 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -46,6 +46,8 @@ 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 @@ -56,6 +58,11 @@ import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ errorcode +try: + from errno import WSAEWOULDBLOCK +except: + pass +from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF)) @@ -81,6 +88,15 @@ class ExitNow(Exception): _reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit) +maxDownloadRate = 0 +downloadChunk = 0 +downloadTimestamp = 0 +downloadBucket = 0 +maxUploadRate = 0 +uploadChunk = 0 +uploadTimestamp = 0 +uploadBucket = 0 + def read(obj): try: obj.handle_read_event() @@ -97,6 +113,44 @@ def write(obj): except: obj.handle_error() +def set_rates(download, upload): + global maxDownloadRate, maxUploadRate, downloadChunk, uploadChunk, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp + maxDownloadRate = float(download) + if maxDownloadRate > 0: + downloadChunk = 1400 + maxUploadRate = float(upload) + if maxUploadRate > 0: + uploadChunk = 1400 + downloadBucket = maxDownloadRate + uploadBucket = maxUploadRate + downloadTimestamp = time.time() + uploadTimestamp = time.time() + +def wait_tx_buckets(): + global downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp + if maxDownloadRate > 0 and maxUploadRate > 0: + wait_for_this_long = min(maxDownloadRate / downloadChunk, maxUploadRate / uploadChunk) + elif maxDownloadRate > 0: + wait_for_this_long = maxDownloadRate / downloadChunk + elif maxUploadRate > 0: + wait_for_this_long = maxUploadRate / uploadChunk + else: + return + wait_for_this_long /= 2 + if wait_for_this_long > 1: + wait_for_this_long = 1 + elif wait_for_this_long < 0.1: + wait_for_this_long = 0.1 + + while downloadBucket < downloadChunk and uploadBucket < uploadChunk: + time.sleep(wait_for_this_long) + downloadBucket += (time.time() - downloadTimestamp) * maxDownloadRate + downloadTimestamp = time.time() + uploadBucket += (time.time() - uploadTimestamp) * maxUploadRate + uploadTimestamp = time.time() + + + def _exception(obj): try: obj.handle_expt_event() @@ -150,13 +204,13 @@ def select_poller(timeout=0.0, map=None): except KeyboardInterrupt: return - for fd in r: + for fd in random.sample(r, len(r)): obj = map.get(fd) if obj is None: continue read(obj) - for fd in w: + for fd in random.sample(w, len(w)): obj = map.get(fd) if obj is None: continue @@ -204,7 +258,7 @@ def poll_poller(timeout=0.0, map=None): r = poll_poller.pollster.poll(timeout) except KeyboardInterrupt: r = [] - for fd, flags in r: + for fd, flags in random.sample(r, len(r)): obj = map.get(fd) if obj is None: continue @@ -252,7 +306,7 @@ def epoll_poller(timeout=0.0, map=None): if err.args[0] != EINTR: raise r = [] - for fd, flags in r: + for fd, flags in random.sample(r, len(r)): obj = map.get(fd) if obj is None: continue @@ -278,7 +332,7 @@ def kqueue_poller(timeout=0.0, map=None): selectables += 1 events = kqueue.control(None, selectables, timeout) - for event in events: + for event in random.sample(events, len(events)): fd = event.ident obj = map.get(fd) if obj is None: @@ -307,13 +361,18 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, elif hasattr(select, 'select'): poller = select_poller - print "Poll loop using %s" % (poller.__name__) + poller = select_poller + +# print "Poll loop using %s" % (poller.__name__) if count is None: while map: + wait_tx_buckets() poller(timeout, map) else: + timeout /= count while map and count > 0: + wait_tx_buckets() poller(timeout, map) count = count - 1 @@ -482,10 +541,17 @@ class dispatcher: try: result = self.socket.send(data) return result - except socket.error as why: - if why.args[0] == EWOULDBLOCK: + except SSLError as err: + if err.errno == SSL_ERROR_WANT_WRITE: return 0 - elif why.args[0] in _DISCONNECTED: + else: + raise + except socket.error as why: + if why.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + err.errno == errno.WSAEWOULDBLOCK): + return 0 + elif why.errno in _DISCONNECTED: self.handle_close() return 0 else: @@ -501,9 +567,18 @@ class dispatcher: return b'' else: return data + except SSLError as err: + if err.errno == SSL_ERROR_WANT_READ: + return b'' + else: + raise except socket.error as why: # winsock sometimes raises ENOTCONN - if why.args[0] in _DISCONNECTED: + if why.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + (sys.platform.startswith('win') and \ + err.errno == errno.WSAEWOULDBLOCK): + return b'' + if why.errno in _DISCONNECTED: self.handle_close() return b'' else: diff --git a/src/network/bmobject.py b/src/network/bmobject.py new file mode 100644 index 00000000..2c3fb59c --- /dev/null +++ b/src/network/bmobject.py @@ -0,0 +1,94 @@ +from binascii import hexlify +import time + +from addresses import calculateInventoryHash +from debug import logger +import protocol +import state + +class BMObjectInsufficientPOWError(Exception): pass + + +class BMObjectInvalidDataError(Exception): pass + + +class BMObjectExpiredError(Exception): pass + + +class BMObjectUnwantedStreamError(Exception): pass + + +class BMObjectInvalidError(Exception): pass + + +class BMObjectAlreadyHaveError(Exception): + pass + + +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): + self.nonce = nonce + self.expiresTime = expiresTime + self.objectType = objectType + self.version = version + self.streamNumber = streamNumber + self.inventoryHash = calculateInventoryHash(data) + self.data = data + self.tag = '' + + 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 %s' % 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 %s' % self.expiresTime) + # TODO: remove from download queue + raise BMObjectExpiredError() + + def checkStream(self): + if self.streamNumber not in state.streamsInWhichIAmParticipating: + logger.debug('The streamNumber %s isn\'t one we are interested in.' % self.streamNumber) + raise BMObjectUnwantedStreamError() + + 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, tag): + if len(self.data) < 146 or len(self.data) > 440: # sanity check + logger.info('pubkey object too short or too long. Ignoring.') + raise BMObjectInvalidError() + if self.version >= 4: + self.tag = tag + logger.debug('tag in received pubkey is: %s' % hexlify(tag)) + + def checkBroadcast(self, tag): + 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() + + if self.version >= 3: + self.tag = tag + logger.debug('tag in received broadcast is: %s' % hexlify(tag)) diff --git a/src/bmproto.py b/src/network/bmproto.py similarity index 51% rename from src/bmproto.py rename to src/network/bmproto.py index c9160c3b..d9ed2a95 100644 --- a/src/bmproto.py +++ b/src/network/bmproto.py @@ -1,28 +1,52 @@ +import base64 +from binascii import hexlify import hashlib +import math import time from pprint import pprint import socket -from struct import unpack +import struct +import random +import traceback +from addresses import calculateInventoryHash +from debug import logger +from inventory import Inventory +import knownnodes from network.advanceddispatcher import AdvancedDispatcher +from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError +import network.connectionpool +from network.downloadqueue import DownloadQueue from network.node import Node import network.asyncore_pollchoose as asyncore from network.proxy import Proxy, ProxyError, GeneralProxyError +from network.bmqueues import BMQueues from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError +from network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue from network.tls import TLSDispatcher import addresses from bmconfigparser import BMConfigParser +from queues import objectProcessorQueue import shared +import state import protocol class BMProtoError(ProxyError): pass -class BMConnection(TLSDispatcher): +class BMProtoInsufficientDataError(BMProtoError): pass + + +class BMProtoExcessiveDataError(BMProtoError): pass + + +class BMConnection(TLSDispatcher, BMQueues): # ~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 @@ -32,46 +56,74 @@ class BMConnection(TLSDispatcher): AdvancedDispatcher.__init__(self, sock) self.verackReceived = False self.verackSent = False + self.lastTx = time.time() + self.connectionFullyEstablished = False + self.connectedAt = 0 + self.skipUntil = 0 if address is None and sock is not None: - self.destination = self.addr() + self.destination = state.Peer(sock.getpeername()[0], sock.getpeername()[1]) self.isOutbound = False TLSDispatcher.__init__(self, sock, server_side=True) - print "received connection in background from %s:%i" % (self.destination[0], self.destination[1]) + self.connectedAt = time.time() + print "received connection in background from %s:%i" % (self.destination.host, self.destination.port) else: self.destination = address self.isOutbound = True - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.connect(self.destination) + 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) - print "connecting in background to %s:%i" % (self.destination[0], self.destination[1]) + self.connect(self.destination) + print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) + shared.connectedHostsList[self.destination] = 0 + BMQueues.__init__(self) def bm_proto_reset(self): self.magic = None self.command = None - self.payloadLength = None + self.payloadLength = 0 self.checksum = None self.payload = None self.invalid = False self.payloadOffset = 0 + self.object = None def state_init(self): self.bm_proto_reset() - self.append_write_buf(protocol.assembleVersionMessage(self.destination[0], self.destination[1], (1,), False)) - if True: - print "Sending version (%ib)" % len(self.write_buf) - self.set_state("bm_header") - return False + if self.isOutbound: + self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + print "%s:%i: Sending version (%ib)" % (self.destination.host, self.destination.port, len(self.write_buf)) + self.set_state("bm_header") + return True - def state_bm_ready(self): - print "doing bm ready" + 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 + UploadQueue.queueCount/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 + if delay > 0: + if initial: + self.skipUntil = self.connectedAt + delay + if self.skipUntil > time.time(): + logger.debug("Skipping processing for %.2fs", self.skipUntil - time.time()) + else: + logger.debug("Skipping processing due to missing object for %.2fs", self.skipUntil - time.time()) + self.skipUntil = time.time() + now + + def set_connection_fully_established(self): + self.antiIntersectionDelay(True) + self.connectionFullyEstablished = True self.sendAddr() self.sendBigInv() - self.set_state("bm_header") - return False def state_bm_header(self): + #print "%s:%i: header" % (self.destination.host, self.destination.port) if len(self.read_buf) < protocol.Header.size: - print "Length below header size" + #print "Length below header size" return False self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size]) self.command = self.command.rstrip('\x00') @@ -87,20 +139,41 @@ class BMConnection(TLSDispatcher): def state_bm_command(self): if len(self.read_buf) < self.payloadLength: - print "Length below announced object length" + #print "Length below announced object length" return False - print "received %s (%ib)" % (self.command, self.payloadLength) + print "%s:%i: command %s (%ib)" % (self.destination.host, self.destination.port, self.command, self.payloadLength) self.payload = self.read_buf[:self.payloadLength] if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: print "Bad checksum, ignoring" self.invalid = True retval = True + if not self.connectionFullyEstablished and self.command not in ("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 print "unimplemented command %s" % (self.command) + except BMProtoInsufficientDataError: + print "packet length too short, skipping" + except BMProtoExcessiveDataError: + print "too much data, skipping" + except BMObjectInsufficientPOWError: + print "insufficient PoW, skipping" + except BMObjectInvalidDataError: + print "object invalid data, skipping" + except BMObjectExpiredError: + print "object expired, skipping" + except BMObjectUnwantedStreamError: + print "object not in wanted stream, skipping" + except BMObjectInvalidError: + print "object invalid, skipping" + except BMObjectAlreadyHaveError: + print "already got object, skipping" + except struct.error: + print "decoding error, skipping" else: print "Skipping command %s due to invalid data" % (self.command) if retval: @@ -120,11 +193,24 @@ class BMConnection(TLSDispatcher): return value def decode_payload_node(self): - services, address, port = self.decode_payload_content("Q16sH") - return Node(services, address, port) + 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, host[12:]) + 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, 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, host[12:]) + + return Node(services, host, port) def decode_payload_content(self, pattern = "v"): - # l = varint indicating the length of the next item + # 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 @@ -135,86 +221,171 @@ class BMConnection(TLSDispatcher): # , = end of array retval = [] - size = 0 + size = None insideDigit = False + i = 0 - for i in range(len(pattern)): - if pattern[i] in "0123456789": + while i < len(pattern): + if pattern[i] in "0123456789" and (i == 0 or pattern[i-1] not in "lL"): + if size is None: + size = 0 size = size * 10 + int(pattern[i]) + i += 1 continue - elif pattern[i] == "l": + elif pattern[i] == "l" and size is None: size = self.decode_payload_varint() + i += 1 continue - if size > 0: - innerval = [] + elif pattern[i] == "L" and size is None: + size = self.decode_payload_varint() + i += 1 + continue + if size is not None: if pattern[i] == "s": retval.append(self.payload[self.payloadOffset:self.payloadOffset + size]) self.payloadOffset += size + i += 1 else: + if "," in pattern[i:]: + subpattern = pattern[i:pattern.index(",")] + else: + subpattern = pattern[i:] + for j in range(size): - if "," in pattern[i:]: - retval.append(self.decode_payload_content(pattern[i:pattern.index(",")])) + if pattern[i-1:i] == "L": + retval.extend(self.decode_payload_content(subpattern)) else: - retval.append(self.decode_payload_content(pattern[i:])) - size = 0 + retval.append(self.decode_payload_content(subpattern)) + i += len(subpattern) + size = None else: if pattern[i] == "v": retval.append(self.decode_payload_varint()) if pattern[i] == "i": retval.append(self.decode_payload_node()) if pattern[i] == "H": - retval.append(unpack(">H", self.payload[self.payloadOffset:self.payloadOffset+2])[0]) + retval.append(struct.unpack(">H", self.payload[self.payloadOffset:self.payloadOffset+2])[0]) self.payloadOffset += 2 if pattern[i] == "I": - retval.append(unpack(">I", self.payload[self.payloadOffset:self.payloadOffset+4])[0]) + retval.append(struct.unpack(">I", self.payload[self.payloadOffset:self.payloadOffset+4])[0]) self.payloadOffset += 4 if pattern[i] == "Q": - retval.append(unpack(">Q", self.payload[self.payloadOffset:self.payloadOffset+8])[0]) + retval.append(struct.unpack(">Q", self.payload[self.payloadOffset:self.payloadOffset+8])[0]) self.payloadOffset += 8 + i += 1 + if self.payloadOffset > self.payloadLength: + print "Insufficient data %i/%i" % (self.payloadOffset, self.payloadLength) + raise BMProtoInsufficientDataError() return retval def bm_command_error(self): fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") + print "%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") - #self.antiIntersectionDelay(True) # only handle getdata requests if we have been connected long enough + items = self.decode_payload_content("L32s") +# if time.time() < self.skipUntil: +# print "skipping getdata" +# return True for i in items: - logger.debug('received getdata request for item:' + hexlify(i)) - if self.objectHashHolderInstance.hasHash(i): + print "received getdata request for item %s" % (hexlify(i)) + #logger.debug('received getdata request for item:' + hexlify(i)) + #if i in ObjUploadQueue.streamElems(1): + if False: self.antiIntersectionDelay() else: if i in Inventory(): self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].payload)) else: - #self.antiIntersectionDelay() + 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,)) + return True + + def bm_command_inv(self): + items = self.decode_payload_content("L32s") + + if len(items) >= BMConnection.maxObjectCount: + logger.error("Too many items in inv message!") + raise BMProtoExcessiveDataError() + else: + print "items in inv: %i" % (len(items)) + + startTime = time.time() + #advertisedSet = set() + for i in items: + #advertisedSet.add(i) + self.handleReceivedObj(i) + #objectsNewToMe = advertisedSet + #for stream in self.streams: + #objectsNewToMe -= Inventory().hashes_by_stream(stream) + logger.info('inv message lists %i objects. Of those %i are new to me. It took %f seconds to figure that out.', len(items), len(self.objectsNewToMe), time.time()-startTime) + + payload = addresses.encodeVarint(len(self.objectsNewToMe)) + ''.join(self.objectsNewToMe.keys()) + self.append_write_buf(protocol.CreatePacket('getdata', payload)) + +# for i in random.sample(self.objectsNewToMe, len(self.objectsNewToMe)): +# DownloadQueue().put(i) + return True def bm_command_object(self): - lengthOfTimeWeShouldUseToProcessThisMessage = shared.checkAndShareObjectWithPeers(self.payload) - self.downloadQueue.task_done(calculateInventoryHash(self.payload)) + objectOffset = self.payloadOffset + nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv") + self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload) + + if len(self.payload) - self.payloadOffset > BMConnection.maxObjectPayloadSize: + logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(self.payload) - self.payloadOffset) + raise BMProtoExcessiveDataError() + + self.object.checkProofOfWorkSufficient() + self.object.checkEOLSanity() + self.object.checkStream() + + try: + if self.object.objectType == protocol.OBJECT_GETPUBKEY: + self.object.checkGetpubkey() + elif self.object.objectType == protocol.OBJECT_PUBKEY: + self.object.checkPubkey(self.payload[self.payloadOffset:self.payloadOffset+32]) + elif self.object.objectType == protocol.OBJECT_MSG: + self.object.checkMessage() + elif self.object.objectType == protocol.OBJECT_BROADCAST: + self.object.checkBroadcast(self.payload[self.payloadOffset:self.payloadOffset+32]) + # other objects don't require other types of tests + except BMObjectAlreadyHaveError: + pass + else: + Inventory()[self.object.inventoryHash] = ( + self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) + objectProcessorQueue.put((self.object.objectType,self.object.data)) + #DownloadQueue().task_done(self.object.inventoryHash) + network.connectionpool.BMConnectionPool().handleReceivedObject(self, self.object.streamNumber, self.object.inventoryHash) + #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) + #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + return True def bm_command_addr(self): - addresses = self.decode_payload_content("lQbQ16sH") + addresses = self.decode_payload_content("lQIQ16sH") + return True def bm_command_ping(self): self.append_write_buf(protocol.CreatePacket('pong')) + return True def bm_command_pong(self): # nothing really - pass + return True def bm_command_verack(self): self.verackReceived = True if self.verackSent: if self.isSSL: self.set_state("tls_init", self.payloadLength) + self.bm_proto_reset() + return False else: - self.set_state("bm_ready", self.payloadLength) - else: - self.set_state("bm_header", self.payloadLength) - self.bm_proto_reset() - return False + self.set_connection_fully_established() + return True + return True def bm_command_version(self): #self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) @@ -223,24 +394,30 @@ class BMConnection(TLSDispatcher): print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) print "services: %08X" % (self.services) print "time offset: %i" % (self.timestamp - int(time.time())) - print "my external IP: %s" % (self.sockNode.address) + print "my external IP: %s" % (self.sockNode.host) print "remote node incoming port: %i" % (self.peerNode.port) print "user agent: %s" % (self.userAgent) 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)) + print "%s:%i: Sending version (%ib)" % (self.destination.host, self.destination.port, len(self.write_buf)) 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", self.payloadLength) + self.bm_proto_reset() + return False else: - self.set_state("bm_ready", self.payloadLength) - self.bm_proto_reset() - return False + self.set_connection_fully_established() + return True + return True def peerValidityChecks(self): if self.remoteProtocolVersion < 3: @@ -271,14 +448,24 @@ class BMConnection(TLSDispatcher): logger.debug ('Closed connection to %s because there is no overlapping interest in streams.', str(self.peer)) 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.peer)) + return False + except: + pass return True def sendAddr(self): def sendChunk(): - if numberOfAddressesInAddrMessage == 0: + if addressCount == 0: return self.append_write_buf(protocol.CreatePacket('addr', \ - addresses.encodeVarint(numberOfAddressesInAddrMessage) + payload)) + addresses.encodeVarint(addressCount) + payload)) # We are going to share a maximum number of 1000 addrs (per overlapping # stream) with our peer. 500 from overlapping streams, 250 from the @@ -287,7 +474,7 @@ class BMConnection(TLSDispatcher): # init addressCount = 0 - payload = '' + payload = b'' for stream in self.streams: addrsInMyStream = {} @@ -320,42 +507,42 @@ class BMConnection(TLSDispatcher): addrsInChildStreamRight = random.sample(filtered.items(), elemCount) for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInMyStream: addressCount += 1 - payload += pack( + payload += struct.pack( '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', stream) - payload += pack( + payload += struct.pack('>I', stream) + payload += struct.pack( '>q', 1) # service bit flags offered by this node payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port + payload += struct.pack('>H', PORT) # remote port if addressCount >= BMConnection.maxAddrCount: sendChunk() - payload = '' + payload = b'' addressCount = 0 for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft: addressCount += 1 - payload += pack( + payload += struct.pack( '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', stream * 2) - payload += pack( + payload += struct.pack('>I', stream * 2) + payload += struct.pack( '>q', 1) # service bit flags offered by this node payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port + payload += struct.pack('>H', PORT) # remote port if addressCount >= BMConnection.maxAddrCount: sendChunk() - payload = '' + payload = b'' addressCount = 0 for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight: addressCount += 1 - payload += pack( + payload += struct.pack( '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += pack('>I', (stream * 2) + 1) - payload += pack( + payload += struct.pack('>I', (stream * 2) + 1) + payload += struct.pack( '>q', 1) # service bit flags offered by this node payload += protocol.encodeHost(HOST) - payload += pack('>H', PORT) # remote port + payload += struct.pack('>H', PORT) # remote port if addressCount >= BMConnection.maxAddrCount: sendChunk() - payload = '' + payload = b'' addressCount = 0 # flush @@ -365,19 +552,21 @@ class BMConnection(TLSDispatcher): def sendChunk(): if objectCount == 0: return - payload = encodeVarint(objectCount) + payload - logger.debug('Sending huge inv message with %i objects to just this one peer', - str(numberOfObjects)) - self.append_write_buf(protocol.CreatePacket('inv', payload)) + 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: for hash in Inventory().unexpired_hashes_by_stream(stream): - if not self.objectHashHolderInstance.hasHash(hash): - bigInvList[hash] = 0 + bigInvList[hash] = 0 +# for hash in ObjUploadQueue().streamHashes(stream): +# try: +# del bigInvList[hash] +# except KeyError: +# pass objectCount = 0 - payload = '' + 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(): @@ -385,12 +574,43 @@ class BMConnection(TLSDispatcher): objectCount += 1 if objectCount >= BMConnection.maxObjectCount: self.sendChunk() - payload = '' + payload = b'' objectCount = 0 # flush sendChunk() + def handle_connect_event(self): + try: + asyncore.dispatcher.handle_connect_event(self) + self.connectedAt = time.time() + except socket.error as e: + print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def handle_read_event(self): + try: + asyncore.dispatcher.handle_read_event(self) + except socket.error as e: + print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def handle_write_event(self): + try: + asyncore.dispatcher.handle_write_event(self) + except socket.error as e: + print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def close(self, reason=None): + if reason is None: + print "%s:%i: closing" % (self.destination.host, self.destination.port) + #traceback.print_stack() + else: + print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) + network.connectionpool.BMConnectionPool().removeConnection(self) + asyncore.dispatcher.close(self) + class Socks5BMConnection(Socks5Connection, BMConnection): def __init__(self, address): @@ -411,24 +631,19 @@ class Socks4aBMConnection(Socks4aConnection, BMConnection): class BMServer(AdvancedDispatcher): - port = 8444 - - def __init__(self, port=None): + 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() - if port is None: - port = BMServer.port - self.bind(('127.0.0.1', port)) - self.connections = 0 + self.bind((host, port)) self.listen(5) def handle_accept(self): pair = self.accept() if pair is not None: sock, addr = pair - BMConnection(sock=sock) + network.connectionpool.BMConnectionPool().addConnection(BMConnection(sock=sock)) if __name__ == "__main__": diff --git a/src/network/bmqueues.py b/src/network/bmqueues.py new file mode 100644 index 00000000..96ad52e4 --- /dev/null +++ b/src/network/bmqueues.py @@ -0,0 +1,95 @@ +import time + +from inventory import Inventory +from network.downloadqueue import DownloadQueue +from network.uploadqueue import UploadQueue + +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 BMQueues(object): + invCleanPeriod = 300 + invInitialCapacity = 50000 + invErrorRate = 0.03 + + def __init__(self): + self.objectsNewToMe = {} + self.objectsNewToThem = {} + self.initInvBloom() + self.initAddrBloom() + + def initInvBloom(self): + if haveBloom: + # lock? + self.invBloom = BloomFilter(capacity=BMQueues.invInitialCapacity, + error_rate=BMQueues.invErrorRate) + + def initAddrBloom(self): + if haveBloom: + # lock? + self.addrBloom = BloomFilter(capacity=BMQueues.invInitialCapacity, + error_rate=BMQueues.invErrorRate) + + def clean(self): + if self.lastcleaned < time.time() - BMQueues.invCleanPeriod: + if haveBloom: + if PendingDownloadQueue().size() == 0: + self.initInvBloom() + self.initAddrBloom() + else: + # release memory + self.objectsNewToMe = self.objectsNewToMe.copy() + self.objectsNewToThem = self.objectsNewToThem.copy() + + def hasObj(self, hashid): + if haveBloom: + return hashid in self.invBloom + else: + return hashid in self.objectsNewToMe + + def handleReceivedObj(self, hashid): + if haveBloom: + self.invBloom.add(hashid) + elif hashid in Inventory(): + try: + del self.objectsNewToThem[hashid] + except KeyError: + pass + else: + self.objectsNewToMe[hashid] = True + + 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 + +# 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/connectionchooser.py b/src/network/connectionchooser.py new file mode 100644 index 00000000..a1b1d10b --- /dev/null +++ b/src/network/connectionchooser.py @@ -0,0 +1,11 @@ +import random + +from bmconfigparser import BMConfigParser +import knownnodes +import state + +def chooseConnection(stream): + if state.trustedPeer: + return state.trustedPeer + else: + return random.choice(knownnodes.knownNodes[stream].keys()) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py new file mode 100644 index 00000000..e79f033c --- /dev/null +++ b/src/network/connectionpool.py @@ -0,0 +1,149 @@ +import errno +import socket +import time +import random + +from bmconfigparser import BMConfigParser +from debug import logger +import helper_bootstrap +import network.bmproto +from network.connectionchooser import chooseConnection +import network.asyncore_pollchoose as asyncore +import protocol +from singleton import Singleton +import shared +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.streams = [] + + self.bootstrapped = False + + def handleReceivedObject(self, connection, streamNumber, hashid): + for i in self.inboundConnections.values() + self.outboundConnections.values(): + if not isinstance(i, network.bmproto.BMConnection): + continue + if i == connection: + try: + del i.objectsNewToThem[hashid] + except KeyError: + pass + else: + try: + del i.objectsNewToThem[hashid] + except KeyError: + i.objectsNewToThem[hashid] = True + try: + del i.objectsNewToMe[hashid] + except KeyError: + pass + + def connectToStream(self, streamNumber): + self.streams.append(streamNumber) + + def addConnection(self, connection): + 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 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 + + def startListening(self): + port = BMConfigParser().safeGetInt("bitmessagesettings", "port") + if BMConfigParser().safeGet("bitmessagesettings", "onionhostname").endswith(".onion"): + host = BMConfigParser().safeGet("bitmessagesettigns", "onionbindip") + else: + host = '127.0.0.1' + if BMConfigParser().safeGetBoolean("bitmessagesettings", "sockslisten") or \ + BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none": + host = '' + self.listeningSockets[state.Peer(host, port)] = network.bmproto.BMServer(host=host, port=port) + + def loop(self): + # defaults to empty loop if outbound connections are maxed + spawnConnections = False + acceptConnections = True + if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): + acceptConnections = False + else: + spawnConnections = True + if 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 + + spawnConnections = False + if spawnConnections: + if not self.bootstrapped: + print "bootstrapping dns" + helper_bootstrap.dns() + self.bootstrapped = True + for i in range(len(self.outboundConnections), BMConfigParser().safeGetInt("bitmessagesettings", "maxoutboundconnections")): + chosen = chooseConnection(random.choice(self.streams)) + if chosen in self.outboundConnections: + continue + if chosen.host in self.inboundConnections: + 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 (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): + self.addConnection(network.bmproto.Socks5BMConnection(chosen)) + elif (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a"): + self.addConnection(network.bmproto.Socks4aBMConnection(chosen)) + elif not chosen.host.endswith(".onion"): + self.addConnection(network.bmproto.BMConnection(chosen)) + except socket.error as e: + if e.errno == errno.ENETUNREACH: + continue + + if acceptConnections and len(self.listeningSockets) == 0: + self.startListening() + logger.info('Listening for incoming connections.') + if len(self.listeningSockets) > 0 and not acceptConnections: + for i in self.listeningSockets: + i.close() + logger.info('Stopped listening for incoming connections.') + +# while len(asyncore.socket_map) > 0 and state.shutdown == 0: +# print "loop, state = %s" % (proxy.state) + asyncore.loop(timeout=2.0, count=1) + + for i in self.inboundConnections.values() + self.outboundConnections.values(): + minTx = time.time() - 20 + if i.connectionFullyEstablished: + minTx -= 300 - 20 + if i.lastTx < minTx: + i.close("Timeout (%is)" % (time.time() - i.lastTx)) diff --git a/src/network/downloadqueue.py b/src/network/downloadqueue.py new file mode 100644 index 00000000..3789fb19 --- /dev/null +++ b/src/network/downloadqueue.py @@ -0,0 +1,12 @@ +#import collections +from threading import current_thread, enumerate as threadingEnumerate, RLock +import Queue +import time + +#from helper_sql import * +from singleton import Singleton + +@Singleton +class DownloadQueue(Queue.Queue): + # keep a track of objects that have been advertised to us but we haven't downloaded them yet + maxWait = 300 diff --git a/src/network/networkthread.py b/src/network/networkthread.py new file mode 100644 index 00000000..3a9d8e37 --- /dev/null +++ b/src/network/networkthread.py @@ -0,0 +1,40 @@ +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 + +class BMNetworkThread(threading.Thread, StoppableThread): + def __init__(self): + threading.Thread.__init__(self, name="BMNetworkThread") + self.initStop() + self.name = "AsyncoreThread" + BMConnectionPool() + logger.error("init asyncore thread") + + def run(self): + while not self._stopped: + BMConnectionPool().loop() + + def stopThread(self): + super(BMNetworkThread, self).stopThread() + for i in BMConnectionPool().listeningSockets: + try: + i.close() + except: + pass + for i in BMConnectionPool().outboundConnections: + try: + i.close() + except: + pass + for i in BMConnectionPool().inboundConnections: + try: + i.close() + except: + pass + + # just in case + asyncore.close_all() diff --git a/src/network/node.py b/src/network/node.py index 054d07d8..ab9f5fbe 100644 --- a/src/network/node.py +++ b/src/network/node.py @@ -1,66 +1,3 @@ -import time - -from inventory import PendingDownloadQueue - -try: - # pybloomfiltermmap - from pybloomfilter import BloomFilter -except ImportError: - try: - # pybloom - from pybloom import BloomFilter - except ImportError: - # bundled pybloom - from fallback.pybloom import BloomFilter - - -class Node(object): - invCleanPeriod = 300 - invInitialCapacity = 50000 - invErrorRate = 0.03 - - def __init__(self): - self.initInvBloom() - self.initAddrBloom() - - def initInvBloom(self): - # lock? - self.invBloom = BloomFilter(capacity=Node.invInitialCapacity, - error_rate=Node.invErrorRate) - - def initAddrBloom(self): - # lock? - self.addrBloom = BloomFilter(capacity=Node.invInitialCapacity, - error_rate=Node.invErrorRate) - - def cleanBloom(self): - if self.lastcleaned < time.time() - Node.invCleanPeriod: - if PendingDownloadQueue().size() == 0: - self.initInvBloom() - self.initAddrBloom() - - def hasInv(self, hashid): - return hashid in self.invBloom - - def addInv(self, hashid): - self.invBloom.add(hashid) - - def hasAddr(self, hashid): - return hashid in self.invBloom - - def addInv(self, hashid): - self.invBloom.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 - -# 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 -# +import collections +Node = collections.namedtuple('Node', ['services', 'host', 'port']) diff --git a/src/network/tls.py b/src/network/tls.py index c7554891..669d9aa3 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -60,14 +60,14 @@ class TLSDispatcher(AdvancedDispatcher): def writable(self): if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - print "tls writable, %r" % (self.want_write) + #print "tls writable, %r" % (self.want_write) return self.want_write else: return AdvancedDispatcher.writable(self) def readable(self): if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - print "tls readable, %r" % (self.want_read) + #print "tls readable, %r" % (self.want_read) return self.want_read else: return AdvancedDispatcher.readable(self) @@ -75,19 +75,19 @@ class TLSDispatcher(AdvancedDispatcher): def handle_read(self): # wait for write buffer flush if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - print "handshaking (read)" + #print "handshaking (read)" self.state_tls_handshake() else: - print "not handshaking (read)" + #print "not handshaking (read)" return AdvancedDispatcher.handle_read(self) def handle_write(self): # wait for write buffer flush if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - print "handshaking (write)" + #print "handshaking (write)" self.state_tls_handshake() else: - print "not handshaking (write)" + #print "not handshaking (write)" return AdvancedDispatcher.handle_write(self) def state_tls_handshake(self): @@ -96,24 +96,25 @@ class TLSDispatcher(AdvancedDispatcher): return False # Perform the handshake. try: - print "handshaking (internal)" + #print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError, err: - print "handshake fail" + #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" + #print "want read" self.want_read = True - elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - print "want write" + if err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + #print "want write" self.want_write = True - else: + if not (self.want_write or self.want_read): raise else: - print "handshake success" + print "%s:%i: 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.state_bm_ready() + self.set_state("bm_header") + self.set_connection_fully_established() return False diff --git a/src/network/uploadqueue.py b/src/network/uploadqueue.py new file mode 100644 index 00000000..5d699e96 --- /dev/null +++ b/src/network/uploadqueue.py @@ -0,0 +1,70 @@ +from collections import namedtuple +import Queue +import random +from threading import current_thread, enumerate as threadingEnumerate, RLock +import time + +#from helper_sql import * +from singleton import Singleton + +UploadElem = namedtuple("UploadElem", "stream identifier") + +class UploadQueueDeadlineException(Exception): + pass + + +class UploadQueue(object): + queueCount = 10 + + def __init__(self): + self.queue = [] + self.lastGet = 0 + self.getIterator = 0 + for i in range(UploadQueue.queueCount): + self.queue.append([]) + + def put(self, item): + self.queue[random.randrange(0, UploadQueue.queueCount)].append(item) + + def get(self): + i = UploadQueue.queueCount + retval = [] + while self.lastGet < time.time() - 1 and i > 0: + if len(self.queue) > 0: + retval.extend(self.queue[self.getIterator]) + self.queue[self.getIterator] = [] + self.lastGet += 1 + # only process each queue once + i -= 1 + self.getIterator = (self.getIterator + 1) % UploadQueue.queueCount + if self.lastGet < time.time() - 1: + self.lastGet = time.time() + return retval + + def streamElems(self, stream): + retval = {} + for q in self.queue: + for elem in q: + if elem.stream == stream: + retval[elem.identifier] = True + return retval + + def len(self): + retval = 0 + for i in range(UploadQueue.queueCount): + retval += len(self.queue[i]) + return retval + + def stop(self): + for i in range(UploadQueue.queueCount): + self.queue[i] = [] + + +@Singleton +class AddrUploadQueue(UploadQueue): + pass + + +@Singleton +class ObjUploadQueue(UploadQueue): + pass diff --git a/src/protocol.py b/src/protocol.py index 9397cd8b..b7847e8f 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -32,6 +32,12 @@ STATUS_WARNING = 0 STATUS_ERROR = 1 STATUS_FATAL = 2 +#Object types +OBJECT_GETPUBKEY = 0 +OBJECT_PUBKEY = 1 +OBJECT_MSG = 2 +OBJECT_BROADCAST = 3 + eightBytesOfRandomDataUsedToDetectConnectionsToSelf = pack( '>Q', random.randrange(1, 18446744073709551615)) -- 2.45.1 From bafdd6a93ac3e581c2be0065d3b36348fedf2fe3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 24 May 2017 16:54:33 +0200 Subject: [PATCH 0744/1102] Allow making outbound connections in asyncore --- src/network/connectionpool.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index e79f033c..7036e7cf 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -99,7 +99,6 @@ class BMConnectionPool(object): ".onion" not in BMConfigParser().get('bitmessagesettings', 'onionhostname')): acceptConnections = False - spawnConnections = False if spawnConnections: if not self.bootstrapped: print "bootstrapping dns" -- 2.45.1 From fa56ab3e6fb73c45707c70a9ed0f09e44d928f7a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 24 May 2017 21:15:36 +0200 Subject: [PATCH 0745/1102] Asyncore update - better error handling - bug fixes - remove some debug output --- src/network/asyncore_pollchoose.py | 17 +++++++++-------- src/network/bmproto.py | 10 +++++++--- src/network/tls.py | 2 +- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index b26d4cab..72a829ce 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,6 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ + ECONNREFUSED, \ errorcode try: from errno import WSAEWOULDBLOCK @@ -65,7 +66,7 @@ except: from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF)) + EBADF, ECONNREFUSED)) OP_READ = 1 OP_WRITE = 2 @@ -530,7 +531,7 @@ class dispatcher: except TypeError: return None except socket.error as why: - if why.args[0] in (EWOULDBLOCK, ECONNABORTED, EAGAIN): + if why.args[0] in (EWOULDBLOCK, ECONNABORTED, EAGAIN, ENOTCONN): return None else: raise @@ -547,11 +548,11 @@ class dispatcher: else: raise except socket.error as why: - if why.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + if why.args[0] in (EAGAIN, EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ - err.errno == errno.WSAEWOULDBLOCK): + err.errno == WSAEWOULDBLOCK): return 0 - elif why.errno in _DISCONNECTED: + elif why.args[0] in _DISCONNECTED: self.handle_close() return 0 else: @@ -574,11 +575,11 @@ class dispatcher: raise except socket.error as why: # winsock sometimes raises ENOTCONN - if why.errno in (errno.EAGAIN, errno.EWOULDBLOCK) or \ + if why.args[0] in (EAGAIN, EWOULDBLOCK) or \ (sys.platform.startswith('win') and \ - err.errno == errno.WSAEWOULDBLOCK): + err.errno == WSAEWOULDBLOCK): return b'' - if why.errno in _DISCONNECTED: + if why.args[0] in _DISCONNECTED: self.handle_close() return b'' else: diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d9ed2a95..9a697b13 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -289,7 +289,7 @@ class BMConnection(TLSDispatcher, BMQueues): # print "skipping getdata" # return True for i in items: - print "received getdata request for item %s" % (hexlify(i)) + #print "received getdata request for item %s" % (hexlify(i)) #logger.debug('received getdata request for item:' + hexlify(i)) #if i in ObjUploadQueue.streamElems(1): if False: @@ -309,7 +309,8 @@ class BMConnection(TLSDispatcher, BMQueues): logger.error("Too many items in inv message!") raise BMProtoExcessiveDataError() else: - print "items in inv: %i" % (len(items)) + pass + #print "items in inv: %i" % (len(items)) startTime = time.time() #advertisedSet = set() @@ -609,7 +610,10 @@ class BMConnection(TLSDispatcher, BMQueues): else: print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) network.connectionpool.BMConnectionPool().removeConnection(self) - asyncore.dispatcher.close(self) + try: + asyncore.dispatcher.close(self) + except AttributeError: + pass class Socks5BMConnection(Socks5Connection, BMConnection): diff --git a/src/network/tls.py b/src/network/tls.py index 669d9aa3..e691006d 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -110,7 +110,7 @@ class TLSDispatcher(AdvancedDispatcher): if not (self.want_write or self.want_read): raise else: - print "%s:%i: handshake success" % (self.destination.host, self.destination.port) + print "%s:%i: TLS handshake success%s" % (self.destination.host, self.destination.port, ", TLS protocol version: %s" % (self.sslSocket.version()) if sys.version_info >= (2, 7, 9) else "") # The handshake has completed, so remove this channel and... self.del_channel() self.set_socket(self.sslSocket) -- 2.45.1 From edcba9982bfd291e9a0c4b69c9026ed29b6dd722 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 24 May 2017 21:35:50 +0200 Subject: [PATCH 0746/1102] Asyncore getdata processing performance improvement - no need to query DB for existence of each entry --- src/network/bmproto.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 9a697b13..bf7019d3 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -295,9 +295,10 @@ class BMConnection(TLSDispatcher, BMQueues): if False: self.antiIntersectionDelay() else: - if i in Inventory(): + try: self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].payload)) - else: + # this is faster than "if i in Inventory()" + except KeyError: 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,)) return True -- 2.45.1 From 9683c879bc778135a3bdb233c1258771f652ab7d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 25 May 2017 14:59:18 +0200 Subject: [PATCH 0747/1102] Asyncore update - Network status UI works but current speed isn't implemented yet - Track per connection and global transferred bytes - Add locking to write queue so that other threads can put stuff there - send ping on timeout (instead of closing the connection) - implement open port checker (untested, never triggered yet) - error handling on IO --- src/bitmessageqt/networkstatus.py | 15 +++++---- src/network/advanceddispatcher.py | 18 +++++++--- src/network/asyncore_pollchoose.py | 12 +++++-- src/network/bmproto.py | 17 ++++++---- src/network/connectionchooser.py | 7 +++- src/network/connectionpool.py | 5 ++- src/network/stats.py | 43 ++++++++++++++++++++++++ src/network/tls.py | 54 ++++++++++++++++++------------ src/queues.py | 1 + 9 files changed, 130 insertions(+), 42 deletions(-) create mode 100644 src/network/stats.py diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index b5870a6b..158f02fa 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -5,10 +5,10 @@ import shared from tr import _translate from inventory import Inventory, PendingDownloadQueue, PendingUpload import l10n +import network.stats from retranslateui import RetranslateMixin from uisignaler import UISignaler import widgets -import throttle class NetworkStatus(QtGui.QWidget, RetranslateMixin): @@ -69,14 +69,15 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): sent and received by 2. """ self.labelBytesRecvCount.setText(_translate( - "networkstatus", "Down: %1/s Total: %2").arg(self.formatByteRate(throttle.ReceiveThrottle().getSpeed()), self.formatBytes(throttle.ReceiveThrottle().total))) + "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(throttle.SendThrottle().getSpeed()), self.formatBytes(throttle.SendThrottle().total))) + "networkstatus", "Up: %1/s Total: %2").arg(self.formatByteRate(network.stats.uploadSpeed()), self.formatBytes(network.stats.sentBytes()))) def updateNetworkStatusTab(self): 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(): + connectedHosts = network.stats.connectedHostsList() + for host, streamNumber in connectedHosts: if not streamNumber in streamNumberTotals: streamNumberTotals[streamNumber] = 1 else: @@ -114,10 +115,10 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): self.tableWidgetConnectionCount.setItem(0,1,newItem) totalNumberOfConnectionsFromAllStreams += connectionCount""" self.labelTotalConnections.setText(_translate( - "networkstatus", "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. + "networkstatus", "Total Connections: %1").arg(str(len(connectedHosts)))) + if len(connectedHosts) > 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.window().setStatusIcon('yellow') - elif len(shared.connectedHostsList) == 0: + elif len(connectedHosts) == 0: self.window().setStatusIcon('red') # timer driven diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index f4ba120e..d1b5f567 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,3 +1,4 @@ +from threading import RLock import time import asyncore_pollchoose as asyncore @@ -11,15 +12,20 @@ class AdvancedDispatcher(asyncore.dispatcher): asyncore.dispatcher.__init__(self, sock) self.read_buf = b"" self.write_buf = b"" + self.writeLock = RLock() self.state = "init" self.lastTx = time.time() + self.sentBytes = 0 + self.receivedBytes = 0 def append_write_buf(self, string = None): - self.write_buf += string + with self.writeLock: + self.write_buf += string def slice_write_buf(self, length=0): if length > 0: - self.write_buf = self.write_buf[length:] + with self.writeLock: + self.write_buf = self.write_buf[length:] def slice_read_buf(self, length=0): if length > 0: @@ -58,9 +64,11 @@ class AdvancedDispatcher(asyncore.dispatcher): if asyncore.maxDownloadRate > 0: newData = self.recv(asyncore.downloadChunk) asyncore.downloadBucket -= len(newData) - self.read_buf += newData else: - self.read_buf += self.recv(AdvancedDispatcher._buf_len) + newData = self.recv(AdvancedDispatcher._buf_len) + self.receivedBytes += len(newData) + asyncore.updateReceived(len(newData)) + self.read_buf += newData self.process() def handle_write(self): @@ -70,6 +78,8 @@ class AdvancedDispatcher(asyncore.dispatcher): asyncore.uploadBucket -= written else: written = self.send(self.write_buf) + asyncore.updateSent(written) + self.sentBytes += written self.slice_write_buf(written) def handle_connect(self): diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 72a829ce..08ee42d0 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -93,10 +93,12 @@ maxDownloadRate = 0 downloadChunk = 0 downloadTimestamp = 0 downloadBucket = 0 +receivedBytes = 0 maxUploadRate = 0 uploadChunk = 0 uploadTimestamp = 0 uploadBucket = 0 +sentBytes = 0 def read(obj): try: @@ -127,6 +129,14 @@ def set_rates(download, upload): downloadTimestamp = time.time() uploadTimestamp = time.time() +def updateReceived(download=0): + global receivedBytes + receivedBytes += download + +def updateSent(upload=0): + global sentBytes + sentBytes += upload + def wait_tx_buckets(): global downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp if maxDownloadRate > 0 and maxUploadRate > 0: @@ -150,8 +160,6 @@ def wait_tx_buckets(): uploadBucket += (time.time() - uploadTimestamp) * maxUploadRate uploadTimestamp = time.time() - - def _exception(obj): try: obj.handle_expt_event() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index bf7019d3..3a5ea1b4 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -28,7 +28,7 @@ from network.tls import TLSDispatcher import addresses from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue +from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue import shared import state import protocol @@ -57,6 +57,7 @@ class BMConnection(TLSDispatcher, BMQueues): self.verackReceived = False self.verackSent = False self.lastTx = time.time() + self.streams = [0] self.connectionFullyEstablished = False self.connectedAt = 0 self.skipUntil = 0 @@ -79,6 +80,7 @@ class BMConnection(TLSDispatcher, BMQueues): print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) shared.connectedHostsList[self.destination] = 0 BMQueues.__init__(self) + UISignalQueue.put(('updateNetworkStatusTab', 'no data')) def bm_proto_reset(self): self.magic = None @@ -115,6 +117,7 @@ class BMConnection(TLSDispatcher, BMQueues): self.skipUntil = time.time() + now def set_connection_fully_established(self): + UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.antiIntersectionDelay(True) self.connectionFullyEstablished = True self.sendAddr() @@ -369,6 +372,10 @@ class BMConnection(TLSDispatcher, BMQueues): addresses = self.decode_payload_content("lQIQ16sH") 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 @@ -399,10 +406,11 @@ class BMConnection(TLSDispatcher, BMQueues): print "my external IP: %s" % (self.sockNode.host) print "remote node incoming port: %i" % (self.peerNode.port) print "user agent: %s" % (self.userAgent) + print "streams: [%s]" % (",".join(map(str,self.streams))) if not self.peerValidityChecks(): # TODO ABORT return True - shared.connectedHostsList[self.destination] = self.streams[0] + #shared.connectedHostsList[self.destination] = self.streams[0] self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: @@ -611,10 +619,7 @@ class BMConnection(TLSDispatcher, BMQueues): else: print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) network.connectionpool.BMConnectionPool().removeConnection(self) - try: - asyncore.dispatcher.close(self) - except AttributeError: - pass + asyncore.dispatcher.close(self) class Socks5BMConnection(Socks5Connection, BMConnection): diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index a1b1d10b..1c8d988d 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -1,11 +1,16 @@ +from queues import Queue import random from bmconfigparser import BMConfigParser import knownnodes +from queues import portCheckerQueue import state def chooseConnection(stream): if state.trustedPeer: return state.trustedPeer else: - return random.choice(knownnodes.knownNodes[stream].keys()) + try: + return portCheckerQueue.get(False) + except Queue.Empty: + return random.choice(knownnodes.knownNodes[stream].keys()) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 7036e7cf..6acf4bb6 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -145,4 +145,7 @@ class BMConnectionPool(object): if i.connectionFullyEstablished: minTx -= 300 - 20 if i.lastTx < minTx: - i.close("Timeout (%is)" % (time.time() - i.lastTx)) + if i.connectionFullyEstablished: + i.append_write_buf(protocol.CreatePacket('ping')) + else: + i.close("Timeout (%is)" % (time.time() - i.lastTx)) diff --git a/src/network/stats.py b/src/network/stats.py new file mode 100644 index 00000000..838ef23a --- /dev/null +++ b/src/network/stats.py @@ -0,0 +1,43 @@ +from bmconfigparser import BMConfigParser +from network.connectionpool import BMConnectionPool +import asyncore_pollchoose as asyncore +import shared +import throttle + +def connectedHostsList(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + retval = [] + for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + if not i.connected: + continue + try: + retval.append((i.destination, i.streams[0])) + except AttributeError: + pass + return retval + else: + return shared.connectedHostsList.items() + +def sentBytes(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + return asyncore.sentBytes + else: + return throttle.SendThrottle().total + +def uploadSpeed(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + return 0 + else: + return throttle.sendThrottle().getSpeed() + +def receivedBytes(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + return asyncore.receivedBytes + else: + return throttle.ReceiveThrottle().total + +def downloadSpeed(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + return 0 + else: + return throttle.ReceiveThrottle().getSpeed() diff --git a/src/network/tls.py b/src/network/tls.py index e691006d..d2abb6b9 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -59,36 +59,48 @@ class TLSDispatcher(AdvancedDispatcher): # self.socket.context.set_ecdh_curve("secp256k1") def writable(self): - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - #print "tls writable, %r" % (self.want_write) - return self.want_write - else: + try: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + #print "tls writable, %r" % (self.want_write) + return self.want_write + else: + return AdvancedDispatcher.writable(self) + except AttributeError: return AdvancedDispatcher.writable(self) def readable(self): - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - #print "tls readable, %r" % (self.want_read) - return self.want_read - else: + try: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + #print "tls readable, %r" % (self.want_read) + return self.want_read + else: + return AdvancedDispatcher.readable(self) + except AttributeError: return AdvancedDispatcher.readable(self) def handle_read(self): - # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - #print "handshaking (read)" - self.state_tls_handshake() - else: - #print "not handshaking (read)" + try: + # wait for write buffer flush + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + #print "handshaking (read)" + self.state_tls_handshake() + else: + #print "not handshaking (read)" + return AdvancedDispatcher.handle_read(self) + except AttributeError: return AdvancedDispatcher.handle_read(self) def handle_write(self): - # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: - #print "handshaking (write)" - self.state_tls_handshake() - else: - #print "not handshaking (write)" - return AdvancedDispatcher.handle_write(self) + try: + # wait for write buffer flush + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + #print "handshaking (write)" + self.state_tls_handshake() + else: + #print "not handshaking (write)" + return AdvancedDispatcher.handle_write(self) + except AttributeError: + return AdvancedDispatcher.handle_read(self) def state_tls_handshake(self): # wait for flush diff --git a/src/queues.py b/src/queues.py index 335863e9..c6b09307 100644 --- a/src/queues.py +++ b/src/queues.py @@ -6,5 +6,6 @@ UISignalQueue = Queue.Queue() addressGeneratorQueue = Queue.Queue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. objectProcessorQueue = ObjectProcessorQueue() +portCheckerQueue = Queue.Queue() apiAddressGeneratorReturnQueue = Queue.Queue( ) # The address generator thread uses this queue to get information back to the API thread. -- 2.45.1 From 51e52401fececa2c760bcd23b12141f4b3e3af13 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 25 May 2017 15:00:10 +0200 Subject: [PATCH 0748/1102] Windows plaform check pythonic - moved to .startswith instead of 'in' - thanks @Lvl4sword --- src/bitmessagemain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index e61675cf..2c0be937 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -92,7 +92,7 @@ def connectToStream(streamNumber): a.start() def _fixWinsock(): - if not ('win32' in sys.platform) and not ('win64' in sys.platform): + if not sys.platform.startswith('win'): return # Python 2 on Windows doesn't define a wrapper for -- 2.45.1 From e309a1edb3e01a3e9e9ca30a5f263e8362b63c26 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 25 May 2017 23:04:33 +0200 Subject: [PATCH 0749/1102] Asyncore update - separate queue for processing blocking stuff on reception - rewrote write buffer as a queue - some addr handling - number of half open connections correct --- src/bitmessagemain.py | 12 ++++-- src/network/advanceddispatcher.py | 36 +++++++++------- src/network/bmproto.py | 68 +++++++++++++++++++------------ src/network/connectionpool.py | 53 ++++++++++++------------ src/network/networkthread.py | 2 +- src/network/receivequeuethread.py | 44 ++++++++++++++++++++ src/network/socks4a.py | 24 +++++------ src/network/socks5.py | 22 +++++----- src/protocol.py | 45 +++++++++++++++++++- src/state.py | 2 + 10 files changed, 213 insertions(+), 95 deletions(-) create mode 100644 src/network/receivequeuethread.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 2c0be937..c05d002a 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -52,6 +52,7 @@ from bmconfigparser import BMConfigParser from network.connectionpool import BMConnectionPool from network.networkthread import BMNetworkThread +from network.receivequeuethread import ReceiveQueueThread # Helper Functions import helper_bootstrap @@ -65,13 +66,13 @@ def connectToStream(streamNumber): if isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): # Some XP and Vista systems can only have 10 outgoing connections at a time. - maximumNumberOfHalfOpenConnections = 9 + state.maximumNumberOfHalfOpenConnections = 9 else: - maximumNumberOfHalfOpenConnections = 64 + state.maximumNumberOfHalfOpenConnections = 64 try: # don't overload Tor if BMConfigParser().get('bitmessagesettings', 'socksproxytype') != 'none': - maximumNumberOfHalfOpenConnections = 4 + state.maximumNumberOfHalfOpenConnections = 4 except: pass @@ -86,7 +87,7 @@ def connectToStream(streamNumber): if BMConfigParser().safeGetBoolean("network", "asyncore"): BMConnectionPool().connectToStream(streamNumber) else: - for i in range(maximumNumberOfHalfOpenConnections): + for i in range(state.maximumNumberOfHalfOpenConnections): a = outgoingSynSender() a.setup(streamNumber, selfInitiatedConnections) a.start() @@ -252,6 +253,9 @@ class Main: asyncoreThread = BMNetworkThread() asyncoreThread.daemon = False asyncoreThread.start() + receiveQueueThread = ReceiveQueueThread() + receiveQueueThread.daemon = False + receiveQueueThread.start() connectToStream(1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index d1b5f567..fb28f3d4 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,4 +1,4 @@ -from threading import RLock +import Queue import time import asyncore_pollchoose as asyncore @@ -12,20 +12,16 @@ class AdvancedDispatcher(asyncore.dispatcher): asyncore.dispatcher.__init__(self, sock) self.read_buf = b"" self.write_buf = b"" - self.writeLock = RLock() + self.writeQueue = Queue.Queue() + self.receiveQueue = Queue.Queue() self.state = "init" self.lastTx = time.time() self.sentBytes = 0 self.receivedBytes = 0 - def append_write_buf(self, string = None): - with self.writeLock: - self.write_buf += string - def slice_write_buf(self, length=0): if length > 0: - with self.writeLock: - self.write_buf = self.write_buf[length:] + self.write_buf = self.write_buf[length:] def slice_read_buf(self, length=0): if length > 0: @@ -54,7 +50,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.state = state def writable(self): - return self.connecting or len(self.write_buf) > 0 + return self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty() def readable(self): return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len @@ -74,18 +70,28 @@ class AdvancedDispatcher(asyncore.dispatcher): def handle_write(self): self.lastTx = time.time() if asyncore.maxUploadRate > 0: - written = self.send(self.write_buf[0:asyncore.uploadChunk]) - asyncore.uploadBucket -= written + bufSize = asyncore.uploadChunk else: - written = self.send(self.write_buf) - asyncore.updateSent(written) - self.sentBytes += written - self.slice_write_buf(written) + bufSize = self._buf_len + while len(self.write_buf) < bufSize: + try: + self.write_buf += self.writeQueue.get(False) + except Queue.Empty: + break + if len(self.write_buf) > 0: + written = self.send(self.write_buf[0:bufSize]) + asyncore.uploadBucket -= written + asyncore.updateSent(written) + self.sentBytes += written + self.slice_write_buf(written) def handle_connect(self): self.lastTx = time.time() self.process() + def state_close(self): + pass + def close(self): self.read_buf = b"" self.write_buf = b"" diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 3a5ea1b4..88a8f794 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -58,7 +58,7 @@ class BMConnection(TLSDispatcher, BMQueues): self.verackSent = False self.lastTx = time.time() self.streams = [0] - self.connectionFullyEstablished = False + self.fullyEstablished = False self.connectedAt = 0 self.skipUntil = 0 if address is None and sock is not None: @@ -95,8 +95,8 @@ class BMConnection(TLSDispatcher, BMQueues): def state_init(self): self.bm_proto_reset() if self.isOutbound: - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) - print "%s:%i: Sending version (%ib)" % (self.destination.host, self.destination.port, len(self.write_buf)) + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + print "%s:%i: Sending version" % (self.destination.host, self.destination.port) self.set_state("bm_header") return True @@ -114,12 +114,12 @@ class BMConnection(TLSDispatcher, BMQueues): logger.debug("Skipping processing for %.2fs", self.skipUntil - time.time()) else: logger.debug("Skipping processing due to missing object for %.2fs", self.skipUntil - time.time()) - self.skipUntil = time.time() + now + self.skipUntil = time.time() + delay def set_connection_fully_established(self): UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.antiIntersectionDelay(True) - self.connectionFullyEstablished = True + self.fullyEstablished = True self.sendAddr() self.sendBigInv() @@ -135,6 +135,8 @@ class BMConnection(TLSDispatcher, BMQueues): self.bm_proto_reset() self.set_state("bm_header", 1) print "Bad magic" + self.close() + return False if self.payloadLength > BMConnection.maxMessageSize: self.invalid = True self.set_state("bm_command", protocol.Header.size) @@ -150,7 +152,7 @@ class BMConnection(TLSDispatcher, BMQueues): print "Bad checksum, ignoring" self.invalid = True retval = True - if not self.connectionFullyEstablished and self.command not in ("version", "verack"): + if not self.fullyEstablished and self.command not in ("version", "verack"): logger.error("Received command %s before connection was fully established, ignoring", self.command) self.invalid = True if not self.invalid: @@ -178,7 +180,10 @@ class BMConnection(TLSDispatcher, BMQueues): except struct.error: print "decoding error, skipping" else: - print "Skipping command %s due to invalid data" % (self.command) + #print "Skipping command %s due to invalid data" % (self.command) + print "Closing due to invalid data" % (self.command) + self.close() + return False if retval: self.set_state("bm_header", self.payloadLength) self.bm_proto_reset() @@ -298,12 +303,7 @@ class BMConnection(TLSDispatcher, BMQueues): if False: self.antiIntersectionDelay() else: - try: - self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].payload)) - # this is faster than "if i in Inventory()" - except KeyError: - 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,)) + self.receiveQueue.put(("object", i)) return True def bm_command_inv(self): @@ -327,7 +327,7 @@ class BMConnection(TLSDispatcher, BMQueues): logger.info('inv message lists %i objects. Of those %i are new to me. It took %f seconds to figure that out.', len(items), len(self.objectsNewToMe), time.time()-startTime) payload = addresses.encodeVarint(len(self.objectsNewToMe)) + ''.join(self.objectsNewToMe.keys()) - self.append_write_buf(protocol.CreatePacket('getdata', payload)) + self.writeQueue.put(protocol.CreatePacket('getdata', payload)) # for i in random.sample(self.objectsNewToMe, len(self.objectsNewToMe)): # DownloadQueue().put(i) @@ -370,6 +370,18 @@ class BMConnection(TLSDispatcher, BMQueues): def bm_command_addr(self): addresses = self.decode_payload_content("lQIQ16sH") + import pprint + for i in addresses: + seenTime, stream, services, ip, port = i + decodedIP = protocol.checkIPAddress(ip) + if stream not in state.streamsInWhichIAmParticipating: + continue + #print "maybe adding %s in stream %i to knownnodes (%i)" % (decodedIP, stream, len(knownnodes.knownNodes[stream])) + if decodedIP is not False and seenTime > time.time() - 10800: + peer = state.Peer(decodedIP, port) + if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer] > seenTime: + continue + knownnodes.knownNodes[stream][peer] = seenTime return True def bm_command_portcheck(self): @@ -377,7 +389,7 @@ class BMConnection(TLSDispatcher, BMQueues): return True def bm_command_ping(self): - self.append_write_buf(protocol.CreatePacket('pong')) + self.writeQueue.put(protocol.CreatePacket('pong')) return True def bm_command_pong(self): @@ -411,11 +423,11 @@ class BMConnection(TLSDispatcher, BMQueues): # TODO ABORT return True #shared.connectedHostsList[self.destination] = self.streams[0] - self.append_write_buf(protocol.CreatePacket('verack')) + self.writeQueue.put(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)) - print "%s:%i: Sending version (%ib)" % (self.destination.host, self.destination.port, len(self.write_buf)) + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, True)) + 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 @@ -431,20 +443,20 @@ class BMConnection(TLSDispatcher, BMQueues): def peerValidityChecks(self): if self.remoteProtocolVersion < 3: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, + self.writeQueue.put(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.peer)) return False if self.timeOffset > 3600: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, + self.writeQueue.put(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 return False elif self.timeOffset < -3600: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, + self.writeQueue.put(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) @@ -453,7 +465,7 @@ class BMConnection(TLSDispatcher, BMQueues): else: shared.timeOffsetWrongCount = 0 if len(self.streams) == 0: - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, + self.writeQueue.put(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.peer)) @@ -461,7 +473,7 @@ class BMConnection(TLSDispatcher, BMQueues): if self.destination in network.connectionpool.BMConnectionPool().inboundConnections: try: if not protocol.checkSocksIP(self.destination.host): - self.append_write_buf(protocol.assembleErrorMessage(fatal=2, + self.writeQueue.put(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.peer)) @@ -474,7 +486,7 @@ class BMConnection(TLSDispatcher, BMQueues): def sendChunk(): if addressCount == 0: return - self.append_write_buf(protocol.CreatePacket('addr', \ + self.writeQueue.put(protocol.CreatePacket('addr', \ addresses.encodeVarint(addressCount) + payload)) # We are going to share a maximum number of 1000 addrs (per overlapping @@ -563,7 +575,7 @@ class BMConnection(TLSDispatcher, BMQueues): 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)) + self.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(objectCount) + payload)) # Select all hashes for objects in this stream. bigInvList = {} @@ -613,6 +625,7 @@ class BMConnection(TLSDispatcher, BMQueues): self.close() def close(self, reason=None): + self.set_state("close") if reason is None: print "%s:%i: closing" % (self.destination.host, self.destination.port) #traceback.print_stack() @@ -653,7 +666,10 @@ class BMServer(AdvancedDispatcher): pair = self.accept() if pair is not None: sock, addr = pair - network.connectionpool.BMConnectionPool().addConnection(BMConnection(sock=sock)) + try: + network.connectionpool.BMConnectionPool().addConnection(BMConnection(sock=sock)) + except socket.errno: + pass if __name__ == "__main__": diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 6acf4bb6..8d4f4539 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -104,29 +104,32 @@ class BMConnectionPool(object): print "bootstrapping dns" helper_bootstrap.dns() self.bootstrapped = True - for i in range(len(self.outboundConnections), BMConfigParser().safeGetInt("bitmessagesettings", "maxoutboundconnections")): - chosen = chooseConnection(random.choice(self.streams)) - if chosen in self.outboundConnections: - continue - if chosen.host in self.inboundConnections: - 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 (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): - self.addConnection(network.bmproto.Socks5BMConnection(chosen)) - elif (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a"): - self.addConnection(network.bmproto.Socks4aBMConnection(chosen)) - elif not chosen.host.endswith(".onion"): - self.addConnection(network.bmproto.BMConnection(chosen)) - except socket.error as e: - if e.errno == errno.ENETUNREACH: + 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): + chosen = chooseConnection(random.choice(self.streams)) + if chosen in self.outboundConnections: continue + if chosen.host in self.inboundConnections: + 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 (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): + self.addConnection(network.bmproto.Socks5BMConnection(chosen)) + elif (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a"): + self.addConnection(network.bmproto.Socks4aBMConnection(chosen)) + elif not chosen.host.endswith(".onion"): + self.addConnection(network.bmproto.BMConnection(chosen)) + except socket.error as e: + if e.errno == errno.ENETUNREACH: + continue if acceptConnections and len(self.listeningSockets) == 0: self.startListening() @@ -142,10 +145,10 @@ class BMConnectionPool(object): for i in self.inboundConnections.values() + self.outboundConnections.values(): minTx = time.time() - 20 - if i.connectionFullyEstablished: + if i.fullyEstablished: minTx -= 300 - 20 if i.lastTx < minTx: - if i.connectionFullyEstablished: - i.append_write_buf(protocol.CreatePacket('ping')) + if i.fullyEstablished: + i.writeQueue.put(protocol.CreatePacket('ping')) else: i.close("Timeout (%is)" % (time.time() - i.lastTx)) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 3a9d8e37..498bd340 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -8,7 +8,7 @@ from network.connectionpool import BMConnectionPool class BMNetworkThread(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="BMNetworkThread") + threading.Thread.__init__(self, name="AsyncoreThread") self.initStop() self.name = "AsyncoreThread" BMConnectionPool() diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py new file mode 100644 index 00000000..6405238d --- /dev/null +++ b/src/network/receivequeuethread.py @@ -0,0 +1,44 @@ +import Queue +import threading + +from bmconfigparser import BMConfigParser +from debug import logger +from helper_threading import StoppableThread +from inventory import Inventory +from network.connectionpool import BMConnectionPool +import protocol + +class ReceiveQueueThread(threading.Thread, StoppableThread): + def __init__(self): + threading.Thread.__init__(self, name="ReceiveQueueThread") + self.initStop() + self.name = "ReceiveQueueThread" + BMConnectionPool() + logger.error("init asyncore thread") + + def run(self): + while not self._stopped: + processed = 0 + for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + try: + command, args = i.receiveQueue.get(False) + except Queue.Empty: + continue + processed += 1 + try: + getattr(self, "command_" + str(command))(i, args) + except AttributeError: + # missing command + raise + if processed == 0: + self.stop.wait(0.2) + + def command_object(self, connection, objHash): + try: + connection.writeQueue.put(protocol.CreatePacket('object', Inventory()[objHash].payload)) + except KeyError: + connection.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.' % (connection.destination,)) + + def stopThread(self): + super(ReceiveQueueThread, self).stopThread() diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 02c8d4af..4b6b64fa 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -59,28 +59,28 @@ class Socks4aConnection(Socks4a): 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])) + self.writeQueue.put(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) + self.writeQueue.put(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)) + self.writeQueue.put(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) + self.writeQueue.put(self.ipaddr) if self._auth: - self.append_write_buf(self._auth[0]) - self.append_write_buf(chr(0x00).encode()) + self.writeQueue.put(self._auth[0]) + self.writeQueue.put(chr(0x00).encode()) if rmtrslv: - self.append_write_buf(self.destination[0] + chr(0x00).encode()) + self.writeQueue.put(self.destination[0] + chr(0x00).encode()) self.set_state("pre_connect", 0) @@ -92,12 +92,12 @@ class Socks4aResolver(Socks4a): 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)) + self.writeQueue.put(struct.pack('>BBH', 0x04, 0xF0, self.destination[1])) + self.writeQueue.put(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.writeQueue.put(self._auth[0]) + self.writeQueue.put(chr(0x00).encode()) + self.writeQueue.put(self.host + chr(0x00).encode()) self.set_state("pre_connect", 0) def resolved(self): diff --git a/src/network/socks5.py b/src/network/socks5.py index 5ba6f3e3..0d1717d4 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -17,9 +17,9 @@ class Socks5(Proxy): def state_init(self): if self._auth: - self.append_write_buf(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) + self.writeQueue.put(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) else: - self.append_write_buf(struct.pack('BBB', 0x05, 0x01, 0x00)) + self.writeQueue.put(struct.pack('BBB', 0x05, 0x01, 0x00)) self.set_state("auth_1", 0) def state_auth_1(self): @@ -35,7 +35,7 @@ class Socks5(Proxy): self.set_state("auth_done", 2) elif ret[1] == 2: # username/password - self.append_write_buf(struct.pack('BB', 1, len(self._auth[0])) + \ + self.writeQueue.put(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_1", 2) @@ -130,23 +130,23 @@ class Socks5Connection(Socks5): def state_auth_done(self): # Now we can request the actual connection - self.append_write_buf(struct.pack('BBB', 0x05, 0x01, 0x00)) + self.writeQueue.put(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) + self.writeQueue.put(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]) + self.writeQueue.put(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.writeQueue.put(chr(0x01).encode() + self.ipaddr) + self.writeQueue.put(struct.pack(">H", self.destination[1])) self.set_state("pre_connect", 0) @@ -158,9 +158,9 @@ class Socks5Resolver(Socks5): 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.writeQueue.put(struct.pack('BBB', 0x05, 0xF0, 0x00)) + self.writeQueue.put(chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host)) + self.writeQueue.put(struct.pack(">H", self.port)) self.set_state("pre_connect", 0) def resolved(self): diff --git a/src/protocol.py b/src/protocol.py index b7847e8f..83ecb7bd 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -67,7 +67,7 @@ def isBitSetWithinBitfield(fourByteString, n): x, = unpack('>L', fourByteString) return x & 2**n != 0 -# data handling +# ip addresses def encodeHost(host): if host.find('.onion') > -1: @@ -86,6 +86,49 @@ def networkType(host): else: return 'IPv6' +def checkIPAddress(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 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 checkIPv6Address(host, hostStandardFormat) + +def checkIPv4Address(host, hostStandardFormat): + if host[0] == '\x7F': # 127/8 + logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) + return False + if host[0] == '\x0A': # 10/8 + logger.debug('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) + 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 + +def checkIPv6Address(host, hostStandardFormat): + if host == ('\x00' * 15) + '\x01': + logger.debug('Ignoring loopback address: ' + hostStandardFormat) + return False + if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: + logger.debug ('Ignoring local address: ' + hostStandardFormat) + return False + if (ord(host[0]) & 0xfe) == 0xfc: + logger.debug ('Ignoring unique local address: ' + hostStandardFormat) + return False + return hostStandardFormat + # checks def haveSSL(server = False): diff --git a/src/state.py b/src/state.py index c7b79e07..72852f3e 100644 --- a/src/state.py +++ b/src/state.py @@ -21,6 +21,8 @@ curses = False sqlReady = False # set to true by sqlTread when ready for processing +maximumNumberOfHalfOpenConnections = 0 + # 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 -- 2.45.1 From b37a05fd0affb67f03aaa2105d5d2ac72ff93dc9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 07:48:29 +0200 Subject: [PATCH 0750/1102] Allow encoding 3 in broadcast API --- src/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api.py b/src/api.py index 82a56d40..24c0fc12 100644 --- a/src/api.py +++ b/src/api.py @@ -714,8 +714,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 4*24*60*60 elif len(params) == 5: fromAddress, subject, message, encodingType, TTL = params - if encodingType != 2: - raise APIError(6, 'The encoding type must be 2 because that is the only one this program currently supports.') + if encodingType not in [2, 3]: + raise APIError(6, 'The encoding type must be 2 or 3.') subject = self._decode(subject, "base64") message = self._decode(message, "base64") if len(subject + message) > (2 ** 18 - 500): -- 2.45.1 From d699a28e4900f9670e0d8cf631ae0aaf44d7c914 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 19:00:19 +0200 Subject: [PATCH 0751/1102] Add variables to errno and socket - to make sure they work cross platform without having to do complicated tests --- src/bitmessagemain.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c05d002a..8f39deb9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -22,6 +22,7 @@ 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 socket import ctypes from struct import pack @@ -92,7 +93,16 @@ def connectToStream(streamNumber): a.setup(streamNumber, selfInitiatedConnections) a.start() -def _fixWinsock(): +def _fixSocket(): + if sys.platform.startswith('linux'): + socket.SO_BINDTODEVICE = 25 + + if not sys.platform.startswith('win'): + errno.WSAEWOULDBLOCK = errno.EWOULDBLOCK + errno.WSAENETUNREACH = errno.ENETUNREACH + errno.WSAECONNREFUSED = errno.ECONNREFUSED + errno.WSAEHOSTUNREACH = errno.EHOSTUNREACH + if not sys.platform.startswith('win'): return @@ -177,7 +187,7 @@ if shared.useVeryEasyProofOfWorkForTesting: class Main: def start(self, daemon=False): - _fixWinsock() + _fixSocket() shared.daemon = daemon -- 2.45.1 From 7b9b7504adf36da5b372c8c93131b2635068cb55 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 19:01:14 +0200 Subject: [PATCH 0752/1102] Don't clean right on startup --- src/class_singleCleaner.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 1ed7a5e4..6c0a62f6 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -49,6 +49,10 @@ class singleCleaner(threading.Thread, StoppableThread): # 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(300) + while state.shutdown == 0: queues.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) -- 2.45.1 From 1d87c635043c7cab027ddc346b2228e695dbd5ae Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 19:02:05 +0200 Subject: [PATCH 0753/1102] Traceback on Ctrl-C - Ctrl-C will print a traceback of all threads instead of complaining --- src/helper_generic.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/helper_generic.py b/src/helper_generic.py index f2a293cd..26d65dcb 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -4,6 +4,7 @@ import sys from binascii import hexlify, unhexlify from multiprocessing import current_process from threading import current_thread, enumerate +import traceback from bmconfigparser import BMConfigParser from debug import logger @@ -29,10 +30,20 @@ def convertIntToString(n): else: return unhexlify('0' + a[2:]) - def convertStringToInt(s): return int(hexlify(s), 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": @@ -46,6 +57,7 @@ def signal_handler(signal, frame): if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): shutdown.doCleanShutdown() else: + allThreadTraceback(frame) print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' def isHostInPrivateIPRange(host): -- 2.45.1 From 36b5e2c04f31c8ded967b511c0ae4bd801f3f807 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 19:03:27 +0200 Subject: [PATCH 0754/1102] Inventory storage abstraction - can have multiple storage types for inventory - sqlite is the old one, filesystem is a new available --- src/inventory.py | 94 +++++--------------- src/storage/__init__.py | 0 src/storage/filesystem.py | 175 ++++++++++++++++++++++++++++++++++++++ src/storage/sqlite.py | 81 ++++++++++++++++++ src/storage/storage.py | 51 +++++++++++ 5 files changed, 329 insertions(+), 72 deletions(-) create mode 100644 src/storage/__init__.py create mode 100644 src/storage/filesystem.py create mode 100644 src/storage/sqlite.py create mode 100644 src/storage/storage.py diff --git a/src/inventory.py b/src/inventory.py index a796968a..b676415b 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -1,87 +1,37 @@ 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(collections.MutableMapping): +class Inventory(): 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.numberOfInventoryLookupsPerformed = 0 - self._streams = collections.defaultdict(set) # 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. - self.lock = RLock() # Guarantees that two receiveDataThreads don't receive and process the same message concurrently (probably sent by a malicious individual) - self.InventoryItem = collections.namedtuple('InventoryItem', 'type stream payload expires tag') + #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() - def __contains__(self, hash): - with self.lock: - self.numberOfInventoryLookupsPerformed += 1 - if hash in self._inventory: - return True - return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) - - 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=?', hash) - if not rows: - raise KeyError(hash) - return self.InventoryItem(*rows[0]) - - def __setitem__(self, hash, value): - with self.lock: - value = self.InventoryItem(*value) - self._inventory[hash] = value - self._streams[value.stream].add(hash) - - 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, type, tag): - with self.lock: - values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] - values += (self.InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) - return values - - def hashes_by_stream(self, stream): - with self.lock: - return self._streams[stream] - - 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 += (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 (?, ?, ?, ?, ?, ?)', objectHash, *value) - self._inventory.clear() - - def clean(self): - with self.lock: - sqlExecute('DELETE FROM inventory WHERE expirestime 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: + del self[hashId] diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py new file mode 100644 index 00000000..38e9c0a2 --- /dev/null +++ b/src/storage/sqlite.py @@ -0,0 +1,81 @@ +import collections +from threading import current_thread, enumerate as threadingEnumerate, RLock +import Queue +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._streams = collections.defaultdict(set) # 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. + 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: + self.numberOfInventoryLookupsPerformed += 1 + if hash in self._inventory: + return True + return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) + + 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=?', 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._streams[value.stream].add(hash) + + 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, type, tag): + with self.lock: + values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] + values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) + return values + + def hashes_by_stream(self, stream): + with self.lock: + return self._streams[stream] + + 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 += (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 (?, ?, ?, ?, ?, ?)', objectHash, *value) + self._inventory.clear() + + def clean(self): + with self.lock: + sqlExecute('DELETE FROM inventory WHERE expirestime Date: Sat, 27 May 2017 19:09:21 +0200 Subject: [PATCH 0755/1102] Asyncore update - bugfixes - UDP socket for local peer discovery - new function assembleAddr to unify creating address command - open port checker functionality (inactive) - sendBigInv is done in a thread separate from the network IO thread --- src/bitmessagemain.py | 13 +- src/bmconfigparser.py | 6 +- src/network/advanceddispatcher.py | 16 +- src/network/announcethread.py | 39 ++ src/network/bmproto.py | 375 +++++-------------- src/network/connectionchooser.py | 7 +- src/network/connectionpool.py | 63 +++- src/network/{bmqueues.py => objectracker.py} | 25 +- src/network/receivequeuethread.py | 43 ++- src/network/tcp.py | 236 ++++++++++++ src/network/tls.py | 8 +- src/network/udp.py | 198 ++++++++++ src/protocol.py | 24 +- src/queues.py | 1 + 14 files changed, 721 insertions(+), 333 deletions(-) create mode 100644 src/network/announcethread.py rename src/network/{bmqueues.py => objectracker.py} (74%) create mode 100644 src/network/tcp.py create mode 100644 src/network/udp.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 8f39deb9..d566852c 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -51,9 +51,13 @@ 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.networkthread import BMNetworkThread from network.receivequeuethread import ReceiveQueueThread +from network.announcethread import AnnounceThread +#from network.downloadthread import DownloadThread # Helper Functions import helper_bootstrap @@ -221,6 +225,8 @@ 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 + # SMTP delivery thread if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': smtpDeliveryThread = smtpDeliver() @@ -261,11 +267,14 @@ class Main: if BMConfigParser().safeGetBoolean("network", "asyncore"): asyncoreThread = BMNetworkThread() - asyncoreThread.daemon = False + asyncoreThread.daemon = True asyncoreThread.start() receiveQueueThread = ReceiveQueueThread() - receiveQueueThread.daemon = False + receiveQueueThread.daemon = True receiveQueueThread.start() + announceThread = AnnounceThread() + announceThread.daemon = True + announceThread.start() connectToStream(1) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 4e66c703..8c4d8b3c 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -16,7 +16,11 @@ BMConfigDefaults = { "maxuploadrate": 0, }, "network": { - "asyncore": False + "asyncore": False, + "bind": None, + }, + "inventory": { + "storage": "sqlite", }, "zlib": { 'maxsize': 1048576 diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index fb28f3d4..938eb11d 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -36,7 +36,10 @@ class AdvancedDispatcher(asyncore.dispatcher): def process(self): if self.state not in ["init", "tls_handshake"] and len(self.read_buf) == 0: return - while True: + if not self.connected: + return + maxLoop = 20 + while maxLoop > 0: try: # print "Trying to handle state \"%s\"" % (self.state) if getattr(self, "state_" + str(self.state))() is False: @@ -44,6 +47,7 @@ class AdvancedDispatcher(asyncore.dispatcher): except AttributeError: # missing state raise + maxLoop -= 1 def set_state(self, state, length=0): self.slice_read_buf(length) @@ -96,4 +100,14 @@ class AdvancedDispatcher(asyncore.dispatcher): self.read_buf = b"" self.write_buf = b"" self.state = "shutdown" + while True: + try: + self.writeQueue.get(False) + except Queue.Empty: + break + while True: + try: + self.receiveQueue.get(False) + except Queue.Empty: + break asyncore.dispatcher.close(self) diff --git a/src/network/announcethread.py b/src/network/announcethread.py new file mode 100644 index 00000000..0ba93d7a --- /dev/null +++ b/src/network/announcethread.py @@ -0,0 +1,39 @@ +import Queue +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 protocol +import state + +class AnnounceThread(threading.Thread, StoppableThread): + def __init__(self): + threading.Thread.__init__(self, name="AnnounceThread") + self.initStop() + self.name = "AnnounceThread" + BMConnectionPool() + logger.error("init announce thread") + + def run(self): + lastSelfAnnounced = 0 + while not self._stopped: + 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(): + for stream in state.streamsInWhichIAmParticipating: + addr = (stream, state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), time.time()) + connection.writeQueue.put(BMProto.assembleAddr([addr])) + + def stopThread(self): + super(AnnounceThread, self).stopThread() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 88a8f794..6e1c3a18 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -19,12 +19,9 @@ import network.connectionpool from network.downloadqueue import DownloadQueue from network.node import Node import network.asyncore_pollchoose as asyncore +from network.objectracker import ObjectTracker from network.proxy import Proxy, ProxyError, GeneralProxyError -from network.bmqueues import BMQueues -from network.socks5 import Socks5Connection, Socks5Resolver, Socks5AuthError, Socks5Error -from network.socks4a import Socks4aConnection, Socks4aResolver, Socks4aError from network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue -from network.tls import TLSDispatcher import addresses from bmconfigparser import BMConfigParser @@ -42,7 +39,7 @@ class BMProtoInsufficientDataError(BMProtoError): pass class BMProtoExcessiveDataError(BMProtoError): pass -class BMConnection(TLSDispatcher, BMQueues): +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 @@ -51,36 +48,40 @@ class BMConnection(TLSDispatcher, BMQueues): 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.verackReceived = False - self.verackSent = False - self.lastTx = time.time() - 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() - print "received connection in background from %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) - print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) - shared.connectedHostsList[self.destination] = 0 - BMQueues.__init__(self) - UISignalQueue.put(('updateNetworkStatusTab', 'no data')) +# def __init__(self, address=None, sock=None): +# AdvancedDispatcher.__init__(self, sock) +# self.verackReceived = False +# self.verackSent = False +# self.lastTx = time.time() +# 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() +# #print "received connection in background from %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) +# #print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) +# shared.connectedHostsList[self.destination] = 0 +# ObjectTracker.__init__(self) +# UISignalQueue.put(('updateNetworkStatusTab', 'no data')) def bm_proto_reset(self): self.magic = None @@ -92,37 +93,6 @@ class BMConnection(TLSDispatcher, BMQueues): self.payloadOffset = 0 self.object = None - def state_init(self): - self.bm_proto_reset() - if self.isOutbound: - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) - print "%s:%i: Sending version" % (self.destination.host, self.destination.port) - self.set_state("bm_header") - return True - - 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 + UploadQueue.queueCount/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 - if delay > 0: - if initial: - self.skipUntil = self.connectedAt + delay - if self.skipUntil > time.time(): - logger.debug("Skipping processing for %.2fs", self.skipUntil - time.time()) - else: - logger.debug("Skipping processing due to missing object for %.2fs", self.skipUntil - time.time()) - self.skipUntil = time.time() + delay - - def set_connection_fully_established(self): - UISignalQueue.put(('updateNetworkStatusTab', 'no data')) - self.antiIntersectionDelay(True) - self.fullyEstablished = True - self.sendAddr() - self.sendBigInv() - def state_bm_header(self): #print "%s:%i: header" % (self.destination.host, self.destination.port) if len(self.read_buf) < protocol.Header.size: @@ -137,7 +107,7 @@ class BMConnection(TLSDispatcher, BMQueues): print "Bad magic" self.close() return False - if self.payloadLength > BMConnection.maxMessageSize: + if self.payloadLength > BMProto.maxMessageSize: self.invalid = True self.set_state("bm_command", protocol.Header.size) return True @@ -309,28 +279,18 @@ class BMConnection(TLSDispatcher, BMQueues): def bm_command_inv(self): items = self.decode_payload_content("L32s") - if len(items) >= BMConnection.maxObjectCount: + if len(items) >= BMProto.maxObjectCount: logger.error("Too many items in inv message!") raise BMProtoExcessiveDataError() else: pass - #print "items in inv: %i" % (len(items)) - startTime = time.time() - #advertisedSet = set() for i in items: - #advertisedSet.add(i) - self.handleReceivedObj(i) - #objectsNewToMe = advertisedSet - #for stream in self.streams: - #objectsNewToMe -= Inventory().hashes_by_stream(stream) - logger.info('inv message lists %i objects. Of those %i are new to me. It took %f seconds to figure that out.', len(items), len(self.objectsNewToMe), time.time()-startTime) + self.receiveQueue.put(("inv", i)) + self.handleReceivedInventory(i) payload = addresses.encodeVarint(len(self.objectsNewToMe)) + ''.join(self.objectsNewToMe.keys()) self.writeQueue.put(protocol.CreatePacket('getdata', payload)) - -# for i in random.sample(self.objectsNewToMe, len(self.objectsNewToMe)): -# DownloadQueue().put(i) return True def bm_command_object(self): @@ -338,7 +298,7 @@ class BMConnection(TLSDispatcher, BMQueues): nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv") self.object = BMObject(nonce, expiresTime, objectType, version, streamNumber, self.payload) - if len(self.payload) - self.payloadOffset > BMConnection.maxObjectPayloadSize: + 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() @@ -368,20 +328,23 @@ class BMConnection(TLSDispatcher, BMQueues): #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) return True + def _decode_addr(self): + return self.decode_payload_content("lQIQ16sH") + def bm_command_addr(self): - addresses = self.decode_payload_content("lQIQ16sH") - import pprint + addresses = self._decode_addr() for i in addresses: seenTime, stream, services, ip, port = i decodedIP = protocol.checkIPAddress(ip) if stream not in state.streamsInWhichIAmParticipating: continue #print "maybe adding %s in stream %i to knownnodes (%i)" % (decodedIP, stream, len(knownnodes.knownNodes[stream])) - if decodedIP is not False and seenTime > time.time() - 10800: + if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: peer = state.Peer(decodedIP, port) if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer] > seenTime: continue knownnodes.knownNodes[stream][peer] = seenTime + AddrUploadQueue().put((stream, peer)) return True def bm_command_portcheck(self): @@ -411,14 +374,15 @@ class BMConnection(TLSDispatcher, BMQueues): def bm_command_version(self): #self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) 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()) - print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) - print "services: %08X" % (self.services) - print "time offset: %i" % (self.timestamp - int(time.time())) - print "my external IP: %s" % (self.sockNode.host) - print "remote node incoming port: %i" % (self.peerNode.port) - print "user agent: %s" % (self.userAgent) - print "streams: [%s]" % (",".join(map(str,self.streams))) + #print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) + #print "services: %08X" % (self.services) + #print "time offset: %i" % (self.timestamp - int(time.time())) + #print "my external IP: %s" % (self.sockNode.host) + #print "remote node incoming port: %i" % (self.peerNode.port) + #print "user agent: %s" % (self.userAgent) + #print "streams: [%s]" % (",".join(map(str,self.streams))) if not self.peerValidityChecks(): # TODO ABORT return True @@ -446,20 +410,20 @@ class BMConnection(TLSDispatcher, BMQueues): self.writeQueue.put(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.peer)) + str(self.remoteProtocolVersion), str(self.destination)) return False - if self.timeOffset > 3600: + if self.timeOffset > BMProto.maxTimeOffset: self.writeQueue.put(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) + self.destination, self.timeOffset) shared.timeOffsetWrongCount += 1 return False - elif self.timeOffset < -3600: + elif self.timeOffset < -BMProto.maxTimeOffset: self.writeQueue.put(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) + self.destination, self.timeOffset) shared.timeOffsetWrongCount += 1 return False else: @@ -468,7 +432,7 @@ class BMConnection(TLSDispatcher, BMQueues): self.writeQueue.put(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.peer)) + str(self.destination)) return False if self.destination in network.connectionpool.BMConnectionPool().inboundConnections: try: @@ -476,218 +440,63 @@ class BMConnection(TLSDispatcher, BMQueues): self.writeQueue.put(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.peer)) + str(self.destination)) return False except: pass + if self.nonce == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: + self.writeQueue.put(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 True - def sendAddr(self): - def sendChunk(): - if addressCount == 0: - return - self.writeQueue.put(protocol.CreatePacket('addr', \ - addresses.encodeVarint(addressCount) + payload)) - - # 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'' - - for stream in self.streams: - addrsInMyStream = {} - addrsInChildStreamLeft = {} - addrsInChildStreamRight = {} - - 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.streams: - 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.streams: - 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: - addressCount += 1 - payload += struct.pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += struct.pack('>I', stream) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += struct.pack('>H', PORT) # remote port - if addressCount >= BMConnection.maxAddrCount: - sendChunk() - payload = b'' - addressCount = 0 - for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamLeft: - addressCount += 1 - payload += struct.pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += struct.pack('>I', stream * 2) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += struct.pack('>H', PORT) # remote port - if addressCount >= BMConnection.maxAddrCount: - sendChunk() - payload = b'' - addressCount = 0 - for (HOST, PORT), timeLastReceivedMessageFromThisNode in addrsInChildStreamRight: - addressCount += 1 - payload += struct.pack( - '>Q', timeLastReceivedMessageFromThisNode) # 64-bit time - payload += struct.pack('>I', (stream * 2) + 1) - payload += struct.pack( - '>q', 1) # service bit flags offered by this node - payload += protocol.encodeHost(HOST) - payload += struct.pack('>H', PORT) # remote port - if addressCount >= BMConnection.maxAddrCount: - sendChunk() - payload = b'' - addressCount = 0 - - # flush - sendChunk() - - 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.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(objectCount) + payload)) - - # Select all hashes for objects in this stream. - bigInvList = {} - for stream in self.streams: - for hash in Inventory().unexpired_hashes_by_stream(stream): - bigInvList[hash] = 0 -# for hash in ObjUploadQueue().streamHashes(stream): -# try: -# del bigInvList[hash] -# except KeyError: -# pass - 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 >= BMConnection.maxObjectCount: - self.sendChunk() - payload = b'' - objectCount = 0 - - # flush - sendChunk() + @staticmethod + def assembleAddr(peerList): + if type(peerList) is state.Peer: + peerList = (peerList) + # TODO handle max length, now it's done by upper layers + payload = addresses.encodeVarint(len(peerList)) + for address in peerList: + 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 + return protocol.CreatePacket('addr', payload) def handle_connect_event(self): try: asyncore.dispatcher.handle_connect_event(self) self.connectedAt = time.time() except socket.error as e: - print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() def handle_read_event(self): try: asyncore.dispatcher.handle_read_event(self) except socket.error as e: - print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() def handle_write_event(self): try: asyncore.dispatcher.handle_write_event(self) except socket.error as e: - print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() def close(self, reason=None): self.set_state("close") - if reason is None: - print "%s:%i: closing" % (self.destination.host, self.destination.port) - #traceback.print_stack() - else: - print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) +# if reason is None: +# print "%s:%i: closing" % (self.destination.host, self.destination.port) +# #traceback.print_stack() +# else: +# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) network.connectionpool.BMConnectionPool().removeConnection(self) - asyncore.dispatcher.close(self) - - -class Socks5BMConnection(Socks5Connection, BMConnection): - def __init__(self, address): - Socks5Connection.__init__(self, address=address) - - def state_socks_handshake_done(self): - BMConnection.state_init(self) - return False - - -class Socks4aBMConnection(Socks4aConnection, BMConnection): - def __init__(self, address): - Socks4aConnection.__init__(self, address=address) - - def state_socks_handshake_done(self): - BMConnection.state_init(self) - return False - - -class BMServer(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() - self.bind((host, port)) - self.listen(5) - - def handle_accept(self): - pair = self.accept() - if pair is not None: - sock, addr = pair - try: - network.connectionpool.BMConnectionPool().addConnection(BMConnection(sock=sock)) - except socket.errno: - pass - - -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) + AdvancedDispatcher.close(self) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 1c8d988d..05ef47bd 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -3,7 +3,7 @@ import random from bmconfigparser import BMConfigParser import knownnodes -from queues import portCheckerQueue +from queues import portCheckerQueue, peerDiscoveryQueue import state def chooseConnection(stream): @@ -13,4 +13,7 @@ def chooseConnection(stream): try: return portCheckerQueue.get(False) except Queue.Empty: - return random.choice(knownnodes.knownNodes[stream].keys()) + try: + return peerDiscoveryQueue.get(False) + except Queue.Empty: + return random.choice(knownnodes.knownNodes[stream].keys()) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 8d4f4539..a75b62aa 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -2,11 +2,14 @@ import errno import socket import time import random +import re from bmconfigparser import BMConfigParser from debug import logger import helper_bootstrap import network.bmproto +import network.tcp +import network.udp from network.connectionchooser import chooseConnection import network.asyncore_pollchoose as asyncore import protocol @@ -23,33 +26,31 @@ class BMConnectionPool(object): self.outboundConnections = {} self.inboundConnections = {} self.listeningSockets = {} + self.udpSockets = {} self.streams = [] self.bootstrapped = False def handleReceivedObject(self, connection, streamNumber, hashid): for i in self.inboundConnections.values() + self.outboundConnections.values(): - if not isinstance(i, network.bmproto.BMConnection): + if not isinstance(i, network.bmproto.BMProto): continue + try: + del i.objectsNewToMe[hashid] + except KeyError: + i.objectsNewToThem[hashid] = True if i == connection: try: del i.objectsNewToThem[hashid] except KeyError: pass - else: - try: - del i.objectsNewToThem[hashid] - except KeyError: - i.objectsNewToThem[hashid] = True - try: - del i.objectsNewToMe[hashid] - except KeyError: - pass def connectToStream(self, streamNumber): self.streams.append(streamNumber) def addConnection(self, connection): + if isinstance(connection, network.udp.UDPSocket): + return if connection.isOutbound: self.outboundConnections[connection.destination] = connection else: @@ -59,7 +60,9 @@ class BMConnectionPool(object): self.inboundConnections[connection.destination.host] = connection def removeConnection(self, connection): - if connection.isOutbound: + if isinstance(connection, network.udp.UDPSocket): + return + elif connection.isOutbound: try: del self.outboundConnections[connection.destination] except KeyError: @@ -73,16 +76,29 @@ class BMConnectionPool(object): except KeyError: pass - def startListening(self): - port = BMConfigParser().safeGetInt("bitmessagesettings", "port") + def getListeningIP(self): if BMConfigParser().safeGet("bitmessagesettings", "onionhostname").endswith(".onion"): host = BMConfigParser().safeGet("bitmessagesettigns", "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 = '' - self.listeningSockets[state.Peer(host, port)] = network.bmproto.BMServer(host=host, port=port) + return host + + def startListening(self): + host = self.getListeningIP() + port = BMConfigParser().safeGetInt("bitmessagesettings", "port") + self.listeningSockets[state.Peer(host, port)] = network.tcp.TCPServer(host=host, port=port) + + def startUDPSocket(self, bind=None): + if bind is None: + host = self.getListeningIP() + self.udpSockets[host] = network.udp.UDPSocket(host=host) + else: + self.udpSockets[bind] = network.udp.UDPSocket(host=bind) def loop(self): # defaults to empty loop if outbound connections are maxed @@ -122,11 +138,11 @@ class BMConnectionPool(object): # continue try: if (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): - self.addConnection(network.bmproto.Socks5BMConnection(chosen)) + self.addConnection(network.tcp.Socks5BMConnection(chosen)) elif (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a"): - self.addConnection(network.bmproto.Socks4aBMConnection(chosen)) + self.addConnection(network.tcp.Socks4aBMConnection(chosen)) elif not chosen.host.endswith(".onion"): - self.addConnection(network.bmproto.BMConnection(chosen)) + self.addConnection(network.tcp.TCPConnection(chosen)) except socket.error as e: if e.errno == errno.ENETUNREACH: continue @@ -134,10 +150,23 @@ class BMConnectionPool(object): if acceptConnections and len(self.listeningSockets) == 0: self.startListening() logger.info('Listening for incoming connections.') + if acceptConnections and len(self.udpSockets) == 0: + if BMConfigParser().safeGet("network", "bind") is None: + self.startUDPSocket() + else: + for bind in re.sub("[^\w.]+", " ", BMConfigParser().safeGet("network", "bind")).split(): + self.startUDPSocket(bind) + logger.info('Starting UDP socket(s).') if len(self.listeningSockets) > 0 and not acceptConnections: for i in self.listeningSockets: i.close() + self.listeningSockets = {} logger.info('Stopped listening for incoming connections.') + if len(self.udpSockets) > 0 and not acceptConnections: + for i in self.udpSockets: + i.close() + self.udpSockets = {} + logger.info('Stopped udp sockets.') # while len(asyncore.socket_map) > 0 and state.shutdown == 0: # print "loop, state = %s" % (proxy.state) diff --git a/src/network/bmqueues.py b/src/network/objectracker.py similarity index 74% rename from src/network/bmqueues.py rename to src/network/objectracker.py index 96ad52e4..246916b9 100644 --- a/src/network/bmqueues.py +++ b/src/network/objectracker.py @@ -1,3 +1,4 @@ +from Queue import Queue import time from inventory import Inventory @@ -21,7 +22,7 @@ except ImportError: # it isn't actually implemented yet so no point in turning it on haveBloom = False -class BMQueues(object): +class ObjectTracker(object): invCleanPeriod = 300 invInitialCapacity = 50000 invErrorRate = 0.03 @@ -29,20 +30,22 @@ class BMQueues(object): def __init__(self): self.objectsNewToMe = {} self.objectsNewToThem = {} + self.downloadPending = 0 + self.downloadQueue = Queue() self.initInvBloom() self.initAddrBloom() def initInvBloom(self): if haveBloom: # lock? - self.invBloom = BloomFilter(capacity=BMQueues.invInitialCapacity, - error_rate=BMQueues.invErrorRate) + self.invBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, + error_rate=ObjectTracker.invErrorRate) def initAddrBloom(self): if haveBloom: # lock? - self.addrBloom = BloomFilter(capacity=BMQueues.invInitialCapacity, - error_rate=BMQueues.invErrorRate) + self.addrBloom = BloomFilter(capacity=ObjectTracker.invInitialCapacity, + error_rate=ObjectTracker.invErrorRate) def clean(self): if self.lastcleaned < time.time() - BMQueues.invCleanPeriod: @@ -61,16 +64,17 @@ class BMQueues(object): else: return hashid in self.objectsNewToMe - def handleReceivedObj(self, hashid): + def handleReceivedInventory(self, hashId): if haveBloom: - self.invBloom.add(hashid) - elif hashid in Inventory(): + self.invBloom.add(hashId) + elif hashId in Inventory(): try: - del self.objectsNewToThem[hashid] + del self.objectsNewToThem[hashId] except KeyError: pass else: - self.objectsNewToMe[hashid] = True + self.objectsNewToMe[hashId] = True +# self.DownloadQueue.put(hashId) def hasAddr(self, addr): if haveBloom: @@ -82,6 +86,7 @@ class BMQueues(object): # 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 diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 6405238d..27a01902 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -1,11 +1,14 @@ import Queue 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 import protocol class ReceiveQueueThread(threading.Thread, StoppableThread): @@ -14,12 +17,17 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): self.initStop() self.name = "ReceiveQueueThread" BMConnectionPool() - logger.error("init asyncore thread") + logger.error("init receive queue thread") def run(self): + lastprinted = int(time.time()) while not self._stopped: + if lastprinted < int(time.time()): + lastprinted = int(time.time()) processed = 0 for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + if self._stopped: + break try: command, args = i.receiveQueue.get(False) except Queue.Empty: @@ -31,7 +39,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # missing command raise if processed == 0: - self.stop.wait(0.2) + self.stop.wait(2) def command_object(self, connection, objHash): try: @@ -40,5 +48,36 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): connection.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.' % (connection.destination,)) + def command_biginv(self, connection, dummy): + def sendChunk(): + if objectCount == 0: + return + logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount) + connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(objectCount) + payload)) + + # Select all hashes for objects in this stream. + bigInvList = {} + for stream in connection.streams: + for objHash in Inventory().unexpired_hashes_by_stream(stream): + bigInvList[objHash] = 0 + connection.objectsNewToThem[objHash] = True + 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: + self.sendChunk() + payload = b'' + objectCount = 0 + + # flush + sendChunk() + + def command_inv(self, connection, hashId): + connection.handleReceivedInventory(hashId) + def stopThread(self): super(ReceiveQueueThread, self).stopThread() diff --git a/src/network/tcp.py b/src/network/tcp.py new file mode 100644 index 00000000..ef54fc18 --- /dev/null +++ b/src/network/tcp.py @@ -0,0 +1,236 @@ +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 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.downloadqueue import DownloadQueue +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.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue +from network.tls import TLSDispatcher + +import addresses +from bmconfigparser import BMConfigParser +from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue +import shared +import state +import protocol + +class TCPConnection(BMProto, TLSDispatcher): + def __init__(self, address=None, sock=None): + AdvancedDispatcher.__init__(self, 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() + #print "received connection in background from %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) + #print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) + shared.connectedHostsList[self.destination] = 0 + ObjectTracker.__init__(self) + UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + + def state_init(self): + self.bm_proto_reset() + if self.isOutbound: + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + print "%s:%i: Sending version" % (self.destination.host, self.destination.port) + self.set_state("bm_header") + return True + + 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 + UploadQueue.queueCount/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 + if delay > 0: + if initial: + self.skipUntil = self.connectedAt + delay + if self.skipUntil > time.time(): + logger.debug("Skipping processing for %.2fs", self.skipUntil - time.time()) + else: + logger.debug("Skipping processing due to missing object for %.2fs", self.skipUntil - time.time()) + self.skipUntil = time.time() + delay + + def set_connection_fully_established(self): + UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + self.antiIntersectionDelay(True) + self.fullyEstablished = True + 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 > (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 > (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 > (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, timestamp in addrs[substream]: + templist.append((substream, peer, timestamp)) + if len(templist) >= BMProto.maxAddrCount: + self.writeQueue.put(BMProto.assembleAddr(templist)) + templist = [] + # flush + if len(templist) > 0: + self.writeQueue.put(BMProto.assembleAddr(templist)) + + def sendBigInv(self): + self.receiveQueue.put(("biginv", None)) + + def handle_connect_event(self): + try: + asyncore.dispatcher.handle_connect_event(self) + self.connectedAt = time.time() + except socket.error as e: + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def handle_read_event(self): + try: + asyncore.dispatcher.handle_read_event(self) + except socket.error as e: + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def handle_write_event(self): + try: + asyncore.dispatcher.handle_write_event(self) + except socket.error as e: + #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) + self.close() + + def close(self, reason=None): + self.set_state("close") +# if reason is None: +# print "%s:%i: closing" % (self.destination.host, self.destination.port) +# #traceback.print_stack() +# else: +# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) + network.connectionpool.BMConnectionPool().removeConnection(self) + asyncore.dispatcher.close(self) + + +class Socks5BMConnection(Socks5Connection, TCPConnection): + def __init__(self, address): + Socks5Connection.__init__(self, address=address) + + def state_socks_handshake_done(self): + TCPConnection.state_init(self) + return False + + +class Socks4aBMConnection(Socks4aConnection, TCPConnection): + def __init__(self, address): + Socks4aConnection.__init__(self, address=address) + + def state_socks_handshake_done(self): + TCPConnection.state_init(self) + return False + + +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() + self.bind((host, port)) + self.listen(5) + + def handle_accept(self): + pair = self.accept() + if pair is not None: + sock, addr = pair + 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 index d2abb6b9..f79f0650 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -60,7 +60,7 @@ class TLSDispatcher(AdvancedDispatcher): def writable(self): try: - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "tls writable, %r" % (self.want_write) return self.want_write else: @@ -70,7 +70,7 @@ class TLSDispatcher(AdvancedDispatcher): def readable(self): try: - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "tls readable, %r" % (self.want_read) return self.want_read else: @@ -81,7 +81,7 @@ class TLSDispatcher(AdvancedDispatcher): def handle_read(self): try: # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "handshaking (read)" self.state_tls_handshake() else: @@ -93,7 +93,7 @@ class TLSDispatcher(AdvancedDispatcher): def handle_write(self): try: # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0: + if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "handshaking (write)" self.state_tls_handshake() else: diff --git a/src/network/udp.py b/src/network/udp.py new file mode 100644 index 00000000..81bcc06a --- /dev/null +++ b/src/network/udp.py @@ -0,0 +1,198 @@ +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 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.downloadqueue import DownloadQueue +from network.node import Node +import network.asyncore_pollchoose as asyncore +from network.objectracker import ObjectTracker +from network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue + +import addresses +from bmconfigparser import BMConfigParser +from queues import objectProcessorQueue, peerDiscoveryQueue, portCheckerQueue, UISignalQueue +import shared +import state +import protocol + +class UDPSocket(BMProto): + port = 8444 + announceInterval = 60 + + def __init__(self, host=None, sock=None): + AdvancedDispatcher.__init__(self, sock) + self.verackReceived = True + self.verackSent = True + # TODO sort out streams + self.streams = [1] + self.fullyEstablished = True + self.connectedAt = 0 + self.skipUntil = 0 + self.isOutbound = False + 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) + print "binding to %s" % (host) + 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.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + self.destination = state.Peer(self.socket.getsockname()[0], self.socket.getsockname()[1]) + ObjectTracker.__init__(self) + self.connecting = False + self.connected = True + # packet was received from a local IP + self.local = False + self.set_state("bm_header") + + # 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 + remoteport = False + for i in addresses: + seenTime, stream, services, ip, port = i + decodedIP = protocol.checkIPAddress(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 + print "received peer discovery from %s:%i (port %i):" % (self.destination.host, self.destination.port, remoteport) + if self.local: + peerDiscoveryQueue.put(state.peer(self.destination.host, remoteport)) + 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_event(self): + return + + def writable(self): + return not self.writeQueue.empty() + + def readable(self): + return len(self.read_buf) < AdvancedDispatcher._buf_len + + def handle_read(self): + print "read!" + try: + (addr, recdata) = self.socket.recvfrom(AdvancedDispatcher._buf_len) + except socket.error as e: + print "socket error: %s" % (str(e)) + return + + self.destination = state.Peer(addr[0], addr[1]) + encodedAddr = socket.inet_pton(self.socket.family, 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 = data + self.process() + + def handle_write(self): +# print "handling write" + try: + data = self.writeQueue.get(False) + except Queue.Empty: + return + try: + retval = self.socket.sendto(data, ('', UDPSocket.port)) +# print "broadcasted %ib" % (retval) + except socket.error as e: + print "socket error on sendato: %s" % (e) + + def close(self, reason=None): + self.set_state("close") +# if reason is None: +# print "%s:%i: closing" % (self.destination.host, self.destination.port) +# #traceback.print_stack() +# else: +# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) + network.connectionpool.BMConnectionPool().removeConnection(self) + asyncore.dispatcher.close(self) + + +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/protocol.py b/src/protocol.py index 83ecb7bd..5661dff0 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -86,13 +86,15 @@ def networkType(host): else: return 'IPv6' -def checkIPAddress(host): +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) + 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) @@ -100,34 +102,34 @@ def checkIPAddress(host): # 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) + return checkIPv6Address(host, hostStandardFormat, private) -def checkIPv4Address(host, hostStandardFormat): +def checkIPv4Address(host, hostStandardFormat, private=False): if host[0] == '\x7F': # 127/8 logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) return False if host[0] == '\x0A': # 10/8 logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) - return False + return hostStandardFormat if private else False if host[0:2] == '\xC0\xA8': # 192.168/16 logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) - return False + return hostStandardFormat if private else 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 False if private else hostStandardFormat -def checkIPv6Address(host, hostStandardFormat): +def checkIPv6Address(host, hostStandardFormat, private=False): if host == ('\x00' * 15) + '\x01': logger.debug('Ignoring loopback address: ' + hostStandardFormat) return False if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: logger.debug ('Ignoring local address: ' + hostStandardFormat) - return False + return hostStandardFormat if private else False if (ord(host[0]) & 0xfe) == 0xfc: logger.debug ('Ignoring unique local address: ' + hostStandardFormat) - return False - return hostStandardFormat + return hostStandardFormat if private else False + return False if private else hostStandardFormat # checks diff --git a/src/queues.py b/src/queues.py index c6b09307..a11bedeb 100644 --- a/src/queues.py +++ b/src/queues.py @@ -7,5 +7,6 @@ addressGeneratorQueue = Queue.Queue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. objectProcessorQueue = ObjectProcessorQueue() portCheckerQueue = Queue.Queue() +peerDiscoveryQueue = Queue.Queue() apiAddressGeneratorReturnQueue = Queue.Queue( ) # The address generator thread uses this queue to get information back to the API thread. -- 2.45.1 From fa9ad537a576588f2f5f49e316dee417ed5c4dae Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 19:39:19 +0200 Subject: [PATCH 0756/1102] Add task_done to asyncore-related queues --- src/network/advanceddispatcher.py | 3 +++ src/network/connectionchooser.py | 7 +++++-- src/network/receivequeuethread.py | 2 ++ src/network/udp.py | 5 +++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 938eb11d..947824bd 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -80,6 +80,7 @@ class AdvancedDispatcher(asyncore.dispatcher): while len(self.write_buf) < bufSize: try: self.write_buf += self.writeQueue.get(False) + self.writeQueue.task_done() except Queue.Empty: break if len(self.write_buf) > 0: @@ -103,11 +104,13 @@ class AdvancedDispatcher(asyncore.dispatcher): while True: try: self.writeQueue.get(False) + self.writeQueue.task_done() except Queue.Empty: break while True: try: self.receiveQueue.get(False) + self.receiveQueue.task_done() except Queue.Empty: break asyncore.dispatcher.close(self) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 05ef47bd..1e26b994 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -11,9 +11,12 @@ def chooseConnection(stream): return state.trustedPeer else: try: - return portCheckerQueue.get(False) + retval = portCheckerQueue.get(False) + portCheckerQueue.task_done() except Queue.Empty: try: - return peerDiscoveryQueue.get(False) + retval = peerDiscoveryQueue.get(False) + peerDiscoveryQueue.task_done() except Queue.Empty: return random.choice(knownnodes.knownNodes[stream].keys()) + return retval diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 27a01902..c5509b65 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -35,7 +35,9 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): processed += 1 try: getattr(self, "command_" + str(command))(i, args) + i.receiveQueue.task_done() except AttributeError: + i.receiveQueue.task_done() # missing command raise if processed == 0: diff --git a/src/network/udp.py b/src/network/udp.py index 81bcc06a..4bb78823 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -137,7 +137,6 @@ class UDPSocket(BMProto): return len(self.read_buf) < AdvancedDispatcher._buf_len def handle_read(self): - print "read!" try: (addr, recdata) = self.socket.recvfrom(AdvancedDispatcher._buf_len) except socket.error as e: @@ -150,6 +149,7 @@ class UDPSocket(BMProto): self.local = True else: self.local = False + print "read %ib" % (len(recdata)) # overwrite the old buffer to avoid mixing data and so that self.local works correctly self.read_buf = data self.process() @@ -162,9 +162,10 @@ class UDPSocket(BMProto): return try: retval = self.socket.sendto(data, ('', UDPSocket.port)) -# print "broadcasted %ib" % (retval) + print "broadcasted %ib" % (retval) except socket.error as e: print "socket error on sendato: %s" % (e) + self.writeQueue.task_done() def close(self, reason=None): self.set_state("close") -- 2.45.1 From 99e714c43225825ccde731c038cb389f059e0c2a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 20:43:27 +0200 Subject: [PATCH 0757/1102] UDP socket bugfixes --- src/network/udp.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/network/udp.py b/src/network/udp.py index 4bb78823..42f8bd18 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -100,7 +100,7 @@ class UDPSocket(BMProto): decodedIP = protocol.checkIPAddress(ip) if stream not in state.streamsInWhichIAmParticipating: continue - if seenTime < time.time() - BMProto.maxtimeOffset or seenTime > time.time() + BMProto.maxTimeOffset: + 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 @@ -109,7 +109,7 @@ class UDPSocket(BMProto): return print "received peer discovery from %s:%i (port %i):" % (self.destination.host, self.destination.port, remoteport) if self.local: - peerDiscoveryQueue.put(state.peer(self.destination.host, remoteport)) + peerDiscoveryQueue.put(state.Peer(self.destination.host, remoteport)) return True def bm_command_portcheck(self): @@ -138,20 +138,21 @@ class UDPSocket(BMProto): def handle_read(self): try: - (addr, recdata) = self.socket.recvfrom(AdvancedDispatcher._buf_len) + (recdata, addr) = self.socket.recvfrom(AdvancedDispatcher._buf_len) except socket.error as e: print "socket error: %s" % (str(e)) return self.destination = state.Peer(addr[0], addr[1]) - encodedAddr = socket.inet_pton(self.socket.family, addr[0]) + encodedAddr = protocol.encodeHost(addr[0]) if protocol.checkIPAddress(encodedAddr, True): self.local = True else: self.local = False print "read %ib" % (len(recdata)) # overwrite the old buffer to avoid mixing data and so that self.local works correctly - self.read_buf = data + self.read_buf = recdata + self.bm_proto_reset() self.process() def handle_write(self): -- 2.45.1 From 21f6d38ec260ea1d8209da014977a9ba93e17916 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 21:52:56 +0200 Subject: [PATCH 0758/1102] Asyncore fixes - TCP fixes --- src/network/advanceddispatcher.py | 4 ++-- src/network/asyncore_pollchoose.py | 4 ++-- src/network/bmproto.py | 22 -------------------- src/network/tcp.py | 33 +++++++++--------------------- src/network/udp.py | 12 +---------- 5 files changed, 15 insertions(+), 60 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 947824bd..8c976b36 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -34,7 +34,7 @@ class AdvancedDispatcher(asyncore.dispatcher): return True def process(self): - if self.state not in ["init", "tls_handshake"] and len(self.read_buf) == 0: + if self.state != "tls_handshake" and len(self.read_buf) == 0: return if not self.connected: return @@ -54,7 +54,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.state = state def writable(self): - return self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty() + return self.connected and (len(self.write_buf) > 0 or not self.writeQueue.empty()) def readable(self): return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 08ee42d0..dda6d7c2 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,7 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, \ + ECONNREFUSED, EHOSTUNREACH, \ errorcode try: from errno import WSAEWOULDBLOCK @@ -66,7 +66,7 @@ except: from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF, ECONNREFUSED)) + EBADF, ECONNREFUSED, EHOSTUNREACH)) OP_READ = 1 OP_WRITE = 2 diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 6e1c3a18..c706b81a 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -469,28 +469,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): payload += struct.pack('>H', peer.port) # remote port return protocol.CreatePacket('addr', payload) - def handle_connect_event(self): - try: - asyncore.dispatcher.handle_connect_event(self) - self.connectedAt = time.time() - except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() - - def handle_read_event(self): - try: - asyncore.dispatcher.handle_read_event(self) - except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() - - def handle_write_event(self): - try: - asyncore.dispatcher.handle_write_event(self) - except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() - def close(self, reason=None): self.set_state("close") # if reason is None: diff --git a/src/network/tcp.py b/src/network/tcp.py index ef54fc18..8f7e60d7 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -63,14 +63,8 @@ class TCPConnection(BMProto, TLSDispatcher): shared.connectedHostsList[self.destination] = 0 ObjectTracker.__init__(self) UISignalQueue.put(('updateNetworkStatusTab', 'no data')) - - def state_init(self): self.bm_proto_reset() - if self.isOutbound: - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) - print "%s:%i: Sending version" % (self.destination.host, self.destination.port) self.set_state("bm_header") - return True def antiIntersectionDelay(self, initial = False): # estimated time for a small object to propagate across the whole network @@ -148,35 +142,28 @@ class TCPConnection(BMProto, TLSDispatcher): def handle_connect_event(self): try: asyncore.dispatcher.handle_connect_event(self) - self.connectedAt = time.time() except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() + if e.errno in asyncore._DISCONNECTED: + self.close("Connection failed") + return + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) + self.connectedAt = time.time() - def handle_read_event(self): + def handle_read(self): try: - asyncore.dispatcher.handle_read_event(self) + AdvancedDispatcher.handle_read(self) except socket.error as e: #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() - def handle_write_event(self): + def handle_write(self): try: - asyncore.dispatcher.handle_write_event(self) + AdvancedDispatcher.handle_write(self) except socket.error as e: #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() - def close(self, reason=None): - self.set_state("close") -# if reason is None: -# print "%s:%i: closing" % (self.destination.host, self.destination.port) -# #traceback.print_stack() -# else: -# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) - network.connectionpool.BMConnectionPool().removeConnection(self) - asyncore.dispatcher.close(self) - class Socks5BMConnection(Socks5Connection, TCPConnection): def __init__(self, address): diff --git a/src/network/udp.py b/src/network/udp.py index 42f8bd18..9e687603 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -127,7 +127,7 @@ class UDPSocket(BMProto): def bm_command_version(self): return True - def handle_connect_event(self): + def handle_connect(self): return def writable(self): @@ -168,16 +168,6 @@ class UDPSocket(BMProto): print "socket error on sendato: %s" % (e) self.writeQueue.task_done() - def close(self, reason=None): - self.set_state("close") -# if reason is None: -# print "%s:%i: closing" % (self.destination.host, self.destination.port) -# #traceback.print_stack() -# else: -# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) - network.connectionpool.BMConnectionPool().removeConnection(self) - asyncore.dispatcher.close(self) - if __name__ == "__main__": # initial fill -- 2.45.1 From 5d4e1e2007c7cb40abdd16ffd89a12873282ccfd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 27 May 2017 22:30:30 +0200 Subject: [PATCH 0759/1102] asyncore fixes - bm headers and commands are only read up to expected length. On a very fast connection (e.g. local VM), reading verack also read a part of the TLS handshake - some debugging info moved from print to logger.debug - tls handshake cleanup --- src/network/advanceddispatcher.py | 17 ++++++++++++----- src/network/bmproto.py | 17 +++++++++-------- src/network/tcp.py | 8 ++++---- src/network/tls.py | 12 ++++++------ 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 8c976b36..96b206cf 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -18,6 +18,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.lastTx = time.time() self.sentBytes = 0 self.receivedBytes = 0 + self.expectBytes = 0 def slice_write_buf(self, length=0): if length > 0: @@ -49,24 +50,30 @@ class AdvancedDispatcher(asyncore.dispatcher): raise maxLoop -= 1 - def set_state(self, state, length=0): + def set_state(self, state, length=0, expectBytes=0): + self.expectBytes = expectBytes self.slice_read_buf(length) self.state = state def writable(self): - return self.connected and (len(self.write_buf) > 0 or not self.writeQueue.empty()) + return self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty() def readable(self): return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len def handle_read(self): self.lastTx = time.time() + downloadBytes = AdvancedDispatcher._buf_len + if asyncore.maxDownloadRate > 0: + downloadBytes = asyncore.downloadChunk + if self.expectBytes > 0 and downloadBytes > self.expectBytes: + downloadBytes = self.expectBytes + newData = self.recv(downloadBytes) if asyncore.maxDownloadRate > 0: - newData = self.recv(asyncore.downloadChunk) asyncore.downloadBucket -= len(newData) - else: - newData = self.recv(AdvancedDispatcher._buf_len) self.receivedBytes += len(newData) + if self.expectBytes > 0: + self.expectBytes -= len(newData) asyncore.updateReceived(len(newData)) self.read_buf += newData self.process() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index c706b81a..d3f02568 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -91,6 +91,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.payload = None self.invalid = False self.payloadOffset = 0 + self.expectBytes = protocol.Header.size self.object = None def state_bm_header(self): @@ -109,7 +110,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return False if self.payloadLength > BMProto.maxMessageSize: self.invalid = True - self.set_state("bm_command", protocol.Header.size) + self.set_state("bm_command", protocol.Header.size, expectBytes=self.payloadLength) return True def state_bm_command(self): @@ -376,13 +377,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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()) - #print "remoteProtocolVersion: %i" % (self.remoteProtocolVersion) - #print "services: %08X" % (self.services) - #print "time offset: %i" % (self.timestamp - int(time.time())) - #print "my external IP: %s" % (self.sockNode.host) - #print "remote node incoming port: %i" % (self.peerNode.port) - #print "user agent: %s" % (self.userAgent) - #print "streams: [%s]" % (",".join(map(str,self.streams))) + logger.debug("remoteProtocolVersion: %i", self.remoteProtocolVersion) + logger.debug("services: %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 port: %i", 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 diff --git a/src/network/tcp.py b/src/network/tcp.py index 8f7e60d7..8c5fb968 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -48,7 +48,7 @@ class TCPConnection(BMProto, TLSDispatcher): self.isOutbound = False TLSDispatcher.__init__(self, sock, server_side=True) self.connectedAt = time.time() - #print "received connection in background from %s:%i" % (self.destination.host, self.destination.port) + logger.debug("Received connection from %s:%i", self.destination.host, self.destination.port) else: self.destination = address self.isOutbound = True @@ -59,7 +59,7 @@ class TCPConnection(BMProto, TLSDispatcher): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) TLSDispatcher.__init__(self, sock, server_side=False) self.connect(self.destination) - #print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) + logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port) shared.connectedHostsList[self.destination] = 0 ObjectTracker.__init__(self) UISignalQueue.put(('updateNetworkStatusTab', 'no data')) @@ -152,14 +152,14 @@ class TCPConnection(BMProto, TLSDispatcher): def handle_read(self): try: - AdvancedDispatcher.handle_read(self) + TLSDispatcher.handle_read(self) except socket.error as e: #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() def handle_write(self): try: - AdvancedDispatcher.handle_write(self) + TLSDispatcher.handle_write(self) except socket.error as e: #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) self.close() diff --git a/src/network/tls.py b/src/network/tls.py index f79f0650..f813e3be 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -54,7 +54,7 @@ class TLSDispatcher(AdvancedDispatcher): do_handshake_on_connect=False) self.sslSocket.setblocking(0) self.want_read = self.want_write = True - self.set_state("tls_handshake") + self.set_state("bm_header") # if hasattr(self.socket, "context"): # self.socket.context.set_ecdh_curve("secp256k1") @@ -83,7 +83,7 @@ class TLSDispatcher(AdvancedDispatcher): # wait for write buffer flush if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "handshaking (read)" - self.state_tls_handshake() + self.tls_handshake() else: #print "not handshaking (read)" return AdvancedDispatcher.handle_read(self) @@ -95,23 +95,23 @@ class TLSDispatcher(AdvancedDispatcher): # wait for write buffer flush if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): #print "handshaking (write)" - self.state_tls_handshake() + self.tls_handshake() else: #print "not handshaking (write)" return AdvancedDispatcher.handle_write(self) except AttributeError: return AdvancedDispatcher.handle_read(self) - def state_tls_handshake(self): + def tls_handshake(self): # wait for flush if len(self.write_buf) > 0: return False # Perform the handshake. try: - #print "handshaking (internal)" + print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError, err: - #print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) + 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" -- 2.45.1 From c85d52b8e8e8d6dfd9e67becab4cd53e8630b607 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 00:24:07 +0200 Subject: [PATCH 0760/1102] Asyncore updates - asyncore is now on by default - inv announcements implemented - bandwidth limit implemented / fixed - stats on download / upload speed now work - make prints into logger - limit knownNodes to 20k as it was before - green light fixed - other minor fixes --- src/api.py | 14 +++-- src/bitmessagemain.py | 4 ++ src/bitmessageqt/networkstatus.py | 2 +- src/bmconfigparser.py | 2 +- src/class_singleCleaner.py | 9 ++- src/class_singleWorker.py | 42 ++++++++++---- src/network/advanceddispatcher.py | 36 ++++++------ src/network/announcethread.py | 2 +- src/network/asyncore_pollchoose.py | 71 ++++++++++++----------- src/network/bmproto.py | 91 ++++++++++++------------------ src/network/connectionpool.py | 5 +- src/network/invthread.py | 82 +++++++++++++++++++++++++++ src/network/networkthread.py | 2 +- src/network/receivequeuethread.py | 2 +- src/network/stats.py | 49 +++++++++++++++- src/network/tcp.py | 12 +++- src/network/tls.py | 7 ++- src/network/udp.py | 12 ++-- src/protocol.py | 23 +++++--- src/queues.py | 1 + src/state.py | 2 + src/storage/filesystem.py | 4 +- 22 files changed, 316 insertions(+), 158 deletions(-) create mode 100644 src/network/invthread.py diff --git a/src/api.py b/src/api.py index 24c0fc12..f2334484 100644 --- a/src/api.py +++ b/src/api.py @@ -858,8 +858,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - protocol.broadcastToSendDataQueues(( - toStreamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((toStreamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + toStreamNumber, 'advertiseobject', inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): # This API method should only be used when msgid is not available @@ -905,8 +908,11 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - protocol.broadcastToSendDataQueues(( - pubkeyStreamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + pubkeyStreamNumber, 'advertiseobject', inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): # Method will eventually be used by a particular Android app to diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index d566852c..ca578c43 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -57,6 +57,7 @@ from network.connectionpool import BMConnectionPool from network.networkthread import BMNetworkThread from network.receivequeuethread import ReceiveQueueThread from network.announcethread import AnnounceThread +from network.invthread import InvThread #from network.downloadthread import DownloadThread # Helper Functions @@ -275,6 +276,9 @@ class Main: announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() + state.invThread = InvThread() + state.invThread.daemon = True + state.invThread.start() connectToStream(1) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 158f02fa..ef9e4c42 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -46,7 +46,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): return "%4.0f kB" % num def updateNumberOfObjectsToBeSynced(self): - self.labelSyncStatus.setText(_translate("networkstatus", "Object(s) to be synced: %n", None, QtCore.QCoreApplication.CodecForTr, PendingDownloadQueue.totalSize() + PendingUpload().len())) + 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() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 8c4d8b3c..b727ad65 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -16,7 +16,7 @@ BMConfigDefaults = { "maxuploadrate": 0, }, "network": { - "asyncore": False, + "asyncore": True, "bind": None, }, "inventory": { diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 6c0a62f6..22b83079 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -1,4 +1,5 @@ import threading +import resource import shared import time import sys @@ -9,6 +10,7 @@ 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 @@ -36,6 +38,7 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) class singleCleaner(threading.Thread, StoppableThread): + cycleLength = 300 def __init__(self): threading.Thread.__init__(self, name="singleCleaner") @@ -51,7 +54,7 @@ class singleCleaner(threading.Thread, StoppableThread): # initial wait if state.shutdown == 0: - self.stop.wait(300) + self.stop.wait(singleCleaner.cycleLength) while state.shutdown == 0: queues.UISignalQueue.put(( @@ -119,8 +122,10 @@ class singleCleaner(threading.Thread, StoppableThread): # TODO: cleanup pending upload / download + logger.info("Memory usage %s (kB)", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) + if state.shutdown == 0: - self.stop.wait(300) + self.stop.wait(singleCleaner.cycleLength) def resendPubkeyRequest(address): diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index c2d16de4..ff357b70 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -192,8 +192,11 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((streamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -283,8 +286,11 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((streamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -374,8 +380,11 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((streamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -504,8 +513,11 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, tag) PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((streamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) @@ -834,8 +846,11 @@ class singleWorker(threading.Thread, StoppableThread): # 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)) - protocol.broadcastToSendDataQueues(( - toStreamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((toStreamNumber, inventoryHash)) + else: + protocol.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): @@ -937,8 +952,11 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, '') PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + if BMConfigParser.safeGetBoolean("network", "asyncore"): + queues.invQueue.put((streamNumber, inventoryHash)) + else: + protocol.broadcastToSendDataQueues(( + streamNumber, 'advertiseobject', inventoryHash)) # wait 10% past expiration sleeptill = int(time.time() + TTL * 1.1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 96b206cf..5f8a94aa 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -2,6 +2,7 @@ import Queue import time import asyncore_pollchoose as asyncore +from debug import logger from bmconfigparser import BMConfigParser class AdvancedDispatcher(asyncore.dispatcher): @@ -56,44 +57,45 @@ class AdvancedDispatcher(asyncore.dispatcher): self.state = state def writable(self): - return self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty() + return asyncore.dispatcher.writable(self) and \ + (self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty()) def readable(self): - return self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len + return asyncore.dispatcher.readable(self) and \ + (self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len) def handle_read(self): self.lastTx = time.time() downloadBytes = AdvancedDispatcher._buf_len if asyncore.maxDownloadRate > 0: - downloadBytes = asyncore.downloadChunk + downloadBytes = asyncore.downloadBucket if self.expectBytes > 0 and downloadBytes > self.expectBytes: downloadBytes = self.expectBytes - newData = self.recv(downloadBytes) - if asyncore.maxDownloadRate > 0: - asyncore.downloadBucket -= len(newData) - self.receivedBytes += len(newData) - if self.expectBytes > 0: - self.expectBytes -= len(newData) - asyncore.updateReceived(len(newData)) - self.read_buf += newData + if downloadBytes > 0: + newData = self.recv(downloadBytes) + self.receivedBytes += len(newData) + if self.expectBytes > 0: + self.expectBytes -= len(newData) + asyncore.update_received(len(newData)) + self.read_buf += newData self.process() def handle_write(self): self.lastTx = time.time() + bufSize = AdvancedDispatcher._buf_len if asyncore.maxUploadRate > 0: - bufSize = asyncore.uploadChunk - else: - bufSize = self._buf_len + bufSize = asyncore.uploadBucket while len(self.write_buf) < bufSize: try: self.write_buf += self.writeQueue.get(False) self.writeQueue.task_done() except Queue.Empty: break + if bufSize <= 0: + return if len(self.write_buf) > 0: written = self.send(self.write_buf[0:bufSize]) - asyncore.uploadBucket -= written - asyncore.updateSent(written) + asyncore.update_sent(written) self.sentBytes += written self.slice_write_buf(written) @@ -107,7 +109,7 @@ class AdvancedDispatcher(asyncore.dispatcher): def close(self): self.read_buf = b"" self.write_buf = b"" - self.state = "shutdown" + self.state = "close" while True: try: self.writeQueue.get(False) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 0ba93d7a..29ed301e 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -17,7 +17,7 @@ class AnnounceThread(threading.Thread, StoppableThread): self.initStop() self.name = "AnnounceThread" BMConnectionPool() - logger.error("init announce thread") + logger.info("init announce thread") def run(self): lastSelfAnnounced = 0 diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index dda6d7c2..25a5b3fb 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -90,12 +90,10 @@ class ExitNow(Exception): _reraised_exceptions = (ExitNow, KeyboardInterrupt, SystemExit) maxDownloadRate = 0 -downloadChunk = 0 downloadTimestamp = 0 downloadBucket = 0 receivedBytes = 0 maxUploadRate = 0 -uploadChunk = 0 uploadTimestamp = 0 uploadBucket = 0 sentBytes = 0 @@ -117,48 +115,37 @@ def write(obj): obj.handle_error() def set_rates(download, upload): - global maxDownloadRate, maxUploadRate, downloadChunk, uploadChunk, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp + global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp maxDownloadRate = float(download) - if maxDownloadRate > 0: - downloadChunk = 1400 maxUploadRate = float(upload) - if maxUploadRate > 0: - uploadChunk = 1400 downloadBucket = maxDownloadRate uploadBucket = maxUploadRate downloadTimestamp = time.time() uploadTimestamp = time.time() -def updateReceived(download=0): - global receivedBytes +def update_received(download=0): + global receivedBytes, maxDownloadRate, downloadBucket, downloadTimestamp + currentTimestamp = time.time() receivedBytes += download + if maxDownloadRate > 0: + bucketIncrease = int(maxDownloadRate * (currentTimestamp - downloadTimestamp)) + downloadBucket += bucketIncrease + if downloadBucket > maxDownloadRate: + downloadBucket = int(maxDownloadRate) + downloadBucket -= download + downloadTimestamp = currentTimestamp -def updateSent(upload=0): - global sentBytes +def update_sent(upload=0): + global sentBytes, maxUploadRate, uploadBucket, uploadTimestamp + currentTimestamp = time.time() sentBytes += upload - -def wait_tx_buckets(): - global downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp - if maxDownloadRate > 0 and maxUploadRate > 0: - wait_for_this_long = min(maxDownloadRate / downloadChunk, maxUploadRate / uploadChunk) - elif maxDownloadRate > 0: - wait_for_this_long = maxDownloadRate / downloadChunk - elif maxUploadRate > 0: - wait_for_this_long = maxUploadRate / uploadChunk - else: - return - wait_for_this_long /= 2 - if wait_for_this_long > 1: - wait_for_this_long = 1 - elif wait_for_this_long < 0.1: - wait_for_this_long = 0.1 - - while downloadBucket < downloadChunk and uploadBucket < uploadChunk: - time.sleep(wait_for_this_long) - downloadBucket += (time.time() - downloadTimestamp) * maxDownloadRate - downloadTimestamp = time.time() - uploadBucket += (time.time() - uploadTimestamp) * maxUploadRate - uploadTimestamp = time.time() + if maxUploadRate > 0: + bucketIncrease = int(maxUploadRate * (currentTimestamp - uploadTimestamp)) + uploadBucket += bucketIncrease + if uploadBucket > maxUploadRate: + uploadBucket = int(maxUploadRate) + uploadBucket -= upload + uploadTimestamp = currentTimestamp def _exception(obj): try: @@ -376,13 +363,19 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, if count is None: while map: - wait_tx_buckets() + # fill buckets first + update_sent() + update_received() + # then poll poller(timeout, map) else: timeout /= count while map and count > 0: - wait_tx_buckets() + # fill buckets first + update_sent() + update_received() poller(timeout, map) + # then poll count = count - 1 class dispatcher: @@ -396,6 +389,8 @@ class dispatcher: ignore_log_types = frozenset(['warning']) poller_registered = False 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: @@ -499,9 +494,13 @@ class dispatcher: # ================================================== def readable(self): + if maxDownloadRate > 0: + return downloadBucket > dispatcher.minTx return True def writable(self): + if maxUploadRate > 0: + return uploadBucket > dispatcher.minTx return True # ================================================== diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d3f02568..a99bdfb2 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -3,7 +3,6 @@ from binascii import hexlify import hashlib import math import time -from pprint import pprint import socket import struct import random @@ -25,7 +24,7 @@ from network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUpl import addresses from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue +from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue, invQueue import shared import state import protocol @@ -53,35 +52,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # maximum time offset maxTimeOffset = 3600 -# def __init__(self, address=None, sock=None): -# AdvancedDispatcher.__init__(self, sock) -# self.verackReceived = False -# self.verackSent = False -# self.lastTx = time.time() -# 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() -# #print "received connection in background from %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) -# #print "connecting in background to %s:%i" % (self.destination.host, self.destination.port) -# shared.connectedHostsList[self.destination] = 0 -# ObjectTracker.__init__(self) -# UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + 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 @@ -95,7 +70,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object = None def state_bm_header(self): - #print "%s:%i: header" % (self.destination.host, self.destination.port) if len(self.read_buf) < protocol.Header.size: #print "Length below header size" return False @@ -105,7 +79,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # skip 1 byte in order to sync self.bm_proto_reset() self.set_state("bm_header", 1) - print "Bad magic" + logger.debug("Bad magic") self.close() return False if self.payloadLength > BMProto.maxMessageSize: @@ -117,10 +91,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): if len(self.read_buf) < self.payloadLength: #print "Length below announced object length" return False - print "%s:%i: command %s (%ib)" % (self.destination.host, self.destination.port, self.command, self.payloadLength) + #logger.debug("%s:%i: command %s (%ib)", self.destination.host, self.destination.port, self.command, self.payloadLength) self.payload = self.read_buf[:self.payloadLength] if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: - print "Bad checksum, ignoring" + logger.debug("Bad checksum, ignoring") self.invalid = True retval = True if not self.fullyEstablished and self.command not in ("version", "verack"): @@ -131,28 +105,28 @@ class BMProto(AdvancedDispatcher, ObjectTracker): retval = getattr(self, "bm_command_" + str(self.command).lower())() except AttributeError: # unimplemented command - print "unimplemented command %s" % (self.command) + logger.debug("unimplemented command %s", self.command) except BMProtoInsufficientDataError: - print "packet length too short, skipping" + logger.debug("packet length too short, skipping") except BMProtoExcessiveDataError: - print "too much data, skipping" + logger.debug("too much data, skipping") except BMObjectInsufficientPOWError: - print "insufficient PoW, skipping" + logger.debug("insufficient PoW, skipping") except BMObjectInvalidDataError: - print "object invalid data, skipping" + logger.debug("object invalid data, skipping") except BMObjectExpiredError: - print "object expired, skipping" + logger.debug("object expired, skipping") except BMObjectUnwantedStreamError: - print "object not in wanted stream, skipping" + logger.debug("object not in wanted stream, skipping") except BMObjectInvalidError: - print "object invalid, skipping" + logger.debug("object invalid, skipping") except BMObjectAlreadyHaveError: - print "already got object, skipping" + logger.debug("already got object, skipping") except struct.error: - print "decoding error, skipping" + logger.debug("decoding error, skipping") else: #print "Skipping command %s due to invalid data" % (self.command) - print "Closing due to invalid data" % (self.command) + logger.debug("Closing due to invalid command %s", self.command) self.close() return False if retval: @@ -253,13 +227,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.payloadOffset += 8 i += 1 if self.payloadOffset > self.payloadLength: - print "Insufficient data %i/%i" % (self.payloadOffset, self.payloadLength) + logger.debug("Insufficient data %i/%i", self.payloadOffset, self.payloadLength) raise BMProtoInsufficientDataError() return retval def bm_command_error(self): fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") - print "%s:%i error: %i, %s" % (self.destination.host, self.destination.port, fatalStatus, errorText) + logger.error("%s:%i error: %i, %s", self.destination.host, self.destination.port, fatalStatus, errorText) return True def bm_command_getdata(self): @@ -325,6 +299,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): objectProcessorQueue.put((self.object.objectType,self.object.data)) #DownloadQueue().task_done(self.object.inventoryHash) network.connectionpool.BMConnectionPool().handleReceivedObject(self, self.object.streamNumber, self.object.inventoryHash) + invQueue.put((self.object.streamNumber, self.object.inventoryHash)) #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) return True @@ -344,8 +319,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): peer = state.Peer(decodedIP, port) if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer] > seenTime: continue - knownnodes.knownNodes[stream][peer] = seenTime - AddrUploadQueue().put((stream, peer)) + if len(knownnodes.knownNodes[stream]) < 20000: + with knownnodes.knownNodesLock: + knownnodes.knownNodes[stream][peer] = seenTime + #knownnodes.knownNodes[stream][peer] = seenTime + #AddrUploadQueue().put((stream, peer)) return True def bm_command_portcheck(self): @@ -392,7 +370,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.verackSent = True if not self.isOutbound: self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, True)) - print "%s:%i: Sending version" % (self.destination.host, self.destination.port) + #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 @@ -472,10 +450,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def close(self, reason=None): self.set_state("close") -# if reason is None: -# print "%s:%i: closing" % (self.destination.host, self.destination.port) -# #traceback.print_stack() -# else: -# print "%s:%i: closing, %s" % (self.destination.host, self.destination.port, reason) + if reason is None: + #logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, ''.join(traceback.format_stack())) + logger.debug("%s:%i: closing", self.destination.host, self.destination.port) + #traceback.print_stack() + else: + logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) network.connectionpool.BMConnectionPool().removeConnection(self) AdvancedDispatcher.close(self) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index a75b62aa..d1a6b6ee 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -21,8 +21,8 @@ import state class BMConnectionPool(object): def __init__(self): asyncore.set_rates( - BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"), - BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate")) + BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate") * 1024, + BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate") * 1024) self.outboundConnections = {} self.inboundConnections = {} self.listeningSockets = {} @@ -117,7 +117,6 @@ class BMConnectionPool(object): if spawnConnections: if not self.bootstrapped: - print "bootstrapping dns" helper_bootstrap.dns() self.bootstrapped = True established = sum(1 for c in self.outboundConnections.values() if (c.connected and c.fullyEstablished)) diff --git a/src/network/invthread.py b/src/network/invthread.py new file mode 100644 index 00000000..75d53a20 --- /dev/null +++ b/src/network/invthread.py @@ -0,0 +1,82 @@ +import collections +import Queue +import random +import threading +import time + +import addresses +from bmconfigparser import BMConfigParser +from debug import logger +from helper_threading import StoppableThread +from network.bmproto import BMProto +from network.connectionpool import BMConnectionPool +from queues import invQueue +import protocol +import state + +class InvThread(threading.Thread, StoppableThread): + size = 10 + + def __init__(self): + threading.Thread.__init__(self, name="InvThread") + self.initStop() + self.name = "InvThread" + + self.shutdown = False + + self.collectionOfInvs = [] + for i in range(InvThread.size): + self.collectionOfInvs.append({}) + + def run(self): + iterator = 0 + while not state.shutdown: + while True: + try: + (stream, hash) = invQueue.get(False) + self.holdHash (stream, hash) + except Queue.Empty: + break + + if len(self.collectionOfInvs[iterator]) > 0: + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + hashes = [] + for stream in connection.streams: + try: + for hashId in self.collectionOfInvs[iterator][stream]: + if hashId in connection.objectsNewToThem: + hashes.append(hashId) + del connection.objectsNewToThem[hashId] + except KeyError: + continue + if len(hashes) > 0: + connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + b"".join(hashes))) + self.collectionOfInvs[iterator] = [] + iterator += 1 + iterator %= InvThread.size + self.stop.wait(1) + + def holdHash(self, stream, hash): + iter = random.randrange(0, InvThread.size) + try: + self.collectionOfInvs[iter][stream].append(hash) + except KeyError, IndexError: + self.collectionOfInvs[iter][stream] = [] + self.collectionOfInvs[iter][stream].append(hash) + + def hasHash(self, hash): + for streamlist in self.collectionOfInvs: + for stream in streamlist: + if hash in streamlist[stream]: + return True + return False + + def hashCount(self): + retval = 0 + for streamlist in self.collectionOfInvs: + for stream in streamlist: + retval += len(streamlist[stream]) + return retval + + def close(self): + self.shutdown = True diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 498bd340..bb6c0301 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -12,7 +12,7 @@ class BMNetworkThread(threading.Thread, StoppableThread): self.initStop() self.name = "AsyncoreThread" BMConnectionPool() - logger.error("init asyncore thread") + logger.info("init asyncore thread") def run(self): while not self._stopped: diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index c5509b65..a0a2c4b8 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -17,7 +17,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): self.initStop() self.name = "ReceiveQueueThread" BMConnectionPool() - logger.error("init receive queue thread") + logger.info("init receive queue thread") def run(self): lastprinted = int(time.time()) diff --git a/src/network/stats.py b/src/network/stats.py index 838ef23a..36baf2cb 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -1,9 +1,19 @@ +import time + from bmconfigparser import BMConfigParser from network.connectionpool import BMConnectionPool +from inventory import PendingDownloadQueue, PendingUpload import asyncore_pollchoose as asyncore import shared import throttle +lastReceivedTimestamp = time.time() +lastReceivedBytes = 0 +currentReceivedSpeed = 0 +lastSentTimestamp = time.time() +lastSentBytes = 0 +currentSentSpeed = 0 + def connectedHostsList(): if BMConfigParser().safeGetBoolean("network", "asyncore"): retval = [] @@ -25,8 +35,15 @@ def sentBytes(): return throttle.SendThrottle().total def uploadSpeed(): + global lastSentTimestamp, lastSentBytes, currentSentSpeed if BMConfigParser().safeGetBoolean("network", "asyncore"): - return 0 + currentTimestamp = time.time() + if int(lastSentTimestamp) < int(currentTimestamp): + currentSentBytes = asyncore.sentBytes + currentSentSpeed = int((currentSentBytes - lastSentBytes) / (currentTimestamp - lastSentTimestamp)) + lastSentBytes = currentSentBytes + lastSentTimestamp = currentTimestamp + return currentSentSpeed else: return throttle.sendThrottle().getSpeed() @@ -37,7 +54,35 @@ def receivedBytes(): return throttle.ReceiveThrottle().total def downloadSpeed(): + global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed if BMConfigParser().safeGetBoolean("network", "asyncore"): - return 0 + currentTimestamp = time.time() + if int(lastReceivedTimestamp) < int(currentTimestamp): + currentReceivedBytes = asyncore.receivedBytes + currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / (currentTimestamp - lastReceivedTimestamp)) + lastReceivedBytes = currentReceivedBytes + lastReceivedTimestamp = currentTimestamp + return currentReceivedSpeed else: return throttle.ReceiveThrottle().getSpeed() + +def pendingDownload(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + tmp = {} + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for k in connection.objectsNewToMe.keys(): + tmp[k] = True + return len(tmp) + else: + return PendingDownloadQueue.totalSize() + +def pendingUpload(): + if BMConfigParser().safeGetBoolean("network", "asyncore"): + return 0 + tmp = {} + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for k in connection.objectsNewToThem.keys(): + tmp[k] = True + return len(tmp) + else: + return PendingUpload().len() diff --git a/src/network/tcp.py b/src/network/tcp.py index 8c5fb968..42d5a831 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -36,7 +36,7 @@ import protocol class TCPConnection(BMProto, TLSDispatcher): def __init__(self, address=None, sock=None): - AdvancedDispatcher.__init__(self, sock) + BMProto.__init__(self, address=address, sock=sock) self.verackReceived = False self.verackSent = False self.streams = [0] @@ -60,7 +60,12 @@ class TCPConnection(BMProto, TLSDispatcher): TLSDispatcher.__init__(self, sock, server_side=False) self.connect(self.destination) logger.debug("Connecting to %s:%i", self.destination.host, self.destination.port) - shared.connectedHostsList[self.destination] = 0 + 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) UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.bm_proto_reset() @@ -83,6 +88,9 @@ class TCPConnection(BMProto, TLSDispatcher): self.skipUntil = time.time() + delay def set_connection_fully_established(self): + if not self.isOutbound and not self.local: + shared.clientHasReceivedIncomingConnections = True + UISignalQueue.put(('setStatusIcon', 'green')) UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.antiIntersectionDelay(True) self.fullyEstablished = True diff --git a/src/network/tls.py b/src/network/tls.py index f813e3be..115f3faa 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -7,6 +7,7 @@ import socket import ssl import sys +from debug import logger from network.advanceddispatcher import AdvancedDispatcher import network.asyncore_pollchoose as asyncore import paths @@ -108,10 +109,10 @@ class TLSDispatcher(AdvancedDispatcher): return False # Perform the handshake. try: - print "handshaking (internal)" + #print "handshaking (internal)" self.sslSocket.do_handshake() except ssl.SSLError, err: - print "%s:%i: handshake fail" % (self.destination.host, self.destination.port) + #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" @@ -122,7 +123,7 @@ class TLSDispatcher(AdvancedDispatcher): if not (self.want_write or self.want_read): raise else: - print "%s:%i: TLS handshake success%s" % (self.destination.host, self.destination.port, ", TLS protocol version: %s" % (self.sslSocket.version()) if sys.version_info >= (2, 7, 9) else "") + logger.debug("%s:%i: TLS handshake success%s", self.destination.host, self.destination.port, ", TLS protocol version: %s" % (self.sslSocket.version()) if sys.version_info >= (2, 7, 9) else "") # The handshake has completed, so remove this channel and... self.del_channel() self.set_socket(self.sslSocket) diff --git a/src/network/udp.py b/src/network/udp.py index 9e687603..29e434a2 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -35,7 +35,7 @@ class UDPSocket(BMProto): announceInterval = 60 def __init__(self, host=None, sock=None): - AdvancedDispatcher.__init__(self, sock) + BMProto.__init__(self, sock) self.verackReceived = True self.verackSent = True # TODO sort out streams @@ -43,7 +43,6 @@ class UDPSocket(BMProto): self.fullyEstablished = True self.connectedAt = 0 self.skipUntil = 0 - self.isOutbound = False if sock is None: if host is None: host = '' @@ -51,7 +50,7 @@ class UDPSocket(BMProto): self.create_socket(socket.AF_INET6, socket.SOCK_DGRAM) else: self.create_socket(socket.AF_INET, socket.SOCK_DGRAM) - print "binding to %s" % (host) + 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: @@ -67,10 +66,11 @@ class UDPSocket(BMProto): ObjectTracker.__init__(self) self.connecting = False self.connected = True - # packet was received from a local IP - self.local = False self.set_state("bm_header") + def state_bm_command(self): + BMProto.state_bm_command(self) + # disable most commands before doing research / testing # only addr (peer discovery), error and object are implemented @@ -163,7 +163,7 @@ class UDPSocket(BMProto): return try: retval = self.socket.sendto(data, ('', UDPSocket.port)) - print "broadcasted %ib" % (retval) + #print "broadcasted %ib" % (retval) except socket.error as e: print "socket error on sendato: %s" % (e) self.writeQueue.task_done() diff --git a/src/protocol.py b/src/protocol.py index 5661dff0..d7bd5b8c 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -106,28 +106,35 @@ def checkIPAddress(host, private=False): def checkIPv4Address(host, hostStandardFormat, private=False): if host[0] == '\x7F': # 127/8 - logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) + if not private: + logger.debug('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 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 - logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) + 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 - logger.debug('Ignoring IP address in private range:' + hostStandardFormat) - return False + 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': - logger.debug('Ignoring loopback address: ' + hostStandardFormat) + if not private: + logger.debug('Ignoring loopback address: ' + hostStandardFormat) return False if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: - logger.debug ('Ignoring local address: ' + hostStandardFormat) + if not private: + logger.debug ('Ignoring local address: ' + hostStandardFormat) return hostStandardFormat if private else False if (ord(host[0]) & 0xfe) == 0xfc: - logger.debug ('Ignoring unique local address: ' + hostStandardFormat) + if not private: + logger.debug ('Ignoring unique local address: ' + hostStandardFormat) return hostStandardFormat if private else False return False if private else hostStandardFormat diff --git a/src/queues.py b/src/queues.py index a11bedeb..7c36d54a 100644 --- a/src/queues.py +++ b/src/queues.py @@ -6,6 +6,7 @@ UISignalQueue = Queue.Queue() addressGeneratorQueue = Queue.Queue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. objectProcessorQueue = ObjectProcessorQueue() +invQueue = Queue.Queue() portCheckerQueue = Queue.Queue() peerDiscoveryQueue = Queue.Queue() apiAddressGeneratorReturnQueue = Queue.Queue( diff --git a/src/state.py b/src/state.py index 72852f3e..ff8a143d 100644 --- a/src/state.py +++ b/src/state.py @@ -23,6 +23,8 @@ sqlReady = False # set to true by sqlTread when ready for processing maximumNumberOfHalfOpenConnections = 0 +invThread = 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 diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index bb4d0e3f..4efe1132 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -111,8 +111,8 @@ class FilesystemInventory(InventoryStorage): 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)) +# for i, v in self._inventory.items(): +# print "loaded stream: %s, %i items" % (i, len(v)) def stream_list(self): return self._inventory.keys() -- 2.45.1 From 65bb6648e75f4c5f596e45ab870d9370504a2137 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 00:47:41 +0200 Subject: [PATCH 0761/1102] Asyncore updates - fix crash in inv thread - more prints changed into logger - minor fixes --- src/network/bmproto.py | 2 +- src/network/invthread.py | 12 +++++------- src/network/networkthread.py | 2 +- src/network/udp.py | 10 +++------- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index a99bdfb2..eb372aa7 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -97,7 +97,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): logger.debug("Bad checksum, ignoring") self.invalid = True retval = True - if not self.fullyEstablished and self.command not in ("version", "verack"): + 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: diff --git a/src/network/invthread.py b/src/network/invthread.py index 75d53a20..37fb7094 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -51,18 +51,16 @@ class InvThread(threading.Thread, StoppableThread): continue if len(hashes) > 0: connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + b"".join(hashes))) - self.collectionOfInvs[iterator] = [] + self.collectionOfInvs[iterator] = {} iterator += 1 iterator %= InvThread.size self.stop.wait(1) def holdHash(self, stream, hash): - iter = random.randrange(0, InvThread.size) - try: - self.collectionOfInvs[iter][stream].append(hash) - except KeyError, IndexError: - self.collectionOfInvs[iter][stream] = [] - self.collectionOfInvs[iter][stream].append(hash) + i = random.randrange(0, InvThread.size) + if stream not in self.collectionOfInvs[i]: + self.collectionOfInvs[i][stream] = [] + self.collectionOfInvs[i][stream].append(hash) def hasHash(self, hash): for streamlist in self.collectionOfInvs: diff --git a/src/network/networkthread.py b/src/network/networkthread.py index bb6c0301..54c58f12 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -19,7 +19,6 @@ class BMNetworkThread(threading.Thread, StoppableThread): BMConnectionPool().loop() def stopThread(self): - super(BMNetworkThread, self).stopThread() for i in BMConnectionPool().listeningSockets: try: i.close() @@ -38,3 +37,4 @@ class BMNetworkThread(threading.Thread, StoppableThread): # just in case asyncore.close_all() + super(BMNetworkThread, self).stopThread() diff --git a/src/network/udp.py b/src/network/udp.py index 29e434a2..5412083f 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -3,7 +3,6 @@ from binascii import hexlify import hashlib import math import time -from pprint import pprint import socket import struct import random @@ -107,7 +106,7 @@ class UDPSocket(BMProto): remoteport = port if remoteport is False: return - print "received peer discovery from %s:%i (port %i):" % (self.destination.host, self.destination.port, remoteport) + logger.debug("received peer discovery from %s:%i (port %i):", self.destination.host, self.destination.port, remoteport) if self.local: peerDiscoveryQueue.put(state.Peer(self.destination.host, remoteport)) return True @@ -140,7 +139,7 @@ class UDPSocket(BMProto): try: (recdata, addr) = self.socket.recvfrom(AdvancedDispatcher._buf_len) except socket.error as e: - print "socket error: %s" % (str(e)) + logger.error("socket error: %s", str(e)) return self.destination = state.Peer(addr[0], addr[1]) @@ -149,23 +148,20 @@ class UDPSocket(BMProto): self.local = True else: self.local = False - print "read %ib" % (len(recdata)) # overwrite the old buffer to avoid mixing data and so that self.local works correctly self.read_buf = recdata self.bm_proto_reset() self.process() def handle_write(self): -# print "handling write" try: data = self.writeQueue.get(False) except Queue.Empty: return try: retval = self.socket.sendto(data, ('', UDPSocket.port)) - #print "broadcasted %ib" % (retval) except socket.error as e: - print "socket error on sendato: %s" % (e) + logger.error("socket error on sendato: %s", str(e)) self.writeQueue.task_done() -- 2.45.1 From 73c41bff9df6fedd2a31542281920d23041f2e20 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 02:30:18 +0200 Subject: [PATCH 0762/1102] typo -BMConfigParser. instead of BMConfigParser(). --- src/api.py | 4 ++-- src/class_singleWorker.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api.py b/src/api.py index f2334484..ee371b38 100644 --- a/src/api.py +++ b/src/api.py @@ -858,7 +858,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((toStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -908,7 +908,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index ff357b70..acdf70ae 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -192,7 +192,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -286,7 +286,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -380,7 +380,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -513,7 +513,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, tag) PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -846,7 +846,7 @@ class singleWorker(threading.Thread, StoppableThread): # 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)) - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((toStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -952,7 +952,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, '') PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') - if BMConfigParser.safeGetBoolean("network", "asyncore"): + if BMConfigParser().safeGetBoolean("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( -- 2.45.1 From 02a07e5119b69d01744ee667935d760eb31af70f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 03:16:14 +0200 Subject: [PATCH 0763/1102] Asyncore update - default to true (original attempt didn't work correctly) --- src/api.py | 4 ++-- src/bitmessagemain.py | 6 +++--- src/class_singleWorker.py | 12 ++++++------ src/network/stats.py | 14 +++++++------- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/api.py b/src/api.py index ee371b38..212cd278 100644 --- a/src/api.py +++ b/src/api.py @@ -858,7 +858,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((toStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -908,7 +908,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index ca578c43..e6b8b56b 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -90,7 +90,7 @@ def connectToStream(streamNumber): if streamNumber*2+1 not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber*2+1] = {} - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): BMConnectionPool().connectToStream(streamNumber) else: for i in range(state.maximumNumberOfHalfOpenConnections): @@ -266,7 +266,7 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() @@ -282,7 +282,7 @@ class Main: connectToStream(1) - if not BMConfigParser().safeGetBoolean("network", "asyncore"): + if not BMConfigParser().get("network", "asyncore"): singleListenerThread = singleListener() singleListenerThread.setup(selfInitiatedConnections) singleListenerThread.daemon = True # close the main program even if there are threads left diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index acdf70ae..07c768a4 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -192,7 +192,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -286,7 +286,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -380,7 +380,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -513,7 +513,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, tag) PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -846,7 +846,7 @@ class singleWorker(threading.Thread, StoppableThread): # 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)) - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((toStreamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( @@ -952,7 +952,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, '') PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): queues.invQueue.put((streamNumber, inventoryHash)) else: protocol.broadcastToSendDataQueues(( diff --git a/src/network/stats.py b/src/network/stats.py index 36baf2cb..b348098c 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -15,7 +15,7 @@ lastSentBytes = 0 currentSentSpeed = 0 def connectedHostsList(): - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): retval = [] for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): if not i.connected: @@ -29,14 +29,14 @@ def connectedHostsList(): return shared.connectedHostsList.items() def sentBytes(): - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): return asyncore.sentBytes else: return throttle.SendThrottle().total def uploadSpeed(): global lastSentTimestamp, lastSentBytes, currentSentSpeed - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): currentTimestamp = time.time() if int(lastSentTimestamp) < int(currentTimestamp): currentSentBytes = asyncore.sentBytes @@ -48,14 +48,14 @@ def uploadSpeed(): return throttle.sendThrottle().getSpeed() def receivedBytes(): - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): return asyncore.receivedBytes else: return throttle.ReceiveThrottle().total def downloadSpeed(): global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): currentTimestamp = time.time() if int(lastReceivedTimestamp) < int(currentTimestamp): currentReceivedBytes = asyncore.receivedBytes @@ -67,7 +67,7 @@ def downloadSpeed(): return throttle.ReceiveThrottle().getSpeed() def pendingDownload(): - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): tmp = {} for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToMe.keys(): @@ -77,7 +77,7 @@ def pendingDownload(): return PendingDownloadQueue.totalSize() def pendingUpload(): - if BMConfigParser().safeGetBoolean("network", "asyncore"): + if BMConfigParser().get("network", "asyncore"): return 0 tmp = {} for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): -- 2.45.1 From e7525d47bedafe920a7f4f11c6f69e9af9ecc500 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 11:26:56 +0200 Subject: [PATCH 0764/1102] Disable memory usage logging - it looks like it's Unix specific and doesn't work on windows --- src/class_singleCleaner.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 22b83079..19c3ca52 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -1,5 +1,4 @@ import threading -import resource import shared import time import sys @@ -122,8 +121,6 @@ class singleCleaner(threading.Thread, StoppableThread): # TODO: cleanup pending upload / download - logger.info("Memory usage %s (kB)", resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) - if state.shutdown == 0: self.stop.wait(singleCleaner.cycleLength) -- 2.45.1 From 74f1a74a8c6ae0a0df18c2ea4b97c751bfb260e9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 11:30:56 +0200 Subject: [PATCH 0765/1102] Make SO_REUSEPORT optional - apparently not available on Windows --- src/network/udp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/udp.py b/src/network/udp.py index 5412083f..48a805d8 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -60,7 +60,10 @@ class UDPSocket(BMProto): self.socket = sock self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + try: + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + except AttributeError: + pass self.destination = state.Peer(self.socket.getsockname()[0], self.socket.getsockname()[1]) ObjectTracker.__init__(self) self.connecting = False -- 2.45.1 From a5c1b0c52955e95da90c38f5f0522f912065bf3c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 12:56:59 +0200 Subject: [PATCH 0766/1102] Asyncore fixes - better handling of WSA* checks on non-windows systems - handle EBADF on Windows/select - better timeouts / loop lengths in main asyncore loop and spawning new connections - remove InvThread prints --- src/bitmessagemain.py | 6 ------ src/network/asyncore_pollchoose.py | 30 ++++++++++++++++++------------ src/network/connectionpool.py | 10 +++++++++- src/network/invthread.py | 3 +++ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index e6b8b56b..57eab27a 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -102,12 +102,6 @@ def _fixSocket(): if sys.platform.startswith('linux'): socket.SO_BINDTODEVICE = 25 - if not sys.platform.startswith('win'): - errno.WSAEWOULDBLOCK = errno.EWOULDBLOCK - errno.WSAENETUNREACH = errno.ENETUNREACH - errno.WSAECONNREFUSED = errno.ECONNREFUSED - errno.WSAEHOSTUNREACH = errno.EHOSTUNREACH - if not sys.platform.startswith('win'): return diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 25a5b3fb..02a362a1 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -61,8 +61,9 @@ from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ errorcode try: from errno import WSAEWOULDBLOCK -except: - pass +except (ImportError, AttributeError): + WSAEWOULDBLOCK = EWOULDBLOCK + from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, @@ -199,6 +200,9 @@ def select_poller(timeout=0.0, map=None): r, w, e = select.select(r, w, e, timeout) except KeyboardInterrupt: return + except socket.error as err: + if err.args[0] in (EBADF): + return for fd in random.sample(r, len(r)): obj = map.get(fd) @@ -369,12 +373,18 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, # then poll poller(timeout, map) else: - timeout /= count + if timeout == 0: + deadline = 0 + else: + deadline = time.time() + timeout while map and count > 0: # fill buckets first update_sent() update_received() - poller(timeout, map) + subtimeout = deadline - time.time() + if subtimeout <= 0: + break + poller(subtimeout, map) # then poll count = count - 1 @@ -555,10 +565,8 @@ class dispatcher: else: raise except socket.error as why: - if why.args[0] in (EAGAIN, EWOULDBLOCK) or \ - (sys.platform.startswith('win') and \ - err.errno == WSAEWOULDBLOCK): - return 0 + if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): + return 0 elif why.args[0] in _DISCONNECTED: self.handle_close() return 0 @@ -582,10 +590,8 @@ class dispatcher: raise except socket.error as why: # winsock sometimes raises ENOTCONN - if why.args[0] in (EAGAIN, EWOULDBLOCK) or \ - (sys.platform.startswith('win') and \ - err.errno == WSAEWOULDBLOCK): - return b'' + if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): + return b'' if why.args[0] in _DISCONNECTED: self.handle_close() return b'' diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index d1a6b6ee..e9bc56c8 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -19,6 +19,7 @@ import state @Singleton class BMConnectionPool(object): + def __init__(self): asyncore.set_rates( BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate") * 1024, @@ -28,6 +29,8 @@ class BMConnectionPool(object): self.listeningSockets = {} self.udpSockets = {} self.streams = [] + self.lastSpawned = 0 + self.spawnWait = 0.3 self.bootstrapped = False @@ -146,6 +149,8 @@ class BMConnectionPool(object): if e.errno == errno.ENETUNREACH: continue + self.lastSpawned = time.time() + if acceptConnections and len(self.listeningSockets) == 0: self.startListening() logger.info('Listening for incoming connections.') @@ -169,7 +174,10 @@ class BMConnectionPool(object): # while len(asyncore.socket_map) > 0 and state.shutdown == 0: # print "loop, state = %s" % (proxy.state) - asyncore.loop(timeout=2.0, count=1) + loopTime = float(self.spawnWait) + if self.lastSpawned < time.time() - self.spawnWait: + loopTime = 1.0 + asyncore.loop(timeout=loopTime, count=10) for i in self.inboundConnections.values() + self.outboundConnections.values(): minTx = time.time() - 20 diff --git a/src/network/invthread.py b/src/network/invthread.py index 37fb7094..a880607a 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,3 +1,4 @@ +from binascii import hexlify import collections import Queue import random @@ -35,6 +36,7 @@ class InvThread(threading.Thread, StoppableThread): try: (stream, hash) = invQueue.get(False) self.holdHash (stream, hash) + #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: break @@ -50,6 +52,7 @@ class InvThread(threading.Thread, StoppableThread): except KeyError: continue if len(hashes) > 0: + #print "sending inv of %i" % (len(hashes)) connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + b"".join(hashes))) self.collectionOfInvs[iterator] = {} iterator += 1 -- 2.45.1 From 97c44b97f41a289399fecb1857658049bbf9a9e7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 13:14:25 +0200 Subject: [PATCH 0767/1102] Asyncore update - handle WSAENOTSOCK --- src/network/asyncore_pollchoose.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 02a362a1..39576849 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -63,6 +63,10 @@ try: from errno import WSAEWOULDBLOCK except (ImportError, AttributeError): WSAEWOULDBLOCK = EWOULDBLOCK +try: + from errno import WSAENOTSOCK +except (ImportError, AttributeError): + WSAENOTSOCK = ENOTSOCK from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE @@ -201,7 +205,7 @@ def select_poller(timeout=0.0, map=None): except KeyboardInterrupt: return except socket.error as err: - if err.args[0] in (EBADF): + if err.args[0] in (EBADF, WSAENOTSOCK): return for fd in random.sample(r, len(r)): -- 2.45.1 From bdaa939e2cd93d2dd4d781a04accd9687db04837 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 13:39:26 +0200 Subject: [PATCH 0768/1102] ENOTSOCK fix --- src/network/asyncore_pollchoose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 39576849..ae18e95e 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,7 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, \ + ECONNREFUSED, EHOSTUNREACH, ENOTSOCK, \ errorcode try: from errno import WSAEWOULDBLOCK -- 2.45.1 From 0aa5dbd95846a8a7a746f2726c082782435ad3db Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 14:35:08 +0200 Subject: [PATCH 0769/1102] Asyncore update - shutdown fix --- src/network/announcethread.py | 2 +- src/network/invthread.py | 2 +- src/network/networkthread.py | 5 +++-- src/network/receivequeuethread.py | 3 ++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 29ed301e..85e69877 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -21,7 +21,7 @@ class AnnounceThread(threading.Thread, StoppableThread): def run(self): lastSelfAnnounced = 0 - while not self._stopped: + while not self._stopped and state.shutdown == 0: processed = 0 if lastSelfAnnounced < time.time() - UDPSocket.announceInterval: self.announceSelf() diff --git a/src/network/invthread.py b/src/network/invthread.py index a880607a..1fd4a401 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -53,7 +53,7 @@ class InvThread(threading.Thread, StoppableThread): continue if len(hashes) > 0: #print "sending inv of %i" % (len(hashes)) - connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + b"".join(hashes))) + connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + "".join(hashes))) self.collectionOfInvs[iterator] = {} iterator += 1 iterator %= InvThread.size diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 54c58f12..7e98bcc0 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -5,6 +5,7 @@ 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): @@ -15,10 +16,11 @@ class BMNetworkThread(threading.Thread, StoppableThread): logger.info("init asyncore thread") def run(self): - while not self._stopped: + while not self._stopped and state.shutdown == 0: BMConnectionPool().loop() def stopThread(self): + super(BMNetworkThread, self).stopThread() for i in BMConnectionPool().listeningSockets: try: i.close() @@ -37,4 +39,3 @@ class BMNetworkThread(threading.Thread, StoppableThread): # just in case asyncore.close_all() - super(BMNetworkThread, self).stopThread() diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index a0a2c4b8..b31b82b4 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -10,6 +10,7 @@ from inventory import Inventory from network.connectionpool import BMConnectionPool from network.bmproto import BMProto import protocol +import state class ReceiveQueueThread(threading.Thread, StoppableThread): def __init__(self): @@ -21,7 +22,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): def run(self): lastprinted = int(time.time()) - while not self._stopped: + while not self._stopped and state.shutdown == 0: if lastprinted < int(time.time()): lastprinted = int(time.time()) processed = 0 -- 2.45.1 From 1ccfd41c3f9e9633852279b1367d9684816bfee9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 14:41:02 +0200 Subject: [PATCH 0770/1102] Asyncore updates - fix connected to myself check --- src/network/bmproto.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index eb372aa7..2ad1853d 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -428,6 +428,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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 -- 2.45.1 From 7f381c0c2580a30c8d5ab7e1f140a6d0e8f0c7ff Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 14:52:31 +0200 Subject: [PATCH 0771/1102] Asyncore update - incoming object handling fix --- src/network/bmproto.py | 3 +-- src/network/connectionpool.py | 2 +- src/network/invthread.py | 6 +++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 2ad1853d..87d24bba 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -298,8 +298,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) objectProcessorQueue.put((self.object.objectType,self.object.data)) #DownloadQueue().task_done(self.object.inventoryHash) - network.connectionpool.BMConnectionPool().handleReceivedObject(self, self.object.streamNumber, self.object.inventoryHash) - invQueue.put((self.object.streamNumber, self.object.inventoryHash)) + invQueue.put((self.object.streamNumber, self.object.inventoryHash, self)) #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) return True diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index e9bc56c8..1e2ed311 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -34,7 +34,7 @@ class BMConnectionPool(object): self.bootstrapped = False - def handleReceivedObject(self, connection, streamNumber, hashid): + def handleReceivedObject(self, streamNumber, hashid, connection = None): for i in self.inboundConnections.values() + self.outboundConnections.values(): if not isinstance(i, network.bmproto.BMProto): continue diff --git a/src/network/invthread.py b/src/network/invthread.py index 1fd4a401..2f0ab594 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -34,7 +34,11 @@ class InvThread(threading.Thread, StoppableThread): while not state.shutdown: while True: try: - (stream, hash) = invQueue.get(False) + data = invQueue.get(False) + if len(data) == 2: + BMConnectionPool().handleReceivedObject(self, data[0], data[1]) + else: + BMConnectionPool().handleReceivedObject(self, data[0], data[1], data[3]) self.holdHash (stream, hash) #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: -- 2.45.1 From 3a543efd83e56b120494a23a548118d37a01c486 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 14:54:13 +0200 Subject: [PATCH 0772/1102] Typo --- src/network/invthread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index 2f0ab594..1081adeb 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -38,7 +38,7 @@ class InvThread(threading.Thread, StoppableThread): if len(data) == 2: BMConnectionPool().handleReceivedObject(self, data[0], data[1]) else: - BMConnectionPool().handleReceivedObject(self, data[0], data[1], data[3]) + BMConnectionPool().handleReceivedObject(self, data[0], data[1], data[2]) self.holdHash (stream, hash) #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: -- 2.45.1 From 11d02b1e415f7876eb0fb0c83c79f15a7fb547ca Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 14:59:42 +0200 Subject: [PATCH 0773/1102] typo --- src/network/invthread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index 1081adeb..61401568 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -36,9 +36,9 @@ class InvThread(threading.Thread, StoppableThread): try: data = invQueue.get(False) if len(data) == 2: - BMConnectionPool().handleReceivedObject(self, data[0], data[1]) + BMConnectionPool().handleReceivedObject(data[0], data[1]) else: - BMConnectionPool().handleReceivedObject(self, data[0], data[1], data[2]) + BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) self.holdHash (stream, hash) #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: -- 2.45.1 From abaa2c72e558b106f1db19617274b485da610cc0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 May 2017 15:04:22 +0200 Subject: [PATCH 0774/1102] typo --- src/network/invthread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index 61401568..6d1828e1 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -39,7 +39,7 @@ class InvThread(threading.Thread, StoppableThread): BMConnectionPool().handleReceivedObject(data[0], data[1]) else: BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) - self.holdHash (stream, hash) + self.holdHash (data[0], data[1]) #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: break -- 2.45.1 From fa9811f4264a2b231744e946b3936e50edab1992 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 30 May 2017 23:53:43 +0200 Subject: [PATCH 0775/1102] Asyncore update - duplicate checking implemented - connection pool vs. socket closing cleanup --- src/network/bmobject.py | 5 +++++ src/network/bmproto.py | 38 ++++++++++++++++------------------- src/network/connectionpool.py | 17 +++++++++++----- src/network/tcp.py | 1 + 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 2c3fb59c..e16a6937 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -3,6 +3,7 @@ import time from addresses import calculateInventoryHash from debug import logger +from inventory import Inventory import protocol import state @@ -64,6 +65,10 @@ class BMObject(object): logger.debug('The streamNumber %s isn\'t one we are interested in.' % self.streamNumber) raise BMObjectUnwantedStreamError() + def checkAlreadyHave(self): + if self.inventoryHash in Inventory(): + raise BMObjectAlreadyHaveError() + def checkMessage(self): return diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 87d24bba..ffd79056 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -280,27 +280,24 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.checkProofOfWorkSufficient() self.object.checkEOLSanity() self.object.checkStream() + self.object.checkAlreadyHave() - try: - if self.object.objectType == protocol.OBJECT_GETPUBKEY: - self.object.checkGetpubkey() - elif self.object.objectType == protocol.OBJECT_PUBKEY: - self.object.checkPubkey(self.payload[self.payloadOffset:self.payloadOffset+32]) - elif self.object.objectType == protocol.OBJECT_MSG: - self.object.checkMessage() - elif self.object.objectType == protocol.OBJECT_BROADCAST: - self.object.checkBroadcast(self.payload[self.payloadOffset:self.payloadOffset+32]) - # other objects don't require other types of tests - except BMObjectAlreadyHaveError: - pass - else: - Inventory()[self.object.inventoryHash] = ( - self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) - objectProcessorQueue.put((self.object.objectType,self.object.data)) - #DownloadQueue().task_done(self.object.inventoryHash) - invQueue.put((self.object.streamNumber, self.object.inventoryHash, self)) - #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) - #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) + if self.object.objectType == protocol.OBJECT_GETPUBKEY: + self.object.checkGetpubkey() + elif self.object.objectType == protocol.OBJECT_PUBKEY: + self.object.checkPubkey(self.payload[self.payloadOffset:self.payloadOffset+32]) + elif self.object.objectType == protocol.OBJECT_MSG: + self.object.checkMessage() + elif self.object.objectType == protocol.OBJECT_BROADCAST: + self.object.checkBroadcast(self.payload[self.payloadOffset:self.payloadOffset+32]) + # other objects don't require other types of tests + Inventory()[self.object.inventoryHash] = ( + self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) + objectProcessorQueue.put((self.object.objectType,self.object.data)) + #DownloadQueue().task_done(self.object.inventoryHash) + invQueue.put((self.object.streamNumber, self.object.inventoryHash, self)) + #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) + #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) return True def _decode_addr(self): @@ -456,5 +453,4 @@ class BMProto(AdvancedDispatcher, ObjectTracker): #traceback.print_stack() else: logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) - network.connectionpool.BMConnectionPool().removeConnection(self) AdvancedDispatcher.close(self) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1e2ed311..ef2fb26b 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -64,7 +64,9 @@ class BMConnectionPool(object): def removeConnection(self, connection): if isinstance(connection, network.udp.UDPSocket): - return + del self.udpSockets[connection.destination.host] + if isinstance(connection, network.tcp.TCPServer): + del self.listeningSockets[state.Peer(connection.destination.host, connection.destination.port)] elif connection.isOutbound: try: del self.outboundConnections[connection.destination] @@ -99,9 +101,10 @@ class BMConnectionPool(object): def startUDPSocket(self, bind=None): if bind is None: host = self.getListeningIP() - self.udpSockets[host] = network.udp.UDPSocket(host=host) + udpSocket = network.udp.UDPSocket(host=host) else: - self.udpSockets[bind] = network.udp.UDPSocket(host=bind) + udpSocket = network.udp.UDPSocket(host=bind) + self.udpSockets[udpSocket.destination.host] = udpSocket def loop(self): # defaults to empty loop if outbound connections are maxed @@ -164,12 +167,10 @@ class BMConnectionPool(object): if len(self.listeningSockets) > 0 and not acceptConnections: for i in self.listeningSockets: i.close() - self.listeningSockets = {} logger.info('Stopped listening for incoming connections.') if len(self.udpSockets) > 0 and not acceptConnections: for i in self.udpSockets: i.close() - self.udpSockets = {} logger.info('Stopped udp sockets.') # while len(asyncore.socket_map) > 0 and state.shutdown == 0: @@ -179,6 +180,7 @@ class BMConnectionPool(object): loopTime = 1.0 asyncore.loop(timeout=loopTime, count=10) + reaper = [] for i in self.inboundConnections.values() + self.outboundConnections.values(): minTx = time.time() - 20 if i.fullyEstablished: @@ -188,3 +190,8 @@ class BMConnectionPool(object): i.writeQueue.put(protocol.CreatePacket('ping')) else: i.close("Timeout (%is)" % (time.time() - i.lastTx)) + 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) + for i in reaper: + self.removeConnection(i) diff --git a/src/network/tcp.py b/src/network/tcp.py index 42d5a831..2a2188ea 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -198,6 +198,7 @@ class TCPServer(AdvancedDispatcher): self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() self.bind((host, port)) + self.destination = state.Peer(host, port) self.listen(5) def handle_accept(self): -- 2.45.1 From f23c169eec7f71b4b217cfb842fb1224b0af398a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 00:04:21 +0200 Subject: [PATCH 0776/1102] Don't connect to myself - track local IP+port of incoming connections and don't connect to them in the future --- src/network/connectionpool.py | 3 +++ src/network/tcp.py | 1 + src/state.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index ef2fb26b..4afada16 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -134,6 +134,9 @@ class BMConnectionPool(object): continue if chosen.host in self.inboundConnections: continue + # don't connect to self + if chosen.host in state.ownAddresses: + continue #for c in self.outboundConnections: # if chosen == c.destination: diff --git a/src/network/tcp.py b/src/network/tcp.py index 2a2188ea..3ce4cc52 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -205,6 +205,7 @@ class TCPServer(AdvancedDispatcher): pair = self.accept() if pair is not None: sock, addr = pair + state.ownAddresses[state.Peer(sock.getsockname()[0], sock.getsockname()[1])] = True try: network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock)) except socket.error: diff --git a/src/state.py b/src/state.py index ff8a143d..618b6c92 100644 --- a/src/state.py +++ b/src/state.py @@ -25,6 +25,8 @@ maximumNumberOfHalfOpenConnections = 0 invThread = 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 -- 2.45.1 From d9e3349eeb861316d955c11acac41b201c9717f9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 00:22:07 +0200 Subject: [PATCH 0777/1102] Fix own IP detection - minor bug in the previous commit --- src/network/connectionpool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 4afada16..447e8170 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -135,7 +135,7 @@ class BMConnectionPool(object): if chosen.host in self.inboundConnections: continue # don't connect to self - if chosen.host in state.ownAddresses: + if chosen in state.ownAddresses: continue #for c in self.outboundConnections: -- 2.45.1 From e522f015a8351029733d09f5593e01bb164fcbb6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 10:15:47 +0200 Subject: [PATCH 0778/1102] Network status updates - only update processed numbers once every 2 seconds - moved inventory lookups to the main inventory so now all storage modules work with it --- src/bitmessageqt/networkstatus.py | 9 ++++++--- src/inventory.py | 3 +++ src/storage/sqlite.py | 1 - 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index ef9e4c42..ce30b4c7 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -49,17 +49,17 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): 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.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.updateNumberOfObjectsToBeSynced() self.labelBroadcastCount.setText(_translate( "networkstatus", "Processed %n broadcast message(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfBroadcastsProcessed)) def updateNumberOfPubkeysProcessed(self): - self.updateNumberOfObjectsToBeSynced() +# self.updateNumberOfObjectsToBeSynced() self.labelPubkeyCount.setText(_translate( "networkstatus", "Processed %n public key(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfPubkeysProcessed)) @@ -128,6 +128,9 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): Inventory().numberOfInventoryLookupsPerformed = 0 self.updateNumberOfBytes() self.updateNumberOfObjectsToBeSynced() + self.updateNumberOfMessagesProcessed() + self.updateNumberOfBroadcastsProcessed() + self.updateNumberOfPubkeysProcessed() def retranslateUi(self): super(QtGui.QWidget, self).retranslateUi() diff --git a/src/inventory.py b/src/inventory.py index b676415b..598021fb 100644 --- a/src/inventory.py +++ b/src/inventory.py @@ -23,10 +23,13 @@ class Inventory(): 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)) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 38e9c0a2..96733a36 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -15,7 +15,6 @@ class SqliteInventory(InventoryStorage): def __contains__(self, hash): with self.lock: - self.numberOfInventoryLookupsPerformed += 1 if hash in self._inventory: return True return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) -- 2.45.1 From 2555f692ebd9e969f270a9c39b9e73b2ae635402 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 10:16:30 +0200 Subject: [PATCH 0779/1102] Network status update part 2 - only update processed items every 2 seconds --- src/class_objectProcessor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 253e6808..d146dfd2 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -181,8 +181,8 @@ class objectProcessor(threading.Thread): def processpubkey(self, data): pubkeyProcessingStartTime = time.time() shared.numberOfPubkeysProcessed += 1 - queues.UISignalQueue.put(( - 'updateNumberOfPubkeysProcessed', 'no data')) +# queues.UISignalQueue.put(( +# 'updateNumberOfPubkeysProcessed', 'no data')) embeddedTime, = unpack('>Q', data[8:16]) readPosition = 20 # bypass the nonce, time, and object type addressVersion, varintLength = decodeVarint( @@ -330,8 +330,8 @@ class objectProcessor(threading.Thread): def processmsg(self, data): messageProcessingStartTime = time.time() shared.numberOfMessagesProcessed += 1 - queues.UISignalQueue.put(( - 'updateNumberOfMessagesProcessed', 'no data')) +# queues.UISignalQueue.put(( +# 'updateNumberOfMessagesProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9]) if msgVersion != 1: @@ -600,8 +600,8 @@ class objectProcessor(threading.Thread): def processbroadcast(self, data): messageProcessingStartTime = time.time() shared.numberOfBroadcastsProcessed += 1 - queues.UISignalQueue.put(( - 'updateNumberOfBroadcastsProcessed', 'no data')) +# queues.UISignalQueue.put(( +# 'updateNumberOfBroadcastsProcessed', 'no data')) inventoryHash = calculateInventoryHash(data) readPosition = 20 # bypass the nonce, time, and object type broadcastVersion, broadcastVersionLength = decodeVarint( -- 2.45.1 From 18988ae2e6c04e43d80f0cdade95fabebb12ad49 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 10:17:36 +0200 Subject: [PATCH 0780/1102] Asyncore updates - performance optimisation, reduce number of loops when waiting for protocol headers / commands --- src/network/bmproto.py | 6 +++--- src/network/tcp.py | 2 +- src/network/udp.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index ffd79056..f59be314 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -78,13 +78,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): if self.magic != 0xE9BEB4D9: # skip 1 byte in order to sync self.bm_proto_reset() - self.set_state("bm_header", 1) + self.set_state("bm_header", length=1, expectBytes=protocol.Header.size) logger.debug("Bad magic") self.close() return False if self.payloadLength > BMProto.maxMessageSize: self.invalid = True - self.set_state("bm_command", protocol.Header.size, expectBytes=self.payloadLength) + self.set_state("bm_command", length=protocol.Header.size, expectBytes=self.payloadLength) return True def state_bm_command(self): @@ -130,7 +130,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.close() return False if retval: - self.set_state("bm_header", self.payloadLength) + self.set_state("bm_header", length=self.payloadLength, expectBytes=protocol.Header.size) self.bm_proto_reset() # else assume the command requires a different state to follow return True diff --git a/src/network/tcp.py b/src/network/tcp.py index 3ce4cc52..f6d0c7ac 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -69,7 +69,7 @@ class TCPConnection(BMProto, TLSDispatcher): ObjectTracker.__init__(self) UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.bm_proto_reset() - self.set_state("bm_header") + 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 diff --git a/src/network/udp.py b/src/network/udp.py index 48a805d8..8c710997 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -68,7 +68,7 @@ class UDPSocket(BMProto): ObjectTracker.__init__(self) self.connecting = False self.connected = True - self.set_state("bm_header") + self.set_state("bm_header", expectBytes=protocol.Header.size) def state_bm_command(self): BMProto.state_bm_command(self) -- 2.45.1 From 4c17a1800648da0bcca5d1aca5302d361bc18e17 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 May 2017 23:34:06 +0200 Subject: [PATCH 0781/1102] Don't send invs to unestablished connections --- src/network/connectionpool.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 447e8170..517b3c98 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -38,6 +38,8 @@ class BMConnectionPool(object): for i in self.inboundConnections.values() + self.outboundConnections.values(): if not isinstance(i, network.bmproto.BMProto): continue + if not i.fullyEstablished: + continue try: del i.objectsNewToMe[hashid] except KeyError: -- 2.45.1 From d75d920a687ff3aa03cd1ccf51c1b23ec17b5b1c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 2 Jun 2017 07:09:35 +0200 Subject: [PATCH 0782/1102] Asyncore updates - clean object tracking dictionaries in the cleaner thread - clean up close / handle_close - add locking to tracking dictionaries --- src/class_singleCleaner.py | 4 ++++ src/network/advanceddispatcher.py | 2 +- src/network/bmproto.py | 8 ++++---- src/network/connectionpool.py | 16 +++++++++------- src/network/objectracker.py | 25 ++++++++++++++++++------- src/network/tcp.py | 10 ++++------ 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 19c3ca52..e6d98989 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -119,6 +119,10 @@ class singleCleaner(threading.Thread, StoppableThread): if thread.isAlive() and hasattr(thread, 'downloadQueue'): thread.downloadQueue.clear() + # inv/object tracking + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + connection.clean() + # TODO: cleanup pending upload / download if state.shutdown == 0: diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 5f8a94aa..89a7423d 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -106,7 +106,7 @@ class AdvancedDispatcher(asyncore.dispatcher): def state_close(self): pass - def close(self): + def handle_close(self): self.read_buf = b"" self.write_buf = b"" self.state = "close" diff --git a/src/network/bmproto.py b/src/network/bmproto.py index f59be314..8c727f00 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -80,7 +80,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.bm_proto_reset() self.set_state("bm_header", length=1, expectBytes=protocol.Header.size) logger.debug("Bad magic") - self.close() + self.handle_close("Bad magic") return False if self.payloadLength > BMProto.maxMessageSize: self.invalid = True @@ -127,7 +127,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): else: #print "Skipping command %s due to invalid data" % (self.command) logger.debug("Closing due to invalid command %s", self.command) - self.close() + self.handle_close("Invalid command %s" % (self.command)) return False if retval: self.set_state("bm_header", length=self.payloadLength, expectBytes=protocol.Header.size) @@ -445,7 +445,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): payload += struct.pack('>H', peer.port) # remote port return protocol.CreatePacket('addr', payload) - def close(self, reason=None): + def handle_close(self, reason=None): self.set_state("close") if reason is None: #logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, ''.join(traceback.format_stack())) @@ -453,4 +453,4 @@ class BMProto(AdvancedDispatcher, ObjectTracker): #traceback.print_stack() else: logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) - AdvancedDispatcher.close(self) + AdvancedDispatcher.handle_close(self) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 517b3c98..6aa6e49b 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -31,7 +31,6 @@ class BMConnectionPool(object): self.streams = [] self.lastSpawned = 0 self.spawnWait = 0.3 - self.bootstrapped = False def handleReceivedObject(self, streamNumber, hashid, connection = None): @@ -41,12 +40,15 @@ class BMConnectionPool(object): if not i.fullyEstablished: continue try: - del i.objectsNewToMe[hashid] + with i.objectsNewToMeLock: + del i.objectsNewToMe[hashid] except KeyError: - i.objectsNewToThem[hashid] = True + with i.objectsNewToThemLock: + i.objectsNewToThem[hashid] = True if i == connection: try: - del i.objectsNewToThem[hashid] + with i.objectsNewToThemLock: + del i.objectsNewToThem[hashid] except KeyError: pass @@ -171,11 +173,11 @@ class BMConnectionPool(object): logger.info('Starting UDP socket(s).') if len(self.listeningSockets) > 0 and not acceptConnections: for i in self.listeningSockets: - i.close() + i.handle_close() logger.info('Stopped listening for incoming connections.') if len(self.udpSockets) > 0 and not acceptConnections: for i in self.udpSockets: - i.close() + i.handle_close() logger.info('Stopped udp sockets.') # while len(asyncore.socket_map) > 0 and state.shutdown == 0: @@ -194,7 +196,7 @@ class BMConnectionPool(object): if i.fullyEstablished: i.writeQueue.put(protocol.CreatePacket('ping')) else: - i.close("Timeout (%is)" % (time.time() - i.lastTx)) + i.handle_close("Timeout (%is)" % (time.time() - i.lastTx)) 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) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 246916b9..d073d78a 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -1,5 +1,6 @@ from Queue import Queue import time +from threading import RLock from inventory import Inventory from network.downloadqueue import DownloadQueue @@ -29,11 +30,14 @@ class ObjectTracker(object): def __init__(self): self.objectsNewToMe = {} + self.objectsNewToMeLock = RLock() self.objectsNewToThem = {} + self.objectsNewToThemLock = RLock() self.downloadPending = 0 self.downloadQueue = Queue() self.initInvBloom() self.initAddrBloom() + self.lastCleaned = time.time() def initInvBloom(self): if haveBloom: @@ -48,15 +52,20 @@ class ObjectTracker(object): error_rate=ObjectTracker.invErrorRate) def clean(self): - if self.lastcleaned < time.time() - BMQueues.invCleanPeriod: + if self.lastCleaned < time.time() - ObjectTracker.invCleanPeriod: if haveBloom: if PendingDownloadQueue().size() == 0: self.initInvBloom() self.initAddrBloom() - else: - # release memory - self.objectsNewToMe = self.objectsNewToMe.copy() - self.objectsNewToThem = self.objectsNewToThem.copy() + else: + # release memory + with self.objectsNewToMeLock: + tmp = self.objectsNewToMe.copy() + self.objectsNewToMe = tmp + with self.objectsNewToThemLock: + tmp = self.objectsNewToThem.copy() + self.objectsNewToThem = tmp + self.lastCleaned = time.time() def hasObj(self, hashid): if haveBloom: @@ -69,11 +78,13 @@ class ObjectTracker(object): self.invBloom.add(hashId) elif hashId in Inventory(): try: - del self.objectsNewToThem[hashId] + with self.objectsNewToThemLock: + del self.objectsNewToThem[hashId] except KeyError: pass else: - self.objectsNewToMe[hashId] = True + with self.objectsNewToMeLock: + self.objectsNewToMe[hashId] = True # self.DownloadQueue.put(hashId) def hasAddr(self, addr): diff --git a/src/network/tcp.py b/src/network/tcp.py index f6d0c7ac..d3b2f862 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -149,10 +149,10 @@ class TCPConnection(BMProto, TLSDispatcher): def handle_connect_event(self): try: - asyncore.dispatcher.handle_connect_event(self) + AdvancedDispatcher.handle_connect_event(self) except socket.error as e: if e.errno in asyncore._DISCONNECTED: - self.close("Connection failed") + logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e))) return self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) @@ -162,15 +162,13 @@ class TCPConnection(BMProto, TLSDispatcher): try: TLSDispatcher.handle_read(self) except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() + logger.debug("%s:%i: Handle read fail: %s" % (self.destination.host, self.destination.port, str(e))) def handle_write(self): try: TLSDispatcher.handle_write(self) except socket.error as e: - #print "%s:%i: socket error: %s" % (self.destination.host, self.destination.port, str(e)) - self.close() + logger.debug("%s:%i: Handle write fail: %s" % (self.destination.host, self.destination.port, str(e))) class Socks5BMConnection(Socks5Connection, TCPConnection): -- 2.45.1 From 6044df5adf84b767e559b482ab90aead7eb1c4ab Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 2 Jun 2017 15:43:35 +0200 Subject: [PATCH 0783/1102] Optional storing of expired and off-stream objects - a new config file option, network/acceptmismatch, allows the inventory to store objects that expired or are from a stream we're not interested in. Having this on will prevent re-requesting objects that other nodes incorrectly advertise. It defaults to false --- src/bmconfigparser.py | 1 + src/network/bmproto.py | 16 ++++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index b727ad65..bfa7e396 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -21,6 +21,7 @@ BMConfigDefaults = { }, "inventory": { "storage": "sqlite", + "acceptmismatch": False, }, "zlib": { 'maxsize': 1048576 diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 8c727f00..722438f5 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -5,8 +5,6 @@ import math import time import socket import struct -import random -import traceback from addresses import calculateInventoryHash from debug import logger @@ -278,8 +276,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker): raise BMProtoExcessiveDataError() self.object.checkProofOfWorkSufficient() - self.object.checkEOLSanity() - self.object.checkStream() + try: + self.object.checkEOLSanity() + except BMObjectExpiredError: + if not BMConfigParser().get("inventory", "acceptmismatch"): + raise + try: + self.object.checkStream() + except BMObjectUnwantedStreamError: + if not BMConfigParser().get("inventory", "acceptmismatch"): + raise self.object.checkAlreadyHave() if self.object.objectType == protocol.OBJECT_GETPUBKEY: @@ -448,9 +454,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def handle_close(self, reason=None): self.set_state("close") if reason is None: - #logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, ''.join(traceback.format_stack())) logger.debug("%s:%i: closing", self.destination.host, self.destination.port) - #traceback.print_stack() else: logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) AdvancedDispatcher.handle_close(self) -- 2.45.1 From f78f1a718b952a79b6ce780c378e0dbf9151fad3 Mon Sep 17 00:00:00 2001 From: Scott Date: Fri, 2 Jun 2017 18:53:13 -0600 Subject: [PATCH 0784/1102] Change api.py --- src/api.py | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/api.py b/src/api.py index 212cd278..8c959832 100644 --- a/src/api.py +++ b/src/api.py @@ -13,8 +13,9 @@ if __name__ == "__main__": sys.exit(0) from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer +import base64 import json -from binascii import hexlify +from binascii import hexlify, unhexlify import shared import time @@ -139,7 +140,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): def _decode(self, text, decode_type): try: - return text.decode(decode_type) + if decode_type == 'hex': + return unhexlify(text) + elif decode_type == 'base64': + return base64.b64decode(text) except Exception as e: raise APIError(22, "Decode error - " + str(e) + ". Had trouble while decoding string: " + repr(text)) @@ -180,7 +184,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): chan = False label = BMConfigParser().get(addressInKeysFile, 'label') if method == 'listAddresses2': - label = label.encode('base64') + label = base64.b64encode(label) data += json.dumps({'label': label, 'address': addressInKeysFile, 'stream': streamNumber, 'enabled': BMConfigParser().getboolean(addressInKeysFile, 'enabled'), 'chan': chan}, indent=4, separators=(',', ': ')) data += ']}' @@ -201,7 +205,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): label = shared.fixPotentiallyInvalidUTF8Data(label) if len(data) > 20: data += ',' - data += json.dumps({'label':label.encode('base64'), 'address': address}, indent=4, separators=(',', ': ')) + data += json.dumps({'label':base64.b64encode(label), 'address': address}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -483,8 +487,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid': hexlify(msgid), 'toAddress': toAddress, 'fromAddress': fromAddress, 'subject': subject.encode( - 'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -521,7 +527,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -534,7 +540,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -561,7 +567,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -575,7 +581,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':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -592,7 +598,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -607,7 +613,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':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) + 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 += ']}' return data @@ -816,15 +822,12 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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) - if len(data) > 20: - data += ',' - data += json.dumps({'label':label.encode('base64'), 'address': address, 'enabled': enabled == 1}, indent=4, separators=(',',': ')) - data += ']}' - return data + data['subscriptions'].append({'label':base64.b64encode(label), 'address': address, 'enabled': enabled == 1}) + return json.dumps(data, indent=4, separators=(',',': ')) def HandleDisseminatePreEncryptedMsg(self, params): # The device issuing this command to PyBitmessage supplies a msg object that has @@ -965,7 +968,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address, = params status, addressVersion, streamNumber, ripe = decodeAddress(address) return json.dumps({'status':status, 'addressVersion':addressVersion, - 'streamNumber':streamNumber, 'ripe':ripe.encode('base64')}, indent=4, + 'streamNumber':streamNumber, 'ripe':base64.b64encode(ripe)}, indent=4, separators=(',', ': ')) def HandleHelloWorld(self, params): @@ -1059,3 +1062,5 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): except Exception as e: logger.exception(e) return "API Error 0021: Unexpected API Failure - %s" % str(e) + + -- 2.45.1 From a9c0000c17bdd2b46930c3cfe20032f7aaee8896 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 3 Jun 2017 16:29:21 +0200 Subject: [PATCH 0785/1102] Treat some invalid objects as received - update to 6044df5adf84b767e559b482ab90aead7eb1c4ab - objects that are expired or in wrong stream are not re-requested anymore, even if they aren't stored in the inventory - the previous option "acceptmismatch" now only affects whether such objects are stored in the inventory --- src/network/bmproto.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 722438f5..e85da3f2 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -278,12 +278,17 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.checkProofOfWorkSufficient() try: self.object.checkEOLSanity() - except BMObjectExpiredError: - if not BMConfigParser().get("inventory", "acceptmismatch"): - raise - try: self.object.checkStream() - except BMObjectUnwantedStreamError: + except (BMObjectExpiredError, BMObjectUnwantedStreamError): + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + try: + del connection.objectsNewtoThem[hashId] + except KeyError: + pass + try: + del connection.objectsNewToMe[hashId] + except KeyError: + pass if not BMConfigParser().get("inventory", "acceptmismatch"): raise self.object.checkAlreadyHave() -- 2.45.1 From e8d9a7f183e6ce409f6e28b6948a8ea28c90e6bf Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 3 Jun 2017 16:30:05 +0200 Subject: [PATCH 0786/1102] Asyncore connect handling - minor improvements in handling of connect events so that it's not processed twice --- src/network/advanceddispatcher.py | 8 ++++++++ src/network/asyncore_pollchoose.py | 4 ++-- src/network/tcp.py | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 89a7423d..dadb625b 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,3 +1,4 @@ +import socket import Queue import time @@ -99,6 +100,13 @@ class AdvancedDispatcher(asyncore.dispatcher): 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() self.process() diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index ae18e95e..8131b2b2 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,7 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, ENOTSOCK, \ + ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, \ errorcode try: from errno import WSAEWOULDBLOCK @@ -71,7 +71,7 @@ except (ImportError, AttributeError): from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF, ECONNREFUSED, EHOSTUNREACH)) + EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH)) OP_READ = 1 OP_WRITE = 2 diff --git a/src/network/tcp.py b/src/network/tcp.py index d3b2f862..986a4b63 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -147,9 +147,9 @@ class TCPConnection(BMProto, TLSDispatcher): def sendBigInv(self): self.receiveQueue.put(("biginv", None)) - def handle_connect_event(self): + def handle_connect(self): try: - AdvancedDispatcher.handle_connect_event(self) + 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))) -- 2.45.1 From 7bde4e9445c5fcb04b75fe162ab84047d7e5f2ff Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 4 Jun 2017 10:25:16 +0200 Subject: [PATCH 0787/1102] Missing module name in bmproto --- src/network/bmproto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index e85da3f2..97c354cd 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -280,7 +280,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.checkEOLSanity() self.object.checkStream() except (BMObjectExpiredError, BMObjectUnwantedStreamError): - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): try: del connection.objectsNewtoThem[hashId] except KeyError: -- 2.45.1 From 009a215224cdd3244fd0bdef0c06b28a424362da Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 9 Jun 2017 10:07:51 +0200 Subject: [PATCH 0788/1102] Fix api connected hosts lists --- src/api.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api.py b/src/api.py index 8c959832..eb2712af 100644 --- a/src/api.py +++ b/src/api.py @@ -31,6 +31,7 @@ import state from pyelliptic.openssl import OpenSSL import queues from struct import pack +import network.stats # Classes from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure @@ -959,7 +960,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: networkStatus = 'connectedAndReceivingIncomingConnections' - return json.dumps({'networkConnections':len(shared.connectedHostsList),'numberOfMessagesProcessed':shared.numberOfMessagesProcessed, 'numberOfBroadcastsProcessed':shared.numberOfBroadcastsProcessed, 'numberOfPubkeysProcessed':shared.numberOfPubkeysProcessed, 'networkStatus':networkStatus, 'softwareName':'PyBitmessage','softwareVersion':softwareVersion}, indent=4, separators=(',', ': ')) + 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=(',', ': ')) def HandleDecodeAddress(self, params): # Return a meaningful decoding of an address. -- 2.45.1 From ae97f7abd86e9dacb185a9dcc1e8ea96a1f8865a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:07:47 +0200 Subject: [PATCH 0789/1102] Typo --- src/bitmessagecurses/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 903b7e68..381d7c7a 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -927,7 +927,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 == "askreceived": + elif status == "ackreceived": t = l10n.formatTimestamp(lastactiontime, False) statstr = "Acknowledgment of the message received at "+t+"." elif status == "broadcastqueued": -- 2.45.1 From d34fdbb3f4b39975ebe6590d6474d6bb830121fb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:08:40 +0200 Subject: [PATCH 0790/1102] Fix network status in api --- src/api.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api.py b/src/api.py index eb2712af..52fb8e6e 100644 --- a/src/api.py +++ b/src/api.py @@ -954,9 +954,9 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): return data def HandleClientStatus(self, params): - if len(shared.connectedHostsList) == 0: + if len(network.stats.connectedHostsList()) == 0: networkStatus = 'notConnected' - elif len(shared.connectedHostsList) > 0 and not shared.clientHasReceivedIncomingConnections: + elif len(network.stats.connectedHostsList()) > 0 and not shared.clientHasReceivedIncomingConnections: networkStatus = 'connectedButHaveNotReceivedIncomingConnections' else: networkStatus = 'connectedAndReceivingIncomingConnections' -- 2.45.1 From f366447e9437497e6d1011df76acf81b33708e4f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:09:14 +0200 Subject: [PATCH 0791/1102] Fix identicon imports --- src/bitmessageqt/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index 73367586..369d05ef 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -58,8 +58,8 @@ def identiconize(address): 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) + 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 -- 2.45.1 From 7e8ee5132242e0dbb4cec77fe3846c116f3c0815 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:09:44 +0200 Subject: [PATCH 0792/1102] Fallback umsgpack import fix --- src/helper_msgcoding.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index a507685e..3e156754 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -3,7 +3,7 @@ try: import msgpack except ImportError: - import fallback.umsgpack as msgpack + import fallback.umsgpack.umsgpack as msgpack import string import zlib -- 2.45.1 From 7f06cb7c2772a2e6d762163d12ae558946b4ee4a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:10:59 +0200 Subject: [PATCH 0793/1102] Inventory flush fix in GUI - Fixes #1011 --- src/bitmessageqt/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 76f6e46d..9f4f0b04 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -77,7 +77,7 @@ from class_objectHashHolder import objectHashHolder from class_singleWorker import singleWorker from dialogs import AddAddressDialog from helper_generic import powQueueSize -from inventory import PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException +from inventory import Inventory, PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException import knownnodes import paths from proofofwork import getPowType @@ -2324,11 +2324,11 @@ class MyForm(settingsmixin.SMainWindow): # in the objectProcessorQueue to be processed if self.NewSubscriptionDialogInstance.ui.checkBoxDisplayMessagesAlreadyInInventory.isChecked(): status, addressVersion, streamNumber, ripe = decodeAddress(address) - shared.inventory.flush() + Inventory().flush() doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() tag = doubleHashOfAddressData[32:] - for value in shared.inventory.by_type_and_tag(3, tag): + for value in Inventory().by_type_and_tag(3, tag): queues.objectProcessorQueue.put((value.type, value.payload)) def click_pushButtonStatusIcon(self): @@ -4398,11 +4398,11 @@ class NewSubscriptionDialog(QtGui.QDialog): self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate("MainWindow", "Address is an old type. We cannot display its past broadcasts.")) else: - shared.inventory.flush() + Inventory().flush() doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() tag = doubleHashOfAddressData[32:] - count = len(shared.inventory.by_type_and_tag(3, tag)) + count = len(Inventory().by_type_and_tag(3, tag)) if count == 0: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate("MainWindow", "There are no recent broadcasts from this address to display.")) -- 2.45.1 From 8d41d5fcf603bd10e4db1c4cad7f3cc7e3b77b95 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:11:21 +0200 Subject: [PATCH 0794/1102] default known nodes update --- src/defaultKnownNodes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index 4557c2e9..5559f1a5 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -16,7 +16,7 @@ def createDefaultKnownNodes(appdata): stream1[state.Peer('75.167.159.54', 8444)] = int(time.time()) stream1[state.Peer('95.165.168.168', 8444)] = int(time.time()) stream1[state.Peer('85.180.139.241', 8444)] = int(time.time()) - stream1[state.Peer('158.222.211.81', 8080)] = int(time.time()) + stream1[state.Peer('158.222.217.190', 8080)] = int(time.time()) stream1[state.Peer('178.62.12.187', 8448)] = int(time.time()) stream1[state.Peer('24.188.198.204', 8111)] = int(time.time()) stream1[state.Peer('109.147.204.113', 1195)] = int(time.time()) -- 2.45.1 From 7deb7c3d4f76d8314a06d84f80e28abba02036ef Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:11:50 +0200 Subject: [PATCH 0795/1102] Typo --- src/highlevelcrypto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 5e7f549c..8729ec5c 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -44,7 +44,7 @@ def sign(msg,hexPrivkey): # SHA256. Eventually this will become the default return makeCryptor(hexPrivkey).sign(msg, digest_alg=OpenSSL.EVP_sha256) else: - raise ValueError("Unknown digest algorithm %s" % (digestAlgo)) + raise ValueError("Unknown digest algorithm %s" % (digestAlg)) # Verifies with hex public key def verify(msg,sig,hexPubkey): # As mentioned above, we must upgrade gracefully to use SHA256. So -- 2.45.1 From cba749088a297327175af68613ca1944275d2b8b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 10 Jun 2017 10:13:49 +0200 Subject: [PATCH 0796/1102] Asyncore updates - mainly work on proxy support, but it's still not fully working - minor bugfixes --- src/network/asyncore_pollchoose.py | 2 +- src/network/bmproto.py | 9 ++++++--- src/network/connectionpool.py | 3 +++ src/network/objectracker.py | 1 + src/network/proxy.py | 20 +++++++++++++++++++- src/network/socks4a.py | 2 +- src/network/socks5.py | 8 +++----- src/network/tcp.py | 28 ++++++++++++++++++---------- src/network/udp.py | 1 + 9 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 8131b2b2..c212effe 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,7 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, \ + ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, \ errorcode try: from errno import WSAEWOULDBLOCK diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 97c354cd..cd36726e 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -282,11 +282,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): except (BMObjectExpiredError, BMObjectUnwantedStreamError): for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): try: - del connection.objectsNewtoThem[hashId] + del connection.objectsNewtoThem[self.object.inventoryHash] except KeyError: pass try: - del connection.objectsNewToMe[hashId] + del connection.objectsNewToMe[self.object.inventoryHash] except KeyError: pass if not BMConfigParser().get("inventory", "acceptmismatch"): @@ -459,7 +459,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def handle_close(self, reason=None): self.set_state("close") if reason is None: - logger.debug("%s:%i: closing", self.destination.host, self.destination.port) + try: + logger.debug("%s:%i: closing", self.destination.host, self.destination.port) + except AttributeError: + logger.debug("Disconnected socket closing") else: logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) AdvancedDispatcher.handle_close(self) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 6aa6e49b..1517f4d7 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -7,6 +7,7 @@ import re from bmconfigparser import BMConfigParser from debug import logger import helper_bootstrap +from network.proxy import Proxy import network.bmproto import network.tcp import network.udp @@ -129,6 +130,8 @@ class BMConnectionPool(object): if not self.bootstrapped: helper_bootstrap.dns() self.bootstrapped = True + Proxy.proxy = (BMConfigParser().safeGet("bitmessagesettings", "sockshostname"), + BMConfigParser().safeGetInt("bitmessagesettings", "socksport")) 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"): diff --git a/src/network/objectracker.py b/src/network/objectracker.py index d073d78a..0c4a8d56 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -54,6 +54,7 @@ class ObjectTracker(object): def clean(self): if self.lastCleaned < time.time() - ObjectTracker.invCleanPeriod: if haveBloom: + # FIXME if PendingDownloadQueue().size() == 0: self.initInvBloom() self.initAddrBloom() diff --git a/src/network/proxy.py b/src/network/proxy.py index e3b5acee..3b7cc848 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -1,7 +1,10 @@ import socket +import state + from advanceddispatcher import AdvancedDispatcher import asyncore_pollchoose as asyncore +import network.connectionpool class ProxyError(Exception): pass class GeneralProxyError(ProxyError): pass @@ -32,10 +35,25 @@ class Proxy(AdvancedDispatcher): self.__class__._auth = authTuple def __init__(self, address): - if type(address) != tuple or (len(address) < 2) or (type(str(address[0])) != type('')) or (type(address[1]) != int): + if not isinstance(address, state.Peer): raise ValueError AdvancedDispatcher.__init__(self) self.destination = address + self.isOutbound = True self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.proxy) print "connecting in background to %s:%i" % (self.proxy[0], self.proxy[1]) + + 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 + + def state_proxy_handshake_done(self): + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + self.connectedAt = time.time() + return False + diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 4b6b64fa..08bd18cf 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -43,7 +43,7 @@ class Socks4a(Proxy): self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: self.__proxypeername = (self.destination[0], self.destport) - self.set_state("socks_handshake_done", 8) + self.set_state("proxy_handshake_done", 8) def proxy_sock_name(self): return socket.inet_ntoa(self.__proxysockname[0]) diff --git a/src/network/socks5.py b/src/network/socks5.py index 0d1717d4..6745308c 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -4,6 +4,7 @@ import struct from advanceddispatcher import AdvancedDispatcher import asyncore_pollchoose as asyncore from proxy import Proxy, ProxyError, GeneralProxyError +import network.connectionpool class Socks5AuthError(ProxyError): pass class Socks5Error(ProxyError): pass @@ -103,7 +104,7 @@ class Socks5(Proxy): def state_proxy_addr_2_2(self): if not self.read_buf_sufficient(self.address_length): return False - self.boundaddr = read_buf + self.boundaddr = self.read_buf self.set_state("proxy_port", self.address_length) def state_proxy_port(self): @@ -115,14 +116,11 @@ class Socks5(Proxy): self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: self.__proxypeername = (self.destination[0], self.destport) - self.set_state("socks_handshake_done", 2) + self.set_state("proxy_handshake_done", 2) def proxy_sock_name(self): return socket.inet_ntoa(self.__proxysockname[0]) - def state_socks_handshake_done(self): - return False - class Socks5Connection(Socks5): def __init__(self, address): diff --git a/src/network/tcp.py b/src/network/tcp.py index 986a4b63..badb6774 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -49,6 +49,10 @@ class TCPConnection(BMProto, TLSDispatcher): TLSDispatcher.__init__(self, sock, server_side=True) self.connectedAt = time.time() logger.debug("Received connection from %s:%i", self.destination.host, self.destination.port) + 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 @@ -159,33 +163,37 @@ class TCPConnection(BMProto, TLSDispatcher): self.connectedAt = time.time() def handle_read(self): - try: - TLSDispatcher.handle_read(self) - except socket.error as e: - logger.debug("%s:%i: Handle read fail: %s" % (self.destination.host, self.destination.port, str(e))) +# try: + TLSDispatcher.handle_read(self) +# except socket.error as e: +# logger.debug("%s:%i: Handle read fail: %s" % (self.destination.host, self.destination.port, str(e))) def handle_write(self): - try: - TLSDispatcher.handle_write(self) - except socket.error as e: - logger.debug("%s:%i: Handle write fail: %s" % (self.destination.host, self.destination.port, str(e))) +# try: + TLSDispatcher.handle_write(self) +# except socket.error as e: +# logger.debug("%s:%i: Handle write fail: %s" % (self.destination.host, self.destination.port, str(e))) 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_socks_handshake_done(self): - TCPConnection.state_init(self) + self.set_state("bm_header", expectBytes=protocol.Header.size) return False 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_socks_handshake_done(self): - TCPConnection.state_init(self) + self.set_state("bm_header", expectBytes=protocol.Header.size) return False diff --git a/src/network/udp.py b/src/network/udp.py index 8c710997..241bf9d7 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -3,6 +3,7 @@ from binascii import hexlify import hashlib import math import time +import Queue import socket import struct import random -- 2.45.1 From a3a55e53c4e4c4e1b3bf2125b781e01e76a0786b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 11 Jun 2017 14:11:39 +0200 Subject: [PATCH 0797/1102] UDP Socket dict address fix - fixes #1008 --- src/network/connectionpool.py | 4 ++-- src/network/udp.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1517f4d7..41fb97be 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -69,7 +69,7 @@ class BMConnectionPool(object): def removeConnection(self, connection): if isinstance(connection, network.udp.UDPSocket): - del self.udpSockets[connection.destination.host] + del self.udpSockets[connection.listening.host] if isinstance(connection, network.tcp.TCPServer): del self.listeningSockets[state.Peer(connection.destination.host, connection.destination.port)] elif connection.isOutbound: @@ -109,7 +109,7 @@ class BMConnectionPool(object): udpSocket = network.udp.UDPSocket(host=host) else: udpSocket = network.udp.UDPSocket(host=bind) - self.udpSockets[udpSocket.destination.host] = udpSocket + self.udpSockets[udpSocket.listening.host] = udpSocket def loop(self): # defaults to empty loop if outbound connections are maxed diff --git a/src/network/udp.py b/src/network/udp.py index 241bf9d7..9eccbf67 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -65,6 +65,7 @@ class UDPSocket(BMProto): self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) except AttributeError: pass + 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 -- 2.45.1 From b7f9e74eeaec252fa0d5acea20d5452c982dbe8a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 12 Jun 2017 12:52:24 +0300 Subject: [PATCH 0798/1102] setup.py: added new packages appeared after 36b5e2c --- setup.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.py b/setup.py index a04c51d4..8a51368d 100644 --- a/setup.py +++ b/setup.py @@ -242,6 +242,9 @@ if __name__ == "__main__": 'pybitmessage.network', 'pybitmessage.pyelliptic', 'pybitmessage.socks', + 'pybitmessage.storage', + 'pybitmessage.fallback', + 'pybitmessage.fallback.umsgpack', 'pybitmessage.plugins' ], package_data={'': [ -- 2.45.1 From 06fed6f9c27af40f9b078fbb5dd71399d37ed268 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 12 Jun 2017 12:58:16 +0300 Subject: [PATCH 0799/1102] setup.py: second exception in list can be treated as variable --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8a51368d..5330ae68 100644 --- a/setup.py +++ b/setup.py @@ -184,7 +184,7 @@ class InstallCmd(install): print "Press Return to continue" try: raw_input() - except EOFError, NameError: + except (EOFError, NameError): pass return install.run(self) -- 2.45.1 From 76fed7821179f8df279148ed35e49950c6442f3f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 12 Jun 2017 13:54:44 +0300 Subject: [PATCH 0800/1102] Made it possible to use installed umsgpack --- setup.py | 49 ++++++++++++++++++++++++++++------------- src/depends.py | 5 +++-- src/helper_msgcoding.py | 7 ++++-- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/setup.py b/setup.py index 5330ae68..0da5680a 100644 --- a/setup.py +++ b/setup.py @@ -52,7 +52,22 @@ packageName = { "openSUSE": "python-msgpack-python", "Fedora": "python2-msgpack", "Guix": "python2-msgpack", - "Gentoo": "dev-python/msgpack" + "Gentoo": "dev-python/msgpack", + "optional": True, + "description": "python-msgpack is recommended for messages coding" + }, + "umsgpack": { + "FreeBSD": "", + "OpenBSD": "", + "Fedora": "", + "openSUSE": "", + "Guix": "", + "Ubuntu 12": "", + "Debian": "python-u-msgpack", + "Ubuntu": "python-u-msgpack", + "Gentoo": "dev-python/u-msgpack", + "optional": True, + "description": "umsgpack can be used instead of msgpack" }, "pyopencl": { "FreeBSD": "py27-pyopencl", @@ -202,9 +217,25 @@ if __name__ == "__main__": ) installRequires = [] - # this will silently accept alternative providers of msgpack if they are already installed + 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 if "msgpack" in detectPrereqs(): installRequires.append("msgpack-python") + elif "umsgpack" in detectPrereqs(): + installRequires.append("umsgpack") + else: + packages += ['pybitmessage.fallback', 'pybitmessage.fallback.umsgpack'] try: dist = setup( @@ -234,19 +265,7 @@ if __name__ == "__main__": "Topic :: Software Development :: Libraries :: Python Modules", ], package_dir={'pybitmessage': 'src'}, - packages=[ - 'pybitmessage', - 'pybitmessage.bitmessageqt', - 'pybitmessage.bitmessagecurses', - 'pybitmessage.messagetypes', - 'pybitmessage.network', - 'pybitmessage.pyelliptic', - 'pybitmessage.socks', - 'pybitmessage.storage', - 'pybitmessage.fallback', - 'pybitmessage.fallback.umsgpack', - 'pybitmessage.plugins' - ], + packages=packages, package_data={'': [ 'bitmessageqt/*.ui', 'bitmsghash/*.cl', 'sslkeys/*.pem', 'translations/*.ts', 'translations/*.qm', diff --git a/src/depends.py b/src/depends.py index 49c5c7a8..d66663b1 100755 --- a/src/depends.py +++ b/src/depends.py @@ -204,7 +204,9 @@ def check_msgpack(): try: import msgpack except ImportError: - logger.error('The msgpack package is not available. PyBitmessage requires msgpack.') + 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'): @@ -224,7 +226,6 @@ def check_msgpack(): else: logger.error('If your package manager does not have this package, try running "pip install msgpack-python".') - return False return True def check_dependencies(verbose = False, optional = False): diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index 3e156754..aae35d27 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -3,12 +3,14 @@ try: import msgpack except ImportError: - import fallback.umsgpack.umsgpack as msgpack + try: + import umsgpack as msgpack + except ImportError: + import fallback.umsgpack.umsgpack as msgpack import string import zlib from bmconfigparser import BMConfigParser -import shared from debug import logger import messagetypes from tr import _translate @@ -18,6 +20,7 @@ BITMESSAGE_ENCODING_TRIVIAL = 1 BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 + class DecompressionSizeException(Exception): def __init__(self, size): self.size = size -- 2.45.1 From 0cc8589b27e1b91c0c8eb0356efe70d1f3ada575 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 21 Jun 2017 12:16:33 +0200 Subject: [PATCH 0801/1102] Asyncore updates - should prevent the same object being re-requested indefinitely - locking for object tracking - move SSL-specific error handling to TLSDispatcher - observe maximum connection limit when accepting a new connection - stack depth test (for debugging purposes) - separate download thread - connection pool init moved to main thread --- src/bitmessagemain.py | 6 +++- src/network/advanceddispatcher.py | 8 ++++- src/network/announcethread.py | 1 - src/network/asyncore_pollchoose.py | 21 +++++-------- src/network/bmproto.py | 21 ++++++------- src/network/downloadthread.py | 48 ++++++++++++++++++++++++++++++ src/network/invthread.py | 9 +++--- src/network/networkthread.py | 1 - src/network/objectracker.py | 17 +++++------ src/network/receivequeuethread.py | 15 +++++++--- src/network/tcp.py | 6 ++++ src/network/tls.py | 18 +++++++++++ 12 files changed, 125 insertions(+), 46 deletions(-) create mode 100644 src/network/downloadthread.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 57eab27a..d9578748 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -58,7 +58,7 @@ from network.networkthread import BMNetworkThread from network.receivequeuethread import ReceiveQueueThread from network.announcethread import AnnounceThread from network.invthread import InvThread -#from network.downloadthread import DownloadThread +from network.downloadthread import DownloadThread # Helper Functions import helper_bootstrap @@ -261,6 +261,7 @@ class Main: singleAPIThread.start() if BMConfigParser().get("network", "asyncore"): + BMConnectionPool() asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() @@ -273,6 +274,9 @@ class Main: state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() + downloadThread = DownloadThread() + downloadThread.daemon = True + downloadThread.start() connectToStream(1) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index dadb625b..80762aa5 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,5 +1,6 @@ -import socket import Queue +import socket +import sys import time import asyncore_pollchoose as asyncore @@ -42,6 +43,11 @@ class AdvancedDispatcher(asyncore.dispatcher): if not self.connected: return maxLoop = 20 + try: + sys._getframe(200) + logger.error("Stack depth warning") + except ValueError: + pass while maxLoop > 0: try: # print "Trying to handle state \"%s\"" % (self.state) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 85e69877..37b7e628 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -16,7 +16,6 @@ class AnnounceThread(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="AnnounceThread") self.initStop() self.name = "AnnounceThread" - BMConnectionPool() logger.info("init announce thread") def run(self): diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index c212effe..94cbfaf3 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -57,7 +57,7 @@ import warnings import os from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, EINVAL, \ ENOTCONN, ESHUTDOWN, EISCONN, EBADF, ECONNABORTED, EPIPE, EAGAIN, \ - ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, \ + ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ENOTSOCK, EINTR, ETIMEDOUT, \ errorcode try: from errno import WSAEWOULDBLOCK @@ -68,10 +68,8 @@ try: except (ImportError, AttributeError): WSAENOTSOCK = ENOTSOCK -from ssl import SSLError, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE - _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH)) + EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT)) OP_READ = 1 OP_WRITE = 2 @@ -563,11 +561,6 @@ class dispatcher: try: result = self.socket.send(data) return result - except SSLError as err: - if err.errno == SSL_ERROR_WANT_WRITE: - return 0 - else: - raise except socket.error as why: if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): return 0 @@ -587,11 +580,6 @@ class dispatcher: return b'' else: return data - except SSLError as err: - if err.errno == SSL_ERROR_WANT_READ: - return b'' - else: - raise except socket.error as why: # winsock sometimes raises ENOTCONN if why.args[0] in (EAGAIN, EWOULDBLOCK, WSAEWOULDBLOCK): @@ -616,6 +604,11 @@ class dispatcher: # cheap inheritance, used to pass all other attribute # references to the underlying socket object. def __getattr__(self, attr): + try: + sys._getframe(200) + logger.error("Stack depth warning") + except ValueError: + pass try: retattr = getattr(self.socket, attr) except AttributeError: diff --git a/src/network/bmproto.py b/src/network/bmproto.py index cd36726e..39464845 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -119,7 +119,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): except BMObjectInvalidError: logger.debug("object invalid, skipping") except BMObjectAlreadyHaveError: - logger.debug("already got object, skipping") + logger.debug("%s:%i already got object, skipping", self.destination.host, self.destination.port) except struct.error: logger.debug("decoding error, skipping") else: @@ -260,10 +260,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): for i in items: self.receiveQueue.put(("inv", i)) - self.handleReceivedInventory(i) - payload = addresses.encodeVarint(len(self.objectsNewToMe)) + ''.join(self.objectsNewToMe.keys()) - self.writeQueue.put(protocol.CreatePacket('getdata', payload)) return True def bm_command_object(self): @@ -279,19 +276,23 @@ class BMProto(AdvancedDispatcher, ObjectTracker): try: self.object.checkEOLSanity() self.object.checkStream() - except (BMObjectExpiredError, BMObjectUnwantedStreamError): + self.object.checkAlreadyHave() + except (BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectAlreadyHaveError) as e: for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): try: - del connection.objectsNewtoThem[self.object.inventoryHash] + with connection.objectsNewToThemLock: + del connection.objectsNewToThem[self.object.inventoryHash] except KeyError: pass try: - del connection.objectsNewToMe[self.object.inventoryHash] + with connection.objectsNewToMeLock: + del connection.objectsNewToMe[self.object.inventoryHash] except KeyError: pass - if not BMConfigParser().get("inventory", "acceptmismatch"): - raise - self.object.checkAlreadyHave() + if not BMConfigParser().get("inventory", "acceptmismatch") or \ + isinstance(e, BMObjectAlreadyHaveError) or \ + isinstance(e, BMObjectExpiredError): + raise e if self.object.objectType == protocol.OBJECT_GETPUBKEY: self.object.checkGetpubkey() diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py new file mode 100644 index 00000000..e8bd44a7 --- /dev/null +++ b/src/network/downloadthread.py @@ -0,0 +1,48 @@ +import Queue +import threading + +import addresses +#from bmconfigparser import BMConfigParser +from debug import logger +from helper_threading import StoppableThread +#from inventory import Inventory +from network.connectionpool import BMConnectionPool +import protocol + +class DownloadThread(threading.Thread, StoppableThread): + maxPending = 500 + requestChunk = 1000 + + def __init__(self): + threading.Thread.__init__(self, name="DownloadThread") + self.initStop() + self.name = "DownloadThread" + logger.info("init download thread") + + def run(self): + while not self._stopped: + requested = 0 + for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + # this may take a while, but it needs a consistency so I think it's better + with i.objectsNewToMeLock: + downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if not v))) + if downloadPending >= DownloadThread.maxPending: + continue + # keys with True values in the dict + request = list((k for k, v in i.objectsNewToMe.iteritems() if v)) + if len(request) == 0: + continue + if len(request) > DownloadThread.requestChunk - downloadPending: + request = request[:DownloadThread.requestChunk - downloadPending] + # mark them as pending + for k in request: + i.objectsNewToMe[k] = False + + payload = addresses.encodeVarint(len(request)) + ''.join(request) + i.writeQueue.put(protocol.CreatePacket('getdata', payload)) + logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) + requested += len(request) + self.stop.wait(1) + + def stopThread(self): + super(DownloadThread, self).stopThread() diff --git a/src/network/invthread.py b/src/network/invthread.py index 6d1828e1..63107a1f 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -40,7 +40,6 @@ class InvThread(threading.Thread, StoppableThread): else: BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) self.holdHash (data[0], data[1]) - #print "Holding hash %i, %s" % (stream, hexlify(hash)) except Queue.Empty: break @@ -50,13 +49,15 @@ class InvThread(threading.Thread, StoppableThread): for stream in connection.streams: try: for hashId in self.collectionOfInvs[iterator][stream]: - if hashId in connection.objectsNewToThem: + try: + with connection.objectsNewToThemLock: + del connection.objectsNewToThem[hashId] hashes.append(hashId) - del connection.objectsNewToThem[hashId] + except KeyError: + pass except KeyError: continue if len(hashes) > 0: - #print "sending inv of %i" % (len(hashes)) connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + "".join(hashes))) self.collectionOfInvs[iterator] = {} iterator += 1 diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 7e98bcc0..a4a23103 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -12,7 +12,6 @@ class BMNetworkThread(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="AsyncoreThread") self.initStop() self.name = "AsyncoreThread" - BMConnectionPool() logger.info("init asyncore thread") def run(self): diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 0c4a8d56..5c0ad147 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -2,6 +2,7 @@ from Queue import Queue import time from threading import RLock +from debug import logger from inventory import Inventory from network.downloadqueue import DownloadQueue from network.uploadqueue import UploadQueue @@ -33,8 +34,6 @@ class ObjectTracker(object): self.objectsNewToMeLock = RLock() self.objectsNewToThem = {} self.objectsNewToThemLock = RLock() - self.downloadPending = 0 - self.downloadQueue = Queue() self.initInvBloom() self.initAddrBloom() self.lastCleaned = time.time() @@ -77,16 +76,14 @@ class ObjectTracker(object): def handleReceivedInventory(self, hashId): if haveBloom: self.invBloom.add(hashId) - elif hashId in Inventory(): - try: - with self.objectsNewToThemLock: - del self.objectsNewToThem[hashId] - except KeyError: - pass - else: + try: + with self.objectsNewToThemLock: + del self.objectsNewToThem[hashId] + except KeyError: + pass + if hashId not in Inventory(): with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True -# self.DownloadQueue.put(hashId) def hasAddr(self, addr): if haveBloom: diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index b31b82b4..6662a078 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -1,4 +1,5 @@ import Queue +import sys import threading import time @@ -17,7 +18,6 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="ReceiveQueueThread") self.initStop() self.name = "ReceiveQueueThread" - BMConnectionPool() logger.info("init receive queue thread") def run(self): @@ -25,6 +25,11 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): while not self._stopped and state.shutdown == 0: if lastprinted < int(time.time()): lastprinted = int(time.time()) + try: + sys._getframe(200) + logger.error("Stack depth warning") + except ValueError: + pass processed = 0 for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): if self._stopped: @@ -61,9 +66,11 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # Select all hashes for objects in this stream. bigInvList = {} for stream in connection.streams: - for objHash in Inventory().unexpired_hashes_by_stream(stream): - bigInvList[objHash] = 0 - connection.objectsNewToThem[objHash] = True + # may lock for a long time, but I think it's better than thousands of small locks + with connection.objectsNewToThemLock: + for objHash in Inventory().unexpired_hashes_by_stream(stream): + bigInvList[objHash] = 0 + connection.objectsNewToThem[objHash] = True objectCount = 0 payload = b'' # Now let us start appending all of these hashes together. They will be diff --git a/src/network/tcp.py b/src/network/tcp.py index badb6774..8a6b5705 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -212,6 +212,12 @@ class TCPServer(AdvancedDispatcher): 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"): + close(sock) + return try: network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock)) except socket.error: diff --git a/src/network/tls.py b/src/network/tls.py index 115f3faa..9694b4b9 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -13,6 +13,8 @@ import network.asyncore_pollchoose as asyncore 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): @@ -90,6 +92,14 @@ class TLSDispatcher(AdvancedDispatcher): 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 + else: + raise def handle_write(self): try: @@ -102,6 +112,14 @@ class TLSDispatcher(AdvancedDispatcher): return AdvancedDispatcher.handle_write(self) except AttributeError: return AdvancedDispatcher.handle_read(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 + else: + raise def tls_handshake(self): # wait for flush -- 2.45.1 From 618f3865c1e456a422ae37e653bfe0f95a51c320 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 21 Jun 2017 12:16:56 +0200 Subject: [PATCH 0802/1102] Main thread end - instead of sleeping, it just ends --- src/bitmessagemain.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index d9578748..40ccdee3 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -309,9 +309,6 @@ class Main: else: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') - while True: - time.sleep(20) - def daemonize(self): if os.fork(): exit(0) -- 2.45.1 From 243025a1aa6aff8d3dde4a4abb7f201249f2d38a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 21 Jun 2017 12:17:40 +0200 Subject: [PATCH 0803/1102] Leave __delitem__ unimplemented in filesystem storage - rename the cleaning method --- src/storage/filesystem.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storage/filesystem.py b/src/storage/filesystem.py index 4efe1132..d64894a9 100644 --- a/src/storage/filesystem.py +++ b/src/storage/filesystem.py @@ -65,7 +65,7 @@ class FilesystemInventory(InventoryStorage): self._inventory[value.stream] = {} self._inventory[value.stream][hash] = value - def __delitem__(self, hash): + def delHashId(self, hash): for stream in self._inventory.keys(): try: del self._inventory[stream][hash] @@ -172,4 +172,4 @@ class FilesystemInventory(InventoryStorage): if item.expires < minTime: deletes.append(hashId) for hashId in deletes: - del self[hashId] + self.delHashId(hashId) -- 2.45.1 From 2685fe29b19bbf6d5a75a0d640d2baef173f18f6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:13:35 +0200 Subject: [PATCH 0804/1102] Code quality improvements --- src/bitmessagemain.py | 1 - src/bitmessageqt/safehtmlparser.py | 6 +++--- src/bmconfigparser.py | 13 ++++++------- src/network/advanceddispatcher.py | 8 +++----- src/network/announcethread.py | 5 ----- src/network/asyncore_pollchoose.py | 5 ----- src/network/bmobject.py | 6 +++--- src/network/bmproto.py | 26 +++++++++++--------------- src/network/connectionchooser.py | 17 ++++++++--------- src/network/connectionpool.py | 1 - src/network/downloadthread.py | 6 +----- src/network/invthread.py | 16 ++++++++-------- src/network/stats.py | 23 ++++++++--------------- src/network/tls.py | 18 ++++++++---------- src/network/udp.py | 25 ++++--------------------- src/storage/sqlite.py | 2 +- src/storage/storage.py | 2 +- 17 files changed, 65 insertions(+), 115 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 40ccdee3..a2d951ed 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -27,7 +27,6 @@ import socket import ctypes from struct import pack from subprocess import call -import time from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index a78991d3..88431855 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -53,20 +53,20 @@ class SafeHTMLParser(HTMLParser): self.allow_external_src = False def add_if_acceptable(self, tag, attrs = None): - if not tag in SafeHTMLParser.acceptable_elements: + if tag not in SafeHTMLParser.acceptable_elements: return self.sanitised += "<" if inspect.stack()[1][3] == "handle_endtag": self.sanitised += "/" self.sanitised += tag - if not attrs is None: + 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 == "" + val = "" self.sanitised += " " + quote_plus(attr) if not (val is None): self.sanitised += "=\"" + val + "\"" diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index bfa7e396..0db58103 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -36,14 +36,13 @@ class BMConfigParser(ConfigParser.SafeConfigParser): raise TypeError("option values must be strings") return ConfigParser.ConfigParser.set(self, section, option, value) - def get(self, section, option, raw=False, vars=None): + def get(self, section, option, raw=False, variables=None): try: if section == "bitmessagesettings" and option == "timeformat": - return ConfigParser.ConfigParser.get(self, section, option, raw, vars) - else: - return ConfigParser.ConfigParser.get(self, section, option, True, vars) + 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, vars) + return ConfigParser.ConfigParser.get(self, section, option, True, variables) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: try: return BMConfigDefaults[section][option] @@ -68,8 +67,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): except (ConfigParser.NoSectionError, ConfigParser.NoOptionError, ValueError, AttributeError): return default - def items(self, section, raw=False, vars=None): - return ConfigParser.ConfigParser.items(self, section, True, vars) + 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()) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 80762aa5..61dd197b 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -5,7 +5,6 @@ import time import asyncore_pollchoose as asyncore from debug import logger -from bmconfigparser import BMConfigParser class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 2097152 # 2MB @@ -34,11 +33,10 @@ class AdvancedDispatcher(asyncore.dispatcher): def read_buf_sufficient(self, length=0): if len(self.read_buf) < length: return False - else: - return True + return True def process(self): - if self.state != "tls_handshake" and len(self.read_buf) == 0: + if self.state != "tls_handshake" and not self.read_buf: return if not self.connected: return @@ -100,7 +98,7 @@ class AdvancedDispatcher(asyncore.dispatcher): break if bufSize <= 0: return - if len(self.write_buf) > 0: + if self.write_buf: written = self.send(self.write_buf[0:bufSize]) asyncore.update_sent(written) self.sentBytes += written diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 37b7e628..3adcae48 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -1,4 +1,3 @@ -import Queue import threading import time @@ -8,7 +7,6 @@ from helper_threading import StoppableThread from network.bmproto import BMProto from network.connectionpool import BMConnectionPool from network.udp import UDPSocket -import protocol import state class AnnounceThread(threading.Thread, StoppableThread): @@ -33,6 +31,3 @@ class AnnounceThread(threading.Thread, StoppableThread): for stream in state.streamsInWhichIAmParticipating: addr = (stream, state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), time.time()) connection.writeQueue.put(BMProto.assembleAddr([addr])) - - def stopThread(self): - super(AnnounceThread, self).stopThread() diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 94cbfaf3..3f188812 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -604,11 +604,6 @@ class dispatcher: # cheap inheritance, used to pass all other attribute # references to the underlying socket object. def __getattr__(self, attr): - try: - sys._getframe(200) - logger.error("Stack depth warning") - except ValueError: - pass try: retattr = getattr(self.socket, attr) except AttributeError: diff --git a/src/network/bmobject.py b/src/network/bmobject.py index e16a6937..318cbfd1 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -51,18 +51,18 @@ class BMObject(object): 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 %s' % self.expiresTime) + 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 %s' % self.expiresTime) + 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 %s isn\'t one we are interested in.' % self.streamNumber) + logger.debug('The streamNumber %i isn\'t one we are interested in.', self.streamNumber) raise BMObjectUnwantedStreamError() def checkAlreadyHave(self): diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 39464845..32bf038c 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -15,14 +15,12 @@ from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInv import network.connectionpool from network.downloadqueue import DownloadQueue from network.node import Node -import network.asyncore_pollchoose as asyncore from network.objectracker import ObjectTracker from network.proxy import Proxy, ProxyError, GeneralProxyError -from network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue import addresses from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue, invQueue +from queues import objectProcessorQueue, portCheckerQueue, invQueue import shared import state import protocol @@ -173,7 +171,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): retval = [] size = None - insideDigit = False i = 0 while i < len(pattern): @@ -353,14 +350,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.set_state("tls_init", self.payloadLength) self.bm_proto_reset() return False - else: - self.set_connection_fully_established() - return True + self.set_connection_fully_established() + return True return True def bm_command_version(self): - #self.remoteProtocolVersion, self.services, self.timestamp, padding1, self.myExternalIP, padding2, self.remoteNodeIncomingPort = protocol.VersionPacket.unpack(self.payload[:protocol.VersionPacket.size]) - self.remoteProtocolVersion, self.services, self.timestamp, self.sockNode, self.peerNode, self.nonce, self.userAgent, self.streams = self.decode_payload_content("IQQiiQlslv") + 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) @@ -377,7 +373,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.writeQueue.put(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, True)) + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + network.connectionpool.BMConnectionPool().streams, True)) #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)): @@ -387,9 +384,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.set_state("tls_init", self.payloadLength) self.bm_proto_reset() return False - else: - self.set_connection_fully_established() - return True + self.set_connection_fully_established() + return True return True def peerValidityChecks(self): @@ -415,7 +411,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return False else: shared.timeOffsetWrongCount = 0 - if len(self.streams) == 0: + if not self.streams: self.writeQueue.put(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.', @@ -442,7 +438,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): @staticmethod def assembleAddr(peerList): - if type(peerList) is state.Peer: + if isinstance(peerList, state.Peer): peerList = (peerList) # TODO handle max length, now it's done by upper layers payload = addresses.encodeVarint(len(peerList)) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 1e26b994..0770bfa6 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -9,14 +9,13 @@ import state def chooseConnection(stream): if state.trustedPeer: return state.trustedPeer - else: + try: + retval = portCheckerQueue.get(False) + portCheckerQueue.task_done() + except Queue.Empty: try: - retval = portCheckerQueue.get(False) - portCheckerQueue.task_done() + retval = peerDiscoveryQueue.get(False) + peerDiscoveryQueue.task_done() except Queue.Empty: - try: - retval = peerDiscoveryQueue.get(False) - peerDiscoveryQueue.task_done() - except Queue.Empty: - return random.choice(knownnodes.knownNodes[stream].keys()) - return retval + return random.choice(knownnodes.knownNodes[stream].keys()) + return retval diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 41fb97be..67778b46 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -15,7 +15,6 @@ from network.connectionchooser import chooseConnection import network.asyncore_pollchoose as asyncore import protocol from singleton import Singleton -import shared import state @Singleton diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index e8bd44a7..a8d3e1f7 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,4 +1,3 @@ -import Queue import threading import addresses @@ -30,7 +29,7 @@ class DownloadThread(threading.Thread, StoppableThread): continue # keys with True values in the dict request = list((k for k, v in i.objectsNewToMe.iteritems() if v)) - if len(request) == 0: + if not request: continue if len(request) > DownloadThread.requestChunk - downloadPending: request = request[:DownloadThread.requestChunk - downloadPending] @@ -43,6 +42,3 @@ class DownloadThread(threading.Thread, StoppableThread): logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) requested += len(request) self.stop.wait(1) - - def stopThread(self): - super(DownloadThread, self).stopThread() diff --git a/src/network/invthread.py b/src/network/invthread.py index 63107a1f..9d05aec4 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -36,14 +36,14 @@ class InvThread(threading.Thread, StoppableThread): try: data = invQueue.get(False) if len(data) == 2: - BMConnectionPool().handleReceivedObject(data[0], data[1]) + BMConnectionPool().handleReceivedObject(data[0], data[1]) else: - BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) + BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) self.holdHash (data[0], data[1]) except Queue.Empty: break - if len(self.collectionOfInvs[iterator]) > 0: + if self.collectionOfInvs[iterator]: for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): hashes = [] for stream in connection.streams: @@ -57,23 +57,23 @@ class InvThread(threading.Thread, StoppableThread): pass except KeyError: continue - if len(hashes) > 0: + if hashes: connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + "".join(hashes))) self.collectionOfInvs[iterator] = {} iterator += 1 iterator %= InvThread.size self.stop.wait(1) - def holdHash(self, stream, hash): + def holdHash(self, stream, hashId): i = random.randrange(0, InvThread.size) if stream not in self.collectionOfInvs[i]: self.collectionOfInvs[i][stream] = [] - self.collectionOfInvs[i][stream].append(hash) + self.collectionOfInvs[i][stream].append(hashId) - def hasHash(self, hash): + def hasHash(self, hashId): for streamlist in self.collectionOfInvs: for stream in streamlist: - if hash in streamlist[stream]: + if hashId in streamlist[stream]: return True return False diff --git a/src/network/stats.py b/src/network/stats.py index b348098c..e17d1041 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -18,21 +18,19 @@ def connectedHostsList(): if BMConfigParser().get("network", "asyncore"): retval = [] for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - if not i.connected: + if not i.fullyEstablished: continue try: retval.append((i.destination, i.streams[0])) except AttributeError: pass return retval - else: - return shared.connectedHostsList.items() + return shared.connectedHostsList.items() def sentBytes(): if BMConfigParser().get("network", "asyncore"): return asyncore.sentBytes - else: - return throttle.SendThrottle().total + return throttle.SendThrottle().total def uploadSpeed(): global lastSentTimestamp, lastSentBytes, currentSentSpeed @@ -44,14 +42,12 @@ def uploadSpeed(): lastSentBytes = currentSentBytes lastSentTimestamp = currentTimestamp return currentSentSpeed - else: - return throttle.sendThrottle().getSpeed() + return throttle.sendThrottle().getSpeed() def receivedBytes(): if BMConfigParser().get("network", "asyncore"): return asyncore.receivedBytes - else: - return throttle.ReceiveThrottle().total + return throttle.ReceiveThrottle().total def downloadSpeed(): global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed @@ -63,8 +59,7 @@ def downloadSpeed(): lastReceivedBytes = currentReceivedBytes lastReceivedTimestamp = currentTimestamp return currentReceivedSpeed - else: - return throttle.ReceiveThrottle().getSpeed() + return throttle.ReceiveThrottle().getSpeed() def pendingDownload(): if BMConfigParser().get("network", "asyncore"): @@ -73,8 +68,7 @@ def pendingDownload(): for k in connection.objectsNewToMe.keys(): tmp[k] = True return len(tmp) - else: - return PendingDownloadQueue.totalSize() + return PendingDownloadQueue.totalSize() def pendingUpload(): if BMConfigParser().get("network", "asyncore"): @@ -84,5 +78,4 @@ def pendingUpload(): for k in connection.objectsNewToThem.keys(): tmp[k] = True return len(tmp) - else: - return PendingUpload().len() + return PendingUpload().len() diff --git a/src/network/tls.py b/src/network/tls.py index 9694b4b9..5a8a5a59 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -63,28 +63,26 @@ class TLSDispatcher(AdvancedDispatcher): def writable(self): try: - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): + if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): #print "tls writable, %r" % (self.want_write) return self.want_write - else: - return AdvancedDispatcher.writable(self) + return AdvancedDispatcher.writable(self) except AttributeError: return AdvancedDispatcher.writable(self) def readable(self): try: - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): + if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): #print "tls readable, %r" % (self.want_read) return self.want_read - else: - return AdvancedDispatcher.readable(self) + 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 len(self.write_buf) == 0 and self.writeQueue.empty(): + if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): #print "handshaking (read)" self.tls_handshake() else: @@ -104,7 +102,7 @@ class TLSDispatcher(AdvancedDispatcher): def handle_write(self): try: # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and len(self.write_buf) == 0 and self.writeQueue.empty(): + if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): #print "handshaking (write)" self.tls_handshake() else: @@ -123,13 +121,13 @@ class TLSDispatcher(AdvancedDispatcher): def tls_handshake(self): # wait for flush - if len(self.write_buf) > 0: + if self.write_buf: return False # Perform the handshake. try: #print "handshaking (internal)" self.sslSocket.do_handshake() - except ssl.SSLError, err: + 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: diff --git a/src/network/udp.py b/src/network/udp.py index 9eccbf67..6770e5a0 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -1,32 +1,15 @@ -import base64 -from binascii import hexlify -import hashlib -import math import time import Queue import socket -import struct -import random -import traceback -from addresses import calculateInventoryHash from debug import logger -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.downloadqueue import DownloadQueue -from network.node import Node +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 network.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue -import addresses -from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue, peerDiscoveryQueue, portCheckerQueue, UISignalQueue -import shared +from queues import objectProcessorQueue, peerDiscoveryQueue, UISignalQueue import state import protocol @@ -35,7 +18,7 @@ class UDPSocket(BMProto): announceInterval = 60 def __init__(self, host=None, sock=None): - BMProto.__init__(self, sock) + super(BMProto, self).__init__(sock=sock) self.verackReceived = True self.verackSent = True # TODO sort out streams diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 96733a36..03c80e49 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -47,7 +47,7 @@ class SqliteInventory(InventoryStorage): with self.lock: return len(self._inventory) + sqlQuery('SELECT count(*) FROM inventory')[0][0] - def by_type_and_tag(self, type, tag): + def by_type_and_tag(self, objectType, tag): with self.lock: values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) diff --git a/src/storage/storage.py b/src/storage/storage.py index 22dfbef5..302c84a0 100644 --- a/src/storage/storage.py +++ b/src/storage/storage.py @@ -30,7 +30,7 @@ class InventoryStorage(Storage, collections.MutableMapping): def __len__(self): raise NotImplementedError - def by_type_and_tag(self, type, tag): + def by_type_and_tag(self, objectType, tag): raise NotImplementedError def hashes_by_stream(self, stream): -- 2.45.1 From bfbdd7e140965d374ac1f33ac9f6b45eae5b9d65 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:14:23 +0200 Subject: [PATCH 0805/1102] Chan address validator button feedback - During validation, the button not only turns gray but also changes label --- src/bitmessageqt/addressvalidator.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bitmessageqt/addressvalidator.py b/src/bitmessageqt/addressvalidator.py index 56352b72..f9de70a2 100644 --- a/src/bitmessageqt/addressvalidator.py +++ b/src/bitmessageqt/addressvalidator.py @@ -15,6 +15,8 @@ class AddressPassPhraseValidatorMixin(): 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: @@ -26,6 +28,10 @@ class AddressPassPhraseValidatorMixin(): 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: @@ -37,6 +43,7 @@ class AddressPassPhraseValidatorMixin(): 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 -- 2.45.1 From 26eb54a82e842cbcfbbb7ce288441f7d835975c0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:16:12 +0200 Subject: [PATCH 0806/1102] Network status updates - now lists each node with its info instead of a per-stream summary --- src/bitmessageqt/networkstatus.py | 70 ++++++++++++++----------------- src/bitmessageqt/networkstatus.ui | 32 ++++++++++---- src/network/stats.py | 2 +- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index ce30b4c7..4ede68f7 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -16,6 +16,8 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): super(NetworkStatus, self).__init__(parent) widgets.load('networkstatus.ui', self) + self.tableWidgetConnectionCount.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) + self.startup = time.localtime() self.labelStartupTime.setText(_translate("networkstatus", "Since startup on %1").arg( l10n.formatTimestamp(self.startup))) @@ -74,51 +76,41 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): "networkstatus", "Up: %1/s Total: %2").arg(self.formatByteRate(network.stats.uploadSpeed()), self.formatBytes(network.stats.sentBytes()))) def updateNetworkStatusTab(self): - 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 = {} connectedHosts = network.stats.connectedHostsList() - for host, streamNumber in connectedHosts: - if not streamNumber in streamNumberTotals: - streamNumberTotals[streamNumber] = 1 - else: - streamNumberTotals[streamNumber] += 1 - while self.tableWidgetConnectionCount.rowCount() > 0: - self.tableWidgetConnectionCount.removeRow(0) - for streamNumber, connectionCount in streamNumberTotals.items(): + self.tableWidgetConnectionCount.setUpdatesEnabled(False) + #self.tableWidgetConnectionCount.setSortingEnabled(False) + #self.tableWidgetConnectionCount.clearContents() + self.tableWidgetConnectionCount.setRowCount(0) + for i in connectedHosts: self.tableWidgetConnectionCount.insertRow(0) - if streamNumber == 0: - newItem = QtGui.QTableWidgetItem("?") + self.tableWidgetConnectionCount.setItem(0, 0, + QtGui.QTableWidgetItem("%s:%i" % (i.destination.host, i.destination.port)) + ) + self.tableWidgetConnectionCount.setItem(0, 1, + QtGui.QTableWidgetItem("%s" % (i.userAgent)) + ) + self.tableWidgetConnectionCount.setItem(0, 2, + QtGui.QTableWidgetItem("%s" % (i.tlsVersion)) + ) + self.tableWidgetConnectionCount.setItem(0, 3, + QtGui.QTableWidgetItem("%s" % (",".join(map(str,i.streams)))) + ) + if i.isOutbound: + brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern) else: - newItem = QtGui.QTableWidgetItem(str(streamNumber)) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.tableWidgetConnectionCount.setItem(0, 0, newItem) - newItem = QtGui.QTableWidgetItem(str(connectionCount)) - newItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.tableWidgetConnectionCount.setItem(0, 1, newItem) - """for currentRow in range(self.tableWidgetConnectionCount.rowCount()): - rowStreamNumber = int(self.tableWidgetConnectionCount.item(currentRow,0).text()) - if streamNumber == rowStreamNumber: - foundTheRowThatNeedsUpdating = True - self.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.tableWidgetConnectionCount.insertRow(0) - newItem = QtGui.QTableWidgetItem(str(streamNumber)) - newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) - self.tableWidgetConnectionCount.setItem(0,0,newItem) - newItem = QtGui.QTableWidgetItem(str(connectionCount)) - newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) - self.tableWidgetConnectionCount.setItem(0,1,newItem) - totalNumberOfConnectionsFromAllStreams += connectionCount""" + brush = QtGui.QBrush(QtGui.QColor("green"), QtCore.Qt.SolidPattern) + for j in (range(1)): + self.tableWidgetConnectionCount.item(0, j).setBackground(brush) + self.tableWidgetConnectionCount.setUpdatesEnabled(True) + #self.tableWidgetConnectionCount.setSortingEnabled(True) + #self.tableWidgetConnectionCount.horizontalHeader().setSortIndicator(1, QtCore.Qt.AscendingOrder) self.labelTotalConnections.setText(_translate( "networkstatus", "Total Connections: %1").arg(str(len(connectedHosts)))) - if len(connectedHosts) > 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. + # 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 connectedHosts and shared.statusIconColor == 'red': self.window().setStatusIcon('yellow') - elif len(connectedHosts) == 0: + elif not connectedHosts and shared.statusIconColor != "red": self.window().setStatusIcon('red') # timer driven @@ -133,6 +125,6 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): self.updateNumberOfPubkeysProcessed() def retranslateUi(self): - super(QtGui.QWidget, self).retranslateUi() + 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 index 6ae988bf..e4264124 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -7,7 +7,7 @@ 0 0 602 - 252 + 254 @@ -18,12 +18,12 @@ - + 20 - QLayout::SetDefaultConstraint + QLayout::SetNoConstraint @@ -31,7 +31,7 @@ 20 - QLayout::SetFixedSize + QLayout::SetMinimumSize @@ -89,13 +89,16 @@ false - true + false QAbstractItemView::NoSelection - false + true + + + 80 false @@ -108,12 +111,22 @@ - Stream # + Peer - Connections + User agent + + + + + TLS + + + + + Stream # @@ -125,6 +138,9 @@ 4 + + QLayout::SetNoConstraint + diff --git a/src/network/stats.py b/src/network/stats.py index e17d1041..7f7c83ac 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -21,7 +21,7 @@ def connectedHostsList(): if not i.fullyEstablished: continue try: - retval.append((i.destination, i.streams[0])) + retval.append(i) except AttributeError: pass return retval -- 2.45.1 From b9d60f8b41ea5ba28ed3bc958953c7ac27fff9dd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:17:01 +0200 Subject: [PATCH 0807/1102] Max known nodes configurable --- src/bmconfigparser.py | 3 +++ src/knownnodes.py | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 0db58103..6725a4d8 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -23,6 +23,9 @@ BMConfigDefaults = { "storage": "sqlite", "acceptmismatch": False, }, + "knownnodes": { + "maxnodes": 20000, + }, "zlib": { 'maxsize': 1048576 } diff --git a/src/knownnodes.py b/src/knownnodes.py index ffb14edc..8f566d43 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -1,12 +1,12 @@ import pickle import threading +from bmconfigparser import BMConfigParser import state knownNodesLock = threading.Lock() knownNodes = {} -knownNodesMax = 20000 knownNodesTrimAmount = 2000 def saveKnownNodes(dirName = None): @@ -17,7 +17,7 @@ def saveKnownNodes(dirName = None): pickle.dump(knownNodes, output) def trimKnownNodes(recAddrStream = 1): - if len(knownNodes[recAddrStream]) < knownNodesMax: + if len(knownNodes[recAddrStream]) < BMConfigParser().get("knownnodes", "maxnodes"): return with knownNodesLock: oldestList = sorted(knownNodes[recAddrStream], key=knownNodes[recAddrStream].get)[:knownNodesTrimAmount] -- 2.45.1 From e9edf70d3a7775e7b8d11e9858da163b0b2d2853 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:18:15 +0200 Subject: [PATCH 0808/1102] TLS updates - save TLS version - minor TLS error handling updates --- src/network/tls.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/network/tls.py b/src/network/tls.py index 5a8a5a59..9dafaab2 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -31,6 +31,7 @@ class TLSDispatcher(AdvancedDispatcher): self.ciphers = ciphers self.tlsStarted = False self.tlsDone = False + self.tlsVersion = "N/A" self.isSSL = False def state_tls_init(self): @@ -96,8 +97,9 @@ class TLSDispatcher(AdvancedDispatcher): elif err.errno in _DISCONNECTED_SSL: self.handle_close() return - else: - raise + logger.info("SSL Error: %s", str(err)) + self.handle_close() + return def handle_write(self): try: @@ -116,8 +118,9 @@ class TLSDispatcher(AdvancedDispatcher): elif err.errno in _DISCONNECTED_SSL: self.handle_close() return 0 - else: - raise + logger.info("SSL Error: %s", str(err)) + self.handle_close() + return def tls_handshake(self): # wait for flush @@ -138,8 +141,19 @@ class TLSDispatcher(AdvancedDispatcher): 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: - logger.debug("%s:%i: TLS handshake success%s", self.destination.host, self.destination.port, ", TLS protocol version: %s" % (self.sslSocket.version()) if sys.version_info >= (2, 7, 9) 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) -- 2.45.1 From dc5a91f32630d7edfd89b5ffbd5813e6814d58a0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:19:19 +0200 Subject: [PATCH 0809/1102] Remove stack depth warnings - I was never able to trigger them --- src/network/advanceddispatcher.py | 11 +++++------ src/network/receivequeuethread.py | 10 +++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 61dd197b..1abc7975 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -41,14 +41,13 @@ class AdvancedDispatcher(asyncore.dispatcher): if not self.connected: return maxLoop = 20 - try: - sys._getframe(200) - logger.error("Stack depth warning") - except ValueError: - pass +# try: +# sys._getframe(200) +# logger.error("Stack depth warning") +# except ValueError: +# pass while maxLoop > 0: try: -# print "Trying to handle state \"%s\"" % (self.state) if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 6662a078..8360ab45 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -25,11 +25,11 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): while not self._stopped and state.shutdown == 0: if lastprinted < int(time.time()): lastprinted = int(time.time()) - try: - sys._getframe(200) - logger.error("Stack depth warning") - except ValueError: - pass +# try: +# sys._getframe(200) +# logger.error("Stack depth warning") +# except ValueError: +# pass processed = 0 for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): if self._stopped: -- 2.45.1 From d57b0c55eec4ddcd22fdddb9800093e34fcadcf2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:21:06 +0200 Subject: [PATCH 0810/1102] Object validator trigger moved - from bmproto to bmobject --- src/network/bmobject.py | 26 +++++++++++++++----------- src/network/bmproto.py | 13 +++---------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 318cbfd1..98a14b5e 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -32,7 +32,7 @@ class BMObject(object): # min TTL, 3 hour (in the past minTTL = -3600 - def __init__(self, nonce, expiresTime, objectType, version, streamNumber, data): + def __init__(self, nonce, expiresTime, objectType, version, streamNumber, data, payloadOffset): self.nonce = nonce self.expiresTime = expiresTime self.objectType = objectType @@ -40,7 +40,7 @@ class BMObject(object): self.streamNumber = streamNumber self.inventoryHash = calculateInventoryHash(data) self.data = data - self.tag = '' + self.tag = data[payloadOffset:payloadOffset+32] def checkProofOfWorkSufficient(self): # Let us check to make sure that the proof of work is sufficient. @@ -69,6 +69,17 @@ class BMObject(object): 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 @@ -77,15 +88,12 @@ class BMObject(object): logger.info('getpubkey message doesn\'t contain enough data. Ignoring.') raise BMObjectInvalidError() - def checkPubkey(self, tag): + 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() - if self.version >= 4: - self.tag = tag - logger.debug('tag in received pubkey is: %s' % hexlify(tag)) - def checkBroadcast(self, tag): + 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() @@ -93,7 +101,3 @@ class BMObject(object): # this isn't supported anymore if self.version < 2: raise BMObjectInvalidError() - - if self.version >= 3: - self.tag = tag - logger.debug('tag in received broadcast is: %s' % hexlify(tag)) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 32bf038c..9b1ba08e 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -263,7 +263,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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.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) @@ -291,15 +291,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): isinstance(e, BMObjectExpiredError): raise e - if self.object.objectType == protocol.OBJECT_GETPUBKEY: - self.object.checkGetpubkey() - elif self.object.objectType == protocol.OBJECT_PUBKEY: - self.object.checkPubkey(self.payload[self.payloadOffset:self.payloadOffset+32]) - elif self.object.objectType == protocol.OBJECT_MSG: - self.object.checkMessage() - elif self.object.objectType == protocol.OBJECT_BROADCAST: - self.object.checkBroadcast(self.payload[self.payloadOffset:self.payloadOffset+32]) - # other objects don't require other types of tests + self.object.checkObjectByType() + Inventory()[self.object.inventoryHash] = ( self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) objectProcessorQueue.put((self.object.objectType,self.object.data)) -- 2.45.1 From 0a79490e2c8f500fa7f6e23c811ca4ef29606030 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:21:42 +0200 Subject: [PATCH 0811/1102] Known nodes maximum configurable part 2 --- src/network/bmproto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 9b1ba08e..61cc53d3 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -317,7 +317,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): peer = state.Peer(decodedIP, port) if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer] > seenTime: continue - if len(knownnodes.knownNodes[stream]) < 20000: + if len(knownnodes.knownNodes[stream]) < BMConfigParser().get("knownnodes", "maxnodes"): with knownnodes.knownNodesLock: knownnodes.knownNodes[stream][peer] = seenTime #knownnodes.knownNodes[stream][peer] = seenTime -- 2.45.1 From 0dc0b22974f3767105e0f2dfb5eb2e9d8d840414 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:22:41 +0200 Subject: [PATCH 0812/1102] Expired / Stream mismatch / duplicate object error handling - cleanup of the code --- src/network/bmproto.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 61cc53d3..0c70f12e 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -7,6 +7,7 @@ import socket import struct from addresses import calculateInventoryHash +from bmconfigparser import BMConfigParser from debug import logger from inventory import Inventory import knownnodes @@ -272,10 +273,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.checkProofOfWorkSufficient() try: self.object.checkEOLSanity() - self.object.checkStream() self.object.checkAlreadyHave() - except (BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectAlreadyHaveError) as e: - for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + network.connectionpool.BMConnectionPool().outboundConnections.values(): + except (BMObjectExpiredError, BMObjectAlreadyHaveError) as e: + for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ + network.connectionpool.BMConnectionPool().outboundConnections.values(): try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[self.object.inventoryHash] @@ -286,9 +287,24 @@ class BMProto(AdvancedDispatcher, ObjectTracker): del connection.objectsNewToMe[self.object.inventoryHash] except KeyError: pass - if not BMConfigParser().get("inventory", "acceptmismatch") or \ - isinstance(e, BMObjectAlreadyHaveError) or \ - isinstance(e, BMObjectExpiredError): + raise e + try: + self.object.checkStream() + except (BMObjectUnwantedStreamError,) as e: + for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ + network.connectionpool.BMConnectionPool().outboundConnections.values(): + try: + with connection.objectsNewToMeLock: + del connection.objectsNewToMe[self.object.inventoryHash] + except KeyError: + pass + if not BMConfigParser().get("inventory", "acceptmismatch"): + try: + with connection.objectsNewToThemLock: + del connection.objectsNewToThem[self.object.inventoryHash] + except KeyError: + pass + if not BMConfigParser().get("inventory", "acceptmismatch"): raise e self.object.checkObjectByType() -- 2.45.1 From 916b85c862d740b4efe8fb3f73fa4ae0489b81b1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:23:16 +0200 Subject: [PATCH 0813/1102] Connection pool cleanup - minor code quality improvement --- src/network/connectionpool.py | 40 ++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 67778b46..ae76c318 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -69,7 +69,7 @@ class BMConnectionPool(object): def removeConnection(self, connection): if isinstance(connection, network.udp.UDPSocket): del self.udpSockets[connection.listening.host] - if isinstance(connection, network.tcp.TCPServer): + elif isinstance(connection, network.tcp.TCPServer): del self.listeningSockets[state.Peer(connection.destination.host, connection.destination.port)] elif connection.isOutbound: try: @@ -163,24 +163,26 @@ class BMConnectionPool(object): self.lastSpawned = time.time() - if acceptConnections and len(self.listeningSockets) == 0: - self.startListening() - logger.info('Listening for incoming connections.') - if acceptConnections and len(self.udpSockets) == 0: - if BMConfigParser().safeGet("network", "bind") is None: - self.startUDPSocket() - else: - for bind in re.sub("[^\w.]+", " ", BMConfigParser().safeGet("network", "bind")).split(): - self.startUDPSocket(bind) - logger.info('Starting UDP socket(s).') - if len(self.listeningSockets) > 0 and not acceptConnections: - for i in self.listeningSockets: - i.handle_close() - logger.info('Stopped listening for incoming connections.') - if len(self.udpSockets) > 0 and not acceptConnections: - for i in self.udpSockets: - i.handle_close() - logger.info('Stopped udp sockets.') + if acceptConnections: + if not self.listeningSockets: + self.startListening() + logger.info('Listening for incoming connections.') + if not self.udpSockets: + if BMConfigParser().safeGet("network", "bind") is None: + self.startUDPSocket() + else: + for bind in re.sub("[^\w.]+", " ", BMConfigParser().safeGet("network", "bind")).split(): + self.startUDPSocket(bind) + logger.info('Starting UDP socket(s).') + else: + if self.listeningSockets: + for i in self.listeningSockets: + i.handle_close() + logger.info('Stopped listening for incoming connections.') + if self.udpSockets: + for i in self.udpSockets: + i.handle_close() + logger.info('Stopped udp sockets.') # while len(asyncore.socket_map) > 0 and state.shutdown == 0: # print "loop, state = %s" % (proxy.state) -- 2.45.1 From 189578cba389423a54c6541d60353a8c209bd62e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 12:23:56 +0200 Subject: [PATCH 0814/1102] Asyncore proxy fixes - SOCKS5 now seems to work, SOCKS4a untested --- src/network/proxy.py | 41 +++++++++++++++++++++++++------- src/network/socks4a.py | 21 +++++++++-------- src/network/socks5.py | 53 ++++++++++++++++++++++++------------------ src/network/tcp.py | 12 +++++++--- 4 files changed, 83 insertions(+), 44 deletions(-) diff --git a/src/network/proxy.py b/src/network/proxy.py index 3b7cc848..c131c22a 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -1,13 +1,36 @@ import socket - -import state +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): + 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 ProxyError(Exception): pass -class GeneralProxyError(ProxyError): pass class Proxy(AdvancedDispatcher): # these are global, and if you change config during runtime, all active/new @@ -22,7 +45,8 @@ class Proxy(AdvancedDispatcher): @proxy.setter def proxy(self, address): - if type(address) != tuple or (len(address) < 2) or (type(str(address[0])) != type('')) or (type(address[1]) != int): + 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 @@ -42,18 +66,17 @@ class Proxy(AdvancedDispatcher): self.isOutbound = True self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.proxy) - print "connecting in background to %s:%i" % (self.proxy[0], self.proxy[1]) 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))) + 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.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) self.connectedAt = time.time() return False - diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 08bd18cf..61f3ec7d 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -1,11 +1,14 @@ import socket import struct -from advanceddispatcher import AdvancedDispatcher -import asyncore_pollchoose as asyncore from proxy import Proxy, ProxyError, GeneralProxyError -class Socks4aError(ProxyError): pass +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): @@ -24,22 +27,20 @@ class Socks4a(Proxy): if self.read_buf[0:1] != chr(0x00).encode(): # bad data self.close() - raise Socks4aError + 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 erro - raise Socks4aError - #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])-90])) + # socks 4 error + raise Socks4aError(ord(self.read_buf[1:2]) - 90) else: - raise Socks4aError - #raise Socks4aError((94, _socks4aerrors[4])) + 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 != None: + if self.ipaddr: self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: self.__proxypeername = (self.destination[0], self.destport) diff --git a/src/network/socks5.py b/src/network/socks5.py index 6745308c..89c3c9b2 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -1,13 +1,27 @@ import socket import struct -from advanceddispatcher import AdvancedDispatcher -import asyncore_pollchoose as asyncore from proxy import Proxy, ProxyError, GeneralProxyError -import network.connectionpool -class Socks5AuthError(ProxyError): pass -class Socks5Error(ProxyError): pass +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): @@ -30,7 +44,7 @@ class Socks5(Proxy): self.read_buf = self.read_buf[2:] if ret[0] != 5: # general error - raise GeneralProxyError + raise GeneralProxyError(1) elif ret[1] == 0: # no auth required self.set_state("auth_done", 2) @@ -39,14 +53,14 @@ class Socks5(Proxy): self.writeQueue.put(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_1", 2) + self.set_state("auth_needed", 2) else: if ret[1] == 0xff: # auth error - raise Socks5AuthError + raise Socks5AuthError(2) else: # other error - raise Socks5Error + raise GeneralProxyError(1) def state_auth_needed(self): if not self.read_buf_sufficient(2): @@ -54,10 +68,10 @@ class Socks5(Proxy): ret = struct.unpack('BB', self.read_buf) if ret[0] != 1: # general error - raise Socks5Error + raise GeneralProxyError(1) if ret[1] != 0: # auth error - raise Socks5AuthError + raise Socks5AuthError(3) # all ok self.set_state = ("auth_done", 2) @@ -66,19 +80,15 @@ class Socks5(Proxy): return False # Get the response if self.read_buf[0:1] != chr(0x05).encode(): - # general error self.close() - raise Socks5Error + raise GeneralProxyError(1) elif self.read_buf[1:2] != chr(0x00).encode(): # Connection failed self.close() if ord(self.read_buf[1:2])<=8: - # socks 5 erro - raise Socks5Error - #raise Socks5Error((ord(resp[1:2]), _socks5errors[ord(resp[1:2])])) + raise Socks5Error(ord(self.read_buf[1:2])) else: - raise Socks5Error - #raise Socks5Error((9, _socks5errors[9])) + raise Socks5Error(9) # Get the bound address/port elif self.read_buf[3:4] == chr(0x01).encode(): self.set_state("proxy_addr_1", 4) @@ -86,8 +96,7 @@ class Socks5(Proxy): self.set_state("proxy_addr_2_1", 4) else: self.close() - #raise GeneralProxyError((1,_generalerrors[1])) - raise GeneralProxyError + raise GeneralProxyError(1) def state_proxy_addr_1(self): if not self.read_buf_sufficient(4): @@ -112,14 +121,14 @@ class Socks5(Proxy): return False self.boundport = struct.unpack(">H", self.read_buf[0:2])[0] self.__proxysockname = (self.boundaddr, self.boundport) - if self.ipaddr != None: + 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", 2) def proxy_sock_name(self): - return socket.inet_ntoa(self.__proxysockname[0]) + return socket.inet_ntoa(self.__proxysockname[0]) class Socks5Connection(Socks5): diff --git a/src/network/tcp.py b/src/network/tcp.py index 8a6b5705..bd925063 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -181,7 +181,10 @@ class Socks5BMConnection(Socks5Connection, TCPConnection): TCPConnection.__init__(self, address=address, sock=self.socket) self.set_state("init") - def state_socks_handshake_done(self): + def state_proxy_handshake_done(self): + Socks5Connection.state_proxy_handshake_done(self) + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + network.connectionpool.BMConnectionPool().streams, False)) self.set_state("bm_header", expectBytes=protocol.Header.size) return False @@ -192,7 +195,10 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection): TCPConnection.__init__(self, address=address, sock=self.socket) self.set_state("init") - def state_socks_handshake_done(self): + def state_proxy_handshake_done(self): + Socks4aConnection.state_proxy_handshake_done(self) + self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + network.connectionpool.BMConnectionPool().streams, False)) self.set_state("bm_header", expectBytes=protocol.Header.size) return False @@ -216,7 +222,7 @@ class TCPServer(AdvancedDispatcher): len(network.connectionpool.BMConnectionPool().outboundConnections) > \ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \ BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"): - close(sock) + sock.close() return try: network.connectionpool.BMConnectionPool().addConnection(TCPConnection(sock=sock)) -- 2.45.1 From aa203b23eec8ff9ccbde3678f01f4ee14f43a09f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 24 Jun 2017 23:09:08 +0200 Subject: [PATCH 0815/1102] Fix typo introduced by code quality patch --- src/storage/sqlite.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 03c80e49..b5c48e3b 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -49,8 +49,8 @@ class SqliteInventory(InventoryStorage): def by_type_and_tag(self, objectType, tag): with self.lock: - values = [value for value in self._inventory.values() if value.type == type and value.tag == tag] - values += (InventoryItem(*value) for value in sqlQuery('SELECT objecttype, streamnumber, payload, expirestime, tag FROM inventory WHERE objecttype=? AND tag=?', type, tag)) + 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, tag)) return values def hashes_by_stream(self, stream): -- 2.45.1 From ccfe58c2c0e54043fb9a6f6e85a724e400dad261 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sun, 25 Jun 2017 16:49:31 +0200 Subject: [PATCH 0816/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 65447 -> 65563 bytes src/translations/bitmessage_ja.ts | 295 ++++++++++++++++-------------- 2 files changed, 155 insertions(+), 140 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index da6c715b15c0b1ffea8a707e3fcbaa5d83dafa2c..d9acc50c19b7d0bde1dd7fc8242ce639528ca365 100644 GIT binary patch delta 1172 zcmX|Bdr(wW9RBXzyLb2AyUPxb;brWyB<|n{EKDpZ@<>F`VL?J5N-B$0e1H$YNhyJ0 zXetERIWRdy^Z+BAP#eYsZ6zU)N6QpMGr*99JfslDh$afOW6k)-Z@!uHednCt?>pa| z#z(Rbia4*Wt(oq9i?!8u{Zs9)eqtNn2B?()f`GnStCx>!x-)R|4dA7XK*1d#Ydi3} z*=qLT4|f1Jwp+6|c+Po4-uf;up9;Q7M)`awQe!9%SetdsdaHc{I~i+TPGho&nQ_yX zBkka6U}_03T#W#H<#;i73*FsRVI1O676oF zfHcbu%mNvf>x4-@`2wA%FN>_nb&mD?J11$6QT}}Gu4&-G`^29&`Ak2}kEhau?%v`T z_#7bbCxugGA&~lyB2*jzzFr}vyiPxSC#_P_BlD zPNg%zn-!|Eu1f0Tys9eFlLn}Ol!}qmhAz<{bg0G(hG^uc$+CEW=_eVIfhi-UQh?aM z$wBF!K(l$6*yv&tnU;5F z7+bcfJ6l^!-6^ayXZ+Fl>EjOpJS}dw#d3li@AGIW?@`KJc{M}!{{{q49gt-6! delta 1101 zcmXAneNa?Y7{;G__wL=j_b%*!Bgh(ifutRni4_WPKo-gnY=R9PAWHg}K!r(&5N7~~ zk0G1V66j_B$i!sANE#H|NH8`k1s7@=2d57}1VRuMWVD!3Q|UDQ^~{`k&+|U#cb-pc zgtiq;;KuH}HA72B9G>9E`d)8wO*{)2?gEGehBh<;sK^AIk;FZoIISFzx)j?a#pT@0(sTvcTP14Kt>W5Z0!L?|DrTrKudS=e2j*nz(E4-!)UUO02WU~NN>$>v<1F=%K&wU7CsBNVFH4g2qfU=H0Jv7H zI~08dh)vKn_#mQghuP(9kIz+qeRB1WBh`>_F#K7dlUx!tr7W$Vb-hfy(mFaxf05iR4G{Ts%6z2 z$f5m`E$WvUCH*YBvbRymSYiM5=O4v&H$5Id)^Kc@#)HXKeQ{Di_;n))1qca~81XI%v3a py>qMAxo#SF`3VKZMWr<9_IIux$mE?(Zdv0T{Mp1gANSmi`WNy^bISk# diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 1757b887..65a5c57d 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -318,7 +318,7 @@ Please type the desired email address (including @mailchuck.com) below: メッセージの確認を受け取りました %1 - + Broadcast queued. 配信がキューに入りました。 @@ -348,7 +348,7 @@ Please type the desired email address (including @mailchuck.com) below: 不明なステータス: %1 %2 - + Not Connected 未接続 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1166,7 +1166,7 @@ Are you sure you want to delete the channel? %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% @@ -1216,61 +1216,61 @@ Are you sure you want to delete the channel? アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 @@ -1280,7 +1280,7 @@ Receiver's required difficulty: %1 and %2 メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました @@ -1290,12 +1290,12 @@ Receiver's required difficulty: %1 and %2 暗号鍵のリクエストに必要な処理を行っています。 - + Broadcasting the public key request. This program will auto-retry if they are offline. 公開鍵のリクエストを配信しています。 このプログラムがオフラインの場合、自動的に再試行されます。 - + Sending public key request. Waiting for reply. Requested at %1 公開鍵のリクエストを送信しています。 返信を待っています。 %1 でリクエストしました @@ -1315,7 +1315,7 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? @@ -1325,37 +1325,37 @@ Receiver's required difficulty: %1 and %2 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %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 は間違っている可能性があります。 設定を確認してください。 @@ -1425,77 +1425,77 @@ Receiver's required difficulty: %1 and %2 チャンネルにはお勧めしません - + Problems connecting? Try enabling UPnP in the Network Settings 接続に問題がありますか? ネットワーク設定でUPnPを有効にしてみてください - + 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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... @@ -1526,14 +1526,14 @@ Receiver's required difficulty: %1 and %2 MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. メッセージのエンコードが不明です。 Bitmessageをアップグレードする必要があるかもしれません。 - + Unknown encoding 不明なエンコード @@ -1841,77 +1841,77 @@ The 'Random Number' option is selected by default but deterministic ad 接続数: - + 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/秒 @@ -1921,30 +1921,45 @@ The 'Random Number' option is selected by default but deterministic ad ネットワークの状態 - + 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 + ピア + + + + User agent + ユーザーエージェント + + + + TLS + TLS + newChanDialog -- 2.45.1 From 30b65aaefc3652afee007556908e98807bfaed77 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sat, 24 Jun 2017 21:24:59 +0200 Subject: [PATCH 0817/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 89786 -> 89830 bytes src/translations/bitmessage_pl.ts | 333 ++++++++++++++++-------------- 2 files changed, 174 insertions(+), 159 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index c02118e4fa3b0d749d8214ba77f336a17e84f342..ad4818c65e659d34fa86c17fb019d922afa09297 100644 GIT binary patch delta 3804 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 diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index 4b2b6371..93f72222 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -207,7 +207,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: Save message as... - Zapisz wiadomość jako... + Zapisz wiadomość jako… @@ -232,7 +232,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: Set avatar... - Ustaw awatar... + Ustaw awatar… @@ -242,7 +242,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: Special address behavior... - Specjalne zachowanie adresu... + Specjalne zachowanie adresu… @@ -320,7 +320,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Otrzymano potwierdzenie odbioru wiadomości %1 - + Broadcast queued. Przekaz w kolejce do wysłania. @@ -350,7 +350,7 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Nieznany status: %1 %2 - + Not Connected Brak połączenia @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 Od - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć wiadomość. - + Save As... - Zapisz jako... + 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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... + Testowanie… - + 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. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,49 +1117,49 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów 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% + Oczekiwanie na wykonanie dowodu pracy… %1% - + Shutting down Pybitmessage... %1% - Zamykanie PyBitmessage... %1% + Zamykanie PyBitmessage… %1% - + Waiting for objects to be sent... %1% - Oczekiwanie na wysłanie obiektów... %1% + Oczekiwanie na wysłanie obiektów… %1% - + Saving settings... %1% - Zapisywanie ustawień... %1% + Zapisywanie ustawień… %1% - + Shutting down core... %1% - Zamykanie rdzenia programu... %1% - - - - Stopping notifications... %1% - Zatrzymywanie powiadomień... %1% + Zamykanie rdzenia programu… %1% + Stopping notifications... %1% + Zatrzymywanie powiadomień… %1% + + + Shutdown imminent... %1% - Zaraz zamknę... %1% + Zaraz zamknę… %1% @@ -1172,9 +1172,9 @@ Czy na pewno chcesz usunąć ten kanał? %n dzień%n dni%n dni%n dni - + Shutting down PyBitmessage... %1% - Zamykanie PyBitmessage... %1% + Zamykanie PyBitmessage… %1% @@ -1189,7 +1189,7 @@ Czy na pewno chcesz usunąć ten kanał? Done generating address. Doing work necessary to broadcast it... - Adresy wygenerowany. Wykonywanie dowodu pracy niezbędnego na jego rozesłanie... + Adresy wygenerowany. Wykonywanie dowodu pracy niezbędnego na jego rozesłanie… @@ -1222,61 +1222,61 @@ Czy na pewno chcesz usunąć ten kanał? 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... + Wykonywanie dowodu pracy niezbędnego do wysłania przekazu… - + Broadcast sent on %1 Przekaz wysłane o %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 @@ -1286,7 +1286,7 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1296,12 +1296,12 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1321,7 +1321,7 @@ Odbiorca wymaga trudności: %1 i %2 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? @@ -1331,37 +1331,37 @@ Odbiorca wymaga trudności: %1 i %2 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. @@ -1430,79 +1430,79 @@ Witamy w przyjaznym i bezpiecznym Bitmessage niezalecany dla kanałów - + Problems connecting? Try enabling UPnP in the Network Settings Problem z połączeniem? Spróbuj włączyć UPnP w ustawieniach sieci. - + 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. - + 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... + Oczekiwanie na połączenie sieciowe… - + Waiting for finishing synchronisation... - Oczekiwanie na zakończenie synchronizacji... + Oczekiwanie na zakończenie synchronizacji… @@ -1531,14 +1531,14 @@ Witamy w przyjaznym i bezpiecznym Bitmessage MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. Wiadomość zawiera nierozpoznane kodowanie. Prawdopodobnie powinieneś zaktualizować Bitmessage. - + Unknown encoding Nierozpoznane kodowanie @@ -1847,77 +1847,77 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 przekazów. - + Inventory lookups per second: 0 Zapytań o elementy na sekundę: 0 - + Objects to be synced: Obiektów do zsynchronizowania: - + Stream # Strumień # Connections - Połączeń + - + 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 @@ -1927,30 +1927,45 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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ść przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. - + Processed %n public key(s). Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. + + + Peer + Użytkownik + + + + User agent + Klient + + + + TLS + TLS + newChanDialog -- 2.45.1 From 8a3577aed74be6ccbe31871fbff7915a28a38a07 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sat, 24 Jun 2017 21:23:27 +0200 Subject: [PATCH 0818/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 86543 -> 86609 bytes src/translations/bitmessage_eo.ts | 335 ++++++++++++++++-------------- 2 files changed, 175 insertions(+), 160 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index eddaf80806073c740d5119e830181d97b2877ddc..073654d4927ecb567df87b758b63d8c5f3be1f5a 100644 GIT binary patch delta 3824 zcmYjUdsvNG7ys?^zVA8bJy%`GFq%j%sU(#y%B>JNE|JS9g+5(4Q7+ZsM6QX_De9

|bOTKmLdFJ{4IM46d``vr3wb%Ns-`*#)Sg0)) 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 EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -203,7 +203,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: Save message as... - Konservi mesaĝon kiel... + Konservi mesaĝon kiel… @@ -228,7 +228,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: Set avatar... - Agordi avataron... + Agordi avataron… @@ -238,7 +238,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: Special address behavior... - Speciala sinteno de adreso... + Speciala sinteno de adreso… @@ -316,7 +316,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Ricevis konfirmon de la mesaĝo je %1 - + Broadcast queued. Elsendo en atendovico. @@ -346,7 +346,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Nekonata stato: %1 %2 - + Not Connected Ne konektita @@ -509,22 +509,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 @@ -532,17 +532,17 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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. @@ -587,67 +587,67 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 De - + Sending email gateway registration request Sendado de peto pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (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 Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis elementon. - + Save As... - Konservi kiel... + 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi 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... + Testado… - + 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. - + 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. La numero de adresversio estas pli alta ol tiun, 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. Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco 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). Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). @@ -1110,49 +1110,49 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% - Atendado ĝis laborpruvo finos... %1% + Atendado ĝis laborpruvo finos… %1% - + Shutting down Pybitmessage... %1% - Fermado de PyBitmessage... %1% + Fermado de PyBitmessage… %1% - + Waiting for objects to be sent... %1% - Atendado ĝis objektoj estos senditaj... %1% + Atendado ĝis objektoj estos senditaj… %1% - + Saving settings... %1% - Konservado de agordoj... %1% + Konservado de agordoj… %1% - + Shutting down core... %1% - Fermado de kerno... %1% - - - - Stopping notifications... %1% - Haltigado de sciigoj... %1% + Fermado de kerno… %1% + Stopping notifications... %1% + Haltigado de sciigoj… %1% + + + Shutdown imminent... %1% - Fermado tuj... %1% + Fermado tuj… %1% @@ -1165,9 +1165,9 @@ Are you sure you want to delete the channel? %n tago%n tagoj - + Shutting down PyBitmessage... %1% - Fermado de PyBitmessage... %1% + Fermado de PyBitmessage… %1% @@ -1182,7 +1182,7 @@ Are you sure you want to delete the channel? Done generating address. Doing work necessary to broadcast it... - Adreso kreita. Kalkulado de laborpruvo, kiu endas por elsendi ĝin... + Adreso kreita. Kalkulado de laborpruvo, kiu endas por elsendi ĝin… @@ -1215,61 +1215,61 @@ Are you sure you want to delete the channel? Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... - Kalkulado de laborpruvo, kiu endas por sendi elsendon... + Kalkulado de laborpruvo, kiu endas por sendi elsendon… - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendado de peto pri ĉifroŝlosilo de ricevonto. - + 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 @@ -1279,7 +1279,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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 @@ -1289,12 +1289,12 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Kalkulado de laborpruvo, kiu endas por peti pri ĉifroŝlosilo. - + 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. - + Sending public key request. Waiting for reply. Requested at %1 Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 @@ -1314,7 +1314,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? @@ -1324,37 +1324,37 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? - + Problem communicating with proxy: %1. Please check your network settings. Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Eraro dum SOCKS5 aŭtentigado: %1. Bonvolu kontroli viajn SOCKS5-agordojn. - + 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. @@ -1423,79 +1423,79 @@ Bonvenon al facila kaj sekura Bitmesaĝo malkonsilinda por kanaloj - + Problems connecting? Try enabling UPnP in the Network Settings Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + 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. - + 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... + Atendado je retkonekto… - + Waiting for finishing synchronisation... - Atendado ĝis samtempigado finiĝos... + Atendado ĝis samtempigado finiĝos… @@ -1524,14 +1524,14 @@ Bonvenon al facila kaj sekura Bitmesaĝo 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 @@ -1840,110 +1840,125 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a Ĉ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 - Konektoj + - + 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 + 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 + + + + User agent + Klienta aplikaĵo + + + + TLS + TLS + newChanDialog -- 2.45.1 From 20e01860cf8b7927c2829fa5b8ad178d9fd0334b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 27 Jun 2017 13:16:41 +0200 Subject: [PATCH 0819/1102] Network status peer list shouldn't be editable --- src/bitmessageqt/networkstatus.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui index e4264124..993cf1c6 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -85,6 +85,9 @@ QFrame::Plain + + QAbstractItemView::NoEditTriggers + false -- 2.45.1 From f5a143d0b83387b2cad2f320f7067d95375ca498 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 27 Jun 2017 13:19:12 +0200 Subject: [PATCH 0820/1102] Config validator - config options can have validators - limit maxoutboundconnections to max 8 --- src/bitmessageqt/settings.py | 2 +- src/bmconfigparser.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 300c3544..4342fd09 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -165,7 +165,7 @@ class Ui_settingsDialog(object): self.lineEditMaxOutboundConnections.setSizePolicy(sizePolicy) self.lineEditMaxOutboundConnections.setMaximumSize(QtCore.QSize(60, 16777215)) self.lineEditMaxOutboundConnections.setObjectName(_fromUtf8("lineEditMaxOutboundConnections")) - self.lineEditMaxOutboundConnections.setValidator(QtGui.QIntValidator(0, 4096, self.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) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 6725a4d8..913df9c0 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -37,6 +37,8 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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): @@ -76,6 +78,20 @@ class BMConfigParser(ConfigParser.SafeConfigParser): 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' @@ -93,3 +109,18 @@ class BMConfigParser(ConfigParser.SafeConfigParser): # 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 -- 2.45.1 From cc3cf777596f43be63310daeae804bd640b015f9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 27 Jun 2017 13:25:12 +0200 Subject: [PATCH 0821/1102] New class multiqueue - to be used for invthread and addthread - updated invthread for multiqueue --- src/multiqueue.py | 35 +++++++++++++++++++++ src/network/invthread.py | 68 +++++++++------------------------------- src/queues.py | 5 ++- 3 files changed, 53 insertions(+), 55 deletions(-) create mode 100644 src/multiqueue.py diff --git a/src/multiqueue.py b/src/multiqueue.py new file mode 100644 index 00000000..30326ee7 --- /dev/null +++ b/src/multiqueue.py @@ -0,0 +1,35 @@ +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) + i = random.randrange(0, self.queueCount) + self.queues[i].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 diff --git a/src/network/invthread.py b/src/network/invthread.py index 9d05aec4..398fecf0 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,37 +1,22 @@ -from binascii import hexlify -import collections import Queue -import random import threading -import time import addresses -from bmconfigparser import BMConfigParser -from debug import logger from helper_threading import StoppableThread -from network.bmproto import BMProto from network.connectionpool import BMConnectionPool from queues import invQueue import protocol import state class InvThread(threading.Thread, StoppableThread): - size = 10 - def __init__(self): threading.Thread.__init__(self, name="InvThread") self.initStop() self.name = "InvThread" - self.shutdown = False - - self.collectionOfInvs = [] - for i in range(InvThread.size): - self.collectionOfInvs.append({}) - def run(self): - iterator = 0 while not state.shutdown: + chunk = [] while True: try: data = invQueue.get(False) @@ -39,50 +24,25 @@ class InvThread(threading.Thread, StoppableThread): BMConnectionPool().handleReceivedObject(data[0], data[1]) else: BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) - self.holdHash (data[0], data[1]) + chunk.append((data[0], data[1])) except Queue.Empty: break - if self.collectionOfInvs[iterator]: - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + if chunk: + for connection in BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): hashes = [] - for stream in connection.streams: + for inv in chunk: + if inv[0] not in connection.streams: + continue try: - for hashId in self.collectionOfInvs[iterator][stream]: - try: - with connection.objectsNewToThemLock: - del connection.objectsNewToThem[hashId] - hashes.append(hashId) - except KeyError: - pass + with connection.objectsNewToThemLock: + del connection.objectsNewToThem[inv[1]] + hashes.append(inv[1]) except KeyError: continue if hashes: - connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(len(hashes)) + "".join(hashes))) - self.collectionOfInvs[iterator] = {} - iterator += 1 - iterator %= InvThread.size + connection.writeQueue.put(protocol.CreatePacket('inv', \ + addresses.encodeVarint(len(hashes)) + "".join(hashes))) + invQueue.iterate() self.stop.wait(1) - - def holdHash(self, stream, hashId): - i = random.randrange(0, InvThread.size) - if stream not in self.collectionOfInvs[i]: - self.collectionOfInvs[i][stream] = [] - self.collectionOfInvs[i][stream].append(hashId) - - def hasHash(self, hashId): - for streamlist in self.collectionOfInvs: - for stream in streamlist: - if hashId in streamlist[stream]: - return True - return False - - def hashCount(self): - retval = 0 - for streamlist in self.collectionOfInvs: - for stream in streamlist: - retval += len(streamlist[stream]) - return retval - - def close(self): - self.shutdown = True diff --git a/src/queues.py b/src/queues.py index 7c36d54a..223c7c3b 100644 --- a/src/queues.py +++ b/src/queues.py @@ -1,12 +1,15 @@ 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 = Queue.Queue() +invQueue = MultiQueue() +addrQueue = MultiQueue() portCheckerQueue = Queue.Queue() peerDiscoveryQueue = Queue.Queue() apiAddressGeneratorReturnQueue = Queue.Queue( -- 2.45.1 From 70c5929e92c7c3d6635d1c159de3fdd89013d0eb Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 4 Jul 2017 17:51:58 +0200 Subject: [PATCH 0822/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 91913 -> 91957 bytes src/translations/bitmessage_ru.ts | 309 ++++++++++++++++-------------- 2 files changed, 162 insertions(+), 147 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index f6e79656161ac4b6782468ae110b55ca9d5fa6b8..b0d1d886b8566e42577ef17983b78da1bd80f8cd 100644 GIT binary patch delta 3686 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 delta 3644 zcmZ`*d0bRw7k=Kk_s(|j+)2J8k{KDyqP zkO>?b0=w(&z|6j^^FaLPtj~}WV6My90Lc!h_hl|K8-dpe%w;M4@4#I) zJc$AftYhw7N`Q-`s$#JB?*#1)h2z;Gn2?aJaJ)k$PY6;tuUHF|S15+QS_`JU zqwu(s3@kA#0@sjTI!h5V<|Sd+s#xfF49FRxShUFqj2fpft&Rnpm5Q|5E?_;|6zOlz z4=FMhHv<)u6@@eFfdLB@Uxd^9QFj$(G6ne5T2VE#gfLC}K~cM?FR&s`adY)~BFlco zEqNB09Ikl4F9n*Wa#FfLWI4j=t{wpfyKwsT1X)uZXL;m4bx$JKJKqa9Va3^v+6(s1 zEY8u7+O;g0bG}|m0V+6GiSD(!z>SDa0vle=c^Z0yO`OR2M4IY=bDOx}I36hN!^N~w z=|5`c5}fV;wwJlwnlhm3ESK9B0p!|o1rh5h(1F}Z=>i2hpR3$P&vDsYwJI8LdfaJS z6x;^eEm-qb4-OsC`Zk<=5T>elNBi5($hX+!ir91h<4*Tf&6mKfa?+P3_$e%pu z1=dU8ziS#uj^p_Y3HCt9V!qbm9G&~~x6V8#Qtjq{Utt4$d0t?@IsqQC;Fv=;ze*VS zbUU!DMR2Qp3MRA)?lDBt9jgW37Y1PT2H}G{H;DCmAtH&mvn5=J3MFV$=a_`KuHO+x zB|>Zgm3qumVU0^Qn3F+BSrZL5cCL`&{>Fi)u-$DSa05c#^QB;YhY342k;6>s}tRs%8REN^W`mEaLO*K9va?Y`?u_#ob=Fyb!fqQC^btB z6hL&QCi$OsFv&`j9!!qiEH&nLcp!U^X3Jm0Xg8?QS1cH zd)lZxs%SrhHo9pXnC}&BOcePGnWUY6hXQTL)tcUXVRpXSq;MKOBhG8{9+Jaq2W^R0 zE3tK$wk))r0{T&VLVQ61KG2@6rp)9M+Vg9uUGtgtrw!h~g7ezD;SHpe7TUkIQD7t8 zL^i&JhEAiXNuVz9DHpZeRbX9TQClBRnLieF$+Xb)xNH)w@{B}^QnBBQ)4-q`;(${T zgkg&4tV{xaREl2H==W)TMQ_U4xnJX^aDv@n& z`t18`Vrh42i#L&DA}4K`9Rl1tD;-$*oEDCI(h&=~sLw;`h$mrM`anAJrW+3XNae9a z-ajE#u%#rec5f{k+bEsc>I1Bgld2yk0e)+wpXM8YzY?UY`etC|W2x?CFPPYvQPQuU zUZ?RoNqVu7u*&#Kr+#pZu$-amxsXWp+aJ2VbI#M&dr{XfmmDmP(m9$B0#63%oYN|Z zE4y@VEvIQLC+kLAcmd=6b^c+&v^m%6rg*di!5+E@CnFFRsEgd6OBLv*ThKxQ{a~px z9yOYP%i+3MQz&IPRJY16i^wuxmzd~9mAI!X_@x@Sx59&tu#3srPh8@H;TREsD z4a~knUiG7ihL0gg-oQ#oYB@RU3B6cikaLe7AO~J@ULN&pO_987#wgPIIC*z(s>tR> z`Nw=WpuIt^9zvu9I&J^VPW#xV)3&6@bq3m~9{l#!vcA>wlZkz40qKz2ZDg9Z75X72 zdutM$5qcNnGTLTS^sbj|z}%hm9zD0vDz#ky!8cT@!^_%SR*Ywf=B(sy<_c3d=gB*pt=9OKbxlsRWme|RyDZIfljO3JT?PG_ z@3uZ8SvPZ1&2Y|(_ca$*cV{l*32Z1Dd8W#v$& diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 19b1ddcc..3cd8fc43 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -58,12 +58,12 @@ 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -315,10 +315,10 @@ Please type the desired email address (including @mailchuck.com) below: Acknowledgement of the message received %1 - Сообщение доставлено в %1 + Доставлено в %1 - + Broadcast queued. Рассылка ожидает очереди. @@ -348,7 +348,7 @@ Please type the desired email address (including @mailchuck.com) below: Неизвестный статус: %1 %2 - + Not Connected Не соединено @@ -380,7 +380,7 @@ Please type the desired email address (including @mailchuck.com) below: 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, находящийся в той же папке, что и эта программа. + Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в той же папке, что и эта программа. Создайте резервную копию этого файла перед тем как будете его редактировать. @@ -388,7 +388,7 @@ Please type the desired email address (including @mailchuck.com) below: 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, находящийся в + Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в %1 Создайте резервную копию этого файла перед тем как будете его редактировать. @@ -400,7 +400,7 @@ 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. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в той же папке, что и эта программа. + Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в той же папке, что и эта программа. Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? (пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) @@ -409,7 +409,7 @@ 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. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.) - Вы можете управлять Вашими ключами, отредактировав файл keys.dat, находящийся в + Вы можете управлять Вашими ключами, редактируя файл keys.dat, находящийся в %1 Создайте резервную копию этого файла перед тем как будете его редактировать. Хотели бы Вы открыть этот файл сейчас? (пожалуйста, закройте Bitmessage до того как Вы внесёте в этот файл какие-либо изменения.) @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,67 +596,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1174,14 +1174,14 @@ Are you sure you want to delete the channel? %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% Sent - Отправленные + Отправлено @@ -1224,61 +1224,61 @@ Are you sure you want to delete the channel? Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. - + Error! Could not find sender address (your address) in the keys.dat file. Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. Выполнение работы, требуемой для отправки сообщения. Для адреса версии 2 (как этот), не требуется указание сложности. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 @@ -1288,9 +1288,9 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для отправки сообщения. - + Message sent. Waiting for acknowledgement. Sent on %1 - Сообщение отправлено. Ожидаем подтверждения. Отправлено на %1 + Отправлено. Ожидаем подтверждения. Отправлено в %1 @@ -1298,12 +1298,12 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для запроса ключа шифрования. - + Broadcasting the public key request. This program will auto-retry if they are offline. Рассылка запросов открытого ключа шифрования. Программа будет повторять попытки, если они оффлайн. - + Sending public key request. Waiting for reply. Requested at %1 Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %1 @@ -1323,7 +1323,7 @@ Receiver's required difficulty: %1 and %2 Отметить все сообщения как прочтенные - + Are you sure you would like to mark all messages read? Вы уверены, что хотите отметить все сообщения как прочтенные? @@ -1333,37 +1333,37 @@ Receiver's required difficulty: %1 and %2 Выполнение работы, требуемой для отправки рассылки. - + 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 объектов ожидают раздачи - + 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, возможно неправильное. Пожалуйста, проверьте ваши настройки. @@ -1432,77 +1432,77 @@ Receiver's required difficulty: %1 and %2 не рекомендовано для чанов - + Problems connecting? Try enabling UPnP in the Network Settings Проблемы подключения? Попробуйте включить UPnP в сетевых настройках. - + 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. - + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации? - + 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... Ожидание окончания синхронизации... @@ -1533,14 +1533,14 @@ Receiver's required difficulty: %1 and %2 MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. Сообщение в неизвестной кодировке. Возможно, вам следует обновить Bitmessage. - + Unknown encoding Неизвестная кодировка @@ -1848,77 +1848,77 @@ The 'Random Number' option is selected by default but deterministic ad Всего соединений: - + 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 кБ/с @@ -1928,30 +1928,45 @@ The 'Random Number' option is selected by default but deterministic ad Состояние сети - + 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 + Узел + + + + User agent + Название приложения + + + + TLS + TLS + newChanDialog -- 2.45.1 From 27f5de0f9cba114004ef9aa49a541dbc07b9a94c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 08:52:16 +0200 Subject: [PATCH 0823/1102] Unified random number provider - not used yet, just an inactive helper function - I received feedback that OpenSSL.rand isn't more secure than os.urandom. I read several debates/analyses about it and concur --- src/helper_random.py | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/helper_random.py diff --git a/src/helper_random.py b/src/helper_random.py new file mode 100644 index 00000000..a0fb08f1 --- /dev/null +++ b/src/helper_random.py @@ -0,0 +1,9 @@ +import os + +from pyelliptic.openssl import OpenSSL + +def randomBytes(n): + try: + return os.urandom(n) + except NotImplementedError: + return OpenSSL.rand(n) -- 2.45.1 From e00a02206b875c5aa8b3cb09e8ea2bf735ef7913 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 08:57:44 +0200 Subject: [PATCH 0824/1102] AddrThread - this thread is for spreading new/updated addresses in active connections, analogous to the InvThread - it doesn't do anything yet, this is just a dummy queue at the moment --- src/bitmessagemain.py | 4 ++++ src/network/addrthread.py | 30 ++++++++++++++++++++++++++++++ src/state.py | 1 + 3 files changed, 35 insertions(+) create mode 100644 src/network/addrthread.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index a2d951ed..461486f7 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -57,6 +57,7 @@ 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 # Helper Functions @@ -276,6 +277,9 @@ class Main: downloadThread = DownloadThread() downloadThread.daemon = True downloadThread.start() + state.addrThread = AddrThread() + state.addrThread.daemon = True + state.addrThread.start() connectToStream(1) diff --git a/src/network/addrthread.py b/src/network/addrthread.py new file mode 100644 index 00000000..a6c401ab --- /dev/null +++ b/src/network/addrthread.py @@ -0,0 +1,30 @@ +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="AddrThread") + self.initStop() + self.name = "AddrThread" + + def run(self): + while not state.shutdown: + chunk = [] + while True: + try: + data = addrQueue.get(False) + chunk.append((data[0], data[1])) + except Queue.Empty: + break + + #finish + + addrQueue.iterate() + self.stop.wait(1) diff --git a/src/state.py b/src/state.py index 618b6c92..1b12831e 100644 --- a/src/state.py +++ b/src/state.py @@ -24,6 +24,7 @@ sqlReady = False # set to true by sqlTread when ready for processing maximumNumberOfHalfOpenConnections = 0 invThread = None +addrThread = None ownAddresses = {} -- 2.45.1 From 773d91bbe27b8b5eeebaedfe62a302eac2ef0535 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:01:40 +0200 Subject: [PATCH 0825/1102] Unknown object log entry less severe - unnecessarily classified as critical - fixes #1023 --- src/class_objectProcessor.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index d146dfd2..5d289fcc 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -69,7 +69,10 @@ 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: - logger.critical('Error! Bug! The class_objectProcessor was passed an object type it doesn\'t recognize: %s' % str(objectType)) + 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")) except varintDecodeError as e: -- 2.45.1 From 9d09f9f3cee36f87f88c68d96d69f61669398a1e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:07:00 +0200 Subject: [PATCH 0826/1102] Reduce severity of socks connectivity errors - Fixes #1024 - Fixes #1019 --- src/network/socks4a.py | 6 ++++++ src/network/socks5.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 61f3ec7d..350e163e 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -84,6 +84,12 @@ class Socks4aConnection(Socks4a): self.writeQueue.put(self.destination[0] + chr(0x00).encode()) self.set_state("pre_connect", 0) + def state_pre_connect(self): + try: + Socks4a.state_pre_connect(self) + except Socks4aError as e: + self.handle_close(e.message) + class Socks4aResolver(Socks4a): def __init__(self, host): diff --git a/src/network/socks5.py b/src/network/socks5.py index 89c3c9b2..f2bc83e4 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -156,6 +156,12 @@ class Socks5Connection(Socks5): self.writeQueue.put(struct.pack(">H", self.destination[1])) self.set_state("pre_connect", 0) + def state_pre_connect(self): + try: + Socks5.state_pre_connect(self) + except Socks5Error as e: + self.handle_close(e.message) + class Socks5Resolver(Socks5): def __init__(self, host): -- 2.45.1 From a0bbd21efcd95a7bff9984f52a7cf0e98d8ecea8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:17:01 +0200 Subject: [PATCH 0827/1102] Add ratings to peers - outbound peers now have a rating - it's also shown in the network status tab - currently it's between -1 to +1, changes by 0.1 steps and uses a hyperbolic function 0.05/(1.0 - rating) to convert rating to probability with which we should connect to that node when randomly chosen - it increases when we successfully establish a full outbound connection to a node, and decreases when we fail to do that - onion nodes have priority when using SOCKS --- src/bitmessageqt/networkstatus.py | 15 ++++++++-- src/bitmessageqt/networkstatus.ui | 5 ++++ src/class_singleCleaner.py | 9 ++++-- src/defaultKnownNodes.py | 18 ++++++------ src/helper_bootstrap.py | 46 +++++++++++++++---------------- src/knownnodes.py | 22 ++++++++++++++- src/network/bmproto.py | 43 +++++++++++++++++------------ src/network/connectionchooser.py | 19 ++++++++++++- src/network/connectionpool.py | 5 +++- src/network/tcp.py | 34 +++++++++++++---------- 10 files changed, 143 insertions(+), 73 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 4ede68f7..2609a3c4 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -4,6 +4,7 @@ import shared from tr import _translate from inventory import Inventory, PendingDownloadQueue, PendingUpload +import knownnodes import l10n import network.stats from retranslateui import RetranslateMixin @@ -87,15 +88,23 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): self.tableWidgetConnectionCount.setItem(0, 0, QtGui.QTableWidgetItem("%s:%i" % (i.destination.host, i.destination.port)) ) - self.tableWidgetConnectionCount.setItem(0, 1, + self.tableWidgetConnectionCount.setItem(0, 2, QtGui.QTableWidgetItem("%s" % (i.userAgent)) ) - self.tableWidgetConnectionCount.setItem(0, 2, + self.tableWidgetConnectionCount.setItem(0, 3, QtGui.QTableWidgetItem("%s" % (i.tlsVersion)) ) - self.tableWidgetConnectionCount.setItem(0, 3, + self.tableWidgetConnectionCount.setItem(0, 4, QtGui.QTableWidgetItem("%s" % (",".join(map(str,i.streams)))) ) + try: + # FIXME hard coded stream no + rating = knownnodes.knownNodes[1][i.destination]['rating'] + except KeyError: + rating = "-" + self.tableWidgetConnectionCount.setItem(0, 1, + QtGui.QTableWidgetItem("%s" % (rating)) + ) if i.isOutbound: brush = QtGui.QBrush(QtGui.QColor("yellow"), QtCore.Qt.SolidPattern) else: diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui index 993cf1c6..f9cc57c4 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -117,6 +117,11 @@ Peer + + + Rating + + User agent diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index e6d98989..c21d8cb1 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -98,9 +98,12 @@ class singleCleaner(threading.Thread, StoppableThread): with knownnodes.knownNodesLock: for stream in knownnodes.knownNodes: for node in knownnodes.knownNodes[stream].keys(): - if now - knownnodes.knownNodes[stream][node] > 2419200: # 28 days - shared.needToWriteKownNodesToDisk = True - del knownnodes.knownNodes[stream][node] + try: + if now - knownnodes.knownNodes[stream][node]["lastseen"] > 2419200: # 28 days + shared.needToWriteKownNodesToDisk = True + del knownnodes.knownNodes[stream][node] + except TypeError: + print "Error in %s" % (str(node)) # Let us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: diff --git a/src/defaultKnownNodes.py b/src/defaultKnownNodes.py index 5559f1a5..05b65014 100644 --- a/src/defaultKnownNodes.py +++ b/src/defaultKnownNodes.py @@ -12,15 +12,15 @@ def createDefaultKnownNodes(appdata): stream1 = {} #stream1[state.Peer('2604:2000:1380:9f:82e:148b:2746:d0c7', 8080)] = int(time.time()) - stream1[state.Peer('5.45.99.75', 8444)] = int(time.time()) - stream1[state.Peer('75.167.159.54', 8444)] = int(time.time()) - stream1[state.Peer('95.165.168.168', 8444)] = int(time.time()) - stream1[state.Peer('85.180.139.241', 8444)] = int(time.time()) - stream1[state.Peer('158.222.217.190', 8080)] = int(time.time()) - stream1[state.Peer('178.62.12.187', 8448)] = int(time.time()) - stream1[state.Peer('24.188.198.204', 8111)] = int(time.time()) - stream1[state.Peer('109.147.204.113', 1195)] = int(time.time()) - stream1[state.Peer('178.11.46.221', 8444)] = 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} ############# Stream 2 ################# stream2 = {} diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 33a533ca..7c7456e1 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -9,30 +9,31 @@ 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: - # We shouldn't have to use the knownnodes.knownNodesLock because this had - # better be the only thread accessing knownNodes right now. - pickleFile = open(state.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(): - knownnodes.knownNodes[stream] = {} - for node_tuple in nodes.items(): - try: - host, (port, lastseen) = node_tuple - peer = state.Peer(host, port) - except: - peer, lastseen = node_tuple - knownnodes.knownNodes[stream][peer] = lastseen + 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) 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'): - knownnodes.knownNodes[1][state.Peer(BMConfigParser().get('bitmessagesettings', 'onionhostname'), BMConfigParser().getint('bitmessagesettings', 'onionport'))] = int(time.time()) + 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.') raise SystemExit @@ -47,17 +48,17 @@ def dns(): try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - knownnodes.knownNodes[1][state.Peer(item[4][0], 8080)] = int(time.time()) + addKnownNode(1, state.Peer(item[4][0], 8080)) except: logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') try: for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - knownnodes.knownNodes[1][state.Peer(item[4][0], 8444)] = int(time.time()) + addKnownNode(1, state.Peer(item[4][0], 8444)) except: logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': - knownnodes.knownNodes[1][state.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) + 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) @@ -90,7 +91,6 @@ def dns(): else: if ip is not None: logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') - knownnodes.knownNodes[1][state.Peer(ip, port)] = time.time() + addKnownNode(1, state.Peer(ip, port)) else: logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') - diff --git a/src/knownnodes.py b/src/knownnodes.py index 8f566d43..86d39cbe 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -16,10 +16,30 @@ def saveKnownNodes(dirName = None): with open(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]) < BMConfigParser().get("knownnodes", "maxnodes"): return with knownNodesLock: - oldestList = sorted(knownNodes[recAddrStream], key=knownNodes[recAddrStream].get)[:knownNodesTrimAmount] + oldestList = sorted(knownNodes[recAddrStream], key=lambda x: x['lastseen'])[:knownNodesTrimAmount] for oldest in oldestList: del knownNodes[recAddrStream][oldest] diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 0c70f12e..c45f9ca3 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -328,16 +328,21 @@ class BMProto(AdvancedDispatcher, ObjectTracker): decodedIP = protocol.checkIPAddress(ip) if stream not in state.streamsInWhichIAmParticipating: continue - #print "maybe adding %s in stream %i to knownnodes (%i)" % (decodedIP, stream, len(knownnodes.knownNodes[stream])) if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: peer = state.Peer(decodedIP, port) - if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer] > seenTime: + if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer]["lastseen"] > seenTime: continue if len(knownnodes.knownNodes[stream]) < BMConfigParser().get("knownnodes", "maxnodes"): with knownnodes.knownNodesLock: - knownnodes.knownNodes[stream][peer] = seenTime - #knownnodes.knownNodes[stream][peer] = seenTime - #AddrUploadQueue().put((stream, peer)) + 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)) return True def bm_command_portcheck(self): @@ -449,18 +454,22 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def assembleAddr(peerList): if isinstance(peerList, state.Peer): peerList = (peerList) - # TODO handle max length, now it's done by upper layers - payload = addresses.encodeVarint(len(peerList)) - for address in peerList: - 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 - return protocol.CreatePacket('addr', payload) + 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 def handle_close(self, reason=None): self.set_state("close") diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 0770bfa6..2cce5036 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -7,6 +7,7 @@ from queues import portCheckerQueue, peerDiscoveryQueue import state def chooseConnection(stream): + haveOnion = BMConfigParser().safeGet("bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' if state.trustedPeer: return state.trustedPeer try: @@ -17,5 +18,21 @@ def chooseConnection(stream): retval = peerDiscoveryQueue.get(False) peerDiscoveryQueue.task_done() except Queue.Empty: - return random.choice(knownnodes.knownNodes[stream].keys()) + for i 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 and peer.host.endswith('.onion') and rating > 0: + rating *= 10 + if rating > 1: + rating = 1 + try: + if 0.05/(1.0-rating) > random.random(): + return peer + except ZeroDivisionError: + return peer + raise ValueError return retval diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index ae76c318..9328720f 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -135,7 +135,10 @@ class BMConnectionPool(object): pending = len(self.outboundConnections) - established if established < BMConfigParser().safeGetInt("bitmessagesettings", "maxoutboundconnections"): for i in range(state.maximumNumberOfHalfOpenConnections - pending): - chosen = chooseConnection(random.choice(self.streams)) + try: + chosen = chooseConnection(random.choice(self.streams)) + except ValueError: + continue if chosen in self.outboundConnections: continue if chosen.host in self.inboundConnections: diff --git a/src/network/tcp.py b/src/network/tcp.py index bd925063..120cfdce 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -98,6 +98,8 @@ class TCPConnection(BMProto, TLSDispatcher): UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.antiIntersectionDelay(True) self.fullyEstablished = True + if self.isOutbound: + knownnodes.increaseRating(self.destination) self.sendAddr() self.sendBigInv() @@ -117,7 +119,7 @@ class TCPConnection(BMProto, TLSDispatcher): 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)} + if v["lastseen"] > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} elemCount = len(filtered) if elemCount > maxAddrCount: elemCount = maxAddrCount @@ -126,25 +128,21 @@ class TCPConnection(BMProto, TLSDispatcher): # 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 > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + 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 > (int(time.time()) - shared.maximumAgeOfNodesThatIAdvertiseToOthers)} + 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, timestamp in addrs[substream]: - templist.append((substream, peer, timestamp)) - if len(templist) >= BMProto.maxAddrCount: - self.writeQueue.put(BMProto.assembleAddr(templist)) - templist = [] - # flush + for peer, params in addrs[substream]: + templist.append((substream, peer, params["lastseen"])) if len(templist) > 0: self.writeQueue.put(BMProto.assembleAddr(templist)) @@ -163,16 +161,22 @@ class TCPConnection(BMProto, TLSDispatcher): self.connectedAt = time.time() def handle_read(self): -# try: TLSDispatcher.handle_read(self) -# except socket.error as e: -# logger.debug("%s:%i: Handle read fail: %s" % (self.destination.host, self.destination.port, str(e))) + 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 def handle_write(self): -# try: TLSDispatcher.handle_write(self) -# except socket.error as e: -# logger.debug("%s:%i: Handle write fail: %s" % (self.destination.host, self.destination.port, str(e))) + + def handle_close(self, reason=None): + if self.isOutbound and not self.fullyEstablished: + knownnodes.decreaseRating(self.destination) + BMProto.handle_close(self, reason) class Socks5BMConnection(Socks5Connection, TCPConnection): -- 2.45.1 From d086781ce82be6e19d8b7706a21d463afe4d6073 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:19:18 +0200 Subject: [PATCH 0828/1102] AddrQueue fix - forgot to commit import --- src/network/bmproto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index c45f9ca3..9ccd69ca 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -21,7 +21,7 @@ from network.proxy import Proxy, ProxyError, GeneralProxyError import addresses from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue, portCheckerQueue, invQueue +from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue import shared import state import protocol -- 2.45.1 From 846fced0a21a15f9f7d98e610b173edb07922b9d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:19:56 +0200 Subject: [PATCH 0829/1102] Remove obsolete inactive code --- src/network/advanceddispatcher.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 1abc7975..0945d764 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -41,11 +41,6 @@ class AdvancedDispatcher(asyncore.dispatcher): if not self.connected: return maxLoop = 20 -# try: -# sys._getframe(200) -# logger.error("Stack depth warning") -# except ValueError: -# pass while maxLoop > 0: try: if getattr(self, "state_" + str(self.state))() is False: -- 2.45.1 From fc19e4119ad25e1436f71f63e64bab5e66dfeeb9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:25:49 +0200 Subject: [PATCH 0830/1102] Download thread updates - now tracks downloads globally too, so it doesn't request the same object from multiple peers at the same time - retries at the earliest every minute - stops trying to download an object after an hour - minor fixes in retrying downloading invalid objects --- src/bitmessagemain.py | 6 ++-- src/network/bmproto.py | 53 ++++++++++++++----------------- src/network/connectionpool.py | 2 +- src/network/downloadthread.py | 29 +++++++++++++---- src/network/objectracker.py | 5 +-- src/network/receivequeuethread.py | 2 +- src/state.py | 1 + 7 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 461486f7..88fa3c1d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -274,12 +274,12 @@ class Main: state.invThread = InvThread() state.invThread.daemon = True state.invThread.start() - downloadThread = DownloadThread() - downloadThread.daemon = True - downloadThread.start() state.addrThread = AddrThread() state.addrThread.daemon = True state.addrThread.start() + state.downloadThread = DownloadThread() + state.downloadThread.daemon = True + state.downloadThread.start() connectToStream(1) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 9ccd69ca..b08b6d61 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -275,47 +275,24 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object.checkEOLSanity() self.object.checkAlreadyHave() except (BMObjectExpiredError, BMObjectAlreadyHaveError) as e: - for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ - network.connectionpool.BMConnectionPool().outboundConnections.values(): - try: - with connection.objectsNewToThemLock: - del connection.objectsNewToThem[self.object.inventoryHash] - except KeyError: - pass - try: - with connection.objectsNewToMeLock: - del connection.objectsNewToMe[self.object.inventoryHash] - except KeyError: - pass + BMProto.stopDownloadingObject(self.object.inventoryHash) raise e try: self.object.checkStream() except (BMObjectUnwantedStreamError,) as e: - for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ - network.connectionpool.BMConnectionPool().outboundConnections.values(): - try: - with connection.objectsNewToMeLock: - del connection.objectsNewToMe[self.object.inventoryHash] - except KeyError: - pass - if not BMConfigParser().get("inventory", "acceptmismatch"): - try: - with connection.objectsNewToThemLock: - del connection.objectsNewToThem[self.object.inventoryHash] - except KeyError: - pass + BMProto.stopDownloadingObject(self.object.inventoryHash, BMConfigParser().get("inventory", "acceptmismatch")) if not BMConfigParser().get("inventory", "acceptmismatch"): raise e - self.object.checkObjectByType() + try: + self.object.checkObjectByType() + objectProcessorQueue.put((self.object.objectType, self.object.data)) + except BMObjectInvalidError as e: + BMProto.stopDownloadingObject(self.object.inventoryHash, True) Inventory()[self.object.inventoryHash] = ( self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) - objectProcessorQueue.put((self.object.objectType,self.object.data)) - #DownloadQueue().task_done(self.object.inventoryHash) invQueue.put((self.object.streamNumber, self.object.inventoryHash, self)) - #ObjUploadQueue().put(UploadElem(self.object.streamNumber, self.object.inventoryHash)) - #broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) return True def _decode_addr(self): @@ -471,6 +448,22 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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: + with connection.objectsNewToMeLock: + del connection.objectsNewToMe[hashId] + except KeyError: + pass + if not forwardAnyway: + try: + with connection.objectsNewToThemLock: + del connection.objectsNewToThem[hashId] + except KeyError: + pass + def handle_close(self, reason=None): self.set_state("close") if reason is None: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 9328720f..c4aa53d8 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -44,7 +44,7 @@ class BMConnectionPool(object): del i.objectsNewToMe[hashid] except KeyError: with i.objectsNewToThemLock: - i.objectsNewToThem[hashid] = True + i.objectsNewToThem[hashid] = time.time() if i == connection: try: with i.objectsNewToThemLock: diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index a8d3e1f7..9c7e92da 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,4 +1,5 @@ import threading +import time import addresses #from bmconfigparser import BMConfigParser @@ -9,26 +10,38 @@ from network.connectionpool import BMConnectionPool import protocol class DownloadThread(threading.Thread, StoppableThread): - maxPending = 500 - requestChunk = 1000 + maxPending = 50 + requestChunk = 100 + requestTimeout = 60 + cleanInterval = 60 + requestExpires = 600 def __init__(self): threading.Thread.__init__(self, name="DownloadThread") self.initStop() self.name = "DownloadThread" logger.info("init download thread") + self.pending = {} + self.lastCleaned = time.time() + + def cleanPending(self): + deadline = time.time() - DownloadThread.requestExpires + self.pending = {k: v for k, v in self.pending.iteritems() if v >= deadline} + self.lastCleaned = time.time() def run(self): while not self._stopped: requested = 0 for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - # this may take a while, but it needs a consistency so I think it's better + now = time.time() + timedOut = now - DownloadThread.requestTimeout + # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: - downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if not v))) + downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in self.pending and self.pending[k] > timedOut))) if downloadPending >= DownloadThread.maxPending: continue # keys with True values in the dict - request = list((k for k, v in i.objectsNewToMe.iteritems() if v)) + request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in self.pending or self.pending[k] < timedOut)) if not request: continue if len(request) > DownloadThread.requestChunk - downloadPending: @@ -36,9 +49,13 @@ class DownloadThread(threading.Thread, StoppableThread): # mark them as pending for k in request: i.objectsNewToMe[k] = False + self.pending[k] = now payload = addresses.encodeVarint(len(request)) + ''.join(request) i.writeQueue.put(protocol.CreatePacket('getdata', payload)) logger.debug("%s:%i Requesting %i objects", i.destination.host, i.destination.port, len(request)) requested += len(request) - self.stop.wait(1) + if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: + self.cleanPending() + if not requested: + self.stop.wait(1) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 5c0ad147..a7295c21 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -28,6 +28,7 @@ class ObjectTracker(object): invCleanPeriod = 300 invInitialCapacity = 50000 invErrorRate = 0.03 + trackingExpires = 3600 def __init__(self): self.objectsNewToMe = {} @@ -62,9 +63,9 @@ class ObjectTracker(object): with self.objectsNewToMeLock: tmp = self.objectsNewToMe.copy() self.objectsNewToMe = tmp + deadline = time.time() - ObjectTracker.trackingExpires with self.objectsNewToThemLock: - tmp = self.objectsNewToThem.copy() - self.objectsNewToThem = tmp + self.objectsNewToThem = {k: v for k, v in self.objectsNewToThem.iteritems() if v >= deadline} self.lastCleaned = time.time() def hasObj(self, hashid): diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 8360ab45..137131c5 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -70,7 +70,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): with connection.objectsNewToThemLock: for objHash in Inventory().unexpired_hashes_by_stream(stream): bigInvList[objHash] = 0 - connection.objectsNewToThem[objHash] = True + connection.objectsNewToThem[objHash] = time.time() objectCount = 0 payload = b'' # Now let us start appending all of these hashes together. They will be diff --git a/src/state.py b/src/state.py index 1b12831e..08da36eb 100644 --- a/src/state.py +++ b/src/state.py @@ -25,6 +25,7 @@ maximumNumberOfHalfOpenConnections = 0 invThread = None addrThread = None +downloadThread = None ownAddresses = {} -- 2.45.1 From fe0664640ea2c37421289e4e88e4ed6d99896ec0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 5 Jul 2017 09:27:52 +0200 Subject: [PATCH 0831/1102] Migrate antiIntersectionDelay to asyncore - implemented by ignoring getdata during the delay rather than sleeping as it was in the threaded model - it can happen that a valid getdata request is received during the delay. A node should be implemented in a way that retries to download, that may not be the case with older PyBitmessage versions or other implementations --- src/network/bmproto.py | 14 ++++---------- src/network/receivequeuethread.py | 2 +- src/network/tcp.py | 8 ++++---- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index b08b6d61..abf2f0ec 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -234,17 +234,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): def bm_command_getdata(self): items = self.decode_payload_content("L32s") -# if time.time() < self.skipUntil: -# print "skipping getdata" -# return True + # skip? + if time.time() < self.skipUntil: + return True for i in items: - #print "received getdata request for item %s" % (hexlify(i)) - #logger.debug('received getdata request for item:' + hexlify(i)) - #if i in ObjUploadQueue.streamElems(1): - if False: - self.antiIntersectionDelay() - else: - self.receiveQueue.put(("object", i)) + self.receiveQueue.put(("object", i)) return True def bm_command_inv(self): diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 137131c5..442c755a 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -54,7 +54,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): connection.writeQueue.put(protocol.CreatePacket('object', Inventory()[objHash].payload)) except KeyError: connection.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.' % (connection.destination,)) + logger.info('%s asked for an object we don\'t have.', connection.destination) def command_biginv(self, connection, dummy): def sendChunk(): diff --git a/src/network/tcp.py b/src/network/tcp.py index 120cfdce..c2052df1 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -29,7 +29,7 @@ from network.tls import TLSDispatcher import addresses from bmconfigparser import BMConfigParser -from queues import objectProcessorQueue, portCheckerQueue, UISignalQueue +from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue import shared import state import protocol @@ -77,7 +77,7 @@ class TCPConnection(BMProto, TLSDispatcher): 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 + UploadQueue.queueCount/2) + 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 @@ -86,9 +86,9 @@ class TCPConnection(BMProto, TLSDispatcher): if initial: self.skipUntil = self.connectedAt + delay if self.skipUntil > time.time(): - logger.debug("Skipping processing for %.2fs", self.skipUntil - time.time()) + logger.debug("Initial skipping processing getdata for %.2fs", self.skipUntil - time.time()) else: - logger.debug("Skipping processing due to missing object for %.2fs", self.skipUntil - time.time()) + logger.debug("Skipping processing getdata due to missing object for %.2fs", self.skipUntil - time.time()) self.skipUntil = time.time() + delay def set_connection_fully_established(self): -- 2.45.1 From 27f9fb0237465d2d9580e96fb140913d273916f2 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 5 Jul 2017 17:09:30 +0200 Subject: [PATCH 0832/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 91957 -> 92019 bytes src/translations/bitmessage_ru.ts | 45 +++++++++++++++++------------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index b0d1d886b8566e42577ef17983b78da1bd80f8cd..f298a70d7e40e8131fe5229ca83b9eb7318c59f5 100644 GIT binary patch delta 897 zcmW+!ZA?>V7=505-+SA8-+ov{D|Ylk6gxE9)!AO>EX}A@tO)B278QOlA&4T=FqVJ` zvJjlpeb_t_6XM5`NgPf^;|R=XWGZM(O0p2Mh;h*@xWoXPnPdrm?R7uioaD_p&y(kz z(>tvEGproW&}INY0MJ;F%33(nIS*j#B7mL%!1mREn`=|0C7E@g^nVHXVFsw(viMAa zWm8Pxbn2>sFH#SDxSkYDVi8rKJEsJawatL5uR&RFK0wFE2L(o{14B~y zZAznoLo|VYETt^TkGE)pfT zfhjiU%w~Xp7qf7mI5vL|ixzhS{87OQ)6W2^8rjFQjsVU$$EtglihBoWkR`Pw`(->& zu!ksD+2{IBX=|+pT+^={xUd$`{+!M!ZfvJPWuX*VP7{h(kIz*%c1;0#|EAfh;hInn zeAWU`zEeFG9|J5iDW;m*Q}w|nu_L;b+Evqa*3xz|0#Gn)*&E<2z}OjTwCtDGIO(Ouk7cyPYT_xXwi?<+E&cL@u;2oHZS}cc>wHh1 z$ojfIYlAT4t>0+Sx-=fm(zjO$QoKvw@h}K5w*G&_`A77Y@+W}iY`yc(7Xazs_4E1D zBGq>NQt}nRPbc)Bx$vm7UmqA2={mllux8*Ps?ZEA%UmF#Z9`nwTDB%1jG^H6ir}@36Nx*eq@X^8!fJM!G ze5Maz`d2=ly#p}hrl4+WH*CAt9Tzh>HR^__QHLJERdiSPX$Nih_l}6Rb&X9=Zf}gA?LFCM!;2fox$5)z?H4e_dTKn zp4-%6GcitSn;WZW%x0=hwSZepI<`FCR%h?4vtzH_aIkC^Wbd&8wt|J(yH;U1sBhj! Um7mtu*BpK1Mt5J12Q!NP1IGRS;Q#;t delta 895 zcmW-fe@xVM7{}kweSh42zu)`ODXG`Rog{dHgX^ffEA;Lr$0ee0F+)(nR>@QvpaX2d zgo=$NMc(zqYz%U3wgrF0`oSohbCtDfJGOSY1`V?x=*Ey%W^NYLXZ`iwp1t?p^E~g@ z%^78CMoHyp761W|XE~j_d5!&7;6M>D832w{fc8C@u1mT?P(C^ZN?w6FE{Wj*nD-`x zUP@o^(wFIZAKlFg)zdm|qV;($)F15zRh&Y@R1^rAvA?4X^jHLq>Yz{?4^zmr?GMh7 zmr{I#{N&|alb_ODZSt6Q+~QVKk_P#LsZS(EBrk2?CMo8+WSX--39|idx+Zr3OBTuc ziX!r6cuMjWZjp-PlfVaV>4EHfKzLaST0aMExGII(dqEF(urQ6@fmfrY5~+hT&;$+Pt^InVvTqK z52<1233LD17*IZA9@y;yRd(@Z^)SUbV)i?$ED!&_44nSPvL{*xN_6r`^MENa%ZkNM z_i@k?rZ#T1c(ooav+^d$)y=~epYvdri5a#3j)Tfm#?w99K@NxUa(6$-K4GLT&H*FWjFD^{wCO`$(Y$%bjoIgx z#iweGxyoUnsM}at;{)z|Yb zCo6DiXPa@D0^DWP)2o~@{N&~pqpdW5(f(U)z6f&LS3P!6?)MIV!99Q$a+J1pfwrA> z1i$it%Bmb&-GU1DYdmHRyK)?-=LBzkA3M%@W`XvMVВсего соединений: - + 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 # № потока @@ -1888,37 +1888,37 @@ The 'Random Number' option is selected by default but deterministic ad - + 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 кБ/с @@ -1928,27 +1928,27 @@ The 'Random Number' option is selected by default but deterministic ad Состояние сети - + 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 открытых ключей. @@ -1959,11 +1959,16 @@ The 'Random Number' option is selected by default but deterministic ad + Rating + Рейтинг + + + User agent Название приложения - + TLS TLS -- 2.45.1 From 1dbf98d7f74c783ec1aeccf1d3825fa2fda4df2e Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 6 Jul 2017 00:06:05 +0200 Subject: [PATCH 0833/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 65563 -> 65615 bytes src/translations/bitmessage_ja.ts | 49 ++++++++++++++++-------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index d9acc50c19b7d0bde1dd7fc8242ce639528ca365..d5116555b3041a779cd40a5be68969fc0bd41510 100644 GIT binary patch delta 872 zcmXAnaZHqT7{|ZA_ulutd*9!2cnV$E;H?%i+Vp~ToY{`E@MbpU0*9w1D@_J8MU7xX zHjiRBrP{bXFpEfYqZ(}ijhyL5V0P}J9W&ZeOTf@t>YdCun+x1q~KI#yDafXt@ z66K@jbn<{{rPVI32 zdiHXTzSKNiJFcxzep^oST9!HI(l>v)z%<(_UANq0`r&$Zw05Q5_2M*e`y7RIzY*3a zws4JW^VFgjES+-Mn~w*9Ri*Yr8#92}2b9z+g`a$OuY0Fs_3fL$u5QQX!ZL>X3)R^V zDKqJG-|l5fD;)*OP#RS@EF)+n?;iuse?ad$RxBOPHRXPGj?c_xo7lk*g5nPEhCZ`u z7YEHXm~Tw^fKO8X*W{vkaQk)Oa@6dcy$7_ZW^dtL;P+W`AhHNVub8JLQ`&vO93JIa zew$ALBTKm=sNArOuVl*GybkB*sKp3wtChuPIHf)&OCB)bYgO{~#^*R?Oul=dnRT~p z8ye@Y?#a%JMZoCuvdefHc=cGy}+As`SXXxz)zO^wSfuzahx(uk2p&{ z({BWv`!;+GT%D#m)8YYin1#x08eKATjGNBOjTd?LZqj6>_?z~~h}cST=@pk~LDuAt zIbF9(p5P@3xfZir3}zwKo4p*+FQn$z)B%(GQ+YTtXMO~HtDp@mIsG)e~X0t&s z&B%T+X+8*s2`-T>!5DREh?`3#N;Y-o;RfLkN*Wjnq5+L#bJ=3uZnD2la__m{J?DJq zR=f0NyVSKxH3KLFem)t?aoaxt_HG0sGeG?|;P+r`SIChI`MXbmrD`ZcB0p?_sXD-M zES7Mwb+MG2m6OcEte$FFc3vmK2aW)DR`BL<36L*iPxBW3I*uCUQ;t#UVLtW+8O+7j z&@%HdgK`893sX>Vu~upnLTnW!gf@1F{GyA!MYUq7qe4hp-v$z+!h+Nc3|!j6Zb_3@&NdAl5*lev-RyhO= zT$HvOe*l3t>7A@@U?d^coiE_t2IxmAtd>bvmNszq0OiYVdEIify$)Dtk~_C>PUEC} z;w66D?UnmhxTdiP8S?s#vk&C^woHlLuZ; zIf~1ETKV`e7rk|}a}NXpO&+_~{Nkerz`j9qRmm=3{w%ecI)wRqB%3`v$YQfsxV%V>W|x|!8tDPxr-RgE zUY|LV*7Wzee0-y21-XLjlVq4Zg;A}3A1B=lY7Mi+z*ianqcN@>t+@|OS808Bp8#Ew zcCO?fzUCijvznc!Xrt|M9?2=~mkutpBCY*a!`&P&(3X4o?CD9WQ(fvudd9H;7m%P% zwY0EYue|gWI2_Y={L5Ey`xX7&$g9BR)B0yeq8zvCT_Z{0;1j)XqKwD8n$oKC*;_06 z)Q8;fVzZvy-UB$HFJ-!c3&Z+SZUd0)A;0ER?UqBY^#gO?Q>*6U{pi<9goQ;)X>RqZ zWjZp!i#Sgi`hIqkTJ$j6M27BRLzLE=ipFNG4|lBNlN{EkPAhQZhRu_|7Es1*MNKWh zOu$xr-3g>l*j|2ycjnq->bLkDn{3CE-vYZswn66<5FE9gF}S^7t+Z_MDcJ{jss5(6 ROV7vmWb`KDIX8=n{{x2TD475N diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 65a5c57d..3aa2723e 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -1841,37 +1841,37 @@ The 'Random Number' option is selected by default but deterministic ad 接続数: - + 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 # ストリーム # @@ -1881,37 +1881,37 @@ The 'Random Number' option is selected by default but deterministic ad - + 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/秒 @@ -1921,42 +1921,47 @@ The 'Random Number' option is selected by default but deterministic ad ネットワークの状態 - + 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 ピア - + + Rating + 評価 + + + User agent ユーザーエージェント - + TLS TLS -- 2.45.1 From 83e60d231a60195c2d01e0f13665bd00cd751471 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 6 Jul 2017 01:22:28 +0200 Subject: [PATCH 0834/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 89830 -> 89888 bytes src/translations/bitmessage_pl.ts | 49 ++++++++++++++++-------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index ad4818c65e659d34fa86c17fb019d922afa09297..ab80193018c5ae2ea21ef7d311873aab5f66d209 100644 GIT binary patch delta 923 zcmW-fZA@Eb6vzLkz4x~F-cm+kl$X%5MOHCk6&Bjb*4Ei|mc_L}!s-;JY`hE-ifm$( zMK;r*OkDywt1ra8pw7tRz-bo7lIr$>2p{SfvY4R|HDRb>j75nrkc_2q!2cR63|M6haCY$;Y@QkQWO~9d@pqiq=x@dkA?Jbk1}*ndI2@`lg}PLh}U zIZaNw#<$5$-*S<`O=;d^aMC{RFhmUD98MXI(Q)<}oixu4#z20=Fl%iDnL~zK(h*?6 zV6?m?gQ|P^ve89-JZH3LoichldqJCvjlM`RXt$AN$#3wj;qQHB;UB0 z&HJ?!jEn%^-;u)U-+==i(t+$#AZ^Gc?~*#Ho>AI$Om5Mxku4V5L811j{q}g5Fr5$P#mx8Rd z|4<3c&;76Dcu?!D{}uGGNgG=H2bh}DM*V+_y{EJ-0B!62iHp4}3K% zUfQJ(%>+S?c3xGT8`kujFE4{0OX{=XBv87dFWFqcZxi}baXZLe!j+m=OCgEo!wRLSh_{i;mqKdSeo*uZUKoo3;R|>vy-uu;qgj1N;9(x12sLq* zy!0O5rXZc>Vkt-;ah>EPKX*z=Y4guKAswV7M=f3&*`jAg9I`blMHy}sH#cz=T zIguOzZrqV;vVQDOnrXb4+QMW1IsY5drtXtV?I#AYJP`cJu|B| zp1v!E`yZ+JfzjPO2MS&{ z27mnrn4C1u#r_sS_i{jY(LS!$z0}67x>xTq?Qe;O6z<_ZJst{}$&1Ut@IABP-x1LI z8|ID!8$kLhvv+@wNc5t4?CWXZ_$G7kT0)q(mX~y|@2WZV`hqZPhdEs{0F>S}=be6F z@q#(OvIA7U$WbGr_u5{m9TJ*8&KO=g%0ot+p5&b2*Du+AJaA3a?RU1DZM25>nkjN} z)(lc7FPUATio81wj|-i6-m)hTw4%!qEO{8vS2!wm?*)a)Q90=Wt*LRWe?-)xNaG<} z#QlWh==2vr<}=5zXG%n?JI-X6L65cbZCgZ5?-IQk>nXF3m)Xgsji(=?v$g*L-g5eE diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index 93f72222..02571284 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -1847,37 +1847,37 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 przekazów. - + Inventory lookups per second: 0 Zapytań o elementy na sekundę: 0 - + Objects to be synced: Obiektów do zsynchronizowania: - + Stream # Strumień # @@ -1887,37 +1887,37 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - + 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 @@ -1927,42 +1927,47 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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ść przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. - + Processed %n public key(s). Przetworzono %n klucz publiczny.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych.Przetworzono %n kluczy publicznych. - + Peer Użytkownik - + + Rating + Ocena + + + User agent Klient - + TLS TLS -- 2.45.1 From 00a4558971f733f4c1a94d913227aeba229c43a8 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 6 Jul 2017 01:22:19 +0200 Subject: [PATCH 0835/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 86609 -> 86675 bytes src/translations/bitmessage_eo.ts | 67 ++++++++++++++++-------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 073654d4927ecb567df87b758b63d8c5f3be1f5a..2f3af4ec956873f5fea32a91fa79c3f9b079d1c3 100644 GIT binary patch delta 3648 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 delta 3587 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 diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 3127cfe3..7181d678 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -131,7 +131,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: @@ -278,7 +278,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: 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 forviŝi ĝin? + Iu de viaj adresoj, %1, estas malnova versio 1 adreso. Versioj 1 adresoj ne estas jam subtenataj. Ĉu ni povas forigi ĝin? @@ -977,7 +977,7 @@ Are you sure you want to delete the channel? Fetch Namecoin ID - Venigu Namecoin ID + Venigi Namecoin ID @@ -1122,7 +1122,7 @@ Are you sure you want to delete the channel? Waiting for PoW to finish... %1% - Atendado ĝis laborpruvo finos… %1% + Atendado ĝis laborpruvo finiĝos… %1% @@ -1192,7 +1192,7 @@ Are you sure you want to delete the channel? %1 is already in 'Your Identities'. Not adding it again. - %1 jam estas en 'Viaj Identigoj'. Ĝi ne estos aldonita ree. + %1 jam estas en ‘Viaj Identigoj’. Ĝi ne estos aldonita ree. @@ -1547,8 +1547,8 @@ Eble vi devas ĝisdatigi Bitmesaĝon. 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 kreado kaj forlasado de adresoj 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: + Tie ĉi vi povas generi tiom da adresoj, kiom vi volas. Ververe kreado kaj forlasado de adresoj 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: @@ -1840,37 +1840,37 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a Ĉ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 # @@ -1880,37 +1880,37 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a - + 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 @@ -1920,42 +1920,47 @@ La 'hazardnombra' adreso estas antaŭagordita, sed antaŭkalkuleblaj a 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 - + + Rating + Takso + + + User agent Klienta aplikaĵo - + TLS TLS -- 2.45.1 From 4536e44b8c3004710a7f3968b8cbc462df70f4d2 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 6 Jul 2017 19:35:40 +0200 Subject: [PATCH 0836/1102] Thread names propagate to system - the thread names should now show up in the monitoring tools of operating systems (tested on linux) --- src/bitmessagemain.py | 6 ++++-- src/helper_threading.py | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 88fa3c1d..b142676b 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -63,7 +63,7 @@ from network.downloadthread import DownloadThread # Helper Functions import helper_bootstrap import helper_generic -from helper_threading import * +import helper_threading def connectToStream(streamNumber): @@ -153,7 +153,7 @@ def _fixSocket(): socket.IPV6_V6ONLY = 27 # This thread, of which there is only one, runs the API. -class singleAPI(threading.Thread, StoppableThread): +class singleAPI(threading.Thread, helper_threading.StoppableThread): def __init__(self): threading.Thread.__init__(self, name="singleAPI") self.initStop() @@ -204,6 +204,8 @@ class Main: self.setSignalHandler() + helper_threading.set_thread_name("MainThread") + helper_bootstrap.knownNodes() # Start the address generation thread addressGeneratorThread = addressGenerator() diff --git a/src/helper_threading.py b/src/helper_threading.py index 599d297d..cd51557f 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -1,4 +1,17 @@ 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: + log('WARN: prctl module is not installed. You will not be able to see thread names') + def set_thread_name(name): pass class StoppableThread(object): def initStop(self): @@ -7,4 +20,4 @@ class StoppableThread(object): def stopThread(self): self._stopped = True - self.stop.set() \ No newline at end of file + self.stop.set() -- 2.45.1 From a2b8867c1aa57ef5b68b0ad3d86937a4eca70ea8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 6 Jul 2017 19:36:04 +0200 Subject: [PATCH 0837/1102] Tooltips for network status columns --- src/bitmessageqt/networkstatus.ui | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui index f9cc57c4..f05e5f62 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -116,26 +116,41 @@ 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 + -- 2.45.1 From ba4162d7fe1a81952ce105431a63d9ede84021ba Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 6 Jul 2017 19:45:36 +0200 Subject: [PATCH 0838/1102] Asyncore update - get rid of per-connection writeQueue/receiveQueue, and instead use strings and locking - minor code cleanup - all state handlers now should set expectBytes - almost all data processing happens in ReceiveDataThread, and AsyncoreThread is almost only I/O (plus TLS). AsyncoreThread simply puts the connection object into the queue when it has some data for processing - allow poll, epoll and kqueue handlers. kqueue is untested and unoptimised, poll and epoll seem to work ok (linux) - stack depth threshold handler in decode_payload_content, this is recursive and I think was causing occasional RuntimeErrors. Fixes #964 - longer asyncore loops, as now data is handled in ReceiveDataThread - randomise node order when deciding what to download. Should prevent retries being stuck to the same node - socks cleanup (socks5 works ok, socks4a untested but should work too) --- src/network/advanceddispatcher.py | 66 +++++++++--------------- src/network/announcethread.py | 2 +- src/network/asyncore_pollchoose.py | 74 +++++++++++++++------------ src/network/bmproto.py | 63 ++++++++++++----------- src/network/connectionpool.py | 11 ++-- src/network/downloadthread.py | 8 ++- src/network/invthread.py | 2 +- src/network/receivequeuethread.py | 81 ++++++------------------------ src/network/socks4a.py | 41 ++++++++------- src/network/socks5.py | 77 +++++++++++++--------------- src/network/tcp.py | 51 ++++++++++++++++--- src/network/tls.py | 36 ++++++++----- src/network/udp.py | 18 +++---- src/queues.py | 1 + 14 files changed, 257 insertions(+), 274 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 0945d764..57bd4f41 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,6 +1,7 @@ import Queue import socket import sys +import threading import time import asyncore_pollchoose as asyncore @@ -14,41 +15,43 @@ class AdvancedDispatcher(asyncore.dispatcher): asyncore.dispatcher.__init__(self, sock) self.read_buf = b"" self.write_buf = b"" - self.writeQueue = Queue.Queue() - self.receiveQueue = Queue.Queue() self.state = "init" self.lastTx = time.time() self.sentBytes = 0 self.receivedBytes = 0 self.expectBytes = 0 + self.readLock = threading.RLock() + self.writeLock = threading.RLock() + + def append_write_buf(self, data): + if data: + with self.writeLock: + self.write_buf += data def slice_write_buf(self, length=0): if length > 0: - self.write_buf = self.write_buf[length:] + with self.writeLock: + self.write_buf = self.write_buf[length:] def slice_read_buf(self, length=0): if length > 0: - self.read_buf = self.read_buf[length:] - - def read_buf_sufficient(self, length=0): - if len(self.read_buf) < length: - return False - return True + with self.readLock: + self.read_buf = self.read_buf[length:] def process(self): - if self.state != "tls_handshake" and not self.read_buf: - return if not self.connected: return - maxLoop = 20 - while maxLoop > 0: + loop = 0 + while len(self.read_buf) >= self.expectBytes: + loop += 1 + if loop > 1000: + logger.error("Stuck at state %s, report this bug please", self.state) + break try: if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: - # missing state raise - maxLoop -= 1 def set_state(self, state, length=0, expectBytes=0): self.expectBytes = expectBytes @@ -57,7 +60,7 @@ class AdvancedDispatcher(asyncore.dispatcher): def writable(self): return asyncore.dispatcher.writable(self) and \ - (self.connecting or len(self.write_buf) > 0 or not self.writeQueue.empty()) + (self.connecting or self.write_buf) def readable(self): return asyncore.dispatcher.readable(self) and \ @@ -68,28 +71,20 @@ class AdvancedDispatcher(asyncore.dispatcher): downloadBytes = AdvancedDispatcher._buf_len if asyncore.maxDownloadRate > 0: downloadBytes = asyncore.downloadBucket - if self.expectBytes > 0 and downloadBytes > self.expectBytes: - downloadBytes = self.expectBytes + if self.expectBytes > 0 and downloadBytes > self.expectBytes - len(self.read_buf): + downloadBytes = self.expectBytes - len(self.read_buf) if downloadBytes > 0: newData = self.recv(downloadBytes) self.receivedBytes += len(newData) - if self.expectBytes > 0: - self.expectBytes -= len(newData) asyncore.update_received(len(newData)) - self.read_buf += newData - self.process() + with self.readLock: + self.read_buf += newData def handle_write(self): self.lastTx = time.time() bufSize = AdvancedDispatcher._buf_len if asyncore.maxUploadRate > 0: bufSize = asyncore.uploadBucket - while len(self.write_buf) < bufSize: - try: - self.write_buf += self.writeQueue.get(False) - self.writeQueue.task_done() - except Queue.Empty: - break if bufSize <= 0: return if self.write_buf: @@ -107,25 +102,12 @@ class AdvancedDispatcher(asyncore.dispatcher): def handle_connect(self): self.lastTx = time.time() - self.process() def state_close(self): - pass + return False def handle_close(self): self.read_buf = b"" self.write_buf = b"" self.state = "close" - while True: - try: - self.writeQueue.get(False) - self.writeQueue.task_done() - except Queue.Empty: - break - while True: - try: - self.receiveQueue.get(False) - self.receiveQueue.task_done() - except Queue.Empty: - break asyncore.dispatcher.close(self) diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 3adcae48..354cfaa8 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -30,4 +30,4 @@ class AnnounceThread(threading.Thread, StoppableThread): for connection in BMConnectionPool().udpSockets.values(): for stream in state.streamsInWhichIAmParticipating: addr = (stream, state.Peer('127.0.0.1', BMConfigParser().safeGetInt("bitmessagesettings", "port")), time.time()) - connection.writeQueue.put(BMProto.assembleAddr([addr])) + connection.append_write_buf(BMProto.assembleAddr([addr])) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 3f188812..07b2c120 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -249,13 +249,16 @@ def poll_poller(timeout=0.0, map=None): newflags |= OP_WRITE else: newflags &= ~ OP_WRITE - if newflags != obj.flags: - obj.flags = newflags - if obj.poller_registered: - poll_poller.pollster.modify(fd, flags) - else: - poll_poller.pollster.register(fd, flags) - obj.poller_registered = True + 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: @@ -292,16 +295,19 @@ def epoll_poller(timeout=0.0, map=None): newflags |= OP_WRITE else: newflags &= ~ OP_WRITE - if newflags != obj.flags: - obj.flags = newflags + 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 - if obj.poller_registered: - epoll_poller.pollster.modify(fd, flags) - else: - epoll_poller.pollster.register(fd, flags) - obj.poller_registered = True + 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 select.error, err: @@ -329,9 +335,12 @@ def kqueue_poller(timeout=0.0, map=None): if obj.writable(): filter |= select.KQ_FILTER_WRITE if filter: - ev = select.kevent(fd, filter=filter, flags=flags) - kqueue.control([ev], 0) - selectables += 1 + try: + ev = select.kevent(fd, filter=filter, flags=flags) + kqueue.control([ev], 0) + selectables += 1 + except IOError: + pass events = kqueue.control(None, selectables, timeout) for event in random.sample(events, len(events)): @@ -347,25 +356,23 @@ def kqueue_poller(timeout=0.0, map=None): def loop(timeout=30.0, use_poll=False, map=None, count=None, - poller=select_poller): + poller=None): if map is None: map = socket_map # code which grants backward compatibility with "use_poll" # argument which should no longer be used in favor of # "poller" - if 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 - poller = select_poller - -# print "Poll loop using %s" % (poller.__name__) + if poller is None: + if 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 count is None: while map: @@ -400,7 +407,7 @@ class dispatcher: addr = None ignore_log_types = frozenset(['warning']) poller_registered = False - flags = 0 + poller_flags = 0 # don't do network IO with a smaller bucket than this minTx = 1500 @@ -456,23 +463,26 @@ class dispatcher: if map is None: map = self._map map[self._fileno] = self + self.poller_flags = 0 def del_channel(self, map=None): fd = self._fileno if map is None: map = self._map + self.poller_flags = 0 + self.poller_registered = False if fd in map: #self.log_info('closing channel %d:%s' % (fd, self)) del map[fd] self._fileno = None try: epoll_poller.pollster.unregister(fd) - except (AttributeError, KeyError, TypeError): + except (AttributeError, KeyError, TypeError, IOError): # no epoll used, or not registered pass try: poll_poller.pollster.unregister(fd) - except (AttributeError, KeyError, TypeError): + except (AttributeError, KeyError, TypeError, IOError): # no poll used, or not registered pass diff --git a/src/network/bmproto.py b/src/network/bmproto.py index abf2f0ec..e00d6d0a 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -5,6 +5,7 @@ import math import time import socket import struct +import sys from addresses import calculateInventoryHash from bmconfigparser import BMConfigParser @@ -67,15 +68,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.object = None def state_bm_header(self): - if len(self.read_buf) < protocol.Header.size: - #print "Length below header size" - return False 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() - self.set_state("bm_header", length=1, expectBytes=protocol.Header.size) logger.debug("Bad magic") self.handle_close("Bad magic") return False @@ -85,10 +83,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def state_bm_command(self): - if len(self.read_buf) < self.payloadLength: - #print "Length below announced object length" - return False - #logger.debug("%s:%i: command %s (%ib)", self.destination.host, self.destination.port, self.command, self.payloadLength) self.payload = self.read_buf[:self.payloadLength] if self.checksum != hashlib.sha512(self.payload).digest()[0:4]: logger.debug("Bad checksum, ignoring") @@ -127,7 +121,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.handle_close("Invalid command %s" % (self.command)) return False if retval: - self.set_state("bm_header", length=self.payloadLength, expectBytes=protocol.Header.size) + self.set_state("bm_header", length=self.payloadLength) self.bm_proto_reset() # else assume the command requires a different state to follow return True @@ -173,6 +167,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): retval = [] size = None i = 0 + try: + sys._getframe(200) + logger.error("Stack depth warning, pattern: %s", pattern) + return + except ValueError: + pass while i < len(pattern): if pattern[i] in "0123456789" and (i == 0 or pattern[i-1] not in "lL"): @@ -237,8 +237,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # skip? if time.time() < self.skipUntil: return True + #TODO make this more asynchronous and allow reordering for i in items: - self.receiveQueue.put(("object", i)) + 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) return True def bm_command_inv(self): @@ -251,7 +256,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): pass for i in items: - self.receiveQueue.put(("inv", i)) + self.handleReceivedInventory(i) return True @@ -321,7 +326,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_ping(self): - self.writeQueue.put(protocol.CreatePacket('pong')) + self.append_write_buf(protocol.CreatePacket('pong')) return True def bm_command_pong(self): @@ -332,11 +337,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.verackReceived = True if self.verackSent: if self.isSSL: - self.set_state("tls_init", self.payloadLength) - self.bm_proto_reset() + self.set_state("tls_init", length=self.payloadLength, expectBytes=0) return False - self.set_connection_fully_established() - return True + self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) + return False return True def bm_command_version(self): @@ -345,20 +349,20 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.nonce = struct.pack('>Q', self.nonce) self.timeOffset = self.timestamp - int(time.time()) logger.debug("remoteProtocolVersion: %i", self.remoteProtocolVersion) - logger.debug("services: %08X", self.services) + 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 port: %i", self.peerNode.port) + 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.writeQueue.put(protocol.CreatePacket('verack')) + self.append_write_buf(protocol.CreatePacket('verack')) self.verackSent = True if not self.isOutbound: - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ network.connectionpool.BMConnectionPool().streams, True)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and @@ -366,29 +370,28 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.isSSL = True if self.verackReceived: if self.isSSL: - self.set_state("tls_init", self.payloadLength) - self.bm_proto_reset() + self.set_state("tls_init", length=self.payloadLength, expectBytes=0) return False - self.set_connection_fully_established() - return True + self.set_state("connection_fully_established", length=self.payloadLength, expectBytes=0) + return False return True def peerValidityChecks(self): if self.remoteProtocolVersion < 3: - self.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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) @@ -397,7 +400,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): else: shared.timeOffsetWrongCount = 0 if not self.streams: - self.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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)) @@ -405,7 +408,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): if self.destination in network.connectionpool.BMConnectionPool().inboundConnections: try: if not protocol.checkSocksIP(self.destination.host): - self.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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)) @@ -413,7 +416,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): except: pass if self.nonce == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: - self.writeQueue.put(protocol.assembleErrorMessage(fatal=2, + 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)) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index c4aa53d8..4c2b4c6c 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -19,7 +19,6 @@ import state @Singleton class BMConnectionPool(object): - def __init__(self): asyncore.set_rates( BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate") * 1024, @@ -30,7 +29,7 @@ class BMConnectionPool(object): self.udpSockets = {} self.streams = [] self.lastSpawned = 0 - self.spawnWait = 0.3 + self.spawnWait = 2 self.bootstrapped = False def handleReceivedObject(self, streamNumber, hashid, connection = None): @@ -187,12 +186,10 @@ class BMConnectionPool(object): i.handle_close() logger.info('Stopped udp sockets.') -# while len(asyncore.socket_map) > 0 and state.shutdown == 0: -# print "loop, state = %s" % (proxy.state) loopTime = float(self.spawnWait) if self.lastSpawned < time.time() - self.spawnWait: - loopTime = 1.0 - asyncore.loop(timeout=loopTime, count=10) + loopTime = 2.0 + asyncore.loop(timeout=loopTime, count=1000) reaper = [] for i in self.inboundConnections.values() + self.outboundConnections.values(): @@ -201,7 +198,7 @@ class BMConnectionPool(object): minTx -= 300 - 20 if i.lastTx < minTx: if i.fullyEstablished: - i.writeQueue.put(protocol.CreatePacket('ping')) + i.append_write_buf(protocol.CreatePacket('ping')) else: i.handle_close("Timeout (%is)" % (time.time() - i.lastTx)) for i in self.inboundConnections.values() + self.outboundConnections.values() + self.listeningSockets.values() + self.udpSockets.values(): diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 9c7e92da..c42d7e1c 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -1,3 +1,4 @@ +import random import threading import time @@ -32,7 +33,10 @@ class DownloadThread(threading.Thread, StoppableThread): def run(self): while not self._stopped: requested = 0 - for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + # Choose downloading peers randomly + connections = BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() + random.shuffle(connections) + for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk @@ -52,7 +56,7 @@ class DownloadThread(threading.Thread, StoppableThread): self.pending[k] = now payload = addresses.encodeVarint(len(request)) + ''.join(request) - i.writeQueue.put(protocol.CreatePacket('getdata', payload)) + 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: diff --git a/src/network/invthread.py b/src/network/invthread.py index 398fecf0..e5ab890a 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -42,7 +42,7 @@ class InvThread(threading.Thread, StoppableThread): except KeyError: continue if hashes: - connection.writeQueue.put(protocol.CreatePacket('inv', \ + connection.append_write_buf(protocol.CreatePacket('inv', \ addresses.encodeVarint(len(hashes)) + "".join(hashes))) invQueue.iterate() self.stop.wait(1) diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 442c755a..120d15e2 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -10,6 +10,7 @@ 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 @@ -21,73 +22,23 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): logger.info("init receive queue thread") def run(self): - lastprinted = int(time.time()) while not self._stopped and state.shutdown == 0: - if lastprinted < int(time.time()): - lastprinted = int(time.time()) -# try: -# sys._getframe(200) -# logger.error("Stack depth warning") -# except ValueError: -# pass - processed = 0 - for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - if self._stopped: - break - try: - command, args = i.receiveQueue.get(False) - except Queue.Empty: - continue - processed += 1 - try: - getattr(self, "command_" + str(command))(i, args) - i.receiveQueue.task_done() - except AttributeError: - i.receiveQueue.task_done() - # missing command - raise - if processed == 0: - self.stop.wait(2) + try: + connection = receiveDataQueue.get(block=True, timeout=1) + receiveDataQueue.task_done() + except Queue.Empty: + continue - def command_object(self, connection, objHash): - try: - connection.writeQueue.put(protocol.CreatePacket('object', Inventory()[objHash].payload)) - except KeyError: - connection.antiIntersectionDelay() - logger.info('%s asked for an object we don\'t have.', connection.destination) - - def command_biginv(self, connection, dummy): - def sendChunk(): - if objectCount == 0: - return - logger.debug('Sending huge inv message with %i objects to just this one peer', objectCount) - connection.writeQueue.put(protocol.CreatePacket('inv', addresses.encodeVarint(objectCount) + payload)) - - # Select all hashes for objects in this stream. - bigInvList = {} - for stream in connection.streams: - # may lock for a long time, but I think it's better than thousands of small locks - with connection.objectsNewToThemLock: - for objHash in Inventory().unexpired_hashes_by_stream(stream): - bigInvList[objHash] = 0 - connection.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: - self.sendChunk() - payload = b'' - objectCount = 0 - - # flush - sendChunk() - - def command_inv(self, connection, hashId): - connection.handleReceivedInventory(hashId) + if self._stopped: + 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 + try: + while connection.process(): + pass + except AttributeError: + # missing command + logger.error("Unknown state %s, ignoring", connection.state) def stopThread(self): super(ReceiveQueueThread, self).stopThread() diff --git a/src/network/socks4a.py b/src/network/socks4a.py index 350e163e..d6cf2ad8 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -19,10 +19,9 @@ class Socks4a(Proxy): def state_init(self): self.set_state("auth_done", 0) + return True def state_pre_connect(self): - if not self.read_buf_sufficient(8): - return False # Get the response if self.read_buf[0:1] != chr(0x00).encode(): # bad data @@ -44,14 +43,12 @@ class Socks4a(Proxy): self.__proxypeername = (socket.inet_ntoa(self.ipaddr), self.destination[1]) else: self.__proxypeername = (self.destination[0], self.destport) - self.set_state("proxy_handshake_done", 8) + self.set_state("proxy_handshake_done", length=8) + return True def proxy_sock_name(self): return socket.inet_ntoa(self.__proxysockname[0]) - def state_socks_handshake_done(self): - return False - class Socks4aConnection(Socks4a): def __init__(self, address): @@ -60,33 +57,34 @@ class Socks4aConnection(Socks4a): def state_auth_done(self): # Now we can request the actual connection rmtrslv = False - self.writeQueue.put(struct.pack('>BBH', 0x04, 0x01, self.destination[1])) + 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.writeQueue.put(self.ipaddr) + 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.writeQueue.put(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)) + 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.writeQueue.put(self.ipaddr) + self.append_write_buf(self.ipaddr) if self._auth: - self.writeQueue.put(self._auth[0]) - self.writeQueue.put(chr(0x00).encode()) + self.append_write_buf(self._auth[0]) + self.append_write_buf(chr(0x00).encode()) if rmtrslv: - self.writeQueue.put(self.destination[0] + chr(0x00).encode()) - self.set_state("pre_connect", 0) + 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: - Socks4a.state_pre_connect(self) + return Socks4a.state_pre_connect(self) except Socks4aError as e: self.handle_close(e.message) @@ -99,13 +97,14 @@ class Socks4aResolver(Socks4a): def state_auth_done(self): # Now we can request the actual connection - self.writeQueue.put(struct.pack('>BBH', 0x04, 0xF0, self.destination[1])) - self.writeQueue.put(struct.pack("BBBB", 0x00, 0x00, 0x00, 0x01)) + 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.writeQueue.put(self._auth[0]) - self.writeQueue.put(chr(0x00).encode()) - self.writeQueue.put(self.host + chr(0x00).encode()) - self.set_state("pre_connect", 0) + 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 index f2bc83e4..e57e7c6a 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -32,28 +32,26 @@ class Socks5(Proxy): def state_init(self): if self._auth: - self.writeQueue.put(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) + self.append_write_buf(struct.pack('BBBB', 0x05, 0x02, 0x00, 0x02)) else: - self.writeQueue.put(struct.pack('BBB', 0x05, 0x01, 0x00)) - self.set_state("auth_1", 0) + 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): - if not self.read_buf_sufficient(2): - return False ret = struct.unpack('BB', self.read_buf) - self.read_buf = self.read_buf[2:] if ret[0] != 5: # general error raise GeneralProxyError(1) elif ret[1] == 0: # no auth required - self.set_state("auth_done", 2) + self.set_state("auth_done", length=2) elif ret[1] == 2: # username/password - self.writeQueue.put(struct.pack('BB', 1, len(self._auth[0])) + \ + 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", 2) + self.set_state("auth_needed", length=2, expectBytes=2) else: if ret[1] == 0xff: # auth error @@ -61,11 +59,10 @@ class Socks5(Proxy): else: # other error raise GeneralProxyError(1) + return True def state_auth_needed(self): - if not self.read_buf_sufficient(2): - return False - ret = struct.unpack('BB', self.read_buf) + ret = struct.unpack('BB', self.read_buf[0:2]) if ret[0] != 1: # general error raise GeneralProxyError(1) @@ -73,11 +70,10 @@ class Socks5(Proxy): # auth error raise Socks5AuthError(3) # all ok - self.set_state = ("auth_done", 2) + self.set_state("auth_done", length=2) + return True def state_pre_connect(self): - if not self.read_buf_sufficient(4): - return False # Get the response if self.read_buf[0:1] != chr(0x05).encode(): self.close() @@ -91,41 +87,38 @@ class Socks5(Proxy): raise Socks5Error(9) # Get the bound address/port elif self.read_buf[3:4] == chr(0x01).encode(): - self.set_state("proxy_addr_1", 4) + 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", 4) + 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): - if not self.read_buf_sufficient(4): - return False self.boundaddr = self.read_buf[0:4] - self.set_state("proxy_port", 4) + self.set_state("proxy_port", length=4, expectBytes=2) + return True def state_proxy_addr_2_1(self): - if not self.read_buf_sufficient(1): - return False self.address_length = ord(self.read_buf[0:1]) - self.set_state("proxy_addr_2_2", 1) + self.set_state("proxy_addr_2_2", length=1, expectBytes=self.address_length) + return True def state_proxy_addr_2_2(self): - if not self.read_buf_sufficient(self.address_length): - return False - self.boundaddr = self.read_buf - self.set_state("proxy_port", self.address_length) + 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): - if not self.read_buf_sufficient(2): - return False 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", 2) + self.set_state("proxy_handshake_done", length=2) + return True def proxy_sock_name(self): return socket.inet_ntoa(self.__proxysockname[0]) @@ -137,28 +130,29 @@ class Socks5Connection(Socks5): def state_auth_done(self): # Now we can request the actual connection - self.writeQueue.put(struct.pack('BBB', 0x05, 0x01, 0x00)) + 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.writeQueue.put(chr(0x01).encode() + self.ipaddr) + 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.writeQueue.put(chr(0x03).encode() + chr(len(self.destination[0])).encode() + self.destination[0]) + 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.writeQueue.put(chr(0x01).encode() + self.ipaddr) - self.writeQueue.put(struct.pack(">H", self.destination[1])) - self.set_state("pre_connect", 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: - Socks5.state_pre_connect(self) + return Socks5.state_pre_connect(self) except Socks5Error as e: self.handle_close(e.message) @@ -171,10 +165,11 @@ class Socks5Resolver(Socks5): def state_auth_done(self): # Now we can request the actual connection - self.writeQueue.put(struct.pack('BBB', 0x05, 0xF0, 0x00)) - self.writeQueue.put(chr(0x03).encode() + chr(len(self.host)).encode() + str(self.host)) - self.writeQueue.put(struct.pack(">H", self.port)) - self.set_state("pre_connect", 0) + 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/tcp.py b/src/network/tcp.py index c2052df1..8ef3d1e1 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -29,7 +29,7 @@ from network.tls import TLSDispatcher import addresses from bmconfigparser import BMConfigParser -from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue +from queues import invQueue, objectProcessorQueue, portCheckerQueue, UISignalQueue, receiveDataQueue import shared import state import protocol @@ -91,6 +91,12 @@ class TCPConnection(BMProto, TLSDispatcher): logger.debug("Skipping processing getdata due to missing object for %.2fs", self.skipUntil - time.time()) 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 @@ -144,10 +150,37 @@ class TCPConnection(BMProto, TLSDispatcher): for peer, params in addrs[substream]: templist.append((substream, peer, params["lastseen"])) if len(templist) > 0: - self.writeQueue.put(BMProto.assembleAddr(templist)) + self.append_write_buf(BMProto.assembleAddr(templist)) def sendBigInv(self): - self.receiveQueue.put(("biginv", None)) + 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): + 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: + self.sendChunk() + payload = b'' + objectCount = 0 + + # flush + sendChunk() def handle_connect(self): try: @@ -156,9 +189,10 @@ class TCPConnection(BMProto, TLSDispatcher): if e.errno in asyncore._DISCONNECTED: logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e))) return - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) self.connectedAt = time.time() + receiveDataQueue.put(self) def handle_read(self): TLSDispatcher.handle_read(self) @@ -169,6 +203,7 @@ class TCPConnection(BMProto, TLSDispatcher): knownnodes.knownNodes[s][self.destination]["lastseen"] = time.time() except KeyError: pass + receiveDataQueue.put(self) def handle_write(self): TLSDispatcher.handle_write(self) @@ -187,10 +222,10 @@ class Socks5BMConnection(Socks5Connection, TCPConnection): def state_proxy_handshake_done(self): Socks5Connection.state_proxy_handshake_done(self) - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ network.connectionpool.BMConnectionPool().streams, False)) self.set_state("bm_header", expectBytes=protocol.Header.size) - return False + return True class Socks4aBMConnection(Socks4aConnection, TCPConnection): @@ -201,10 +236,10 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection): def state_proxy_handshake_done(self): Socks4aConnection.state_proxy_handshake_done(self) - self.writeQueue.put(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ + self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ network.connectionpool.BMConnectionPool().streams, False)) self.set_state("bm_header", expectBytes=protocol.Header.size) - return False + return True class TCPServer(AdvancedDispatcher): diff --git a/src/network/tls.py b/src/network/tls.py index 9dafaab2..69fc2c20 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -10,6 +10,7 @@ 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 @@ -58,14 +59,17 @@ class TLSDispatcher(AdvancedDispatcher): do_handshake_on_connect=False) self.sslSocket.setblocking(0) self.want_read = self.want_write = True - self.set_state("bm_header") + 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 and self.writeQueue.empty(): - #print "tls writable, %r" % (self.want_write) + if self.tlsStarted and not self.tlsDone and not self.write_buf: return self.want_write return AdvancedDispatcher.writable(self) except AttributeError: @@ -73,9 +77,13 @@ class TLSDispatcher(AdvancedDispatcher): def readable(self): try: - if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): + # 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) @@ -83,11 +91,11 @@ class TLSDispatcher(AdvancedDispatcher): def handle_read(self): try: # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): - #print "handshaking (read)" + 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: - #print "not handshaking (read)" + #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) @@ -104,14 +112,14 @@ class TLSDispatcher(AdvancedDispatcher): def handle_write(self): try: # wait for write buffer flush - if self.tlsStarted and not self.tlsDone and not self.write_buf and self.writeQueue.empty(): - #print "handshaking (write)" + 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: - #print "not handshaking (write)" + #logger.debug("%s:%i Not TLS handshaking (write)", self.destination.host, self.destination.port) return AdvancedDispatcher.handle_write(self) except AttributeError: - return AdvancedDispatcher.handle_read(self) + return AdvancedDispatcher.handle_write(self) except ssl.SSLError as err: if err.errno == ssl.SSL_ERROR_WANT_WRITE: return 0 @@ -158,6 +166,8 @@ class TLSDispatcher(AdvancedDispatcher): self.del_channel() self.set_socket(self.sslSocket) self.tlsDone = True - self.set_state("bm_header") - self.set_connection_fully_established() + + self.bm_proto_reset() + self.set_state("connection_fully_established") + receiveDataQueue.put(self) return False diff --git a/src/network/udp.py b/src/network/udp.py index 6770e5a0..824c9bfa 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -9,7 +9,7 @@ from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInv import network.asyncore_pollchoose as asyncore from network.objectracker import ObjectTracker -from queues import objectProcessorQueue, peerDiscoveryQueue, UISignalQueue +from queues import objectProcessorQueue, peerDiscoveryQueue, UISignalQueue, receiveDataQueue import state import protocol @@ -80,7 +80,7 @@ class UDPSocket(BMProto): 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 + return True remoteport = False for i in addresses: seenTime, stream, services, ip, port = i @@ -93,7 +93,7 @@ class UDPSocket(BMProto): # if the address isn't local, interpret it as the hosts' own announcement remoteport = port if remoteport is False: - return + return True logger.debug("received peer discovery from %s:%i (port %i):", self.destination.host, self.destination.port, remoteport) if self.local: peerDiscoveryQueue.put(state.Peer(self.destination.host, remoteport)) @@ -118,7 +118,7 @@ class UDPSocket(BMProto): return def writable(self): - return not self.writeQueue.empty() + return self.write_buf def readable(self): return len(self.read_buf) < AdvancedDispatcher._buf_len @@ -139,18 +139,14 @@ class UDPSocket(BMProto): # overwrite the old buffer to avoid mixing data and so that self.local works correctly self.read_buf = recdata self.bm_proto_reset() - self.process() + receiveDataQueue.put(self) def handle_write(self): try: - data = self.writeQueue.get(False) - except Queue.Empty: - return - try: - retval = self.socket.sendto(data, ('', UDPSocket.port)) + retval = self.socket.sendto(self.write_buf, ('', UDPSocket.port)) except socket.error as e: logger.error("socket error on sendato: %s", str(e)) - self.writeQueue.task_done() + self.slice_write_buf(retval) if __name__ == "__main__": diff --git a/src/queues.py b/src/queues.py index 223c7c3b..f768c59f 100644 --- a/src/queues.py +++ b/src/queues.py @@ -12,5 +12,6 @@ invQueue = MultiQueue() addrQueue = MultiQueue() portCheckerQueue = Queue.Queue() peerDiscoveryQueue = Queue.Queue() +receiveDataQueue = Queue.Queue() apiAddressGeneratorReturnQueue = Queue.Queue( ) # The address generator thread uses this queue to get information back to the API thread. -- 2.45.1 From de22e547c57be633cb32d51e93a6efe9c9e90293 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 6 Jul 2017 20:06:43 +0200 Subject: [PATCH 0839/1102] Remove buggy log message if prctl is missing - it's not that important that you need to be informed of it, and importing logging may cause cyclic dependencies/other problems --- src/helper_threading.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/helper_threading.py b/src/helper_threading.py index cd51557f..7ea4a12d 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -10,7 +10,6 @@ try: threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap threading.Thread._Thread__bootstrap = _thread_name_hack except ImportError: - log('WARN: prctl module is not installed. You will not be able to see thread names') def set_thread_name(name): pass class StoppableThread(object): -- 2.45.1 From a98b8690d3e5276f47299366b44f1faaad6319f3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 7 Jul 2017 07:55:29 +0200 Subject: [PATCH 0840/1102] Asyncore fixes - fix broken loops - optimise I/O tests --- src/network/advanceddispatcher.py | 54 ++++++++++++++----------------- src/network/receivequeuethread.py | 6 +--- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 57bd4f41..338e3bba 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -40,18 +40,14 @@ class AdvancedDispatcher(asyncore.dispatcher): def process(self): if not self.connected: - return - loop = 0 + return False while len(self.read_buf) >= self.expectBytes: - loop += 1 - if loop > 1000: - logger.error("Stuck at state %s, report this bug please", self.state) - break try: if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: raise + return False def set_state(self, state, length=0, expectBytes=0): self.expectBytes = expectBytes @@ -59,39 +55,39 @@ class AdvancedDispatcher(asyncore.dispatcher): self.state = state def writable(self): + self.uploadChunk = AdvancedDispatcher._buf_len + if asyncore.maxUploadRate > 0: + self.uploadChunk = asyncore.uploadBucket + self.uploadChunk = min(self.uploadChunk, len(self.write_buf)) return asyncore.dispatcher.writable(self) and \ - (self.connecting or self.write_buf) + (self.connecting or self.uploadChunk > 0) def readable(self): + self.downloadChunk = AdvancedDispatcher._buf_len + if asyncore.maxDownloadRate > 0: + self.downloadChunk = asyncore.downloadBucket + try: + if self.expectBytes > 0 and not self.fullyEstablished: + self.downloadChunk = min(self.downloadChunk, self.expectBytes - len(self.read_buf)) + except AttributeError: + pass return asyncore.dispatcher.readable(self) and \ - (self.connecting or len(self.read_buf) < AdvancedDispatcher._buf_len) + (self.connecting or self.downloadChunk > 0) def handle_read(self): self.lastTx = time.time() - downloadBytes = AdvancedDispatcher._buf_len - if asyncore.maxDownloadRate > 0: - downloadBytes = asyncore.downloadBucket - if self.expectBytes > 0 and downloadBytes > self.expectBytes - len(self.read_buf): - downloadBytes = self.expectBytes - len(self.read_buf) - if downloadBytes > 0: - newData = self.recv(downloadBytes) - self.receivedBytes += len(newData) - asyncore.update_received(len(newData)) - with self.readLock: - self.read_buf += newData + newData = self.recv(self.downloadChunk) + self.receivedBytes += len(newData) + asyncore.update_received(len(newData)) + with self.readLock: + self.read_buf += newData def handle_write(self): self.lastTx = time.time() - bufSize = AdvancedDispatcher._buf_len - if asyncore.maxUploadRate > 0: - bufSize = asyncore.uploadBucket - if bufSize <= 0: - return - if self.write_buf: - written = self.send(self.write_buf[0:bufSize]) - asyncore.update_sent(written) - self.sentBytes += written - self.slice_write_buf(written) + 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: diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 120d15e2..f1e81a0d 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -34,11 +34,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # cycle as long as there is data # methods should return False if there isn't enough data, or the connection is to be aborted try: - while connection.process(): - pass + connection.process() except AttributeError: # missing command logger.error("Unknown state %s, ignoring", connection.state) - - def stopThread(self): - super(ReceiveQueueThread, self).stopThread() -- 2.45.1 From 4f969088cfdd271d5c5a1a2f7614b4e6f627589d Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 6 Jul 2017 23:39:57 +0200 Subject: [PATCH 0841/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 89888 -> 90995 bytes src/translations/bitmessage_pl.ts | 49 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index ab80193018c5ae2ea21ef7d311873aab5f66d209..4ecb0a11d0dffee1d30516e399739dab8ff4aab8 100644 GIT binary patch delta 2224 zcmYLKdr(y875{yA@7>3}3mZ{EFl?_6R%K*;f(nB21`9|;u|{gT>|S7zePnl$E~$Xk z(L`&7e6bsiG)|+_8Y3npkJ4!pjY(xX;>2;Bj-;A2(blnQw5CndR_VEGw12=k_k8F3 z{eI{1%^rMDy8C;ncYU9cw^tJ!zb zL?ATErpy@voBuCfO=qRsxKD5jhB4kxUscQayFzp72SVOwTY%tcp}dFe(}#tY<^Les zqdebW7baWy_YDP83!}nlq6^F#6#gQHfvbW+{82WTJi%c7iA17~@V5+(%*59XS;fbJ z<1xeB^KSr)w;8gnr@&I)H{=AmNXK^#`86t7jgw1afl!#oOU1HP<{hH#DXJ*HOH6)s z9dJ8K%zuX(n)i3HxaJ7(r!U2dk*|P8pV&D51+c{XqITR#&3r}Ns0;wN_KR&ZI{|4_ zj08yxcJK>gnf&-n@#KwJU`tDRhSZfg`=Ye9M*}NKke+?LoJuK>cIP^QeQTu`m&^jr z9+dXq4TDWf;v3h`kC|#@VbC)9mn68jg-hls zGgh400E|6lslpiW_G!zyF&S)GtIjwD--tUOJP!>{G>)im76zv3fiXZP|0a*Kzu%HNY)Kg$L#Uy55cwNCD8xDK{( zzP$gh{{@DJ<$;2K)1F_G2iM*Q-q;`yDKzC5ljRd|GvwXK@ifKu0 z2AKF7KW4FaPuZ!|{FXQm-BF$xJ3`}GqPU+a1WV{qc6Dwgo1*l-KT2B4l>O(6!KUt2 z4pIjY~A%yFL5+mUs#q# zPwNKnmkWfFK7L7d$OV(FpFDG(qGdcmX%ZIn@^-}`2w(Gl#VOkZiRMWp!}2qJfuhs@ z!0##k`P23!e)+_7dVB{G@7oi>9zSE7laU5kCfVlu+re@-*s_Q1V2cjh@+Q;sO4E41 z)j3s~X4_ImVcT=IJ)`uNHy^bfvR|Z!V6nYAav#j`5x;58F_nBwYg(T)n3>=n8#fzu z=tLAv2qAzDxcH|hCdTG2XGYa!rcHs7{w5X&{C>?H@do^==68ppLEViNCbJZ_G{zEG zYOEoJ&5oV7vhLF9s6;JPw4oi1Wc_dv10j>&LL6a4@PFv!%39Us@r1N+SPg{KmOwb- zcloq9_B*Q*n8YlbPzA4kjgM8N@Gn#!57^BC0M-gsynCD%l{_@5M&)beVeX8{-j;GTeInk%IJE zf}9an!&+NYR!9p5LOORi&=l!#g}!Y>?PKh=D6l7E2L+azt$2(b0c6pw~*7mcz1C@j6(L!Ig%VII2Vil;^OeodG^k4V%6JH#qBldP38yD+MXUW|(238U; zpd+5yLFkQyr?=4iAp4ObQb!mMHBh5T=R;QKqec$YMvJ@=A8nGWSyLk+mwRJ4KC^JU z+pX_ch^DHK+D+Ts{p~utA`#6Oj8I}g_4+;DOJX+YPuBM68Ew8_sjK5h6 zt4*PRPtBUAr_YNog{!HFpdJvlc{gfp-j+bX6W=JUO(&td`r_z_#1QwJ+9QVchqEo5 I$Ud$7A4joTYXATM delta 1308 zcmX9-YfzL`7=GSwzi+?&zHcwOTx8c+(PR}S7Q}YtwhOk3z{nahtWlzQ!IY9jvQZom zhBB`Ob0m}`uauXB%qhf))QrR*@FRXWuE97?WI2R7W@Qu5nfh_&ne(3aJm)>n^S+P2 zmyUiTHH0gZ0L%f|K52}0T9tU<6}~=`f%OYO1<{Q~PC@vkvD#_(uZ47RHz=nZ`qMgo zwh(e~A;*i2-3~#GY#ek7X&p?WVA|XqEZzDwC$9M)f4YX?o-&YkH1kWzkM-CzR3j2**g6$@Y793V_F-^0Jz~&H5PwWD@`dGf; z5at)Nje<)Mwy;*d%L!-Q!fUpbLi(LLVAFMBQ7y-cHer3%6OgZ#d36pUa)_1ae0Fa@ z2$@%b3=4&y#Y$jU&>8nhpxhePt#ih!@9Gl#9Y9C3E@|LAkn)bsZM+5wJD~HtS;OCt z(Rl+gpgbKji9W$QiRFvgdHS8AWhMVfYM~f;rWkmbAbLBwkn^sK{=jMA#|L6g-|xWc zjpFLC10Z!kEbVY{5x0u3Ywf^ji}=RuDnJUcVKG~sGA3Rfi36qBnOmxfpWQCi*Or1Z z?@GHqU&KofllG^%fJ4iqgQ;;q|52&saV5xcj}1!B_>>Q&`-_$U2`1?e-ASPQzVzpU z$v`aAPcGwW{wRH68`s6QnI-5Q)~qS|U2oR_%l-PpdBdP3Pg#lHv)VUHKN#dCW_0LB z_2t0vZ)I!44xs8Id7j!2l4Ut<)hu9Vtek(VAJ{V{2OFw^yL;u*IUD%bMY;Y+Cg8Wq zI~UtP^KZ!SyN7@mNp6Td0ZjbBp6G)@b`i^$UDnJqhLlI6!2Whap|6O0HpKSJi8PaS z%K??*l&PQcf-}7=!Z3Z>VoU&ET~~@HRPIYisSJDvta(SNdpZu1Dp`ra8LwPYTI+8B zH;yYuGkE&wU&{GoT$6QGN?)=a6cMfTjeQIX_poyYr&ZHbt%56wFVwJn?(&psHf(U^ zWmKr^*YYesQ_JqSfuX_wkQ}qsn&tOFNwV5#f}YbmeNjciVv@kF=YI0-%^N z?bfzY&JzfoF-dc(sSk~}w-4~>ROZ&!35lhw zRdWiok@aXU)xN-Nh~nkQO>B%uV~(&`V|ntlwdMx}Gx;c0n8zJvP}DI?VyqodqAbbf zTR@(<7I&`$G`GrWszystkich 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 przekazów. - + Inventory lookups per second: 0 Zapytań o elementy na sekundę: 0 - + Objects to be synced: Obiektów do zsynchronizowania: - + Stream # Strumień # @@ -1912,12 +1912,12 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ Zapytań o elementy na sekundę: %1 - + Up: 0 kB/s Wysyłanie: 0 kB/s - + Down: 0 kB/s Pobieranie: 0 kB/s @@ -1957,20 +1957,45 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 -- 2.45.1 From 6eb9e93575f53de1d6a76e46c2ba71b0622bcb27 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 7 Jul 2017 15:20:23 +0200 Subject: [PATCH 0842/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 65615 -> 66390 bytes src/translations/bitmessage_ja.ts | 49 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index d5116555b3041a779cd40a5be68969fc0bd41510..37e8086d9a717d80de0d10fe159843685ad6c397 100644 GIT binary patch delta 1979 zcmYLKc~BH*7Jt*zb9E2Qio0aRFg9)+H*7I}#09ScjRuSdh@dE0JO-u*hNGKIH!2}= zlojH!>fonkVu@OW#3hL&TWBc+NC0E-7}k4(29_9=fFN--No7}b-$2U!W9EIw``+)p z-|xMdf0VJ;D_HMuO)~)?62Nz~GSn8-x&`1b;Q+<|0?2*^;K$XKD{V}Zt8%j~WbjX* zJGBj9*a7-lE#8%ZAvF$dS7o!6X`5ErZDZ~vQ=KMtcCP}-o0>52hA~^S6H>S50Q9{B ztK4s(eFCdb!~#sw!E4HF4A}zd`t4|U(S4d|=GME^r?E1%_W)#5Zv0C$AbpSuir6;tu@U{wV z#DY%%N~*Nv%HIKOA=)T&J3vRbHd-zL_-0relPI8j3)Qi)Oy6@fj*U-lnZ#PwVM(_O z*x(P-0P0?3V@@KY-(|B45^Dhton&A2Jpza;Wi!U_1!(JF#ZTg)S=HLTvd_oDp`CjTX+Dq^5;BSy75-?^jc5@}^ z0{}g1xdVNV0lX|%7yBRV@H1TfD#R-NhHKza=Df??7oFJYt>d`%vU(KgFn6&6IaoZx zeVdNd?zVG7`w_0Em)9iJ0m$*ZsR)IQ$mTiiB^VFsR-U`90-W>m0p)R+ZU^0I3Ny?~ zngY<|rN>Ox(u>J_Vk2U1sN|PFtwntn@|ndiBW4}H;|(0_)+N06^Bb7UWB$OE1=ti} z{6W*7QK#elM||Ic?50WLq`yNXbOdnNphSN8!}fgcP) zeLp?H4+=RriAT&NbuG~OTx599^X7s@RRDKRo7J0h04D4<7o}+c-rQy0@ue3r%FTP{ zhTyPN&?+vL>3>MOIU9G|XTDi{1?T?<8o;}l?(4LWw=tg`qgA|}>zom2{5_`8a+hAi z)62){2rs>K>0aRQ@)r>Ng}^7)K!6KZEz_o8VEtvwOHv^=S&}8H!wS&*o@LHNoUij5 zT4lCRZtAy`$K!GP49o5tILv9wEH&0HfP{9-hd$))>I6Dujy4QTMjn1*X=x*=e=VT> zR5+LU{^kR&{V6}E1RJqAK#!l_Es!Ni%v9a7B#2U`r>MZcr0c(Wj)tD8ig_LuK@te0 znw%wrq=A%>bwnmNan-RR;8~F1MM;9g>GX(-BFG*gTUJ!bkuQ!$X*|*9(J5qz>PAtNgd(|6a7a!;%@&0MQS=zFyZ{L=>)l^X*US$Y11}#~^I&!4ip8Xv zTtm1I$Wc=L3??)Q-%V8nMa*+Wc*FwP;|EY=m%7p68Lg-OV8=>EvzH!OKe1FMnk1g+ zFxgH_`YhQ*BtOI3U0atDDdRWEhn2U7zh-?p!g?oh{4GQF+8Xe>34@zY6}42r;^L P6{>~5QuyH9+Nl2liq59A delta 1291 zcmXAodrXs87{;G|{l0$vF0@)NnKc$P(hV}Jk`)!lWdi|?6fd*NCOVlKM8zqN4V_#h z8t=9_m^mU|HXOlBz%Zwv6&#|qOTlS$17vvNG8|}}b55tQH}S7G=bZQQoZoZKt?hhs zKJOYX4FND2@Oj;1tfmX4z(=9L<_;h|4)`m_y}-(yi*s+WntNwMIJ*<*+X`K|md=hr zbk3mo!tJqeb#vV9R_YyEK+OXyt`PcHp<+Y z&9xeq0iH)(H=hNR{-jm+2tfbG%%io2)|F`|#8v{iCE7_hP61Z4)~+@HjRV^7b-5&9 zh&Iv@MClzYfRExjr?MnIe%AR?-nf*ma@Wm|Jdpxagz%APh~%A}e5|7!IDCdr^#2Xa z$m7$76#;d<{EA8&QS|Yvl?vc{AHU`;Ld0jXE1Ht#bcbej0goG4sxCaOD_Pg>q#^hFbq{r! zz{Xpm$(08<{}ZRkO~Co*V#KmHfu&k8sfE^Q+eD{p3-C>gxMK1u(ryq7k3<8udE)lj zqkx`4ai9HnU`nLu8u=|ylgOUxoZO#NSdwTnb*Jg4K7I%+FV)YFT0oxt#`cOfu4WJO zhz_}SrZl>Y6nBqcBlKefXJZg3TqmUr%E09qDa&yQh+iocJRcxk2`p7lJ`R^k3apJ*!_2^yXvzQTFqI!%}G=-NdqF&Hb?~$t)l8C(9a*aZMuemPQ zH_=nS5XMp^3wK+?wn!HF$|)tFfd0_sUUpm>%bKJydHyWLQA>r{Ze{LZIZ;nnKH2;p z6*eooHx*J`qqyo?so_hd_(m*Q{l0QYdWY!$pm_6%_O@w?_g)3Cp;7tuYX@*GP-)2_ zo_`!sS`!Zd7ASota;xgJ(ifCL&-kJ`$+-l`=u~6gwu5buLqgjk)lX-Z0Qb7ojcwC` zQTx@L6bH=*^wIQNyyIA-Y8!Vh(^wEs+x3f#`&;R2rX(9nEiFJ&gYkr)*!>d0Mg)Y5 qJ+Z{&NiZ9znpC|tpy4drez}Bwe#KLL(HpF(j`l6!s{i#bvHuTGySh>U diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 3aa2723e..9733c02a 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -1841,37 +1841,37 @@ The 'Random Number' option is selected by default but deterministic ad 接続数: - + 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 # ストリーム # @@ -1906,12 +1906,12 @@ The 'Random Number' option is selected by default but deterministic ad 毎秒のインベントリ検索: %1 - + Up: 0 kB/s アップ: 0 kB/秒 - + Down: 0 kB/s ダウン: 0 kB/秒 @@ -1951,20 +1951,45 @@ The 'Random Number' option is selected by default but deterministic ad ピア - + + 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 -- 2.45.1 From 1aa45d6eacdfa769f566c302c9ee8ec695ae9684 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 6 Jul 2017 23:35:37 +0200 Subject: [PATCH 0843/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 86675 -> 87724 bytes src/translations/bitmessage_eo.ts | 49 ++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 2f3af4ec956873f5fea32a91fa79c3f9b079d1c3..69c28969c621850702ee10caacc3114925c62cb1 100644 GIT binary patch delta 2193 zcmYjSdsGzX6~Es+c6MhLHZBnb58KfeHb8cH2#65y6-5*X(TIHensbV$t)V$!=}B{k7ocJO9g0r7|6=Kz3bALsWZKu zY01TI;NSZxki`jL8DR0<2O!ie2U4Eidp3n7?7H5uG$uEL@}#CHV;t6OeIHZ56tiO? zsM*s5Bp+aXa2wjKu;J}efb0a=q!(e%r(v^Y585iapA<0OAJQS>VlrCkIPo&h!!(6) zId6@SA0%@Cp$%ki)@dMVhiN6_VhaCBLyVW1s-^w7TXdG5Wg3!x%@lu*tu*gv%DU0E zJi;_C{tu7>4=rI`jN=HcWlQJfon%JieLzSLbB)sh#*VYxQ&{1hI@bO?4`c~X-)2)Y z344n5EPE5+m%G^P%WolFqinwYJP>;)TcB;nLgLtxDjEHsraV{56qpdn#ym_kf->a-3pKeJNezeD#Kp3@Glg3 z0rpPuFE307_|0to;J#g%x(cLh53RHm)a9SCjMZSNc}~j>iwf|{1;N?V z1z>z4ED$dN++HIT`P=~AnL_0V?w=VFYI-^Wu2c$2P7sLqh_LguMF0;S6`rj~0rm}ycymhX7)o-@|+-$W~z#V|Wo3@R2MAYeHn_hJRV9Wcq9pBvsm{#d>Ybs7G zPeWFh7&mDfntl~XoSW{qra8HlqST7a!6h-F64kx0fDT!`UGqN`8~x~2yg_XG9Eaqy z15ry7hsEuizXIa^LOl4_TL2#&76(fwal(tllj{-ec(Qm}LYaI2D4x57lg_Z>`R~D&2kqhVejvFQ?Z%a20Qs`LVjQ9T(jgtb5yNI?)Y0Ts}?U%e_ z!i;$9>?$0qYjhY-lbYzXq~^}fjQ{4*A0c>k{B2h}kQqO5WThqpSg$#9)ixlWPaXLe zT|hGP9mR9-emQ2*e!F+xtp>-A6?n{bI({~amwBt;IO-a~uiaJ0@uAy5=48=vdx22s z$2l$EM4$hA#mV-#^qZwFSPdGepg=Pi-~*Z1AP517;MxzG6$b_^_?x**Q&pwj2x_XV zsP&PKu(|AOmB_5V*EsU}+FU4yYVbtEBA8Ccv@-Ze2%imjs$=?KbR{F42BH5;o>*Qj z`~3chqU*92ksCGLP<`)y%cdAQ7HZ033e}EJ6U7wnE*Uzu z+l*%>^RecdqwizFdLWFk8b%@|eRDZ7v&$3#6-I`r z!#7ynu{3Cea6EhsiflxD_04)z0==!i-W-|;iexHR|Gy#i8HN%H8|bIWLDe5@5Bl4D zEwZZl72PX8*7&$$Mg`RdG-`vQ%Yld%l07-5e@;|mUm$=39|LL$HY+W`Mosfa2SjNx auL8!Jb6}=Ki0C@dX0+WE^c9hOTlQb47hebf delta 1299 zcmX9;dr;I>7(Ms*+~0%UT)-4%alndfknCfDIaaRE5!h^vnBai;?S~*4F_7wbb{2%} z%>l`o7-)&)F}O6)W#w#>s7Sm{>vO!Z;T*gA!2j4)2=C4UkW>@${Tmr>$J}pRKuRd) z7dhFT0W6SqGW5~?#K9$`(IByK)>8VA*f?V&jpQumzT0F}ga8!ICDF-eL1G%Io3n6s zLJK(?*V{pB*ed-e+QKa#zLrbBSq7}!&*hdfTs4zhG36;pS_aMJEu40S`gm7F$_1{| zxEOeGgu5dY0bTXHULk^HhS3&2ZY%~b@<~~Zz~|ffl=jn1rcU0jUj#8!@QyVljKD}f z(-Xz&12jZ%aVcA=TbMe%|CwM~#GaDaFAS}p2mDzlWHvJ?$G$IQdFp^)&I;3lPXOO> zVM*vd5NN`(MjMlJKv=0Y0C)O?Rj+LX#II?$FjduCh4T;MS^IC)E|w%js$zNRGLUh5 z#T{SeGVX=qZl?{{+b@1RDIT~yOsxL92qd(Lc8S)6M2~nccP0?uAwJ_z0RC%YPxcTX zhL?sEurkMOX?86W#yE{8Nfz_C%hHbbN&xR1>Cp6UkgO`|lN?J@uS#8BMlmH?dL*p| zKDi{DE4KjaugVkDHsHBWb}k+Rl#Z3%9c;ZdD0?e612^3AvQ$4v!Wp^z$YdbnguHFW za1gs+{>c72ke4r44m}R^T%%7VFXt4gTeg|U%{NSZ{0P{-)iB#NhnaSO?v|6uNZKNM z)ZRE{#Ah#^yidao(W7Qy5NPO8<_)UMm!Fj)&m~~tIi;+30O&8KKEq2N!<3rxtH6bA z%Fzr~e|L#;`WO>s@ku3^76GCvO7O*D5XC`H8LVdHtJ+#7CECm` z$2KQ0V5UCB!i_GYn-zAUt8UL?RwrtQl<`dcXWErgKXAHEyYfc^P{nK4t2`j#L9L_s z5%YSc);VoIV7;V0Ff+IA_iGQL3K(%wPw_4U_Biw@iFVL+YJ5U$o&HW<4T$Z!zWzo! z5Y?_1&m+Leq57^?_DB5lslIPAlP+@>ZB<>|cqbJ#tD01y-`Ld7QhbrxwYRz0JX)h! zxn4hQ)oiLM%4itoVZ-v6zF@oI#WYS|ofhUa{xxef%hDp_fW-(Bvc{Ag7XcXVn9^3i z3le|JWWQno8Ix^FAHmY1S!t_oi|JcuDx1o-QDNHC$)dSIHl46^us^HYR397wdDTV3 wLmcw>A~tĈ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 # @@ -1905,12 +1905,12 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Petoj pri inventaro en sekundo: %1 - + Up: 0 kB/s Alŝuto: 0 kB/s - + Down: 0 kB/s Elŝuto: 0 kB/s @@ -1950,20 +1950,45 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj 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 -- 2.45.1 From 5ae1b6d865165ebdbbb39db6ff28d51992ae108e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 8 Jul 2017 06:52:17 +0200 Subject: [PATCH 0844/1102] Asyncore update: remove obsolete files --- src/network/downloadqueue.py | 12 ------- src/network/uploadqueue.py | 70 ------------------------------------ 2 files changed, 82 deletions(-) delete mode 100644 src/network/downloadqueue.py delete mode 100644 src/network/uploadqueue.py diff --git a/src/network/downloadqueue.py b/src/network/downloadqueue.py deleted file mode 100644 index 3789fb19..00000000 --- a/src/network/downloadqueue.py +++ /dev/null @@ -1,12 +0,0 @@ -#import collections -from threading import current_thread, enumerate as threadingEnumerate, RLock -import Queue -import time - -#from helper_sql import * -from singleton import Singleton - -@Singleton -class DownloadQueue(Queue.Queue): - # keep a track of objects that have been advertised to us but we haven't downloaded them yet - maxWait = 300 diff --git a/src/network/uploadqueue.py b/src/network/uploadqueue.py deleted file mode 100644 index 5d699e96..00000000 --- a/src/network/uploadqueue.py +++ /dev/null @@ -1,70 +0,0 @@ -from collections import namedtuple -import Queue -import random -from threading import current_thread, enumerate as threadingEnumerate, RLock -import time - -#from helper_sql import * -from singleton import Singleton - -UploadElem = namedtuple("UploadElem", "stream identifier") - -class UploadQueueDeadlineException(Exception): - pass - - -class UploadQueue(object): - queueCount = 10 - - def __init__(self): - self.queue = [] - self.lastGet = 0 - self.getIterator = 0 - for i in range(UploadQueue.queueCount): - self.queue.append([]) - - def put(self, item): - self.queue[random.randrange(0, UploadQueue.queueCount)].append(item) - - def get(self): - i = UploadQueue.queueCount - retval = [] - while self.lastGet < time.time() - 1 and i > 0: - if len(self.queue) > 0: - retval.extend(self.queue[self.getIterator]) - self.queue[self.getIterator] = [] - self.lastGet += 1 - # only process each queue once - i -= 1 - self.getIterator = (self.getIterator + 1) % UploadQueue.queueCount - if self.lastGet < time.time() - 1: - self.lastGet = time.time() - return retval - - def streamElems(self, stream): - retval = {} - for q in self.queue: - for elem in q: - if elem.stream == stream: - retval[elem.identifier] = True - return retval - - def len(self): - retval = 0 - for i in range(UploadQueue.queueCount): - retval += len(self.queue[i]) - return retval - - def stop(self): - for i in range(UploadQueue.queueCount): - self.queue[i] = [] - - -@Singleton -class AddrUploadQueue(UploadQueue): - pass - - -@Singleton -class ObjUploadQueue(UploadQueue): - pass -- 2.45.1 From 0f3a69adf42804d92946fc72f3eea65f934e8a8b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 8 Jul 2017 06:53:20 +0200 Subject: [PATCH 0845/1102] Asyncore update: remove references to deleted files --- src/network/bmproto.py | 1 - src/network/objectracker.py | 2 -- src/network/tcp.py | 2 -- 3 files changed, 5 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index e00d6d0a..837c4ce8 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -15,7 +15,6 @@ import knownnodes from network.advanceddispatcher import AdvancedDispatcher from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError import network.connectionpool -from network.downloadqueue import DownloadQueue from network.node import Node from network.objectracker import ObjectTracker from network.proxy import Proxy, ProxyError, GeneralProxyError diff --git a/src/network/objectracker.py b/src/network/objectracker.py index a7295c21..4541ea76 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -4,8 +4,6 @@ from threading import RLock from debug import logger from inventory import Inventory -from network.downloadqueue import DownloadQueue -from network.uploadqueue import UploadQueue haveBloom = False diff --git a/src/network/tcp.py b/src/network/tcp.py index 8ef3d1e1..1a4a906c 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -17,14 +17,12 @@ 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.downloadqueue import DownloadQueue 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.uploadqueue import UploadQueue, UploadElem, AddrUploadQueue, ObjUploadQueue from network.tls import TLSDispatcher import addresses -- 2.45.1 From 2d7d9c2f929a230bd9af18721aa52ba902d7e0be Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 8 Jul 2017 06:54:25 +0200 Subject: [PATCH 0846/1102] Asyncore update - request downloads in bigger chunks - don't put whole objects into the receiveDataQueue --- src/network/downloadthread.py | 4 ++-- src/network/receivequeuethread.py | 26 +++++++++++++++++++++++--- src/network/tcp.py | 4 ++-- src/network/tls.py | 2 +- src/network/udp.py | 2 +- 5 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index c42d7e1c..d1c7b0f4 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -11,8 +11,8 @@ from network.connectionpool import BMConnectionPool import protocol class DownloadThread(threading.Thread, StoppableThread): - maxPending = 50 - requestChunk = 100 + maxPending = 200 + requestChunk = 1000 requestTimeout = 60 cleanInterval = 60 requestExpires = 600 diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index f1e81a0d..5e707398 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -24,17 +24,37 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): def run(self): while not self._stopped and state.shutdown == 0: try: - connection = receiveDataQueue.get(block=True, timeout=1) + dest = receiveDataQueue.get(block=True, timeout=1) receiveDataQueue.task_done() except Queue.Empty: continue if self._stopped: 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: - connection.process() + BMConnectionPool().inboundConnections[dest].process() + except KeyError: + pass + except AttributeError: + logger.error("Unknown state %s, ignoring", connection.state) + + try: + BMConnectionPool().outboundConnections[dest].process() + except KeyError: + pass + except AttributeError: + logger.error("Unknown state %s, ignoring", connection.state) + + try: + BMConnectionPool().udpSockets[dest].process() + except KeyError: + pass except AttributeError: - # missing command logger.error("Unknown state %s, ignoring", connection.state) diff --git a/src/network/tcp.py b/src/network/tcp.py index 1a4a906c..75ddea1c 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -190,7 +190,7 @@ class TCPConnection(BMProto, TLSDispatcher): self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) #print "%s:%i: Sending version" % (self.destination.host, self.destination.port) self.connectedAt = time.time() - receiveDataQueue.put(self) + receiveDataQueue.put(self.destination) def handle_read(self): TLSDispatcher.handle_read(self) @@ -201,7 +201,7 @@ class TCPConnection(BMProto, TLSDispatcher): knownnodes.knownNodes[s][self.destination]["lastseen"] = time.time() except KeyError: pass - receiveDataQueue.put(self) + receiveDataQueue.put(self.destination) def handle_write(self): TLSDispatcher.handle_write(self) diff --git a/src/network/tls.py b/src/network/tls.py index 69fc2c20..379dae99 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -169,5 +169,5 @@ class TLSDispatcher(AdvancedDispatcher): self.bm_proto_reset() self.set_state("connection_fully_established") - receiveDataQueue.put(self) + receiveDataQueue.put(self.destination) return False diff --git a/src/network/udp.py b/src/network/udp.py index 824c9bfa..5c19fa69 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -139,7 +139,7 @@ class UDPSocket(BMProto): # overwrite the old buffer to avoid mixing data and so that self.local works correctly self.read_buf = recdata self.bm_proto_reset() - receiveDataQueue.put(self) + receiveDataQueue.put(self.destination) def handle_write(self): try: -- 2.45.1 From 2df9598774dfff1782db9804ae79e7ace8425f2e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 8 Jul 2017 07:33:29 +0200 Subject: [PATCH 0847/1102] Asyncore update: Fix incoming connections - dereferencing wasn't done correctly for incoming connections --- src/network/receivequeuethread.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 5e707398..6a2ebb65 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -35,26 +35,25 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # 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 + # state_* methods should return False if there isn't enough data, + # or the connection is to be aborted try: BMConnectionPool().inboundConnections[dest].process() except KeyError: - pass + try: + BMConnectionPool().inboundConnections[dest.host].process() + except KeyError: + pass except AttributeError: - logger.error("Unknown state %s, ignoring", connection.state) + pass try: BMConnectionPool().outboundConnections[dest].process() - except KeyError: + except (KeyError, AttributeError): pass - except AttributeError: - logger.error("Unknown state %s, ignoring", connection.state) try: BMConnectionPool().udpSockets[dest].process() - except KeyError: + except (KeyError, AttributeError): pass - except AttributeError: - logger.error("Unknown state %s, ignoring", connection.state) -- 2.45.1 From 4fce01e34a5edde768ba643175b403fd7925000b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 8 Jul 2017 18:02:47 +0200 Subject: [PATCH 0848/1102] Less data transferred in invThread and addrThread --- src/network/addrthread.py | 4 ++++ src/network/bmproto.py | 4 ++-- src/network/connectionpool.py | 11 +++++++++++ src/network/invthread.py | 6 +++++- src/network/receivequeuethread.py | 19 +++---------------- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/network/addrthread.py b/src/network/addrthread.py index a6c401ab..e0b31b6e 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -21,8 +21,12 @@ class AddrThread(threading.Thread, StoppableThread): 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 diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 837c4ce8..78149726 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -290,7 +290,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): Inventory()[self.object.inventoryHash] = ( self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) - invQueue.put((self.object.streamNumber, self.object.inventoryHash, self)) + invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination)) return True def _decode_addr(self): @@ -317,7 +317,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): "rating": 0, "self": False, } - addrQueue.put((stream, peer, self)) + addrQueue.put((stream, peer, self.destination)) return True def bm_command_portcheck(self): diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 4c2b4c6c..ba5481da 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -54,6 +54,17 @@ class BMConnectionPool(object): def connectToStream(self, streamNumber): self.streams.append(streamNumber) + def getConnectionByAddr(self, addr): + if addr in self.inboundConnections: + return self.inboundConnections[addr] + if addr.host in self.inboundConnections: + return self.inboundConnections[addr.host] + if addr in self.outboundConnections: + return self.outboundConnections[addr] + if addr in self.udpSockets: + return self.udpSockets[addr] + raise KeyError + def addConnection(self, connection): if isinstance(connection, network.udp.UDPSocket): return diff --git a/src/network/invthread.py b/src/network/invthread.py index e5ab890a..0cc689b4 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -23,10 +23,14 @@ class InvThread(threading.Thread, StoppableThread): if len(data) == 2: BMConnectionPool().handleReceivedObject(data[0], data[1]) else: - BMConnectionPool().handleReceivedObject(data[0], data[1], data[2]) + source = BMConnectionPool().getConnectionByAddr(data[2]) + BMConnectionPool().handleReceivedObject(data[0], data[1], source) chunk.append((data[0], data[1])) except Queue.Empty: break + # connection not found, handle it as if generated locally + except KeyError: + BMConnectionPool().handleReceivedObject(data[0], data[1]) if chunk: for connection in BMConnectionPool().inboundConnections.values() + \ diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index 6a2ebb65..b6810a3c 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -39,21 +39,8 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # or the connection is to be aborted try: - BMConnectionPool().inboundConnections[dest].process() - except KeyError: - try: - BMConnectionPool().inboundConnections[dest.host].process() - except KeyError: - pass - except AttributeError: - pass - - try: - BMConnectionPool().outboundConnections[dest].process() - except (KeyError, AttributeError): - pass - - try: - BMConnectionPool().udpSockets[dest].process() + BMConnectionPool().getConnectionByAddr(dest).process() + # KeyError = connection object not found + # AttributeError = state isn't implemented except (KeyError, AttributeError): pass -- 2.45.1 From f088e0ae21916c05deab43d2cdac12ec40fcaf22 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 07:05:50 +0200 Subject: [PATCH 0849/1102] Change thread names - not needed to have "Thread" in the name of a thread --- src/network/addrthread.py | 4 ++-- src/network/announcethread.py | 4 ++-- src/network/downloadthread.py | 4 ++-- src/network/invthread.py | 4 ++-- src/network/networkthread.py | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/network/addrthread.py b/src/network/addrthread.py index e0b31b6e..8c78894f 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -10,9 +10,9 @@ import state class AddrThread(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="AddrThread") + threading.Thread.__init__(self, name="AddrBroadcaster") self.initStop() - self.name = "AddrThread" + self.name = "AddrBroadcaster" def run(self): while not state.shutdown: diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 354cfaa8..26d9f9cf 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -11,9 +11,9 @@ import state class AnnounceThread(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="AnnounceThread") + threading.Thread.__init__(self, name="Announcer") self.initStop() - self.name = "AnnounceThread" + self.name = "Announcer" logger.info("init announce thread") def run(self): diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index d1c7b0f4..34f23eed 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -18,9 +18,9 @@ class DownloadThread(threading.Thread, StoppableThread): requestExpires = 600 def __init__(self): - threading.Thread.__init__(self, name="DownloadThread") + threading.Thread.__init__(self, name="Downloader") self.initStop() - self.name = "DownloadThread" + self.name = "Downloader" logger.info("init download thread") self.pending = {} self.lastCleaned = time.time() diff --git a/src/network/invthread.py b/src/network/invthread.py index 0cc689b4..d680ea13 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -10,9 +10,9 @@ import state class InvThread(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="InvThread") + threading.Thread.__init__(self, name="InvBroadcaster") self.initStop() - self.name = "InvThread" + self.name = "InvBroadcaster" def run(self): while not state.shutdown: diff --git a/src/network/networkthread.py b/src/network/networkthread.py index a4a23103..25e9f547 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -9,9 +9,9 @@ import state class BMNetworkThread(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__init__(self, name="AsyncoreThread") + threading.Thread.__init__(self, name="Asyncore") self.initStop() - self.name = "AsyncoreThread" + self.name = "Asyncore" logger.info("init asyncore thread") def run(self): -- 2.45.1 From bdf61489aebdcad5b5238602727894fb8801fe2e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 07:08:10 +0200 Subject: [PATCH 0850/1102] Allow multiple ReceiveQueue threads - defaults to 3 --- src/bitmessagemain.py | 7 ++++--- src/bmconfigparser.py | 3 +++ src/helper_threading.py | 15 +++++++++++++++ src/network/advanceddispatcher.py | 7 +++++-- src/network/receivequeuethread.py | 10 +++++----- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index b142676b..3e0a1c84 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -267,9 +267,10 @@ class Main: asyncoreThread = BMNetworkThread() asyncoreThread.daemon = True asyncoreThread.start() - receiveQueueThread = ReceiveQueueThread() - receiveQueueThread.daemon = True - receiveQueueThread.start() + for i in range(BMConfigParser().getint("threads", "receive")): + receiveQueueThread = ReceiveQueueThread(i) + receiveQueueThread.daemon = True + receiveQueueThread.start() announceThread = AnnounceThread() announceThread.daemon = True announceThread.start() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 913df9c0..094cd73d 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -15,6 +15,9 @@ BMConfigDefaults = { "maxtotalconnections": 200, "maxuploadrate": 0, }, + "threads": { + "receive": 3, + }, "network": { "asyncore": True, "bind": None, diff --git a/src/helper_threading.py b/src/helper_threading.py index 7ea4a12d..56c5b8b2 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -1,4 +1,6 @@ +from contextlib import contextmanager import threading + try: import prctl def set_thread_name(name): prctl.set_name(name) @@ -20,3 +22,16 @@ class StoppableThread(object): 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/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 338e3bba..dbe65e39 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -6,6 +6,7 @@ import time import asyncore_pollchoose as asyncore from debug import logger +from helper_threading import BusyError, nonBlocking class AdvancedDispatcher(asyncore.dispatcher): _buf_len = 2097152 # 2MB @@ -22,6 +23,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.expectBytes = 0 self.readLock = threading.RLock() self.writeLock = threading.RLock() + self.processingLock = threading.RLock() def append_write_buf(self, data): if data: @@ -43,8 +45,9 @@ class AdvancedDispatcher(asyncore.dispatcher): return False while len(self.read_buf) >= self.expectBytes: try: - if getattr(self, "state_" + str(self.state))() is False: - break + with nonBlocking(self.processingLock): + if getattr(self, "state_" + str(self.state))() is False: + break except AttributeError: raise return False diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index b6810a3c..a899851f 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -15,17 +15,16 @@ import protocol import state class ReceiveQueueThread(threading.Thread, StoppableThread): - def __init__(self): - threading.Thread.__init__(self, name="ReceiveQueueThread") + def __init__(self, num=0): + threading.Thread.__init__(self, name="ReceiveQueue_%i" %(num)) self.initStop() - self.name = "ReceiveQueueThread" - logger.info("init receive queue thread") + 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) - receiveDataQueue.task_done() except Queue.Empty: continue @@ -44,3 +43,4 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # AttributeError = state isn't implemented except (KeyError, AttributeError): pass + receiveDataQueue.task_done() -- 2.45.1 From 3941b39136206a50c90fb1cad4d320bb5d70c676 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 07:10:05 +0200 Subject: [PATCH 0851/1102] Randomise node id - in order to detect if it's connected to to itself, PyBitmessage now uses a per-connection id rather than a global one --- src/network/connectionpool.py | 9 +++++++++ src/network/tcp.py | 12 +++++++++--- src/protocol.py | 7 +++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index ba5481da..be7b8ceb 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -65,6 +65,15 @@ class BMConnectionPool(object): return self.udpSockets[addr] 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, network.udp.UDPSocket): return diff --git a/src/network/tcp.py b/src/network/tcp.py index 75ddea1c..01b19817 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -11,6 +11,7 @@ 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 @@ -47,6 +48,7 @@ class TCPConnection(BMProto, TLSDispatcher): 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 @@ -187,7 +189,9 @@ class TCPConnection(BMProto, TLSDispatcher): if e.errno in asyncore._DISCONNECTED: logger.debug("%s:%i: Connection failed: %s" % (self.destination.host, self.destination.port, str(e))) return - self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, network.connectionpool.BMConnectionPool().streams, False)) + 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) @@ -220,8 +224,9 @@ class Socks5BMConnection(Socks5Connection, TCPConnection): 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)) + network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid)) self.set_state("bm_header", expectBytes=protocol.Header.size) return True @@ -234,8 +239,9 @@ class Socks4aBMConnection(Socks4aConnection, TCPConnection): 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)) + network.connectionpool.BMConnectionPool().streams, False, nodeid=self.nodeid)) self.set_state("bm_header", expectBytes=protocol.Header.size) return True diff --git a/src/protocol.py b/src/protocol.py index d7bd5b8c..c2a58de8 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -186,7 +186,7 @@ def CreatePacket(command, payload=''): b[Header.size:] = payload return bytes(b) -def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server = False): +def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server = False, nodeid = None): payload = '' payload += pack('>L', 3) # protocol version. payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer. @@ -217,7 +217,10 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server payload += pack('>H', BMConfigParser().getint('bitmessagesettings', 'port')) random.seed() - payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf + if nodeid is not None: + payload += nodeid[0:8] + else: + payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf userAgent = '/PyBitmessage:' + softwareVersion + '/' payload += encodeVarint(len(userAgent)) payload += userAgent -- 2.45.1 From 853c8561ec4b936531902a28e33f087686332907 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 07:12:52 +0200 Subject: [PATCH 0852/1102] Per connection node id part 2 - forgot to include this in the previous commit --- src/network/bmproto.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 78149726..d2b5fa1f 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -362,7 +362,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.verackSent = True if not self.isOutbound: self.append_write_buf(protocol.assembleVersionMessage(self.destination.host, self.destination.port, \ - network.connectionpool.BMConnectionPool().streams, True)) + 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)): @@ -414,7 +414,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return False except: pass - if self.nonce == protocol.eightBytesOfRandomDataUsedToDetectConnectionsToSelf: + 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.", -- 2.45.1 From db2d78c9b6da261ee58bb8a4385bd124c559423b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 07:15:27 +0200 Subject: [PATCH 0853/1102] Make protocol decoder less recursive - apparently, recursion has bad performance in Python, so the decoder is now flat, except when parsing "version" command --- src/network/bmproto.py | 151 +++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 59 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d2b5fa1f..9aac3dda 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -152,8 +152,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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 + # 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 @@ -163,68 +163,101 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # 0-9 = length of the next item # , = end of array - retval = [] + 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 - i = 0 - try: - sys._getframe(200) - logger.error("Stack depth warning, pattern: %s", pattern) - return - except ValueError: - pass + isArray = False - while i < len(pattern): - if pattern[i] in "0123456789" and (i == 0 or pattern[i-1] not in "lL"): - if size is None: - size = 0 - size = size * 10 + int(pattern[i]) - i += 1 - continue - elif pattern[i] == "l" and size is None: + # 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() - i += 1 - continue - elif pattern[i] == "L" and size is None: - size = self.decode_payload_varint() - i += 1 - continue - if size is not None: - if pattern[i] == "s": - retval.append(self.payload[self.payloadOffset:self.payloadOffset + size]) - self.payloadOffset += size - i += 1 + if i == "L": + isArray = True else: - if "," in pattern[i:]: - subpattern = pattern[i:pattern.index(",")] - else: - subpattern = pattern[i:] - - for j in range(size): - if pattern[i-1:i] == "L": - retval.extend(self.decode_payload_content(subpattern)) - else: - retval.append(self.decode_payload_content(subpattern)) - i += len(subpattern) + 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, []]) + 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: - if pattern[i] == "v": - retval.append(self.decode_payload_varint()) - if pattern[i] == "i": - retval.append(self.decode_payload_node()) - if pattern[i] == "H": - retval.append(struct.unpack(">H", self.payload[self.payloadOffset:self.payloadOffset+2])[0]) - self.payloadOffset += 2 - if pattern[i] == "I": - retval.append(struct.unpack(">I", self.payload[self.payloadOffset:self.payloadOffset+4])[0]) - self.payloadOffset += 4 - if pattern[i] == "Q": - retval.append(struct.unpack(">Q", self.payload[self.payloadOffset:self.payloadOffset+8])[0]) - self.payloadOffset += 8 - i += 1 + 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() - return retval def bm_command_error(self): fatalStatus, banTime, inventoryVector, errorText = self.decode_payload_content("vvlsls") @@ -232,7 +265,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_getdata(self): - items = self.decode_payload_content("L32s") + items = self.decode_payload_content("l32s") # skip? if time.time() < self.skipUntil: return True @@ -246,7 +279,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def bm_command_inv(self): - items = self.decode_payload_content("L32s") + items = self.decode_payload_content("l32s") if len(items) >= BMProto.maxObjectCount: logger.error("Too many items in inv message!") @@ -294,7 +327,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True def _decode_addr(self): - return self.decode_payload_content("lQIQ16sH") + return self.decode_payload_content("LQIQ16sH") def bm_command_addr(self): addresses = self._decode_addr() @@ -344,7 +377,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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.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) -- 2.45.1 From f6d5d93bf249346fc7dbc215ed83e85b19b256ca Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 20:52:11 +0200 Subject: [PATCH 0854/1102] Multiple receive queues fix - forgot to commit busy handler --- src/network/advanceddispatcher.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index dbe65e39..1c33f376 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -50,6 +50,8 @@ class AdvancedDispatcher(asyncore.dispatcher): break except AttributeError: raise + except BusyError: + return False return False def set_state(self, state, length=0, expectBytes=0): -- 2.45.1 From dcc181bf75f4cac0288d300ceb235810ada93803 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 10 Jul 2017 23:18:58 +0200 Subject: [PATCH 0855/1102] Asyncore processing thread synchronisation - threre was a synchronisation problem where one thread could process more data than another thread was expecting, leading to the thread crashing --- src/network/advanceddispatcher.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 1c33f376..005aa038 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -43,9 +43,12 @@ class AdvancedDispatcher(asyncore.dispatcher): def process(self): if not self.connected: return False - while len(self.read_buf) >= self.expectBytes: + loop = 0 + while True: try: with nonBlocking(self.processingLock): + if len(self.read_buf) < self.expectBytes: + return False if getattr(self, "state_" + str(self.state))() is False: break except AttributeError: -- 2.45.1 From 4f19c37fdc3ace47784363066d103f5f99593fe7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 11 Jul 2017 10:29:29 +0200 Subject: [PATCH 0856/1102] Parser fix for multi-level arrays --- src/network/bmproto.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 9aac3dda..30068d6d 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -219,6 +219,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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": -- 2.45.1 From aa059d6f2fd45ec0d7de7bb2cd0477ff3552eb14 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 21 Jul 2017 07:47:18 +0200 Subject: [PATCH 0857/1102] Handle TLS errors in receivequeuethread - well at least EBADF, it seems to happen sometimes --- src/network/receivequeuethread.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index a899851f..a617e16e 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -1,4 +1,6 @@ +import errno import Queue +import socket import sys import threading import time @@ -43,4 +45,9 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): # 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() -- 2.45.1 From 2530c62050e9bcf26381233fa0f4b95f6f90e62e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 21 Jul 2017 07:49:34 +0200 Subject: [PATCH 0858/1102] epoll throws IOError rather than select.error --- src/network/asyncore_pollchoose.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 07b2c120..c1296744 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -310,6 +310,10 @@ def epoll_poller(timeout=0.0, map=None): 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 -- 2.45.1 From a29f7534ee54a6b93498ec13e581ee2da22dfc94 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 21 Jul 2017 09:06:02 +0200 Subject: [PATCH 0859/1102] Add EINTR handler for select and poll pollers --- src/network/asyncore_pollchoose.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index c1296744..3b21d3da 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -203,7 +203,7 @@ def select_poller(timeout=0.0, map=None): except KeyboardInterrupt: return except socket.error as err: - if err.args[0] in (EBADF, WSAENOTSOCK): + if err.args[0] in (EBADF, WSAENOTSOCK, EINTR): return for fd in random.sample(r, len(r)): @@ -263,6 +263,9 @@ def poll_poller(timeout=0.0, map=None): 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: -- 2.45.1 From 20cbac9752b103465064081f72fc8e038e9dfcdb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 28 Jul 2017 08:54:34 +0200 Subject: [PATCH 0860/1102] Fix daemonize for Windows Fixes #1034 --- src/bitmessagemain.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 3e0a1c84..50c138a2 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -316,14 +316,24 @@ class Main: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') def daemonize(self): - if os.fork(): - exit(0) - shared.thisapp.lock() # relock + try: + if os.fork(): + exit(0) + except AttributeError: + # fork not implemented + pass + else: + shared.thisapp.lock() # relock os.umask(0) os.setsid() - if os.fork(): - exit(0) - shared.thisapp.lock() # relock + try: + if os.fork(): + 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() -- 2.45.1 From 501f07dd34676fe472620b2a8274a01f389f158a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 28 Jul 2017 09:19:53 +0200 Subject: [PATCH 0861/1102] Setsid is not available on Windows - wrap an error handler around it --- src/bitmessagemain.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 50c138a2..4a7227e9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -325,7 +325,11 @@ class Main: else: shared.thisapp.lock() # relock os.umask(0) - os.setsid() + try: + os.setsid() + except AttributeError: + # setsid not implemented + pass try: if os.fork(): exit(0) -- 2.45.1 From e7382b7714947c69ad0427890bf4618ba3716ff9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 28 Jul 2017 09:39:49 +0200 Subject: [PATCH 0862/1102] Write PID into the lock file --- src/singleinstance.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index a6ac4552..d6337ff6 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -44,7 +44,7 @@ class singleinstance: # 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) + 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: @@ -52,6 +52,9 @@ class singleinstance: sys.exit(-1) print(e.errno) raise + else: + pidLine = "%i\n" % self.lockPid + self.fd.write(pidLine) else: # non Windows self.fp = open(self.lockfile, 'w') try: @@ -63,6 +66,10 @@ class singleinstance: except IOError: print 'Another instance of this application is already running' sys.exit(-1) + else: + pidLine = "%i\n" % self.lockPid + self.fp.write(pidLine) + self.fp.flush() def cleanup(self): if not self.initialized: -- 2.45.1 From 3e6de7a9ad10a14d1289f913b6ef0a4358578438 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 28 Jul 2017 19:21:56 +0200 Subject: [PATCH 0863/1102] Flush PID file on unix as well --- src/singleinstance.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/singleinstance.py b/src/singleinstance.py index d6337ff6..8a7fb68e 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -55,6 +55,7 @@ class singleinstance: else: pidLine = "%i\n" % self.lockPid self.fd.write(pidLine) + self.fd.flush() else: # non Windows self.fp = open(self.lockfile, 'w') try: -- 2.45.1 From 7a4551e1e72ce5ffd6fc359437435c077103e027 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 30 Jul 2017 09:36:20 +0200 Subject: [PATCH 0864/1102] Fix signal handler in daemon mode - signal handler requires the main thread to run --- src/bitmessagemain.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 4a7227e9..388a6068 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -27,6 +27,7 @@ import socket import ctypes from struct import pack from subprocess import call +from time import sleep from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections @@ -315,6 +316,10 @@ class Main: else: BMConfigParser().remove_option('bitmessagesettings', 'dontconnect') + if daemon: + while state.shutdown == 0: + sleep(1) + def daemonize(self): try: if os.fork(): -- 2.45.1 From 8f14fb05a1356ebe80de82ba08d248261bb700a6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 5 Aug 2017 10:14:15 +0200 Subject: [PATCH 0865/1102] UDP socket setsockopt fix --- src/network/udp.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/network/udp.py b/src/network/udp.py index 5c19fa69..bf52ebd5 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -33,6 +33,7 @@ class UDPSocket(BMProto): 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 @@ -42,12 +43,7 @@ class UDPSocket(BMProto): #except AttributeError: else: self.socket = sock - 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 + 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) @@ -55,6 +51,14 @@ class UDPSocket(BMProto): self.connected = True 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): BMProto.state_bm_command(self) -- 2.45.1 From 5108d08ac904231536d9d972c49cd4686f84ca65 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 18:18:21 +0200 Subject: [PATCH 0866/1102] Windows asyncore error handler fix - WSAEWOULDBLOCK is now checked on connect and accept --- src/network/asyncore_pollchoose.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 3b21d3da..ba156990 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -550,7 +550,7 @@ class dispatcher: self.connected = False self.connecting = True err = self.socket.connect_ex(address) - if err in (EINPROGRESS, EALREADY, EWOULDBLOCK) \ + if err in (EINPROGRESS, EALREADY, EWOULDBLOCK, WSAEWOULDBLOCK) \ or err == EINVAL and os.name in ('nt', 'ce'): self.addr = address return @@ -567,7 +567,7 @@ class dispatcher: except TypeError: return None except socket.error as why: - if why.args[0] in (EWOULDBLOCK, ECONNABORTED, EAGAIN, ENOTCONN): + if why.args[0] in (EWOULDBLOCK, WSAEWOULDBLOCK, ECONNABORTED, EAGAIN, ENOTCONN): return None else: raise -- 2.45.1 From 578c5dd49542b565578bec3b7c8836d624ffa81b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 18:29:08 +0200 Subject: [PATCH 0867/1102] Fix windows PID file --- src/singleinstance.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index 8a7fb68e..78a0cb33 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -54,8 +54,7 @@ class singleinstance: raise else: pidLine = "%i\n" % self.lockPid - self.fd.write(pidLine) - self.fd.flush() + os.write(self.fd, pidLine) else: # non Windows self.fp = open(self.lockfile, 'w') try: -- 2.45.1 From 5895dc2f1ff21ccc69f7571582f90d52875d51a5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 20:39:14 +0200 Subject: [PATCH 0868/1102] Asyncore Windows error handling - windows behaves somewhat differently when using select --- src/network/asyncore_pollchoose.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index ba156990..db6c1f4a 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -67,9 +67,14 @@ try: from errno import WSAENOTSOCK except (ImportError, AttributeError): WSAENOTSOCK = ENOTSOCK +try: + from errno import WSAECONNRESET +except (ImportError, AttributeError): + WSEACONNRESET = ECONNRESET _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, - EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT)) + EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, + WSAECONNRESET)) OP_READ = 1 OP_WRITE = 2 @@ -203,7 +208,10 @@ def select_poller(timeout=0.0, map=None): except KeyboardInterrupt: return except socket.error as err: - if err.args[0] in (EBADF, WSAENOTSOCK, EINTR): + 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)): @@ -686,6 +694,9 @@ class dispatcher: # 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() -- 2.45.1 From 38872159fb9dee140288504cde1a31b5bbdea85c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 20:40:35 +0200 Subject: [PATCH 0869/1102] Typo in previous commit --- src/network/asyncore_pollchoose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index db6c1f4a..91b41e23 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -208,7 +208,7 @@ def select_poller(timeout=0.0, map=None): except KeyboardInterrupt: return except socket.error as err: - if err.args[0] in (EBADF EINTR): + if err.args[0] in (EBADF, EINTR): return except Exception as err: if err.args[0] in (WSAENOTSOCK, ): -- 2.45.1 From 4564d37f5b969de760eec1ac7a12e0e9501ed121 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 21:26:25 +0200 Subject: [PATCH 0870/1102] Typo in previous commits --- src/network/asyncore_pollchoose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 91b41e23..2b874c0f 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -70,7 +70,7 @@ except (ImportError, AttributeError): try: from errno import WSAECONNRESET except (ImportError, AttributeError): - WSEACONNRESET = ECONNRESET + WSAECONNRESET = ECONNRESET _DISCONNECTED = frozenset((ECONNRESET, ENOTCONN, ESHUTDOWN, ECONNABORTED, EPIPE, EBADF, ECONNREFUSED, EHOSTUNREACH, ENETUNREACH, ETIMEDOUT, -- 2.45.1 From f338c00f8efc8868743882875ba9b9b5d92d90a0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 21:29:54 +0200 Subject: [PATCH 0871/1102] Change peer discovery tracking from queue to a dict - with a queue, a situation could occur when new entries are appended but nothing is polling the queue --- src/class_singleCleaner.py | 9 ++++++ src/network/connectionchooser.py | 49 ++++++++++++++++++-------------- src/network/udp.py | 4 +-- src/queues.py | 1 - src/state.py | 2 ++ 5 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index c21d8cb1..5cc35b41 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -38,6 +38,7 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) class singleCleaner(threading.Thread, StoppableThread): cycleLength = 300 + expireDiscoveredPeers = 300 def __init__(self): threading.Thread.__init__(self, name="singleCleaner") @@ -126,6 +127,14 @@ class singleCleaner(threading.Thread, StoppableThread): for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): connection.clean() + # discovery tracking + exp = time.time() - singleCleander.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 if state.shutdown == 0: diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 2cce5036..b4d7a37f 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -3,9 +3,15 @@ import random from bmconfigparser import BMConfigParser import knownnodes -from queues import portCheckerQueue, peerDiscoveryQueue +from queues import portCheckerQueue import state +def getDiscoveredPeer(stream): + try: + peer = random.choice(state.discoveredPeers.keys()) + except (IndexError, KeyError): + raise ValueError + def chooseConnection(stream): haveOnion = BMConfigParser().safeGet("bitmessagesettings", "socksproxytype")[0:5] == 'SOCKS' if state.trustedPeer: @@ -13,26 +19,25 @@ def chooseConnection(stream): try: retval = portCheckerQueue.get(False) portCheckerQueue.task_done() + return retval except Queue.Empty: + pass + if random.choice((False, True)): + return getDiscoveredPeer(stream) + for i in range(50): + peer = random.choice(knownnodes.knownNodes[stream].keys()) try: - retval = peerDiscoveryQueue.get(False) - peerDiscoveryQueue.task_done() - except Queue.Empty: - for i 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 and peer.host.endswith('.onion') and rating > 0: - rating *= 10 - if rating > 1: - rating = 1 - try: - if 0.05/(1.0-rating) > random.random(): - return peer - except ZeroDivisionError: - return peer - raise ValueError - return retval + rating = knownnodes.knownNodes[stream][peer]["rating"] + except TypeError: + print "Error in %s" % (peer) + rating = 0 + if haveOnion and peer.host.endswith('.onion') and rating > 0: + rating *= 10 + 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/udp.py b/src/network/udp.py index bf52ebd5..910e2430 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -9,7 +9,7 @@ from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInv import network.asyncore_pollchoose as asyncore from network.objectracker import ObjectTracker -from queues import objectProcessorQueue, peerDiscoveryQueue, UISignalQueue, receiveDataQueue +from queues import objectProcessorQueue, UISignalQueue, receiveDataQueue import state import protocol @@ -100,7 +100,7 @@ class UDPSocket(BMProto): return True logger.debug("received peer discovery from %s:%i (port %i):", self.destination.host, self.destination.port, remoteport) if self.local: - peerDiscoveryQueue.put(state.Peer(self.destination.host, remoteport)) + state.discoveredPeers[state.Peer(self.destination.host, remoteport)] = time.time return True def bm_command_portcheck(self): diff --git a/src/queues.py b/src/queues.py index f768c59f..e8923dbd 100644 --- a/src/queues.py +++ b/src/queues.py @@ -11,7 +11,6 @@ objectProcessorQueue = ObjectProcessorQueue() invQueue = MultiQueue() addrQueue = MultiQueue() portCheckerQueue = Queue.Queue() -peerDiscoveryQueue = 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/state.py b/src/state.py index 08da36eb..c9cb3d1c 100644 --- a/src/state.py +++ b/src/state.py @@ -41,6 +41,8 @@ ownAddresses = {} # security. trustedPeer = None +discoveredPeers = {} + Peer = collections.namedtuple('Peer', ['host', 'port']) def resetNetworkProtocolAvailability(): -- 2.45.1 From d9e4f2ceb86437f5cb6e851aa5e4b2297adf3232 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 21:38:23 +0200 Subject: [PATCH 0872/1102] Typo in previous commit --- src/class_singleCleaner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 5cc35b41..c37c3ecf 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -128,7 +128,7 @@ class singleCleaner(threading.Thread, StoppableThread): connection.clean() # discovery tracking - exp = time.time() - singleCleander.expireDiscoveredPeers + exp = time.time() - singleCleaner.expireDiscoveredPeers reaper = (k for k, v in state.discoveredPeers.items() if v < exp) for k in reaper: try: -- 2.45.1 From 0324958e9234ccbe66af12e15cbc7f5d7cb2c348 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 6 Aug 2017 23:05:54 +0200 Subject: [PATCH 0873/1102] Peer discovery fixes - incoming packets weren't correctly processed --- src/network/connectionchooser.py | 2 +- src/network/connectionpool.py | 4 ++-- src/network/udp.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index b4d7a37f..616a80f6 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -8,7 +8,7 @@ import state def getDiscoveredPeer(stream): try: - peer = random.choice(state.discoveredPeers.keys()) + return random.choice(state.discoveredPeers.keys()) except (IndexError, KeyError): raise ValueError diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index be7b8ceb..201432f0 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -61,8 +61,8 @@ class BMConnectionPool(object): return self.inboundConnections[addr.host] if addr in self.outboundConnections: return self.outboundConnections[addr] - if addr in self.udpSockets: - return self.udpSockets[addr] + if addr.host in self.udpSockets: + return self.udpSockets[addr.host] raise KeyError def isAlreadyConnected(self, nodeid): diff --git a/src/network/udp.py b/src/network/udp.py index 910e2430..8448da16 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -100,7 +100,7 @@ class UDPSocket(BMProto): 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 + state.discoveredPeers[state.Peer(self.destination.host, remoteport)] = time.time() return True def bm_command_portcheck(self): @@ -143,7 +143,7 @@ class UDPSocket(BMProto): # overwrite the old buffer to avoid mixing data and so that self.local works correctly self.read_buf = recdata self.bm_proto_reset() - receiveDataQueue.put(self.destination) + receiveDataQueue.put(self.listening) def handle_write(self): try: -- 2.45.1 From cc955cd69d7c0a9f41b98d88c85eaf91b2a8e6ba Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 9 Aug 2017 17:29:23 +0200 Subject: [PATCH 0874/1102] Try new ports of binding fails - API and BM protocol will try random ports for binding if those configured are occupied --- src/api.py | 2 ++ src/bitmessagemain.py | 22 ++++++++++++++++++++-- src/network/asyncore_pollchoose.py | 5 +++++ src/network/connectionpool.py | 4 +++- src/network/tcp.py | 21 ++++++++++++++++++++- src/upnp.py | 13 ++++++++++++- 6 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/api.py b/src/api.py index 52fb8e6e..7c67f89f 100644 --- a/src/api.py +++ b/src/api.py @@ -55,6 +55,8 @@ class APIError(Exception): class StoppableXMLRPCServer(SimpleXMLRPCServer): + allow_reuse_address = True + def serve_forever(self): while state.shutdown == 0: self.handle_request() diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 388a6068..17e97ffd 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -28,6 +28,7 @@ import ctypes from struct import pack from subprocess import call from time import sleep +from random import randint from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections @@ -171,8 +172,25 @@ class singleAPI(threading.Thread, helper_threading.StoppableThread): pass def run(self): - se = StoppableXMLRPCServer((BMConfigParser().get('bitmessagesettings', 'apiinterface'), BMConfigParser().getint( - 'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) + 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.register_introspection_functions() se.serve_forever() diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 2b874c0f..c2568e9f 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -58,6 +58,7 @@ 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 @@ -71,6 +72,10 @@ 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, diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 201432f0..8474e84c 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -119,7 +119,9 @@ class BMConnectionPool(object): def startListening(self): host = self.getListeningIP() port = BMConfigParser().safeGetInt("bitmessagesettings", "port") - self.listeningSockets[state.Peer(host, port)] = network.tcp.TCPServer(host=host, port=port) + # correct port even if it changed + ls = network.tcp.TCPServer(host=host, port=port) + self.listeningSockets[ls.destination] = ls def startUDPSocket(self, bind=None): if bind is None: diff --git a/src/network/tcp.py b/src/network/tcp.py index 01b19817..0fcbc160 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -252,10 +252,29 @@ class TCPServer(AdvancedDispatcher): AdvancedDispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.set_reuse_addr() - self.bind((host, port)) + 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: diff --git a/src/upnp.py b/src/upnp.py index 6c245345..ff657619 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -7,6 +7,7 @@ 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 @@ -179,7 +180,6 @@ class uPnPThread(threading.Thread, StoppableThread): def __init__ (self): threading.Thread.__init__(self, name="uPnPThread") - self.localPort = BMConfigParser().getint('bitmessagesettings', 'port') try: self.extPort = BMConfigParser().getint('bitmessagesettings', 'extport') except: @@ -199,6 +199,17 @@ class uPnPThread(threading.Thread, StoppableThread): 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: -- 2.45.1 From e071efac1a86e510c3e83d0b388485f1e3d7192b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 9 Aug 2017 17:29:48 +0200 Subject: [PATCH 0875/1102] Typo --- src/network/connectionpool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 8474e84c..96c6a6b6 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -106,7 +106,7 @@ class BMConnectionPool(object): def getListeningIP(self): if BMConfigParser().safeGet("bitmessagesettings", "onionhostname").endswith(".onion"): - host = BMConfigParser().safeGet("bitmessagesettigns", "onionbindip") + host = BMConfigParser().safeGet("bitmessagesettings", "onionbindip") else: host = '127.0.0.1' if BMConfigParser().safeGetBoolean("bitmessagesettings", "sockslisten") or \ -- 2.45.1 From 0b07b1c89a31ae3fcf6b26512498a30b89a5be62 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 9 Aug 2017 17:34:47 +0200 Subject: [PATCH 0876/1102] Peer discovery updates - allow loopback addresses, now you can bind different loopback IP addresses on a single system and they will auto-cross-connect - always listen for discovery on 0.0.0.0 - [network] - bind now also applies for the TCP socket as well as UDP socket - closing socket iterator fix --- src/bmconfigparser.py | 2 +- src/network/announcethread.py | 2 ++ src/network/connectionchooser.py | 7 ++++++- src/network/connectionpool.py | 16 ++++++++++------ src/network/udp.py | 3 ++- src/protocol.py | 4 +++- 6 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index 094cd73d..b8bf790f 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -20,7 +20,7 @@ BMConfigDefaults = { }, "network": { "asyncore": True, - "bind": None, + "bind": '', }, "inventory": { "storage": "sqlite", diff --git a/src/network/announcethread.py b/src/network/announcethread.py index 26d9f9cf..a94eeb36 100644 --- a/src/network/announcethread.py +++ b/src/network/announcethread.py @@ -28,6 +28,8 @@ class AnnounceThread(threading.Thread, StoppableThread): 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/connectionchooser.py b/src/network/connectionchooser.py index 616a80f6..681291ad 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -8,9 +8,14 @@ import state def getDiscoveredPeer(stream): try: - return random.choice(state.discoveredPeers.keys()) + 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' diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 96c6a6b6..3adc1772 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -113,7 +113,7 @@ class BMConnectionPool(object): BMConfigParser().get("bitmessagesettings", "socksproxytype") == "none": # python doesn't like bind + INADDR_ANY? #host = socket.INADDR_ANY - host = '' + host = BMConfigParser().get("network", "bind") return host def startListening(self): @@ -126,9 +126,12 @@ class BMConnectionPool(object): def startUDPSocket(self, bind=None): if bind is None: host = self.getListeningIP() - udpSocket = network.udp.UDPSocket(host=host) + udpSocket = network.udp.UDPSocket(host=host, announcing=True) else: - udpSocket = network.udp.UDPSocket(host=bind) + if bind is False: + udpSocket = network.udp.UDPSocket(announcing=False) + else: + udpSocket = network.udp.UDPSocket(host=bind, announcing=True) self.udpSockets[udpSocket.listening.host] = udpSocket def loop(self): @@ -192,19 +195,20 @@ class BMConnectionPool(object): self.startListening() logger.info('Listening for incoming connections.') if not self.udpSockets: - if BMConfigParser().safeGet("network", "bind") is None: + 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: + for i in self.listeningSockets.values(): i.handle_close() logger.info('Stopped listening for incoming connections.') if self.udpSockets: - for i in self.udpSockets: + for i in self.udpSockets.values(): i.handle_close() logger.info('Stopped udp sockets.') diff --git a/src/network/udp.py b/src/network/udp.py index 8448da16..27cf0abb 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -17,7 +17,7 @@ class UDPSocket(BMProto): port = 8444 announceInterval = 60 - def __init__(self, host=None, sock=None): + def __init__(self, host=None, sock=None, announcing=False): super(BMProto, self).__init__(sock=sock) self.verackReceived = True self.verackSent = True @@ -49,6 +49,7 @@ class UDPSocket(BMProto): 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): diff --git a/src/protocol.py b/src/protocol.py index c2a58de8..7ad0db17 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -37,6 +37,8 @@ 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)) @@ -108,7 +110,7 @@ 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 False + return hostStandardFormat if private else False if host[0] == '\x0A': # 10/8 if not private: logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) -- 2.45.1 From 6c695c8ac77842f02af25162b89ed250e725a584 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 9 Aug 2017 17:36:52 +0200 Subject: [PATCH 0877/1102] Remove non-asyncore network code (partial) --- src/api.py | 12 +----- src/bitmessagemain.py | 55 ++++++++++--------------- src/bmconfigparser.py | 1 - src/class_singleWorker.py | 36 +++------------- src/network/stats.py | 86 ++++++++++++++++----------------------- 5 files changed, 65 insertions(+), 125 deletions(-) diff --git a/src/api.py b/src/api.py index 7c67f89f..dcc83538 100644 --- a/src/api.py +++ b/src/api.py @@ -864,11 +864,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((toStreamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - toStreamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((toStreamNumber, inventoryHash)) def HandleTrashSentMessageByAckDAta(self, params): # This API method should only be used when msgid is not available @@ -914,11 +910,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - pubkeyStreamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((pubkeyStreamNumber, inventoryHash)) def HandleGetMessageDataByDestinationHash(self, params): # Method will eventually be used by a particular Android app to diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 17e97ffd..eed725d3 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -92,13 +92,7 @@ def connectToStream(streamNumber): if streamNumber*2+1 not in knownnodes.knownNodes: knownnodes.knownNodes[streamNumber*2+1] = {} - if BMConfigParser().get("network", "asyncore"): - BMConnectionPool().connectToStream(streamNumber) - else: - for i in range(state.maximumNumberOfHalfOpenConnections): - a = outgoingSynSender() - a.setup(streamNumber, selfInitiatedConnections) - a.start() + BMConnectionPool().connectToStream(streamNumber) def _fixSocket(): if sys.platform.startswith('linux'): @@ -281,36 +275,29 @@ class Main: singleAPIThread.daemon = True # close the main program even if there are threads left singleAPIThread.start() - if BMConfigParser().get("network", "asyncore"): - 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() + 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 not BMConfigParser().get("network", "asyncore"): - singleListenerThread = singleListener() - singleListenerThread.setup(selfInitiatedConnections) - singleListenerThread.daemon = True # close the main program even if there are threads left - singleListenerThread.start() - if BMConfigParser().safeGetBoolean('bitmessagesettings','upnp'): import upnp upnpThread = upnp.uPnPThread() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index b8bf790f..acc4476a 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -19,7 +19,6 @@ BMConfigDefaults = { "receive": 3, }, "network": { - "asyncore": True, "bind": '', }, "inventory": { diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 07c768a4..e7f58f1b 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -192,11 +192,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((streamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -286,11 +282,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((streamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -380,11 +372,7 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((streamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateStatusBar', '')) try: BMConfigParser().set( @@ -513,11 +501,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, tag) PendingUpload().add(inventoryHash) logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((streamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((streamNumber, inventoryHash)) queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr._translate("MainWindow", "Broadcast sent on %1").arg(l10n.formatTimestamp())))) @@ -846,11 +830,7 @@ class singleWorker(threading.Thread, StoppableThread): # 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)) - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((toStreamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - toStreamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((toStreamNumber, 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): @@ -952,11 +932,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, streamNumber, payload, embeddedTime, '') PendingUpload().add(inventoryHash) logger.info('sending inv (for the getpubkey message)') - if BMConfigParser().get("network", "asyncore"): - queues.invQueue.put((streamNumber, inventoryHash)) - else: - protocol.broadcastToSendDataQueues(( - streamNumber, 'advertiseobject', inventoryHash)) + queues.invQueue.put((streamNumber, inventoryHash)) # wait 10% past expiration sleeptill = int(time.time() + TTL * 1.1) diff --git a/src/network/stats.py b/src/network/stats.py index 7f7c83ac..45961ac1 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -15,67 +15,53 @@ lastSentBytes = 0 currentSentSpeed = 0 def connectedHostsList(): - if BMConfigParser().get("network", "asyncore"): - retval = [] - for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - if not i.fullyEstablished: - continue - try: - retval.append(i) - except AttributeError: - pass - return retval - return shared.connectedHostsList.items() + 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(): - if BMConfigParser().get("network", "asyncore"): - return asyncore.sentBytes - return throttle.SendThrottle().total + return asyncore.sentBytes def uploadSpeed(): global lastSentTimestamp, lastSentBytes, currentSentSpeed - if BMConfigParser().get("network", "asyncore"): - currentTimestamp = time.time() - if int(lastSentTimestamp) < int(currentTimestamp): - currentSentBytes = asyncore.sentBytes - currentSentSpeed = int((currentSentBytes - lastSentBytes) / (currentTimestamp - lastSentTimestamp)) - lastSentBytes = currentSentBytes - lastSentTimestamp = currentTimestamp - return currentSentSpeed - return throttle.sendThrottle().getSpeed() + 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(): - if BMConfigParser().get("network", "asyncore"): - return asyncore.receivedBytes - return throttle.ReceiveThrottle().total + return asyncore.receivedBytes def downloadSpeed(): global lastReceivedTimestamp, lastReceivedBytes, currentReceivedSpeed - if BMConfigParser().get("network", "asyncore"): - currentTimestamp = time.time() - if int(lastReceivedTimestamp) < int(currentTimestamp): - currentReceivedBytes = asyncore.receivedBytes - currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / (currentTimestamp - lastReceivedTimestamp)) - lastReceivedBytes = currentReceivedBytes - lastReceivedTimestamp = currentTimestamp - return currentReceivedSpeed - return throttle.ReceiveThrottle().getSpeed() + 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(): - if BMConfigParser().get("network", "asyncore"): - tmp = {} - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - for k in connection.objectsNewToMe.keys(): - tmp[k] = True - return len(tmp) - return PendingDownloadQueue.totalSize() + tmp = {} + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for k in connection.objectsNewToMe.keys(): + tmp[k] = True + return len(tmp) def pendingUpload(): - if BMConfigParser().get("network", "asyncore"): - return 0 - tmp = {} - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): - for k in connection.objectsNewToThem.keys(): - tmp[k] = True - return len(tmp) - return PendingUpload().len() + return 0 + tmp = {} + for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for k in connection.objectsNewToThem.keys(): + tmp[k] = True + return len(tmp) -- 2.45.1 From e7231f3aead4d10a49dbb46092b4204fee598e2e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 9 Aug 2017 23:30:22 +0200 Subject: [PATCH 0878/1102] Fix multiple TCP bind address handling --- src/network/connectionpool.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 3adc1772..1026d305 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -116,11 +116,12 @@ class BMConnectionPool(object): host = BMConfigParser().get("network", "bind") return host - def startListening(self): - host = self.getListeningIP() + def startListening(self, bind=None): + if bind is None: + bind = self.getListeningIP() port = BMConfigParser().safeGetInt("bitmessagesettings", "port") # correct port even if it changed - ls = network.tcp.TCPServer(host=host, port=port) + ls = network.tcp.TCPServer(host=bind, port=port) self.listeningSockets[ls.destination] = ls def startUDPSocket(self, bind=None): @@ -192,7 +193,11 @@ class BMConnectionPool(object): if acceptConnections: if not self.listeningSockets: - self.startListening() + 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") == '': -- 2.45.1 From 85e4e5438ca942d3d9ac5b6d3938adad711e6067 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 11 Aug 2017 09:38:00 +0200 Subject: [PATCH 0879/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 96084 -> 97437 bytes src/translations/bitmessage_de.ts | 356 +++++++++++++++++------------- 2 files changed, 200 insertions(+), 156 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 4a74855d7a47ec4a283f69ca93a1174c3d40a899..6bef4d31ab079830dc5d9da8359206caf3d17d48 100644 GIT binary patch delta 4810 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 MY-SZdp5^uZFD#l{q5uE@ diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index d9c57fd2..99505de8 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -27,7 +27,7 @@ Register on email gateway - An E-Mailschnittstelle registrieren + An E-Mail Schnittstelle registrieren @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -324,7 +324,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Bestätigung der Nachricht erhalten %1 - + Broadcast queued. Rundruf in Warteschlange. @@ -354,7 +354,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Unbekannter Status: %1 %2 - + Not Connected Nicht verbunden @@ -386,7 +386,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. + 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. @@ -395,7 +395,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 anlegen. +Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. @@ -405,7 +405,7 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. 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 anlegen. Möchten Sie die Datei jetzt öffnen? (Stellen Sie sicher, dass Sie Bitmessage beendet haben, bevor Sie etwas ändern.) + 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.) @@ -414,7 +414,7 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. 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 anlegen. Möchten Sie die Datei jetzt öffnen? +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.) @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 @@ -541,19 +541,19 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. + Fehler: Ihr Konto war an keiner E-Mail Schnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die - + 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 Von - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anlegen. Möchten Sie die 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1016,7 +1016,7 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? TTL: - Haltbarkeit: + Lebenszeit: @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1174,7 +1174,7 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% @@ -1224,60 +1224,60 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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% @@ -1287,7 +1287,7 @@ Receiver's required difficulty: %1 and %2 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 @@ -1297,22 +1297,22 @@ Receiver's required difficulty: %1 and %2 Arbeit wird verrichtet, um den Schlüssel nachzufragen... - + 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. - + 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 - + UPnP port mapping established on port %1 UPnP Port-Mapping eingerichtet auf Port %1 - + UPnP port mapping removed UPnP Port-Mapping entfernt @@ -1322,7 +1322,7 @@ Receiver's required difficulty: %1 and %2 Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? @@ -1332,37 +1332,37 @@ Receiver's required difficulty: %1 and %2 Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? - + Problem communicating with proxy: %1. Please check your network settings. Kommunikationsfehler mit dem Proxy: %1. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. SOCKS5-Authentizierung fehlgeschlagen: %1. Bitte überprüfen Sie Ihre SOCKS5-Einstellungen. - + 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. @@ -1420,11 +1420,10 @@ Receiver's required difficulty: %1 and %2 * discuss in chan(nel)s with other people -Wilkommen zu einfacher und sicherer Bitmessage +Willkommen zu einfachem und sicherem Bitmessage * senden Sie Nachrichten an andere Leute -* senden Sie Rundruf-Nachrichte wie bei Twitter oder -* diskutieren Sie mit anderen Leuten in Chans - +* senden Sie Rundrufe wie bei Twitter oder +* diskutieren Sie mit anderen Leuten in Chans @@ -1432,77 +1431,77 @@ Wilkommen zu einfacher und sicherer Bitmessage für Chans nicht empfohlen - + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + 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. - + 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... @@ -1533,14 +1532,14 @@ Wilkommen zu einfacher und sicherer Bitmessage 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 @@ -1849,77 +1848,77 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 - Verbindungen + - + 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 @@ -1929,30 +1928,75 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 ausgehandelten Datenströme + newChanDialog @@ -2014,12 +2058,12 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Optional, for advanced usage - Optional, für fortgeschrittene + Optional, für Fortgeschrittene Chan address - Chan-adresse + Chan-Adresse @@ -2390,7 +2434,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi <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 Verfalldatum herunterlädt, zum Beisplel 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>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> -- 2.45.1 From 4d0a40fd2aa50b2f0cd6ddfa590c6d7238fafc7a Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 11 Aug 2017 09:46:06 +0200 Subject: [PATCH 0880/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 88644 -> 89951 bytes src/translations/bitmessage_sk.ts | 329 +++++++++++++++++------------- 2 files changed, 187 insertions(+), 142 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 9a3e3670bf05e692e2084bef71abbc91bd73c4c9..525f4b38b7718e499d3278aec4920621a50ed13a 100644 GIT binary patch delta 2443 zcmZuydr(y875{yA-}f#uf+C=-7bc)G*#$A6i1HAtXocb!K!0~|LmZ>IuOqKb&1b`Ni)sL+a79WkGWae2YmHobIbS+!194v4_kn~CH%N~mYDpA`PVllfK8Ej zoMmnH_}iBC>lCn(JC=?6XHzL}Shh^{052T0yihm+_&C|J%!NmPbmj^pT(6>I^MdmZ7qqyWZgOU8d!BQ zcUueUinFX2Yl!N!?bcgX71;GJTf){(prh3`Sv&(~*W4GH|1 zc<`})VE+j59f_tKoguz|hJ^0O7f-A^Nb^}Oe!78L&{QH`S$YjPwO_m$rF6MJmssUK zV259Fv@1ZFDv74gkch5hlK590EGbEf>!O_-Ife%v>9)e^Oxn)Z_!ft&Gwn60>RrmY zJ5!oJum`N@rc}SWjB;Lup7lXjdf2Xmc}b~+vbHasl7)wd1kzbc(x z7XS_)mQG(K4zH|`{`g`QSh_BqYrh3HW4Cm^;(1`g@1+|FG~T~ol5WUNU^#it+?wU! z+2X|PoG+Z=IWJM}hn@O`A|T_p&i2I&_(g(q^Qo@_V9R$XUggNm;_c1>P-r#MJI#_GF@A9m9{)ZMw{_NowBMbHi@We~6ZE z)v$ioFtFsy@j02Pfc2RgU zhO^FEJVD_d1n5POfWwsV8%k@?mSfg{_tASR!S|t_(#hnh&|L?mlw;)uV<&@Tm~bNG zsgj3Ld~k@&qlA&ZqNs9vs8#l=K3Q*6ZJuGFCF(Dr@ zY9cFBBQ@fzFk}8SBWB!%>C{Xf8d;;oAzpMmrL&n%MvT$u5YcU+hPF|4#z>6%V%*@N zuL^p9;ANB$h-Dg7h=JXRcGAcL28OQ;H~nu94pWYuj6oUM!-U(8HdbLB42TYx+33y( zOpW|?gdU;C2P}+8gSC;tNA=YYRz{2iL;c@Z-996r2T63^21V8*-uh-OHc+j#zTS{x zghp-%q5i*X;MH{{7}m)z)F}s4U!X1EYxTCsYRIQ(9(fVTfuaIx0~xhJ(PV!l6qMZ) z$zPrrQ;gT|r delta 1329 zcmX9-c~I3=6#njSeZK`BJV6%WDI_S*cr3~y4<53*@)~0VQE>$oOu$e}41`FhTw$(; zI*>Av2Z7K5$s&7AI%WblX*=rE@7=qnJJ8J&H)C(gajv(F|t=kaU27> zLxmX~Pl4rB$UkXi>U|@u(OQ6q9}4eGECa+#^sbPuj>-`(J_-Su98ROeioo$6Vs&Lc zh|OEv6=wzZpBDE|4FP`i77sot1@SGVJz}tB@?r78^tXUefAKlr1QdshFH+rsAWd>F zWMTF^Df0-^!Q&PUmCPnvhV=2q3Sc2G)z7*MGCP6hO3}-w&X#(z7`2#l(qpLzXnZM~ zYPJAn8{`Gl9ZegmHAMjlsYa0E3PP2uZBT551MNTwur}-hU)9U)f(k+ zJPUu=ubgURnykF3bVT}sxLs5_hCXBIm*@#Yut{>N+B&8rZm6R&n5(89de>l`6;rOR z&SO#b0kyC%3ivhXKO{a!)rv(AKqe)q2k*TGuC%Hx_J7!9|E`|S9tOVhP|s@2-nwM< z`%X65LKn?d%-p07TCSK?cbn!?#a6~Gi5^h`Xs6=8#rvw}_?9I$1!;3fjxo_q+KSCd zAY!JrqpX^tzgBahn-$!s9qdX0@wun3jn86yVleU{ND+IA*>)~08K?~Igi)BbJnb`mmJy&0U z#|8vm*Ei)5;J8WO(Ov@#UDWp`GU?LtX}fCYY^_w(g4HQ~`kl>PY2!)8}DhoUho$QLm586%4} zfJ9^)qpq1jtUnuVWA=i$U!m=~H4sK)RXV$t4aPm)Y!l1NjZNm;K+zgwbH^}<*^PR- zM9a1pZ1^%J(6z5pPk-t%GRV6jv#xR)@zS-F;-aGb73&L%i%RPPbmCR_Tp{P26ExyZ foC7+!N}QXGq(rET8BK0FqrFHTao+bP@1_3>#bbn< diff --git a/src/translations/bitmessage_sk.ts b/src/translations/bitmessage_sk.ts index 98c7cb56..d58d4f46 100644 --- a/src/translations/bitmessage_sk.ts +++ b/src/translations/bitmessage_sk.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrácia zlyhala: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: @@ -321,7 +321,7 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Potvrdenie prijatia správy %1 - + Broadcast queued. Rozoslanie vo fronte. @@ -351,7 +351,7 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Neznámy stav: %1 %2 - + Not Connected Nepripojený @@ -514,22 +514,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +537,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,67 +592,67 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 Od - + Sending email gateway registration request Odosielam požiadavku o registráciu na e-mailovej bráne @@ -667,142 +667,142 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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 Odosielam žiadosť o odhlásenie z e-mailovej brány - + Sending email gateway status request Odosielam požiadavku o stave e-mailovej brány - + 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. Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. - + 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? 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. Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. - + 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. Zadajte adresu vyššie. - + 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). Používate port TCP %1. (Možno zmeniť v nastaveniach). @@ -1115,47 +1115,47 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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% @@ -1170,7 +1170,7 @@ Ste si istý, že chcete kanál odstrániť? %n deň%n dni%n dní - + Shutting down PyBitmessage... %1% Ukončujem PyBitmessage... %1% @@ -1220,61 +1220,61 @@ Ste si istý, že chcete kanál odstrániť? 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 @@ -1284,7 +1284,7 @@ Priímcova požadovaná obtiažnosť: %1 a %2 Vykonávam prácu potrebnú na odoslanie... - + Message sent. Waiting for acknowledgement. Sent on %1 Správa odoslaná. Čakanie na potvrdenie. Odoslaná %1 @@ -1294,22 +1294,22 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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é @@ -1319,7 +1319,7 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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é? @@ -1329,37 +1329,37 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. @@ -1429,77 +1429,77 @@ Vitajte v jednoduchom a bezpečnom Bitmessage nie je odporúčaná pre kanály - + Problems connecting? Try enabling UPnP in the Network Settings Problémy so spojením? Skúste zapnúť UPnP v Nastaveniach siete - + 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. - + 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... @@ -1530,14 +1530,14 @@ Vitajte v jednoduchom a bezpečnom Bitmessage 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 @@ -1846,77 +1846,77 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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 - Spojenia + - + 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 @@ -1926,30 +1926,75 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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 -- 2.45.1 From 3c50615998cbb641742dc55c9573bf0de9313601 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sun, 13 Aug 2017 16:54:52 +0200 Subject: [PATCH 0881/1102] Auto-updated language zh_cn from transifex --- src/translations/bitmessage_zh_cn.qm | Bin 54427 -> 57332 bytes src/translations/bitmessage_zh_cn.ts | 697 ++++++++++++++++----------- 2 files changed, 421 insertions(+), 276 deletions(-) diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index 14625aef1df9c67a46a6983006d20f671c2b9baa..77b56321fd51c739be799b37851bf168ca4230b0 100644 GIT binary patch delta 5887 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 delta 3358 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 KtiN3KH~t?N0`l_! diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 323bf123..263477d3 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -58,12 +58,12 @@ 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)如下: @@ -82,7 +82,7 @@ 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: @@ -166,122 +166,122 @@ Please type the desired email address (including @mailchuck.com) below: 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. 正在等待他们的加密密钥,我们会在稍后再次请求。 @@ -291,17 +291,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. 已经添加到队列。 - + Message sent. Waiting for acknowledgement. Sent at %1 消息已经发送. 正在等待回执. 发送于 %1 - + Message sent. Sent at %1 消息已经发送. 发送于 %1 @@ -311,47 +311,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 显示比特信 @@ -361,12 +361,12 @@ Please type the desired email address (including @mailchuck.com) below: 发送 - + Subscribe 订阅 - + Channel 频道 @@ -376,66 +376,66 @@ Please type the desired email address (including @mailchuck.com) below: 退出 - + 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. @@ -505,22 +505,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -529,17 +529,17 @@ It is important that you back up this file. Would you like to open the file now? 收件人必须在此期间得到它. 如果您的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​​, 注册正在处理请稍候重试发送. @@ -584,217 +584,217 @@ It is important that you back up this file. Would you like to open the file now? - + 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接收了地址。 - + 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? 比特信无法找到你的地址 %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? @@ -803,7 +803,7 @@ 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? @@ -812,92 +812,92 @@ 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. 没有可以显示的近期广播。 - + You are using TCP port %1. (This can be changed in the settings). 您正在使用TCP端口 %1 。(可以在设置中修改)。 @@ -1097,57 +1097,57 @@ Are you sure you want to delete the channel? 缩放级别%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% @@ -1157,42 +1157,42 @@ Are you sure you want to delete the channel? %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 完成生成地址 @@ -1202,226 +1202,295 @@ Are you sure you want to delete the channel? - + 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 件发件人的地址 ( 您的地址). - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. 做必要的工作, 以发送信息. 这样第2版的地址没有难度. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. 做必要的工作, 以发送信息. - + Message sent. Waiting for acknowledgement. Sent on %1 信息发送. 等待确认. 已发送%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 发送公钥的请求. 等待回复. 请求在%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。请报告给开发者。 + + + + + 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 + 频道内不建议的内容 + + + + Problems connecting? Try enabling UPnP in the Network Settings + 连接问题?请尝试在网络设置里打开UPnP + + + 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有问题。 - + 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... 等待同步完成…… @@ -1452,14 +1521,14 @@ Receiver's required difficulty: %1 and %2 MsgDecode - + The message has an unknown encoding. Perhaps you should upgrade Bitmessage. 这些消息使用了未知编码方式。 你可能需要更新Bitmessage软件。 - + Unknown encoding 未知编码 @@ -1617,27 +1686,27 @@ The 'Random Number' option is selected by default but deterministic ad 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> <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阶段。 @@ -1647,7 +1716,7 @@ The 'Random Number' option is selected by default but deterministic ad - + <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> @@ -1680,12 +1749,12 @@ The 'Random Number' option is selected by default but deterministic ad 地址 - + Blacklist 黑名单 - + Whitelist 白名单 @@ -1767,77 +1836,77 @@ The 'Random Number' option is selected by default but deterministic ad 总连接: - + 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 /秒 @@ -1847,30 +1916,75 @@ The 'Random Number' option is selected by default but deterministic ad 网络状态 - + 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 @@ -1953,16 +2067,42 @@ The 'Random Number' option is selected by default but deterministic ad 成功创建或加入频道%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 + 二维码 + + regenerateAddressesDialog @@ -2019,218 +2159,218 @@ 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 愿意在发送到手机时使用不加密的目标地址 - + Use 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 - + 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 最大可接受难度 @@ -2240,82 +2380,87 @@ The 'Random Number' option is selected by default but deterministic ad - + <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): -- 2.45.1 From 58b47bc6de9816bf8c74e6a597d3fa1d28a15436 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Aug 2017 12:22:24 +0200 Subject: [PATCH 0882/1102] Forking fixes --- src/bitmessagemain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index eed725d3..426af695 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -328,7 +328,7 @@ class Main: def daemonize(self): try: if os.fork(): - exit(0) + os._exit(0) except AttributeError: # fork not implemented pass @@ -342,7 +342,7 @@ class Main: pass try: if os.fork(): - exit(0) + os._exit(0) except AttributeError: # fork not implemented pass -- 2.45.1 From a48dff3bee03bb37b2893372aba7563e3b97433c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Aug 2017 12:24:43 +0200 Subject: [PATCH 0883/1102] PoW init reordering - inited by the worker thread on its own init, instead of when the imports are being evaluated - also got rid of windows-style newlines in OpenCL PoW --- src/class_singleWorker.py | 1 + src/openclpow.py | 216 +++++++++++++++++++------------------- src/proofofwork.py | 9 +- 3 files changed, 114 insertions(+), 112 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index e7f58f1b..58eb33c6 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -42,6 +42,7 @@ class singleWorker(threading.Thread, StoppableThread): # QThread.__init__(self, parent) threading.Thread.__init__(self, name="singleWorker") self.initStop() + proofofwork.init() def stopThread(self): try: diff --git a/src/openclpow.py b/src/openclpow.py index ca40e634..894a5b77 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -1,111 +1,111 @@ -#!/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(): +#!/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) - + 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/proofofwork.py b/src/proofofwork.py index eb845c25..12d513b6 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -237,6 +237,9 @@ def resetPoW(): # init def init(): global bitmsglib, bso, bmpow + + openclpow.initCL() + if "win32" == sys.platform: if ctypes.sizeof(ctypes.c_voidp) == 4: bitmsglib = 'bitmsghash32.dll' @@ -286,7 +289,5 @@ def init(): bmpow = None else: bmpow = None - -init() -if bmpow is None: - buildCPoW() + if bmpow is None: + buildCPoW() -- 2.45.1 From 623553393b640cb459262053bd73cd3ddc320810 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Aug 2017 12:25:38 +0200 Subject: [PATCH 0884/1102] PID file truncate fix - on unix it truncated the file if a second instance was being launched --- src/singleinstance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index 78a0cb33..7a025945 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -56,7 +56,7 @@ class singleinstance: pidLine = "%i\n" % self.lockPid os.write(self.fd, pidLine) else: # non Windows - self.fp = open(self.lockfile, 'w') + 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 @@ -68,6 +68,7 @@ class singleinstance: sys.exit(-1) else: pidLine = "%i\n" % self.lockPid + self.fp.truncate(0) self.fp.write(pidLine) self.fp.flush() -- 2.45.1 From 8b3d7ea2780dbd1ddc23dd0fc3e27f7824ce04d3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Aug 2017 14:09:19 +0200 Subject: [PATCH 0885/1102] C PoW init fix --- src/proofofwork.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/proofofwork.py b/src/proofofwork.py index 12d513b6..df6ed295 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -19,6 +19,8 @@ import state bitmsglib = 'bitmsghash.so' +bmpow = None + def _set_idle(): if 'linux' in sys.platform: os.nice(20) -- 2.45.1 From 2da4d007303afead1028f7d468b2a890af5c0900 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 15 Aug 2017 18:14:36 +0200 Subject: [PATCH 0886/1102] Support message C PoW fix --- src/bitmessageqt/support.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 67e46500..8ec3c16d 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -13,7 +13,7 @@ from helper_sql import * from l10n import getTranslationLanguage from openclpow import openclAvailable, openclEnabled import paths -from proofofwork import bmpow +import proofofwork from pyelliptic.openssl import OpenSSL import queues import shared @@ -111,7 +111,7 @@ def createSupportMessage(myapp): if paths.frozen: frozen = paths.frozen portablemode = "True" if state.appdata == paths.lookupExeFolder() else "False" - cpow = "True" if bmpow 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) -- 2.45.1 From 314af0925f0514ce84f297877f4347bd1d767668 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 20 Aug 2017 11:55:54 +0200 Subject: [PATCH 0887/1102] Daemonize fix for Windows - /dev/null isn't available on Windows so just close the console sockets directly --- src/bitmessagemain.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 426af695..62e79371 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -351,12 +351,18 @@ class Main: shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() - si = file('/dev/null', 'r') - so = file('/dev/null', 'a+') - se = file('/dev/null', 'a+', 0) - os.dup2(si.fileno(), sys.stdin.fileno()) - os.dup2(so.fileno(), sys.stdout.fileno()) - os.dup2(se.fileno(), sys.stderr.fileno()) + try: + si = file('/dev/null', 'r') + so = file('/dev/null', 'a+') + se = file('/dev/null', 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + # /dev/null not available + except IOError: + sys.stdin.close() + sys.stdout.close() + sys.stderr.close() def setSignalHandler(self): signal.signal(signal.SIGINT, helper_generic.signal_handler) -- 2.45.1 From b886f935d465eb8dd42537117746185556dc83c7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 20 Aug 2017 12:05:53 +0200 Subject: [PATCH 0888/1102] Daemon Windows fix - closing the filehandle isn't the correct approach, it causes more bugs. Use os.devnull instead --- src/bitmessagemain.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 62e79371..894c9e08 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -351,18 +351,12 @@ class Main: shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() - try: - si = file('/dev/null', 'r') - so = file('/dev/null', 'a+') - se = file('/dev/null', 'a+', 0) - os.dup2(si.fileno(), sys.stdin.fileno()) - os.dup2(so.fileno(), sys.stdout.fileno()) - os.dup2(se.fileno(), sys.stderr.fileno()) - # /dev/null not available - except IOError: - sys.stdin.close() - sys.stdout.close() - sys.stderr.close() + 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()) def setSignalHandler(self): signal.signal(signal.SIGINT, helper_generic.signal_handler) -- 2.45.1 From b7f808cde18c503502977cac679ea00682d4ab53 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 21 Aug 2017 10:39:03 +0200 Subject: [PATCH 0889/1102] Add shutdown command to API - calling "shutdown" now cleanly shuts down PyBitmessage, however the call may not return so you need to add an error handler to the call. With python for example, wrap the "shutdown()" in "try:/except socket.error" --- src/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api.py b/src/api.py index dcc83538..05b27432 100644 --- a/src/api.py +++ b/src/api.py @@ -30,6 +30,7 @@ import protocol import state from pyelliptic.openssl import OpenSSL import queues +import shutdown from struct import pack import network.stats @@ -982,6 +983,10 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): sqlStoredProcedure('deleteandvacuume') return 'done' + def HandleShutdown(self, params): + shutdown.doCleanShutdown() + return 'done' + handlers = {} handlers['helloWorld'] = HandleHelloWorld handlers['add'] = HandleAdd @@ -1032,6 +1037,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): handlers['clientStatus'] = HandleClientStatus handlers['decodeAddress'] = HandleDecodeAddress handlers['deleteAndVacuum'] = HandleDeleteAndVacuum + handlers['shutdown'] = HandleShutdown def _handle_request(self, method, params): if (self.handlers.has_key(method)): -- 2.45.1 From 18119339f8d1fab0ae150e6ce98c4bb161089f67 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 22 Aug 2017 13:23:03 +0200 Subject: [PATCH 0890/1102] Add shutdown to CLI --- src/bitmessagecli.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 068a5597..ee877818 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -12,6 +12,7 @@ import getopt import imghdr import ntpath import json +import socket import time import sys import os @@ -1283,6 +1284,13 @@ def clientStatus(): 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 @@ -1705,6 +1713,11 @@ def UI(usrInput): #Main user menu usrPrompt = 1 main() + elif usrInput == "shutdown": + shutdown() + usrPrompt = 1 + main() + elif usrInput == "million+": genMilAddr() usrPrompt = 1 -- 2.45.1 From 660997b8f4a94a21a73d050134e7e886dee12b9c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 22 Aug 2017 13:49:27 +0200 Subject: [PATCH 0891/1102] Code Quality --- src/api.py | 13 ++++++----- src/bitmessagemain.py | 2 -- src/network/advanceddispatcher.py | 3 --- src/network/asyncore_pollchoose.py | 37 +++++++++++++++--------------- src/network/bmproto.py | 8 ++----- src/network/connectionchooser.py | 10 ++++---- src/network/stats.py | 21 +++++++++-------- 7 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/api.py b/src/api.py index 05b27432..e20854fc 100644 --- a/src/api.py +++ b/src/api.py @@ -26,7 +26,6 @@ import helper_inbox import helper_sent import hashlib -import protocol import state from pyelliptic.openssl import OpenSSL import queues @@ -980,12 +979,14 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): queues.UISignalQueue.put(('updateStatusBar', message)) def HandleDeleteAndVacuum(self, params): - sqlStoredProcedure('deleteandvacuume') - return 'done' + if not params: + sqlStoredProcedure('deleteandvacuume') + return 'done' def HandleShutdown(self, params): - shutdown.doCleanShutdown() - return 'done' + if not params: + shutdown.doCleanShutdown() + return 'done' handlers = {} handlers['helloWorld'] = HandleHelloWorld @@ -1041,7 +1042,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 894c9e08..1d37123f 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -44,8 +44,6 @@ import threading 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 diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 005aa038..eb636aed 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -1,6 +1,4 @@ -import Queue import socket -import sys import threading import time @@ -43,7 +41,6 @@ class AdvancedDispatcher(asyncore.dispatcher): def process(self): if not self.connected: return False - loop = 0 while True: try: with nonBlocking(self.processingLock): diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index c2568e9f..caa9d650 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -137,7 +137,7 @@ def set_rates(download, upload): uploadTimestamp = time.time() def update_received(download=0): - global receivedBytes, maxDownloadRate, downloadBucket, downloadTimestamp + global receivedBytes, downloadBucket, downloadTimestamp currentTimestamp = time.time() receivedBytes += download if maxDownloadRate > 0: @@ -149,7 +149,7 @@ def update_received(download=0): downloadTimestamp = currentTimestamp def update_sent(upload=0): - global sentBytes, maxUploadRate, uploadBucket, uploadTimestamp + global sentBytes, uploadBucket, uploadTimestamp currentTimestamp = time.time() sentBytes += upload if maxUploadRate > 0: @@ -349,14 +349,14 @@ def kqueue_poller(timeout=0.0, map=None): flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE selectables = 0 for fd, obj in map.items(): - filter = 0 + kq_filter = 0 if obj.readable(): - filter |= select.KQ_FILTER_READ + kq_filter |= select.KQ_FILTER_READ if obj.writable(): - filter |= select.KQ_FILTER_WRITE - if filter: + kq_filter |= select.KQ_FILTER_WRITE + if kq_filter: try: - ev = select.kevent(fd, filter=filter, flags=flags) + ev = select.kevent(fd, filter=kq_filter, flags=flags) kqueue.control([ev], 0) selectables += 1 except IOError: @@ -383,9 +383,10 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, # argument which should no longer be used in favor of # "poller" - if poller is None: - if hasattr(select, 'epoll'): + if use_poll: + poller = poll_poller + elif hasattr(select, 'epoll'): poller = epoll_poller elif hasattr(select, 'kqueue'): poller = kqueue_poller @@ -506,9 +507,9 @@ class dispatcher: # no poll used, or not registered pass - def create_socket(self, family=socket.AF_INET, type=socket.SOCK_STREAM): - self.family_and_type = family, type - sock = socket.socket(family, type) + 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) @@ -652,9 +653,9 @@ class dispatcher: def log(self, message): sys.stderr.write('log: %s\n' % str(message)) - def log_info(self, message, type='info'): - if type not in self.ignore_log_types: - print('%s: %s' % (type, 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: @@ -744,7 +745,7 @@ class dispatcher: def handle_accepted(self, sock, addr): sock.close() - self.log_info('unhandled accepted event', 'warning') + self.log_info('unhandled accepted event on %s' % (addr), 'warning') def handle_close(self): self.log_info('unhandled close event', 'warning') @@ -808,8 +809,8 @@ def close_all(map=None, ignore_all=False): for x in list(map.values()): try: x.close() - except OSError as x: - if x.args[0] == EBADF: + except OSError as e: + if e.args[0] == EBADF: pass elif not ignore_all: raise diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 30068d6d..dbdc26d2 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -1,26 +1,22 @@ import base64 -from binascii import hexlify import hashlib -import math import time import socket import struct -import sys -from addresses import calculateInventoryHash from bmconfigparser import BMConfigParser from debug import logger from inventory import Inventory import knownnodes from network.advanceddispatcher import AdvancedDispatcher -from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError +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 bmconfigparser import BMConfigParser from queues import objectProcessorQueue, portCheckerQueue, invQueue, addrQueue import shared import state diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index 681291ad..ee2a8b40 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -6,7 +6,7 @@ import knownnodes from queues import portCheckerQueue import state -def getDiscoveredPeer(stream): +def getDiscoveredPeer(): try: peer = random.choice(state.discoveredPeers.keys()) except (IndexError, KeyError): @@ -27,9 +27,11 @@ def chooseConnection(stream): return retval except Queue.Empty: pass - if random.choice((False, True)): - return getDiscoveredPeer(stream) - for i in range(50): + # 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"] diff --git a/src/network/stats.py b/src/network/stats.py index 45961ac1..ade56ac0 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -1,11 +1,7 @@ import time -from bmconfigparser import BMConfigParser from network.connectionpool import BMConnectionPool -from inventory import PendingDownloadQueue, PendingUpload import asyncore_pollchoose as asyncore -import shared -import throttle lastReceivedTimestamp = time.time() lastReceivedBytes = 0 @@ -16,7 +12,8 @@ currentSentSpeed = 0 def connectedHostsList(): retval = [] - for i in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for i in BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): if not i.fullyEstablished: continue try: @@ -46,22 +43,26 @@ def downloadSpeed(): currentTimestamp = time.time() if int(lastReceivedTimestamp) < int(currentTimestamp): currentReceivedBytes = asyncore.receivedBytes - currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / (currentTimestamp - lastReceivedTimestamp)) + currentReceivedSpeed = int((currentReceivedBytes - lastReceivedBytes) / + (currentTimestamp - lastReceivedTimestamp)) lastReceivedBytes = currentReceivedBytes lastReceivedTimestamp = currentTimestamp return currentReceivedSpeed def pendingDownload(): tmp = {} - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for connection in BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToMe.keys(): tmp[k] = True return len(tmp) def pendingUpload(): - return 0 tmp = {} - for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): + for connection in BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): for k in connection.objectsNewToThem.keys(): tmp[k] = True - return len(tmp) + #This probably isn't the correct logic so it's disabled + #return len(tmp) + return 0 -- 2.45.1 From 7e35ea6bdffe4ff815aab03d4876de68815ea3a6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Aug 2017 14:16:37 +0200 Subject: [PATCH 0892/1102] Email gateway autoregistration fixes - don't treat "@" in label as an email address - ask for confirmation before autoregistering. It confused some newbies into thinking that bitmessage requires payment --- src/bitmessageqt/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9f4f0b04..014831bf 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1968,12 +1968,16 @@ class MyForm(settingsmixin.SMainWindow): if "<" in toAddress and ">" in toAddress: toAddress = toAddress.split('<')[1].split('>')[0] # email address - elif toAddress.find("@") >= 0: + 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 -- 2.45.1 From a8e5ea18a623b6de78b15f24b1bcadd958b642c8 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 24 Aug 2017 21:30:54 +0200 Subject: [PATCH 0893/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 87724 -> 88118 bytes src/translations/bitmessage_eo.ts | 231 +++++++++++++++--------------- 2 files changed, 118 insertions(+), 113 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 69c28969c621850702ee10caacc3114925c62cb1..e2ac21b2aa70225463a742effbc36a26f4194b0b 100644 GIT binary patch delta 2812 zcmYjSeO!%aAOBwGKJWK^&Y@ytrg&i9JxJU90aI8H{{9@Y z%{j44cPebnskAS8)^se3v zCT)c4(v85*Mz~iL0S5-c^KusuHys9L7*G)jA6NRWbSHezyMev2A0xk~eKteDrgC6k zE8c8a2@cn%h;GbX(y9^1GWQT)E8fXDPV~0+;Emr9y>1cM=oN^uEF*l5S%=BJzcb=8 zL%_yMF-N|R!oMJHVWZy}u^Ve=Iz0} z1y7*yCJUJV0Ql`Y7LeHi?AXCZ<&}Yj*u)h2?3S4&Knr9Pv!oYf_Tm?o8cf{RPh)H2 z{eTnkY)f@5Fer{~t0Hpa!o?GkFv$<`;!BCa_1PrJn41Ma@)pU&e8R~@<1@Oa6+MslwHGVE`AOSN#t~^Ns?cxIp@!B z10Rgy^xMN=N7W6^GpGVgHkunAc@X&L8qWW6H5Fzv7bwsHnr?2iH4kh^5jWPT2aA+) zS4eJ#|2 z1^&UE|A_XBc5?L!vmNkJI2M%5Lhi>8jldKgce`vdWx<fAO0-6>MtJgS+1RB7M6vA_c#>DVLGIQ|c$k;Y2O>KN&yx=vECLYm-QLIm@q z=7WCJ66w-po|J4|E?w;1XBi;-LTXEs0nZ*uvtLF67qi87X_(q6NcwHtP_U6x#6Ve? z&!TFeceg>)d&@N9|K%{q1lUsiZ z0ET@m&nl*x3J#HfxP(NAo+;lRbq8#+AjZqx?N@imk2thz4U(UY*8*cYV#{Gje$3S$uWxJz7-@@rK0$b5#n?Cpn&_k75fUQqA<4yy@vGQ zjfp*Y-=;V+g{YO>Q=ASg2Mf;;rzs3kCmNJN@`qqSb;_WJ9l)AZ${ArZX|Gboo-6^p zHY>9y_))XoSFWpwqpVy~ZW=~u{o$}uJf#J`DN`PwH4b0@x!zc%e6k`PxN20n z+?_#9>Z2O)4-z(LuGmLu@Ob)2H5J{!p)6Hww;D`4QI%<|rI?Sa3Z8WVUB8R*O2aVe z8r3H&&jGbk)y_~dZ*5Uke@f{y?NQYQxPs}HtLk172W_QTr8L-O=hb{VB^~u@=V{a< zy^pG$%_OJfPqhbYp)5D54J)qz?WfeyYxe^MU#b(!D0Yt$wYhC7r6*dQlt}JEo7IbM z2GUd>@CsSK75bFNb z>NEM&beqqpFML3GOKeyFI_C~Gp{u(6BMNM2r5Z6j~| zx(g^D&QI^I1RM33fA9TqbgTIB>zA#hui}Id9N$=K1RD^+H!bY|8*`d(p0oup)bedkRIly1e4CyIx_6G? zA58%ljTRz&9m1Uy-a5AO8Un`U(L;(#8#5%RXe$7KT#xiN-m%c(4 zTqS(7m5MLdB-G!_1ICUQE-W$vH)Dm1x(*<{QfPWi*JVJraP|Gm*I!x-6!oZ!l{;#~XoDGquC|ke{SNt*>z# zczDHXCq1Eo>)IxI2?l#@nRe&wAYjQp?WcO;vUZ8~-`j&}gbmTwkDy`!deHMi4_yL4~wBErX@i#v1@c(g<}zibr{v`v>(YIR$jke>g1?ai zS+}mJnQpcmg>IL76A`-^AQ7{QuTgvi2jJcge;IJyQ|tkw$BW zk1Q+}ds$u+FKIpBaF{VA{pEO_K?X}+nP!mNg|u>*XAp)f9m>k-$&MAPIB{kD#HYMt<3-l&^g2k3%&df9|H2dk_O|oR_GtB8(mJG9FvCu+>8J5(A`fQ6W ziHsMTZ02m!Qa}ATo6Ve(X4BiO|1%Q{vij6y9edV~C5YB5ULWa3FnOROC>!x~gk-`3 g3M<*cj($y8^a`z{K^l>9SUK1(fwkseSAH${3(#>+pa1{> delta 2606 zcmX9=dt6QF8h*aD*1oN^*WRNXmyD)CJEA1rBbScj+QuN4Ar(1^O65MXRW8Y`S}{t< z6laPWCfAtU4bBKZU6ji(D3{8ZA(z6u^xJ$?J#LCiJyDbVQ8T;u4)ojaM^@+>f~znD*(B4Cvj z8#L7u$lA!vl@!2hGz*?giQjv`LP3FJQ(1Tmz27{IMR}9J>jK!?Y0kj$-`VB^p9G!4 zwiS{f1Abx0^LSwO0rpGZeC0al%ANmRQSm0r>kFLkJ+jK2&D_uxgmXu8;R9cRc{p)% zoelx(7jTiuQGja~&JrID^yuC=@vn2>fox$%2T1Dor z;!E`BD8~i-xcW*+cvS%uBn!zNdBA*&ke+RUBC2|bUmO-r*Y}_^E-C$0eq2+j z60h=ev};x+tq242Oj0H99}32TR2zJpf%In8R_`9buN_obf5(Bf&r=?$Oq|OAMONEd zd@9uAc2nuCyw$<6WTxlu)seHJXo3W&qbpni$F1rGsbnV4qw3^^%YncN>g*AZz=o!% z^KM@S7LHf{s1R?vS?a=`W?;-sb@4`Ppr*6>$S3(~534UuGXTDg>hc0B>e3SRoj~I6 zW~FXaM`0YcozqyQT8Q8!ji*=!eE3G=6XF1@=&1>)ruE7zn!wa}8Xp0gus*ZFoO3lv zI|l&$@-(YQbp-RCqS@$v7Z^TKliDtq1awf|t4*$tyK45XC+8rj7402b@%H&vtouuI zWF+y;sMDNr-vQRYNtvKAjW{t$>!p4{bVq8vUNi!0R%*xjO`y(Lqn%uu0obQ&7Y%Wy zrhcML$(;gR8>3Bgq%vRd)GDV8K3^RZ?Y7ccYwGekMmGu{fuh&C$sa|s?|EIE`5fhZLYMIN1DPvI3DcS!d6jN^(k0-` zYF$o0+Flo`JFsgsP4PXtE3P(R@;lv?_ryVVP!4HL7Ganu#ZbXfCRztjGkoD8T8EL6 zT(j7PJp{T`iKe7-8gPDM;M#pa!eMb{7UkY0Lkz1Q1=hD*44+Bid?$$!_oz9mGCw10 zS0OH+`V`FJ4>7B*1vs4}7WuuSlKP0n6DivQ8}XR*l1iFZDV{3x0pob_?22M?;92q7 zYAV^x2J!yXN5H9UvEh44tb44)0*a^xMUrj_dBrzY68Y=EGA~JdI3LWgQIZqr{*jZF zLY=MUWU}Nv#-8S0ljJw46d3zb8erWKcv2#nN2JhPt^SOxonA7RP(C}Hq_H3KiBFs~ zx>QtHVXN=uNkZunC}be6JpZsfQoY47`V;O#@{;)>b8fqd!WACz7u zFI8ol(U)~Bm8zFCg82-TYKCnFOy{I}E3)ddW~tteZUj@4-X$;y*yN!f*o%a_*-wcV zZGC>dte;ajm~_k1&l|oS%=Myv{w-f>nH%~glNk-AcKUVaQ|a6geZ~MP=b*v*jL;E4 z`9q~bG+AnL^v78ojrq*a$h>;$Pi`TL#fRw2>Xrlj2kWmzm}yp4>8~3bftY-K^{dWc zed6`EzPmx!-$DJ$HKgvUXjxl(h}5r>JIy5}_uY zXlsqGQ47GF%8l+9ZNYlF8+|*`^ftCPjy$}aEFSg2I699AA4@b&*g~iP$-gaO?%Bu={&scK#Y` diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 9212f03b..2502c2d6 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -316,7 +316,7 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Ricevis konfirmon de la mesaĝo je %1 - + Broadcast queued. Elsendo en atendovico. @@ -542,7 +542,7 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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. @@ -587,67 +587,67 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 De - + Sending email gateway registration request Sendado de peto pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (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 Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi 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. Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco 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). Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). @@ -1110,7 +1110,7 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. @@ -1120,37 +1120,37 @@ Are you sure you want to delete the channel? La nova versio de PyBitmessage estas disponebla: %1. Elŝutu ĝin de https://github.com/Bitmessage/PyBitmessage/releases/latest - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finiĝos… %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage… %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj… %1% - + Saving settings... %1% Konservado de agordoj… %1% - + Shutting down core... %1% Fermado de kerno… %1% - + Stopping notifications... %1% Haltigado de sciigoj… %1% - + Shutdown imminent... %1% Fermado tuj… %1% @@ -1165,7 +1165,7 @@ Are you sure you want to delete the channel? %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage… %1% @@ -1215,61 +1215,61 @@ Are you sure you want to delete the channel? Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... Kalkulado de laborpruvo, kiu endas por sendi elsendon… - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendado de peto pri ĉifroŝlosilo de ricevonto. - + 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 @@ -1279,7 +1279,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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 @@ -1289,22 +1289,22 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Kalkulado de laborpruvo, kiu endas por peti pri ĉifroŝlosilo. - + 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. - + Sending public key request. Waiting for reply. Requested at %1 Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 - + UPnP port mapping established on port %1 UPnP pord-mapigo farita je pordo %1 - + UPnP port mapping removed UPnP pord-mapigo forigita @@ -1314,7 +1314,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? @@ -1324,22 +1324,22 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? @@ -1399,7 +1399,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Ne povis kompreni NMControl. - + 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. @@ -1428,72 +1428,77 @@ Bonvenon al facila kaj sekura Bitmesaĝo Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + + 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. - + 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… @@ -1633,7 +1638,7 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj (saves you some bandwidth and processing power) - (konservas iomete rettrafikon kaj komputopovon) + (konservas iomete da ret-trafiko kaj komput-povo) @@ -2084,17 +2089,17 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj 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. -- 2.45.1 From 022e0ce59327eec009f92023660d65ccd9a744f4 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sat, 26 Aug 2017 04:35:44 +0200 Subject: [PATCH 0894/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 66390 -> 66676 bytes src/translations/bitmessage_ja.ts | 229 +++++++++++++++--------------- 2 files changed, 117 insertions(+), 112 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 37e8086d9a717d80de0d10fe159843685ad6c397..4cf32fd716f80eb8c6aeb03193bef46811d9b2b8 100644 GIT binary patch delta 2732 zcmXw5c~}$o7Cp&iotY$6(buBHxR6?_IPytZ6hsAg;|@Yai4q_zK_M1b0#X+c1RSgt zaVv<$ne0JPd5yW|Rt9tv4Q7%-+MWX%FFc2)--H~@KUHBhxY zZ-vqEWCY}gGl1vGP<+GC*Iz&x6iE0C>cAtwv}S0(ssn`g&?)dGuyYPNm2UuQ0^z)5 zJ+QbI`l1|Q-Ff&yW-9}+mt`eI!)gBcu$p~`;vZ^E- z%TEIz{2|#=O2s|*5UZqq(tNY{Mrw3EI$ApPZW=JTN;)Q$a7vgo+W!?vkSF>wddCHa zG;3fbS^iF%y@1YM6(HRnejn%&BQ2S20|L)WE3{?6*Q=$q;e_EYq}Sv70@K5!Kdq=C zMPsEmwPxV^`_hN9Bw*JKMz-7oI5mUev*f^wnT+Q0en6ka=vI*=C7w)|{f)rVfuI#Q705K14r!zQnoTeeK}xsW;}R0;K!HDCkZJemYnf587SdZX2jeEAY%$M zZXt=eLdit8ks99l%o4Y|K(~v`=8F|T?iprt+Z-UaoY^*K6%lr2j`F0^Zv&Zgo9Nke zo2gS;96+z6_8(;Cf0>JGO@LP{(^xQ$T!>(rf=PjxNapEcBCuA={Bd|H5E>=ZxvU3H zddPHhsb?OnmUY_`LZ%Ow`5p=Y?x)B`nZ5zG*UHA$wvd7j*}N|KRN!ryWv?5J#7S8! zR|b^cmBsbzN`A>~GW!CO>S&`Z`OPSxP$xc-`LVSTvhSNeqI@Ss54oT8$Odtd+^>H_ zr93^A*f!SYw|C>DSG2XdBIEa;Yy)+OKuE(pp!R^nG6^<$y=FX zs(Oa}bwDS;IZe?ihQgjOis`$k8|pF?;fbVTrHdjy(grM7DiW@_lQ=yTi*ku$(`m)p z&qxISfr`TM4}e#P#W025QKVKJYS*r`P;oX)3k0=XtA?LAfh{qGw9WU@O(kDATtO2i&G9S5N$a zCZR>S-s3jl>8s4`M$K|`yE6BI3F2RhUhZY}%5Sq8Y1T(}V2|%RaF@CR%Sx1oCQxY! z$;xUE!e;}-NlN4RY$uhM;ssR}tnzyC6o@ERP4}Bg)N55CC&(_BzN+LvHyYL>s?4HL zawSxi*Pm?7->wo*X@T{_RL5tH0FHTzRZ2hST_aVkD;EM^RjZvIP6v*ssk`qcVVhX7 ztIF8>s9Ze}?|{!&sYBkez&Q_fl8L%;bfh}%&$qyd8)BHs*uO@t-kSa+katGCV;F^( zeWEVkN%oCBsIGN)2F?#r*S?_|&Si_GDx>4Hp5+#j=_p~lOiBSRw6a|+B&XEE_LkfS zx_`(T)2{;MZER4+cQm{vHll#IJ3nVF%@fIV_ccsZIg9eqn%K98IFj=Xsk#?4ZUa z)-6pZG;_HpZvt^`TtWRPS~gcaxkB|2>bnEnw{JF(c`e-8R4cH0GI#dZG9d8>?x)Qr z;HneXu;eMwoX_1HyO9WjYwk?_T7I5uHpI{}I>-w_L^$R???0ejxWjxvB|{geD?e*R zENxFGKH}9}8lQc<<%?}JmB;zm(vfuV9d~}gxUF=L-Q?{*52c-*!!HSu(7dhZ*Zq)7 zgf{W{!^!9ug?#?J@w7w)v6eMDiW2!_5*pX2(hhvA=1+b>h0cD)*F8$1IjQC^#Srh3 za{jW8c+a@ZH@u?j@n?s3#0TPiet=hpx|uV{>$ zDZi<=W}vtS*nM0hWF8~qQ#9VKCm<$rA31I}YhqjJtaYz6wgWaGJ5rP22&N0=Z_UzC zIW+r5&GO}b)cG}d^KXNzdzVY5RAr112rj4lr#2haS(gV_P$U`g5WyZ**)Json9Z z7yTqhHB z_niO^#_7TfJ_kN_)!A~0$Op4^3kOgkRqu3Zqbb4ZNxGbyA~6LkI8i7F{%M%Ew;RkguJ^xBG;Om72AQtWggOGpqT!hVW8E0hSkg<>K0vt^kP7c~*P8B`L`qWpOjih_)sf5-kfCSraYoKccJ@nAn~p*=mob;3%`* el5Ae$W*A|&TjCek+jIXvOiT;yTH%@7GwFX!=WGuE delta 2539 zcmX9=d0bBU9)8Yy&byuSE<>)lDrM_6Qb{w3jI5FEMJZ*9L?o4^##+54l4x_RSt1QL z)0>izCDNG5QnxITQDc;BsZ8l|$8x{!``7b1=lss^_k5q{`F_voOyX)2x%3{&;Q)pL zmB%xB>s-qcfFEpu4SxV36M(nA;Hqtai6g<)1pt$*!L>L79(4Z;79E0g*;U};;*1#G zxR$|?p4$qvEr2YSrMKfC_i-nzgVMbO@N9u5y9#jp3fR=5MWIt1qHQh~LV z8LzDjPdzd8S6bz}2TmD>fcWp>QcJv!I%DM5t-$#Iz&&RZpijc2-M;|lekRNdz~tv% zz`%A)-_=fBJurPYPq+#*Le~S2BjLIBB2~NEggGhjNe%^`?Zup>^!(W;_!hgt3^r2C zjdZ0lO5ra{CQKC%GQ$i{_F;>6HnESx-nCZ1=}a71+8qc?LC!fd+P^>YQf31ukHa{M zo)-qA_%799Cr6ETJ7D|^b*t_G^X8)7g3hgcfX4CX0YwhFu2Ef4zKrs4CouRV(>+TA zT$;*Qn{&XdF-+efB`}~qi1|j$jBB@iAm|D+ z*53t){EN}o(gwDTOrReTKW@eZfj0JzV?sXA`xmuL#0V02NjS4Lzya8HoY_@Kg7$jH z>^G7iZPv_%9I|ndnz{6Cu2>^+l8949DXTM-I7&u7jt6F3l1z#toEabq8S@r+zCjXZ zUrf<4NWzmM0NrefA!a$y&qI=2+YPw6RI>g5&p%62Rt+e8#_whhxRLF$Ih<2IUDlfkT{6z?vz%*?)xwgSXRg$nzxxa z+OX$Uq~5cy*&BQ4THnA{$%BEuktRI(NDSw!42kd9cjsmSbC+=1-l;&THK(0VA!}N} z^*rGRQeVh`e+Ve@oAmwG5&&a>Y?nH_5qZ zF-GcU`yfl25J!Yxtdk}cOaiWCOH*9wr0{#vy(4J#&SBEb4${0PQG6=ZNgCgaYMGVc z)oYp8Ph@>%q%3e1h3T|h7QQ$Fh?dKi-*ck!EoDEZ6TcVvvZU3d>==95fhkXc&TLuE zqkmJEL-sF`>h5JHGY-}R-}}poQq6!P9kR1u35pC`vRT}!5U*%}6rJLt?^xh`U-6pU%{<3W(Y0|UsgbAb(d-3WSf;c%PHI2z z6niUl{m!*1r{Ob@uw3c)nFp?0DBvX zxv`J3@W>3B;%AhVPUgT3D`n+Js^R(?u~?xqlq+~)B^i!myxH_v>e|P=SuiOn3FiAT zO@PHfUYBqeC}`$=w&qcn>iI>P#NE7|4{n)8)}-^6U;$`vT<#+SzxQ3A90>O`_^%18cB zf67jp1OIvt5o>rXFw^tNgNcH29c9HnMBv#Pz~4&Xo1&<$bU_{OPIXm?Mx~V@b&)V) zrVY)#bivKH6d2W07;Q!g$Zr<(Q>X>AwwbWnQ_!C$KC3f?S)a+9=1IcB4dh8#zOZe5 z0^w94{qjQ~?1PYbhgz+suW&&59VPCx@bkwVqA4x5frdsF6P^+b?wp~l7bK_MzN0XiHiK?AJQ)qOUi}!e)A=_Vd zfuX)#Vl?544%Ow|RE~d}s_Gf3=x|k49jd2UxnEVIC3drGRCRBA(?qIN{l4K2eFoZ9 zom)uVg<7?uxtP>nskR8C7-Sw)4_H_ZSl?Fb_R;?OerkL11f}Mf+A;Y8*&CuB(Nzj@ zy)ej7U#ni$MQ0`dp^i8m0c@YCUT&B}ACAA(>&K^&b2@c&v>WBys6OtHH> diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 9733c02a..ed8704ce 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -318,7 +318,7 @@ Please type the desired email address (including @mailchuck.com) below: メッセージの確認を受け取りました %1 - + Broadcast queued. 配信がキューに入りました。 @@ -543,7 +543,7 @@ It is important that you back up this file. Would you like to open the file now? 送信しようとしているメッセージが %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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From 送信元 - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,7 +1111,7 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + Display the %1 recent broadcast(s) from this address. このアドレスから%1の最新の配信を表示します。 @@ -1121,37 +1121,37 @@ Are you sure you want to delete the channel? 新しいバージョンの 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% @@ -1166,7 +1166,7 @@ Are you sure you want to delete the channel? %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% @@ -1216,61 +1216,61 @@ Are you sure you want to delete the channel? アラート: ディスクまたはデータストレージのボリュームがいっぱいです。 Bitmessageが終了します。 - + Error! Could not find sender address (your address) in the keys.dat file. エラー! keys.datファイルで送信元アドレス (あなたのアドレス) を見つけることができませんでした。 - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. メッセージの送信に必要な処理を行っています。 このようなバージョン2のアドレスには、必要な難易度はありません。 - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 @@ -1280,7 +1280,7 @@ Receiver's required difficulty: %1 and %2 メッセージの送信に必要な処理を行っています。 - + Message sent. Waiting for acknowledgement. Sent on %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました @@ -1290,22 +1290,22 @@ Receiver's required difficulty: %1 and %2 暗号鍵のリクエストに必要な処理を行っています。 - + Broadcasting 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 ポート%1でUPnPポートマッピングが確立しました - + UPnP port mapping removed UPnPポートマッピングを削除しました @@ -1315,7 +1315,7 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? @@ -1325,22 +1325,22 @@ Receiver's required difficulty: %1 and %2 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1400,7 +1400,7 @@ Receiver's required difficulty: %1 and %2 NMControl を理解できませんでした。 - + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 @@ -1430,72 +1430,77 @@ Receiver's required difficulty: %1 and %2 接続に問題がありますか? ネットワーク設定で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 には何かしら誤りがあります。 - + 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... 同期の完了を待っています... @@ -2085,17 +2090,17 @@ The 'Random Number' option is selected by default but deterministic ad 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 モジュールが利用できません。ビルドしてください。 -- 2.45.1 From fc960cbf86d6f948e04d58ee10ed6f1c73233be2 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 29 Aug 2017 13:50:49 +0300 Subject: [PATCH 0895/1102] Fixed own logical error when missing msgpack package is being appended to install_requires list instead of the available one. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 0da5680a..9357284b 100644 --- a/setup.py +++ b/setup.py @@ -230,9 +230,9 @@ if __name__ == "__main__": ] # this will silently accept alternative providers of msgpack # if they are already installed - if "msgpack" in detectPrereqs(): + if "msgpack" in detectPrereqs(False): installRequires.append("msgpack-python") - elif "umsgpack" in detectPrereqs(): + elif "umsgpack" in detectPrereqs(False): installRequires.append("umsgpack") else: packages += ['pybitmessage.fallback', 'pybitmessage.fallback.umsgpack'] -- 2.45.1 From 5f0a1e05e9c09051a38dedbe1c52ed41e84f1830 Mon Sep 17 00:00:00 2001 From: that_lurker Date: Sun, 10 Sep 2017 15:40:01 +0300 Subject: [PATCH 0896/1102] Added pull request template --- PULL_REQUEST_TEMPLATE.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..91c3bc96 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +## 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 -- 2.45.1 From 24a9dc3b372c5032990bea333329e57efab00f39 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 19 Sep 2017 16:27:42 +0200 Subject: [PATCH 0897/1102] Put dependency checking into a separate file --- checkdeps.py | 215 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 checkdeps.py diff --git a/checkdeps.py b/checkdeps.py new file mode 100644 index 00000000..65f8a787 --- /dev/null +++ b/checkdeps.py @@ -0,0 +1,215 @@ +"""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]) + 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" -- 2.45.1 From ef8f40ccc4abb677e96243ab096d0c818c80e8f3 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 10 Mar 2017 01:00:54 +0200 Subject: [PATCH 0898/1102] Moved notifications to plugins (including sound) --- setup.py | 17 ++- src/bitmessageqt/__init__.py | 194 +++++++++++++--------------- src/plugins/notification_notify2.py | 13 ++ src/plugins/plugin.py | 8 +- src/plugins/sound_playfile.py | 37 ++++++ 5 files changed, 160 insertions(+), 109 deletions(-) create mode 100644 src/plugins/notification_notify2.py create mode 100644 src/plugins/sound_playfile.py diff --git a/setup.py b/setup.py index 9357284b..c7f7fab5 100644 --- a/setup.py +++ b/setup.py @@ -254,7 +254,9 @@ if __name__ == "__main__": install_requires=installRequires, extras_require={ 'qrcode': ['qrcode'], - 'pyopencl': ['pyopencl'] + 'pyopencl': ['pyopencl'], + 'notify2': ['pygobject', 'notify2'], + 'sound:platform_system=="Windows"': ['winsound'] }, classifiers=[ "License :: OSI Approved :: MIT License" @@ -278,9 +280,16 @@ if __name__ == "__main__": 'popMenuYourIdentities.qrcode = ' 'pybitmessage.plugins.qrcodeui [qrcode]' ], - # 'console_scripts': [ - # 'pybitmessage = pybitmessage.bitmessagemain:main' - # ] + 'notification.message': [ + 'notify2 = pybitmessage.plugins.notification_notify2' + '[notify2]' + ], + 'notification.sound': [ + 'fallback = pybitmessage.plugins.sound_playfile [sound]' + ], + # 'console_scripts': [ + # 'pybitmessage = pybitmessage.bitmessagemain:main' + # ] }, scripts=['src/pybitmessage'], cmdclass={'install': InstallCmd} diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 014831bf..44dcb8ec 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4,8 +4,6 @@ try: import gi gi.require_version('MessagingMenu', '1.0') from gi.repository import MessagingMenu - gi.require_version('Notify', '0.7') - from gi.repository import Notify withMessagingMenu = True except (ImportError, ValueError): MessagingMenu = None @@ -62,9 +60,8 @@ import platform import textwrap import debug import random -import subprocess import string -import datetime +from datetime import datetime, timedelta from helper_sql import * import helper_search import l10n @@ -153,7 +150,7 @@ class MyForm(settingsmixin.SMainWindow): SOUND_CONNECTION_GREEN = 5 # the last time that a message arrival sound was played - lastSoundTime = datetime.datetime.now() - datetime.timedelta(days=1) + lastSoundTime = datetime.now() - timedelta(days=1) # the maximum frequency of message sounds in seconds maxSoundFrequencySec = 60 @@ -1368,39 +1365,41 @@ class MyForm(settingsmixin.SMainWindow): # 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 + return category in ( + self.SOUND_CONNECTED, + self.SOUND_DISCONNECTED, + self.SOUND_CONNECTION_GREEN + ) # play a sound def playSound(self, category, label): # filename of the sound to be played soundFilename = None - # whether to play a sound or not - play = True + def _choose_ext(basename): + for ext in ('.wav', '.mp3', '.oga'): + if os.path.isfile(basename + ext): + return ext # if the address had a known label in the address book - if label is not None: + if label: # Does a sound file exist for this particular contact? - if (os.path.isfile(state.appdata + 'sounds/' + label + '.wav') or - os.path.isfile(state.appdata + 'sounds/' + label + '.mp3')): - soundFilename = state.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 + soundFilename = state.appdata + 'sounds/' + label + ext = _choose_ext(soundFilename) + if not ext: + soundFilename = None 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 self.isConnectionSound(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 self.SOUND_KNOWN: soundFilename = state.appdata + 'sounds/known' @@ -1415,75 +1414,55 @@ class MyForm(settingsmixin.SMainWindow): soundFilename = state.appdata + 'sounds/disconnected' # sound when the connection status becomes green elif category is self.SOUND_CONNECTION_GREEN: - soundFilename = state.appdata + 'sounds/green' + soundFilename = state.appdata + 'sounds/green' - 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 soundFilename is None: + return - # if not wav then try mp3 format - if not os.path.isfile(soundFilename + '.wav'): - soundFilename = soundFilename + '.mp3' - else: - soundFilename = soundFilename + '.wav' + if not self.isConnectionSound(category): + # record the last time that a received message sound was played + self.lastSoundTime = datetime.now() - 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: - logger.warning("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: - logger.warning("WARNING: mpg123 must be installed in order to play mp3 sounds") - else: - try: - subprocess.call(["aplay", soundFilename], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE) - except: - logger.warning("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) + try: # try already known format + soundFilename += ext + except (TypeError, NameError): + ext = _choose_ext(soundFilename) + if not ext: + return + + soundFilename += ext + + self._player(soundFilename) # initialise the message notifier def notifierInit(self): - if withMessagingMenu: - Notify.init('pybitmessage') - - # shows a notification - def notifierShow(self, title, subtitle, fromCategory, label): - 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: + def _simple_notify( + title, subtitle, category, label=None, icon=None): self.tray.showMessage(title, subtitle, 1, 2000) + self._notifier = _simple_notify + self._player = QtGui.QSound.play + + if not get_plugins: + return + + for plugin in get_plugins('notification.message'): + self._notifier = plugin + break + + if not QtGui.QSound.isAvailable(): + for plugin in get_plugins('notification.sound'): + self._player = plugin + break + else: + logger.warning("No sound player 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()) @@ -1663,15 +1642,18 @@ class MyForm(settingsmixin.SMainWindow): def setStatusIcon(self, color): # print 'setting status icon color' + _notifications_enabled = not BMConfigParser().getboolean( + 'bitmessagesettings', 'hidetrayconnectionnotifications') if color == 'red': self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # if the connection is lost then show a notification - if self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): - self.notifierShow('Bitmessage', unicode(_translate( - "MainWindow", "Connection lost").toUtf8(),'utf-8'), - self.SOUND_DISCONNECTED, None) + if self.connected and _notifications_enabled: + self.notifierShow( + 'Bitmessage', + _translate("MainWindow", "Connection lost"), + self.SOUND_DISCONNECTED) if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": self.statusBar().showMessage(_translate( @@ -1689,10 +1671,11 @@ class MyForm(settingsmixin.SMainWindow): ":/newPrefix/images/yellowicon.png")) shared.statusIconColor = 'yellow' # if a new connection has been established then show a notification - if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): - self.notifierShow('Bitmessage', unicode(_translate( - "MainWindow", "Connected").toUtf8(),'utf-8'), - self.SOUND_CONNECTED, None) + if not self.connected and _notifications_enabled: + self.notifierShow( + 'Bitmessage', + _translate("MainWindow", "Connected"), + self.SOUND_CONNECTED) self.connected = True if self.actionStatus is not None: @@ -1705,10 +1688,11 @@ class MyForm(settingsmixin.SMainWindow): self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/greenicon.png")) shared.statusIconColor = 'green' - if not self.connected and not BMConfigParser().getboolean('bitmessagesettings', 'hidetrayconnectionnotifications'): - self.notifierShow('Bitmessage', unicode(_translate( - "MainWindow", "Connected").toUtf8(),'utf-8'), - self.SOUND_CONNECTION_GREEN, None) + if not self.connected and _notifications_enabled: + self.notifierShow( + 'Bitmessage', + _translate("MainWindow", "Connected"), + self.SOUND_CONNECTION_GREEN) self.connected = True if self.actionStatus is not None: @@ -2253,8 +2237,14 @@ class MyForm(settingsmixin.SMainWindow): else: acct = ret self.propagateUnreadCount(acct.address) - if BMConfigParser().getboolean('bitmessagesettings', 'showtraynotifications'): - self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) + if BMConfigParser().getboolean( + 'bitmessagesettings', 'showtraynotifications'): + self.notifierShow( + _translate("MainWindow", "New Message"), + _translate("MainWindow", "From %1").arg( + unicode(acct.fromLabel, 'utf-8')), + self.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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py new file mode 100644 index 00000000..90f09df3 --- /dev/null +++ b/src/plugins/notification_notify2.py @@ -0,0 +1,13 @@ +# -*- 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' + Notify.Notification.new(title, subtitle, icon).show() diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index 288be48a..395f0e9d 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -3,10 +3,12 @@ import pkg_resources -def get_plugins(group, point, name=None): +def get_plugins(group, point='', name=None): for plugin in pkg_resources.iter_entry_points(group): - if plugin.name.startswith(point): + if plugin.name == name or plugin.name.startswith(point): try: yield plugin.load().connect_plugin - except (AttributeError, pkg_resources.DistributionNotFound): + except (AttributeError, + pkg_resources.DistributionNotFound, + pkg_resources.UnknownExtra): continue diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py new file mode 100644 index 00000000..03a164af --- /dev/null +++ b/src/plugins/sound_playfile.py @@ -0,0 +1,37 @@ +# -*- 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 connect_plugin(sound_file): + global play_cmd + + ext = os.path.splitext(sound_file)[-1] + try: + subprocess.call([play_cmd[ext], sound_file]) + return + except (KeyError, AttributeError): + pass + + programs = ['gst123'] + if ext == '.wav': + programs.append('aplay') + elif ext == '.mp3': + programs += ['mpg123', 'mpg321', 'mpg321-mpg123'] + for cmd in programs: + try: + subprocess.call([cmd, sound_file]) + except OSError: + pass # log here! + else: + play_cmd[ext] = cmd + break -- 2.45.1 From be716bf228685f11742dcf15a0d9189dddd3d6a8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 10 Mar 2017 16:45:46 +0200 Subject: [PATCH 0899/1102] Improved and documented plugin module --- src/bitmessageqt/__init__.py | 16 +++++++++------- src/plugins/plugin.py | 29 +++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 44dcb8ec..39202d17 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -86,7 +86,7 @@ import throttle from version import softwareVersion try: - from plugins.plugin import get_plugins + from plugins.plugin import get_plugin, get_plugins except ImportError: get_plugins = False @@ -1441,19 +1441,21 @@ class MyForm(settingsmixin.SMainWindow): 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 - for plugin in get_plugins('notification.message'): - self._notifier = plugin - break + _plugin = get_plugin('notification.message') + if _plugin: + self._notifier = _plugin if not QtGui.QSound.isAvailable(): - for plugin in get_plugins('notification.sound'): - self._player = plugin - break + _plugin = get_plugin( + 'notification.sound', 'file', fallback='file.fallback') + if _plugin: + self._player = _plugin else: logger.warning("No sound player plugin found!") diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index 395f0e9d..ba14b836 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -3,12 +3,33 @@ import pkg_resources -def get_plugins(group, point='', name=None): - for plugin in pkg_resources.iter_entry_points(group): - if plugin.name == name or plugin.name.startswith(point): +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(group): + if name and ep.name == name or ep.name.startswith(point): try: - yield plugin.load().connect_plugin + 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 -- 2.45.1 From 91eb75b1407ad18cb4919c9786d6d99f32b8caac Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 10 Mar 2017 18:34:31 +0200 Subject: [PATCH 0900/1102] gst-play-1.0 is another player program which bundled with gstreamer 1.0 --- src/plugins/sound_playfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py index 03a164af..65d5dda9 100644 --- a/src/plugins/sound_playfile.py +++ b/src/plugins/sound_playfile.py @@ -22,7 +22,7 @@ except ImportError: except (KeyError, AttributeError): pass - programs = ['gst123'] + programs = ['gst123', 'gst-play-1.0'] if ext == '.wav': programs.append('aplay') elif ext == '.mp3': -- 2.45.1 From 84a903f116e99403023de753b1db980312446b8f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 11 Mar 2017 13:33:51 +0200 Subject: [PATCH 0901/1102] Redirected output of the player programs to /dev/null --- src/plugins/sound_playfile.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/plugins/sound_playfile.py b/src/plugins/sound_playfile.py index 65d5dda9..c8216d07 100644 --- a/src/plugins/sound_playfile.py +++ b/src/plugins/sound_playfile.py @@ -12,13 +12,17 @@ except ImportError: 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: - subprocess.call([play_cmd[ext], sound_file]) - return + return _subprocess(play_cmd[ext], sound_file) except (KeyError, AttributeError): pass @@ -29,7 +33,7 @@ except ImportError: programs += ['mpg123', 'mpg321', 'mpg321-mpg123'] for cmd in programs: try: - subprocess.call([cmd, sound_file]) + _subprocess(cmd, sound_file) except OSError: pass # log here! else: -- 2.45.1 From 289a6c5bfa9218e0bec83bbc970160d56525ff5b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 11 Mar 2017 13:40:33 +0200 Subject: [PATCH 0902/1102] Added support for sound notification plugins which use the desktop sound theme, with pycanberra for example. Plugin name should start with 'theme' in that case, whereas the name of plugins playing the sound file starts with 'file'. --- setup.py | 3 ++- src/bitmessageqt/__init__.py | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index c7f7fab5..eb79c3b7 100644 --- a/setup.py +++ b/setup.py @@ -285,7 +285,8 @@ if __name__ == "__main__": '[notify2]' ], 'notification.sound': [ - 'fallback = pybitmessage.plugins.sound_playfile [sound]' + 'file.fallback = pybitmessage.plugins.sound_playfile' + '[sound]' ], # 'console_scripts': [ # 'pybitmessage = pybitmessage.bitmessagemain:main' diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 39202d17..fd0bcdc1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1387,6 +1387,7 @@ class MyForm(settingsmixin.SMainWindow): soundFilename = state.appdata + 'sounds/' + label ext = _choose_ext(soundFilename) if not ext: + category = self.SOUND_KNOWN soundFilename = None if soundFilename is None: @@ -1417,6 +1418,7 @@ class MyForm(settingsmixin.SMainWindow): soundFilename = state.appdata + 'sounds/green' if soundFilename is None: + logger.warning("Probably wrong category number in playSound()") return if not self.isConnectionSound(category): @@ -1428,7 +1430,10 @@ class MyForm(settingsmixin.SMainWindow): except (TypeError, NameError): ext = _choose_ext(soundFilename) if not ext: - return + try: # if no user sound file found try to play from theme + return self._theme_player(category, label) + except TypeError: + return soundFilename += ext @@ -1450,6 +1455,10 @@ class MyForm(settingsmixin.SMainWindow): _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( @@ -1457,7 +1466,7 @@ class MyForm(settingsmixin.SMainWindow): if _plugin: self._player = _plugin else: - logger.warning("No sound player plugin found!") + logger.warning("No notification.sound plugin found") def notifierShow( self, title, subtitle, category, label=None, icon=None): -- 2.45.1 From cd8171887195edd089826be33e19dc68e836867d Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 15 Mar 2017 15:56:47 +0200 Subject: [PATCH 0903/1102] Moved sound category constants to the separate module `sound` for importing from the sound theme plugins. --- src/bitmessageqt/__init__.py | 42 +++++++++++------------------------- src/bitmessageqt/sound.py | 19 ++++++++++++++++ 2 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 src/bitmessageqt/sound.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fd0bcdc1..8d126812 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -84,6 +84,7 @@ import state from statusbar import BMStatusBar import throttle from version import softwareVersion +import sound try: from plugins.plugin import get_plugin, get_plugins @@ -141,14 +142,6 @@ def change_translation(newlocale): class MyForm(settingsmixin.SMainWindow): - # 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) @@ -1362,15 +1355,6 @@ class MyForm(settingsmixin.SMainWindow): # 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): - return category in ( - self.SOUND_CONNECTED, - self.SOUND_DISCONNECTED, - self.SOUND_CONNECTION_GREEN - ) - # play a sound def playSound(self, category, label): # filename of the sound to be played @@ -1387,14 +1371,14 @@ class MyForm(settingsmixin.SMainWindow): soundFilename = state.appdata + 'sounds/' + label ext = _choose_ext(soundFilename) if not ext: - category = self.SOUND_KNOWN + category = sound.SOUND_KNOWN soundFilename = None 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 self.isConnectionSound(category): + 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 @@ -1402,26 +1386,26 @@ class MyForm(settingsmixin.SMainWindow): return # the sound is for an address which exists in the address book - if category is self.SOUND_KNOWN: + if category is sound.SOUND_KNOWN: soundFilename = state.appdata + 'sounds/known' # the sound is for an unknown address - elif category is self.SOUND_UNKNOWN: + elif category is sound.SOUND_UNKNOWN: soundFilename = state.appdata + 'sounds/unknown' # initial connection sound - elif category is self.SOUND_CONNECTED: + elif category is sound.SOUND_CONNECTED: soundFilename = state.appdata + 'sounds/connected' # disconnected sound - elif category is self.SOUND_DISCONNECTED: + elif category is sound.SOUND_DISCONNECTED: soundFilename = state.appdata + 'sounds/disconnected' # sound when the connection status becomes green - elif category is self.SOUND_CONNECTION_GREEN: + elif category is sound.SOUND_CONNECTION_GREEN: soundFilename = state.appdata + 'sounds/green' if soundFilename is None: logger.warning("Probably wrong category number in playSound()") return - if not self.isConnectionSound(category): + if not sound.is_connection_sound(category): # record the last time that a received message sound was played self.lastSoundTime = datetime.now() @@ -1664,7 +1648,7 @@ class MyForm(settingsmixin.SMainWindow): self.notifierShow( 'Bitmessage', _translate("MainWindow", "Connection lost"), - self.SOUND_DISCONNECTED) + sound.SOUND_DISCONNECTED) if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": self.statusBar().showMessage(_translate( @@ -1686,7 +1670,7 @@ class MyForm(settingsmixin.SMainWindow): self.notifierShow( 'Bitmessage', _translate("MainWindow", "Connected"), - self.SOUND_CONNECTED) + sound.SOUND_CONNECTED) self.connected = True if self.actionStatus is not None: @@ -1703,7 +1687,7 @@ class MyForm(settingsmixin.SMainWindow): self.notifierShow( 'Bitmessage', _translate("MainWindow", "Connected"), - self.SOUND_CONNECTION_GREEN) + sound.SOUND_CONNECTION_GREEN) self.connected = True if self.actionStatus is not None: @@ -2254,7 +2238,7 @@ class MyForm(settingsmixin.SMainWindow): _translate("MainWindow", "New Message"), _translate("MainWindow", "From %1").arg( unicode(acct.fromLabel, 'utf-8')), - self.SOUND_UNKNOWN + 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 diff --git a/src/bitmessageqt/sound.py b/src/bitmessageqt/sound.py new file mode 100644 index 00000000..4b6aaf00 --- /dev/null +++ b/src/bitmessageqt/sound.py @@ -0,0 +1,19 @@ +# -*- 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 + ) -- 2.45.1 From c8a47b988fb3c464d8d6e86b8032f09211314910 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 23 Mar 2017 19:04:56 +0200 Subject: [PATCH 0904/1102] Moved "Ubuntu" MessagingMenu code into indicator_libmessaging plugin --- src/bitmessageqt/__init__.py | 222 +++++--------------------- src/plugins/indicator_libmessaging.py | 71 ++++++++ 2 files changed, 109 insertions(+), 184 deletions(-) create mode 100644 src/plugins/indicator_libmessaging.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8d126812..942ed3de 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1,19 +1,10 @@ from debug import logger -withMessagingMenu = False -try: - import gi - gi.require_version('MessagingMenu', '1.0') - from gi.repository import MessagingMenu - withMessagingMenu = True -except (ImportError, ValueError): - MessagingMenu = None try: from PyQt4 import QtCore, QtGui from PyQt4.QtCore import * from PyQt4.QtGui import * 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) @@ -30,7 +21,7 @@ import shared from bitmessageui import * from bmconfigparser import BMConfigParser import defaults -from namecoin import namecoinConnection, ensureNamecoinOptions +from namecoin import namecoinConnection from newaddressdialog import * from newaddresswizard import * from messageview import MessageView @@ -51,12 +42,10 @@ from iconglossary import * from connect import * import locale import sys -from time import strftime, localtime, gmtime import time import os import hashlib from pyelliptic.openssl import OpenSSL -import platform import textwrap import debug import random @@ -66,15 +55,13 @@ from helper_sql import * import helper_search import l10n import openclpow -import types -from utils import * -from collections import OrderedDict +from utils import str_broadcast_subscribers, avatarize from account import * -from class_objectHashHolder import objectHashHolder -from class_singleWorker import singleWorker from dialogs import AddAddressDialog from helper_generic import powQueueSize -from inventory import Inventory, PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException +from inventory import ( + Inventory, PendingDownloadQueue, PendingUpload, + PendingUploadDeadlineException) import knownnodes import paths from proofofwork import getPowType @@ -140,6 +127,7 @@ def change_translation(newlocale): except: logger.error("Failed to set locale to %s", lang, exc_info=True) + class MyForm(settingsmixin.SMainWindow): # the last time that a message arrival sound was played @@ -148,8 +136,6 @@ class MyForm(settingsmixin.SMainWindow): # the maximum frequency of message sounds in seconds maxSoundFrequencySec = 60 - str_chan = '[chan]' - REPLY_TYPE_SENDER = 0 REPLY_TYPE_CHAN = 1 @@ -858,14 +844,6 @@ class MyForm(settingsmixin.SMainWindow): 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: @@ -895,32 +873,19 @@ class MyForm(settingsmixin.SMainWindow): self.appIndicatorShowOrHideWindow()""" # Show the program window and select inbox tab - def appIndicatorInbox(self, mm_app, source_id): + def appIndicatorInbox(self, item=None): self.appIndicatorShow() # select inbox 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.ui.treeWidgetYourIdentities.setCurrentItem( + self.ui.treeWidgetYourIdentities.topLevelItem(0).child(0) + ) + + if item: + self.ui.tableWidgetInbox.setCurrentItem(item) 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): @@ -1218,142 +1183,21 @@ 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): - # 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 == 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): - unreadMessages = 0 - unreadSubscriptions = 0 + counters = [0, 0] - queryreturn = sqlQuery( - '''SELECT msgid, toaddress, read FROM inbox where folder='inbox' ''') - for row in queryreturn: - msgid, toAddress, read = row - - try: - if toAddress == str_broadcast_subscribers: - toLabel = str_broadcast_subscribers - else: - toLabel = BMConfigParser().get(toAddress, 'label') - except: - toLabel = '' - if toLabel == '': - toLabel = toAddress + queryreturn = sqlQuery(''' + SELECT msgid, toaddress, read FROM inbox where folder='inbox' + ''') + for msgid, toAddress, read in queryreturn: if not read: - if toLabel == str_broadcast_subscribers: - # increment the unread subscriptions - unreadSubscriptions = unreadSubscriptions + 1 - else: - # increment the unread messages - unreadMessages = unreadMessages + 1 - return unreadMessages, unreadSubscriptions + # increment the unread subscriptions if True (1) + # else messages (0) + counters[toAddress == str_broadcast_subscribers] += 1 - # 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: - logger.warning('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 - logger.warning('WARNING: messaging menu disabled') - - # update the Ubuntu messaging menu - def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel): - # if this isn't ubuntu then don't do anything - if not self.isUbuntu(): - return - - # has messageing menu been installed - if not withMessagingMenu: - logger.warning('WARNING: messaging menu disabled or libmessaging-menu-dev not installed') - return - - # remember this item to that the messaging menu can find it - if toLabel == 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) + return counters # play a sound def playSound(self, category, label): @@ -1423,6 +1267,17 @@ class MyForm(settingsmixin.SMainWindow): self._player(soundFilename) + # 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): + self.indicatorUpdate = _noop_update + # initialise the message notifier def notifierInit(self): def _simple_notify( @@ -2241,8 +2096,10 @@ class MyForm(settingsmixin.SMainWindow): 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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) + # 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: self.dialog = EmailGatewayRegistrationDialog(self, _translate("EmailGatewayRegistrationDialog", "Registration failed:"), @@ -2836,9 +2693,6 @@ class MyForm(settingsmixin.SMainWindow): shutdown.doCleanShutdown() self.statusBar().showMessage(_translate("MainWindow", "Stopping notifications... %1%").arg(str(90))) self.tray.hide() - # unregister the messaging system - if self.mmapp is not None: - self.mmapp.unregister() self.statusBar().showMessage(_translate("MainWindow", "Shutdown imminent... %1%").arg(str(100))) shared.thisapp.cleanup() @@ -4510,7 +4364,7 @@ def run(): myapp = MyForm() myapp.appIndicatorInit(app) - myapp.ubuntuMessagingMenuInit() + myapp.indicatorInit() myapp.notifierInit() myapp._firstrun = BMConfigParser().safeGetBoolean( 'bitmessagesettings', 'dontconnect') diff --git a/src/plugins/indicator_libmessaging.py b/src/plugins/indicator_libmessaging.py new file mode 100644 index 00000000..96ab1516 --- /dev/null +++ b/src/plugins/indicator_libmessaging.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +import gi +gi.require_version('MessagingMenu', '1.0') +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': str(_translate('MainWindow', 'Send')), + 'messages': str(_translate('MainWindow', 'Messages')), + 'subscriptions': str(_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 -- 2.45.1 From b77eb0c7e57a41917284a35d68caae0d987fadeb Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 24 Mar 2017 14:31:27 +0200 Subject: [PATCH 0905/1102] Namespace 'bitmessage' for plugins entry points --- setup.py | 6 +++--- src/plugins/plugin.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index eb79c3b7..06d49ba5 100644 --- a/setup.py +++ b/setup.py @@ -276,15 +276,15 @@ if __name__ == "__main__": ext_modules=[bitmsghash], zip_safe=False, entry_points={ - 'gui.menu': [ + 'bitmessage.gui.menu': [ 'popMenuYourIdentities.qrcode = ' 'pybitmessage.plugins.qrcodeui [qrcode]' ], - 'notification.message': [ + 'bitmessage.notification.message': [ 'notify2 = pybitmessage.plugins.notification_notify2' '[notify2]' ], - 'notification.sound': [ + 'bitmessage.notification.sound': [ 'file.fallback = pybitmessage.plugins.sound_playfile' '[sound]' ], diff --git a/src/plugins/plugin.py b/src/plugins/plugin.py index ba14b836..6601adaf 100644 --- a/src/plugins/plugin.py +++ b/src/plugins/plugin.py @@ -9,7 +9,7 @@ def get_plugins(group, point='', name=None, fallback=None): 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(group): + 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 -- 2.45.1 From de531949e05bc3f59b2bedf83ddde7547ba4246b Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 24 Mar 2017 13:51:46 +0200 Subject: [PATCH 0906/1102] setup.py changes needed for indicator_libmessaging: - entry point 'indicator' and new extra 'gir' which requires only pygobject - desktop entry - icons are renamed and placed into separate dirs for standard sizes, because data_files keyword not supports file renaming --- setup.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 06d49ba5..cf6bd9d2 100644 --- a/setup.py +++ b/setup.py @@ -2,6 +2,7 @@ import os import sys +import shutil try: from setuptools import setup, Extension from setuptools.command.install import install @@ -167,6 +168,7 @@ def prereqToPackages(): print packageName[package].get('description') + def compilerToPackages(): if not detectOS() in compiling: return @@ -202,6 +204,14 @@ class InstallCmd(install): except (EOFError, NameError): pass + # prepare icons directories + os.makedirs('desktop/icons/scalable') + shutil.copyfile( + 'desktop/can-icon.svg', 'desktop/icons/scalable/pybitmessage.svg') + os.makedirs('desktop/icons/24x24') + shutil.copyfile( + 'desktop/icon24.png', 'desktop/icons/24x24/pybitmessage.png') + return install.run(self) @@ -253,9 +263,10 @@ if __name__ == "__main__": #keywords='', install_requires=installRequires, extras_require={ + 'gir': ['pygobject'], 'qrcode': ['qrcode'], 'pyopencl': ['pyopencl'], - 'notify2': ['pygobject', 'notify2'], + 'notify2': ['notify2'], 'sound:platform_system=="Windows"': ['winsound'] }, classifiers=[ @@ -273,6 +284,14 @@ if __name__ == "__main__": '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={ @@ -282,12 +301,16 @@ if __name__ == "__main__": ], 'bitmessage.notification.message': [ 'notify2 = pybitmessage.plugins.notification_notify2' - '[notify2]' + '[gir, notify2]' ], 'bitmessage.notification.sound': [ 'file.fallback = pybitmessage.plugins.sound_playfile' '[sound]' ], + 'bitmessage.indicator': [ + 'libmessaging =' + 'pybitmessage.plugins.indicator_libmessaging [gir]' + ], # 'console_scripts': [ # 'pybitmessage = pybitmessage.bitmessagemain:main' # ] -- 2.45.1 From 1f47a4060e9bb51d255ab6e3c583e9723d33a295 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 4 Sep 2017 16:06:48 +0300 Subject: [PATCH 0907/1102] Added "Set notification sound..." context menu on addressbook entry. --- src/bitmessageqt/__init__.py | 57 +++++++++++++++++++++++++++++++++--- src/bitmessageqt/sound.py | 2 ++ 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 942ed3de..bb90bb47 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -325,6 +325,10 @@ 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) @@ -1205,9 +1209,9 @@ class MyForm(settingsmixin.SMainWindow): soundFilename = None def _choose_ext(basename): - for ext in ('.wav', '.mp3', '.oga'): - if os.path.isfile(basename + ext): - return ext + for ext in sound.extensions: + if os.path.isfile(os.extsep.join([basename, ext])): + return os.extsep + ext # if the address had a known label in the address book if label: @@ -3175,6 +3179,7 @@ class MyForm(settingsmixin.SMainWindow): 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 @@ -3578,7 +3583,51 @@ class MyForm(settingsmixin.SMainWindow): 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) + def on_context_menuYourIdentities(self, point): currentItem = self.getCurrentItem() self.popMenuYourIdentities = QtGui.QMenu(self) diff --git a/src/bitmessageqt/sound.py b/src/bitmessageqt/sound.py index 4b6aaf00..9c86a9a4 100644 --- a/src/bitmessageqt/sound.py +++ b/src/bitmessageqt/sound.py @@ -17,3 +17,5 @@ def is_connection_sound(category): SOUND_DISCONNECTED, SOUND_CONNECTION_GREEN ) + +extensions = ('wav', 'mp3', 'oga') -- 2.45.1 From 53c3eeb8f77c2d175707d95a5c948df40679a5e8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 11 Sep 2017 17:44:17 +0300 Subject: [PATCH 0908/1102] Sound plugins using pycanberra and gst-python --- setup.py | 3 +++ src/plugins/sound_canberra.py | 21 +++++++++++++++++++++ src/plugins/sound_gstreamer.py | 14 ++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/plugins/sound_canberra.py create mode 100644 src/plugins/sound_gstreamer.py diff --git a/setup.py b/setup.py index cf6bd9d2..dc803931 100644 --- a/setup.py +++ b/setup.py @@ -304,6 +304,9 @@ if __name__ == "__main__": '[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]' ], diff --git a/src/plugins/sound_canberra.py b/src/plugins/sound_canberra.py new file mode 100644 index 00000000..094901ed --- /dev/null +++ b/src/plugins/sound_canberra.py @@ -0,0 +1,21 @@ +# -*- 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 new file mode 100644 index 00000000..062da3f9 --- /dev/null +++ b/src/plugins/sound_gstreamer.py @@ -0,0 +1,14 @@ +# -*- 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) -- 2.45.1 From 2504bc66707948cbd8e156b967b953a31336857e Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 21 Sep 2017 13:59:43 +0300 Subject: [PATCH 0909/1102] Fixed fetch of connected hosts number in bitmessageqt.support --- src/bitmessageqt/support.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 8ec3c16d..03b302e6 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -16,7 +16,7 @@ import paths import proofofwork from pyelliptic.openssl import OpenSSL import queues -import shared +import network.stats import state from version import softwareVersion @@ -124,7 +124,7 @@ def createSupportMessage(myapp): upnp = BMConfigParser().get('bitmessagesettings', 'upnp') except: upnp = "N/A" - connectedhosts = len(shared.connectedHostsList) + 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)) -- 2.45.1 From 196d688b138393d1d540df3322844dfe7e7c02ba Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 21 Sep 2017 13:43:01 +0200 Subject: [PATCH 0910/1102] Remove dependency checking from setup.py - still silently checks for msgpack to set the setuptools requirements correctly, but does not display anything --- setup.py | 362 +++++++++++++------------------------------------------ 1 file changed, 83 insertions(+), 279 deletions(-) diff --git a/setup.py b/setup.py index dc803931..44356e7e 100644 --- a/setup.py +++ b/setup.py @@ -3,207 +3,13 @@ import os import sys import shutil -try: - from setuptools import setup, Extension - from setuptools.command.install import install - haveSetuptools = True -except ImportError: - install = object - haveSetuptools = False - -from importlib import import_module +from setuptools import setup, Extension +from setuptools.command.install import install from src.version import softwareVersion -packageManager = { - "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" -} - -packageName = { - "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 messages coding" - }, - "umsgpack": { - "FreeBSD": "", - "OpenBSD": "", - "Fedora": "", - "openSUSE": "", - "Guix": "", - "Ubuntu 12": "", - "Debian": "python-u-msgpack", - "Ubuntu": "python-u-msgpack", - "Gentoo": "dev-python/u-msgpack", - "optional": True, - "description": "umsgpack can be used instead of msgpack" - }, - "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": "", - } -} - -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", -} - - -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"): - 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]) - except ValueError: - pass - if detectOS.result == "Ubuntu" and version < 14: - detectOS.result = "Ubuntu 12" - elif os.path.isfile("/etc/config.scm"): - detectOS.result = "Guix" - return detectOS.result - - -def detectPrereqs(missing=True): - available = [] - for module in packageName.keys(): - try: - import_module(module) - if not missing: - available.append(module) - except ImportError: - if missing: - available.append(module) - return available - - -def prereqToPackages(): - print "You can install the requirements by running, as root:" - print "%s %s" % ( - packageManager[detectOS()], " ".join( - packageName[x][detectOS()] for x in detectPrereqs())) - for package in detectPrereqs(): - if packageName[package].get('optional'): - print packageName[package].get('description') - - - -def compilerToPackages(): - if not detectOS() in compiling: - return - print "You can install the requirements by running, as root:" - print "%s %s" % ( - packageManager[detectOS.result], compiling[detectOS.result]) - - class InstallCmd(install): def run(self): - detectOS.result = None - prereqs = detectPrereqs() - if prereqs and detectOS() in packageManager: - print "It looks like you're using %s. " \ - "It is highly recommended to use the package manager " \ - "instead of setuptools." % (detectOS.result) - prereqToPackages() - try: - for module in prereqs: - if not packageName[module]['optional']: - sys.exit() - except KeyError: - sys.exit() - - if not haveSetuptools: - print "It looks like you're missing setuptools." - sys.exit() - - if prereqs and sys.stdin.isatty(): - print "Press Return to continue" - try: - raw_input() - except (EOFError, NameError): - pass - # prepare icons directories os.makedirs('desktop/icons/scalable') shutil.copyfile( @@ -238,92 +44,90 @@ if __name__ == "__main__": 'pybitmessage.storage', 'pybitmessage.plugins' ] + # this will silently accept alternative providers of msgpack # if they are already installed - if "msgpack" in detectPrereqs(False): - installRequires.append("msgpack-python") - elif "umsgpack" in detectPrereqs(False): - installRequires.append("umsgpack") - else: - packages += ['pybitmessage.fallback', 'pybitmessage.fallback.umsgpack'] try: - 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", + 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]' ], - 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']) + 'bitmessage.notification.message': [ + 'notify2 = pybitmessage.plugins.notification_notify2' + '[gir, notify2]' ], - 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} - ) - except SystemExit as err: - print err.message - except: - print "It looks like building the package failed.\n" \ - "You may be missing a C++ compiler and the OpenSSL headers." - compilerToPackages() + '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} + ) -- 2.45.1 From 0150a35dd44fd1a6a2b934c700800e24e3636499 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 21 Sep 2017 17:51:34 +0200 Subject: [PATCH 0911/1102] Change main thread name to PyBitmessage --- dev/powinterrupttest.py | 2 +- src/bitmessagemain.py | 2 +- src/helper_generic.py | 2 +- src/helper_threading.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev/powinterrupttest.py b/dev/powinterrupttest.py index 2f8cfcac..cc4c2197 100644 --- a/dev/powinterrupttest.py +++ b/dev/powinterrupttest.py @@ -14,7 +14,7 @@ def signal_handler(signal, frame): 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 != "MainThread": + if current_thread().name != "PyBitmessage": return shutdown = 1 diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 1d37123f..9182b4cb 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -215,7 +215,7 @@ class Main: self.setSignalHandler() - helper_threading.set_thread_name("MainThread") + helper_threading.set_thread_name("PyBitmessage") helper_bootstrap.knownNodes() # Start the address generation thread diff --git a/src/helper_generic.py b/src/helper_generic.py index 26d65dcb..b750e519 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -51,7 +51,7 @@ def signal_handler(signal, frame): raise SystemExit if "PoolWorker" in current_process().name: raise SystemExit - if current_thread().name != "MainThread": + if current_thread().name != "PyBitmessage": return logger.error("Got signal %i", signal) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): diff --git a/src/helper_threading.py b/src/helper_threading.py index 56c5b8b2..3b7ba378 100644 --- a/src/helper_threading.py +++ b/src/helper_threading.py @@ -12,7 +12,7 @@ try: threading.Thread.__bootstrap_original__ = threading.Thread._Thread__bootstrap threading.Thread._Thread__bootstrap = _thread_name_hack except ImportError: - def set_thread_name(name): pass + def set_thread_name(name): threading.current_thread().name = name class StoppableThread(object): def initStop(self): -- 2.45.1 From 1881bcea6848be24b8f30172fd91070eaf8e174c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 21 Sep 2017 18:18:42 +0200 Subject: [PATCH 0912/1102] Don't connect on first start until approved --- src/network/connectionpool.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1026d305..3a7f9e6d 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -141,9 +141,7 @@ class BMConnectionPool(object): acceptConnections = True if BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): acceptConnections = False - else: - spawnConnections = True - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): + elif BMConfigParser().safeGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): spawnConnections = True if BMConfigParser().get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and \ (not BMConfigParser().getboolean('bitmessagesettings', 'sockslisten') and \ -- 2.45.1 From df21f53271af10b6a7f56408112cd644bddaf6e8 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 21 Sep 2017 19:08:10 +0200 Subject: [PATCH 0913/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 88118 -> 88527 bytes src/translations/bitmessage_eo.ts | 323 ++++++++++++++++-------------- 2 files changed, 169 insertions(+), 154 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index e2ac21b2aa70225463a742effbc36a26f4194b0b..018a268ec83772d69447e5484473f13f7826df76 100644 GIT binary patch delta 3567 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 VMCroyaWM&|oo8K2Zv7aR_dic^H1hxe delta 3371 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 EmailGatewayRegistrationDialog - + Registration failed: Registrado malsukcesis: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: @@ -166,52 +166,52 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 Malforviŝi - + View HTML code as formatted text Montri HTML-n kiel aranĝitan tekston - + Save message as... Konservi mesaĝon kiel… - + Mark Unread Marki kiel nelegitan - + New Nova @@ -236,12 +236,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso… - + Email gateway Retpoŝta kluzo @@ -251,37 +251,37 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 - + 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. @@ -291,17 +291,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -311,47 +311,47 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -361,12 +361,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Sendi - + Subscribe Aboni - + Channel Kanalo @@ -376,12 +376,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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. @@ -390,17 +390,17 @@ It is important that you back up this file. 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.) @@ -409,37 +409,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -509,22 +509,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 @@ -532,17 +532,17 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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. @@ -587,67 +587,67 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 - De + - + Sending email gateway registration request Sendado de peto pri registrado je retpoŝta kluzo @@ -662,142 +662,142 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (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 Sendado de peto pri malregistrado de retpoŝta kluzo - + Sending email gateway status request Sendado de peto pri stato de retpoŝta kluzo - + 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. - + 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 etikedon laŭvole. - + 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. Malforviŝis 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? @@ -806,7 +806,7 @@ Are you sure you want to delete the subscription? Ĉu vi certe volas forviŝi 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? @@ -815,92 +815,92 @@ Are you sure you want to delete the channel? Ĉu vi certe volas forviŝi 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. Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. - + 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. La numero de adresversio estas pli alta ol tiun, 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. Kelkaj datumoj koditaj en la adreso estas tro mallongaj. - + Some data encoded in the address is too long. Kelkaj datumoj koditaj en la adreso estas tro longaj. - + Some data encoded in the address is malformed. Kelkaj datumoj koditaj en la adreso estas misformitaj. - + Enter an address above. Enmetu adreson supre. - + Address is an old type. We cannot display its past broadcasts. Malnova speco 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). Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). @@ -1110,47 +1110,47 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. - + 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 - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finiĝos… %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage… %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj… %1% - + Saving settings... %1% Konservado de agordoj… %1% - + Shutting down core... %1% Fermado de kerno… %1% - + Stopping notifications... %1% Haltigado de sciigoj… %1% - + Shutdown imminent... %1% Fermado tuj… %1% @@ -1160,17 +1160,17 @@ Are you sure you want to delete the channel? %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage… %1% - + Sent Senditaj @@ -1274,7 +1274,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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. @@ -1284,7 +1284,7 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 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. @@ -1309,37 +1309,37 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pord-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? @@ -1404,7 +1404,12 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. - + + Set notification sound... + Agordi sciigan sonon… + + + Welcome to easy and secure Bitmessage * send messages to other people @@ -1418,90 +1423,100 @@ Bonvenon al facila kaj sekura Bitmesaĝo * babili kun aliaj uloj en mesaĝ-kanaloj - + not recommended for chans malkonsilinda por kanaloj - + Problems connecting? Try enabling UPnP in the Network Settings Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + 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. - + + 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? + MessageView -- 2.45.1 From 680cc2cafc5c209f08e61aa54a68dd4b62676674 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 21 Sep 2017 19:16:40 +0200 Subject: [PATCH 0914/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 97437 -> 98426 bytes src/translations/bitmessage_de.ts | 364 ++++++++++++++++-------------- 2 files changed, 192 insertions(+), 172 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 6bef4d31ab079830dc5d9da8359206caf3d17d48..63ccd5254141b427e57228bcf0ec9e72a1c935d7 100644 GIT binary patch delta 3809 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 dB_-bI~&?}oKv$R83JlMr){{ozafwlku delta 3327 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 KfzIrb-~RyYKIA0; diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 99505de8..df53838a 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -174,52 +174,52 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 @@ -244,12 +244,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + Email gateway E-Mail Schnittstelle @@ -259,37 +259,37 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 - + 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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. @@ -398,17 +398,17 @@ It is important that you back up this file. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -596,67 +596,67 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 - Von + - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1169,17 +1169,17 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Stunde%n Stunden - + %n day(s) %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1224,85 +1224,85 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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... - + 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. - + 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 @@ -1317,37 +1317,37 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1407,12 +1407,17 @@ Receiver's required difficulty: %1 and %2 Kann NMControl nicht verstehen. - + 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. - + + Set notification sound... + Benachrichtigungsklang einstellen ... + + + Welcome to easy and secure Bitmessage * send messages to other people @@ -1426,85 +1431,100 @@ Willkommen zu einfachem und sicherem Bitmessage * diskutieren Sie mit anderen Leuten in Chans - + not recommended for chans für Chans nicht empfohlen - + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + + 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. - + + 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? + MessageView @@ -1995,7 +2015,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi List of streams negotiated between you and the peer - Liste der zwischen Ihnen und dem Peer ausgehandelten Datenströme + Liste der zwischen Ihnen und dem Peer ausgehandelter Datenströme @@ -2092,17 +2112,17 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. -- 2.45.1 From abea17ded94bdda1d61071c8cba8d878f78c17e9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 21 Sep 2017 19:57:34 +0200 Subject: [PATCH 0915/1102] setup.py check if directory already exists --- setup.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 44356e7e..0851b78f 100644 --- a/setup.py +++ b/setup.py @@ -11,10 +11,16 @@ from src.version import softwareVersion class InstallCmd(install): def run(self): # prepare icons directories - os.makedirs('desktop/icons/scalable') + try: + os.makedirs('desktop/icons/scalable') + except os.error: + pass shutil.copyfile( 'desktop/can-icon.svg', 'desktop/icons/scalable/pybitmessage.svg') - os.makedirs('desktop/icons/24x24') + try: + os.makedirs('desktop/icons/24x24') + except os.error: + pass shutil.copyfile( 'desktop/icon24.png', 'desktop/icons/24x24/pybitmessage.png') -- 2.45.1 From a8ab574c3e9b4d57ff94f78d9124d504de274d10 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 21 Sep 2017 21:06:53 +0200 Subject: [PATCH 0916/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 90995 -> 91798 bytes src/translations/bitmessage_pl.ts | 366 ++++++++++++++++-------------- 2 files changed, 193 insertions(+), 173 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 4ecb0a11d0dffee1d30516e399739dab8ff4aab8..1b51288030ccc843e1f67e161a1c72f4791723d1 100644 GIT binary patch delta 3878 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 gbfiVbt&^rD^J1>smgMJKS!K9hdQ>v EmailGatewayRegistrationDialog - + Registration failed: Rejestracja nie powiodła się: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): @@ -170,52 +170,52 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: 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 @@ -240,12 +240,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Kopiuj adres do schowka - + Special address behavior... Specjalne zachowanie adresu… - + Email gateway Przekaźnik e-mail @@ -255,37 +255,37 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -295,17 +295,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,47 +315,47 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -365,12 +365,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Wyślij - + Subscribe Subskrybuj - + Channel Kanał @@ -380,12 +380,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -394,17 +394,17 @@ It is important that you back up this file. 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.) @@ -413,37 +413,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +513,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +539,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,67 +594,67 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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 - Od + - + Sending email gateway registration request Wysyłanie zapytania o rejestrację na bramce poczty @@ -669,142 +669,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 Wysyłanie zapytania o wyrejestrowanie z bramki poczty - + Sending email gateway status request Wysyłanie zapytania o stan bramki poczty - + 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. Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. - + 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óć 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? @@ -813,7 +813,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,92 +822,92 @@ Are you sure you want to delete the channel? 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. To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. - + The address should start with ''BM-'' Adres powinien zaczynać sie 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. Wprowadź adres powyżej. - + Address is an old type. We cannot display its past broadcasts. Adres starego typu - + There are no recent broadcasts from this address to display. Brak niedawnych wiadomości przekazów do wyświetlenia. - + 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). @@ -1117,47 +1117,47 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. Pokaż %1 ostatnich wiadomości przekazów 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% @@ -1167,17 +1167,17 @@ Czy na pewno chcesz usunąć ten kanał? %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 @@ -1222,131 +1222,131 @@ Czy na pewno chcesz usunąć ten kanał? 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 Przekaz wysłane o %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? @@ -1406,12 +1406,17 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1425,85 +1430,100 @@ Witamy w przyjaznym i bezpiecznym Bitmessage * dyskutuj na kanałach (chany) z innymi ludźmi - + not recommended for chans niezalecany dla kanałów - + 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. - + + 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ć? + MessageView @@ -2091,17 +2111,17 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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. -- 2.45.1 From cfa84cf81a87d85b8b05565b12c195cfd2470fab Mon Sep 17 00:00:00 2001 From: f97ada87 Date: Sat, 23 Sep 2017 07:59:14 +1000 Subject: [PATCH 0917/1102] change default log output from stdout to stderr --- src/debug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.py b/src/debug.py index 663bbeeb..83b11835 100644 --- a/src/debug.py +++ b/src/debug.py @@ -64,7 +64,7 @@ def configureLogging(): 'class': 'logging.StreamHandler', 'formatter': 'default', 'level': log_level, - 'stream': 'ext://sys.stdout' + 'stream': 'ext://sys.stderr' }, 'file': { 'class': 'logging.handlers.RotatingFileHandler', -- 2.45.1 From aaa5e9d309f2654b2f84d090f768faeaa048c172 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 23 Sep 2017 18:25:41 +0200 Subject: [PATCH 0918/1102] Windows daemon mode workaround --- src/bitmessagemain.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 9182b4cb..b015d5bf 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -349,12 +349,13 @@ class Main: shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() - 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 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()) def setSignalHandler(self): signal.signal(signal.SIGINT, helper_generic.signal_handler) -- 2.45.1 From c89d86a779be070e1b4e6572c63bef01247d57ac Mon Sep 17 00:00:00 2001 From: f97ada87 Date: Sun, 24 Sep 2017 07:42:15 +1000 Subject: [PATCH 0919/1102] use getopt parser for command-line arguments --- src/bitmessagemain.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index b015d5bf..f5793ba5 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -29,6 +29,7 @@ from struct import pack from subprocess import call from time import sleep from random import randint +import getopt from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections @@ -199,11 +200,24 @@ class Main: def start(self, daemon=False): _fixSocket() - shared.daemon = daemon + try: + opts, args = getopt.getopt(sys.argv[1:], "hcd", + ["help", "curses", "daemon"]) - # get curses flag - if '-c' in sys.argv: - state.curses = True + 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 + + shared.daemon = daemon # is the application already running? If yes then exit. shared.thisapp = singleinstance("", daemon) @@ -362,6 +376,17 @@ class Main: 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. +''' + def stop(self): with shared.printLock: print('Stopping Bitmessage Deamon.') -- 2.45.1 From 849583642874d2144e26c49f629de3dd8f82a66b Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sun, 24 Sep 2017 11:49:32 +0200 Subject: [PATCH 0920/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 92019 -> 93991 bytes src/translations/bitmessage_ru.ts | 415 +++++++++++++++++------------- 2 files changed, 230 insertions(+), 185 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index f298a70d7e40e8131fe5229ca83b9eb7318c59f5..2cdfe4db1dcb94bd4196bf9f57bcc9f46dcc9db9 100644 GIT binary patch delta 4697 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 delta 3307 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 diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 450b346e..038ddda0 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -58,12 +58,12 @@ 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 Новый адрес @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: Скопировать адрес в буфер обмена - + Special address behavior... Особое поведение адресов... - + Email gateway Email-шлюз @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: Удалить - + 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: Отправить - + Subscribe Подписки - + Channel Канал @@ -378,13 +378,13 @@ Please type the desired email address (including @mailchuck.com) below: Выйти - + 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. @@ -393,19 +393,19 @@ 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.) @@ -415,37 +415,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,67 +596,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1169,17 +1169,17 @@ Are you sure you want to delete the channel? %n час%n часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправлено @@ -1224,131 +1224,131 @@ Are you sure you want to delete the channel? Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. - + Error! Could not find sender address (your address) in the keys.dat file. Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. Выполнение работы, требуемой для отправки сообщения. Для адреса версии 2 (как этот), не требуется указание сложности. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. - + Message sent. Waiting for acknowledgement. Sent on %1 Отправлено. Ожидаем подтверждения. Отправлено в %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 Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1408,12 +1408,17 @@ Receiver's required difficulty: %1 and %2 Не удалось разобрать ответ NMControl. - + Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers. Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + + Set notification sound... + Установить звук уведомления... + + + Welcome to easy and secure Bitmessage * send messages to other people @@ -1427,85 +1432,100 @@ Receiver's required difficulty: %1 and %2 * участвуйте в обсуждениях в чанах - + not recommended for chans не рекомендовано для чанов - + 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? + Вы пытаетесь отправить email вместо 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. - + + 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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?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 @@ -1848,37 +1868,37 @@ The 'Random Number' option is selected by default but deterministic ad Всего соединений: - + 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 # № потока @@ -1913,12 +1933,12 @@ The 'Random Number' option is selected by default but deterministic ad Поисков в каталоге в секунду: %1 - + Up: 0 kB/s Отправка: 0 кБ/с - + Down: 0 kB/s Загрузка: 0 кБ/с @@ -1958,20 +1978,45 @@ The 'Random Number' option is selected by default but deterministic ad Узел - + + 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 @@ -2067,17 +2112,17 @@ The 'Random Number' option is selected by default but deterministic ad 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 недоступен. Пожалуйста, соберите его. -- 2.45.1 From 6ce86b1d0af296dcd2da27a3461b35668f33b83c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 25 Sep 2017 01:17:04 +0200 Subject: [PATCH 0921/1102] Dandelion++ implementation - untested, some functionality may be missing, don't turn on - also, it randomises upload of requested objects - affects #1049 --- src/bitmessagemain.py | 2 ++ src/bmconfigparser.py | 1 + src/class_singleCleaner.py | 5 ++++ src/network/bmobject.py | 4 +++ src/network/bmproto.py | 52 +++++++++++++++++++++++++++++++---- src/network/connectionpool.py | 16 +++++++++++ src/network/dandelion.py | 29 +++++++++++++++++++ src/network/invthread.py | 3 ++ src/network/objectracker.py | 6 ++++ src/network/tcp.py | 6 +++- src/protocol.py | 15 ++++++++-- 11 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 src/network/dandelion.py diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index f5793ba5..1a091c4c 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -54,6 +54,7 @@ from bmconfigparser import BMConfigParser from inventory import Inventory from network.connectionpool import BMConnectionPool +from network.dandelion import DandelionStems from network.networkthread import BMNetworkThread from network.receivequeuethread import ReceiveQueueThread from network.announcethread import AnnounceThread @@ -248,6 +249,7 @@ class Main: sqlLookup.start() Inventory() # init + DandelionStems() # init, needs to be early because other thread may access it early # SMTP delivery thread if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index acc4476a..bb4377a2 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -20,6 +20,7 @@ BMConfigDefaults = { }, "network": { "bind": '', + "dandelion": 0, }, "inventory": { "storage": "sqlite", diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index c37c3ecf..2e4140b6 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -10,6 +10,7 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from network.connectionpool import BMConnectionPool +from network.dandelion import DandelionStems from debug import logger import knownnodes import queues @@ -126,6 +127,10 @@ class singleCleaner(threading.Thread, StoppableThread): # inv/object tracking for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): connection.clean() + # dandelion fluff trigger by expiration + for h, t in DandelionStems().timeouts: + if time.time() > t: + DandelionStems().remove(h) # discovery tracking exp = time.time() - singleCleaner.expireDiscoveredPeers diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 98a14b5e..4cde0c4f 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -4,6 +4,7 @@ import time from addresses import calculateInventoryHash from debug import logger from inventory import Inventory +from network.dandelion import DandelionStems import protocol import state @@ -66,6 +67,9 @@ class BMObject(object): raise BMObjectUnwantedStreamError() def checkAlreadyHave(self): + # if it's a stem duplicate, pretend we don't have it + if self.inventoryHash in DandelionStems().stem: + return if self.inventoryHash in Inventory(): raise BMObjectAlreadyHaveError() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index dbdc26d2..d5214471 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -1,6 +1,7 @@ import base64 import hashlib import time +import random import socket import struct @@ -9,6 +10,7 @@ from debug import logger from inventory import Inventory import knownnodes from network.advanceddispatcher import AdvancedDispatcher +from network.dandelion import DandelionStems, REASSIGN_INTERVAL from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, \ BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError import network.connectionpool @@ -61,6 +63,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.payloadOffset = 0 self.expectBytes = protocol.Header.size self.object = None + self.dandelionRoutes = [] + self.dandelionRefresh = 0 def state_bm_header(self): self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size]) @@ -266,13 +270,23 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # skip? if time.time() < self.skipUntil: return True - #TODO make this more asynchronous and allow reordering + #TODO make this more asynchronous + random.shuffle(items) for i in items: - try: - self.append_write_buf(protocol.CreatePacket('object', Inventory()[i].payload)) - except KeyError: + if i in DandelionStems().stem and \ + self not in DandelionStems().stem[i]: self.antiIntersectionDelay() - logger.info('%s asked for an object we don\'t have.', self.destination) + 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 bm_command_inv(self): @@ -289,6 +303,34 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True + def bm_command_dinv(self): + """ + Dandelion stem announce + """ + items = self.decode_payload_content("l32s") + + if len(items) >= BMProto.maxObjectCount: + logger.error("Too many items in dinv message!") + raise BMProtoExcessiveDataError() + else: + pass + + # ignore command if dandelion turned off + if BMConfigParser().safeGetBoolean("network", "dandelion") == 0: + return True + + if self.dandelionRefresh < time.time(): + self.dandelionRoutes = network.connectionpool.dandelionRouteSelector(self) + self.dandelionRefresh = time.time() + REASSIGN_INTERVAL + + for i in items: + # Fluff trigger by RNG, per item + if random.randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): + DandelionStem().add(i, self.dandelionRoutes) + self.handleReceivedInventory(i) + + return True + def bm_command_object(self): objectOffset = self.payloadOffset nonce, expiresTime, objectType, version, streamNumber = self.decode_payload_content("QQIvv") diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 3a7f9e6d..cde5c9eb 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -51,6 +51,22 @@ class BMConnectionPool(object): except KeyError: pass + def dandelionRouteSelector(node): + # Choose 2 peers randomly + # TODO: handle streams + peers = [] + connections = BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values() + random.shuffle(connections) + for i in connections: + if i == node: + continue + if i.services | protocol.NODE_DANDELION: + peers.append(i) + if len(peers) == 2: + break + return peers + def connectToStream(self, streamNumber): self.streams.append(streamNumber) diff --git a/src/network/dandelion.py b/src/network/dandelion.py new file mode 100644 index 00000000..ea27915f --- /dev/null +++ b/src/network/dandelion.py @@ -0,0 +1,29 @@ +import random +from threading import RLock + +import protocol +from singleton import Singleton + +# randomise routes after 600 seconds +REASSIGN_INTERVAL = 600 +FLUFF_TRIGGER_TIMEOUT = 300 + +@Singleton +class DandelionStems(): + def __init__(self): + self.stem = {} + self.timeouts = {} + self.lock = RLock() + + def add(self, hashId, stems): + with self.lock: + self.stem[hashId] = stems + self.timeouts[hashId] = time.time() + + def remove(self, hashId): + with self.lock: + try: + del self.stem[hashId] + del self.timeouts[hashId] + except KeyError: + pass diff --git a/src/network/invthread.py b/src/network/invthread.py index d680ea13..a868ce95 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -4,6 +4,7 @@ import threading import addresses from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool +from network.dandelion import DandelionStems from queues import invQueue import protocol import state @@ -39,6 +40,8 @@ class InvThread(threading.Thread, StoppableThread): for inv in chunk: if inv[0] not in connection.streams: continue + if inv in DandelionStems().stem and connection not in DandelionStems().stem[inv]: + continue try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[inv[1]] diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 4541ea76..7149f4b1 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -4,6 +4,7 @@ from threading import RLock from debug import logger from inventory import Inventory +from network.dandelion import DandelionStems haveBloom = False @@ -83,6 +84,11 @@ class ObjectTracker(object): if hashId not in Inventory(): with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True + elif hashId in DandelionStems().stem: + # Fluff trigger by cycle detection + DandelionStems().remove(hashId) + with self.objectsNewToMeLock: + self.objectsNewToMe[hashId] = True def hasAddr(self, addr): if haveBloom: diff --git a/src/network/tcp.py b/src/network/tcp.py index 0fcbc160..60acb22c 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -18,6 +18,7 @@ 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 DandelionStems from network.node import Node import network.asyncore_pollchoose as asyncore from network.proxy import Proxy, ProxyError, GeneralProxyError @@ -88,7 +89,7 @@ class TCPConnection(BMProto, TLSDispatcher): 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", self.skipUntil - time.time()) + logger.debug("Skipping processing getdata due to missing object for %.2fs", delay) self.skipUntil = time.time() + delay def state_connection_fully_established(self): @@ -165,6 +166,9 @@ class TCPConnection(BMProto, TLSDispatcher): # 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 objHash in DandelionStems().stem: + continue bigInvList[objHash] = 0 self.objectsNewToThem[objHash] = time.time() objectCount = 0 diff --git a/src/protocol.py b/src/protocol.py index 7ad0db17..ef31b6c1 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -23,6 +23,7 @@ from version import softwareVersion #Service flags NODE_NETWORK = 1 NODE_SSL = 2 +NODE_DANDELION = 8 #Bitfield flags BITFIELD_DOESACK = 1 @@ -191,7 +192,12 @@ def CreatePacket(command, payload=''): def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server = False, nodeid = None): payload = '' payload += pack('>L', 3) # protocol version. - payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer. + # bitflags of the services I offer. + payload += pack('>q', + NODE_NETWORK | + (NODE_SSL if haveSSL(server) else 0) | + (NODE_DANDELION if BMConfigParser().safeGetInt('network', 'dandelion') > 0 else 0) + ) payload += pack('>q', int(time.time())) payload += pack( @@ -203,7 +209,12 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server payload += encodeHost(remoteHost) payload += pack('>H', remotePort) # remote IPv6 and port - payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer. + # bitflags of the services I offer. + payload += pack('>q', + NODE_NETWORK | + (NODE_SSL if haveSSL(server) else 0) | + (NODE_DANDELION if BMConfigParser().safeGetInt('network', 'dandelion') > 0 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 -- 2.45.1 From d574b167d8be0d463ab30918591f8a4b67e60920 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 25 Sep 2017 08:49:21 +0200 Subject: [PATCH 0922/1102] Dandelion updates & fixes - Addresses #1049 - Add dandelion routes for locally generated objects - Minor bugfixes - Send dinv commands on stem objects (instead of always sending inv command) --- src/network/bmproto.py | 2 +- src/network/connectionpool.py | 6 +++--- src/network/invthread.py | 37 +++++++++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d5214471..66f066ef 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -320,7 +320,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True if self.dandelionRefresh < time.time(): - self.dandelionRoutes = network.connectionpool.dandelionRouteSelector(self) + self.dandelionRoutes = BMConnectionPool.dandelionRouteSelector(self) self.dandelionRefresh = time.time() + REASSIGN_INTERVAL for i in items: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index cde5c9eb..fae509c7 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -51,12 +51,12 @@ class BMConnectionPool(object): except KeyError: pass - def dandelionRouteSelector(node): + def dandelionRouteSelector(self, node): # Choose 2 peers randomly # TODO: handle streams peers = [] - connections = BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values() + connections = self.inboundConnections.values() + \ + self.outboundConnections.values() random.shuffle(connections) for i in connections: if i == node: diff --git a/src/network/invthread.py b/src/network/invthread.py index a868ce95..992930db 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,10 +1,13 @@ import Queue +from random import randint 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 DandelionStems +from network.dandelion import DandelionStems, REASSIGN_INTERVAL from queues import invQueue import protocol import state @@ -14,15 +17,30 @@ class InvThread(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="InvBroadcaster") self.initStop() self.name = "InvBroadcaster" + # for locally generated objects + self.dandelionRoutes = [] + self.dandelionRefresh = 0 + + def dandelionLocalRouteRefresh(self): + if self.dandelionRefresh < time(): + self.dandelionRoutes = BMConnectionPool().dandelionRouteSelector(None) + self.dandelionRefresh = time() + REASSIGN_INTERVAL def run(self): while not state.shutdown: chunk = [] while True: + self.dandelionLocalRouteRefresh() try: data = invQueue.get(False) + # locally generated if len(data) == 2: BMConnectionPool().handleReceivedObject(data[0], data[1]) + # Fluff trigger by RNG + # auto-ignore if config set to 0, i.e. dandelion is off + if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): + DandelionStems.add(data[1], self.dandelionRoutes) + # came over the network else: source = BMConnectionPool().getConnectionByAddr(data[2]) BMConnectionPool().handleReceivedObject(data[0], data[1], source) @@ -36,20 +54,27 @@ class InvThread(threading.Thread, StoppableThread): if chunk: for connection in BMConnectionPool().inboundConnections.values() + \ BMConnectionPool().outboundConnections.values(): - hashes = [] + fluffs = [] + stems = [] for inv in chunk: if inv[0] not in connection.streams: continue - if inv in DandelionStems().stem and connection not in DandelionStems().stem[inv]: + if inv[1] in DandelionStems().stem: + if connection in DandelionStems().stem[inv[1]]: + stems.append(inv[1]) continue + # else try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[inv[1]] - hashes.append(inv[1]) + fluffs.append(inv[1]) except KeyError: continue - if hashes: + if fluffs: connection.append_write_buf(protocol.CreatePacket('inv', \ - addresses.encodeVarint(len(hashes)) + "".join(hashes))) + addresses.encodeVarint(len(fluffs)) + "".join(fluffs))) + if stems: + connection.append_write_buf(protocol.CreatePacket('dinv', \ + addresses.encodeVarint(len(stems)) + "".join(stems))) invQueue.iterate() self.stop.wait(1) -- 2.45.1 From 9923d288e03a24215e3cc90a7e95abbdfa6cdd1f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 25 Sep 2017 09:17:15 +0200 Subject: [PATCH 0923/1102] Dandelion fixes - in route selector, some connections may not have the services attribute (yet) - Addresses #1049 --- src/network/connectionpool.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index fae509c7..2943200b 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -61,10 +61,13 @@ class BMConnectionPool(object): for i in connections: if i == node: continue - if i.services | protocol.NODE_DANDELION: - peers.append(i) - if len(peers) == 2: - break + try: + if i.services | protocol.NODE_DANDELION: + peers.append(i) + if len(peers) == 2: + break + except AttributeError: + continue return peers def connectToStream(self, streamNumber): -- 2.45.1 From 1798c90622d68630b492fa13238703770a29ec29 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 25 Sep 2017 11:10:16 +0200 Subject: [PATCH 0924/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 66676 -> 66995 bytes src/translations/bitmessage_ja.ts | 323 ++++++++++++++++-------------- 2 files changed, 169 insertions(+), 154 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 4cf32fd716f80eb8c6aeb03193bef46811d9b2b8..4a639cbf8891e2567c3d6cf1a334c605391371df 100644 GIT binary patch delta 3535 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 OmyqjM*06GA@_zxJdQ1-h delta 3359 zcmX9>d0b8T8-C6`=iGbGJ?GwQY0L;|khMsp#V(QU8YDC!OGLVjZL)SX23b@mimEZH(6Ot!Ivk(l{eeveOoy`9eazRUAI@AG|c-g2ojK}vRVbOX>9C_Vy6 zDL`N-Anyj|763u+K*L=?@NdB2)4+(@K;Z`9>y~_f8;I-)RM{b2bOU;Igj6~b=-m*~ zQ%{~9UTyd7gB(=|9GM4sg#?UFguMPgAf_JVbe?yNOX45Fz{H-AcVz<4xUfM*TV415J_8HJj;tALY%aGt#qm{kOqZArj)chR`y z0}!C1sj&+%XDM1a^W1cQxSwqRJcvZw)5UOL_&Ru{WB~D<;B##ukl7C%Kd<1yHweu9 z94FQ_Hz<@O`SaA>rtToY2!@$XNfV)dEc-CQ}`fat%+J=y2 zlYvJ$7&eLT|8~Og{Y=PBM(A|^`mFQ{!t~2%Gcnqb!*2A#w=P5?Vqu$g$>k44E z5v9{gfKj2iRgdWuSD-wg05E2v>Q|OKW4NGft^```7HVy>07u6N4V@)6Xizud%QghQ zY?jbmYYc4m6}-Y919?{kujxD(TOzcNV}egI1pk^jz}VwL_b?v<{f}U~Mh7j+h42wf zd`AmmEa-UX0wMAp&mVCU?0&?3VzjVyWNTo>5n)X(ajyGT*qBY6UU&_F3Conw9s&?rc^>{?CWyhFFbV?W=2)FpmX0W9jN+Z28es6Sb^J&fN6p3~)7nBb1Z zx}tE}@Rz!4(M^CMBX!s3pCluqbT=(yfD`w052Wcp)(ugb$HI;Wi`ohqcsW!wUvlgP zTvmwIMeN;nAF=k{a$wv6(KWpbE7&eJ_T5JAr;8o|9NM@aM9-33Ch9DDYYg!FE3rdN z99t)goo%jkctz|!x)fOYmDp#h1k5*xk?+_7zt!UG)^~t97sL%0@_^*i;)ZvlfT&zC z!!c?RGjNfb^fI%a4${@u(8#film?-k}=RB zbsbxKH7hKWB6hc?3LKN7)EprDjx?n?Ng~;$8Q&19f^sSLeE^VdmEvDt1r~IZ5;|l8 zAtzGbOP@O;q+RY=oP}*tUb+);@|6m9b^(gUODCSTVAx~Qso8EoJG*qPRv~eDAl*Fn ziXtXRWw9>6%r~;|2ctK)%N}cJ?So{W7wf4-J!HSLlz@Y)WdBGJh#o5UsI&nsmdX9@ zTp{)I$%MAWw znh_zc;j{yNOUs#>R%G7VMgDV z6~OpRxS#gnZ#8FbWK@($aU~2?m&_Uy}ZK337s4=A_NxpiMG4;3wSlP*VczAc< zkdN{3p)Q1Ai1F+W4qNzd#&ZrA>e>e5&Bb|NDW$e?wW(hhdvOQBrG2yoOwr)z8`iULBP**6%=c3nl#k9iCK_9~S-& zq?}eZccR0b4odD8k}l|gQsm_foNKQXz0Y8PMCC$x7BIzMxqO{KI%1V;DO@c)Rw<8y z-|-?nZZbLifKx6ebt=h@?WWoT;wZ0GrrHt3)cpukBjFx#Xl81<@CrGT`_2@ylzU0I z%``rZ06M=gMLg|KZe^Mx$1~tFyJ_+rc4|xGYJ2IGDK3mR&g~hdw1*6s;%v(4@*mag zPgCBo4@~G!(?PY830^iGFJ@td%}gg3ggwGj_UW78?VCcYM0@B-?@(3wKmDU`<-g*OL^S9rP^MKRBZ(xxKX62gB%}8orfdU zadSzT!c*$?#nSUgZY^A{7J z_N#h*gAKUiq?XRE0G_T^Zw9Slf>58<;uPkdQ=ht0N6HRpo}Xr5@;$Aa`zJ*6HAm0= zB3D2+ZTS2sUUg2|_}8PU7kjjbwHXwu!&+2!4xxon(N;Ea_x_~ zB@C$7DwnWjewJKGvq_{MxMX)OD+-u(7Dy$egs|3-Er-d+|QXSNpxSd3rTsD|$>PE$yXNe)Zn z9(-PT%hK|*V$Sj`i@R+jXR!WrOHkD^pyaG&&iNBShq0E$LJlzIf+guWKb-4i*|3j9 z5iFLpG|uFz9+u5t`%<_2S+=;c+zB--=hHcJ`)*l^+mLZUwXJuf+GZA3+ngv%sf|0* zR$a9%5iHLKHQ@}F`CC4?Sa^j#wzhF&BlVZ9UiO(>Qzuxx&$w_MJ!tJ%kLq{+b8Ei? zL~8IH>%dGRvb>iybk9-Xz!YnE+V@mZH>*8~iPR0VPIb3&6h2zxd-43K0oJ6Ox%|yB z(3 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 を含む) を次のように記入してください: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 新規 @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: アドレスをコピー - + Special address behavior... アドレスの特別な動作 - + Email gateway メールゲートウェイ @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: 削除 - + 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. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,67 +588,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ - + From - 送信元 + - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1161,17 +1161,17 @@ Are you sure you want to delete the channel? %n 時間 - + %n day(s) %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1275,7 +1275,7 @@ Receiver's required difficulty: %1 and %2 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 @@ -1285,7 +1285,7 @@ Receiver's required difficulty: %1 and %2 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 @@ -1310,37 +1310,37 @@ Receiver's required difficulty: %1 and %2 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 PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1405,7 +1405,12 @@ Receiver's required difficulty: %1 and %2 GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + + Set notification sound... + 通知音を設定... + + + Welcome to easy and secure Bitmessage * send messages to other people @@ -1420,90 +1425,100 @@ Receiver's required difficulty: %1 and %2 - + not recommended for chans チャンネルにはお勧めしません - + 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 には何かしら誤りがあります。 - + + 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 -- 2.45.1 From dbd12ab8b4ad970df1d6b336bbe90ead3b6cbee3 Mon Sep 17 00:00:00 2001 From: f97ada87 Date: Mon, 25 Sep 2017 19:12:00 +1000 Subject: [PATCH 0925/1102] fix truncation of received ackdata in objectProcessor --- src/class_objectProcessor.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 5d289fcc..e59645bc 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -97,14 +97,24 @@ class objectProcessor(threading.Thread): # Let's check whether this is a message acknowledgement bound for us. if len(data) < 32: return - if data[-32:] in shared.ackdataForWhichImWatching: + readPosition = 20 # bypass the nonce, time, and object type + # chomp version number + versionNumber, varIntLength = decodeVarint( + data[readPosition:readPosition + 10]) + readPosition += varIntLength + # chomp stream number + streamNumber, varIntLength = decodeVarint( + data[readPosition:readPosition + 10]) + readPosition += varIntLength + + if data[readPosition:] in shared.ackdataForWhichImWatching: logger.info('This object is an acknowledgement bound for me.') - del shared.ackdataForWhichImWatching[data[-32:]] + del shared.ackdataForWhichImWatching[data[readPosition:]] sqlExecute('UPDATE sent SET status=?, lastactiontime=? WHERE ackdata=?', 'ackreceived', int(time.time()), - data[-32:]) - queues.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr._translate("MainWindow",'Acknowledgement of the message received %1').arg(l10n.formatTimestamp())))) + 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.') -- 2.45.1 From 08748fa9aeb992c4ace43e0a9fe2ea487b7b0d75 Mon Sep 17 00:00:00 2001 From: f97ada87 Date: Wed, 27 Sep 2017 00:36:02 +1000 Subject: [PATCH 0926/1102] move config read inside main function --- src/bitmessagemain.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 1a091c4c..06d89ba8 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -198,9 +198,11 @@ if shared.useVeryEasyProofOfWorkForTesting: defaults.networkDefaultPayloadLengthExtraBytes / 100) class Main: - def start(self, daemon=False): + def start(self): _fixSocket() + daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon') + try: opts, args = getopt.getopt(sys.argv[1:], "hcd", ["help", "curses", "daemon"]) @@ -406,8 +408,7 @@ All parameters are optional. def main(): mainprogram = Main() - mainprogram.start( - BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')) + mainprogram.start() if __name__ == "__main__": main() -- 2.45.1 From be0e724b2394c3c704147ea61f402b4757f4e806 Mon Sep 17 00:00:00 2001 From: f97ada87 Date: Sat, 30 Sep 2017 19:19:44 +1000 Subject: [PATCH 0927/1102] implement stealth ack objects --- src/api.py | 6 +++-- src/bitmessagecurses/__init__.py | 7 ++++-- src/bitmessageqt/__init__.py | 6 +++-- src/bitmessageqt/account.py | 4 +++- src/class_objectProcessor.py | 17 +++++--------- src/class_singleWorker.py | 19 +++++++++++---- src/class_smtpServer.py | 4 +++- src/helper_ackPayload.py | 40 ++++++++++++++++++++++++++++++++ 8 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 src/helper_ackPayload.py diff --git a/src/api.py b/src/api.py index e20854fc..edb9e23d 100644 --- a/src/api.py +++ b/src/api.py @@ -35,6 +35,7 @@ import network.stats # Classes from helper_sql import sqlQuery,sqlExecute,SqlBulkExecute,sqlStoredProcedure +from helper_ackPayload import genAckPayload from debug import logger from inventory import Inventory from version import softwareVersion @@ -679,7 +680,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): if not fromAddressEnabled: raise APIError(14, 'Your fromAddress is disabled. Cannot send.') - ackdata = OpenSSL.rand(32) + stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + ackdata = genAckPayload(streamNumber, stealthLevel) t = ('', toAddress, @@ -740,7 +742,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): fromAddress, 'enabled') except: raise APIError(13, 'could not find your fromAddress in the keys.dat file.') - ackdata = OpenSSL.rand(32) + ackdata = genAckPayload(streamNumber, 0) toAddress = '[Broadcast subscribers]' ripe = '' diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py index 381d7c7a..fc1d74b2 100644 --- a/src/bitmessagecurses/__init__.py +++ b/src/bitmessagecurses/__init__.py @@ -20,6 +20,7 @@ import curses import dialog from dialog import Dialog from helper_sql import * +from helper_ackPayload import genAckPayload from addresses import * import ConfigParser @@ -778,7 +779,8 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F if len(shared.connectedHostsList) == 0: set_background_title(d, "Not connected warning") scrollbox(d, unicode("Because you are not currently connected to the network, ")) - ackdata = OpenSSL.rand(32) + stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + ackdata = genAckPayload(streamNumber, stealthLevel) sqlExecute( "INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", "", @@ -802,7 +804,8 @@ def sendMessage(sender="", recv="", broadcast=None, subject="", body="", reply=F set_background_title(d, "Empty sender error") scrollbox(d, unicode("You must specify an address to send the message from.")) else: - ackdata = OpenSSL.rand(32) + # dummy ackdata, no need for stealth + ackdata = genAckPayload(streamNumber, 0) recv = BROADCAST_STR ripe = "" sqlExecute( diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index bb90bb47..09669616 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -52,6 +52,7 @@ import random import string from datetime import datetime, timedelta from helper_sql import * +from helper_ackPayload import genAckPayload import helper_search import l10n import openclpow @@ -1879,7 +1880,8 @@ class MyForm(settingsmixin.SMainWindow): if shared.statusIconColor == 'red': 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) + stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + ackdata = genAckPayload(streamNumber, stealthLevel) t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', @@ -1933,7 +1935,7 @@ class MyForm(settingsmixin.SMainWindow): # 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. - ackdata = OpenSSL.rand(32) + ackdata = genAckPayload(streamNumber, 0) toAddress = str_broadcast_subscribers ripe = '' t = ('', # msgid. We don't know what this will be until the POW is done. diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index eee6c7b4..92d497f8 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -5,6 +5,7 @@ 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 @@ -166,7 +167,8 @@ class GatewayAccount(BMAccount): def send(self): status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) - ackdata = OpenSSL.rand(32) + stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + ackdata = genAckPayload(streamNumber, stealthLevel) t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index e59645bc..876eff62 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -21,6 +21,7 @@ import helper_inbox import helper_msgcoding import helper_sent from helper_sql import * +from helper_ackPayload import genAckPayload import protocol import queues import state @@ -97,15 +98,9 @@ class objectProcessor(threading.Thread): # Let's check whether this is a message acknowledgement bound for us. if len(data) < 32: return - readPosition = 20 # bypass the nonce, time, and object type - # chomp version number - versionNumber, varIntLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += varIntLength - # chomp stream number - streamNumber, varIntLength = decodeVarint( - data[readPosition:readPosition + 10]) - readPosition += varIntLength + + # 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.') @@ -558,8 +553,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. - 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. + # 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. + ackdata = genAckPayload(streamNumber, 0) toAddress = '[Broadcast subscribers]' ripe = '' diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 58eb33c6..322bb20e 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -81,6 +81,16 @@ class singleWorker(threading.Thread, StoppableThread): logger.info('Watching for ackdata ' + hexlify(ackdata)) 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( 10) # give some time for the GUI to start before we start on existing POW tasks. @@ -967,11 +977,10 @@ 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) - payload = pack('>Q', (embeddedTime)) - payload += '\x00\x00\x00\x02' # object type: msg - payload += encodeVarint(1) # msg version - payload += encodeVarint(toStreamNumber) + ackdata - + + # 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)) diff --git a/src/class_smtpServer.py b/src/class_smtpServer.py index 3bc81a61..b62a7130 100644 --- a/src/class_smtpServer.py +++ b/src/class_smtpServer.py @@ -14,6 +14,7 @@ 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 @@ -65,7 +66,8 @@ class smtpServerPyBitmessage(smtpd.SMTPServer): def send(self, fromAddress, toAddress, subject, message): status, addressVersionNumber, streamNumber, ripe = decodeAddress(toAddress) - ackdata = OpenSSL.rand(32) + stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + ackdata = genAckPayload(streamNumber, stealthLevel) t = () sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', diff --git a/src/helper_ackPayload.py b/src/helper_ackPayload.py new file mode 100644 index 00000000..ef99ec2a --- /dev/null +++ b/src/helper_ackPayload.py @@ -0,0 +1,40 @@ +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 -- 2.45.1 From b1442ecb0a1e8c383040a071c648624c38fef5c5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 30 Sep 2017 13:42:04 +0200 Subject: [PATCH 0928/1102] Dandelion fixes and updates - also, randomise the item order in an inv/dinv command --- src/network/bmproto.py | 6 ++---- src/network/dandelion.py | 10 ++++++---- src/network/invthread.py | 26 +++++++++++++++----------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 66f066ef..8099c5fc 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -274,7 +274,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): random.shuffle(items) for i in items: if i in DandelionStems().stem and \ - self not in DandelionStems().stem[i]: + self != DandelionStems().stem[i]: self.antiIntersectionDelay() logger.info('%s asked for a stem object we didn\'t offer to it.', self.destination) break @@ -324,9 +324,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.dandelionRefresh = time.time() + REASSIGN_INTERVAL for i in items: - # Fluff trigger by RNG, per item - if random.randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): - DandelionStem().add(i, self.dandelionRoutes) + DandelionStems().add(i, self, self.dandelionRoutes) self.handleReceivedInventory(i) return True diff --git a/src/network/dandelion.py b/src/network/dandelion.py index ea27915f..045f7288 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,7 +1,6 @@ -import random +from random import choice from threading import RLock -import protocol from singleton import Singleton # randomise routes after 600 seconds @@ -12,18 +11,21 @@ FLUFF_TRIGGER_TIMEOUT = 300 class DandelionStems(): def __init__(self): self.stem = {} + self.source = {} self.timeouts = {} self.lock = RLock() - def add(self, hashId, stems): + def add(self, hashId, source, stems): with self.lock: - self.stem[hashId] = stems + self.stem[hashId] = choice(stems) + self.source[hashId] = source self.timeouts[hashId] = time.time() def remove(self, hashId): with self.lock: try: del self.stem[hashId] + del self.source[hashId] del self.timeouts[hashId] except KeyError: pass diff --git a/src/network/invthread.py b/src/network/invthread.py index 992930db..574e8a3a 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -1,5 +1,5 @@ import Queue -from random import randint +from random import randint, shuffle import threading from time import time @@ -35,11 +35,8 @@ class InvThread(threading.Thread, StoppableThread): data = invQueue.get(False) # locally generated if len(data) == 2: + DandelionStems.add(data[1], None, self.dandelionRoutes) BMConnectionPool().handleReceivedObject(data[0], data[1]) - # Fluff trigger by RNG - # auto-ignore if config set to 0, i.e. dandelion is off - if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): - DandelionStems.add(data[1], self.dandelionRoutes) # came over the network else: source = BMConnectionPool().getConnectionByAddr(data[2]) @@ -59,21 +56,28 @@ class InvThread(threading.Thread, StoppableThread): for inv in chunk: if inv[0] not in connection.streams: continue - if inv[1] in DandelionStems().stem: - if connection in DandelionStems().stem[inv[1]]: - stems.append(inv[1]) - continue - # else try: with connection.objectsNewToThemLock: del connection.objectsNewToThem[inv[1]] - fluffs.append(inv[1]) except KeyError: continue + if inv[1] in DandelionStems().stem: + if connection == DandelionStems().stem[inv[1]]: + # Fluff trigger by RNG + # auto-ignore if config set to 0, i.e. dandelion is off + if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): + stems.append(inv[1]) + else: + fluffs.append(inv[1]) + continue + else: + 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() -- 2.45.1 From 6548999a49a1943fc4c17cd51584e831b1610db7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 2 Oct 2017 08:02:29 +0200 Subject: [PATCH 0929/1102] Dandelion fix - thanks to g1itch for reporting - addresses #1049 --- src/network/invthread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/invthread.py b/src/network/invthread.py index 574e8a3a..cbed7a70 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -35,7 +35,7 @@ class InvThread(threading.Thread, StoppableThread): data = invQueue.get(False) # locally generated if len(data) == 2: - DandelionStems.add(data[1], None, self.dandelionRoutes) + DandelionStems().add(data[1], None, self.dandelionRoutes) BMConnectionPool().handleReceivedObject(data[0], data[1]) # came over the network else: -- 2.45.1 From 1abdc148077058f25f090aef95ad8a3ffdfe6ec8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 3 Oct 2017 18:01:54 +0300 Subject: [PATCH 0930/1102] Fix statusbar chan creation message: non-ASCII characters displayed incorrectly --- src/bitmessageqt/newchandialog.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index a7784206..b28d2bec 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -37,7 +37,7 @@ class NewChanDialog(QtGui.QDialog, RetranslateMixin): 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(str(self.chanPassPhrase.text().toUtf8())))) + UISignalQueue.put(('updateStatusBar', _translate("newchandialog", "Successfully created / joined chan %1").arg(unicode(self.chanPassPhrase.text())))) self.parent.ui.tabWidget.setCurrentIndex(3) self.done(QtGui.QDialog.Accepted) else: -- 2.45.1 From 333170b17256842a12a00bebe0e3e0863271d02a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=A0urda?= Date: Fri, 6 Oct 2017 12:19:34 +0200 Subject: [PATCH 0931/1102] Dandelion fixes - more exception handling - only use outbound connections for stems (thanks to @amillter for info) - don't create stems if config disabled - addresses #1049 --- src/network/connectionpool.py | 3 +-- src/network/dandelion.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 2943200b..7ae8afd9 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -55,8 +55,7 @@ class BMConnectionPool(object): # Choose 2 peers randomly # TODO: handle streams peers = [] - connections = self.inboundConnections.values() + \ - self.outboundConnections.values() + connections = self.outboundConnections.values() random.shuffle(connections) for i in connections: if i == node: diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 045f7288..840cc909 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,6 +1,8 @@ from random import choice from threading import RLock +from time import time +from bmconfigparser import BMConfigParser from singleton import Singleton # randomise routes after 600 seconds @@ -16,10 +18,15 @@ class DandelionStems(): self.lock = RLock() def add(self, hashId, source, stems): + if BMConfigParser().safeGetInt('network', 'dandelion') == 0: + return with self.lock: - self.stem[hashId] = choice(stems) + try: + self.stem[hashId] = choice(stems) + except IndexError: + self.stem = None self.source[hashId] = source - self.timeouts[hashId] = time.time() + self.timeouts[hashId] = time() def remove(self, hashId): with self.lock: -- 2.45.1 From a49b3b5f848783f6df9a4483a41b9e50c50a89ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=A0urda?= Date: Fri, 6 Oct 2017 18:26:06 +0200 Subject: [PATCH 0932/1102] Asyncore UDP fix - when there was an error writing to a udp socket, it wasn't handled correctly --- src/network/udp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/udp.py b/src/network/udp.py index 27cf0abb..bd867125 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -151,6 +151,7 @@ class UDPSocket(BMProto): 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) -- 2.45.1 From 1eb0dd6f01f75184ea3145b6f7bda852fc0f1fd7 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Sun, 15 Oct 2017 13:45:31 +0200 Subject: [PATCH 0933/1102] Auto-updated language fr from transifex --- src/translations/bitmessage_fr.qm | Bin 97042 -> 98998 bytes src/translations/bitmessage_fr.ts | 461 +++++++++++++++++------------- 2 files changed, 263 insertions(+), 198 deletions(-) diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 2eccb916105d2b8c6b91deea59a3f929ba821f02..742e62d828d8f0097737237cc4353a8ca0d454d8 100644 GIT binary patch delta 4700 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 delta 3364 zcmX|D3s{V48@}K9zHer}nQvyuAvvU$a_Art9ad2yhq6eCB+_o8l2{crCC4^GC8Z+D zV#!ugWaZFW8=xkt3y>%RbBEIJr-6|1 zU||m6ubKhjW5GAi10r(3KeGWM4Lgx(H4svGApJOmUGIUziy-K8#sk?t5OTbMJsl8^ z6o3WTK&aRZ78D5iA&xcq!&4|An6aB3|qdei$q#=)|tADDM8hF_%boA*I)yFCx69)Zy}lYn<;;biy% z2n~gM!8%~I8z%0o1_leA$arH+`g11WTn5jKmsH^ec&N5{}}^-`2wr~1af zM1w8`On8mv<&D6O=eW~{(y?j6eYaCY^ly0kGnHHXgo%6K(EF~;V2>88cLD3)n+Npq zCz-rg|<+IC@9gweM?+Pj4G9%U@a|4EW%7oJt_|O}f6!sWs9VxSLxl07L z$*j&&Ki4_QtXc_^{*l?NS_@osmJNTm7OZEI%&9dISaV4>F@Z2{mn>v#8xeI{w$!Rj zPl1-o!Zw8iU(S{3<060&)w1N9UBRr1WGPl<^!%l4%d!{1rRTCefe!$SF0upu^nO@^ ztW--0b_lZCK*F7CWH-YGl60@in&K{yBBsh(v-ud4>-#0In@>`oIiK%&*bhwZ%#SH2*O-2vck?2OUsdxSwIsr@ zfqd{WYZ~@+UcW?L1jc9bO9#gS@)Ca4zr^)_y!pho8^HOa{H9UF>4q!(jvS(DbUpt= zDg)eC@<)bHqGulPM=T5J`vJZ*r#n#9z@Iwo3})TLpL;e0Y=$*o9b*PeYv*qooTulJ zd`s19(o_zAca<@4{A<0yZd(H`(*>&x!b2Xy=$E^I1Utc@<|SBa6m!XjVdHlw@nwcR<=&}AVak6P{CEF{?0fsM@*k`jW!=1dT_ zIMV(H(}i6QLx4Y~2-&Zrz((mKgx#AcV794Hv{@kAc_B%jAK}^T4#}^02SN$+(}& zBW~CdrAqnAZ8UasR?9biOVkCm$a5w?1k*2Rmlyn24{UlOKbYnRm?g-MT2Q6)YUQO{ zy8&-Yrnx_ROy2-B}HlXoYAiv{79QqW>U&tv?NvXnM8&R~;KrvcHmG>=H zI4&3jq`gykHrD~W-Y9&w#gYHoD}skFCQWo#B<*oQA9##bY?x{U=5MFiYIhfym7>_z zlhohyU0R#mTrZqZ{E$M!fsoH=vHLT&-|9prBq_?L z0R!f%LR%@**9SY1*=<$D`_l4_@)F$KJxs48-PPcHRPRqFeZOu<5RQvHT1o1{8h z=LlwOpt_JiGk0)?>gom;VC4+eAN~)4mIbQknUvV%)oSKxRzwont`=j0feF8=Ra^s* z8mU%2SOI2fsMaL9Q|0w(xuUVYS*LcMeFg|lEct z)>l2f;}F=am+GL^Bn0CE^>?vJgiF=is#++&7p04U=27{=B9_nW%;Mhbo=rMr*<7Bx!g3nvp(FB_#p(XZ)pU@Dau&_)CIOC@87 zxvG9r$tP)7e3U98NTYwxlPXyhxnM#kvN>0zs-5G2ZKtHV$MJNNY>=*odI2Atr3T## zI-0ji&24l!n|V*Vy}FSC8cJ_A5+PX!HOfb2#8`=@&r&ne&eLm}fk77l8=1yDivq;{ zps`9j4E+1M#wNLvG;EX>thUxq8mC$Emf|!PXu^+&(@a0nMCg5i_z+F3TPhJ9rdhMb znP#m)lXt5Q_`R#dbS{Udf?Z(%Nh5h8fW;;WG|3{*3KQ zI*|!qXq&z0PV?qTC$do=w0}(>s3%F7YCjrl!G>+t4KwRaZsDP`4PQyuNei9bC1bj+ z#_F8YP9<#7O)GE)t`+L${CEbeOR+96dmXuAh%P+Uf!zPHF4B@JH@c%s zoIvYMzSX6+6a&d6x&q^7BBH16aP3Dh$K|@BiH;N)S9KNr^T>`)=qgvd04_M`&i5cJ zH`HAV_X57M)IA(S!?=6B?){c^bd6M#_lLD-{?mi`l>VrRjOZ!Hcm%^l`Kfw2{R 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) : @@ -173,52 +173,52 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : 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 @@ -243,12 +243,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Copier l’adresse dans le presse-papier - + Special address behavior... Comportement spécial de l’adresse… - + Email gateway Passerelle de courriel @@ -258,37 +258,37 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -298,17 +298,17 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -318,47 +318,47 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) : - + 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 @@ -368,12 +368,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :Envoyer - + Subscribe S’abonner - + Channel Canal @@ -383,12 +383,12 @@ Veuillez taper l’adresse de courriel désirée (incluant @mailchuck.com) :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. @@ -396,54 +396,54 @@ It is important that you back up this file. 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. @@ -513,22 +513,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -537,17 +537,17 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -592,67 +592,67 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r - + 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 - De + - + Sending email gateway registration request Envoi de la demande d’inscription de la passerelle de courriel @@ -667,142 +667,142 @@ Le destinataire doit l’obtenir avant ce temps. Si votre client Bitmessage ne r 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? @@ -811,7 +811,7 @@ Are you sure you want to delete the subscription? Ê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? @@ -820,92 +820,92 @@ Are you sure you want to delete the channel? Ê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). @@ -1115,47 +1115,47 @@ Are you sure you want to delete the channel? 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% @@ -1165,17 +1165,17 @@ Are you sure you want to delete the channel? %n heure%n heures - + %n day(s) %n jour%n jours - + Shutting down PyBitmessage... %1% PyBitmessage en cours d’arrêt… %1% - + Sent Envoyé @@ -1220,146 +1220,146 @@ Are you sure you want to delete the channel? Alerte : votre disque ou le volume de stockage de données est plein. Bitmessage va maintenant se fermer. - + 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. - + Doing work necessary to send broadcast... Travail en cours afin d’envoyer le message de diffusion… - + Broadcast sent on %1 Message de diffusion envoyé %1 - + Encryption key was requested earlier. La clé de chiffrement a été demandée plus tôt. - + Sending a request for the recipient's encryption key. Envoi d’une demande de la clé de chiffrement du destinataire. - + Looking up the receiver's public key Recherche de la clé publique du récepteur - + 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 - + 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. - + 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 - + 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 - + 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 - + Doing work necessary to send message. Travail en cours afin d’envoyer le message. - + Message sent. Waiting for acknowledgement. Sent on %1 Message envoyé. En attente de l’accusé de réception. Envoyé %1 - + Doing work necessary to request encryption key. Travail en cours afin d’obtenir la clé de chiffrement. - + 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. - + 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 - + UPnP port mapping established on port %1 Transfert de port UPnP établi sur le port %1 - + UPnP port mapping removed Transfert de port UPnP retiré - + Mark all messages as read Marquer tous les messages comme lus - + Are you sure you would like to mark all messages read? Êtes-vous sûr(e) de vouloir marquer tous les messages comme lus ? - + Doing work necessary to send broadcast. Travail en cours afin d’envoyer la diffusion. - + 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 - + Wait until these tasks finish? Attendre jusqu'à ce que ces tâches se terminent ? - + 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. - + SOCKS5 Authentication problem: %1. Please check your SOCKS5 settings. Problème d’authentification SOCKS5 : %1. Veuillez vérifier vos réglages SOCKS5. - + 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. @@ -1404,12 +1404,17 @@ Difficulté requise du destinataire : %1 et %2 Ne pouvait pas comprendre NMControl. - + 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 @@ -1424,85 +1429,100 @@ Bienvenue dans le facile et sécurisé Bitmessage - + not recommended for chans pas recommandé pour les canaux - + Problems connecting? Try enabling UPnP in the Network Settings Des difficultés à se connecter ? Essayez de permettre UPnP dans les "Paramètres réseau" - + + 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 ? + + + 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 - + 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. - + 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. - + 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. - + 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. - + 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. - + 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: Something is wrong with the recipient address %1. Erreur : quelque chose ne va pas avec l'adresse de destinataire %1. - + + From %1 + De %1 + + + 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 ? - + Not connected Non connecté - + 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 ? - + Waiting for network connection... En attente de connexion réseau... - + Waiting for finishing synchronisation... En attente d'achèvement de la synchronisation... + + + 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 ? + MessageView @@ -1530,14 +1550,14 @@ Bienvenue dans le facile et sécurisé Bitmessage 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 @@ -1845,77 +1865,77 @@ The 'Random Number' option is selected by default but deterministic ad 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 - Connexions + - + 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 @@ -1925,30 +1945,75 @@ The 'Random Number' option is selected by default but deterministic ad 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 + + newChanDialog @@ -2044,17 +2109,17 @@ The 'Random Number' option is selected by default but deterministic ad 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. -- 2.45.1 From 4c9006a632761ff63902307eba1b96d8ad39ff58 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 16 Oct 2017 08:07:32 +0200 Subject: [PATCH 0934/1102] Asyncore performance optimisation - use bytearray instead of strings for buffers --- src/network/advanceddispatcher.py | 25 ++++++++++++++++--------- src/network/bmproto.py | 18 +++++++++--------- src/network/downloadthread.py | 5 ++++- src/network/udp.py | 4 ++-- 4 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index eb636aed..576eed39 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -12,8 +12,8 @@ class AdvancedDispatcher(asyncore.dispatcher): def __init__(self, sock=None): if not hasattr(self, '_map'): asyncore.dispatcher.__init__(self, sock) - self.read_buf = b"" - self.write_buf = b"" + self.read_buf = bytearray() + self.write_buf = bytearray() self.state = "init" self.lastTx = time.time() self.sentBytes = 0 @@ -25,18 +25,23 @@ class AdvancedDispatcher(asyncore.dispatcher): def append_write_buf(self, data): if data: - with self.writeLock: - self.write_buf += 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: - self.write_buf = self.write_buf[length:] + del self.write_buf[0:length] def slice_read_buf(self, length=0): if length > 0: with self.readLock: - self.read_buf = self.read_buf[length:] + del self.read_buf[0:length] def process(self): if not self.connected: @@ -85,7 +90,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.receivedBytes += len(newData) asyncore.update_received(len(newData)) with self.readLock: - self.read_buf += newData + self.read_buf.extend(newData) def handle_write(self): self.lastTx = time.time() @@ -108,7 +113,9 @@ class AdvancedDispatcher(asyncore.dispatcher): return False def handle_close(self): - self.read_buf = b"" - self.write_buf = b"" + with self.readLock: + self.read_buf = bytearray() + with self.writeLock: + self.write_buf = bytearray() self.state = "close" asyncore.dispatcher.close(self) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 8099c5fc..a086fde0 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -138,16 +138,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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, host[12:]) + host = socket.inet_ntop(socket.AF_INET, buffer(host, 12, 4)) 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, host) + host = socket.inet_ntop(socket.AF_INET6, buffer(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, host[12:]) + host = socket.inet_ntop(socket.AF_INET, buffer(host, 12, 4)) return Node(services, host, port) @@ -272,7 +272,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True #TODO make this more asynchronous random.shuffle(items) - for i in items: + for i in map(str, items): if i in DandelionStems().stem and \ self != DandelionStems().stem[i]: self.antiIntersectionDelay() @@ -298,7 +298,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): else: pass - for i in items: + for i in map(str, items): self.handleReceivedInventory(i) return True @@ -323,7 +323,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.dandelionRoutes = BMConnectionPool.dandelionRouteSelector(self) self.dandelionRefresh = time.time() + REASSIGN_INTERVAL - for i in items: + for i in map(str, items): DandelionStems().add(i, self, self.dandelionRoutes) self.handleReceivedInventory(i) @@ -354,12 +354,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): try: self.object.checkObjectByType() - objectProcessorQueue.put((self.object.objectType, self.object.data)) + objectProcessorQueue.put((self.object.objectType, buffer(self.object.data))) except BMObjectInvalidError as e: BMProto.stopDownloadingObject(self.object.inventoryHash, True) Inventory()[self.object.inventoryHash] = ( - self.object.objectType, self.object.streamNumber, self.payload[objectOffset:], self.object.expiresTime, self.object.tag) + self.object.objectType, self.object.streamNumber, buffer(self.payload[objectOffset:]), self.object.expiresTime, buffer(self.object.tag)) invQueue.put((self.object.streamNumber, self.object.inventoryHash, self.destination)) return True @@ -370,7 +370,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): addresses = self._decode_addr() for i in addresses: seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(ip) + decodedIP = protocol.checkIPAddress(buffer(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 34f23eed..98b6df05 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -55,7 +55,10 @@ class DownloadThread(threading.Thread, StoppableThread): i.objectsNewToMe[k] = False self.pending[k] = now - payload = addresses.encodeVarint(len(request)) + ''.join(request) + payload = bytearray() + payload.extend(addresses.encodeVarint(len(request))) + for chunk in request: + payload.extend(chunk) 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) diff --git a/src/network/udp.py b/src/network/udp.py index bd867125..3d238a5e 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -89,7 +89,7 @@ class UDPSocket(BMProto): remoteport = False for i in addresses: seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(ip) + decodedIP = protocol.checkIPAddress(buffer(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if seenTime < time.time() - BMProto.maxTimeOffset or seenTime > time.time() + BMProto.maxTimeOffset: @@ -142,7 +142,7 @@ class UDPSocket(BMProto): else: self.local = False # overwrite the old buffer to avoid mixing data and so that self.local works correctly - self.read_buf = recdata + self.read_buf[0:] = recdata self.bm_proto_reset() receiveDataQueue.put(self.listening) -- 2.45.1 From 9dae77dd2bc5c4104fdb5b9a53bd6f8ec151b0fc Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 12 Oct 2017 00:26:14 +0300 Subject: [PATCH 0935/1102] Quiet Mode (i.e. turn off notification) in tray menu --- src/bitmessageqt/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index bb90bb47..0cedf8c7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -864,6 +864,12 @@ 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): @@ -1157,6 +1163,14 @@ class MyForm(settingsmixin.SMainWindow): 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) -- 2.45.1 From 8e761693889b914ef52c4c27b3c57e28ff096c65 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 7 Oct 2017 17:28:32 +0300 Subject: [PATCH 0936/1102] Check IP before adding to knownnodes in helper_bootstrap --- src/helper_bootstrap.py | 48 ++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index 7c7456e1..0ba86348 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -9,6 +9,7 @@ import knownnodes import socks import state + def addKnownNode(stream, peer, lastseen=None, self=False): if lastseen is None: lastseen = time.time() @@ -18,6 +19,7 @@ def addKnownNode(stream, peer, lastseen=None, self=False): "self": self, } + def knownNodes(): try: with open(state.appdata + 'knownnodes.dat', 'rb') as pickleFile: @@ -38,26 +40,37 @@ def knownNodes(): logger.error('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. - if BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'none': + def try_add_known_node(stream, addr, port, method=''): try: - for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): - logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - addKnownNode(1, state.Peer(item[4][0], 8080)) - except: - logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') - try: - for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): - logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - addKnownNode(1, state.Peer(item[4][0], 8444)) - except: - logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') - elif BMConfigParser().get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + 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]: + try: + for item in socket.getaddrinfo( + 'bootstrap%s.bitmessage.org' % port, 80): + try_add_known_node(1, item[4][0], port) + 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]: @@ -89,8 +102,9 @@ def dns(): except: logger.error("SOCKS DNS resolving failed", exc_info=True) else: - if ip is not None: - logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') - addKnownNode(1, state.Peer(ip, port)) + try_add_known_node(1, ip, port, 'SOCKS') else: - logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') + logger.info( + 'DNS bootstrap skipped because the proxy type does not support' + ' DNS resolution.' + ) -- 2.45.1 From 59d1309a9e4c389cf6b21c9786490c704705b2a5 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 9 Oct 2017 12:09:09 +0300 Subject: [PATCH 0937/1102] Fixed typo when closing tempfile in bitmessageqt.__init__ --- src/bitmessageqt/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0cedf8c7..7e945229 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3994,8 +3994,9 @@ class settingsDialog(QtGui.QDialog): else: try: import tempfile - file = tempfile.NamedTemporaryFile(dir=paths.lookupExeFolder(), delete=True) - file.close # should autodelete + tempfile.NamedTemporaryFile( + dir=paths.lookupExeFolder(), delete=True + ).close() # should autodelete except: self.ui.checkBoxPortableMode.setDisabled(True) -- 2.45.1 From 9cffd50de8580577850099f8611b367a0c84a8d6 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 12 Oct 2017 16:13:59 +0300 Subject: [PATCH 0938/1102] Fixed statusbar message on error in namecoin name search --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7e945229..4d2c0bad 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1999,7 +1999,7 @@ class MyForm(settingsmixin.SMainWindow): err, addr = nc.query(identities[-1].strip()) if err is not None: self.statusBar().showMessage(_translate( - "MainWindow", "Error: " + err), 10000) + "MainWindow", "Error: %1").arg(err), 10000) else: identities[-1] = addr self.ui.lineEditTo.setText("; ".join(identities)) -- 2.45.1 From 7e0932815dbd0e0f8e181c815014bcce560cc5eb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 01:46:32 +0200 Subject: [PATCH 0939/1102] UDP socket closing fix - invalid data or an incomplete read on UDP socket caused it to close --- src/network/bmproto.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index a086fde0..fb0fea30 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -114,6 +114,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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) -- 2.45.1 From 1ba1f026866ebd163d260201843eb87051065e4c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 08:31:05 +0200 Subject: [PATCH 0940/1102] Remove superfluous validator signal connect in newchandialog - apparently it connects automatically and just creates an error message --- src/bitmessageqt/newchandialog.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index b28d2bec..a129c608 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -15,8 +15,6 @@ class NewChanDialog(QtGui.QDialog, RetranslateMixin): 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)) - QtCore.QObject.connect(self.chanAddress, QtCore.SIGNAL('textEdited()'), self.chanAddress.validator(), QtCore.SLOT('checkData(self)')) - QtCore.QObject.connect(self.chanPassPhrase, QtCore.SIGNAL('textEdited()'), self.chanPassPhrase.validator(), QtCore.SLOT('checkData(self)')) self.timer = QtCore.QTimer() QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.delayedUpdateStatus) -- 2.45.1 From a013814c6b244dfb8009411572bd5b56f47d6dee Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 08:39:09 +0200 Subject: [PATCH 0941/1102] Network tab updates - handle add/remove entry instead of recreating the whole connection list - update processed object counts after each object --- src/bitmessageqt/networkstatus.py | 67 ++++++++++++++++++++----------- src/bitmessageqt/uisignaler.py | 3 +- src/class_objectProcessor.py | 12 +++--- src/network/tcp.py | 5 ++- 4 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 2609a3c4..e9073cb8 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -11,6 +11,7 @@ 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): @@ -31,7 +32,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "updateNetworkStatusTab()"), self.updateNetworkStatusTab) + "updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab) self.timer = QtCore.QTimer() self.timer.start(2000) # milliseconds @@ -52,17 +53,17 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): 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.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.updateNumberOfObjectsToBeSynced() self.labelBroadcastCount.setText(_translate( "networkstatus", "Processed %n broadcast message(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfBroadcastsProcessed)) def updateNumberOfPubkeysProcessed(self): -# self.updateNumberOfObjectsToBeSynced() + self.updateNumberOfObjectsToBeSynced() self.labelPubkeyCount.setText(_translate( "networkstatus", "Processed %n public key(s).", None, QtCore.QCoreApplication.CodecForTr, shared.numberOfPubkeysProcessed)) @@ -76,50 +77,71 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): self.labelBytesSentCount.setText(_translate( "networkstatus", "Up: %1/s Total: %2").arg(self.formatByteRate(network.stats.uploadSpeed()), self.formatBytes(network.stats.sentBytes()))) - def updateNetworkStatusTab(self): - connectedHosts = network.stats.connectedHostsList() + 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) - #self.tableWidgetConnectionCount.clearContents() - self.tableWidgetConnectionCount.setRowCount(0) - for i in connectedHosts: + self.tableWidgetConnectionCount.setSortingEnabled(False) + if add: self.tableWidgetConnectionCount.insertRow(0) self.tableWidgetConnectionCount.setItem(0, 0, - QtGui.QTableWidgetItem("%s:%i" % (i.destination.host, i.destination.port)) + QtGui.QTableWidgetItem("%s:%i" % (destination.host, destination.port)) ) self.tableWidgetConnectionCount.setItem(0, 2, - QtGui.QTableWidgetItem("%s" % (i.userAgent)) + QtGui.QTableWidgetItem("%s" % (c.userAgent)) ) self.tableWidgetConnectionCount.setItem(0, 3, - QtGui.QTableWidgetItem("%s" % (i.tlsVersion)) + QtGui.QTableWidgetItem("%s" % (c.tlsVersion)) ) self.tableWidgetConnectionCount.setItem(0, 4, - QtGui.QTableWidgetItem("%s" % (",".join(map(str,i.streams)))) + QtGui.QTableWidgetItem("%s" % (",".join(map(str,c.streams)))) ) try: # FIXME hard coded stream no - rating = knownnodes.knownNodes[1][i.destination]['rating'] + rating = "%.1f" % (knownnodes.knownNodes[1][destination]['rating']) except KeyError: rating = "-" self.tableWidgetConnectionCount.setItem(0, 1, QtGui.QTableWidgetItem("%s" % (rating)) ) - if i.isOutbound: + 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.tableWidgetConnectionCount.horizontalHeader().setSortIndicator(1, QtCore.Qt.AscendingOrder) + self.tableWidgetConnectionCount.setSortingEnabled(True) + self.tableWidgetConnectionCount.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) self.labelTotalConnections.setText(_translate( - "networkstatus", "Total Connections: %1").arg(str(len(connectedHosts)))) + "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 connectedHosts and shared.statusIconColor == 'red': + if self.tableWidgetConnectionCount.rowCount() and shared.statusIconColor == 'red': self.window().setStatusIcon('yellow') - elif not connectedHosts and shared.statusIconColor != "red": + elif self.tableWidgetConnectionCount.rowCount() == 0 and shared.statusIconColor != "red": self.window().setStatusIcon('red') # timer driven @@ -129,9 +151,6 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): Inventory().numberOfInventoryLookupsPerformed = 0 self.updateNumberOfBytes() self.updateNumberOfObjectsToBeSynced() - self.updateNumberOfMessagesProcessed() - self.updateNumberOfBroadcastsProcessed() - self.updateNumberOfPubkeysProcessed() def retranslateUi(self): super(NetworkStatus, self).retranslateUi() diff --git a/src/bitmessageqt/uisignaler.py b/src/bitmessageqt/uisignaler.py index aabfaf68..055f9097 100644 --- a/src/bitmessageqt/uisignaler.py +++ b/src/bitmessageqt/uisignaler.py @@ -45,7 +45,8 @@ class UISignaler(QThread): "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()")) + 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': diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index e59645bc..ec2b32b9 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -194,8 +194,8 @@ class objectProcessor(threading.Thread): def processpubkey(self, data): pubkeyProcessingStartTime = time.time() shared.numberOfPubkeysProcessed += 1 -# queues.UISignalQueue.put(( -# 'updateNumberOfPubkeysProcessed', 'no data')) + queues.UISignalQueue.put(( + 'updateNumberOfPubkeysProcessed', 'no data')) embeddedTime, = unpack('>Q', data[8:16]) readPosition = 20 # bypass the nonce, time, and object type addressVersion, varintLength = decodeVarint( @@ -343,8 +343,8 @@ class objectProcessor(threading.Thread): def processmsg(self, data): messageProcessingStartTime = time.time() shared.numberOfMessagesProcessed += 1 -# queues.UISignalQueue.put(( -# 'updateNumberOfMessagesProcessed', 'no data')) + queues.UISignalQueue.put(( + 'updateNumberOfMessagesProcessed', 'no data')) readPosition = 20 # bypass the nonce, time, and object type msgVersion, msgVersionLength = decodeVarint(data[readPosition:readPosition + 9]) if msgVersion != 1: @@ -613,8 +613,8 @@ class objectProcessor(threading.Thread): def processbroadcast(self, data): messageProcessingStartTime = time.time() shared.numberOfBroadcastsProcessed += 1 -# queues.UISignalQueue.put(( -# 'updateNumberOfBroadcastsProcessed', 'no data')) + queues.UISignalQueue.put(( + 'updateNumberOfBroadcastsProcessed', 'no data')) inventoryHash = calculateInventoryHash(data) readPosition = 20 # bypass the nonce, time, and object type broadcastVersion, broadcastVersionLength = decodeVarint( diff --git a/src/network/tcp.py b/src/network/tcp.py index 60acb22c..dd813ac6 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -72,7 +72,6 @@ class TCPConnection(BMProto, TLSDispatcher): self.local = False #shared.connectedHostsList[self.destination] = 0 ObjectTracker.__init__(self) - UISignalQueue.put(('updateNetworkStatusTab', 'no data')) self.bm_proto_reset() self.set_state("bm_header", expectBytes=protocol.Header.size) @@ -102,7 +101,7 @@ class TCPConnection(BMProto, TLSDispatcher): if not self.isOutbound and not self.local: shared.clientHasReceivedIncomingConnections = True UISignalQueue.put(('setStatusIcon', 'green')) - UISignalQueue.put(('updateNetworkStatusTab', 'no data')) + UISignalQueue.put(('updateNetworkStatusTab', (self.isOutbound, True, self.destination))) self.antiIntersectionDelay(True) self.fullyEstablished = True if self.isOutbound: @@ -218,6 +217,8 @@ class TCPConnection(BMProto, TLSDispatcher): if self.isOutbound and not self.fullyEstablished: knownnodes.decreaseRating(self.destination) BMProto.handle_close(self, reason) + if self.fullyEstablished: + UISignalQueue.put(('updateNetworkStatusTab', (self.isOutbound, False, self.destination))) class Socks5BMConnection(Socks5Connection, TCPConnection): -- 2.45.1 From 453bcdbb1d29baad80a8fa75e714a3ecd598dcaf Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 08:39:30 +0200 Subject: [PATCH 0942/1102] Typo in newchandialog --- src/bitmessageqt/newchandialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/newchandialog.ui b/src/bitmessageqt/newchandialog.ui index 0abe061c..59dbb2bb 100644 --- a/src/bitmessageqt/newchandialog.ui +++ b/src/bitmessageqt/newchandialog.ui @@ -53,7 +53,7 @@ - Chan passhphrase/name: + Chan passphrase/name: -- 2.45.1 From d44c6c6464863e1cc0dfb87a247a71801cf67e85 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 08:52:44 +0200 Subject: [PATCH 0943/1102] Forget known nodes with bad rating --- src/class_singleCleaner.py | 14 +++++++++++--- src/knownnodes.py | 8 ++++++-- src/network/bmproto.py | 9 ++++++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 2e4140b6..3068910d 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -96,16 +96,24 @@ class singleCleaner(threading.Thread, StoppableThread): # cleanup old nodes now = int(time.time()) - toDelete = [] with knownnodes.knownNodesLock: for stream in knownnodes.knownNodes: - for node in knownnodes.knownNodes[stream].keys(): + keys = knownnodes.knownNodes[stream].keys() + for node in keys: try: + # scrap old nodes if now - knownnodes.knownNodes[stream][node]["lastseen"] > 2419200: # 28 days - shared.needToWriteKownNodesToDisk = True + 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 us write out the knowNodes to disk if there is anything new to write out. if shared.needToWriteKnownNodesToDisk: diff --git a/src/knownnodes.py b/src/knownnodes.py index 86d39cbe..aa080128 100644 --- a/src/knownnodes.py +++ b/src/knownnodes.py @@ -1,4 +1,5 @@ import pickle +import os import threading from bmconfigparser import BMConfigParser @@ -9,11 +10,14 @@ 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(dirName + 'knownnodes.dat', 'wb') as output: + with open(os.path.join(dirName, 'knownnodes.dat'), 'wb') as output: pickle.dump(knownNodes, output) def increaseRating(peer): @@ -37,7 +41,7 @@ def decreaseRating(peer): pass def trimKnownNodes(recAddrStream = 1): - if len(knownNodes[recAddrStream]) < BMConfigParser().get("knownnodes", "maxnodes"): + if len(knownNodes[recAddrStream]) < int(BMConfigParser().get("knownnodes", "maxnodes")): return with knownNodesLock: oldestList = sorted(knownNodes[recAddrStream], key=lambda x: x['lastseen'])[:knownNodesTrimAmount] diff --git a/src/network/bmproto.py b/src/network/bmproto.py index fb0fea30..c245a675 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -378,9 +378,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): continue if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: peer = state.Peer(decodedIP, port) - if peer in knownnodes.knownNodes[stream] and knownnodes.knownNodes[stream][peer]["lastseen"] > seenTime: - continue - if len(knownnodes.knownNodes[stream]) < BMConfigParser().get("knownnodes", "maxnodes"): + 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 -- 2.45.1 From a090eea9b03ad7316e471743e1e61a411172bcc1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 08:56:48 +0200 Subject: [PATCH 0944/1102] Minor multiqueue updates - add task_done to addrthread and invthread - implement totalSize for multiqueue - order in invThread changed --- src/multiqueue.py | 6 ++++-- src/network/addrthread.py | 2 ++ src/network/invthread.py | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/multiqueue.py b/src/multiqueue.py index 30326ee7..62b0fa87 100644 --- a/src/multiqueue.py +++ b/src/multiqueue.py @@ -24,8 +24,7 @@ class MultiQueue(Queue.Queue): # Put a new item in the queue def _put(self, item): #self.queue.append(item) - i = random.randrange(0, self.queueCount) - self.queues[i].append((item)) + self.queues[random.randrange(self.queueCount)].append((item)) # Get an item from the queue def _get(self): @@ -33,3 +32,6 @@ class MultiQueue(Queue.Queue): 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/network/addrthread.py b/src/network/addrthread.py index 8c78894f..5b0ea638 100644 --- a/src/network/addrthread.py +++ b/src/network/addrthread.py @@ -31,4 +31,6 @@ class AddrThread(threading.Thread, StoppableThread): #finish addrQueue.iterate() + for i in range(len(chunk)): + addrQueue.task_done() self.stop.wait(1) diff --git a/src/network/invthread.py b/src/network/invthread.py index cbed7a70..4f26c0fa 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -33,6 +33,7 @@ class InvThread(threading.Thread, StoppableThread): self.dandelionLocalRouteRefresh() try: data = invQueue.get(False) + chunk.append((data[0], data[1])) # locally generated if len(data) == 2: DandelionStems().add(data[1], None, self.dandelionRoutes) @@ -41,7 +42,6 @@ class InvThread(threading.Thread, StoppableThread): else: source = BMConnectionPool().getConnectionByAddr(data[2]) BMConnectionPool().handleReceivedObject(data[0], data[1], source) - chunk.append((data[0], data[1])) except Queue.Empty: break # connection not found, handle it as if generated locally @@ -81,4 +81,6 @@ class InvThread(threading.Thread, StoppableThread): connection.append_write_buf(protocol.CreatePacket('dinv', \ addresses.encodeVarint(len(stems)) + "".join(stems))) invQueue.iterate() + for i in range(len(chunk)): + invQueue.task_done() self.stop.wait(1) -- 2.45.1 From f785558ca556d7b3b3968c326db31d0ee6c06181 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:00:02 +0200 Subject: [PATCH 0945/1102] Don't close UDP socket on bad packet magic --- src/network/bmproto.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index c245a675..3ae7b635 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -74,7 +74,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.set_state("bm_header", length=1) self.bm_proto_reset() logger.debug("Bad magic") - self.handle_close("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 -- 2.45.1 From 7ec3fc7a5ab235c04d1dc09ce514f45bed11cb25 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:00:54 +0200 Subject: [PATCH 0946/1102] Prevent negative DownloadChunk in asyncore --- src/network/advanceddispatcher.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 576eed39..331daf03 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -79,6 +79,8 @@ class AdvancedDispatcher(asyncore.dispatcher): 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 \ -- 2.45.1 From d28a7bfb862e6d9b9716098b27e5ec1d2f482da8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:02:33 +0200 Subject: [PATCH 0947/1102] Asyncore performance optimisation - don't transfer unnecessary amount of bytes from network buffers - slice buffer more efficiently if it results in an empty buffer --- src/network/advanceddispatcher.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 331daf03..97481238 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -36,12 +36,18 @@ class AdvancedDispatcher(asyncore.dispatcher): def slice_write_buf(self, length=0): if length > 0: with self.writeLock: - del self.write_buf[0:length] + 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: - del self.read_buf[0:length] + if length >= len(self.read_buf): + del self.read_buf[:] + else: + del self.read_buf[0:length] def process(self): if not self.connected: @@ -77,7 +83,7 @@ class AdvancedDispatcher(asyncore.dispatcher): if asyncore.maxDownloadRate > 0: self.downloadChunk = asyncore.downloadBucket try: - if self.expectBytes > 0 and not self.fullyEstablished: + if self.expectBytes > 0: self.downloadChunk = min(self.downloadChunk, self.expectBytes - len(self.read_buf)) if self.downloadChunk < 0: self.downloadChunk = 0 -- 2.45.1 From 01d46c30e49dcc889105885de37ca0bc8a5d7187 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:03:36 +0200 Subject: [PATCH 0948/1102] Remove obsolete imports --- src/shutdown.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/shutdown.py b/src/shutdown.py index a066104c..278759e5 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -3,8 +3,6 @@ import Queue import threading import time -from class_outgoingSynSender import outgoingSynSender -from class_sendDataThread import sendDataThread from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure @@ -51,9 +49,7 @@ def doCleanShutdown(): time.sleep(.25) for thread in threading.enumerate(): - if isinstance(thread, sendDataThread): - thread.sendDataThreadQueue.put((0, 'shutdown','no data')) - if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): + if thread is not threading.currentThread() and isinstance(thread, StoppableThread): logger.debug("Waiting for thread %s", thread.name) thread.join() -- 2.45.1 From 391d40d78bd980db75caecb156496f7ce045c08a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:08:05 +0200 Subject: [PATCH 0949/1102] Socket closing changes - closing reason moved to a variable - actual closing now done in asyncore thread instead of receivedata thread --- src/network/advanceddispatcher.py | 2 +- src/network/bmproto.py | 13 +++++++------ src/network/connectionpool.py | 5 ++++- src/network/socks4a.py | 3 ++- src/network/socks5.py | 3 ++- src/network/tcp.py | 4 ++-- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 97481238..2115c454 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -126,4 +126,4 @@ class AdvancedDispatcher(asyncore.dispatcher): with self.writeLock: self.write_buf = bytearray() self.state = "close" - asyncore.dispatcher.close(self) + self.close() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 3ae7b635..d66d8c4b 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -1,9 +1,9 @@ import base64 import hashlib -import time import random import socket import struct +import time from bmconfigparser import BMConfigParser from debug import logger @@ -122,7 +122,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): else: #print "Skipping command %s due to invalid data" % (self.command) logger.debug("Closing due to invalid command %s", self.command) - self.handle_close("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) @@ -538,13 +539,13 @@ class BMProto(AdvancedDispatcher, ObjectTracker): except KeyError: pass - def handle_close(self, reason=None): + def handle_close(self): self.set_state("close") - if reason is None: + 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") - else: - logger.debug("%s:%i: closing, %s", self.destination.host, self.destination.port, reason) AdvancedDispatcher.handle_close(self) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 7ae8afd9..1e50eb1c 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -247,8 +247,11 @@ class BMConnectionPool(object): if i.fullyEstablished: i.append_write_buf(protocol.CreatePacket('ping')) else: - i.handle_close("Timeout (%is)" % (time.time() - i.lastTx)) + i.close_reason = "Timeout (%is)" % (time.time() - i.lastTx) + i.handle_close() for i in self.inboundConnections.values() + self.outboundConnections.values() + self.listeningSockets.values() + self.udpSockets.values(): + if i.state == "close": + i.handle_close() if not (i.accepting or i.connecting or i.connected): reaper.append(i) for i in reaper: diff --git a/src/network/socks4a.py b/src/network/socks4a.py index d6cf2ad8..978ede04 100644 --- a/src/network/socks4a.py +++ b/src/network/socks4a.py @@ -86,7 +86,8 @@ class Socks4aConnection(Socks4a): try: return Socks4a.state_pre_connect(self) except Socks4aError as e: - self.handle_close(e.message) + self.close_reason = e.message + self.set_state("close") class Socks4aResolver(Socks4a): diff --git a/src/network/socks5.py b/src/network/socks5.py index e57e7c6a..52050ec9 100644 --- a/src/network/socks5.py +++ b/src/network/socks5.py @@ -154,7 +154,8 @@ class Socks5Connection(Socks5): try: return Socks5.state_pre_connect(self) except Socks5Error as e: - self.handle_close(e.message) + self.close_reason = e.message + self.set_state("close") class Socks5Resolver(Socks5): diff --git a/src/network/tcp.py b/src/network/tcp.py index dd813ac6..ab282fb4 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -213,12 +213,12 @@ class TCPConnection(BMProto, TLSDispatcher): def handle_write(self): TLSDispatcher.handle_write(self) - def handle_close(self, reason=None): + def handle_close(self): if self.isOutbound and not self.fullyEstablished: knownnodes.decreaseRating(self.destination) - BMProto.handle_close(self, reason) if self.fullyEstablished: UISignalQueue.put(('updateNetworkStatusTab', (self.isOutbound, False, self.destination))) + BMProto.handle_close(self) class Socks5BMConnection(Socks5Connection, TCPConnection): -- 2.45.1 From 7b470d4b6665da8d9cdbf7038611ba817adcacdc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:11:34 +0200 Subject: [PATCH 0950/1102] handle shutdown in receivequeuethread - sometimes during shutdown, the receivequeuethread would get stuck --- src/network/advanceddispatcher.py | 8 +++++--- src/network/receivequeuethread.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 2115c454..35121d1c 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -5,6 +5,7 @@ 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 = 2097152 # 2MB @@ -50,16 +51,17 @@ class AdvancedDispatcher(asyncore.dispatcher): del self.read_buf[0:length] def process(self): - if not self.connected: - return False - while True: + 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 getattr(self, "state_" + str(self.state))() is False: break except AttributeError: + logger.error("Unknown state %s", self.state) raise except BusyError: return False diff --git a/src/network/receivequeuethread.py b/src/network/receivequeuethread.py index a617e16e..5399b972 100644 --- a/src/network/receivequeuethread.py +++ b/src/network/receivequeuethread.py @@ -30,7 +30,7 @@ class ReceiveQueueThread(threading.Thread, StoppableThread): except Queue.Empty: continue - if self._stopped: + if self._stopped or state.shutdown: break # cycle as long as there is data -- 2.45.1 From ab458531e8db577941d5053d6bb0c700e50d60ed Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 19 Oct 2017 09:16:29 +0200 Subject: [PATCH 0951/1102] Changes in SOCKS and onion handling in connectionchooser - onion addresses have a priority of 1 when SOCKS is on - don't connect to private/loopback addresses when SOCKS is on --- src/network/connectionchooser.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/network/connectionchooser.py b/src/network/connectionchooser.py index ee2a8b40..819dfeb1 100644 --- a/src/network/connectionchooser.py +++ b/src/network/connectionchooser.py @@ -3,6 +3,7 @@ import random from bmconfigparser import BMConfigParser import knownnodes +import protocol from queues import portCheckerQueue import state @@ -38,8 +39,15 @@ def chooseConnection(stream): except TypeError: print "Error in %s" % (peer) rating = 0 - if haveOnion and peer.host.endswith('.onion') and rating > 0: - rating *= 10 + 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: -- 2.45.1 From 364642404a98a8d842b0554c76253a011a6b25bc Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 19 Oct 2017 12:26:51 +0200 Subject: [PATCH 0952/1102] Auto-updated language ja from transifex --- src/translations/bitmessage_ja.qm | Bin 66995 -> 66960 bytes src/translations/bitmessage_ja.ts | 306 +++++++++++++++--------------- 2 files changed, 158 insertions(+), 148 deletions(-) diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 4a639cbf8891e2567c3d6cf1a334c605391371df..3756d6d34e241eba949ddf23e8c87202d607df8c 100644 GIT binary patch delta 2987 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 diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index f62493ba..90e49dc2 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -58,12 +58,12 @@ 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 を含む) を次のように記入してください: @@ -283,7 +283,7 @@ Please type the desired email address (including @mailchuck.com) below: %1は古いバージョン1のアドレスです。バージョン1のアドレスはサポートが終了しています。すぐに削除しますか? - + Waiting for their encryption key. Will request it again soon. 暗号鍵を待っています。 すぐにもう一度リクエストします。 @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. キューに入りました。 - + Message sent. Waiting for acknowledgement. Sent at %1 メッセージを送信しました。 確認応答を待っています。 %1 で送信されました - + Message sent. Sent at %1 メッセージは送信されました。送信先: %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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を表示 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: 送る - + Subscribe 購読 - + Channel チャンネル @@ -378,66 +378,66 @@ Please type the desired email address (including @mailchuck.com) below: 終了 - + 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 のどちらかにする必要があります。 @@ -507,22 +507,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -533,17 +533,17 @@ It is important that you back up this file. Would you like to open the file now? コンピュータがメッセージを送信するために必要な処理が増えます。 多くの場合 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 として登録を送信しています。送信を再試行する前に、登録が処理されるまでお待ちください。 @@ -588,57 +588,57 @@ It is important that you back up this file. Would you like to open the file now? - + 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 のバージョン番号は処理できません。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. 宛先が指定されていません。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 - + New Message 新規メッセージ @@ -648,7 +648,7 @@ It is important that you back up this file. Would you like to open the file now? - + Sending email gateway registration request メールゲートウェイの登録リクエストを送信しています @@ -663,142 +663,142 @@ It is important that you back up this file. Would you like to open the file now? 入力されたアドレスは不正です。無視されました。 - + 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回追加することはできません。 必要に応じて、既存の名前を変更してください。 - + 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? @@ -807,7 +807,7 @@ 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? @@ -816,92 +816,92 @@ 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 (設定で変更できます)。 @@ -1111,47 +1111,47 @@ Are you sure you want to delete the channel? 新しい項目を追加 - + 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% @@ -1166,12 +1166,12 @@ Are you sure you want to delete the channel? %n 日 - + Shutting down PyBitmessage... %1% PyBitmessageをシャットダウンしています... %1% - + Sent 送信済 @@ -1275,7 +1275,7 @@ Receiver's required difficulty: %1 and %2 問題: あなた自身またはチャンネルにメッセージを送信しようとしていますが、暗号鍵がkeys.datファイルに見つかりませんでした。 メッセージを暗号化できませんでした。 %1 - + Doing work necessary to send message. メッセージの送信に必要な処理を行っています。 @@ -1285,7 +1285,7 @@ Receiver's required difficulty: %1 and %2 メッセージを送信しました。 確認応答を待っています。 %1 で送信しました - + Doing work necessary to request encryption key. 暗号鍵のリクエストに必要な処理を行っています。 @@ -1315,32 +1315,32 @@ Receiver's required difficulty: %1 and %2 すべてのメッセージを既読にする - + Are you sure you would like to mark all messages read? すべてのメッセージを既読にしてもよろしいですか? - + Doing work necessary to send broadcast. 配信に必要な処理を行っています。 - + Proof of work pending PoW(証明)を待っています - + %n object(s) pending proof of work %n オブジェクトが証明待ち (PoW) - + %n object(s) waiting to be distributed %n オブジェクトが配布待ち - + Wait until these tasks finish? これらのタスクが完了するまで待ちますか? @@ -1405,7 +1405,7 @@ Receiver's required difficulty: %1 and %2 GPUが正しく求められないため、OpenCLが無効になりました。 開発者に報告してください。 - + Set notification sound... 通知音を設定... @@ -1430,92 +1430,102 @@ Receiver's required difficulty: %1 and %2 チャンネルにはお勧めしません - + + 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? すでにこのアドレス帳エントリの通知音を設定しています。 上書きしてもよろしいですか? @@ -1901,27 +1911,27 @@ The 'Random Number' option is selected by default but deterministic ad - + 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 @@ -1941,27 +1951,27 @@ The 'Random Number' option is selected by default but deterministic ad ネットワークの状態 - + 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 件の公開鍵を処理しました。 @@ -2065,8 +2075,8 @@ The 'Random Number' option is selected by default but deterministic ad - Chan passhphrase/name: - チャンネルのパスフレーズ/名前: + Chan passphrase/name: + @@ -2087,17 +2097,17 @@ The 'Random Number' option is selected by default but deterministic ad newchandialog - + Successfully created / joined chan %1 チャンネル %1 を正常に作成 / 参加しました - + Chan creation / joining failed チャンネルの作成 / 参加に失敗しました - + Chan creation / joining cancelled チャンネルの作成 / 参加をキャンセルしました -- 2.45.1 From 9be36f2d78f6ae46562a393c2fd9097a5bb08f3a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 17 Oct 2017 01:30:01 +0300 Subject: [PATCH 0953/1102] Use unicode instead of str for MessagingMenu --- src/plugins/indicator_libmessaging.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/indicator_libmessaging.py b/src/plugins/indicator_libmessaging.py index 96ab1516..36178663 100644 --- a/src/plugins/indicator_libmessaging.py +++ b/src/plugins/indicator_libmessaging.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import gi -gi.require_version('MessagingMenu', '1.0') +gi.require_version('MessagingMenu', '1.0') # noqa:E402 from gi.repository import MessagingMenu from pybitmessage.bitmessageqt.utils import str_broadcast_subscribers @@ -19,9 +19,9 @@ class IndicatorLibmessaging(object): return self._menu = { - 'send': str(_translate('MainWindow', 'Send')), - 'messages': str(_translate('MainWindow', 'Messages')), - 'subscriptions': str(_translate('MainWindow', 'Subscriptions')) + 'send': unicode(_translate('MainWindow', 'Send')), + 'messages': unicode(_translate('MainWindow', 'Messages')), + 'subscriptions': unicode(_translate('MainWindow', 'Subscriptions')) } self.new_message_item = self.new_broadcast_item = None -- 2.45.1 From 8fcdf51e576e899f3a63abad9c15ef435a72640a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 18 Oct 2017 22:03:06 +0300 Subject: [PATCH 0954/1102] One more unicode related exception - when editing a contact label --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4d2c0bad..4cda426d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3885,7 +3885,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderMessagelistToLabels() completerList = self.ui.lineEditTo.completer().model().stringList() for i in range(len(completerList)): - if str(completerList[i]).endswith(" <" + item.address + ">"): + if unicode(completerList[i]).endswith(" <" + item.address + ">"): completerList[i] = item.label + " <" + item.address + ">" self.ui.lineEditTo.completer().model().setStringList(completerList) -- 2.45.1 From 393769307d0ffbd1e02bfd2893927cba0e20c191 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 19 Oct 2017 21:17:30 +0300 Subject: [PATCH 0955/1102] Slightly redrawn the scalable icon --- desktop/can-icon.svg | 176 +++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 105 deletions(-) diff --git a/desktop/can-icon.svg b/desktop/can-icon.svg index b4c2bd89..7c854e34 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="744.09448819" - height="1052.3622047" + width="793.70081" + height="1122.5197" id="svg2" version="1.1" - inkscape:version="0.48.4 r9939" + inkscape:version="0.92.1 r" sodipodi:docname="can-icon.svg"> @@ -45,7 +45,7 @@ image/svg+xml - + @@ -55,129 +55,95 @@ id="layer1"> - - - - - - - - - - - + transform="translate(10.559462,156.88343)"> - + sodipodi:nodetypes="ccccc" + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + d="M 395.54691,28.063323 112.5256,508.60245" + style="fill:#808080;stroke:#000000;stroke-width:1.64679658px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.11949684" + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> - + d="M 193.26809,521.672 466.89638,43.16174" + style="fill:none;stroke:#000000;stroke-width:1.65778315px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.06918239" + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> - - + d="M 283.66518,559.54595 549.75376,77.722668" + style="fill:#b3b3b3;stroke:#000000;stroke-width:1.65072334px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.07547171" + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + d="M 442.34039,696.99151 701.70079,210.05539" + style="fill:none;stroke:#000000;stroke-width:1.65072334px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.21383649" + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + inkscape:export-xdpi="4.57552" + inkscape:export-ydpi="4.57552" /> + + + -- 2.45.1 From 15857e6551862a119c699a68524ab2f9eed1ca99 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 20 Oct 2017 01:07:30 +0200 Subject: [PATCH 0956/1102] Asyncore updates - reduce buffer size to 128kB (was 2MB) - IP address handling use str instead of buffer (the latter, even though it should be faster, breaks the code on Windows) - read up to full buffer after fully established (otherwise downloads become too slow due to the loop time). This reverts a change made in d28a7bfb862e6d9b9716098b27e5ec1d2f482da8 --- src/network/advanceddispatcher.py | 4 ++-- src/network/bmproto.py | 8 ++++---- src/network/udp.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 35121d1c..50ddf44b 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -8,7 +8,7 @@ from helper_threading import BusyError, nonBlocking import state class AdvancedDispatcher(asyncore.dispatcher): - _buf_len = 2097152 # 2MB + _buf_len = 131072 # 128kB def __init__(self, sock=None): if not hasattr(self, '_map'): @@ -85,7 +85,7 @@ class AdvancedDispatcher(asyncore.dispatcher): if asyncore.maxDownloadRate > 0: self.downloadChunk = asyncore.downloadBucket try: - if self.expectBytes > 0: + 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 diff --git a/src/network/bmproto.py b/src/network/bmproto.py index d66d8c4b..445af9a9 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -144,16 +144,16 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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, buffer(host, 12, 4)) + 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, buffer(host)) + 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, buffer(host, 12, 4)) + host = socket.inet_ntop(socket.AF_INET, str(host[12:16])) return Node(services, host, port) @@ -376,7 +376,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): addresses = self._decode_addr() for i in addresses: seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(buffer(ip)) + decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if decodedIP is not False and seenTime > time.time() - BMProto.addressAlive: diff --git a/src/network/udp.py b/src/network/udp.py index 3d238a5e..e7f6974d 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -89,7 +89,7 @@ class UDPSocket(BMProto): remoteport = False for i in addresses: seenTime, stream, services, ip, port = i - decodedIP = protocol.checkIPAddress(buffer(ip)) + decodedIP = protocol.checkIPAddress(str(ip)) if stream not in state.streamsInWhichIAmParticipating: continue if seenTime < time.time() - BMProto.maxTimeOffset or seenTime > time.time() + BMProto.maxTimeOffset: -- 2.45.1 From 2d34e7364899401bbb63668670ce83bbeee621d4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 20 Oct 2017 01:21:49 +0200 Subject: [PATCH 0957/1102] Dandelion updates - fixes and feedback from @gfanti and @amiller - addresses #1049 - minor refactoring - two global child stems with fixed mapping between parent and child stem - allow child stems which don't support dandelion - only allow outbound connections to be stems - adjust stems if opening/closing outbound connections (should allow partial dandelion functionality when not enough outbound connections are available instead of breaking) --- src/bitmessagemain.py | 4 +- src/class_singleCleaner.py | 6 +- src/network/bmobject.py | 4 +- src/network/bmproto.py | 12 ++-- src/network/connectionpool.py | 18 +----- src/network/dandelion.py | 102 ++++++++++++++++++++++++++++------ src/network/invthread.py | 30 +++++----- src/network/objectracker.py | 6 +- src/network/tcp.py | 8 ++- 9 files changed, 122 insertions(+), 68 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 06d89ba8..83a41919 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -54,7 +54,7 @@ from bmconfigparser import BMConfigParser from inventory import Inventory from network.connectionpool import BMConnectionPool -from network.dandelion import DandelionStems +from network.dandelion import Dandelion from network.networkthread import BMNetworkThread from network.receivequeuethread import ReceiveQueueThread from network.announcethread import AnnounceThread @@ -251,7 +251,7 @@ class Main: sqlLookup.start() Inventory() # init - DandelionStems() # init, needs to be early because other thread may access it early + Dandelion() # init, needs to be early because other thread may access it early # SMTP delivery thread if daemon and BMConfigParser().safeGet("bitmessagesettings", "smtpdeliver", '') != '': diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 3068910d..f3125806 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -10,7 +10,7 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from network.connectionpool import BMConnectionPool -from network.dandelion import DandelionStems +from network.dandelion import Dandelion from debug import logger import knownnodes import queues @@ -136,9 +136,7 @@ class singleCleaner(threading.Thread, StoppableThread): for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): connection.clean() # dandelion fluff trigger by expiration - for h, t in DandelionStems().timeouts: - if time.time() > t: - DandelionStems().remove(h) + Dandelion().expire() # discovery tracking exp = time.time() - singleCleaner.expireDiscoveredPeers diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 4cde0c4f..f4c883ca 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -4,7 +4,7 @@ import time from addresses import calculateInventoryHash from debug import logger from inventory import Inventory -from network.dandelion import DandelionStems +from network.dandelion import Dandelion import protocol import state @@ -68,7 +68,7 @@ class BMObject(object): def checkAlreadyHave(self): # if it's a stem duplicate, pretend we don't have it - if self.inventoryHash in DandelionStems().stem: + if self.inventoryHash in Dandelion().hashMap: return if self.inventoryHash in Inventory(): raise BMObjectAlreadyHaveError() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 445af9a9..2469d6e4 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -10,7 +10,7 @@ from debug import logger from inventory import Inventory import knownnodes from network.advanceddispatcher import AdvancedDispatcher -from network.dandelion import DandelionStems, REASSIGN_INTERVAL +from network.dandelion import Dandelion from network.bmobject import BMObject, BMObjectInsufficientPOWError, BMObjectInvalidDataError, \ BMObjectExpiredError, BMObjectUnwantedStreamError, BMObjectInvalidError, BMObjectAlreadyHaveError import network.connectionpool @@ -279,8 +279,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): #TODO make this more asynchronous random.shuffle(items) for i in map(str, items): - if i in DandelionStems().stem and \ - self != DandelionStems().stem[i]: + if i in Dandelion().hashMap and \ + self != Dandelion().hashMap[i]: self.antiIntersectionDelay() logger.info('%s asked for a stem object we didn\'t offer to it.', self.destination) break @@ -325,12 +325,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): if BMConfigParser().safeGetBoolean("network", "dandelion") == 0: return True - if self.dandelionRefresh < time.time(): - self.dandelionRoutes = BMConnectionPool.dandelionRouteSelector(self) - self.dandelionRefresh = time.time() + REASSIGN_INTERVAL - for i in map(str, items): - DandelionStems().add(i, self, self.dandelionRoutes) + Dandelion().addHash(i, self) self.handleReceivedInventory(i) return True diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 1e50eb1c..04336b00 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -9,6 +9,7 @@ from debug import logger import helper_bootstrap from network.proxy import Proxy import network.bmproto +from network.dandelion import Dandelion import network.tcp import network.udp from network.connectionchooser import chooseConnection @@ -51,23 +52,10 @@ class BMConnectionPool(object): except KeyError: pass - def dandelionRouteSelector(self, node): + def reRandomiseDandelionStems(self): # Choose 2 peers randomly # TODO: handle streams - peers = [] - connections = self.outboundConnections.values() - random.shuffle(connections) - for i in connections: - if i == node: - continue - try: - if i.services | protocol.NODE_DANDELION: - peers.append(i) - if len(peers) == 2: - break - except AttributeError: - continue - return peers + Dandelion().reRandomiseStems(self.outboundConnections.values()) def connectToStream(self, streamNumber): self.streams.append(streamNumber) diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 840cc909..a7ef4083 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,4 +1,4 @@ -from random import choice +from random import choice, shuffle from threading import RLock from time import time @@ -8,31 +8,101 @@ from singleton import Singleton # randomise routes after 600 seconds REASSIGN_INTERVAL = 600 FLUFF_TRIGGER_TIMEOUT = 300 +MAX_STEMS = 2 @Singleton -class DandelionStems(): +class Dandelion(): def __init__(self): - self.stem = {} - self.source = {} - self.timeouts = {} + self.stem = [] + self.nodeMap = {} + self.hashMap = {} + self.timeout = {} + self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() - def add(self, hashId, source, stems): + def addHash(self, hashId, source): if BMConfigParser().safeGetInt('network', 'dandelion') == 0: return with self.lock: - try: - self.stem[hashId] = choice(stems) - except IndexError: - self.stem = None - self.source[hashId] = source - self.timeouts[hashId] = time() + self.hashMap[hashId] = self.getNodeStem(source) + self.timeout[hashId] = time() + FLUFF_TRIGGER_TIMEOUT - def remove(self, hashId): + def removeHash(self, hashId): with self.lock: try: - del self.stem[hashId] - del self.source[hashId] - del self.timeouts[hashId] + del self.hashMap[hashId] except KeyError: pass + try: + del self.timeout[hashId] + except KeyError: + pass + + 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) + # active mappings pointing nowhere + for k in (k for k, v in self.nodeMap.iteritems() if self.nodeMap[k] is None): + self.nodeMap[k] = connection + for k in (k for k, v in self.hashMap.iteritems() if self.hashMap[k] is None): + self.hashMap[k] = connection + + 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 self.nodeMap[k] == connection): + self.nodeMap[k] = None + for k in (k for k, v in self.hashMap.iteritems() if self.hashMap[k] == connection): + self.hashMap[k] = None + if len(self.stem) < MAX_STEMS: + self.stem.append(connection) + + 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() + return self.nodeMap[node] + + def getHashStem(self, hashId): + with self.lock: + return self.hashMap[hashId] + + def expire(self): + with self.lock: + deadline = time() + toDelete = [k for k, v in self.hashMap.iteritems() if self.timeout[k] < deadline] + for k in toDelete: + del self.timeout[k] + del self.hashMap[k] + + def reRandomiseStems(self, connections): + shuffle(connections) + with self.lock: + # random two connections + self.stem = connections[:MAX_STEMS] + self.nodeMap = {} + # hashMap stays to cater for pending stems + self.refresh = time() + REASSIGN_INTERVAL diff --git a/src/network/invthread.py b/src/network/invthread.py index 4f26c0fa..5852df0b 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -7,7 +7,7 @@ import addresses from bmconfigparser import BMConfigParser from helper_threading import StoppableThread from network.connectionpool import BMConnectionPool -from network.dandelion import DandelionStems, REASSIGN_INTERVAL +from network.dandelion import Dandelion from queues import invQueue import protocol import state @@ -17,26 +17,17 @@ class InvThread(threading.Thread, StoppableThread): threading.Thread.__init__(self, name="InvBroadcaster") self.initStop() self.name = "InvBroadcaster" - # for locally generated objects - self.dandelionRoutes = [] - self.dandelionRefresh = 0 - - def dandelionLocalRouteRefresh(self): - if self.dandelionRefresh < time(): - self.dandelionRoutes = BMConnectionPool().dandelionRouteSelector(None) - self.dandelionRefresh = time() + REASSIGN_INTERVAL def run(self): while not state.shutdown: chunk = [] while True: - self.dandelionLocalRouteRefresh() try: data = invQueue.get(False) chunk.append((data[0], data[1])) # locally generated if len(data) == 2: - DandelionStems().add(data[1], None, self.dandelionRoutes) + Dandelion().addHash(data[1], None) BMConnectionPool().handleReceivedObject(data[0], data[1]) # came over the network else: @@ -61,17 +52,19 @@ class InvThread(threading.Thread, StoppableThread): del connection.objectsNewToThem[inv[1]] except KeyError: continue - if inv[1] in DandelionStems().stem: - if connection == DandelionStems().stem[inv[1]]: + try: + if connection == Dandelion().hashMap[inv[1]]: # Fluff trigger by RNG # auto-ignore if config set to 0, i.e. dandelion is off - if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion"): + # send a normal inv if stem node doesn't support dandelion + if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion") and \ + connection.services | protocol.NODE_DANDELION > 0: stems.append(inv[1]) else: fluffs.append(inv[1]) - continue - else: + except KeyError: fluffs.append(inv[1]) + if fluffs: shuffle(fluffs) connection.append_write_buf(protocol.CreatePacket('inv', \ @@ -80,7 +73,12 @@ class InvThread(threading.Thread, StoppableThread): 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(): + BMConnectionPool().reRandomiseDandelionStems() + self.stop.wait(1) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 7149f4b1..62016d75 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -4,7 +4,7 @@ from threading import RLock from debug import logger from inventory import Inventory -from network.dandelion import DandelionStems +from network.dandelion import Dandelion haveBloom = False @@ -84,9 +84,9 @@ class ObjectTracker(object): if hashId not in Inventory(): with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True - elif hashId in DandelionStems().stem: + elif hashId in Dandelion().hashMap: # Fluff trigger by cycle detection - DandelionStems().remove(hashId) + Dandelion().removeHash(hashId) with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True diff --git a/src/network/tcp.py b/src/network/tcp.py index ab282fb4..70e22e08 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -18,7 +18,7 @@ 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 DandelionStems +from network.dandelion import Dandelion from network.node import Node import network.asyncore_pollchoose as asyncore from network.proxy import Proxy, ProxyError, GeneralProxyError @@ -106,6 +106,8 @@ class TCPConnection(BMProto, TLSDispatcher): self.fullyEstablished = True if self.isOutbound: knownnodes.increaseRating(self.destination) + if self.isOutbound: + Dandelion().maybeAddStem(self) self.sendAddr() self.sendBigInv() @@ -166,7 +168,7 @@ class TCPConnection(BMProto, TLSDispatcher): with self.objectsNewToThemLock: for objHash in Inventory().unexpired_hashes_by_stream(stream): # don't advertise stem objects on bigInv - if objHash in DandelionStems().stem: + if objHash in Dandelion().hashMap: continue bigInvList[objHash] = 0 self.objectsNewToThem[objHash] = time.time() @@ -218,6 +220,8 @@ class TCPConnection(BMProto, TLSDispatcher): 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) -- 2.45.1 From a746ba9da7ea51ab6fd308ee502d53307720efee Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 20 Oct 2017 13:21:39 +0200 Subject: [PATCH 0958/1102] Stop downloading objects with insufficient PoW - object with insufficient PoW weren't correctly detected and it tried to download them over and over again --- src/network/bmproto.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 2469d6e4..a3f7d620 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -340,11 +340,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): logger.info('The payload length of this object is too large (%s bytes). Ignoring it.' % len(self.payload) - self.payloadOffset) raise BMProtoExcessiveDataError() - self.object.checkProofOfWorkSufficient() try: + self.object.checkProofOfWorkSufficient() self.object.checkEOLSanity() self.object.checkAlreadyHave() - except (BMObjectExpiredError, BMObjectAlreadyHaveError) as e: + except (BMObjectExpiredError, BMObjectAlreadyHaveError, BMObjectInsufficientPOWError) as e: BMProto.stopDownloadingObject(self.object.inventoryHash) raise e try: -- 2.45.1 From 6655e99aa35bb28b72206675d9e895f08bb7d9e4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 20 Oct 2017 23:11:33 +0200 Subject: [PATCH 0959/1102] Pending download stats optimisations - tracks separately a global list for a faster sum. Needs slightly more memory --- src/network/bmproto.py | 4 ++++ src/network/objectracker.py | 2 ++ src/network/stats.py | 24 +++++++++++++----------- src/state.py | 3 +++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index a3f7d620..5f689307 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -534,6 +534,10 @@ class BMProto(AdvancedDispatcher, ObjectTracker): del connection.objectsNewToThem[hashId] except KeyError: pass + try: + del state.missingObjects[hashId] + except KeyError: + pass def handle_close(self): self.set_state("close") diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 62016d75..bfb75174 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -5,6 +5,7 @@ from threading import RLock from debug import logger from inventory import Inventory from network.dandelion import Dandelion +from state import missingObjects haveBloom = False @@ -82,6 +83,7 @@ class ObjectTracker(object): except KeyError: pass if hashId not in Inventory(): + missingObjects[hashId] = None with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True elif hashId in Dandelion().hashMap: diff --git a/src/network/stats.py b/src/network/stats.py index ade56ac0..80925f7c 100644 --- a/src/network/stats.py +++ b/src/network/stats.py @@ -2,6 +2,7 @@ import time from network.connectionpool import BMConnectionPool import asyncore_pollchoose as asyncore +from state import missingObjects lastReceivedTimestamp = time.time() lastReceivedBytes = 0 @@ -50,19 +51,20 @@ def downloadSpeed(): return currentReceivedSpeed def pendingDownload(): - tmp = {} - for connection in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): - for k in connection.objectsNewToMe.keys(): - tmp[k] = True - return len(tmp) + 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 + #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/state.py b/src/state.py index c9cb3d1c..32433e2d 100644 --- a/src/state.py +++ b/src/state.py @@ -43,6 +43,9 @@ trustedPeer = None discoveredPeers = {} +# tracking pending downloads globally, for stats +missingObjects = {} + Peer = collections.namedtuple('Peer', ['host', 'port']) def resetNetworkProtocolAvailability(): -- 2.45.1 From b025624f2a9111710e7ecbba3be020af49b317ea Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 20 Oct 2017 23:21:25 +0200 Subject: [PATCH 0960/1102] missingObjects fix - didn't notice valid objects arriving (only invalid) --- src/network/bmproto.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 5f689307..9bc60af7 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -359,6 +359,11 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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 Inventory()[self.object.inventoryHash] = ( self.object.objectType, self.object.streamNumber, buffer(self.payload[objectOffset:]), self.object.expiresTime, buffer(self.object.tag)) -- 2.45.1 From 8b06fdf648842165c1b29fdc49eaa62411aa63c3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 21 Oct 2017 21:55:12 +0200 Subject: [PATCH 0961/1102] checkdeps OS version handler fix - it didn't work if OS version didn't contain a quote --- checkdeps.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checkdeps.py b/checkdeps.py index 65f8a787..05f00944 100644 --- a/checkdeps.py +++ b/checkdeps.py @@ -111,7 +111,7 @@ def detectOSRelease(): detectOS.result = None if line.startswith("VERSION_ID="): try: - version = float(line.split("\"")[1]) + version = float(line.split("=")[1].replace("\"", "")) except ValueError: pass if detectOS.result == "Ubuntu" and version < 14: -- 2.45.1 From 75a6f605c1a4c903ec0e3f212dff3c6d54d53c9a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 22 Oct 2017 11:32:37 +0200 Subject: [PATCH 0962/1102] Download optimisation - more accurate tracking - randomise download order - longer cycle --- src/network/downloadthread.py | 25 ++++++++++++++++--------- src/network/objectracker.py | 3 ++- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 98b6df05..7cbe11ad 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -9,9 +9,10 @@ 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): - maxPending = 200 + minPending = 200 requestChunk = 1000 requestTimeout = 60 cleanInterval = 60 @@ -22,13 +23,18 @@ class DownloadThread(threading.Thread, StoppableThread): self.initStop() self.name = "Downloader" logger.info("init download thread") - self.pending = {} self.lastCleaned = time.time() def cleanPending(self): deadline = time.time() - DownloadThread.requestExpires - self.pending = {k: v for k, v in self.pending.iteritems() if v >= deadline} - self.lastCleaned = time.time() + 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: @@ -41,11 +47,12 @@ class DownloadThread(threading.Thread, StoppableThread): timedOut = now - DownloadThread.requestTimeout # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: - downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in self.pending and self.pending[k] > timedOut))) - if downloadPending >= DownloadThread.maxPending: + downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut))) + if downloadPending >= DownloadThread.minPending: continue # keys with True values in the dict - request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in self.pending or self.pending[k] < timedOut)) + request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in missingObjects or missingObjects[k] < timedOut)) + random.shuffle(request) if not request: continue if len(request) > DownloadThread.requestChunk - downloadPending: @@ -53,7 +60,7 @@ class DownloadThread(threading.Thread, StoppableThread): # mark them as pending for k in request: i.objectsNewToMe[k] = False - self.pending[k] = now + missingObjects[k] = now payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) @@ -65,4 +72,4 @@ class DownloadThread(threading.Thread, StoppableThread): if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() if not requested: - self.stop.wait(1) + self.stop.wait(5) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index bfb75174..a86ec23f 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -83,7 +83,8 @@ class ObjectTracker(object): except KeyError: pass if hashId not in Inventory(): - missingObjects[hashId] = None + if hashId not in missingObjects: + missingObjects[hashId] = time.time() with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True elif hashId in Dandelion().hashMap: -- 2.45.1 From 4b40d4bce1a9a23abda072d502a5e2adc89e7498 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 22 Oct 2017 15:28:30 +0200 Subject: [PATCH 0963/1102] Download thread error handling --- src/network/downloadthread.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 7cbe11ad..414aacd2 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -47,11 +47,17 @@ class DownloadThread(threading.Thread, StoppableThread): timedOut = now - DownloadThread.requestTimeout # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: - downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut))) + try: + downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut))) + except KeyError: + continue if downloadPending >= DownloadThread.minPending: continue # keys with True values in the dict - request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in missingObjects or missingObjects[k] < timedOut)) + try: + request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in missingObjects or missingObjects[k] < timedOut)) + except KeyError: + continue random.shuffle(request) if not request: continue -- 2.45.1 From e17d33cd75f3c5110f4e66aa9352533ab2eadc37 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 24 Oct 2017 14:02:15 +0300 Subject: [PATCH 0964/1102] Respect user selected sort order on "Network Status" tab --- src/bitmessageqt/networkstatus.py | 9 +++++++-- src/bitmessageqt/networkstatus.ui | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index e9073cb8..67284495 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -13,12 +13,18 @@ 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) - self.tableWidgetConnectionCount.horizontalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents) + 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( @@ -135,7 +141,6 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): break self.tableWidgetConnectionCount.setUpdatesEnabled(True) self.tableWidgetConnectionCount.setSortingEnabled(True) - self.tableWidgetConnectionCount.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) 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. diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui index f05e5f62..e0c01b57 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -97,6 +97,9 @@ QAbstractItemView::NoSelection + + true + true -- 2.45.1 From 8b7b91b23d3fbd6b9f264f727988852ea256e8d8 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 31 Oct 2017 09:40:18 +0100 Subject: [PATCH 0965/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 98426 -> 98493 bytes src/translations/bitmessage_de.ts | 340 +++++++++++++++--------------- 2 files changed, 175 insertions(+), 165 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 63ccd5254141b427e57228bcf0ec9e72a1c935d7..c04e1950848d63fcd660fbaab722484281145989 100644 GIT binary patch delta 3396 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 SiD)}(N_6z`C2s7~fd2!gn)eL= delta 3340 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 U8WI>`F*h(OD&%N|Gy6F7{}wCvM*si- diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index df53838a..1dd83139 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -58,12 +58,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -289,7 +289,7 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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. @@ -299,17 +299,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,47 +319,47 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -369,12 +369,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Senden - + Subscribe Abonnieren - + Channel Chan @@ -384,12 +384,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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. @@ -398,17 +398,17 @@ It is important that you back up this file. 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.) @@ -418,37 +418,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di (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. @@ -518,22 +518,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -541,17 +541,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -596,57 +596,57 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -656,7 +656,7 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + Sending email gateway registration request Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. @@ -671,142 +671,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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 E-Mail Schnittestellen-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mail Schnittestellen Statusantrag wird versandt - + 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 wirklich 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + 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? @@ -815,7 +815,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,92 +824,92 @@ Are you sure you want to delete the channel? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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). Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). @@ -1119,47 +1119,47 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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% @@ -1174,12 +1174,12 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? %n Tag%n Tage - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1282,7 +1282,7 @@ Receiver's required difficulty: %1 and %2 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. @@ -1292,7 +1292,7 @@ Receiver's required difficulty: %1 and %2 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... @@ -1322,32 +1322,32 @@ Receiver's required difficulty: %1 and %2 Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1412,7 +1412,7 @@ Receiver's required difficulty: %1 and %2 Ihre Grafikkarte hat inkorrekt berechnet, OpenCL wird deaktiviert. Bitte benachrichtigen Sie die Entwickler. - + Set notification sound... Benachrichtigungsklang einstellen ... @@ -1436,92 +1436,102 @@ Willkommen zu einfachem und sicherem Bitmessage für Chans nicht empfohlen - + + Quiet Mode + + + + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + 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? @@ -1868,37 +1878,37 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 # @@ -1908,37 +1918,37 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - + 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 @@ -1948,72 +1958,72 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 @@ -2072,7 +2082,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - Chan passhphrase/name: + Chan passphrase/name: Chan-Name @@ -2094,17 +2104,17 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 -- 2.45.1 From d6e94cf77ffa2b1a7460421c02ee77741f36b235 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 2 Nov 2017 12:42:50 +0100 Subject: [PATCH 0966/1102] Auto-updated language zh_cn from transifex --- src/translations/bitmessage_zh_cn.qm | Bin 57332 -> 57717 bytes src/translations/bitmessage_zh_cn.ts | 440 ++++++++++++++------------- 2 files changed, 235 insertions(+), 205 deletions(-) diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index 77b56321fd51c739be799b37851bf168ca4230b0..cc37b14624423f37136395a23ad72d84c3370e09 100644 GIT binary patch delta 3833 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 EFOUd~RR910 delta 3528 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 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)如下: @@ -166,52 +166,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 新建 @@ -236,12 +236,12 @@ Please type the desired email address (including @mailchuck.com) below: 将地址复制到剪贴板 - + Special address behavior... 特别的地址行为... - + Email gateway 电子邮件网关 @@ -251,37 +251,37 @@ Please type the desired email address (including @mailchuck.com) below: 删除 - + 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. 正在等待他们的加密密钥,我们会在稍后再次请求。 @@ -291,17 +291,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. 已经添加到队列。 - + Message sent. Waiting for acknowledgement. Sent at %1 消息已经发送. 正在等待回执. 发送于 %1 - + Message sent. Sent at %1 消息已经发送. 发送于 %1 @@ -311,47 +311,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 显示比特信 @@ -361,12 +361,12 @@ Please type the desired email address (including @mailchuck.com) below: 发送 - + Subscribe 订阅 - + Channel 频道 @@ -376,66 +376,66 @@ Please type the desired email address (including @mailchuck.com) below: 退出 - + 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. @@ -505,22 +505,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -529,17 +529,17 @@ It is important that you back up this file. Would you like to open the file now? 收件人必须在此期间得到它. 如果您的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​​, 注册正在处理请稍候重试发送. @@ -584,67 +584,67 @@ It is important that you back up this file. Would you like to open the file now? - + 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接收了地址。 - + New Message 新消息 - + From - 来自 + - + Sending email gateway registration request 发送电​​子邮件网关注册请求 @@ -659,142 +659,142 @@ It is important that you back up this file. Would you like to open the file now? 您输入的地址是无效的,将被忽略。 - + 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? 比特信无法找到你的地址 %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? @@ -803,7 +803,7 @@ 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? @@ -812,92 +812,92 @@ 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. 没有可以显示的近期广播。 - + You are using TCP port %1. (This can be changed in the settings). 您正在使用TCP端口 %1 。(可以在设置中修改)。 @@ -1107,47 +1107,47 @@ Are you sure you want to delete the channel? 添加新条目 - + 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% @@ -1157,17 +1157,17 @@ Are you sure you want to delete the channel? %n 小时 - + %n day(s) %n 天 - + Shutting down PyBitmessage... %1% 关闭PyBitmessage...%1% - + Sent 发送 @@ -1212,86 +1212,86 @@ Are you sure you want to delete the channel? 警告: 您的磁盘或数据存储量已满. 比特信将立即退出. - + Error! Could not find sender address (your address) in the keys.dat file. 错误! 找不到在keys.dat 件发件人的地址 ( 您的地址). - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. 做必要的工作, 以发送信息. 这样第2版的地址没有难度. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. 做必要的工作, 以发送信息. - + Message sent. Waiting for acknowledgement. Sent on %1 信息发送. 等待确认. 已发送%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 发送公钥的请求. 等待回复. 请求在%1 @@ -1306,37 +1306,37 @@ Receiver's required difficulty: %1 and %2 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? 等待所有任务执行完? @@ -1396,12 +1396,17 @@ Receiver's required difficulty: %1 and %2 不能理解 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 @@ -1415,85 +1420,110 @@ Receiver's required difficulty: %1 and %2 *在频道(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 @@ -1836,37 +1866,37 @@ The 'Random Number' option is selected by default but deterministic ad 总连接: - + 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 # 数据流 # @@ -1876,37 +1906,37 @@ The 'Random Number' option is selected by default but deterministic ad - + 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 /秒 @@ -1916,72 +1946,72 @@ The 'Random Number' option is selected by default but deterministic ad 网络状态 - + 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 您和节点之间已协商的流列表 @@ -2040,8 +2070,8 @@ The 'Random Number' option is selected by default but deterministic ad - Chan passhphrase/name: - 频道命名: + Chan passphrase/name: + @@ -2062,17 +2092,17 @@ The 'Random Number' option is selected by default but deterministic ad newchandialog - + Successfully created / joined chan %1 成功创建或加入频道%1 - + Chan creation / joining failed 频道创建或加入失败 - + Chan creation / joining cancelled 频道创建或加入已取消 @@ -2080,17 +2110,17 @@ The 'Random Number' option is selected by default but deterministic ad 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模块不可用。请编译它。 -- 2.45.1 From 89567cecfa7246b717141955eb438540cebfb41e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Nov 2017 23:19:16 +0100 Subject: [PATCH 0967/1102] Notifier plugin fix - NotifyOSD doesn't like too many notification objects in a queue, so just create one on init and update its contents if there is a new notification --- src/plugins/notification_notify2.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py index 90f09df3..e91d8f1b 100644 --- a/src/plugins/notification_notify2.py +++ b/src/plugins/notification_notify2.py @@ -6,8 +6,10 @@ 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' - Notify.Notification.new(title, subtitle, icon).show() + connect_plugin.notification.update(title, subtitle, icon) + connect_plugin.notification.show.show() + +connect_plugin.notification = Notify.Notification.new("Init", "Init") -- 2.45.1 From d2f79d3172ff395084ecc2e4ba5c61005bb06662 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Nov 2017 23:20:15 +0100 Subject: [PATCH 0968/1102] sqlite storage fix - typo on cleaning --- src/storage/sqlite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index b5c48e3b..aba64244 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -75,6 +75,6 @@ class SqliteInventory(InventoryStorage): with self.lock: sqlExecute('DELETE FROM inventory WHERE expirestime Date: Tue, 14 Nov 2017 23:43:05 +0100 Subject: [PATCH 0969/1102] close handling fix - don't close a connection twice --- src/network/connectionpool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 04336b00..ebde717b 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -236,7 +236,7 @@ class BMConnectionPool(object): i.append_write_buf(protocol.CreatePacket('ping')) else: i.close_reason = "Timeout (%is)" % (time.time() - i.lastTx) - i.handle_close() + i.set_state("close") for i in self.inboundConnections.values() + self.outboundConnections.values() + self.listeningSockets.values() + self.udpSockets.values(): if i.state == "close": i.handle_close() -- 2.45.1 From 2da1115d17e22bac2dcc60e4fb74241b4df9ea76 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 14 Nov 2017 23:46:07 +0100 Subject: [PATCH 0970/1102] Typo Typo in 89567cecfa7246b717141955eb438540cebfb41e --- src/plugins/notification_notify2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/notification_notify2.py b/src/plugins/notification_notify2.py index e91d8f1b..3fd935c4 100644 --- a/src/plugins/notification_notify2.py +++ b/src/plugins/notification_notify2.py @@ -10,6 +10,6 @@ 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.show() + connect_plugin.notification.show() connect_plugin.notification = Notify.Notification.new("Init", "Init") -- 2.45.1 From 5a787f41d2527e936f2f6d2ae3da9e7f177a66cb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Nov 2017 13:37:51 +0100 Subject: [PATCH 0971/1102] Socket closing changes - explicit close only through asyncore error handler - implicit close through garbage collector - avoid duplicate closing --- src/network/advanceddispatcher.py | 6 +++--- src/network/bmproto.py | 3 +++ src/network/connectionpool.py | 8 ++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 50ddf44b..c50b6a43 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -78,7 +78,7 @@ class AdvancedDispatcher(asyncore.dispatcher): self.uploadChunk = asyncore.uploadBucket self.uploadChunk = min(self.uploadChunk, len(self.write_buf)) return asyncore.dispatcher.writable(self) and \ - (self.connecting or self.uploadChunk > 0) + (self.connecting or (self.connected and self.uploadChunk > 0)) def readable(self): self.downloadChunk = AdvancedDispatcher._buf_len @@ -92,7 +92,7 @@ class AdvancedDispatcher(asyncore.dispatcher): except AttributeError: pass return asyncore.dispatcher.readable(self) and \ - (self.connecting or self.downloadChunk > 0) + (self.connecting or self.accepting or (self.connected and self.downloadChunk > 0)) def handle_read(self): self.lastTx = time.time() @@ -127,5 +127,5 @@ class AdvancedDispatcher(asyncore.dispatcher): self.read_buf = bytearray() with self.writeLock: self.write_buf = bytearray() - self.state = "close" + self.set_state("close") self.close() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 9bc60af7..e4f7b406 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -546,6 +546,9 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index ebde717b..aa48093e 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -214,11 +214,13 @@ class BMConnectionPool(object): else: if self.listeningSockets: for i in self.listeningSockets.values(): - i.handle_close() + 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.handle_close() + i.close_reason = "Stopping UDP socket" + i.accepting = i.connecting = i.connected = False logger.info('Stopped udp sockets.') loopTime = float(self.spawnWait) @@ -238,8 +240,6 @@ class BMConnectionPool(object): 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 i.state == "close": - i.handle_close() if not (i.accepting or i.connecting or i.connected): reaper.append(i) for i in reaper: -- 2.45.1 From 1e02d2b48a5e135f0eb8567c4b374b6c84205a97 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Nov 2017 19:49:51 +0100 Subject: [PATCH 0972/1102] Download optimisation - pending download tracking now per-connection instead of globally --- src/network/downloadthread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 414aacd2..8c384edc 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -48,7 +48,7 @@ class DownloadThread(threading.Thread, StoppableThread): # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk with i.objectsNewToMeLock: try: - downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut))) + downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut and not v))) except KeyError: continue if downloadPending >= DownloadThread.minPending: -- 2.45.1 From 3c3d69e5de70dbc01f3dfd6063d2775e89fdad12 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Nov 2017 19:50:39 +0100 Subject: [PATCH 0973/1102] Reap closed connection fix --- src/network/connectionpool.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index aa48093e..d0cbdcd0 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -242,5 +242,11 @@ class BMConnectionPool(object): 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) -- 2.45.1 From 4690dd6f00c3f26f3ab17138c0e50231f2dfc83b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 17 Nov 2017 23:53:46 +0100 Subject: [PATCH 0974/1102] Copy object contents from buffers on instantiation - this may fix some memory issues --- src/network/bmobject.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/network/bmobject.py b/src/network/bmobject.py index f4c883ca..249ec2ab 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -40,8 +40,9 @@ class BMObject(object): self.version = version self.streamNumber = streamNumber self.inventoryHash = calculateInventoryHash(data) - self.data = data - self.tag = data[payloadOffset:payloadOffset+32] + # 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. -- 2.45.1 From 3aa6f386dbb0099b99babf150893ba4ac40d1996 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 18 Nov 2017 09:47:17 +0100 Subject: [PATCH 0975/1102] Dandelion fixes - dandelion would always think there is a cycle and trigger fluff - cycle fluff trigger didn't correctly re-download and re-announce the object. Now it remembers between (d)inv and object commands that it's in a fluff trigger phase. --- src/network/bmproto.py | 2 +- src/network/connectionpool.py | 2 ++ src/network/dandelion.py | 9 +++++++++ src/network/objectracker.py | 10 ++++------ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index e4f7b406..17b2c761 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -326,8 +326,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): return True for i in map(str, items): - Dandelion().addHash(i, self) self.handleReceivedInventory(i) + Dandelion().addHash(i, self) return True diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index d0cbdcd0..46bb8aba 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -51,6 +51,8 @@ class BMConnectionPool(object): del i.objectsNewToThem[hashid] except KeyError: pass + if hashid in Dandelion().fluff: + Dandelion.removeHash(hashid) def reRandomiseDandelionStems(self): # Choose 2 peers randomly diff --git a/src/network/dandelion.py b/src/network/dandelion.py index a7ef4083..3e49d906 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -16,6 +16,7 @@ class Dandelion(): self.stem = [] self.nodeMap = {} self.hashMap = {} + self.fluff = {} self.timeout = {} self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() @@ -37,6 +38,14 @@ class Dandelion(): del self.timeout[hashId] except KeyError: pass + try: + del self.fluff[hashId] + except KeyError: + pass + + def fluffTrigger(self, hashId): + with self.lock: + self.fluff[hashId] = None def maybeAddStem(self, connection): # fewer than MAX_STEMS outbound connections at last reshuffle? diff --git a/src/network/objectracker.py b/src/network/objectracker.py index a86ec23f..f846e7d5 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -82,16 +82,14 @@ class ObjectTracker(object): del self.objectsNewToThem[hashId] except KeyError: pass - if hashId not in Inventory(): + # Fluff trigger by cycle detection + if hashId not in Inventory() or hashId in Dandelion().hashMap: + if hashId in Dandelion().hashMap: + Dandelion().fluffTrigger(hashId) if hashId not in missingObjects: missingObjects[hashId] = time.time() with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True - elif hashId in Dandelion().hashMap: - # Fluff trigger by cycle detection - Dandelion().removeHash(hashId) - with self.objectsNewToMeLock: - self.objectsNewToMe[hashId] = True def hasAddr(self, addr): if haveBloom: -- 2.45.1 From 5e042b76e70f7b262b083447c05a87fa8da0ed85 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 18 Nov 2017 10:05:41 +0100 Subject: [PATCH 0976/1102] Typo - missing brackets --- src/network/connectionpool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 46bb8aba..f489d9fc 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -52,7 +52,7 @@ class BMConnectionPool(object): except KeyError: pass if hashid in Dandelion().fluff: - Dandelion.removeHash(hashid) + Dandelion().removeHash(hashid) def reRandomiseDandelionStems(self): # Choose 2 peers randomly -- 2.45.1 From fdfbb77ed204077bd4560e173e4bf97487e55d6f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Nov 2017 00:05:55 +0100 Subject: [PATCH 0977/1102] Close filehandles on connection reaping - I thought this is done automatically through garbage collection, but I think as the channel is still assigned in the asyncore map, it needs to be done manually. Basically filehandle limit exceeded and it crashed --- src/network/connectionpool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index f489d9fc..2f937a15 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -111,6 +111,7 @@ class BMConnectionPool(object): del self.inboundConnections[connection.destination.host] except KeyError: pass + connection.close() def getListeningIP(self): if BMConfigParser().safeGet("bitmessagesettings", "onionhostname").endswith(".onion"): -- 2.45.1 From e558b1fb72e6a3d95f4d51ea219dc25e15924510 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 19 Nov 2017 13:48:43 +0100 Subject: [PATCH 0978/1102] Error handling - proxy connections didn't init fullyEstablished --- src/network/proxy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/proxy.py b/src/network/proxy.py index c131c22a..7d46cd86 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -64,6 +64,7 @@ class Proxy(AdvancedDispatcher): AdvancedDispatcher.__init__(self) self.destination = address self.isOutbound = True + self.fullyEstablished = False self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect(self.proxy) -- 2.45.1 From 6ca3460090dfe09b2d184f21f5c48f7fdb272d6f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Nov 2017 14:49:18 +0100 Subject: [PATCH 0979/1102] Put garbage collection into the cleaner thread - this maybe addresses #1079 --- src/class_singleCleaner.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index f3125806..e89dd1b1 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -1,7 +1,7 @@ +import gc import threading import shared import time -import sys import os import tr#anslate @@ -14,7 +14,6 @@ from network.dandelion import Dandelion from debug import logger import knownnodes import queues -import protocol import state """ @@ -46,6 +45,7 @@ class singleCleaner(threading.Thread, StoppableThread): self.initStop() 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) @@ -148,6 +148,8 @@ class singleCleaner(threading.Thread, StoppableThread): pass # TODO: cleanup pending upload / download + gc.collect() + if state.shutdown == 0: self.stop.wait(singleCleaner.cycleLength) -- 2.45.1 From 44dd08a2284a5300887ae012f754dfa0d64689b8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 22 Nov 2017 21:13:35 +0100 Subject: [PATCH 0980/1102] Remove obsolete code in cleaner thread --- src/class_singleCleaner.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index e89dd1b1..bec1a11d 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -63,8 +63,6 @@ class singleCleaner(threading.Thread, StoppableThread): Inventory().flush() queues.UISignalQueue.put(('updateStatusBar', '')) - protocol.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. @@ -127,10 +125,10 @@ class singleCleaner(threading.Thread, StoppableThread): os._exit(0) shared.needToWriteKnownNodesToDisk = False - # clear download queues - for thread in threading.enumerate(): - if thread.isAlive() and hasattr(thread, 'downloadQueue'): - thread.downloadQueue.clear() +# # 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(): -- 2.45.1 From 52162046bd51b472597f7a32a50b5cb3f1040d31 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 29 Nov 2017 10:38:58 +0100 Subject: [PATCH 0981/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 93991 -> 94127 bytes src/translations/bitmessage_ru.ts | 342 +++++++++++++++--------------- 2 files changed, 176 insertions(+), 166 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 2cdfe4db1dcb94bd4196bf9f57bcc9f46dcc9db9..82604f65804e3eb917008e1b63b0678f848e6585 100644 GIT binary patch delta 3508 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 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -283,7 +283,7 @@ Please type the desired email address (including @mailchuck.com) below: Один из Ваших адресов, %1, является устаревшим адресом версии 1. Адреса версии 1 больше не поддерживаются. Хотите ли Вы удалить его сейчас? - + Waiting for their encryption key. Will request it again soon. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,47 +313,47 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -363,12 +363,12 @@ Please type the desired email address (including @mailchuck.com) below: Отправить - + Subscribe Подписки - + Channel Канал @@ -378,13 +378,13 @@ Please type the desired email address (including @mailchuck.com) below: Выйти - + 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. @@ -393,19 +393,19 @@ 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.) @@ -415,37 +415,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,57 +596,57 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Новое сообщение @@ -656,7 +656,7 @@ It is important that you back up this file. Would you like to open the file now? - + Sending email gateway registration request Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,92 +824,92 @@ 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. Это адрес 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). Вы используете TCP порт %1. (Его можно поменять в настройках). @@ -1119,47 +1119,47 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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% @@ -1174,12 +1174,12 @@ Are you sure you want to delete the channel? %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправлено @@ -1283,7 +1283,7 @@ Receiver's required difficulty: %1 and %2 Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. @@ -1293,7 +1293,7 @@ Receiver's required difficulty: %1 and %2 Отправлено. Ожидаем подтверждения. Отправлено в %1 - + Doing work necessary to request encryption key. Выполнение работы, требуемой для запроса ключа шифрования. @@ -1323,32 +1323,32 @@ Receiver's required difficulty: %1 and %2 Отметить все сообщения как прочтенные - + 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1413,7 +1413,7 @@ Receiver's required difficulty: %1 and %2 Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + Set notification sound... Установить звук уведомления... @@ -1437,92 +1437,102 @@ Receiver's required difficulty: %1 and %2 не рекомендовано для чанов - + + 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? Вы пытаетесь отправить email вместо 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 + Ошибка: %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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?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? У вас уже есть звук уведомления для этого адресата. Вы уверены, что хотите перезаписать звук уведомления? @@ -1868,37 +1878,37 @@ The 'Random Number' option is selected by default but deterministic ad Всего соединений: - + 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 # № потока @@ -1908,37 +1918,37 @@ The 'Random Number' option is selected by default but deterministic ad - + Since startup on %1 - С начала работы в %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 кБ/с @@ -1948,72 +1958,72 @@ The 'Random Number' option is selected by default but deterministic ad Состояние сети - + 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 Перечень потоков, согласованных с конкретным узлом @@ -2072,7 +2082,7 @@ The 'Random Number' option is selected by default but deterministic ad - Chan passhphrase/name: + Chan passphrase/name: Пароль/имя чана: @@ -2094,17 +2104,17 @@ The 'Random Number' option is selected by default but deterministic ad newchandialog - + Successfully created / joined chan %1 Успешно создан / подключен чан %1 - + Chan creation / joining failed Не удалось создать / подключить чан - + Chan creation / joining cancelled Создание / подключение чана отменено -- 2.45.1 From 6ce3ce6b2226c829b7778e6231b2563f86e35de8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 30 Nov 2017 19:39:31 +0100 Subject: [PATCH 0982/1102] Chunking helper for sql statements with too many variables - preparation for #1081 --- src/helper_sql.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/helper_sql.py b/src/helper_sql.py index d27401cf..086cebfe 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -21,6 +21,24 @@ def sqlQuery(sqlStatement, *args): 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)): + sqlSubmitQueue.put(sqlStatement) + # first static args, and then iterative chunk + sqlSubmitQueue.put(args[0:len(args)-idCount] + args[i:i+sqlExecuteChunked.chunkSize - len(args)-idCount]) + retVal = sqlReturnQueue.get() + totalRowCount += retVal[1] + sqlSubmitQueue.put('commit') + return totalRowCount + def sqlExecute(sqlStatement, *args): sqlLock.acquire() sqlSubmitQueue.put(sqlStatement) -- 2.45.1 From 48c0a2ae2ebd3ec046dfa3f4325a36588934985a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 30 Nov 2017 19:42:49 +0100 Subject: [PATCH 0983/1102] Arithmetic fix for preceding commit --- src/helper_sql.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper_sql.py b/src/helper_sql.py index 086cebfe..7410202b 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -33,7 +33,7 @@ def sqlExecuteChunked(sqlStatement, idCount, *args): for i in range(len(args)-idCount, len(args), sqlExecuteChunked.chunkSize - (len(args)-idCount)): sqlSubmitQueue.put(sqlStatement) # first static args, and then iterative chunk - sqlSubmitQueue.put(args[0:len(args)-idCount] + args[i:i+sqlExecuteChunked.chunkSize - len(args)-idCount]) + sqlSubmitQueue.put(args[0:len(args)-idCount] + args[i:i+sqlExecuteChunked.chunkSize - (len(args)-idCount)]) retVal = sqlReturnQueue.get() totalRowCount += retVal[1] sqlSubmitQueue.put('commit') -- 2.45.1 From 6c224447a62931a468b45f7438d67dc2e4fcbfa8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 30 Nov 2017 19:44:03 +0100 Subject: [PATCH 0984/1102] Minor fixes that came over BM - typo in quit confirmation dialog - nicer traceback in unhandled exceptions --- src/bitmessageqt/__init__.py | 2 +- src/debug.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4cda426d..8ae31e8a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2618,7 +2618,7 @@ class MyForm(settingsmixin.SMainWindow): QtGui.QMessageBox.Yes|QtGui.QMessageBox.No|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) if reply == QtGui.QMessageBox.No: waitForPow = False - elif reply == QtGui.QMessage.Cancel: + elif reply == QtGui.QMessageBox.Cancel: return if PendingDownloadQueue.totalSize() > 0: diff --git a/src/debug.py b/src/debug.py index 83b11835..b03e8bf9 100644 --- a/src/debug.py +++ b/src/debug.py @@ -20,7 +20,6 @@ import logging import logging.config import os import sys -import traceback import helper_startup import state helper_startup.loadConfig() @@ -30,8 +29,7 @@ helper_startup.loadConfig() log_level = 'WARNING' def log_uncaught_exceptions(ex_cls, ex, tb): - logging.critical(''.join(traceback.format_tb(tb))) - logging.critical('{0}: {1}'.format(ex_cls, ex)) + logging.critical('Unhandled exception', exc_info=(ex_cls, ex, tb)) def configureLogging(): have_logging = False -- 2.45.1 From 4ee9d0544692332a596e183d9ad9e4e0672c90a9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 30 Nov 2017 20:08:14 +0100 Subject: [PATCH 0985/1102] Randomise key order during decryption - may help against timing/radio attacks --- src/class_objectProcessor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index ec2b32b9..21de6856 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -361,7 +361,7 @@ class objectProcessor(threading.Thread): # 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 shared.myECCryptorObjects.items(): + for key, cryptorObject in sorted(shared.myECCryptorObjects.items(), key=lambda x: random.random()): try: if initialDecryptionSuccessful: # continue decryption attempts to avoid timing attacks cryptorObject.decrypt(data[readPosition:]) @@ -634,7 +634,7 @@ class objectProcessor(threading.Thread): """ signedData = data[8:readPosition] initialDecryptionSuccessful = False - for key, cryptorObject in shared.MyECSubscriptionCryptorObjects.items(): + for key, cryptorObject in sorted(shared.MyECSubscriptionCryptorObjects.items(), key=lambda x: random.random()): try: if initialDecryptionSuccessful: # continue decryption attempts to avoid timing attacks cryptorObject.decrypt(data[readPosition:]) -- 2.45.1 From 3b86dfc639ba6fd77d69aed0b1a71b2259c08c5e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 2 Dec 2017 00:45:01 +0100 Subject: [PATCH 0986/1102] Log missing indicator plugin --- src/bitmessageqt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8ae31e8a..c731b469 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1294,6 +1294,7 @@ class MyForm(settingsmixin.SMainWindow): try: self.indicatorUpdate = get_plugin('indicator')(self) except (NameError, TypeError): + logger.warning("No indicator plugin found") self.indicatorUpdate = _noop_update # initialise the message notifier -- 2.45.1 From 41ead2bfb5d0d2e61c9559042814b45b246d4c91 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 2 Dec 2017 00:48:08 +0100 Subject: [PATCH 0987/1102] Distribute downloads more evenly - also increases expireation of missing objects from 10 minutes to an hour --- src/network/downloadthread.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 8c384edc..0cbdac16 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -13,10 +13,10 @@ from state import missingObjects class DownloadThread(threading.Thread, StoppableThread): minPending = 200 - requestChunk = 1000 + maxRequestChunk = 1000 requestTimeout = 60 cleanInterval = 60 - requestExpires = 600 + requestExpires = 3600 def __init__(self): threading.Thread.__init__(self, name="Downloader") @@ -42,6 +42,7 @@ class DownloadThread(threading.Thread, StoppableThread): # Choose downloading peers randomly connections = BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() random.shuffle(connections) + requestChunk = max(int(DownloadThread.maxRequestChunk / len(connections)), 1) for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout @@ -61,8 +62,8 @@ class DownloadThread(threading.Thread, StoppableThread): random.shuffle(request) if not request: continue - if len(request) > DownloadThread.requestChunk - downloadPending: - request = request[:DownloadThread.requestChunk - downloadPending] + if len(request) > requestChunk - downloadPending: + request = request[:requestChunk - downloadPending] # mark them as pending for k in request: i.objectsNewToMe[k] = False -- 2.45.1 From a3398d6a17e623da780744148be33d4ea7fda02b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 2 Dec 2017 00:50:58 +0100 Subject: [PATCH 0988/1102] Don't crash download thread if no connections --- src/network/downloadthread.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 0cbdac16..5fe1ee25 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -42,7 +42,10 @@ class DownloadThread(threading.Thread, StoppableThread): # Choose downloading peers randomly connections = BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() random.shuffle(connections) - requestChunk = max(int(DownloadThread.maxRequestChunk / len(connections)), 1) + try: + requestChunk = max(int(DownloadThread.maxRequestChunk / len(connections)), 1) + except ZeroDivisionError: + requestChunk = 1 for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout -- 2.45.1 From 5605672f753162a82eb7651f3dc3d20d0502ec20 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 2 Dec 2017 02:48:10 +0100 Subject: [PATCH 0989/1102] Fix tag search when inventory contains blobs - recent changes caused the "tag" (and "payload") columns in the inventory table in messages.dat to be stored as blobs. Searches by tag (e.g. pubkey lookups) stopped working. This fixes it. --- src/storage/sqlite.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index aba64244..7c9e8822 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -1,6 +1,7 @@ import collections from threading import current_thread, enumerate as threadingEnumerate, RLock import Queue +import sqlite3 import time from helper_sql import * @@ -50,7 +51,7 @@ class SqliteInventory(InventoryStorage): 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, 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 hashes_by_stream(self, stream): -- 2.45.1 From dd780f8d806afae29db5c7173d3e3a9eb1bcfb2e Mon Sep 17 00:00:00 2001 From: sandakersmann Date: Thu, 7 Dec 2017 00:27:59 +0100 Subject: [PATCH 0990/1102] This type of data is called metadata --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a161d04..0ea6144b 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 "non-content" data, like the +message cannot be spoofed, and it aims to hide metadata, like the sender and receiver of messages, from passive eavesdroppers like those running warrantless wiretapping programs. -- 2.45.1 From 395812c0f8b50bcc56b411d4c293b7735382c32f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 20 Dec 2017 09:20:24 +0100 Subject: [PATCH 0991/1102] Systemd config file - tested on Debian 9, you may have to adjust paths/uids if your deployment differs --- packages/systemd/bitmessage.service | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 packages/systemd/bitmessage.service diff --git a/packages/systemd/bitmessage.service b/packages/systemd/bitmessage.service new file mode 100644 index 00000000..1a9f7f47 --- /dev/null +++ b/packages/systemd/bitmessage.service @@ -0,0 +1,18 @@ +[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 -- 2.45.1 From 6fb5a751c624efce8bc41736d219b0acda7cebaa Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 20 Dec 2017 09:41:36 +0100 Subject: [PATCH 0992/1102] Add collectd monitoring script --- packages/collectd/pybitmessagestatus.py | 60 +++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 packages/collectd/pybitmessagestatus.py diff --git a/packages/collectd/pybitmessagestatus.py b/packages/collectd/pybitmessagestatus.py new file mode 100644 index 00000000..1db9f5b1 --- /dev/null +++ b/packages/collectd/pybitmessagestatus.py @@ -0,0 +1,60 @@ +#!/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) -- 2.45.1 From 3cb9547389e41bbf8b7cd8e258e91db57614e4b6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 21 Dec 2017 14:26:51 +0100 Subject: [PATCH 0993/1102] Only write PID after last fork - should fix systemd integration --- src/bitmessagemain.py | 2 +- src/singleinstance.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 83a41919..91032fe5 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -363,7 +363,7 @@ class Main: # fork not implemented pass else: - shared.thisapp.lock() # relock + shared.thisapp.lock(True) # relock and write pid shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() diff --git a/src/singleinstance.py b/src/singleinstance.py index 7a025945..883c83cc 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -36,7 +36,7 @@ class singleinstance: self.initialized = True atexit.register(self.cleanup) - def lock(self): + def lock(self, writePid = False): if self.lockPid is None: self.lockPid = os.getpid() if sys.platform == 'win32': @@ -68,9 +68,10 @@ class singleinstance: sys.exit(-1) else: pidLine = "%i\n" % self.lockPid - self.fp.truncate(0) - self.fp.write(pidLine) - self.fp.flush() + if writePid: + self.fp.truncate(0) + self.fp.write(pidLine) + self.fp.flush() def cleanup(self): if not self.initialized: -- 2.45.1 From a0e5ee4ccedf9c744b345be38c1db08bff1e052d Mon Sep 17 00:00:00 2001 From: sigoa Date: Tue, 26 Dec 2017 14:17:37 +0100 Subject: [PATCH 0994/1102] utf chan name support, various fixes no unused variables etc. any longer --- src/bitmessagecli.py | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index ee877818..e216a91a 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -1,14 +1,15 @@ -#!/usr/bin/python2.7 +#!/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.4.2, by .dok (Version 0.3.0) +# This is an example of a daemon client for PyBitmessage 0.4.3, by .dok (Version 0.3.1) import xmlrpclib import datetime -import hashlib -import getopt +#import hashlib +#import getopt import imghdr import ntpath import json @@ -37,7 +38,7 @@ def userInput(message): #Checks input for exit or quit. Also formats for input, elif (uInput.lower() == 'quit'): #Quits the program print '\n Bye\n' sys.exit() - os.exit() + os._exit() # _ else: return uInput @@ -55,7 +56,7 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe 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() + os._exit() elif 'win32' in sys.platform or 'win64' in sys.platform: dataFolder = path.join(environ['APPDATA'], APPNAME) + '\\' @@ -117,7 +118,7 @@ def apiInit(apiEnabled): apiUsr = userInput("API Username") apiPwd = userInput("API Password") - apiInterface = userInput("API Interface. (127.0.0.1)") + #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() @@ -207,7 +208,7 @@ def apiData(): 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 + #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')) @@ -424,7 +425,7 @@ def unsubscribe(): break - uInput = userInput("Are you sure, (Y)es or (N)o?").lower() + userInput("Are you sure, (Y)es or (N)o?").lower() # #uInput = api.deleteSubscription(address) print ('\n You are now unsubscribed from: ' + address + '\n') @@ -522,9 +523,9 @@ def listAdd(): #Lists all of the addresses and their info print ' | # | Label | Address |S#|Enabled|' print ' |---|-------------------|-------------------------------------|--|-------|' for addNum in range (0, numAddresses): #processes all of the addresses and lists them out - label = str(jsonAddresses['addresses'][addNum]['label']) + 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']) + stream = str(jsonAddresses['addresses'][addNum]['stream']) enabled = str(jsonAddresses['addresses'][addNum]['enabled']) if (len(label) > 19): @@ -593,7 +594,7 @@ def genMilAddr(): #Generate address lbl = "random" + str(i) addressLabel = lbl.encode('base64') try: - generatedAddress = api.createRandomAddress(addressLabel) + api.createRandomAddress(addressLabel) # generatedAddress = except: print '\n Connection Error\n' usrPrompt = 0 @@ -912,7 +913,7 @@ def inbox(unreadOnly = False): #Lists the messages by: Message Number, To Addres if not message['read']: messagesUnread += 1 if (messagesPrinted%20 == 0 and messagesPrinted != 0): - uInput = userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() + 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) @@ -940,7 +941,7 @@ def outbox(): 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): - uInput = userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() + 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.' @@ -1319,12 +1320,12 @@ def UI(usrInput): #Main user menu print ' |------------------------|----------------------------------------------|' print ' | subscribe | Subscribes to an address |' print ' | unsubscribe | Unsubscribes from an address |' - #print ' | listSubscriptions | Lists all of the subscriptions. |' + #print ' | listSubscriptions | Lists all of the subscriptions. |' print ' |------------------------|----------------------------------------------|' - print ' | create | Creates a channel |' + print ' | create | Creates a channel |' print ' | join | Joins a channel |' print ' | leave | Leaves a channel |' - print ' |------------------------|----------------------------------------------|' + 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 |' @@ -1368,7 +1369,7 @@ def UI(usrInput): #Main user menu elif usrInput == "quit": #Quits the application print '\n Bye\n' sys.exit() - os.exit() + os._exit() elif usrInput == "listaddresses": #Lists all of the identities in the addressbook listAdd() @@ -1445,17 +1446,17 @@ def UI(usrInput): #Main user menu elif usrInput == "create": createChan() - userPrompt = 1 + usrPrompt = 1 main() elif usrInput == "join": joinChan() - userPrompt = 1 + usrPrompt = 1 main() elif usrInput == "leave": leaveChan() - userPrompt = 1 + usrPrompt = 1 main() elif usrInput == "inbox": @@ -1668,7 +1669,7 @@ def UI(usrInput): #Main user menu usrPrompt = 1 else: print '\n Invalid Entry.\n' - userPrompt = 1 + usrPrompt = 1 main() elif usrInput == "exit": -- 2.45.1 From 394d564bdca86b88d60d058a7f1966a1d884fd76 Mon Sep 17 00:00:00 2001 From: sigoa Date: Tue, 26 Dec 2017 15:01:12 +0100 Subject: [PATCH 0995/1102] minor mod of ver. not a biggie --- src/bitmessagecli.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index e216a91a..d7f4e5a9 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -3,7 +3,7 @@ # 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.4.3, by .dok (Version 0.3.1) +# This is an example of a daemon client for PyBitmessage 0.6.2, by .dok (Version 0.3.1) , modified import xmlrpclib @@ -1320,7 +1320,7 @@ def UI(usrInput): #Main user menu print ' |------------------------|----------------------------------------------|' print ' | subscribe | Subscribes to an address |' print ' | unsubscribe | Unsubscribes from an address |' - #print ' | listSubscriptions | Lists all of the subscriptions. |' + #print' | listSubscriptions | Lists all of the subscriptions. |' print ' |------------------------|----------------------------------------------|' print ' | create | Creates a channel |' print ' | join | Joins a channel |' @@ -1741,7 +1741,7 @@ def main(): if (usrPrompt == 0): print '\n ------------------------------' print ' | Bitmessage Daemon by .dok |' - print ' | Version 0.2.6 for BM 0.3.5 |' + print ' | Version 0.3.1 for BM 0.6.2 |' print ' ------------------------------' api = xmlrpclib.ServerProxy(apiData()) #Connect to BitMessage using these api credentials @@ -1770,4 +1770,4 @@ def main(): UI("quit") if __name__ == "__main__": - main() + main() -- 2.45.1 From 02490e3286ad1d865bdc9ec4552766a0304f6b37 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 29 Dec 2017 08:41:15 +0100 Subject: [PATCH 0996/1102] Don't break if over 50k messages - typo if there were over 50k messages in inventory caused PyBM to stall --- src/network/tcp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/tcp.py b/src/network/tcp.py index 70e22e08..922aa79d 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -180,7 +180,7 @@ class TCPConnection(BMProto, TLSDispatcher): payload += hash objectCount += 1 if objectCount >= BMProto.maxObjectCount: - self.sendChunk() + sendChunk() payload = b'' objectCount = 0 -- 2.45.1 From e9b1aa48a91624db922d832a1d342e63ad896b4e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 29 Dec 2017 08:49:08 +0100 Subject: [PATCH 0997/1102] Protocol error handler fixes - was broken if there was no error message in "raise" - added default texts for network exceptions --- src/network/bmobject.py | 17 +++++++++++------ src/network/bmproto.py | 9 ++++++--- src/network/proxy.py | 2 +- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 249ec2ab..267cac58 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -8,23 +8,28 @@ from network.dandelion import Dandelion import protocol import state -class BMObjectInsufficientPOWError(Exception): pass +class BMObjectInsufficientPOWError(Exception): + errorCodes = ("Insufficient proof of work") -class BMObjectInvalidDataError(Exception): pass +class BMObjectInvalidDataError(Exception): + errorCodes = ("Data invalid") -class BMObjectExpiredError(Exception): pass +class BMObjectExpiredError(Exception): + errorCodes = ("Object expired") -class BMObjectUnwantedStreamError(Exception): pass +class BMObjectUnwantedStreamError(Exception): + errorCodes = ("Object in unwanted stream") -class BMObjectInvalidError(Exception): pass +class BMObjectInvalidError(Exception): + errorCodes = ("Invalid object") class BMObjectAlreadyHaveError(Exception): - pass + errorCodes = ("Already have this object") class BMObject(object): diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 17b2c761..47c6c858 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -24,13 +24,16 @@ import shared import state import protocol -class BMProtoError(ProxyError): pass +class BMProtoError(ProxyError): + errorCodes = ("Protocol error") -class BMProtoInsufficientDataError(BMProtoError): pass +class BMProtoInsufficientDataError(BMProtoError): + errorCodes = ("Insufficient data") -class BMProtoExcessiveDataError(BMProtoError): pass +class BMProtoExcessiveDataError(BMProtoError): + errorCodes = ("Too much data") class BMProto(AdvancedDispatcher, ObjectTracker): diff --git a/src/network/proxy.py b/src/network/proxy.py index 7d46cd86..96930c18 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -10,7 +10,7 @@ import state class ProxyError(Exception): errorCodes = ("UnknownError") - def __init__(self, code): + def __init__(self, code=-1): self.code = code try: self.message = self.__class__.errorCodes[self.code] -- 2.45.1 From bcc5a210a484dd76b7e9ad3b033f47e704026770 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 29 Dec 2017 09:13:41 +0100 Subject: [PATCH 0998/1102] Fix PID file if not daemonized --- src/singleinstance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index 883c83cc..fdb5ee98 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -31,7 +31,7 @@ class singleinstance: import bitmessageqt bitmessageqt.init() - self.lock() + self.lock(not daemon) self.initialized = True atexit.register(self.cleanup) -- 2.45.1 From 1864762a0a3af4f32ba7fc5994bcb51d76643da3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 12:49:08 +0100 Subject: [PATCH 0999/1102] Apply bandwidth limits without restart - also minor style fixes --- src/bitmessageqt/__init__.py | 10 +++++----- src/network/asyncore_pollchoose.py | 4 ++-- src/network/connectionpool.py | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c731b469..e6ff0cd0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -69,7 +69,7 @@ import queues import shutdown import state from statusbar import BMStatusBar -import throttle +from network.asyncore_pollchoose import set_rates from version import softwareVersion import sound @@ -2288,16 +2288,16 @@ class MyForm(settingsmixin.SMainWindow): int(float(self.settingsDialogInstance.ui.lineEditMaxDownloadRate.text())))) BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) - except: + except ValueError: 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())))) - throttle.SendThrottle().resetLimit() - throttle.ReceiveThrottle().resetLimit() - BMConfigParser().set('bitmessagesettings', 'namecoinrpctype', self.settingsDialogInstance.getNamecoinType()) BMConfigParser().set('bitmessagesettings', 'namecoinrpchost', str( diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index caa9d650..c5586a91 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -129,8 +129,8 @@ def write(obj): def set_rates(download, upload): global maxDownloadRate, maxUploadRate, downloadBucket, uploadBucket, downloadTimestamp, uploadTimestamp - maxDownloadRate = float(download) - maxUploadRate = float(upload) + maxDownloadRate = float(download) * 1024 + maxUploadRate = float(upload) * 1024 downloadBucket = maxDownloadRate uploadBucket = maxUploadRate downloadTimestamp = time.time() diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 2f937a15..3b817e65 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -22,8 +22,8 @@ import state class BMConnectionPool(object): def __init__(self): asyncore.set_rates( - BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate") * 1024, - BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate") * 1024) + BMConfigParser().safeGetInt("bitmessagesettings", "maxdownloadrate"), + BMConfigParser().safeGetInt("bitmessagesettings", "maxuploadrate")) self.outboundConnections = {} self.inboundConnections = {} self.listeningSockets = {} -- 2.45.1 From 36cc5b9cf5e122b736854079b78e6b0dfb903bbc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 12:51:35 +0100 Subject: [PATCH 1000/1102] Download optimisations - don't make empty download requests - use smaller chunks when they can be spread across multiple connections --- src/network/downloadthread.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 5fe1ee25..35616f1b 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -43,7 +43,7 @@ class DownloadThread(threading.Thread, StoppableThread): connections = BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() random.shuffle(connections) try: - requestChunk = max(int(DownloadThread.maxRequestChunk / len(connections)), 1) + requestChunk = max(int(min(DownloadThread.maxRequestChunk, len(missingObjects)) / len(connections)), 1) except ZeroDivisionError: requestChunk = 1 for i in connections: @@ -63,15 +63,14 @@ class DownloadThread(threading.Thread, StoppableThread): except KeyError: continue random.shuffle(request) + if len(request) > requestChunk - downloadPending: + request = request[:max(1, requestChunk - downloadPending)] if not request: continue - if len(request) > requestChunk - downloadPending: - request = request[:requestChunk - downloadPending] # mark them as pending for k in request: i.objectsNewToMe[k] = False missingObjects[k] = now - payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) for chunk in request: -- 2.45.1 From baba0ae206b6cc8f6d81725fb1184a5d70225ed9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 13:04:58 +0100 Subject: [PATCH 1001/1102] Remove obsolete code --- src/shutdown.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shutdown.py b/src/shutdown.py index 278759e5..49c2fb9b 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -9,14 +9,12 @@ from helper_sql import sqlQuery, sqlStoredProcedure from helper_threading import StoppableThread from knownnodes import saveKnownNodes from inventory import Inventory -import protocol 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. - protocol.broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) for thread in threading.enumerate(): if thread.isAlive() and isinstance(thread, StoppableThread): -- 2.45.1 From d9a42630830eef597021179924351bba3b959386 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 13:08:12 +0100 Subject: [PATCH 1002/1102] Daemonising fixes - change forking exit order as systemd expects (wait until child is ready, then exit parent, then grandparent) - fix signal handler if prctl not installed - revert recent PID file changes --- src/bitmessagemain.py | 19 ++++++++++++++++++- src/helper_generic.py | 2 +- src/singleinstance.py | 18 +++++++++++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 91032fe5..6f796939 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -342,13 +342,21 @@ class Main: sleep(1) def daemonize(self): + grandfatherPid = os.getpid() + parentPid = None try: if os.fork(): + # unlock + shared.thisapp.cleanup() + # wait until grandchild ready + 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: @@ -358,12 +366,17 @@ class Main: 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(True) # relock and write pid + shared.thisapp.lock() # relock shared.thisapp.lockPid = None # indicate we're the final child sys.stdout.flush() sys.stderr.flush() @@ -374,6 +387,10 @@ class Main: 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) diff --git a/src/helper_generic.py b/src/helper_generic.py index b750e519..4f7a1299 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -51,7 +51,7 @@ def signal_handler(signal, frame): raise SystemExit if "PoolWorker" in current_process().name: raise SystemExit - if current_thread().name != "PyBitmessage": + if current_thread().name not in ("PyBitmessage", "MainThread"): return logger.error("Got signal %i", signal) if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): diff --git a/src/singleinstance.py b/src/singleinstance.py index fdb5ee98..d7cc0ab3 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -36,7 +36,7 @@ class singleinstance: self.initialized = True atexit.register(self.cleanup) - def lock(self, writePid = False): + def lock(self): if self.lockPid is None: self.lockPid = os.getpid() if sys.platform == 'win32': @@ -68,16 +68,24 @@ class singleinstance: sys.exit(-1) else: pidLine = "%i\n" % self.lockPid - if writePid: - self.fp.truncate(0) - self.fp.write(pidLine) - self.fp.flush() + 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: -- 2.45.1 From 6b54a4ab0e1ddfc39d06dca2d5aea010be7e8a5a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 1 Jan 2018 13:10:19 +0100 Subject: [PATCH 1003/1102] Daemonize fix - forgot to revert a line in previous commit --- src/singleinstance.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/singleinstance.py b/src/singleinstance.py index d7cc0ab3..ed1048ba 100644 --- a/src/singleinstance.py +++ b/src/singleinstance.py @@ -31,7 +31,7 @@ class singleinstance: import bitmessageqt bitmessageqt.init() - self.lock(not daemon) + self.lock() self.initialized = True atexit.register(self.cleanup) -- 2.45.1 From bb5f1d6f98b3dabec7a432bcde399bbec12c0b8a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 10:29:21 +0100 Subject: [PATCH 1004/1102] Setup.py typo - surprisingly, it only was broken on some systems, e.g. Debian 8 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0851b78f..ba34f6df 100644 --- a/setup.py +++ b/setup.py @@ -83,7 +83,7 @@ if __name__ == "__main__": 'qrcode': ['qrcode'], 'pyopencl': ['pyopencl'], 'notify2': ['notify2'], - 'sound:platform_system=="Windows"': ['winsound'] + 'sound;platform_system=="Windows"': ['winsound'] }, classifiers=[ "License :: OSI Approved :: MIT License" -- 2.45.1 From 9b58f35b80e1ece4f6d8fdefcc8ec13fce687b08 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 13:56:03 +0100 Subject: [PATCH 1005/1102] App name in version --- src/version.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/version.py b/src/version.py index bd06ca9b..694f71e4 100644 --- a/src/version.py +++ b/src/version.py @@ -1 +1,2 @@ +softwareName = 'PyBitmessage' softwareVersion = '0.6.2' -- 2.45.1 From 8788f2d3497e061d14e9ae4bd0864c6ea2373b39 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 14:29:21 +0100 Subject: [PATCH 1006/1102] Server full and duplicate handling - will try to report "Server full" over protocol for 10 extra connections over limit, instead of simply dropping them - if connected to the same host inbound and outbound, handle as server full (prevents duplicate connections) --- src/network/bmproto.py | 14 ++++++++++++++ src/network/tcp.py | 5 ++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 47c6c858..21ec692c 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -497,6 +497,20 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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.")) diff --git a/src/network/tcp.py b/src/network/tcp.py index 922aa79d..5a27aca3 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -292,7 +292,10 @@ class TCPServer(AdvancedDispatcher): if len(network.connectionpool.BMConnectionPool().inboundConnections) + \ len(network.connectionpool.BMConnectionPool().outboundConnections) > \ BMConfigParser().safeGetInt("bitmessagesettings", "maxtotalconnections") + \ - BMConfigParser().safeGetInt("bitmessagesettings", "maxbootstrapconnections"): + 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: -- 2.45.1 From 4086253730e2551a9b3aa3df5af13ff9be322bee Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 15:24:47 +0100 Subject: [PATCH 1007/1102] Bandwidth limit optimisation - should be slightly more accurate and use slightly fewer resources --- src/network/advanceddispatcher.py | 4 ++-- src/network/asyncore_pollchoose.py | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index c50b6a43..3e84ed85 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -75,7 +75,7 @@ class AdvancedDispatcher(asyncore.dispatcher): def writable(self): self.uploadChunk = AdvancedDispatcher._buf_len if asyncore.maxUploadRate > 0: - self.uploadChunk = asyncore.uploadBucket + 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)) @@ -83,7 +83,7 @@ class AdvancedDispatcher(asyncore.dispatcher): def readable(self): self.downloadChunk = AdvancedDispatcher._buf_len if asyncore.maxDownloadRate > 0: - self.downloadChunk = asyncore.downloadBucket + 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)) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index c5586a91..5717ff78 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -112,6 +112,8 @@ uploadBucket = 0 sentBytes = 0 def read(obj): + if not can_receive(): + return try: obj.handle_read_event() except _reraised_exceptions: @@ -120,6 +122,8 @@ def read(obj): obj.handle_error() def write(obj): + if not can_send(): + return try: obj.handle_write_event() except _reraised_exceptions: @@ -136,12 +140,18 @@ def set_rates(download, upload): 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 = int(maxDownloadRate * (currentTimestamp - downloadTimestamp)) + bucketIncrease = maxDownloadRate * (currentTimestamp - downloadTimestamp) downloadBucket += bucketIncrease if downloadBucket > maxDownloadRate: downloadBucket = int(maxDownloadRate) @@ -153,7 +163,7 @@ def update_sent(upload=0): currentTimestamp = time.time() sentBytes += upload if maxUploadRate > 0: - bucketIncrease = int(maxUploadRate * (currentTimestamp - uploadTimestamp)) + bucketIncrease = maxUploadRate * (currentTimestamp - uploadTimestamp) uploadBucket += bucketIncrease if uploadBucket > maxUploadRate: uploadBucket = int(maxUploadRate) @@ -170,9 +180,9 @@ def _exception(obj): def readwrite(obj, flags): try: - if flags & select.POLLIN: + if flags & select.POLLIN and can_receive(): obj.handle_read_event() - if flags & select.POLLOUT: + if flags & select.POLLOUT and can_send(): obj.handle_write_event() if flags & select.POLLPRI: obj.handle_expt_event() -- 2.45.1 From f74f82e54f97a9075e95ae59474e4948ce1d6e82 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 22:20:33 +0100 Subject: [PATCH 1008/1102] Start downloading earlier --- src/network/objectracker.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index f846e7d5..62f01e4f 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -29,6 +29,7 @@ class ObjectTracker(object): invInitialCapacity = 50000 invErrorRate = 0.03 trackingExpires = 3600 + initialTimeOffset = 60 def __init__(self): self.objectsNewToMe = {} @@ -87,7 +88,7 @@ class ObjectTracker(object): if hashId in Dandelion().hashMap: Dandelion().fluffTrigger(hashId) if hashId not in missingObjects: - missingObjects[hashId] = time.time() + missingObjects[hashId] = time.time() - ObjectTracker.initialTimeOffset with self.objectsNewToMeLock: self.objectsNewToMe[hashId] = True -- 2.45.1 From c9851b9f41da4db4365ef080b1533ab845992bd1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 2 Jan 2018 22:23:03 +0100 Subject: [PATCH 1009/1102] Connection lookups invalid data handling - shouldn't throw an exception if argument is a string rather than Peer --- src/network/connectionpool.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 3b817e65..44534a76 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -65,12 +65,18 @@ class BMConnectionPool(object): def getConnectionByAddr(self, addr): if addr in self.inboundConnections: return self.inboundConnections[addr] - if addr.host in self.inboundConnections: - return self.inboundConnections[addr.host] + try: + if addr.host in self.inboundConnections: + return self.inboundConnections[addr.host] + except AttributeError: + pass if addr in self.outboundConnections: return self.outboundConnections[addr] - if addr.host in self.udpSockets: - return self.udpSockets[addr.host] + try: + if addr.host in self.udpSockets: + return self.udpSockets[addr.host] + except AttributeError: + pass raise KeyError def isAlreadyConnected(self, nodeid): -- 2.45.1 From 1b921a718cc06ea7e49f4085650f60ac2c50e5dd Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 28 Sep 2017 18:10:03 +0300 Subject: [PATCH 1010/1102] Check daemon status in singleinstance instead of config --- src/helper_generic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helper_generic.py b/src/helper_generic.py index 4f7a1299..588ae8f1 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -6,7 +6,7 @@ from multiprocessing import current_process from threading import current_thread, enumerate import traceback -from bmconfigparser import BMConfigParser +import shared from debug import logger import queues import shutdown @@ -54,7 +54,7 @@ def signal_handler(signal, frame): if current_thread().name not in ("PyBitmessage", "MainThread"): return logger.error("Got signal %i", signal) - if BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): + if shared.thisapp.daemon: shutdown.doCleanShutdown() else: allThreadTraceback(frame) -- 2.45.1 From 0c4d4de82fb8f57fd488beee35181b2a08c7e5e6 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sun, 1 Oct 2017 18:39:35 +0300 Subject: [PATCH 1011/1102] Changed the daemon check approach in other places, where it makes sense --- src/class_singleCleaner.py | 2 +- src/shutdown.py | 3 +-- src/tr.py | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index bec1a11d..ed0ee044 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -66,7 +66,7 @@ class singleCleaner(threading.Thread, StoppableThread): # 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 BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): + if shared.thisapp.daemon: queues.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) diff --git a/src/shutdown.py b/src/shutdown.py index 49c2fb9b..f447148b 100644 --- a/src/shutdown.py +++ b/src/shutdown.py @@ -3,7 +3,6 @@ import Queue import threading import time -from bmconfigparser import BMConfigParser from debug import logger from helper_sql import sqlQuery, sqlStoredProcedure from helper_threading import StoppableThread @@ -60,7 +59,7 @@ def doCleanShutdown(): except Queue.Empty: break - if BMConfigParser().safeGetBoolean('bitmessagesettings','daemon'): + if shared.thisapp.daemon: logger.info('Clean shutdown complete.') shared.thisapp.cleanup() os._exit(0) diff --git a/src/tr.py b/src/tr.py index c185690c..19c234a1 100644 --- a/src/tr.py +++ b/src/tr.py @@ -1,6 +1,6 @@ import os -from bmconfigparser import BMConfigParser +import shared # 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: @@ -17,7 +17,7 @@ def _translate(context, text, disambiguation = None, encoding = None, n = None): return translateText(context, text, n) def translateText(context, text, n = None): - if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon'): + if not shared.thisapp.daemon: try: from PyQt4 import QtCore, QtGui except Exception as err: -- 2.45.1 From 460107abaa05cf0bfb51098e68c868171a0d57b0 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 7 Oct 2017 15:50:25 +0300 Subject: [PATCH 1012/1102] Handled AttributeError when tr imported from plugin --- src/tr.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tr.py b/src/tr.py index 19c234a1..cf7f16ac 100644 --- a/src/tr.py +++ b/src/tr.py @@ -17,7 +17,11 @@ def _translate(context, text, disambiguation = None, encoding = None, n = None): return translateText(context, text, n) def translateText(context, text, n = None): - if not shared.thisapp.daemon: + try: + is_daemon = shared.thisapp.daemon + except AttributeError: # inside the plugin + is_daemon = False + if not is_daemon: try: from PyQt4 import QtCore, QtGui except Exception as err: -- 2.45.1 From ba91d212614798a371c8a41233a5288c155c4d71 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 22 Jan 2018 22:18:01 +0100 Subject: [PATCH 1013/1102] CPU hogging fix - handle _command functions that don't return anything - fix udp command function --- src/network/advanceddispatcher.py | 2 +- src/network/udp.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 3e84ed85..31555c62 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -58,7 +58,7 @@ class AdvancedDispatcher(asyncore.dispatcher): break if len(self.read_buf) < self.expectBytes: return False - if getattr(self, "state_" + str(self.state))() is False: + if not getattr(self, "state_" + str(self.state))(): break except AttributeError: logger.error("Unknown state %s", self.state) diff --git a/src/network/udp.py b/src/network/udp.py index e7f6974d..0dba5a3f 100644 --- a/src/network/udp.py +++ b/src/network/udp.py @@ -61,7 +61,7 @@ class UDPSocket(BMProto): pass def state_bm_command(self): - BMProto.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 -- 2.45.1 From 01c8f3b66d5c40e3d3fdda6f884bc76ea9193380 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 22 Jan 2018 22:37:29 +0100 Subject: [PATCH 1014/1102] Fix asyncore CPU usage on no connection - if there are no connections, asyncore would hog CPU - thanks to an anonymous contributor --- src/network/asyncore_pollchoose.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index 5717ff78..de8ededc 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -52,6 +52,7 @@ import select import socket import sys import time +from threading import current_thread import warnings import os @@ -246,6 +247,8 @@ def select_poller(timeout=0.0, map=None): 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.""" @@ -294,6 +297,8 @@ def poll_poller(timeout=0.0, map=None): if obj is None: continue readwrite(obj, flags) + else: + current_thread().stop.wait(timeout) # Aliases for backward compatibility poll = select_poller @@ -349,6 +354,8 @@ def epoll_poller(timeout=0.0, map=None): 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.""" @@ -383,6 +390,8 @@ def kqueue_poller(timeout=0.0, map=None): if event.filter == select.KQ_FILTER_WRITE: write(obj) kqueue.close() + else: + current_thread().stop.wait(timeout) def loop(timeout=30.0, use_poll=False, map=None, count=None, -- 2.45.1 From d6df4470e1153fc01f32691cdff7bc415c73a4f7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 23 Jan 2018 15:59:58 +0100 Subject: [PATCH 1015/1102] No connection CPU hog fix - the previous fix was incomplete, it shouldn't consume excessive resources now when there are no connections --- src/network/asyncore_pollchoose.py | 35 +++++++++++++----------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index de8ededc..f9dc9ee5 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -398,6 +398,8 @@ 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" @@ -414,27 +416,20 @@ def loop(timeout=30.0, use_poll=False, map=None, count=None, elif hasattr(select, 'select'): poller = select_poller - if count is None: - while map: - # fill buckets first - update_sent() - update_received() - # then poll - poller(timeout, map) + if timeout == 0: + deadline = 0 else: - if timeout == 0: - deadline = 0 - else: - deadline = time.time() + timeout - while map and count > 0: - # fill buckets first - update_sent() - update_received() - subtimeout = deadline - time.time() - if subtimeout <= 0: - break - poller(subtimeout, map) - # then poll + 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: -- 2.45.1 From 870905100594bdf6c1ab37fbf7d2cd9a3fb38d4e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 25 Jan 2018 08:11:42 +0100 Subject: [PATCH 1016/1102] Fix non-ascii logging Tested with UTF-8, KOI8-R and ISO-8859-2 encodings. --- src/debug.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/debug.py b/src/debug.py index b03e8bf9..79c6e64e 100644 --- a/src/debug.py +++ b/src/debug.py @@ -54,7 +54,7 @@ def configureLogging(): 'version': 1, 'formatters': { 'default': { - 'format': '%(asctime)s - %(levelname)s - %(message)s', + 'format': u'%(asctime)s - %(levelname)s - %(message)s', }, }, 'handlers': { -- 2.45.1 From 61ddc1208e21ed51510e09b3ef3ac8c6af37cd4f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 25 Jan 2018 12:58:29 +0200 Subject: [PATCH 1017/1102] No more shared.daemon variable --- src/bitmessagemain.py | 2 -- src/class_singleCleaner.py | 2 +- src/shared.py | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 6f796939..74011f29 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -220,8 +220,6 @@ class Main: elif opt in ("-c", "--curses"): state.curses = True - shared.daemon = daemon - # is the application already running? If yes then exit. shared.thisapp = singleinstance("", daemon) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index ed0ee044..1def6cdb 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -121,7 +121,7 @@ class singleCleaner(threading.Thread, StoppableThread): 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.daemon: + if shared.thisapp.daemon: os._exit(0) shared.needToWriteKnownNodesToDisk = False diff --git a/src/shared.py b/src/shared.py index 34597c78..e2f3c1cc 100644 --- a/src/shared.py +++ b/src/shared.py @@ -49,7 +49,7 @@ clientHasReceivedIncomingConnections = False #used by API command clientStatus numberOfMessagesProcessed = 0 numberOfBroadcastsProcessed = 0 numberOfPubkeysProcessed = 0 -daemon = False + needToWriteKnownNodesToDisk = False # If True, the singleCleaner will write it to disk eventually. maximumLengthOfTimeToBotherResendingMessages = 0 timeOffsetWrongCount = 0 -- 2.45.1 From 0097ea6476a96aa49023d32f33b2277fbb364f59 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 25 Jan 2018 14:29:25 +0200 Subject: [PATCH 1018/1102] The condition which is always False causes critical error #1081 --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e6ff0cd0..5f69228d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2542,7 +2542,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(i, 2).setUnread(False) tableWidget.item(i, 3).setFont(font) # sqlite default limit, unfortunately getting/setting isn't exposed to python - if i % 999 == 999: + if i % 999 == 0: markread += partialUpdate(self.getCurrentFolder(), msgids) msgids = [] -- 2.45.1 From 80fdb08f0369a86e4e65b740c0457b467fdff416 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 25 Jan 2018 23:04:38 +0200 Subject: [PATCH 1019/1102] Made use of helper_sql.sqlExecuteChunked() in the on_action_MarkAllRead --- src/bitmessageqt/__init__.py | 42 ++++++++++++++++-------------------- src/helper_sql.py | 21 ++++++++++++++---- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5f69228d..b43f8163 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2509,48 +2509,42 @@ class MyForm(settingsmixin.SMainWindow): # self.rerenderInboxToLabels() def on_action_MarkAllRead(self): - def partialUpdate(folder, msgids): - if len(msgids) == 0: - return 0 - if folder == 'sent': - return sqlExecute( - "UPDATE sent SET read = 1 WHERE ackdata IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) - else: - return sqlExecute( - "UPDATE inbox SET read = 1 WHERE msgid IN(%s) AND read=0" %(",".join("?"*len(msgids))), *msgids) - - if QtGui.QMessageBox.question(self, "Marking all messages as read?", _translate("MainWindow", "Are you sure you would like to mark all messages read?"), QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: + if QtGui.QMessageBox.question( + self, "Marking all messages as read?", + _translate( + "MainWindow", + "Are you sure you would like to mark all messages read?" + ), QMessageBox.Yes | QMessageBox.No) != QMessageBox.Yes: return addressAtCurrentRow = self.getCurrentAccount() tableWidget = self.getCurrentMessagelist() - if tableWidget.rowCount() == 0: + idCount = tableWidget.rowCount() + if idCount == 0: return - msgids = [] - font = QFont() font.setBold(False) - markread = 0 - - for i in range(0, tableWidget.rowCount()): + msgids = [] + for i in range(0, idCount): msgids.append(str(tableWidget.item( i, 3).data(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) - # sqlite default limit, unfortunately getting/setting isn't exposed to python - if i % 999 == 0: - markread += partialUpdate(self.getCurrentFolder(), msgids) - msgids = [] - if len(msgids) > 0: - markread += partialUpdate(self.getCurrentFolder(), msgids) + 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) + self.propagateUnreadCount( + addressAtCurrentRow, self.getCurrentFolder(), None, 0) def click_NewAddressDialog(self): addresses = [] diff --git a/src/helper_sql.py b/src/helper_sql.py index 7410202b..fec67bef 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -21,8 +21,10 @@ def sqlQuery(sqlStatement, *args): return queryreturn + def sqlExecuteChunked(sqlStatement, idCount, *args): - #SQLITE_MAX_VARIABLE_NUMBER, unfortunately getting/setting isn't exposed to python + # SQLITE_MAX_VARIABLE_NUMBER, + # unfortunately getting/setting isn't exposed to python sqlExecuteChunked.chunkSize = 999 if idCount == 0 or idCount > len(args): @@ -30,15 +32,26 @@ def sqlExecuteChunked(sqlStatement, idCount, *args): totalRowCount = 0 with sqlLock: - for i in range(len(args)-idCount, len(args), sqlExecuteChunked.chunkSize - (len(args)-idCount)): - sqlSubmitQueue.put(sqlStatement) + 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] + args[i:i+sqlExecuteChunked.chunkSize - (len(args)-idCount)]) + 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) -- 2.45.1 From 6fca1631af41aa46f1b30543676b59c553ac9e29 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 25 Jan 2018 23:22:15 +0200 Subject: [PATCH 1020/1102] Made use of helper_sql.sqlExecuteChunked() also in on_action_InboxMarkUnread --- src/bitmessageqt/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b43f8163..98c6dace 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2784,9 +2784,13 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 1).setUnread(True) tableWidget.item(currentRow, 2).setUnread(True) tableWidget.item(currentRow, 3).setFont(font) - #sqlite requires the exact number of ?s to prevent injection - rowcount = sqlExecute('''UPDATE inbox SET read=0 WHERE msgid IN (%s) AND read=1''' % ( - "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) + # for 1081 + idCount = len(inventoryHashesToMarkUnread) + rowcount = sqlExecuteChunked( + '''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''', + idCount, *inventoryHashesToMarkUnread + ) + if rowcount == 1: # performance optimisation self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder()) -- 2.45.1 From 0f61ed9f19940b2895c28eae986f5b085b6c83a9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 28 Jan 2018 08:12:46 +0100 Subject: [PATCH 1021/1102] Optimise UI deleting and undeleting multiple messages - use sqlExecuteChunked and disable UI updates while removing entries --- src/bitmessageqt/__init__.py | 67 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 98c6dace..1ced3809 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2985,54 +2985,61 @@ class MyForm(settingsmixin.SMainWindow): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - unread = False currentRow = 0 folder = self.getCurrentFolder() shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier - while tableWidget.selectedIndexes(): - currentRow = tableWidget.selectedIndexes()[0].row() + tableWidget.setUpdatesEnabled(False); + inventoryHashesToTrash = [] + for row in tableWidget.selectedIndexes(): + currentRow = row.row() inventoryHashToTrash = str(tableWidget.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) - if folder == "trash" or shifted: - sqlExecute('''DELETE FROM inbox WHERE msgid=?''', inventoryHashToTrash) - else: - sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) - if tableWidget.item(currentRow, 0).unread: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) - if folder != "trash" and not shifted: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), 1) - - self.getCurrentMessageTextedit().setText("") + currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) + if inventoryHashToTrash in inventoryHashesToTrash: + continue + inventoryHashesToTrash.append(inventoryHashToTrash) tableWidget.removeRow(currentRow) - self.statusBar().showMessage(_translate( - "MainWindow", "Moved items to trash."), 10000) - if currentRow == 0: - tableWidget.selectRow(currentRow) + idCount = len(inventoryHashesToTrash) + if folder == "trash" or shifted: + sqlExecuteChunked('''DELETE FROM inbox WHERE msgid IN ({0})''', + idCount, *inventoryHashesToTrash) else: - tableWidget.selectRow(currentRow - 1) + sqlExecuteChunked('''UPDATE inbox SET folder='trash' WHERE msgid IN ({0})''', + idCount, *inventoryHashesToTrash) + tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) + self.getCurrentMessageTextedit().setText("") + tableWidget.setUpdatesEnabled(True) + self.propagateUnreadCount(self.getCurrentAccount, folder) + self.statusBar().showMessage(_translate( + "MainWindow", "Moved items to trash."), 10000) def on_action_TrashUndelete(self): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - unread = False currentRow = 0 - while tableWidget.selectedIndexes(): - currentRow = tableWidget.selectedIndexes()[0].row() + tableWidget.setUpdatesEnabled(False) + inventoryHashesToTrash = [] + for row in tableWidget.selectedIndexes(): + currentRow = row.row() inventoryHashToTrash = str(tableWidget.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) - sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) - if tableWidget.item(currentRow, 0).unread: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) - self.getCurrentMessageTextedit().setText("") + currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) + if inventoryHashToTrash in inventoryHashesToTrash: + continue + inventoryHashesToTrash.append(inventoryHashToTrash) tableWidget.removeRow(currentRow) - self.statusBar().showMessage(_translate( - "MainWindow", "Undeleted item."), 10000) if currentRow == 0: tableWidget.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) + self.getCurrentMessageTextedit().setText("") + tableWidget.setUpdatesEnabled(True) + self.propagateUnreadCount(self.getCurrentAccount) + self.statusBar().showMessage(_translate( + "MainWindow", "Undeleted items."), 10000) def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() -- 2.45.1 From ff92cc30c81a7c58775eddda30e35583bed5cda3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 28 Jan 2018 09:16:37 +0100 Subject: [PATCH 1022/1102] Fix previous commit (UI deleting optimisation) --- src/bitmessageqt/__init__.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1ced3809..b3d19017 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2990,14 +2990,15 @@ class MyForm(settingsmixin.SMainWindow): shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier tableWidget.setUpdatesEnabled(False); inventoryHashesToTrash = [] - for row in tableWidget.selectedIndexes(): - currentRow = row.row() - inventoryHashToTrash = str(tableWidget.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - if inventoryHashToTrash in inventoryHashesToTrash: - continue - inventoryHashesToTrash.append(inventoryHashToTrash) - tableWidget.removeRow(currentRow) + # 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) + 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})''', @@ -3019,14 +3020,15 @@ class MyForm(settingsmixin.SMainWindow): currentRow = 0 tableWidget.setUpdatesEnabled(False) inventoryHashesToTrash = [] - for row in tableWidget.selectedIndexes(): - currentRow = row.row() - inventoryHashToTrash = str(tableWidget.item( - currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - if inventoryHashToTrash in inventoryHashesToTrash: - continue - inventoryHashesToTrash.append(inventoryHashToTrash) - tableWidget.removeRow(currentRow) + # 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) + tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) if currentRow == 0: tableWidget.selectRow(currentRow) else: -- 2.45.1 From aabce6bab2e703d713aa19369a51275ec86f03bf Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 28 Jan 2018 12:48:25 +0100 Subject: [PATCH 1023/1102] Fix selection after delete/undelete --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 65b9f5db..ff44bdd4 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3000,6 +3000,7 @@ class MyForm(settingsmixin.SMainWindow): if inventoryHashToTrash in inventoryHashesToTrash: continue inventoryHashesToTrash.append(inventoryHashToTrash) + currentRow = r.topRow() tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) idCount = len(inventoryHashesToTrash) if folder == "trash" or shifted: @@ -3030,6 +3031,7 @@ class MyForm(settingsmixin.SMainWindow): if inventoryHashToTrash in inventoryHashesToTrash: continue inventoryHashesToTrash.append(inventoryHashToTrash) + currentRow = r.topRow() tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) if currentRow == 0: tableWidget.selectRow(currentRow) -- 2.45.1 From cc63c1270bbfe5cdc33ae5705de68d5f0700a546 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 28 Jan 2018 16:13:07 +0100 Subject: [PATCH 1024/1102] Fix message content display after deleting/undeleting --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ff44bdd4..10fae547 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3001,6 +3001,7 @@ class MyForm(settingsmixin.SMainWindow): 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: @@ -3010,7 +3011,6 @@ class MyForm(settingsmixin.SMainWindow): sqlExecuteChunked('''UPDATE inbox SET folder='trash' WHERE msgid IN ({0})''', idCount, *inventoryHashesToTrash) tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) - self.getCurrentMessageTextedit().setText("") tableWidget.setUpdatesEnabled(True) self.propagateUnreadCount(self.getCurrentAccount, folder) self.statusBar().showMessage(_translate( @@ -3032,6 +3032,7 @@ class MyForm(settingsmixin.SMainWindow): continue inventoryHashesToTrash.append(inventoryHashToTrash) currentRow = r.topRow() + self.getCurrentMessageTextedit().setText("") tableWidget.model().removeRows(r.topRow(), r.bottomRow()-r.topRow()+1) if currentRow == 0: tableWidget.selectRow(currentRow) @@ -3041,7 +3042,6 @@ class MyForm(settingsmixin.SMainWindow): sqlExecuteChunked('''UPDATE inbox SET folder='inbox' WHERE msgid IN({0})''', idCount, *inventoryHashesToTrash) tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) - self.getCurrentMessageTextedit().setText("") tableWidget.setUpdatesEnabled(True) self.propagateUnreadCount(self.getCurrentAccount) self.statusBar().showMessage(_translate( -- 2.45.1 From 25ef9fec51a6a95eb2753309f066c9fb201d191c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 24 Jan 2018 18:37:05 +0200 Subject: [PATCH 1025/1102] Added menu entry "File -> Go offline/Go online" switching dontconnect config variable and "Work offline" option to connectDialog. --- src/bitmessageqt/__init__.py | 13 ++++++++++++- src/bitmessageqt/bitmessageui.py | 13 +++++++++++++ src/bitmessageqt/connect.py | 8 ++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 10fae547..f0ac0f5d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -143,6 +143,8 @@ class MyForm(settingsmixin.SMainWindow): 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, @@ -1471,7 +1473,7 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().remove_option( 'bitmessagesettings', 'dontconnect') BMConfigParser().save() - else: + elif self.connectDialogInstance.ui.radioButtonConfigureNetwork.isChecked(): self.click_actionSettings() def showMigrationWizard(self, level): @@ -2585,6 +2587,14 @@ class MyForm(settingsmixin.SMainWindow): else: logger.debug('new address dialog box rejected') + 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) + # Quit selected from menu or application indicator def quit(self): '''quit_msg = "Are you sure you want to exit Bitmessage?" @@ -4446,6 +4456,7 @@ def run(): 'bitmessagesettings', 'dontconnect') if myapp._firstrun: myapp.showConnectDialog() # ask the user if we may connect + myapp.ui.updateNetworkSwitchMenuLabel() # try: # if BMConfigParser().get('bitmessagesettings', 'mailchuck') < 1: diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index f001487e..3eb04101 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -586,6 +586,8 @@ 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) @@ -621,6 +623,7 @@ 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.actionExit) self.menuSettings.addAction(self.actionSettings) self.menuHelp.addAction(self.actionHelp) @@ -641,6 +644,16 @@ class Ui_MainWindow(object): 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) + ) + def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) self.treeWidgetYourIdentities.headerItem().setText(0, _translate("MainWindow", "Identities", None)) diff --git a/src/bitmessageqt/connect.py b/src/bitmessageqt/connect.py index 1e224afb..9151156f 100644 --- a/src/bitmessageqt/connect.py +++ b/src/bitmessageqt/connect.py @@ -39,13 +39,16 @@ class Ui_connectDialog(object): self.radioButtonConfigureNetwork = QtGui.QRadioButton(connectDialog) self.radioButtonConfigureNetwork.setObjectName(_fromUtf8("radioButtonConfigureNetwork")) self.gridLayout.addWidget(self.radioButtonConfigureNetwork, 2, 0, 1, 2) + self.radioButtonWorkOffline = QtGui.QRadioButton(connectDialog) + self.radioButtonWorkOffline.setObjectName(_fromUtf8("radioButtonWorkOffline")) + self.gridLayout.addWidget(self.radioButtonWorkOffline, 3, 0, 1, 2) spacerItem = QtGui.QSpacerItem(185, 24, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) + self.gridLayout.addItem(spacerItem, 4, 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.gridLayout.addWidget(self.buttonBox, 4, 1, 1, 1) self.retranslateUi(connectDialog) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), connectDialog.accept) @@ -57,4 +60,5 @@ class Ui_connectDialog(object): 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)) + self.radioButtonWorkOffline.setText(_translate("connectDialog", "Work offline", None)) -- 2.45.1 From 9e79386595bd7f8c2fa43b837e5afd1ca5b85fc5 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 30 Jan 2018 13:55:01 +0200 Subject: [PATCH 1026/1102] Set state to "close" and call `handle_close()` for all connections --- src/network/connectionpool.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 44534a76..793e284f 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -203,6 +203,14 @@ class BMConnectionPool(object): continue 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: -- 2.45.1 From 81c80aa98ff4404c0cd3762c769f1ed16863e7c1 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 6 Oct 2017 14:45:27 +0300 Subject: [PATCH 1027/1102] Use AddAddressDialog for "Add sender to your Addres Book" context menu --- src/bitmessageqt/__init__.py | 47 +++++++++++++++++------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f0ac0f5d..5e2ec982 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2138,25 +2138,31 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway registration request"), 10000) - def click_pushButtonAddAddressBook(self): - self.AddAddressDialogInstance = AddAddressDialog(self) - if self.AddAddressDialogInstance.exec_(): - if self.AddAddressDialogInstance.ui.labelAddressCheck.text() == _translate("MainWindow", "Address is valid."): + def click_pushButtonAddAddressBook(self, dialog=None): + if not dialog: + dialog = AddAddressDialog(self) + if dialog.exec_(): + if dialog.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) + address = addBMIfNotPresent( + str(dialog.ui.lineEditAddress.text())) + label = str(dialog.ui.newAddressLabel.text().toUtf8()) + self.addEntryToAddressBook(address, label) else: self.statusBar().showMessage(_translate( - "MainWindow", "The address you entered was invalid. Ignoring it."), 10000) + "MainWindow", + "The address you entered was invalid. Ignoring it." + ), 10000) - def addEntryToAddressBook(self,address,label): - queryreturn = sqlQuery('''select * from addressbook where address=?''', address) + def addEntryToAddressBook(self, address, label): + queryreturn = sqlQuery( + '''select * from addressbook where address=?''', address) if queryreturn == []: - sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', str(label), address) + sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', + label, address) self.rerenderMessagelistFromLabels() self.rerenderMessagelistToLabels() self.rerenderAddressBook() @@ -2935,19 +2941,10 @@ class MyForm(settingsmixin.SMainWindow): # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() addressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 1).data(Qt.UserRole) - # Let's make sure that it isn't already in the address book - queryreturn = sqlQuery('''select * from addressbook where address=?''', - addressAtCurrentInboxRow) - if queryreturn == []: - sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', - '--New entry. Change label in Address Book.--', - addressAtCurrentInboxRow) - self.rerenderAddressBook() - self.statusBar().showMessage(_translate( - "MainWindow", "Entry added to the Address Book. Edit the label to your liking."), 10000) - 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."), 10000) + self.ui.tabWidget.setCurrentIndex(1) + dialog = AddAddressDialog(self) + dialog.ui.lineEditAddress.setText(addressAtCurrentInboxRow) + self.click_pushButtonAddAddressBook(dialog) def on_action_InboxAddSenderToBlackList(self): tableWidget = self.getCurrentMessagelist() -- 2.45.1 From d9d9f9d7874117e75e5f90763b880adcca3b1d91 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 12 Oct 2017 23:36:47 +0300 Subject: [PATCH 1028/1102] Returned AddAddressDialog and NewSubscriptionDialog into dialogs module where it's been initialized by loading the ui-files. --- src/bitmessageqt/__init__.py | 171 ++++++++-------------- src/bitmessageqt/addaddressdialog.py | 65 -------- src/bitmessageqt/addaddressdialog.ui | 25 +++- src/bitmessageqt/dialogs.py | 115 +++++++++++---- src/bitmessageqt/newsubscriptiondialog.py | 69 --------- src/bitmessageqt/newsubscriptiondialog.ui | 31 +++- 6 files changed, 200 insertions(+), 276 deletions(-) delete mode 100644 src/bitmessageqt/addaddressdialog.py delete mode 100644 src/bitmessageqt/newsubscriptiondialog.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5e2ec982..10cbc8f9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -27,7 +27,6 @@ from newaddresswizard import * from messageview import MessageView from migrationwizard import * from foldertree import * -from newsubscriptiondialog import * from regenerateaddresses import * from newchandialog import * from safehtmlparser import * @@ -51,14 +50,14 @@ import debug import random import string from datetime import datetime, timedelta -from helper_sql import * from helper_ackPayload import genAckPayload +from helper_sql import sqlQuery, sqlExecute, sqlExecuteChunked, sqlStoredProcedure import helper_search import l10n import openclpow from utils import str_broadcast_subscribers, avatarize from account import * -from dialogs import AddAddressDialog +import dialogs from helper_generic import powQueueSize from inventory import ( Inventory, PendingDownloadQueue, PendingUpload, @@ -2140,71 +2139,85 @@ class MyForm(settingsmixin.SMainWindow): def click_pushButtonAddAddressBook(self, dialog=None): if not dialog: - dialog = AddAddressDialog(self) + dialog = dialogs.AddAddressDialog(self) if dialog.exec_(): - if dialog.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(dialog.ui.lineEditAddress.text())) - label = str(dialog.ui.newAddressLabel.text().toUtf8()) - self.addEntryToAddressBook(address, label) - else: + if not dialog.valid: self.statusBar().showMessage(_translate( "MainWindow", "The address you entered was invalid. Ignoring it." - ), 10000) + ), 10000) + return + + address = addBMIfNotPresent(str(dialog.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. + if shared.isAddressInMyAddressBook(address): + 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." + ), 10000) + return + label = str(dialog.lineEditLabel.text().toUtf8()) + self.addEntryToAddressBook(address, label) def addEntryToAddressBook(self, address, label): - queryreturn = sqlQuery( - '''select * from addressbook where address=?''', address) - if queryreturn == []: - sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', - label, address) - self.rerenderMessagelistFromLabels() - self.rerenderMessagelistToLabels() - self.rerenderAddressBook() - 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."), 10000) + if shared.isAddressInMyAddressBook(address): + return + sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', label, address) + self.rerenderMessagelistFromLabels() + self.rerenderMessagelistToLabels() + self.rerenderAddressBook() def addSubscription(self, address, label): - address = addBMIfNotPresent(address) - #This should be handled outside of this function, for error displaying and such, but it must also be checked here. + # 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 (?,?,?)''',str(label),address,True) + # Add to database (perhaps this should be separated from the MyForm class) + sqlExecute( + '''INSERT INTO subscriptions VALUES (?,?,?)''', + label, address, True + ) self.rerenderMessagelistFromLabels() shared.reloadBroadcastSendersForWhichImWatching() self.rerenderAddressBook() self.rerenderTabTreeSubscriptions() def click_pushButtonAddSubscription(self): - 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."), 10000) + dialog = dialogs.NewSubscriptionDialog(self) + if dialog.exec_(): + if not dialog.valid: + self.statusBar().showMessage(_translate( + "MainWindow", + "The address you entered was invalid. Ignoring it." + ), 10000) 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. + + address = addBMIfNotPresent(str(dialog.lineEditAddress.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 subscriptions twice. Perhaps rename the existing one if you want."), 10000) + self.statusBar().showMessage(_translate( + "MainWindow", + "Error: You cannot add the same address to your" + " subscriptions twice. Perhaps rename the existing one" + " if you want." + ), 10000) return - label = self.NewSubscriptionDialogInstance.ui.newsubscriptionlabel.text().toUtf8() + label = str(dialog.lineEditLabel.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) - Inventory().flush() - doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( - addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() - tag = doubleHashOfAddressData[32:] - for value in Inventory().by_type_and_tag(3, tag): - queues.objectProcessorQueue.put((value.type, value.payload)) + # 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 + )) def click_pushButtonStatusIcon(self): logger.debug('click_pushButtonStatusIcon') @@ -2942,8 +2955,8 @@ class MyForm(settingsmixin.SMainWindow): addressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 1).data(Qt.UserRole) self.ui.tabWidget.setCurrentIndex(1) - dialog = AddAddressDialog(self) - dialog.ui.lineEditAddress.setText(addressAtCurrentInboxRow) + dialog = dialogs.AddAddressDialog(self) + dialog.lineEditAddress.setText(addressAtCurrentInboxRow) self.click_pushButtonAddAddressBook(dialog) def on_action_InboxAddSenderToBlackList(self): @@ -4280,64 +4293,6 @@ class EmailGatewayRegistrationDialog(QtGui.QDialog): QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) -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: - Inventory().flush() - doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( - addressVersion) + encodeVarint(streamNumber) + ripe).digest()).digest() - tag = doubleHashOfAddressData[32:] - count = len(Inventory().by_type_and_tag(3, tag)) - if count == 0: - self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "There are no recent broadcasts from this address to display.")) - else: - self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) - self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "Display the %1 recent broadcast(s) from this address.").arg(count)) - - class NewAddressDialog(QtGui.QDialog): def __init__(self, parent): diff --git a/src/bitmessageqt/addaddressdialog.py b/src/bitmessageqt/addaddressdialog.py deleted file mode 100644 index 5ed19e0a..00000000 --- a/src/bitmessageqt/addaddressdialog.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- 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 d7963e0a..09701fa4 100644 --- a/src/bitmessageqt/addaddressdialog.ui +++ b/src/bitmessageqt/addaddressdialog.ui @@ -7,9 +7,15 @@ 0 0 368 - 162 + 232 + + + 368 + 200 + + Add new entry @@ -25,7 +31,7 @@ - + @@ -47,7 +53,7 @@ - + Qt::Horizontal @@ -57,6 +63,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index d8133eb1..5eeaaadd 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -1,42 +1,107 @@ from PyQt4 import QtCore, QtGui -from addaddressdialog import Ui_AddAddressDialog -from addresses import decodeAddress +from addresses import decodeAddress, encodeVarint from tr import _translate +from retranslateui import RetranslateMixin +import widgets + +import hashlib +from inventory import Inventory -class AddAddressDialog(QtGui.QDialog): +class AddressCheckMixin(object): - 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( + 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, a, b, c = decodeAddress(str(QString)) - if status == 'missingbm': - self.ui.labelAddressCheck.setText(_translate( + 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", "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).")) + self.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.")) + 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.ui.labelAddressCheck.setText(_translate( + self.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.")) + self.labelAddressCheck.setText(_translate( + "MainWindow", + "Some data encoded in the address is too short." + )) elif status == 'ripetoolong': - self.ui.labelAddressCheck.setText(_translate( + self.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.")) + self.labelAddressCheck.setText(_translate( + "MainWindow", + "Some data encoded in the address is malformed." + )) + + +class AddAddressDialog(QtGui.QDialog, RetranslateMixin, AddressCheckMixin): + + def __init__(self, parent=None): + super(AddAddressDialog, self).__init__(parent) + widgets.load('addaddressdialog.ui', self) + AddressCheckMixin.__init__(self) + + +class NewSubscriptionDialog( + QtGui.QDialog, RetranslateMixin, AddressCheckMixin): + + 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 %1 recent broadcast(s) from this address." + ).arg(count)) diff --git a/src/bitmessageqt/newsubscriptiondialog.py b/src/bitmessageqt/newsubscriptiondialog.py deleted file mode 100644 index a63cce4a..00000000 --- a/src/bitmessageqt/newsubscriptiondialog.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- 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", "Enter an address above.", None)) - diff --git a/src/bitmessageqt/newsubscriptiondialog.ui b/src/bitmessageqt/newsubscriptiondialog.ui index ed8615f4..ec67efa3 100644 --- a/src/bitmessageqt/newsubscriptiondialog.ui +++ b/src/bitmessageqt/newsubscriptiondialog.ui @@ -7,9 +7,15 @@ 0 0 368 - 173 + 254 + + + 368 + 200 + + Add new entry @@ -22,7 +28,7 @@ - + @@ -32,7 +38,7 @@ - + @@ -44,17 +50,17 @@ - + false - CheckBox + Enter an address above. - + Qt::Horizontal @@ -64,6 +70,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + -- 2.45.1 From e2e7e16ab703477a42e25e4d411572fdb2d64035 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 13 Oct 2017 01:36:54 +0300 Subject: [PATCH 1029/1102] Moved aboutDialog and iconGlossaryDialog also into dialogs module --- src/bitmessageqt/__init__.py | 37 +----- src/bitmessageqt/about.py | 74 ------------ src/bitmessageqt/about.ui | 187 ++++++++++++++----------------- src/bitmessageqt/dialogs.py | 26 +++++ src/bitmessageqt/iconglossary.py | 98 ---------------- src/bitmessageqt/iconglossary.ui | 2 +- 6 files changed, 113 insertions(+), 311 deletions(-) delete mode 100644 src/bitmessageqt/about.py delete mode 100644 src/bitmessageqt/iconglossary.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 10cbc8f9..a4ce38ac 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -35,9 +35,7 @@ from emailgateway import * from settings import * import settingsmixin import support -from about import * from help import * -from iconglossary import * from connect import * import locale import sys @@ -62,6 +60,7 @@ from helper_generic import powQueueSize from inventory import ( Inventory, PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException) +from uisignaler import UISignaler import knownnodes import paths from proofofwork import getPowType @@ -70,9 +69,9 @@ import shutdown import state from statusbar import BMStatusBar from network.asyncore_pollchoose import set_rates -from version import softwareVersion import sound + try: from plugins.plugin import get_plugin, get_plugins except ImportError: @@ -2220,10 +2219,7 @@ class MyForm(settingsmixin.SMainWindow): )) def click_pushButtonStatusIcon(self): - logger.debug('click_pushButtonStatusIcon') - self.iconGlossaryInstance = iconGlossaryDialog(self) - if self.iconGlossaryInstance.exec_(): - pass + dialogs.IconGlossaryDialog(self, config=BMConfigParser()).exec_() def click_actionHelp(self): self.helpDialogInstance = helpDialog(self) @@ -2233,8 +2229,7 @@ class MyForm(settingsmixin.SMainWindow): support.createSupportMessage(self) def click_actionAbout(self): - self.aboutDialogInstance = aboutDialog(self) - self.aboutDialogInstance.exec_() + dialogs.AboutDialog(self).exec_() def click_actionSettings(self): self.settingsDialogInstance = settingsDialog(self) @@ -3975,16 +3970,6 @@ class connectDialog(QtGui.QDialog): 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.label.setText("PyBitmessage " + softwareVersion) - self.ui.labelVersion.setText(paths.lastCommit()) - class regenerateAddressesDialog(QtGui.QDialog): @@ -4312,18 +4297,6 @@ class NewAddressDialog(QtGui.QDialog): 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(BMConfigParser().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. @@ -4332,8 +4305,6 @@ class myTableWidgetItem(QTableWidgetItem): def __lt__(self, other): return int(self.data(33).toPyObject()) < int(other.data(33).toPyObject()) -from uisignaler import UISignaler - app = None myapp = None diff --git a/src/bitmessageqt/about.py b/src/bitmessageqt/about.py deleted file mode 100644 index a3483675..00000000 --- a/src/bitmessageqt/about.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- 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(10, 106, 341, 20)) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label.setFont(font) - self.label.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignVCenter) - self.label.setObjectName(_fromUtf8("label")) - self.labelVersion = QtGui.QLabel(aboutDialog) - self.labelVersion.setGeometry(QtCore.QRect(10, 116, 341, 41)) - self.labelVersion.setObjectName(_fromUtf8("labelVersion")) - self.labelVersion.setAlignment(QtCore.Qt.AlignCenter|QtCore.Qt.AlignVCenter) - 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-2016 Jonathan Warren
Copyright © 2013-2016 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 3deab41b..d09cbc4d 100644 --- a/src/bitmessageqt/about.ui +++ b/src/bitmessageqt/about.ui @@ -6,117 +6,94 @@ 0 0 - 360 - 315 + 430 + 340 About - - - - 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 - - + + + + + + + + :/newPrefix/images/can-icon-24px.png + + + true + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + PyBitmessage + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + <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 + + + + - + + + buttonBox diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 5eeaaadd..f9615612 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -5,7 +5,9 @@ from retranslateui import RetranslateMixin import widgets import hashlib +import paths from inventory import Inventory +from version import softwareVersion class AddressCheckMixin(object): @@ -105,3 +107,27 @@ class NewSubscriptionDialog( "MainWindow", "Display the %1 recent broadcast(s) from this address." ).arg(count)) + + +class AboutDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent=None): + super(AboutDialog, self).__init__(parent) + widgets.load('about.ui', self) + commit = paths.lastCommit()[:7] + label = "PyBitmessage " + softwareVersion + if commit: + label += '-' + commit + self.labelVersion.setText(label) + QtGui.QWidget.resize(self, 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) + + self.labelPortNumber.setText(_translate( + "iconGlossaryDialog", + "You are using TCP port %1. (This can be changed in the settings)." + ).arg(config.getint('bitmessagesettings', 'port'))) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) diff --git a/src/bitmessageqt/iconglossary.py b/src/bitmessageqt/iconglossary.py deleted file mode 100644 index 32d92db6..00000000 --- a/src/bitmessageqt/iconglossary.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- 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 870a90ee..1bac94c8 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). -- 2.45.1 From c965a1d2aaad6b387868d5f7e0cd21c5e60df731 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 16 Oct 2017 16:09:52 +0300 Subject: [PATCH 1030/1102] Moved helpDialog and connectDialog also into dialogs module --- src/bitmessageqt/__init__.py | 35 ++++---------------- src/bitmessageqt/connect.py | 64 ------------------------------------ src/bitmessageqt/connect.ui | 11 +++++-- src/bitmessageqt/dialogs.py | 14 ++++++++ src/bitmessageqt/help.py | 48 --------------------------- 5 files changed, 29 insertions(+), 143 deletions(-) delete mode 100644 src/bitmessageqt/connect.py delete mode 100644 src/bitmessageqt/help.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a4ce38ac..ac753f5f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -35,8 +35,6 @@ from emailgateway import * from settings import * import settingsmixin import support -from help import * -from connect import * import locale import sys import time @@ -1465,13 +1463,13 @@ class MyForm(settingsmixin.SMainWindow): NewChanDialog(self) def showConnectDialog(self): - self.connectDialogInstance = connectDialog(self) - if self.connectDialogInstance.exec_(): - if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked(): + dialog = dialogs.ConnectDialog(self) + if dialog.exec_(): + if dialog.radioButtonConnectNow.isChecked(): BMConfigParser().remove_option( 'bitmessagesettings', 'dontconnect') BMConfigParser().save() - elif self.connectDialogInstance.ui.radioButtonConfigureNetwork.isChecked(): + elif dialog.radioButtonConfigureNetwork.isChecked(): self.click_actionSettings() def showMigrationWizard(self, level): @@ -1480,7 +1478,7 @@ class MyForm(settingsmixin.SMainWindow): pass else: pass - + def changeEvent(self, event): if event.type() == QtCore.QEvent.LanguageChange: self.ui.retranslateUi(self) @@ -2222,8 +2220,7 @@ class MyForm(settingsmixin.SMainWindow): dialogs.IconGlossaryDialog(self, config=BMConfigParser()).exec_() def click_actionHelp(self): - self.helpDialogInstance = helpDialog(self) - self.helpDialogInstance.exec_() + dialogs.HelpDialog(self).exec_() def click_actionSupport(self): support.createSupportMessage(self) @@ -3949,26 +3946,6 @@ class MyForm(settingsmixin.SMainWindow): 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 regenerateAddressesDialog(QtGui.QDialog): diff --git a/src/bitmessageqt/connect.py b/src/bitmessageqt/connect.py deleted file mode 100644 index 9151156f..00000000 --- a/src/bitmessageqt/connect.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- 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) - self.radioButtonWorkOffline = QtGui.QRadioButton(connectDialog) - self.radioButtonWorkOffline.setObjectName(_fromUtf8("radioButtonWorkOffline")) - self.gridLayout.addWidget(self.radioButtonWorkOffline, 3, 0, 1, 2) - spacerItem = QtGui.QSpacerItem(185, 24, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout.addItem(spacerItem, 4, 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, 4, 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)) - self.radioButtonWorkOffline.setText(_translate("connectDialog", "Work offline", None)) - diff --git a/src/bitmessageqt/connect.ui b/src/bitmessageqt/connect.ui index 74173860..8b76f5ac 100644 --- a/src/bitmessageqt/connect.ui +++ b/src/bitmessageqt/connect.ui @@ -38,7 +38,14 @@ - + + + + Work offline + + + + Qt::Horizontal @@ -51,7 +58,7 @@ - + Qt::Horizontal diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index f9615612..3b2cce2d 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -131,3 +131,17 @@ class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): "You are using TCP port %1. (This can be changed in the settings)." ).arg(config.getint('bitmessagesettings', 'port'))) QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + +class HelpDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent=None): + super(HelpDialog, self).__init__(parent) + widgets.load('help.ui', self) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + +class ConnectDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent=None): + super(ConnectDialog, self).__init__(parent) + widgets.load('connect.ui', self) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) diff --git a/src/bitmessageqt/help.py b/src/bitmessageqt/help.py deleted file mode 100644 index ff876514..00000000 --- a/src/bitmessageqt/help.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- 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)) - -- 2.45.1 From 62a930c374c2f416f64764331a51ed507602075a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 17 Oct 2017 18:00:27 +0300 Subject: [PATCH 1031/1102] Moved SpecialAddressBehaviorDialog into dialogs module --- src/bitmessageqt/__init__.py | 54 +----------------- src/bitmessageqt/dialogs.py | 65 ++++++++++++++++++++++ src/bitmessageqt/specialaddressbehavior.py | 64 --------------------- 3 files changed, 66 insertions(+), 117 deletions(-) delete mode 100644 src/bitmessageqt/specialaddressbehavior.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ac753f5f..4cb388a4 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -30,7 +30,6 @@ from foldertree import * from regenerateaddresses import * from newchandialog import * from safehtmlparser import * -from specialaddressbehavior import * from emailgateway import * from settings import * import settingsmixin @@ -2449,31 +2448,7 @@ class MyForm(settingsmixin.SMainWindow): pass def on_action_SpecialAddressBehaviorDialog(self): - self.dialog = SpecialAddressBehaviorDialog(self) - # For Modal dialogs - if self.dialog.exec_(): - addressAtCurrentRow = self.getCurrentAccount() - if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): - return - if self.dialog.ui.radioButtonBehaveNormalAddress.isChecked(): - BMConfigParser().set(str( - addressAtCurrentRow), 'mailinglist', 'false') - # Set the color to either black or grey - if BMConfigParser().getboolean(addressAtCurrentRow, 'enabled'): - self.setCurrentItemColor(QApplication.palette() - .text().color()) - else: - self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) - else: - BMConfigParser().set(str( - addressAtCurrentRow), 'mailinglist', 'true') - BMConfigParser().set(str(addressAtCurrentRow), 'mailinglistname', str( - self.dialog.ui.lineEditMailingListName.text().toUtf8())) - self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta - self.rerenderComboBoxSendFrom() - self.rerenderComboBoxSendFromBroadcast() - BMConfigParser().save() - self.rerenderMessagelistToLabels() + dialogs.SpecialAddressBehaviorDialog(self, BMConfigParser()) def on_action_EmailGatewayDialog(self): self.dialog = EmailGatewayDialog(self) @@ -4190,33 +4165,6 @@ 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 - addressAtCurrentRow = parent.getCurrentAccount() - if not BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'chan'): - if BMConfigParser().safeGetBoolean(addressAtCurrentRow, 'mailinglist'): - self.ui.radioButtonBehaviorMailingList.click() - else: - self.ui.radioButtonBehaveNormalAddress.click() - try: - mailingListName = BMConfigParser().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 EmailGatewayDialog(QtGui.QDialog): def __init__(self, parent): diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 3b2cce2d..5e0d9718 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -145,3 +145,68 @@ class ConnectDialog(QtGui.QDialog, RetranslateMixin): super(ConnectDialog, self).__init__(parent) widgets.load('connect.ui', self) 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( + "MainWindow", + "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() diff --git a/src/bitmessageqt/specialaddressbehavior.py b/src/bitmessageqt/specialaddressbehavior.py deleted file mode 100644 index 78ff890d..00000000 --- a/src/bitmessageqt/specialaddressbehavior.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- 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)) - -- 2.45.1 From f3808212b5547d709f0de085d583f64c4603772f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 18 Oct 2017 18:42:59 +0300 Subject: [PATCH 1032/1102] Added link to github into labelVersion in AboutDialog --- src/bitmessageqt/about.ui | 2 +- src/bitmessageqt/dialogs.py | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/about.ui b/src/bitmessageqt/about.ui index d09cbc4d..099875c0 100644 --- a/src/bitmessageqt/about.ui +++ b/src/bitmessageqt/about.ui @@ -39,7 +39,7 @@ - PyBitmessage + <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::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 5e0d9718..0fffd01a 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -114,11 +114,15 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin): super(AboutDialog, self).__init__(parent) widgets.load('about.ui', self) commit = paths.lastCommit()[:7] - label = "PyBitmessage " + softwareVersion + version = softwareVersion if commit: - label += '-' + commit - self.labelVersion.setText(label) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + version += '-' + commit + self.labelVersion.setText( + self.labelVersion.text().replace( + ':version:', version + ).replace(':branch:', commit or 'v%s' % version) + ) + self.labelVersion.setOpenExternalLinks(True) class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): -- 2.45.1 From b9cd571d9b1d93c6cea37917d58b2d0b7fbe6890 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 3 Nov 2017 14:28:48 +0200 Subject: [PATCH 1033/1102] Hide redundant QGroupBox title --- src/bitmessageqt/dialogs.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 0fffd01a..ce1702df 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -130,6 +130,9 @@ class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): 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)." -- 2.45.1 From 20288d4ab420470ab573b470f22c0fbcfe95f77a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 7 Nov 2017 13:46:23 +0200 Subject: [PATCH 1034/1102] Try to replace copyright year from last commit date --- src/bitmessageqt/dialogs.py | 15 +++++++++++++-- src/bitmessageqt/support.py | 4 ++-- src/paths.py | 17 ++++++++++++----- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index ce1702df..ef22fd3b 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -113,10 +113,11 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin): def __init__(self, parent=None): super(AboutDialog, self).__init__(parent) widgets.load('about.ui', self) - commit = paths.lastCommit()[:7] + last_commit = paths.lastCommit() version = softwareVersion + commit = last_commit.get('commit') if commit: - version += '-' + commit + version += '-' + commit[:7] self.labelVersion.setText( self.labelVersion.text().replace( ':version:', version @@ -124,6 +125,16 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin): ) self.labelVersion.setOpenExternalLinks(True) + try: + self.label_2.setText( + self.label_2.text().replace( + '2017', str(last_commit.get('time').year) + )) + except AttributeError: + pass + + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): def __init__(self, parent=None, config=None): diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 03b302e6..db690a2b 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -85,9 +85,9 @@ def createSupportMessage(myapp): return myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) - + version = softwareVersion - commit = paths.lastCommit() + commit = paths.lastCommit().get('commit') if commit: version += " GIT " + commit diff --git a/src/paths.py b/src/paths.py index 0f843edf..325fcd8b 100644 --- a/src/paths.py +++ b/src/paths.py @@ -1,5 +1,7 @@ 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 @@ -95,13 +97,18 @@ def tail(f, lines=20): 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') - version = "" - if (path.isfile(githeadfile)): + result = {} + if path.isfile(githeadfile): try: with open(githeadfile, 'rt') as githead: - version = tail(githead, 1).split()[1] - except IOError: + 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 version + return result -- 2.45.1 From b899086d917433e13962f8cb2b458c58f811a63d Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 18 Jan 2018 16:14:29 +0200 Subject: [PATCH 1035/1102] Followed the recommendation #527 about tab indexes --- src/bitmessageqt/__init__.py | 82 ++++++++++++++++++++++--------- src/bitmessageqt/bitmessageui.py | 8 ++- src/bitmessageqt/messageview.py | 19 ++++--- src/bitmessageqt/newchandialog.py | 4 +- src/bitmessageqt/support.py | 8 ++- 5 files changed, 86 insertions(+), 35 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4cb388a4..60e1b05e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -884,7 +884,9 @@ class MyForm(settingsmixin.SMainWindow): def appIndicatorInbox(self, item=None): self.appIndicatorShow() # select inbox - self.ui.tabWidget.setCurrentIndex(0) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.inbox) + ) self.ui.treeWidgetYourIdentities.setCurrentItem( self.ui.treeWidgetYourIdentities.topLevelItem(0).child(0) ) @@ -898,18 +900,24 @@ class MyForm(settingsmixin.SMainWindow): # Show the program window and select send tab def appIndicatorSend(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.send) + ) # Show the program window and select subscriptions tab def appIndicatorSubscribe(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex(2) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.subscriptions) + ) # Show the program window and select channels tab def appIndicatorChannel(self): self.appIndicatorShow() - self.ui.tabWidget.setCurrentIndex(3) - + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.chans) + ) + 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") @@ -1373,8 +1381,12 @@ class MyForm(settingsmixin.SMainWindow): currentAddress = self.getCurrentAccount() if currentAddress: self.setSendFromComboBox(currentAddress) - self.ui.tabWidgetSend.setCurrentIndex(0) - self.ui.tabWidget.setCurrentIndex(1) + 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: @@ -1455,7 +1467,9 @@ class MyForm(settingsmixin.SMainWindow): return queues.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) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.chans) + ) # opens 'join chan' dialog def click_actionJoinChan(self): @@ -1775,7 +1789,8 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().clearMessage() - if self.ui.tabWidgetSend.currentIndex() == 0: + if self.ui.tabWidgetSend.currentIndex() == \ + self.ui.tabWidgetSend.indexOf(self.ui.sendDirect): # message to specific people sendMessageToPeople = True fromAddress = str(self.ui.comboBoxSendFrom.itemData( @@ -1979,7 +1994,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) self.ui.lineEditSubjectBroadcast.setText('') self.ui.textEditMessageBroadcast.reset() - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.send) + ) self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) self.statusBar().showMessage(_translate( "MainWindow", "Broadcast queued."), 10000) @@ -2009,10 +2026,12 @@ class MyForm(settingsmixin.SMainWindow): def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. - if BMConfigParser().safeGetBoolean(str(address), 'mailinglist'): - self.ui.tabWidgetSend.setCurrentIndex(1) - else: - self.ui.tabWidgetSend.setCurrentIndex(0) + self.ui.tabWidgetSend.setCurrentIndex( + self.ui.tabWidgetSend.indexOf( + self.ui.sendBroadcast + if BMConfigParser().safeGetBoolean(str(address), 'mailinglist') + else self.ui.sendDirect + )) def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() @@ -2480,8 +2499,12 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(acct.toAddress) self.ui.lineEditSubject.setText(acct.subject) self.ui.textEditMessage.setText(acct.message) - self.ui.tabWidgetSend.setCurrentIndex(0) - self.ui.tabWidget.setCurrentIndex(1) + 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() elif self.dialog.ui.radioButtonRegister.isChecked(): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) @@ -2870,7 +2893,9 @@ class MyForm(settingsmixin.SMainWindow): 'message': self.ui.textEditMessage } if toAddressAtCurrentInboxRow == str_broadcast_subscribers: - self.ui.tabWidgetSend.setCurrentIndex(0) + self.ui.tabWidgetSend.setCurrentIndex( + self.ui.tabWidgetSend.indexOf(self.ui.sendDirect) + ) # toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow elif not BMConfigParser().has_section(toAddressAtCurrentInboxRow): QtGui.QMessageBox.information(self, _translate("MainWindow", "Address is gone"), _translate( @@ -2880,13 +2905,16 @@ class MyForm(settingsmixin.SMainWindow): "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) else: self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow) - if self.ui.tabWidgetSend.currentIndex() == 1: + 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(1) + self.ui.tabWidgetSend.setCurrentIndex(broadcast_tab_index) toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow if fromAddressAtCurrentInboxRow == tableWidget.item(currentInboxRow, 1).label or ( isinstance(acct, GatewayAccount) and fromAddressAtCurrentInboxRow == acct.relayAddress): @@ -2910,7 +2938,9 @@ class MyForm(settingsmixin.SMainWindow): widget['subject'].setText(tableWidget.item(currentInboxRow, 2).label) else: widget['subject'].setText('Re: ' + tableWidget.item(currentInboxRow, 2).label) - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.send) + ) widget['message'].setFocus() def on_action_InboxAddSenderToAddressBook(self): @@ -2921,7 +2951,9 @@ class MyForm(settingsmixin.SMainWindow): # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() addressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 1).data(Qt.UserRole) - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.send) + ) dialog = dialogs.AddAddressDialog(self) dialog.lineEditAddress.setText(addressAtCurrentInboxRow) self.click_pushButtonAddAddressBook(dialog) @@ -3170,7 +3202,9 @@ class MyForm(settingsmixin.SMainWindow): "MainWindow", "No addresses selected."), 10000) else: self.statusBar().clearMessage() - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.send) + ) def on_action_AddressBookSubscribe(self): listOfSelectedRows = {} @@ -3184,7 +3218,9 @@ class MyForm(settingsmixin.SMainWindow): continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) - self.ui.tabWidget.setCurrentIndex(2) + self.ui.tabWidget.setCurrentIndex( + self.ui.tabWidget.indexOf(self.ui.subscriptions) + ) def on_context_menuAddressBook(self, point): self.popMenuAddressBook = QtGui.QMenu(self) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 3eb04101..f5d28a7f 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -634,8 +634,12 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menuHelp.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) - self.tabWidgetSend.setCurrentIndex(0) + self.tabWidget.setCurrentIndex( + self.tabWidget.indexOf(self.inbox) + ) + self.tabWidgetSend.setCurrentIndex( + self.tabWidgetSend.indexOf(self.sendDirect) + ) QtCore.QMetaObject.connectSlotsByName(MainWindow) MainWindow.setTabOrder(self.tableWidgetInbox, self.textEditInboxMessage) MainWindow.setTabOrder(self.textEditInboxMessage, self.comboBoxSendFrom) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 40830a70..de357e23 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -53,15 +53,20 @@ class MessageView(QtGui.QTextBrowser): def confirmURL(self, link): if link.scheme() == "mailto": - QtGui.QApplication.activeWindow().ui.lineEditTo.setText(link.path()) + window = QtGui.QApplication.activeWindow() + window.ui.lineEditTo.setText(link.path()) if link.hasQueryItem("subject"): - QtGui.QApplication.activeWindow().ui.lineEditSubject.setText(link.queryItemValue("subject")) + window.ui.lineEditSubject.setText( + link.queryItemValue("subject")) if link.hasQueryItem("body"): - QtGui.QApplication.activeWindow().ui.textEditMessage.setText(link.queryItemValue("body")) - QtGui.QApplication.activeWindow().setSendFromComboBox() - QtGui.QApplication.activeWindow().ui.tabWidgetSend.setCurrentIndex(0) - QtGui.QApplication.activeWindow().ui.tabWidget.setCurrentIndex(1) - QtGui.QApplication.activeWindow().ui.textEditMessage.setFocus() + 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"), diff --git a/src/bitmessageqt/newchandialog.py b/src/bitmessageqt/newchandialog.py index a129c608..ed683b13 100644 --- a/src/bitmessageqt/newchandialog.py +++ b/src/bitmessageqt/newchandialog.py @@ -36,7 +36,9 @@ class NewChanDialog(QtGui.QDialog, RetranslateMixin): 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(3) + 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"))) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index db690a2b..cea5ddc8 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -129,6 +129,10 @@ def createSupportMessage(myapp): 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(0) + myapp.ui.tabWidgetSend.setCurrentIndex( + myapp.ui.tabWidgetSend.indexOf(myapp.ui.sendDirect) + ) # send tab - myapp.ui.tabWidget.setCurrentIndex(1) + myapp.ui.tabWidget.setCurrentIndex( + myapp.ui.tabWidget.indexOf(myapp.ui.send) + ) -- 2.45.1 From fe76d230eb1e9aa0ee4b2c27f2b49bcbaaf999bd Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Thu, 18 Jan 2018 18:47:09 +0200 Subject: [PATCH 1036/1102] Moved RegenerateAddressesDialog into dialogs module --- src/bitmessageqt/__init__.py | 63 ++++++------ src/bitmessageqt/dialogs.py | 7 ++ src/bitmessageqt/regenerateaddresses.py | 124 ------------------------ 3 files changed, 43 insertions(+), 151 deletions(-) delete mode 100644 src/bitmessageqt/regenerateaddresses.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 60e1b05e..2b9daa57 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -27,7 +27,6 @@ from newaddresswizard import * from messageview import MessageView from migrationwizard import * from foldertree import * -from regenerateaddresses import * from newchandialog import * from safehtmlparser import * from emailgateway import * @@ -1442,31 +1441,50 @@ class MyForm(settingsmixin.SMainWindow): elif self.getCurrentFolder(self.ui.treeWidgetChans) == "trash": self.loadMessagelist(self.ui.tableWidgetInboxChans, self.getCurrentAccount(self.ui.treeWidgetChans), "trash") - - # menu botton 'regenerate deterministic addresses' + # menu button 'regenerate deterministic addresses' def click_actionRegenerateDeterministicAddresses(self): - 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.")) + dialog = dialogs.RegenerateAddressesDialog(self) + if dialog.exec_(): + if dialog.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( - self.regenerateAddressesDialogInstance.ui.lineEditStreamNumber.text()) + streamNumberForAddress = int(dialog.lineEditStreamNumber.text()) try: addressVersionNumber = int( - self.regenerateAddressesDialogInstance.ui.lineEditAddressVersionNumber.text()) + dialog.lineEditAddressVersionNumber.text()) except: - 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: - 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", self.regenerateAddressesDialogInstance.ui.spinBoxNumberOfAddressesToMake.value( - ), self.regenerateAddressesDialogInstance.ui.lineEditPassphrase.text().toUtf8(), self.regenerateAddressesDialogInstance.ui.checkBoxEighteenByteRipe.isChecked())) + 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) ) @@ -3959,15 +3977,6 @@ class MyForm(settingsmixin.SMainWindow): obj.loadSettings() -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): def __init__(self, parent): diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index ef22fd3b..58003f3a 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -109,6 +109,13 @@ class NewSubscriptionDialog( ).arg(count)) +class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent=None): + super(RegenerateAddressesDialog, self).__init__(parent) + widgets.load('regenerateaddresses.ui', self) + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + class AboutDialog(QtGui.QDialog, RetranslateMixin): def __init__(self, parent=None): super(AboutDialog, self).__init__(parent) diff --git a/src/bitmessageqt/regenerateaddresses.py b/src/bitmessageqt/regenerateaddresses.py deleted file mode 100644 index 7129b632..00000000 --- a/src/bitmessageqt/regenerateaddresses.py +++ /dev/null @@ -1,124 +0,0 @@ -# -*- 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)) - -- 2.45.1 From 8109fa7ecef43618302b8f17fe47e6645d002e72 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 19 Jan 2018 16:26:07 +0200 Subject: [PATCH 1037/1102] Moved EmailGatewayDialog (with both usage) into dialogs module --- src/bitmessageqt/__init__.py | 138 +++++++++---------------------- src/bitmessageqt/dialogs.py | 77 +++++++++++++++++ src/bitmessageqt/emailgateway.py | 103 ----------------------- src/bitmessageqt/emailgateway.ui | 85 +++++++++++++++++-- 4 files changed, 191 insertions(+), 212 deletions(-) delete mode 100644 src/bitmessageqt/emailgateway.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2b9daa57..197d9d21 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -29,7 +29,6 @@ from migrationwizard import * from foldertree import * from newchandialog import * from safehtmlparser import * -from emailgateway import * from settings import * import settingsmixin import support @@ -2155,20 +2154,22 @@ class MyForm(settingsmixin.SMainWindow): # 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 hasattr(acct, "feedback") \ + and acct.feedback != GatewayAccount.ALL_OK: if acct.feedback == GatewayAccount.REGISTRATION_DENIED: - self.dialog = EmailGatewayRegistrationDialog(self, _translate("EmailGatewayRegistrationDialog", "Registration failed:"), - _translate("EmailGatewayRegistrationDialog", "The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below:") - ) - if self.dialog.exec_(): - email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) - # register resets address variables - acct.register(email) - BMConfigParser().set(acct.fromAddress, 'label', email) - BMConfigParser().set(acct.fromAddress, 'gateway', 'mailchuck') - BMConfigParser().save() - self.statusBar().showMessage(_translate( - "MainWindow", "Sending email gateway registration request"), 10000) + dialog = dialogs.EmailGatewayDialog( + self, + _translate( + "EmailGatewayRegistrationDialog", + "Registration failed:"), + _translate( + "EmailGatewayRegistrationDialog", + "The requested email address is not available," + " please try a new one."), + config=BMConfigParser() + ) + if dialog.exec_(): + dialog.register(acct) def click_pushButtonAddAddressBook(self, dialog=None): if not dialog: @@ -2488,56 +2489,31 @@ class MyForm(settingsmixin.SMainWindow): dialogs.SpecialAddressBehaviorDialog(self, BMConfigParser()) def on_action_EmailGatewayDialog(self): - self.dialog = EmailGatewayDialog(self) + dialog = dialogs.EmailGatewayDialog(self, config=BMConfigParser()) # For Modal dialogs - if self.dialog.exec_(): - addressAtCurrentRow = self.getCurrentAccount() - acct = accountClass(addressAtCurrentRow) - # no chans / mailinglists - if acct.type != AccountMixin.NORMAL: - return - if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): - acct.unregister() - BMConfigParser().remove_option(addressAtCurrentRow, 'gateway') - BMConfigParser().save() - self.statusBar().showMessage(_translate( - "MainWindow", "Sending email gateway unregistration request"), 10000) - elif self.dialog.ui.radioButtonStatus.isChecked() and isinstance(acct, GatewayAccount): - acct.status() - self.statusBar().showMessage(_translate( - "MainWindow", "Sending email gateway status request"), 10000) - elif self.dialog.ui.radioButtonSettings.isChecked() and isinstance(acct, GatewayAccount): - acct.settings() - listOfAddressesInComboBoxSendFrom = [str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) for i in range(self.ui.comboBoxSendFrom.count())] - if acct.fromAddress in listOfAddressesInComboBoxSendFrom: - currentIndex = listOfAddressesInComboBoxSendFrom.index(acct.fromAddress) - self.ui.comboBoxSendFrom.setCurrentIndex(currentIndex) - 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() - elif self.dialog.ui.radioButtonRegister.isChecked(): - email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) - acct = MailchuckAccount(addressAtCurrentRow) - acct.register(email) - BMConfigParser().set(addressAtCurrentRow, 'label', email) - BMConfigParser().set(addressAtCurrentRow, 'gateway', 'mailchuck') - BMConfigParser().save() - self.statusBar().showMessage(_translate( - "MainWindow", "Sending email gateway registration request"), 10000) + acct = dialog.exec_() + + # Only settings ramain here + if acct: + 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: - pass - #print "well nothing" -# shared.writeKeysFile() -# self.rerenderInboxToLabels() + 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( @@ -4210,44 +4186,6 @@ class settingsDialog(QtGui.QDialog): self.parent.ui.pushButtonFetchNamecoinID.show() -class EmailGatewayDialog(QtGui.QDialog): - - def __init__(self, parent): - QtGui.QWidget.__init__(self, parent) - self.ui = Ui_EmailGatewayDialog() - self.ui.setupUi(self) - self.parent = parent - addressAtCurrentRow = parent.getCurrentAccount() - acct = accountClass(addressAtCurrentRow) - if isinstance(acct, GatewayAccount): - self.ui.radioButtonUnregister.setEnabled(True) - self.ui.radioButtonStatus.setEnabled(True) - self.ui.radioButtonStatus.setChecked(True) - self.ui.radioButtonSettings.setEnabled(True) - else: - self.ui.radioButtonStatus.setEnabled(False) - self.ui.radioButtonSettings.setEnabled(False) - self.ui.radioButtonUnregister.setEnabled(False) - label = BMConfigParser().get(addressAtCurrentRow, 'label') - if label.find("@mailchuck.com") > -1: - self.ui.lineEditEmail.setText(label) - - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - -class EmailGatewayRegistrationDialog(QtGui.QDialog): - - def __init__(self, parent, title, label): - QtGui.QWidget.__init__(self, parent) - self.ui = Ui_EmailGatewayRegistrationDialog() - self.ui.setupUi(self) - self.parent = parent - self.setWindowTitle(title) - self.ui.label.setText(label) - - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - - class NewAddressDialog(QtGui.QDialog): def __init__(self, parent): diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 58003f3a..c6fee734 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -1,5 +1,6 @@ from PyQt4 import QtCore, QtGui from addresses import decodeAddress, encodeVarint +from account import GatewayAccount, MailchuckAccount, AccountMixin, accountClass from tr import _translate from retranslateui import RetranslateMixin import widgets @@ -235,3 +236,79 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin): self.parent.rerenderComboBoxSendFromBroadcast() self.config.save() self.parent.rerenderMessagelistToLabels() + + +class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent, title=None, label=None, config=None): + super(EmailGatewayDialog, self).__init__(parent) + widgets.load('emailgateway.ui', self) + self.parent = parent + self.config = config + if title and label: + self.setWindowTitle(title) + self.label.setText(label) + 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 register(self, acct=None): + email = str(self.lineEditEmail.text().toUtf8()) + if acct is None: + acct = self.acct + acct.register(email) + self.config.set(acct.fromAddress, 'label', email) + self.config.set(acct.fromAddress, 'gateway', 'mailchuck') + self.config.save() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway registration request" + ), 10000) + + 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(): + self.register() + elif self.radioButtonUnregister.isChecked(): + self.acct.unregister() + self.config.remove_option(self.acct.fromAddress, 'gateway') + self.config.save() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway unregistration request" + ), 10000) + elif self.radioButtonStatus.isChecked(): + self.acct.status() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway status request" + ), 10000) + elif self.radioButtonSettings.isChecked(): + return self.acct diff --git a/src/bitmessageqt/emailgateway.py b/src/bitmessageqt/emailgateway.py deleted file mode 100644 index 54ca4529..00000000 --- a/src/bitmessageqt/emailgateway.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'emailgateway.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_EmailGatewayDialog(object): - def setupUi(self, EmailGatewayDialog): - EmailGatewayDialog.setObjectName(_fromUtf8("EmailGatewayDialog")) - EmailGatewayDialog.resize(386, 172) - self.gridLayout = QtGui.QGridLayout(EmailGatewayDialog) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.radioButtonRegister = QtGui.QRadioButton(EmailGatewayDialog) - self.radioButtonRegister.setChecked(True) - self.radioButtonRegister.setObjectName(_fromUtf8("radioButtonRegister")) - self.gridLayout.addWidget(self.radioButtonRegister, 1, 0, 1, 1) - self.radioButtonStatus = QtGui.QRadioButton(EmailGatewayDialog) - self.radioButtonStatus.setObjectName(_fromUtf8("radioButtonStatus")) - self.gridLayout.addWidget(self.radioButtonStatus, 4, 0, 1, 1) - self.radioButtonSettings = QtGui.QRadioButton(EmailGatewayDialog) - self.radioButtonSettings.setObjectName(_fromUtf8("radioButtonSettings")) - self.gridLayout.addWidget(self.radioButtonSettings, 5, 0, 1, 1) - self.radioButtonUnregister = QtGui.QRadioButton(EmailGatewayDialog) - self.radioButtonUnregister.setObjectName(_fromUtf8("radioButtonUnregister")) - self.gridLayout.addWidget(self.radioButtonUnregister, 6, 0, 1, 1) - self.label = QtGui.QLabel(EmailGatewayDialog) - self.label.setWordWrap(True) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) - self.label_2 = QtGui.QLabel(EmailGatewayDialog) - self.label_2.setObjectName(_fromUtf8("label_2")) - self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) - self.lineEditEmail = QtGui.QLineEdit(EmailGatewayDialog) - self.lineEditEmail.setEnabled(True) - self.lineEditEmail.setObjectName(_fromUtf8("lineEditEmail")) - self.gridLayout.addWidget(self.lineEditEmail, 3, 0, 1, 1) - self.buttonBox = QtGui.QDialogButtonBox(EmailGatewayDialog) - 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, 7, 0, 1, 1) - - self.retranslateUi(EmailGatewayDialog) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayDialog.accept) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayDialog.reject) - QtCore.QObject.connect(self.radioButtonRegister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setEnabled) - QtCore.QObject.connect(self.radioButtonStatus, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) - QtCore.QObject.connect(self.radioButtonSettings, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) - QtCore.QObject.connect(self.radioButtonUnregister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) - QtCore.QMetaObject.connectSlotsByName(EmailGatewayDialog) - EmailGatewayDialog.setTabOrder(self.radioButtonRegister, self.lineEditEmail) - EmailGatewayDialog.setTabOrder(self.lineEditEmail, self.radioButtonUnregister) - EmailGatewayDialog.setTabOrder(self.radioButtonUnregister, self.buttonBox) - - def retranslateUi(self, EmailGatewayDialog): - EmailGatewayDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway", None, QtGui.QApplication.UnicodeUTF8)) - self.radioButtonRegister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Register on email gateway", None, QtGui.QApplication.UnicodeUTF8)) - self.radioButtonStatus.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Account status at email gateway", None, QtGui.QApplication.UnicodeUTF8)) - self.radioButtonSettings.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Change account settings at email gateway", None, QtGui.QApplication.UnicodeUTF8)) - self.radioButtonUnregister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Unregister from email gateway", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.", None, QtGui.QApplication.UnicodeUTF8)) - self.label_2.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Desired email address (including @mailchuck.com):", None, QtGui.QApplication.UnicodeUTF8)) - - -class Ui_EmailGatewayRegistrationDialog(object): - def setupUi(self, EmailGatewayRegistrationDialog): - EmailGatewayRegistrationDialog.setObjectName(_fromUtf8("EmailGatewayRegistrationDialog")) - EmailGatewayRegistrationDialog.resize(386, 172) - self.gridLayout = QtGui.QGridLayout(EmailGatewayRegistrationDialog) - self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.label = QtGui.QLabel(EmailGatewayRegistrationDialog) - self.label.setWordWrap(True) - self.label.setObjectName(_fromUtf8("label")) - self.gridLayout.addWidget(self.label, 0, 0, 1, 1) - self.lineEditEmail = QtGui.QLineEdit(EmailGatewayRegistrationDialog) - self.lineEditEmail.setObjectName(_fromUtf8("lineEditEmail")) - self.gridLayout.addWidget(self.lineEditEmail, 1, 0, 1, 1) - self.buttonBox = QtGui.QDialogButtonBox(EmailGatewayRegistrationDialog) - 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, 7, 0, 1, 1) - - self.retranslateUi(EmailGatewayRegistrationDialog) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayRegistrationDialog.accept) - QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayRegistrationDialog.reject) - QtCore.QMetaObject.connectSlotsByName(EmailGatewayRegistrationDialog) - - def retranslateUi(self, EmailGatewayRegistrationDialog): - EmailGatewayRegistrationDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway registration", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.\nPlease type the desired email address (including @mailchuck.com) below:", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/bitmessageqt/emailgateway.ui b/src/bitmessageqt/emailgateway.ui index 927df46a..77a66dec 100644 --- a/src/bitmessageqt/emailgateway.ui +++ b/src/bitmessageqt/emailgateway.ui @@ -7,20 +7,20 @@ 0 0 386 - 172 + 240 Email gateway - + true - Desired email address (including @mailchuck.com) + Desired email address (including @mailchuck.com): @@ -50,28 +50,60 @@ - - + + true @mailchuck.com + + 0 + - Email gateway alows 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. true + + + + false + + + Account status at email gateway + + + false + + + + + + + false + + + Change account settings at email gateway + + + false + + + + + false + Unregister from email gateway @@ -84,7 +116,10 @@ radioButtonRegister - lineEditEmailAddress + lineEditEmail + radioButtonStatus + radioButtonSettings + radioButtonUnregister buttonBox @@ -124,7 +159,7 @@ radioButtonRegister clicked(bool) - lineEditEmailAddress + lineEditEmail setEnabled(bool) @@ -140,7 +175,7 @@ radioButtonUnregister clicked(bool) - lineEditEmailAddress + lineEditEmail setDisabled(bool) @@ -153,5 +188,37 @@ + + radioButtonStatus + clicked(bool) + lineEditEmail + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + + + radioButtonSettings + clicked(bool) + lineEditEmail + setDisabled(bool) + + + 20 + 20 + + + 20 + 20 + + + -- 2.45.1 From 35a11c271a2e9e6937a7dd8d34b377a5bf314383 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 19 Jan 2018 18:30:35 +0200 Subject: [PATCH 1038/1102] Moved NewAddressDialog into dialogs module --- src/bitmessageqt/__init__.py | 99 +++++++------- src/bitmessageqt/dialogs.py | 20 ++- src/bitmessageqt/newaddressdialog.py | 193 --------------------------- 3 files changed, 64 insertions(+), 248 deletions(-) delete mode 100644 src/bitmessageqt/newaddressdialog.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 197d9d21..a44fd86a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -22,8 +22,6 @@ from bitmessageui import * from bmconfigparser import BMConfigParser import defaults from namecoin import namecoinConnection -from newaddressdialog import * -from newaddresswizard import * from messageview import MessageView from migrationwizard import * from foldertree import * @@ -2554,41 +2552,53 @@ class MyForm(settingsmixin.SMainWindow): addressAtCurrentRow, self.getCurrentFolder(), None, 0) def click_NewAddressDialog(self): - addresses = [] - for addressInKeysFile in getSortedAccounts(): - addresses.append(addressInKeysFile) -# self.dialog = Ui_NewAddressWizard(addresses) -# self.dialog.exec_() -# print "Name: " + self.dialog.field("name").toString() -# print "Email: " + self.dialog.field("email").toString() -# return - self.dialog = NewAddressDialog(self) + dialog = dialogs.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] - queues.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. - queues.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: + if not dialog.exec_(): logger.debug('new address dialog box rejected') + return + + # dialog.buttonBox.enabled = False + if dialog.radioButtonRandomAddress.isChecked(): + if dialog.radioButtonMostAvailable.isChecked(): + streamNumberForAddress = 1 + else: + # User selected 'Use the same stream as an existing + # address.' + streamNumberForAddress = decodeAddress( + dialog.comboBoxExisting.currentText())[2] + queues.addressGeneratorQueue.put(( + 'createRandomAddress', 4, streamNumberForAddress, + str(dialog.newaddresslabel.text().toUtf8()), 1, "", + dialog.checkBoxEighteenByteRipe.isChecked() + )) + else: + if dialog.lineEditPassphrase.text() != \ + dialog.lineEditPassphraseAgain.text(): + QMessageBox.about( + self, _translate("MainWindow", "Passphrase mismatch"), + _translate( + "MainWindow", + "The passphrase you entered twice doesn\'t" + " match. Try again.") + ) + elif dialog.lineEditPassphrase.text() == "": + 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", + dialog.spinBoxNumberOfAddressesToMake.value(), + dialog.lineEditPassphrase.text().toUtf8(), + dialog.checkBoxEighteenByteRipe.isChecked() + )) def network_switch(self): dontconnect_option = not BMConfigParser().safeGetBoolean( @@ -4186,25 +4196,6 @@ class settingsDialog(QtGui.QDialog): self.parent.ui.pushButtonFetchNamecoinID.show() -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. - for addressInKeysFile in getSortedAccounts(): - self.ui.radioButtonExisting.click() - self.ui.comboBoxExisting.addItem( - addressInKeysFile) - row += 1 - self.ui.groupBoxDeterministic.setHidden(True) - 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. diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index c6fee734..f7ac5497 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -1,6 +1,9 @@ from PyQt4 import QtCore, QtGui from addresses import decodeAddress, encodeVarint -from account import GatewayAccount, MailchuckAccount, AccountMixin, accountClass +from account import ( + GatewayAccount, MailchuckAccount, AccountMixin, accountClass, + getSortedAccounts +) from tr import _translate from retranslateui import RetranslateMixin import widgets @@ -70,6 +73,21 @@ class AddAddressDialog(QtGui.QDialog, RetranslateMixin, AddressCheckMixin): AddressCheckMixin.__init__(self) +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)) + + class NewSubscriptionDialog( QtGui.QDialog, RetranslateMixin, AddressCheckMixin): diff --git a/src/bitmessageqt/newaddressdialog.py b/src/bitmessageqt/newaddressdialog.py deleted file mode 100644 index afe6fa2d..00000000 --- a/src/bitmessageqt/newaddressdialog.py +++ /dev/null @@ -1,193 +0,0 @@ -# -*- 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)) - -- 2.45.1 From cd88d063a1899bdc3212d5d1ff57b99452000943 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 19 Jan 2018 18:38:15 +0200 Subject: [PATCH 1039/1102] Imported NewChanDialog into dialogs module --- src/bitmessageqt/__init__.py | 3 +-- src/bitmessageqt/dialogs.py | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a44fd86a..34ab49b5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -25,7 +25,6 @@ from namecoin import namecoinConnection from messageview import MessageView from migrationwizard import * from foldertree import * -from newchandialog import * from safehtmlparser import * from settings import * import settingsmixin @@ -1488,7 +1487,7 @@ class MyForm(settingsmixin.SMainWindow): # opens 'join chan' dialog def click_actionJoinChan(self): - NewChanDialog(self) + dialogs.NewChanDialog(self) def showConnectDialog(self): dialog = dialogs.ConnectDialog(self) diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index f7ac5497..c7cd5bd4 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -8,12 +8,17 @@ from tr import _translate from retranslateui import RetranslateMixin import widgets +from newchandialog import NewChanDialog + import hashlib import paths from inventory import Inventory from version import softwareVersion +__all__ = [NewChanDialog] + + class AddressCheckMixin(object): def __init__(self): -- 2.45.1 From 25876ded2bb1d2689db892a417cf503b1fd1278a Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 19 Jan 2018 18:42:44 +0200 Subject: [PATCH 1040/1102] Removed unused import of inventory.Inventory --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 34ab49b5..54a98b14 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -50,7 +50,7 @@ from account import * import dialogs from helper_generic import powQueueSize from inventory import ( - Inventory, PendingDownloadQueue, PendingUpload, + PendingDownloadQueue, PendingUpload, PendingUploadDeadlineException) from uisignaler import UISignaler import knownnodes -- 2.45.1 From 641db73614f86f7fad7e015801a7770e661368db Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 22 Jan 2018 15:19:02 +0200 Subject: [PATCH 1041/1102] Removed unused _encoding and _transalate --- src/bitmessageqt/__init__.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 54a98b14..70b84523 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -11,11 +11,7 @@ except Exception as err: import sys sys.exit() -try: - _encoding = QtGui.QApplication.UnicodeUTF8 -except AttributeError: - logger.exception('QtGui.QApplication.UnicodeUTF8 error', exc_info=True) - +from tr import _translate from addresses import * import shared from bitmessageui import * @@ -70,12 +66,6 @@ except ImportError: get_plugins = False -def _translate(context, text, disambiguation = None, encoding = None, number = None): - if number is None: - return QtGui.QApplication.translate(context, text) - else: - return QtGui.QApplication.translate(context, text, None, QtCore.QCoreApplication.CodecForTr, number) - def change_translation(newlocale): global qmytranslator, qsystranslator try: -- 2.45.1 From c699f6d872cd97e2b21de2808fa345e03a463038 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 22 Jan 2018 18:52:28 +0200 Subject: [PATCH 1042/1102] Got rid of wildcard imports in bitmessageqt.__init__ --- src/bitmessageqt/__init__.py | 300 +++++++++++++++++++++-------------- 1 file changed, 179 insertions(+), 121 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 70b84523..dfcb9685 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1,32 +1,31 @@ from debug import logger +import sys try: from PyQt4 import QtCore, QtGui - from PyQt4.QtCore import * - from PyQt4.QtGui import * 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) - import sys sys.exit() from tr import _translate -from addresses import * +from addresses import decodeAddress, addBMIfNotPresent import shared -from bitmessageui import * +from bitmessageui import Ui_MainWindow from bmconfigparser import BMConfigParser import defaults from namecoin import namecoinConnection from messageview import MessageView -from migrationwizard import * -from foldertree import * -from safehtmlparser import * -from settings import * +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 -import sys import time import os import hashlib @@ -42,7 +41,9 @@ import helper_search import l10n import openclpow from utils import str_broadcast_subscribers, avatarize -from account import * +from account import ( + getSortedAccounts, getSortedSubscriptions, accountClass, BMAccount, + GatewayAccount, MailchuckAccount, AccountColor) import dialogs from helper_generic import powQueueSize from inventory import ( @@ -378,7 +379,8 @@ class MyForm(settingsmixin.SMainWindow): # sort ascending when creating if treeWidget.topLevelItemCount() == 0: - treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) + treeWidget.header().setSortIndicator( + 0, QtCore.Qt.AscendingOrder) # init dictionary db = getSortedSubscriptions(True) @@ -463,7 +465,8 @@ class MyForm(settingsmixin.SMainWindow): # sort ascending when creating if treeWidget.topLevelItemCount() == 0: - treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) + treeWidget.header().setSortIndicator( + 0, QtCore.Qt.AscendingOrder) # init dictionary db = {} enabled = {} @@ -691,7 +694,8 @@ class MyForm(settingsmixin.SMainWindow): self.pushButtonStatusIcon = QtGui.QPushButton(self) self.pushButtonStatusIcon.setText('') - self.pushButtonStatusIcon.setIcon(QIcon(':/newPrefix/images/redicon.png')) + 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( @@ -1021,7 +1025,7 @@ class MyForm(settingsmixin.SMainWindow): l10n.formatTimestamp(lastactiontime)) newItem = myTableWidgetItem(statusText) newItem.setToolTip(statusText) - newItem.setData(Qt.UserRole, QByteArray(ackdata)) + newItem.setData(QtCore.Qt.UserRole, QtCore.QByteArray(ackdata)) newItem.setData(33, int(lastactiontime)) newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) @@ -1030,7 +1034,7 @@ class MyForm(settingsmixin.SMainWindow): return acct def addMessageListItemInbox(self, tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read): - font = QFont() + font = QtGui.QFont() font.setBold(True) if toAddress == str_broadcast_subscribers: acct = accountClass(fromAddress) @@ -1052,7 +1056,7 @@ class MyForm(settingsmixin.SMainWindow): # time received time_item = myTableWidgetItem(l10n.formatTimestamp(received)) time_item.setToolTip(l10n.formatTimestamp(received)) - time_item.setData(Qt.UserRole, QByteArray(msgid)) + time_item.setData(QtCore.Qt.UserRole, QtCore.QByteArray(msgid)) time_item.setData(33, int(received)) time_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) @@ -1089,7 +1093,8 @@ class MyForm(settingsmixin.SMainWindow): toAddress, fromAddress, subject, status, ackdata, lastactiontime = row self.addMessageListItemSent(tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime) - tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) + tableWidget.horizontalHeader().setSortIndicator( + 3, QtCore.Qt.DescendingOrder) tableWidget.setSortingEnabled(True) tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Sent", None)) tableWidget.setUpdatesEnabled(True) @@ -1121,7 +1126,8 @@ class MyForm(settingsmixin.SMainWindow): msgfolder, msgid, toAddress, fromAddress, subject, received, read = row self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read) - tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) + tableWidget.horizontalHeader().setSortIndicator( + 3, QtCore.Qt.DescendingOrder) tableWidget.setSortingEnabled(True) tableWidget.selectRow(0) tableWidget.horizontalHeaderItem(3).setText(_translate("MainWindow", "Received", None)) @@ -1134,7 +1140,7 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.tray, QtCore.SIGNAL( traySignal), self.__icon_activated) - m = QMenu() + m = QtGui.QMenu() self.actionStatus = QtGui.QAction(_translate( "MainWindow", "Not Connected"), m, checkable=False) @@ -1397,11 +1403,11 @@ class MyForm(settingsmixin.SMainWindow): # 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."), 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."), QtGui.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), 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(state.appdata), QtGui.QMessageBox.Ok) elif sys.platform == 'win32' or sys.platform == 'win64': if state.appdata == '': reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate( @@ -1432,7 +1438,7 @@ class MyForm(settingsmixin.SMainWindow): dialog = dialogs.RegenerateAddressesDialog(self) if dialog.exec_(): if dialog.lineEditPassphrase.text() == "": - QMessageBox.about( + QtGui.QMessageBox.about( self, _translate("MainWindow", "bad passphrase"), _translate( "MainWindow", @@ -1445,7 +1451,7 @@ class MyForm(settingsmixin.SMainWindow): addressVersionNumber = int( dialog.lineEditAddressVersionNumber.text()) except: - QMessageBox.about( + QtGui.QMessageBox.about( self, _translate("MainWindow", "Bad address version number"), _translate( @@ -1455,7 +1461,7 @@ class MyForm(settingsmixin.SMainWindow): )) return if addressVersionNumber < 3 or addressVersionNumber > 4: - QMessageBox.about( + QtGui.QMessageBox.about( self, _translate("MainWindow", "Bad address version number"), _translate( @@ -1509,7 +1515,7 @@ class MyForm(settingsmixin.SMainWindow): if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: if BMConfigParser().getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: - QTimer.singleShot(0, self.appIndicatorHide) + QtCore.QTimer.singleShot(0, self.appIndicatorHide) elif event.oldState() & QtCore.Qt.WindowMinimized: # The window state has just been changed to # Normal/Maximised/FullScreen @@ -1531,7 +1537,7 @@ class MyForm(settingsmixin.SMainWindow): 'bitmessagesettings', 'hidetrayconnectionnotifications') if color == 'red': self.pushButtonStatusIcon.setIcon( - QIcon(":/newPrefix/images/redicon.png")) + QtGui.QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # if the connection is lost then show a notification if self.connected and _notifications_enabled: @@ -1552,8 +1558,8 @@ class MyForm(settingsmixin.SMainWindow): 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(QIcon( - ":/newPrefix/images/yellowicon.png")) + self.pushButtonStatusIcon.setIcon( + QtGui.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: @@ -1571,7 +1577,7 @@ class MyForm(settingsmixin.SMainWindow): 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( - QIcon(":/newPrefix/images/greenicon.png")) + QtGui.QIcon(":/newPrefix/images/greenicon.png")) shared.statusIconColor = 'green' if not self.connected and _notifications_enabled: self.notifierShow( @@ -1587,7 +1593,7 @@ class MyForm(settingsmixin.SMainWindow): def initTrayIcon(self, iconFileName, app): self.currentTrayIconFileName = iconFileName - self.tray = QSystemTrayIcon( + self.tray = QtGui.QSystemTrayIcon( self.calcTrayIcon(iconFileName, self.findInboxUnreadCount()), app) def setTrayIconFile(self, iconFileName): @@ -1616,9 +1622,10 @@ class MyForm(settingsmixin.SMainWindow): fontMetrics = QtGui.QFontMetrics(font) rect = fontMetrics.boundingRect(txt) # draw text - painter = QPainter() + painter = QtGui.QPainter() painter.begin(pixmap) - painter.setPen(QtGui.QPen(QtGui.QColor(255, 0, 0), Qt.SolidPattern)) + painter.setPen( + QtGui.QPen(QtGui.QColor(255, 0, 0), QtCore.Qt.SolidPattern)) painter.setFont(font) painter.drawText(24-rect.right()-marginX, -rect.top()+marginY, txt) painter.end() @@ -1627,13 +1634,14 @@ 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()) + def changedInboxUnread(self, row=None): + self.drawTrayIcon( + self.currentTrayIconFileName, self.findInboxUnreadCount()) self.rerenderTabTreeMessages() self.rerenderTabTreeSubscriptions() self.rerenderTabTreeChans() - def findInboxUnreadCount(self, count = None): + def findInboxUnreadCount(self, count=None): if count is None: queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''') cnt = 0 @@ -1653,8 +1661,7 @@ class MyForm(settingsmixin.SMainWindow): continue for i in range(sent.rowCount()): - rowAddress = sent.item( - i, 0).data(Qt.UserRole) + rowAddress = sent.item(i, 0).data(QtCore.Qt.UserRole) if toAddress == rowAddress: sent.item(i, 3).setToolTip(textToDisplay) try: @@ -1674,9 +1681,9 @@ class MyForm(settingsmixin.SMainWindow): continue for i in range(sent.rowCount()): toAddress = sent.item( - i, 0).data(Qt.UserRole) + i, 0).data(QtCore.Qt.UserRole) tableAckdata = sent.item( - i, 3).data(Qt.UserRole).toPyObject() + i, 3).data(QtCore.Qt.UserRole).toPyObject() status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if ackdata == tableAckdata: @@ -1697,11 +1704,11 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]): for i in range(inbox.rowCount()): - if msgid == str(inbox.item(i, 3).data(Qt.UserRole).toPyObject()): + if msgid == str(inbox.item(i, 3).data(QtCore.Qt.UserRole).toPyObject()): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed"), 10000) treeWidget = self.widgetConvert(inbox) - self.propagateUnreadCount(inbox.item(i, 1 if inbox.item(i, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder(treeWidget), treeWidget, 0) + 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 @@ -1711,7 +1718,7 @@ class MyForm(settingsmixin.SMainWindow): def displayAlert(self, title, text, exitAfterUserClicksOk): self.statusBar().showMessage(text) - QtGui.QMessageBox.critical(self, title, text, QMessageBox.Ok) + QtGui.QMessageBox.critical(self, title, text, QtGui.QMessageBox.Ok) if exitAfterUserClicksOk: os._exit(0) @@ -1739,7 +1746,7 @@ class MyForm(settingsmixin.SMainWindow): oldRows[item.address] = [item.label, item.type, i] if self.ui.tableWidgetAddressBook.rowCount() == 0: - self.ui.tableWidgetAddressBook.horizontalHeader().setSortIndicator(0, Qt.AscendingOrder) + self.ui.tableWidgetAddressBook.horizontalHeader().setSortIndicator(0, QtCore.Qt.AscendingOrder) if self.ui.tableWidgetAddressBook.isSortingEnabled(): self.ui.tableWidgetAddressBook.setSortingEnabled(False) @@ -1773,7 +1780,8 @@ class MyForm(settingsmixin.SMainWindow): completerList.append(unicode(newRows[address][0], encoding="UTF-8") + " <" + address + ">") # sort - self.ui.tableWidgetAddressBook.sortByColumn(0, Qt.AscendingOrder) + self.ui.tableWidgetAddressBook.sortByColumn( + 0, QtCore.Qt.AscendingOrder) self.ui.tableWidgetAddressBook.setSortingEnabled(True) self.ui.lineEditTo.completer().model().setStringList(completerList) @@ -1786,7 +1794,7 @@ class MyForm(settingsmixin.SMainWindow): "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) + 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_pushButtonSend(self): encoding = 3 if QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier else 2 @@ -1798,8 +1806,8 @@ class MyForm(settingsmixin.SMainWindow): # message to specific people sendMessageToPeople = True fromAddress = str(self.ui.comboBoxSendFrom.itemData( - self.ui.comboBoxSendFrom.currentIndex(), - Qt.UserRole).toString()) + self.ui.comboBoxSendFrom.currentIndex(), + QtCore.Qt.UserRole).toString()) toAddresses = str(self.ui.lineEditTo.text().toUtf8()) subject = str(self.ui.lineEditSubject.text().toUtf8()) message = str( @@ -1808,23 +1816,29 @@ class MyForm(settingsmixin.SMainWindow): # broadcast message sendMessageToPeople = False fromAddress = str(self.ui.comboBoxSendFromBroadcast.itemData( - self.ui.comboBoxSendFromBroadcast.currentIndex(), - Qt.UserRole).toString()) + self.ui.comboBoxSendFromBroadcast.currentIndex(), + QtCore.Qt.UserRole).toString()) subject = str(self.ui.lineEditSubjectBroadcast.text().toUtf8()) message = str( self.ui.textEditMessageBroadcast.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): - 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): + 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))) return - + acct = accountClass(fromAddress) if sendMessageToPeople: # To send a message to specific people (rather than broadcast) @@ -1900,11 +1914,11 @@ class MyForm(settingsmixin.SMainWindow): toAddress = addBMIfNotPresent(toAddress) if addressVersionNumber > 4 or addressVersionNumber <= 1: - QMessageBox.about(self, _translate("MainWindow", "Address version number"), _translate( + QtGui.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: - QMessageBox.about(self, _translate("MainWindow", "Stream number"), _translate( + QtGui.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() @@ -2050,8 +2064,11 @@ class MyForm(settingsmixin.SMainWindow): 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, Qt.UserRole).toString()) - self.ui.comboBoxSendFrom.setItemData(i, AccountColor(address).accountColor(), Qt.ForegroundRole) + address = str(self.ui.comboBoxSendFrom.itemData( + i, QtCore.Qt.UserRole).toString()) + self.ui.comboBoxSendFrom.setItemData( + i, AccountColor(address).accountColor(), + QtCore.Qt.ForegroundRole) self.ui.comboBoxSendFrom.insertItem(0, '', '') if(self.ui.comboBoxSendFrom.count() == 2): self.ui.comboBoxSendFrom.setCurrentIndex(1) @@ -2070,8 +2087,11 @@ class MyForm(settingsmixin.SMainWindow): 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, Qt.UserRole).toString()) - self.ui.comboBoxSendFromBroadcast.setItemData(i, AccountColor(address).accountColor(), Qt.ForegroundRole) + 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) @@ -2285,7 +2305,7 @@ class MyForm(settingsmixin.SMainWindow): if int(BMConfigParser().get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'dontconnect'): - QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + QtGui.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( self.settingsDialogInstance.ui.lineEditTCPPort.text())) @@ -2299,7 +2319,7 @@ class MyForm(settingsmixin.SMainWindow): #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.statusIconColor != 'red': - QMessageBox.about(self, _translate("MainWindow", "Restart"), _translate( + QtGui.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() @@ -2328,7 +2348,7 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().set('bitmessagesettings', 'maxuploadrate', str( int(float(self.settingsDialogInstance.ui.lineEditMaxUploadRate.text())))) except ValueError: - QMessageBox.about(self, _translate("MainWindow", "Number needed"), _translate( + QtGui.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"), @@ -2408,7 +2428,7 @@ 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. - QMessageBox.about(self, _translate("MainWindow", "Will not resend ever"), _translate( + QtGui.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') @@ -2508,7 +2528,8 @@ class MyForm(settingsmixin.SMainWindow): _translate( "MainWindow", "Are you sure you would like to mark all messages read?" - ), QMessageBox.Yes | QMessageBox.No) != QMessageBox.Yes: + ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No + ) != QtGui.QMessageBox.Yes: return addressAtCurrentRow = self.getCurrentAccount() tableWidget = self.getCurrentMessagelist() @@ -2517,13 +2538,13 @@ class MyForm(settingsmixin.SMainWindow): if idCount == 0: return - font = QFont() + font = QtGui.QFont() font.setBold(False) msgids = [] for i in range(0, idCount): msgids.append(str(tableWidget.item( - i, 3).data(Qt.UserRole).toPyObject())) + 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) @@ -2564,7 +2585,7 @@ class MyForm(settingsmixin.SMainWindow): else: if dialog.lineEditPassphrase.text() != \ dialog.lineEditPassphraseAgain.text(): - QMessageBox.about( + QtGui.QMessageBox.about( self, _translate("MainWindow", "Passphrase mismatch"), _translate( "MainWindow", @@ -2572,7 +2593,7 @@ class MyForm(settingsmixin.SMainWindow): " match. Try again.") ) elif dialog.lineEditPassphrase.text() == "": - QMessageBox.about( + QtGui.QMessageBox.about( self, _translate("MainWindow", "Choose a passphrase"), _translate( "MainWindow", "You really do need a passphrase.") @@ -2780,14 +2801,14 @@ class MyForm(settingsmixin.SMainWindow): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - font = QFont() + font = QtGui.QFont() font.setBold(True) inventoryHashesToMarkUnread = [] modified = 0 for row in tableWidget.selectedIndexes(): currentRow = row.row() inventoryHashToMarkUnread = str(tableWidget.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) + currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) if inventoryHashToMarkUnread in inventoryHashesToMarkUnread: # it returns columns as separate items, so we skip dupes continue @@ -2807,9 +2828,9 @@ class MyForm(settingsmixin.SMainWindow): if rowcount == 1: # performance optimisation - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder()) + 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(Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + 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) # 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. @@ -2873,7 +2894,7 @@ class MyForm(settingsmixin.SMainWindow): fromAddressAtCurrentInboxRow = tableWidget.item( currentInboxRow, 1).address msgid = str(tableWidget.item( - currentInboxRow, 3).data(Qt.UserRole).toPyObject()) + currentInboxRow, 3).data(QtCore.Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: @@ -2892,10 +2913,10 @@ class MyForm(settingsmixin.SMainWindow): # toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow elif not BMConfigParser().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), QMessageBox.Ok) + "MainWindow", "Bitmessage cannot find your address %1. Perhaps you removed it?").arg(toAddressAtCurrentInboxRow), QtGui.QMessageBox.Ok) elif not BMConfigParser().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."), 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."), QtGui.QMessageBox.Ok) else: self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow) broadcast_tab_index = self.ui.tabWidgetSend.indexOf( @@ -2943,7 +2964,7 @@ class MyForm(settingsmixin.SMainWindow): currentInboxRow = tableWidget.currentRow() # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() addressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole) + currentInboxRow, 1).data(QtCore.Qt.UserRole) self.ui.tabWidget.setCurrentIndex( self.ui.tabWidget.indexOf(self.ui.send) ) @@ -2958,9 +2979,9 @@ class MyForm(settingsmixin.SMainWindow): currentInboxRow = tableWidget.currentRow() # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() addressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole) + currentInboxRow, 1).data(QtCore.Qt.UserRole) recipientAddress = tableWidget.item( - currentInboxRow, 0).data(Qt.UserRole) + currentInboxRow, 0).data(QtCore.Qt.UserRole) # Let's make sure that it isn't already in the address book queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) @@ -2983,15 +3004,16 @@ class MyForm(settingsmixin.SMainWindow): messageLists = (messageLists) for messageList in messageLists: if row is not None: - inventoryHash = str(messageList.item(row, 3).data(Qt.UserRole).toPyObject()) + 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(Qt.UserRole).toPyObject() == inventoryHash: + 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(Qt.UserRole).toPyObject() == ackData: + if messageList.item(i, 3).data(QtCore.Qt.UserRole).toPyObject() == ackData: messageList.removeRow(i) # Send item on the Inbox tab to trash @@ -3065,13 +3087,14 @@ class MyForm(settingsmixin.SMainWindow): return currentInboxRow = tableWidget.currentRow() try: - subjectAtCurrentInboxRow = str(tableWidget.item(currentInboxRow,2).data(Qt.UserRole)) + subjectAtCurrentInboxRow = str(tableWidget.item( + currentInboxRow, 2).data(QtCore.Qt.UserRole)) except: subjectAtCurrentInboxRow = '' # Retrieve the message data out of the SQL database msgid = str(tableWidget.item( - currentInboxRow, 3).data(Qt.UserRole).toPyObject()) + currentInboxRow, 3).data(QtCore.Qt.UserRole).toPyObject()) queryreturn = sqlQuery( '''select message from inbox where msgid=?''', msgid) if queryreturn != []: @@ -3079,7 +3102,7 @@ class MyForm(settingsmixin.SMainWindow): message, = row defaultFilename = "".join(x for x in subjectAtCurrentInboxRow if x.isalnum()) + '.txt' - filename = QFileDialog.getSaveFileName(self, _translate("MainWindow","Save As..."), defaultFilename, "Text files (*.txt);;All files (*.*)") + filename = QtGui.QFileDialog.getSaveFileName(self, _translate("MainWindow","Save As..."), defaultFilename, "Text files (*.txt);;All files (*.*)") if filename == '': return try: @@ -3102,13 +3125,13 @@ class MyForm(settingsmixin.SMainWindow): while tableWidget.selectedIndexes() != []: currentRow = tableWidget.selectedIndexes()[0].row() ackdataToTrash = str(tableWidget.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) + 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(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + 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.statusBar().showMessage(_translate( @@ -3121,7 +3144,7 @@ class MyForm(settingsmixin.SMainWindow): def on_action_ForceSend(self): currentRow = self.ui.tableWidgetInbox.currentRow() addressAtCurrentRow = self.ui.tableWidgetInbox.item( - currentRow, 0).data(Qt.UserRole) + currentRow, 0).data(QtCore.Qt.UserRole) toRipe = decodeAddress(addressAtCurrentRow)[3] sqlExecute( '''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''', @@ -3136,7 +3159,7 @@ class MyForm(settingsmixin.SMainWindow): def on_action_SentClipboard(self): currentRow = self.ui.tableWidgetInbox.currentRow() addressAtCurrentRow = self.ui.tableWidgetInbox.item( - currentRow, 0).data(Qt.UserRole) + currentRow, 0).data(QtCore.Qt.UserRole) clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) @@ -3207,7 +3230,11 @@ 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.statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want."), 10000) + self.statusBar().showMessage(_translate( + "MainWindow", + "Error: You cannot add the same address to your" + " subscriptions twice. Perhaps rename the existing" + " one if you want."), 10000) continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) @@ -3240,9 +3267,21 @@ class MyForm(settingsmixin.SMainWindow): # 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?"), QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: + 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=?''', @@ -3366,12 +3405,13 @@ class MyForm(settingsmixin.SMainWindow): currentRow = messagelist.currentRow() if currentRow >= 0: msgid = str(messagelist.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) # data is saved at the 4. column of the table... + 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(); + currentIndex = self.ui.tabWidget.currentIndex() messagelistList = [ self.ui.textEditInboxMessage, False, @@ -3394,9 +3434,9 @@ class MyForm(settingsmixin.SMainWindow): except: return self.ui.textEditInboxMessage - def getCurrentSearchLine(self, currentIndex = None, retObj = False): + def getCurrentSearchLine(self, currentIndex=None, retObj=False): if currentIndex is None: - currentIndex = self.ui.tabWidget.currentIndex(); + currentIndex = self.ui.tabWidget.currentIndex() messagelistList = [ self.ui.inboxSearchLineEdit, False, @@ -3411,9 +3451,9 @@ class MyForm(settingsmixin.SMainWindow): else: return None - def getCurrentSearchOption(self, currentIndex = None): + def getCurrentSearchOption(self, currentIndex=None): if currentIndex is None: - currentIndex = self.ui.tabWidget.currentIndex(); + currentIndex = self.ui.tabWidget.currentIndex() messagelistList = [ self.ui.inboxSearchOption, False, @@ -3426,7 +3466,7 @@ class MyForm(settingsmixin.SMainWindow): return None # Group of functions for the Your Identities dialog box - def getCurrentItem(self, treeWidget = None): + def getCurrentItem(self, treeWidget=None): if treeWidget is None: treeWidget = self.getCurrentTreeWidget() if treeWidget: @@ -3435,7 +3475,7 @@ class MyForm(settingsmixin.SMainWindow): return currentItem return False - def getCurrentAccount(self, treeWidget = None): + def getCurrentAccount(self, treeWidget=None): currentItem = self.getCurrentItem(treeWidget) if currentItem: account = currentItem.address @@ -3444,7 +3484,7 @@ class MyForm(settingsmixin.SMainWindow): # TODO need debug msg? return False - def getCurrentFolder(self, treeWidget = None): + def getCurrentFolder(self, treeWidget=None): if treeWidget is None: treeWidget = self.getCurrentTreeWidget() #treeWidget = self.ui.treeWidgetYourIdentities @@ -3470,9 +3510,21 @@ class MyForm(settingsmixin.SMainWindow): def on_action_YourIdentitiesDelete(self): account = self.getCurrentItem() if account.type == AccountMixin.NORMAL: - return # maybe in the future + 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?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: + 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 @@ -3526,18 +3578,18 @@ class MyForm(settingsmixin.SMainWindow): else: currentColumn = 1 if self.getCurrentFolder() == "sent": - myAddress = tableWidget.item(currentRow, 1).data(Qt.UserRole) - otherAddress = tableWidget.item(currentRow, 0).data(Qt.UserRole) + 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(Qt.UserRole) - otherAddress = tableWidget.item(currentRow, 1).data(Qt.UserRole) + 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(Qt.UserRole) + text = tableWidget.item(currentRow, currentColumn).data(QtCore.Qt.UserRole) text = unicode(str(text), 'utf-8', 'ignore') clipboard = QtGui.QApplication.clipboard() clipboard.setText(text) @@ -3580,7 +3632,10 @@ class MyForm(settingsmixin.SMainWindow): current_files += [upper] filters[0:0] = ['Image files (' + ' '.join(all_images_filter) + ')'] filters[1:1] = ['All files (*.*)'] - sourcefile = QFileDialog.getOpenFileName(self, _translate("MainWindow","Set avatar..."), filter = ';;'.join(filters)) + sourcefile = QtGui.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] exists = QtCore.QFile.exists(destination) @@ -3730,7 +3785,7 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuInbox.addAction(self.actionMarkUnread) self.popMenuInbox.addSeparator() address = tableWidget.item( - tableWidget.currentRow(), 0).data(Qt.UserRole) + tableWidget.currentRow(), 0).data(QtCore.Qt.UserRole) account = accountClass(address) if account.type == AccountMixin.CHAN: self.popMenuInbox.addAction(self.actionReplyChan) @@ -3762,7 +3817,7 @@ class MyForm(settingsmixin.SMainWindow): currentRow = self.ui.tableWidgetInbox.currentRow() if currentRow >= 0: ackData = str(self.ui.tableWidgetInbox.item( - currentRow, 3).data(Qt.UserRole).toPyObject()) + currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) queryreturn = sqlQuery('''SELECT status FROM sent where ackdata=?''', ackData) for row in queryreturn: status, = row @@ -3799,7 +3854,7 @@ class MyForm(settingsmixin.SMainWindow): searchOption = self.getCurrentSearchOption() messageTextedit = self.getCurrentMessageTextedit() if messageTextedit: - messageTextedit.setPlainText(QString("")) + messageTextedit.setPlainText(QtCore.QString("")) messagelist = self.getCurrentMessagelist() if messagelist: account = self.getCurrentAccount() @@ -3885,7 +3940,7 @@ class MyForm(settingsmixin.SMainWindow): if refresh: if not tableWidget: return - font = QFont() + font = QtGui.QFont() font.setBold(False) # inventoryHashesToMarkRead = [] # inventoryHashToMarkRead = str(tableWidget.item( @@ -3896,7 +3951,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 2).setUnread(False) tableWidget.item(currentRow, 3).setFont(font) if propagate: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) else: data = self.getCurrentMessageId() @@ -4188,7 +4243,7 @@ class settingsDialog(QtGui.QDialog): # 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(QTableWidgetItem): +class myTableWidgetItem(QtGui.QTableWidgetItem): def __lt__(self, other): return int(self.data(33).toPyObject()) < int(other.data(33).toPyObject()) @@ -4197,7 +4252,8 @@ class myTableWidgetItem(QTableWidgetItem): app = None myapp = None -class MySingleApplication(QApplication): + +class MySingleApplication(QtGui.QApplication): """ Listener to allow our Qt form to get focus when another instance of the application is open. @@ -4247,12 +4303,14 @@ class MySingleApplication(QApplication): if myapp: myapp.appIndicatorShow() + def init(): global app if not app: app = MySingleApplication(sys.argv) return app + def run(): global myapp app = init() -- 2.45.1 From ece5ad91137cdbd9723b7493614ab2dd766045d5 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 23 Jan 2018 11:48:59 +0200 Subject: [PATCH 1043/1102] Separated dialogs which deal with addresses into address_dialogs module --- src/bitmessageqt/address_dialogs.py | 274 +++++++++++++++++++++++++++ src/bitmessageqt/dialogs.py | 281 +--------------------------- 2 files changed, 284 insertions(+), 271 deletions(-) create mode 100644 src/bitmessageqt/address_dialogs.py diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py new file mode 100644 index 00000000..0492dbec --- /dev/null +++ b/src/bitmessageqt/address_dialogs.py @@ -0,0 +1,274 @@ +from PyQt4 import QtCore, QtGui +from addresses import decodeAddress, encodeVarint +from account import ( + GatewayAccount, MailchuckAccount, AccountMixin, accountClass, + getSortedAccounts +) +from tr import _translate +from retranslateui import RetranslateMixin +import widgets + +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", "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 AddAddressDialog(QtGui.QDialog, RetranslateMixin, AddressCheckMixin): + + def __init__(self, parent=None): + super(AddAddressDialog, self).__init__(parent) + widgets.load('addaddressdialog.ui', self) + AddressCheckMixin.__init__(self) + + +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)) + + +class NewSubscriptionDialog( + QtGui.QDialog, RetranslateMixin, AddressCheckMixin): + + 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 %1 recent broadcast(s) from this address." + ).arg(count)) + + +class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): + def __init__(self, parent=None): + super(RegenerateAddressesDialog, self).__init__(parent) + widgets.load('regenerateaddresses.ui', self) + 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( + "MainWindow", + "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, title=None, label=None, config=None): + super(EmailGatewayDialog, self).__init__(parent) + widgets.load('emailgateway.ui', self) + self.parent = parent + self.config = config + if title and label: + self.setWindowTitle(title) + self.label.setText(label) + 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 register(self, acct=None): + email = str(self.lineEditEmail.text().toUtf8()) + if acct is None: + acct = self.acct + acct.register(email) + self.config.set(acct.fromAddress, 'label', email) + self.config.set(acct.fromAddress, 'gateway', 'mailchuck') + self.config.save() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway registration request" + ), 10000) + + 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(): + self.register() + elif self.radioButtonUnregister.isChecked(): + self.acct.unregister() + self.config.remove_option(self.acct.fromAddress, 'gateway') + self.config.save() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway unregistration request" + ), 10000) + elif self.radioButtonStatus.isChecked(): + self.acct.status() + self.parent.statusBar().showMessage(_translate( + "MainWindow", + "Sending email gateway status request" + ), 10000) + elif self.radioButtonSettings.isChecked(): + return self.acct diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index c7cd5bd4..80bffed4 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -1,143 +1,23 @@ -from PyQt4 import QtCore, QtGui -from addresses import decodeAddress, encodeVarint -from account import ( - GatewayAccount, MailchuckAccount, AccountMixin, accountClass, - getSortedAccounts -) +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 hashlib import paths -from inventory import Inventory from version import softwareVersion -__all__ = [NewChanDialog] - - -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", "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 AddAddressDialog(QtGui.QDialog, RetranslateMixin, AddressCheckMixin): - - def __init__(self, parent=None): - super(AddAddressDialog, self).__init__(parent) - widgets.load('addaddressdialog.ui', self) - AddressCheckMixin.__init__(self) - - -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)) - - -class NewSubscriptionDialog( - QtGui.QDialog, RetranslateMixin, AddressCheckMixin): - - 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 %1 recent broadcast(s) from this address." - ).arg(count)) - - -class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent=None): - super(RegenerateAddressesDialog, self).__init__(parent) - widgets.load('regenerateaddresses.ui', self) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) +__all__ = [ + "NewChanDialog", "AddAddressDialog", "NewAddressDialog", + "NewSubscriptionDialog", "RegenerateAddressesDialog", + "SpecialAddressBehaviorDialog", "EmailGatewayDialog" +] class AboutDialog(QtGui.QDialog, RetranslateMixin): @@ -194,144 +74,3 @@ class ConnectDialog(QtGui.QDialog, RetranslateMixin): super(ConnectDialog, self).__init__(parent) widgets.load('connect.ui', self) 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( - "MainWindow", - "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, title=None, label=None, config=None): - super(EmailGatewayDialog, self).__init__(parent) - widgets.load('emailgateway.ui', self) - self.parent = parent - self.config = config - if title and label: - self.setWindowTitle(title) - self.label.setText(label) - 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 register(self, acct=None): - email = str(self.lineEditEmail.text().toUtf8()) - if acct is None: - acct = self.acct - acct.register(email) - self.config.set(acct.fromAddress, 'label', email) - self.config.set(acct.fromAddress, 'gateway', 'mailchuck') - self.config.save() - self.parent.statusBar().showMessage(_translate( - "MainWindow", - "Sending email gateway registration request" - ), 10000) - - 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(): - self.register() - elif self.radioButtonUnregister.isChecked(): - self.acct.unregister() - self.config.remove_option(self.acct.fromAddress, 'gateway') - self.config.save() - self.parent.statusBar().showMessage(_translate( - "MainWindow", - "Sending email gateway unregistration request" - ), 10000) - elif self.radioButtonStatus.isChecked(): - self.acct.status() - self.parent.statusBar().showMessage(_translate( - "MainWindow", - "Sending email gateway status request" - ), 10000) - elif self.radioButtonSettings.isChecked(): - return self.acct -- 2.45.1 From 41155406d62bc767bd44169dae02d9e406586eb6 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 23 Jan 2018 18:15:11 +0200 Subject: [PATCH 1044/1102] Simplified showing statusbar messages: - Use MyForm.statusbar set in __init__ instead of MyForm.statusBar() - MyForm.updateStatusBar() to show the message in MyForm methods - queues.UISignalQueue.put(('updateStatusBar', msg)) in dialogs --- src/bitmessageqt/__init__.py | 338 ++++++++++++++++++---------- src/bitmessageqt/address_dialogs.py | 33 +-- 2 files changed, 237 insertions(+), 134 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index dfcb9685..ba4e3fd0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1522,7 +1522,6 @@ class MyForm(settingsmixin.SMainWindow): pass # QtGui.QWidget.changeEvent(self, event) - def __icon_activated(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self.actionShow.setChecked(not self.actionShow.isChecked()) @@ -1547,8 +1546,12 @@ class MyForm(settingsmixin.SMainWindow): sound.SOUND_DISCONNECTED) if not BMConfigParser().safeGetBoolean('bitmessagesettings', 'upnp') and \ BMConfigParser().get('bitmessagesettings', 'socksproxytype') == "none": - self.statusBar().showMessage(_translate( - "MainWindow", "Problems connecting? Try enabling UPnP in the Network Settings"), 10000) + self.updateStatusBar( + _translate( + "MainWindow", + "Problems connecting? Try enabling UPnP in the Network" + " Settings" + )) self.connected = False if self.actionStatus is not None: @@ -1556,8 +1559,8 @@ 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() + 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")) shared.statusIconColor = 'yellow' @@ -1574,8 +1577,8 @@ 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() + 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")) shared.statusIconColor = 'green' @@ -1705,19 +1708,24 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tableWidgetInboxChans]): for i in range(inbox.rowCount()): if msgid == str(inbox.item(i, 3).data(QtCore.Qt.UserRole).toPyObject()): - self.statusBar().showMessage(_translate( - "MainWindow", "Message trashed"), 10000) + 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.statusBar().showMessage(_translate("MainWindow", "New version of PyBitmessage is available: %1. Download it from https://github.com/Bitmessage/PyBitmessage/releases/latest").arg(self.notifiedNewVersion), 10000) + self.updateStatusBar(_translate( + "MainWindow", + "New version of PyBitmessage is available: %1. Download it" + " from https://github.com/Bitmessage/PyBitmessage/releases/latest" + ).arg(self.notifiedNewVersion) + ) def displayAlert(self, title, text, exitAfterUserClicksOk): - self.statusBar().showMessage(text) + self.updateStatusBar(text) QtGui.QMessageBox.critical(self, title, text, QtGui.QMessageBox.Ok) if exitAfterUserClicksOk: os._exit(0) @@ -1799,7 +1807,7 @@ class MyForm(settingsmixin.SMainWindow): def click_pushButtonSend(self): encoding = 3 if QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier else 2 - self.statusBar().clearMessage() + self.statusbar.clearMessage() if self.ui.tabWidgetSend.currentIndex() == \ self.ui.tabWidgetSend.indexOf(self.ui.sendDirect): @@ -1871,8 +1879,14 @@ class MyForm(settingsmixin.SMainWindow): BMConfigParser().set(fromAddress, 'label', email) BMConfigParser().set(fromAddress, 'gateway', 'mailchuck') BMConfigParser().save() - self.statusBar().showMessage(_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), 10000) + 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) @@ -1884,32 +1898,68 @@ class MyForm(settingsmixin.SMainWindow): logger.error('Error: Could not decode recipient address ' + toAddress + ':' + status) if status == 'missingbm': - self.statusBar().showMessage(_translate( - "MainWindow", "Error: Bitmessage addresses start with BM- Please check the recipient address %1").arg(toAddress), 10000) + self.updateStatusBar(_translate( + "MainWindow", + "Error: Bitmessage addresses start with" + " BM- Please check the recipient address %1" + ).arg(toAddress)) elif status == 'checksumfailed': - self.statusBar().showMessage(_translate( - "MainWindow", "Error: The recipient address %1 is not typed or copied correctly. Please check it.").arg(toAddress), 10000) + self.statusbar_message(_translate( + "MainWindow", + "Error: The recipient address %1 is not" + " typed or copied correctly. Please check it." + ).arg(toAddress)) elif status == 'invalidcharacters': - self.statusBar().showMessage(_translate( - "MainWindow", "Error: The recipient address %1 contains invalid characters. Please check it.").arg(toAddress), 10000) + self.updateStatusBar(_translate( + "MainWindow", + "Error: The recipient address %1 contains" + " invalid characters. Please check it." + ).arg(toAddress)) elif status == 'versiontoohigh': - self.statusBar().showMessage(_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), 10000) + 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)) elif status == 'ripetooshort': - self.statusBar().showMessage(_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), 10000) + 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)) elif status == 'ripetoolong': - self.statusBar().showMessage(_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), 10000) + 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)) elif status == 'varintmalformed': - self.statusBar().showMessage(_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), 10000) + 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)) else: - self.statusBar().showMessage(_translate( - "MainWindow", "Error: Something is wrong with the recipient address %1.").arg(toAddress), 10000) + self.updateStatusBar(_translate( + "MainWindow", + "Error: Something is wrong with the" + " recipient address %1." + ).arg(toAddress)) elif fromAddress == '': - self.statusBar().showMessage(_translate( - "MainWindow", "Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab."), 10000) + self.updateStatusBar(_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) @@ -1921,11 +1971,17 @@ class MyForm(settingsmixin.SMainWindow): QtGui.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.clearMessage() if shared.statusIconColor == 'red': - 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.")) - stealthLevel = BMConfigParser().safeGetInt('bitmessagesettings', 'ackstealthlevel') + 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) t = () sqlExecute( @@ -1965,18 +2021,21 @@ class MyForm(settingsmixin.SMainWindow): if self.replyFromTab is not None: self.ui.tabWidget.setCurrentIndex(self.replyFromTab) self.replyFromTab = None - self.statusBar().showMessage(_translate( - "MainWindow", "Message queued."), 10000) - #self.ui.tableWidgetInbox.setCurrentCell(0, 0) + self.updateStatusBar(_translate( + "MainWindow", "Message queued.")) + # self.ui.tableWidgetInbox.setCurrentCell(0, 0) else: - self.statusBar().showMessage(_translate( - "MainWindow", "Your \'To\' field is empty."), 10000) + self.updateStatusBar(_translate( + "MainWindow", "Your \'To\' field is empty.")) else: # User selected 'Broadcast' if fromAddress == '': - self.statusBar().showMessage(_translate( - "MainWindow", "Error: You must specify a From address. If you don\'t have one, go to the \'Your Identities\' tab."), 10000) + self.updateStatusBar(_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.clearMessage() # 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. @@ -2016,30 +2075,32 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tabWidget.indexOf(self.ui.send) ) self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) - self.statusBar().showMessage(_translate( - "MainWindow", "Broadcast queued."), 10000) + self.updateStatusBar(_translate( + "MainWindow", "Broadcast queued.")) def click_pushButtonLoadFromAddressBook(self): self.ui.tabWidget.setCurrentIndex(5) for i in range(4): time.sleep(0.1) - self.statusBar().clearMessage() + self.statusbar.clearMessage() time.sleep(0.1) - self.statusBar().showMessage(_translate( - "MainWindow", "Right click one or more entries in your address book and select \'Send message to this address\'."), 10000) + self.updateStatusBar(_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()) if err is not None: - self.statusBar().showMessage(_translate( - "MainWindow", "Error: %1").arg(err), 10000) + self.statusbar_message("Error: %1", args=[err]) else: identities[-1] = addr self.ui.lineEditTo.setText("; ".join(identities)) - self.statusBar().showMessage(_translate( - "MainWindow", "Fetched address from namecoin identity."), 10000) + self.updateStatusBar(_translate( + "MainWindow", "Fetched address from namecoin identity.")) def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): # If this is a chan then don't let people broadcast because no one @@ -2183,23 +2244,22 @@ class MyForm(settingsmixin.SMainWindow): dialog = dialogs.AddAddressDialog(self) if dialog.exec_(): if not dialog.valid: - self.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "The address you entered was invalid. Ignoring it." - ), 10000) + )) return - address = addBMIfNotPresent(str(dialog.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. if shared.isAddressInMyAddressBook(address): - self.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "Error: You cannot add the same address to your" " address book twice. Try renaming the existing one" " if you want." - ), 10000) + )) return label = str(dialog.lineEditLabel.text().toUtf8()) self.addEntryToAddressBook(address, label) @@ -2231,23 +2291,22 @@ class MyForm(settingsmixin.SMainWindow): dialog = dialogs.NewSubscriptionDialog(self) if dialog.exec_(): if not dialog.valid: - self.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "The address you entered was invalid. Ignoring it." - ), 10000) + )) return - address = addBMIfNotPresent(str(dialog.lineEditAddress.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( + self.updateStatusBar(_translate( "MainWindow", "Error: You cannot add the same address to your" " subscriptions twice. Perhaps rename the existing one" " if you want." - ), 10000) + )) return label = str(dialog.lineEditLabel.text().toUtf8()) self.addSubscription(address, label) @@ -2322,7 +2381,7 @@ class MyForm(settingsmixin.SMainWindow): QtGui.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() + self.statusbar.clearMessage() state.resetNetworkProtocolAvailability() # just in case we changed something in the network connectivity if self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': BMConfigParser().set('bitmessagesettings', 'socksproxytype', str( @@ -2674,23 +2733,27 @@ class MyForm(settingsmixin.SMainWindow): self.quitAccepted = True - self.statusBar().showMessage(_translate( - "MainWindow", "Shutting down PyBitmessage... %1%").arg(str(0))) + self.updateStatusBar(_translate( + "MainWindow", "Shutting down PyBitmessage... %1%").arg(0)) if waitForConnection: - self.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "Waiting for network connection...")) while shared.statusIconColor == 'red': time.sleep(0.5) - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + 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.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "Waiting for finishing synchronisation...")) while PendingDownloadQueue.totalSize() > 0: time.sleep(0.5) - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) if waitForPow: # check if PoW queue empty @@ -2702,51 +2765,83 @@ class MyForm(settingsmixin.SMainWindow): if curWorkerQueue > maxWorkerQueue: maxWorkerQueue = curWorkerQueue if curWorkerQueue > 0: - self.statusBar().showMessage(_translate("MainWindow", "Waiting for PoW to finish... %1%").arg(str(50 * (maxWorkerQueue - curWorkerQueue) / maxWorkerQueue))) + 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.statusBar().showMessage(_translate("MainWindow", "Shutting down Pybitmessage... %1%").arg(str(50))) - - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + 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: - time.sleep(0.5) # a bit of time so that the hashHolder is populated - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) - + # 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.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(50))) + self.updateStatusBar(_translate( + "MainWindow", "Waiting for objects to be sent... %1%").arg(50)) try: while PendingUpload().progress() < 1: - self.statusBar().showMessage(_translate("MainWindow", "Waiting for objects to be sent... %1%").arg(str(int(50 + 20 * PendingUpload().progress())))) + 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) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) except PendingUploadDeadlineException: pass - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) # save state and geometry self and all widgets - self.statusBar().showMessage(_translate("MainWindow", "Saving settings... %1%").arg(str(70))) - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + 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): + if hasattr(obj, "__class__") \ + and isinstance(obj, settingsmixin.SettingsMixin): saveMethod = getattr(obj, "saveSettings", None) - if callable (saveMethod): + if callable(saveMethod): obj.saveSettings() - self.statusBar().showMessage(_translate("MainWindow", "Shutting down core... %1%").arg(str(80))) - QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 1000) + self.updateStatusBar(_translate( + "MainWindow", "Shutting down core... %1%").arg(80)) + QtCore.QCoreApplication.processEvents( + QtCore.QEventLoop.AllEvents, 1000 + ) shutdown.doCleanShutdown() - self.statusBar().showMessage(_translate("MainWindow", "Stopping notifications... %1%").arg(str(90))) + self.updateStatusBar(_translate( + "MainWindow", "Stopping notifications... %1%").arg(90)) self.tray.hide() - self.statusBar().showMessage(_translate("MainWindow", "Shutdown imminent... %1%").arg(str(100))) + self.updateStatusBar(_translate( + "MainWindow", "Shutdown imminent... %1%").arg(100)) shared.thisapp.cleanup() logger.info("Shutdown complete") super(MyForm, myapp).close() - #return + # return os._exit(0) # window close event @@ -2991,11 +3086,15 @@ class MyForm(settingsmixin.SMainWindow): label, addressAtCurrentInboxRow, True) self.ui.blackwhitelist.rerenderBlackWhiteList() - self.statusBar().showMessage(_translate( - "MainWindow", "Entry added to the blacklist. Edit the label to your liking."), 10000) + self.updateStatusBar(_translate( + "MainWindow", + "Entry added to the blacklist. Edit the label to your liking.") + ) else: - self.statusBar().showMessage(_translate( - "MainWindow", "Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want."), 10000) + 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: @@ -3047,9 +3146,9 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) tableWidget.setUpdatesEnabled(True) self.propagateUnreadCount(self.getCurrentAccount, folder) - self.statusBar().showMessage(_translate( - "MainWindow", "Moved items to trash."), 10000) - + self.updateStatusBar(_translate( + "MainWindow", "Moved items to trash.")) + def on_action_TrashUndelete(self): tableWidget = self.getCurrentMessagelist() if not tableWidget: @@ -3078,8 +3177,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.selectRow(0 if currentRow == 0 else currentRow - 1) tableWidget.setUpdatesEnabled(True) self.propagateUnreadCount(self.getCurrentAccount) - self.statusBar().showMessage(_translate( - "MainWindow", "Undeleted items."), 10000) + self.updateStatusBar(_translate("MainWindow", "Undeleted item.")) def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3109,9 +3207,9 @@ class MyForm(settingsmixin.SMainWindow): f = open(filename, 'w') f.write(message) f.close() - except Exception, e: + except Exception: logger.exception('Message not saved', exc_info=True) - self.statusBar().showMessage(_translate("MainWindow", "Write error."), 10000) + self.updateStatusBar(_translate("MainWindow", "Write error.")) # Send item on the Sent tab to trash def on_action_SentTrash(self): @@ -3134,12 +3232,11 @@ class MyForm(settingsmixin.SMainWindow): 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.statusBar().showMessage(_translate( - "MainWindow", "Moved items to trash."), 10000) - if currentRow == 0: - self.ui.tableWidgetInbox.selectRow(currentRow) - else: - self.ui.tableWidgetInbox.selectRow(currentRow - 1) + self.updateStatusBar(_translate( + "MainWindow", "Moved items to trash.")) + + self.ui.tableWidgetInbox.selectRow( + currentRow if currentRow == 0 else currentRow - 1) def on_action_ForceSend(self): currentRow = self.ui.tableWidgetInbox.currentRow() @@ -3214,10 +3311,10 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(unicode( self.ui.lineEditTo.text().toUtf8(), encoding="UTF-8") + '; ' + stringToAdd) if listOfSelectedRows == {}: - self.statusBar().showMessage(_translate( - "MainWindow", "No addresses selected."), 10000) + self.updateStatusBar(_translate( + "MainWindow", "No addresses selected.")) else: - self.statusBar().clearMessage() + self.statusbar.clearMessage() self.ui.tabWidget.setCurrentIndex( self.ui.tabWidget.indexOf(self.ui.send) ) @@ -3230,11 +3327,11 @@ 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.statusBar().showMessage(_translate( + self.updateStatusBar(_translate( "MainWindow", "Error: You cannot add the same address to your" " subscriptions twice. Perhaps rename the existing" - " one if you want."), 10000) + " one if you want.")) continue labelAtCurrentRow = self.ui.tableWidgetAddressBook.item(currentRow,0).text().toUtf8() self.addSubscription(addressAtCurrentRow, labelAtCurrentRow) @@ -3991,9 +4088,9 @@ class MyForm(settingsmixin.SMainWindow): logger.info('Status bar: ' + message) if option == 1: - self.statusBar().addImportant(message) + self.statusbar.addImportant(message) else: - self.statusBar().showMessage(message, 10000) + self.statusbar.showMessage(message, 10000) def initSettings(self): QtCore.QCoreApplication.setOrganizationName("PyBitmessage") @@ -4001,9 +4098,10 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QCoreApplication.setApplicationName("pybitmessageqt") self.loadSettings() for attr, obj in self.ui.__dict__.iteritems(): - if hasattr(obj, "__class__") and isinstance(obj, settingsmixin.SettingsMixin): + if hasattr(obj, "__class__") and \ + isinstance(obj, settingsmixin.SettingsMixin): loadMethod = getattr(obj, "loadSettings", None) - if callable (loadMethod): + if callable(loadMethod): obj.loadSettings() diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index 0492dbec..52137890 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -8,6 +8,7 @@ from tr import _translate from retranslateui import RetranslateMixin import widgets +import queues import hashlib from inventory import Inventory @@ -32,7 +33,9 @@ class AddressCheckMixin(object): self._onSuccess(addressVersion, streamNumber, ripe) elif status == 'missingbm': self.labelAddressCheck.setText(_translate( - "MainWindow", "The address should start with ''BM-''")) + "MainWindow", # dialog name should be here + "The address should start with ''BM-''" + )) elif status == 'checksumfailed': self.labelAddressCheck.setText(_translate( "MainWindow", @@ -47,7 +50,9 @@ class AddressCheckMixin(object): )) elif status == 'invalidcharacters': self.labelAddressCheck.setText(_translate( - "MainWindow", "The address contains invalid characters.")) + "MainWindow", + "The address contains invalid characters." + )) elif status == 'ripetooshort': self.labelAddressCheck.setText(_translate( "MainWindow", @@ -55,7 +60,9 @@ class AddressCheckMixin(object): )) elif status == 'ripetoolong': self.labelAddressCheck.setText(_translate( - "MainWindow", "Some data encoded in the address is too long.")) + "MainWindow", + "Some data encoded in the address is too long." + )) elif status == 'varintmalformed': self.labelAddressCheck.setText(_translate( "MainWindow", @@ -152,7 +159,7 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin): if self.address_is_chan: # address is a chan address self.radioButtonBehaviorMailingList.setDisabled(True) self.lineEditMailingListName.setText(_translate( - "MainWindow", + "SpecialAddressBehaviorDialog", "This is a chan address. You cannot use it as a" " pseudo-mailing list." )) @@ -240,10 +247,8 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): self.config.set(acct.fromAddress, 'label', email) self.config.set(acct.fromAddress, 'gateway', 'mailchuck') self.config.save() - self.parent.statusBar().showMessage(_translate( - "MainWindow", - "Sending email gateway registration request" - ), 10000) + self.parent.statusbar_message( + "Sending email gateway registration request") def accept(self): self.hide() @@ -260,15 +265,15 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): self.acct.unregister() self.config.remove_option(self.acct.fromAddress, 'gateway') self.config.save() - self.parent.statusBar().showMessage(_translate( - "MainWindow", + queues.UISignalQueue.put(('updateStatusBar', _translate( + "EmailGatewayDialog", "Sending email gateway unregistration request" - ), 10000) + ))) elif self.radioButtonStatus.isChecked(): self.acct.status() - self.parent.statusBar().showMessage(_translate( - "MainWindow", + queues.UISignalQueue.put(('updateStatusBar', _translate( + "EmailGatewayDialog", "Sending email gateway status request" - ), 10000) + ))) elif self.radioButtonSettings.isChecked(): return self.acct -- 2.45.1 From afcd83a43450f9f92b11bba24ec43769bc30b668 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 24 Jan 2018 17:27:51 +0200 Subject: [PATCH 1045/1102] This is probably the right way to handle modal dialogs --- src/bitmessageqt/__init__.py | 207 ++++++++++------------------ src/bitmessageqt/address_dialogs.py | 117 ++++++++++++---- 2 files changed, 168 insertions(+), 156 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ba4e3fd0..e0166962 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2225,44 +2225,31 @@ class MyForm(settingsmixin.SMainWindow): if hasattr(acct, "feedback") \ and acct.feedback != GatewayAccount.ALL_OK: if acct.feedback == GatewayAccount.REGISTRATION_DENIED: - dialog = dialogs.EmailGatewayDialog( - self, - _translate( - "EmailGatewayRegistrationDialog", - "Registration failed:"), - _translate( - "EmailGatewayRegistrationDialog", - "The requested email address is not available," - " please try a new one."), - config=BMConfigParser() - ) - if dialog.exec_(): - dialog.register(acct) + dialogs.EmailGatewayDialog( + self, BMConfigParser(), acct).exec_() def click_pushButtonAddAddressBook(self, dialog=None): if not dialog: dialog = dialogs.AddAddressDialog(self) - if dialog.exec_(): - if not dialog.valid: - self.updateStatusBar(_translate( - "MainWindow", - "The address you entered was invalid. Ignoring it." - )) - return - address = addBMIfNotPresent(str(dialog.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. - 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 - label = str(dialog.lineEditLabel.text().toUtf8()) - self.addEntryToAddressBook(address, label) + dialog.exec_() + try: + address, label = dialog.data + except AttributeError: + return + + # 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 + + self.addEntryToAddressBook(address, label) def addEntryToAddressBook(self, address, label): if shared.isAddressInMyAddressBook(address): @@ -2289,35 +2276,33 @@ class MyForm(settingsmixin.SMainWindow): def click_pushButtonAddSubscription(self): dialog = dialogs.NewSubscriptionDialog(self) - if dialog.exec_(): - if not dialog.valid: - self.updateStatusBar(_translate( - "MainWindow", - "The address you entered was invalid. Ignoring it." + 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 )) - return - address = addBMIfNotPresent(str(dialog.lineEditAddress.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.updateStatusBar(_translate( - "MainWindow", - "Error: You cannot add the same address to your" - " subscriptions twice. Perhaps rename the existing one" - " if you want." - )) - return - label = str(dialog.lineEditLabel.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 - # to the objectProcessorQueue to be processed - if dialog.checkBoxDisplayMessagesAlreadyInInventory.isChecked(): - for value in dialog.recent: - queues.objectProcessorQueue.put(( - value.type, value.payload - )) def click_pushButtonStatusIcon(self): dialogs.IconGlossaryDialog(self, config=BMConfigParser()).exec_() @@ -2557,29 +2542,32 @@ class MyForm(settingsmixin.SMainWindow): def on_action_EmailGatewayDialog(self): dialog = dialogs.EmailGatewayDialog(self, config=BMConfigParser()) # For Modal dialogs - acct = dialog.exec_() + dialog.exec_() + try: + acct = dialog.data + except AttributeError: + return - # Only settings ramain here - if acct: - 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) + # 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() + 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( @@ -2621,53 +2609,7 @@ class MyForm(settingsmixin.SMainWindow): addressAtCurrentRow, self.getCurrentFolder(), None, 0) def click_NewAddressDialog(self): - dialog = dialogs.NewAddressDialog(self) - # For Modal dialogs - if not dialog.exec_(): - logger.debug('new address dialog box rejected') - return - - # dialog.buttonBox.enabled = False - if dialog.radioButtonRandomAddress.isChecked(): - if dialog.radioButtonMostAvailable.isChecked(): - streamNumberForAddress = 1 - else: - # User selected 'Use the same stream as an existing - # address.' - streamNumberForAddress = decodeAddress( - dialog.comboBoxExisting.currentText())[2] - queues.addressGeneratorQueue.put(( - 'createRandomAddress', 4, streamNumberForAddress, - str(dialog.newaddresslabel.text().toUtf8()), 1, "", - dialog.checkBoxEighteenByteRipe.isChecked() - )) - else: - if dialog.lineEditPassphrase.text() != \ - dialog.lineEditPassphraseAgain.text(): - QtGui.QMessageBox.about( - self, _translate("MainWindow", "Passphrase mismatch"), - _translate( - "MainWindow", - "The passphrase you entered twice doesn\'t" - " match. Try again.") - ) - elif dialog.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", - dialog.spinBoxNumberOfAddressesToMake.value(), - dialog.lineEditPassphrase.text().toUtf8(), - dialog.checkBoxEighteenByteRipe.isChecked() - )) + dialogs.NewAddressDialog(self) def network_switch(self): dontconnect_option = not BMConfigParser().safeGetBoolean( @@ -3063,9 +3005,8 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tabWidget.setCurrentIndex( self.ui.tabWidget.indexOf(self.ui.send) ) - dialog = dialogs.AddAddressDialog(self) - dialog.lineEditAddress.setText(addressAtCurrentInboxRow) - self.click_pushButtonAddAddressBook(dialog) + self.click_pushButtonAddAddressBook( + dialogs.AddAddressDialog(self, addressAtCurrentInboxRow)) def on_action_InboxAddSenderToBlackList(self): tableWidget = self.getCurrentMessagelist() diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index 52137890..dde08409 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -1,5 +1,5 @@ from PyQt4 import QtCore, QtGui -from addresses import decodeAddress, encodeVarint +from addresses import decodeAddress, encodeVarint, addBMIfNotPresent from account import ( GatewayAccount, MailchuckAccount, AccountMixin, accountClass, getSortedAccounts @@ -70,12 +70,33 @@ class AddressCheckMixin(object): )) -class AddAddressDialog(QtGui.QDialog, RetranslateMixin, AddressCheckMixin): +class AddressDataDialog(QtGui.QDialog, AddressCheckMixin): + def __init__(self, parent): + super(AddressDataDialog, self).__init__(parent) + self.parent = parent - def __init__(self, parent=None): + 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): @@ -91,10 +112,54 @@ class NewAddressDialog(QtGui.QDialog, RetranslateMixin): 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( - QtGui.QDialog, RetranslateMixin, AddressCheckMixin): +class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): def __init__(self, parent=None): super(NewSubscriptionDialog, self).__init__(parent) @@ -206,14 +271,20 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog, RetranslateMixin): class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): - def __init__(self, parent, title=None, label=None, config=None): + 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 title and label: - self.setWindowTitle(title) - self.label.setText(label) + 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() @@ -239,17 +310,6 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): self.lineEditEmail.setFocus() QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) - def register(self, acct=None): - email = str(self.lineEditEmail.text().toUtf8()) - if acct is None: - acct = self.acct - acct.register(email) - self.config.set(acct.fromAddress, 'label', email) - self.config.set(acct.fromAddress, 'gateway', 'mailchuck') - self.config.save() - self.parent.statusbar_message( - "Sending email gateway registration request") - def accept(self): self.hide() # no chans / mailinglists @@ -259,8 +319,17 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): if not isinstance(self.acct, GatewayAccount): return - if self.radioButtonRegister.isChecked(): - self.register() + 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') @@ -276,4 +345,6 @@ class EmailGatewayDialog(QtGui.QDialog, RetranslateMixin): "Sending email gateway status request" ))) elif self.radioButtonSettings.isChecked(): - return self.acct + self.data = self.acct + + super(EmailGatewayDialog, self).accept() -- 2.45.1 From c92c2aebc2271736f9567efb7492985ccd07fb09 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Sat, 27 Jan 2018 16:40:01 +0200 Subject: [PATCH 1046/1102] Blank title of RegenerateAddressesDialog also --- src/bitmessageqt/address_dialogs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index dde08409..7b619625 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -202,6 +202,7 @@ 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)) -- 2.45.1 From 80ca82ad8b6da8e20c4d14711289309a8161ba99 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Tue, 30 Jan 2018 16:33:27 +0100 Subject: [PATCH 1047/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 94127 -> 94216 bytes src/translations/bitmessage_ru.ts | 456 ++++++++++++++++-------------- 2 files changed, 238 insertions(+), 218 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index 82604f65804e3eb917008e1b63b0678f848e6585..bd61a1fa8c6b498c84f83d81d39131e62154eabf 100644 GIT binary patch delta 3390 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 E0aV)Sod5s; delta 3290 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 diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 0473d209..3e020294 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -58,12 +58,12 @@ 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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: @@ -83,7 +83,7 @@ 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: @@ -168,52 +168,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 Новый адрес @@ -238,12 +238,12 @@ Please type the desired email address (including @mailchuck.com) below: Скопировать адрес в буфер обмена - + Special address behavior... Особое поведение адресов... - + Email gateway Email-шлюз @@ -253,37 +253,37 @@ Please type the desired email address (including @mailchuck.com) below: Удалить
- + 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +293,17 @@ Please type the desired email address (including @mailchuck.com) below:
- + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,78 +313,78 @@ Please type the desired email address (including @mailchuck.com) below:
- + 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 Подписки - + 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. @@ -393,19 +393,19 @@ 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.) @@ -415,37 +415,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -515,22 +515,22 @@ It is important that you back up this file. Would you like to open the file now?
- + 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 @@ -541,17 +541,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,57 +596,57 @@ It is important that you back up this file. Would you like to open the file now?
- + 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 Новое сообщение @@ -656,7 +656,7 @@ It is important that you back up this file. Would you like to open the file now?
- + Sending email gateway registration request Отправка запроса на регистрацию на Email-шлюзе @@ -671,142 +671,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 Отправка запроса на отмену регистрации на Email-шлюзе - + Sending email gateway status request Отправка запроса статуса аккаунта на Email-шлюзе - + 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? @@ -815,7 +815,7 @@ 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? @@ -824,277 +824,277 @@ 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. Это адрес 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). Вы используете TCP порт %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 Ctrl+Q - + F1 F1 - + Contact support Связаться с поддержкой - + About О программе - + Regenerate deterministic addresses Сгенерировать заново все адреса - + Delete all trashed messages Стереть все сообщения из корзины - + Join / Create chan Подключить или создать чан @@ -1119,67 +1119,67 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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 часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправлено @@ -1224,86 +1224,86 @@ Are you sure you want to delete the channel? Внимание: свободное место на диске закончилось. Bitmessage завершит свою работу. - + Error! Could not find sender address (your address) in the keys.dat file. Ошибка: невозможно найти адрес отправителя (ваш адрес) в файле ключей keys.dat - + 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 - + Doing work necessary to send message. There is no required difficulty for version 2 addresses like this. Выполнение работы, требуемой для отправки сообщения. Для адреса версии 2 (как этот), не требуется указание сложности. - + Doing work necessary to send message. Receiver's required difficulty: %1 and %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: 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 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. - + Message sent. Waiting for acknowledgement. Sent on %1 Отправлено. Ожидаем подтверждения. Отправлено в %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 Отправка запроса открытого ключа шифрования. Ожидание ответа. Запрошено в %1 @@ -1318,37 +1318,37 @@ Receiver's required difficulty: %1 and %2 Распределение портов 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1413,12 +1413,12 @@ Receiver's required difficulty: %1 and %2 Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + Set notification sound... Установить звук уведомления... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1432,110 +1432,125 @@ Receiver's required difficulty: %1 and %2 * участвуйте в обсуждениях в чанах - + 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? Вы пытаетесь отправить email вместо 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 Ошибка: %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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?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... Ожидание окончания синхронизации... - + + Undeleted items. + Восстановленные элементы. + + + You have already set a notification sound for this address book entry. Do you really want to overwrite it? У вас уже есть звук уведомления для этого адресата. Вы уверены, что хотите перезаписать звук уведомления? + + + Go online + Подключиться к сети + + + + Go offline + +
MessageView @@ -1804,25 +1819,30 @@ The 'Random Number' option is selected by default but deterministic ad 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 @@ -1953,7 +1973,7 @@ The 'Random Number' option is selected by default but deterministic ad Загрузка: 0 кБ/с - + Network Status Состояние сети -- 2.45.1 From 9807d3e4b41cbbe38843530a2e7bd859b8312e15 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 30 Jan 2018 17:42:10 +0100 Subject: [PATCH 1048/1102] Don't complain about being disconnected if in offline mode --- src/bitmessageqt/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e0166962..8e836fe1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2663,7 +2663,8 @@ class MyForm(settingsmixin.SMainWindow): else: PendingDownloadQueue.stop() - if shared.statusIconColor == 'red': + 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) -- 2.45.1 From 175f8b14a508d83ebcae0edb75eb2dd84378923c Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 31 Jan 2018 12:31:23 +0200 Subject: [PATCH 1049/1102] Update SOURCES and FORMS in bitmessage.pro --- src/translations/bitmessage.pro | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 818d799d..e3c85535 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -21,33 +21,35 @@ SOURCES = ../addresses.py\ ../shared.py\ ../upnp.py\ ../bitmessageqt/__init__.py\ - ../bitmessageqt/about.py\ ../bitmessageqt/account.py\ - ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/address_dialogs.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/blacklist.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/dialogs.py\ ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ ../bitmessageqt/languagebox.py\ ../bitmessageqt/messagecompose.py\ ../bitmessageqt/messageview.py\ ../bitmessageqt/networkstatus.py\ - ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.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/newchandialog.ui + ../bitmessageqt/newaddressdialog.ui\ + ../bitmessageqt/newchandialog.ui\ + ../bitmessageqt/newsubscriptiondialog.ui\ + ../bitmessageqt/regenerateaddresses.ui\ + ../bitmessageqt/specialaddressbehavior.ui TRANSLATIONS = \ bitmessage_ar.ts \ -- 2.45.1 From f4861be976c84a408fae1867e65128e35b102112 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 31 Jan 2018 12:33:43 +0200 Subject: [PATCH 1050/1102] Add Ukrainian translation file --- src/translations/bitmessage.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index e3c85535..f5d6b946 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -68,6 +68,7 @@ TRANSLATIONS = \ bitmessage_pt.ts \ bitmessage_sk.ts \ bitmessage_ru.ts \ + bitmessage_uk.ts \ bitmessage_zh_cn.ts CODECFORTR = UTF-8 -- 2.45.1 From 0c4ea7d20f6cb07e11bbe70e353ed4b336e35af5 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Wed, 31 Jan 2018 17:34:38 +0100 Subject: [PATCH 1051/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 94216 -> 91386 bytes src/translations/bitmessage_ru.ts | 653 ++++++++++++++++-------------- 2 files changed, 341 insertions(+), 312 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index bd61a1fa8c6b498c84f83d81d39131e62154eabf..c831d389433262f7920f31b7e6fd20c4e0ba7586 100644 GIT binary patch delta 4118 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 delta 5558 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 MW_w$9XE(b252=$Q$N&HU diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 3e020294..38e1112f 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry Добавить новую запись - + Label Имя - + Address Адрес @@ -20,64 +20,93 @@ 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-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только 1 шлюз Mailchuck (@mailchuck.com). + Email-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только шлюз Mailchuck (@mailchuck.com). - + Desired email address (including @mailchuck.com): - Введите желаемый email-адрес (включая @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 недоступен, попробуйте ввести другой. Введите желаемый адрес (включая @mailchuck.com) ниже: + Email gateway registration - Регистрация на 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: - Email-шлюз позволяет вам обмениваться сообщениями с пользователями обычной электронной почты. В настоящий момент доступен только шлюз Mailchuck (@mailchuck.com). -Пожалуйста, введите желаемый адрес email (включая @mailchuck.com) ниже: + @@ -168,52 +197,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 Новый адрес @@ -238,12 +267,12 @@ Please type the desired email address (including @mailchuck.com) below: Скопировать адрес в буфер обмена - + Special address behavior... Особое поведение адресов... - + Email gateway Email-шлюз @@ -253,37 +282,37 @@ Please type the desired email address (including @mailchuck.com) below: Удалить - + 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -293,17 +322,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -313,78 +342,78 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 Подписки - + 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. @@ -393,19 +422,19 @@ 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.) @@ -415,27 +444,27 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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 Неверный номер версии адреса @@ -445,7 +474,7 @@ It is important that you back up this file. Would you like to open the file now? Адрес номера версии должен быть числом: либо 3, либо 4. - + Your address version number must be either 3 or 4. Адрес номера версии должен быть либо 3, либо 4. @@ -515,22 +544,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -541,17 +570,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -596,57 +625,57 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Новое сообщение @@ -656,9 +685,9 @@ It is important that you back up this file. Would you like to open the file now? - + Sending email gateway registration request - Отправка запроса на регистрацию на Email-шлюзе + @@ -671,142 +700,142 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 - Отправка запроса на отмену регистрации на Email-шлюзе + - + Sending email gateway status request - Отправка запроса статуса аккаунта на Email-шлюзе + - + 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? @@ -815,7 +844,7 @@ 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? @@ -824,277 +853,277 @@ 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. - Это адрес 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. + Версия этого адреса более поздняя, чем те, что поддерживает программа. Пожалуйста, обновите 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). - Вы используете TCP порт %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 Ctrl+Q - + F1 F1 - + Contact support Связаться с поддержкой - + About О программе - + Regenerate deterministic addresses Сгенерировать заново все адреса - + Delete all trashed messages Стереть все сообщения из корзины - + Join / Create chan Подключить или создать чан @@ -1119,67 +1148,67 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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 часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправлено @@ -1283,7 +1312,7 @@ Receiver's required difficulty: %1 and %2 Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. @@ -1293,7 +1322,7 @@ Receiver's required difficulty: %1 and %2 Отправлено. Ожидаем подтверждения. Отправлено в %1 - + Doing work necessary to request encryption key. Выполнение работы, требуемой для запроса ключа шифрования. @@ -1318,37 +1347,37 @@ Receiver's required difficulty: %1 and %2 Распределение портов 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1413,12 +1442,12 @@ Receiver's required difficulty: %1 and %2 Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + Set notification sound... Установить звук уведомления... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1432,145 +1461,135 @@ Receiver's required difficulty: %1 and %2 * участвуйте в обсуждениях в чанах - + 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? Вы пытаетесь отправить email вместо 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 - Ошибка: %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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?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... Ожидание окончания синхронизации... - - Undeleted items. - Восстановленные элементы. - - - + You have already set a notification sound for this address book entry. Do you really want to overwrite it? У вас уже есть звук уведомления для этого адресата. Вы уверены, что хотите перезаписать звук уведомления? - + Go online Подключиться к сети - + Go offline - + Отключиться от сети 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 Нажмите здесь для отключения @@ -1593,98 +1612,98 @@ Perhaps you should upgrade Bitmessage. 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 - + 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) (немного сэкономит Вам пропускную способность сети и вычислительную мощь) @@ -1692,22 +1711,22 @@ The 'Random Number' option is selected by default but deterministic ad NewSubscriptionDialog - + Add new entry Добавить новую запись - + Label Имя - + Address Адрес - + Enter an address above. Введите адрес выше. @@ -1715,55 +1734,60 @@ The 'Random Number' option is selected by default but deterministic ad 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 ? - версия ? + - + <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. Это бета версия программы. @@ -1772,10 +1796,10 @@ The 'Random Number' option is selected by default but deterministic ad <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>Авторское право: &copy; 2012-2016 Джонатан Уоррен<br/>Авторское право: &copy; 2013-2016 Разработчики Bitmessage</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> @@ -1819,45 +1843,45 @@ The 'Random Number' option is selected by default but deterministic ad 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> - + As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: Bitmessage - общественный проект. Вы можете найти подсказки и советы на Wiki-страничке Bitmessage: @@ -1865,30 +1889,35 @@ 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 @@ -1973,7 +2002,7 @@ The 'Random Number' option is selected by default but deterministic ad Загрузка: 0 кБ/с - + Network Status Состояние сети @@ -2129,12 +2158,12 @@ The 'Random Number' option is selected by default but deterministic ad Успешно создан / подключен чан %1 - + Chan creation / joining failed Не удалось создать / подключить чан - + Chan creation / joining cancelled Создание / подключение чана отменено @@ -2168,54 +2197,54 @@ The 'Random Number' option is selected by default but deterministic ad 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 Потратить несколько лишних минут, чтобы сделать адрес(а) короче на 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. - Если Вы ранее создавали детерминистические адреса, но случайно потеряли их, Вы можете их восстановить здесь. Если же Вы использовали генератор случайных чисел чтобы создать Ваши адреса, то Вы не сможете их здесь восстановить. + -- 2.45.1 From 25a9e5ea450628ac5141c804afceb413f35acbc8 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Wed, 31 Jan 2018 20:12:04 +0200 Subject: [PATCH 1052/1102] Fixed errors I introduced in commit 4115540 after rebase --- src/bitmessageqt/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8e836fe1..3422664b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1904,7 +1904,7 @@ class MyForm(settingsmixin.SMainWindow): " BM- Please check the recipient address %1" ).arg(toAddress)) elif status == 'checksumfailed': - self.statusbar_message(_translate( + self.updateStatusBar(_translate( "MainWindow", "Error: The recipient address %1 is not" " typed or copied correctly. Please check it." @@ -2095,7 +2095,8 @@ class MyForm(settingsmixin.SMainWindow): identities = str(self.ui.lineEditTo.text().toUtf8()).split(";") err, addr = nc.query(identities[-1].strip()) if err is not None: - self.statusbar_message("Error: %1", args=[err]) + self.updateStatusBar( + _translate("MainWindow", "Error: %1").arg(err)) else: identities[-1] = addr self.ui.lineEditTo.setText("; ".join(identities)) -- 2.45.1 From 222e666a607c9d88f389fbb422006f8b56205f89 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 Jan 2018 21:09:36 +0100 Subject: [PATCH 1053/1102] Network thread shutdown iterator fix Thanks to @g1itch for pointing this out. --- src/network/networkthread.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/network/networkthread.py b/src/network/networkthread.py index 25e9f547..5a709c8b 100644 --- a/src/network/networkthread.py +++ b/src/network/networkthread.py @@ -20,17 +20,17 @@ class BMNetworkThread(threading.Thread, StoppableThread): def stopThread(self): super(BMNetworkThread, self).stopThread() - for i in BMConnectionPool().listeningSockets: + for i in BMConnectionPool().listeningSockets.values(): try: i.close() except: pass - for i in BMConnectionPool().outboundConnections: + for i in BMConnectionPool().outboundConnections.values(): try: i.close() except: pass - for i in BMConnectionPool().inboundConnections: + for i in BMConnectionPool().inboundConnections.values(): try: i.close() except: -- 2.45.1 From d223bfc6f29367b7d70e35f7bf1185a7bc3ca239 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 31 Jan 2018 22:25:23 +0100 Subject: [PATCH 1054/1102] Fix kqueue poller - separate read and write filters - make filters peristent for reduced syscall count --- src/network/asyncore_pollchoose.py | 95 +++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/src/network/asyncore_pollchoose.py b/src/network/asyncore_pollchoose.py index f9dc9ee5..cd19063a 100644 --- a/src/network/asyncore_pollchoose.py +++ b/src/network/asyncore_pollchoose.py @@ -361,35 +361,65 @@ 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: - kqueue = select.kqueue() - flags = select.KQ_EV_ADD | select.KQ_EV_ENABLE + updates = [] selectables = 0 for fd, obj in map.items(): kq_filter = 0 if obj.readable(): - kq_filter |= select.KQ_FILTER_READ - if obj.writable(): - kq_filter |= select.KQ_FILTER_WRITE - if kq_filter: - try: - ev = select.kevent(fd, filter=kq_filter, flags=flags) - kqueue.control([ev], 0) - selectables += 1 - except IOError: - pass + 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 - events = kqueue.control(None, selectables, timeout) - for event in random.sample(events, len(events)): + 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) - kqueue.close() else: current_thread().stop.wait(timeout) @@ -499,27 +529,38 @@ class dispatcher: 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 - self.poller_flags = 0 - self.poller_registered = False 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 - 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.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 -- 2.45.1 From 68b58ce0c5c288e964e0036aee284a50d51f0b5a Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 12:19:39 +0100 Subject: [PATCH 1055/1102] Download optimisation - new data structure to handle download tracking, uses less CPU --- src/network/bmproto.py | 3 +- src/network/connectionpool.py | 3 +- src/network/downloadthread.py | 29 ++------- src/network/objectracker.py | 12 ++-- src/randomtrackingdict.py | 118 ++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 36 deletions(-) create mode 100644 src/randomtrackingdict.py diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 21ec692c..4bf63bca 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -546,8 +546,7 @@ class BMProto(AdvancedDispatcher, ObjectTracker): for connection in network.connectionpool.BMConnectionPool().inboundConnections.values() + \ network.connectionpool.BMConnectionPool().outboundConnections.values(): try: - with connection.objectsNewToMeLock: - del connection.objectsNewToMe[hashId] + del connection.objectsNewToMe[hashId] except KeyError: pass if not forwardAnyway: diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 793e284f..2f34e485 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -40,8 +40,7 @@ class BMConnectionPool(object): if not i.fullyEstablished: continue try: - with i.objectsNewToMeLock: - del i.objectsNewToMe[hashid] + del i.objectsNewToMe[hashid] except KeyError: with i.objectsNewToThemLock: i.objectsNewToThem[hashid] = time.time() diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 35616f1b..ec921c58 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -3,10 +3,8 @@ 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 import protocol from state import missingObjects @@ -49,32 +47,15 @@ class DownloadThread(threading.Thread, StoppableThread): for i in connections: now = time.time() timedOut = now - DownloadThread.requestTimeout - # this may take a while, but it needs a consistency so I think it's better to lock a bigger chunk - with i.objectsNewToMeLock: - try: - downloadPending = len(list((k for k, v in i.objectsNewToMe.iteritems() if k in missingObjects and missingObjects[k] > timedOut and not v))) - except KeyError: - continue - if downloadPending >= DownloadThread.minPending: - continue - # keys with True values in the dict - try: - request = list((k for k, v in i.objectsNewToMe.iteritems() if k not in missingObjects or missingObjects[k] < timedOut)) - except KeyError: - continue - random.shuffle(request) - if len(request) > requestChunk - downloadPending: - request = request[:max(1, requestChunk - downloadPending)] - if not request: - continue - # mark them as pending - for k in request: - i.objectsNewToMe[k] = False - missingObjects[k] = now + try: + request = i.objectsNewToMe.randomKeys(requestChunk) + except KeyError: + continue payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) for chunk in request: payload.extend(chunk) + missingObjects[k] = now 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) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 62f01e4f..a786c696 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -5,6 +5,7 @@ from threading import RLock from debug import logger from inventory import Inventory from network.dandelion import Dandelion +from randomtrakcingdict import RandomTrackingDict from state import missingObjects haveBloom = False @@ -32,8 +33,7 @@ class ObjectTracker(object): initialTimeOffset = 60 def __init__(self): - self.objectsNewToMe = {} - self.objectsNewToMeLock = RLock() + self.objectsNewToMe = RandomTrackingDict() self.objectsNewToThem = {} self.objectsNewToThemLock = RLock() self.initInvBloom() @@ -61,9 +61,6 @@ class ObjectTracker(object): self.initAddrBloom() else: # release memory - with self.objectsNewToMeLock: - tmp = self.objectsNewToMe.copy() - self.objectsNewToMe = tmp deadline = time.time() - ObjectTracker.trackingExpires with self.objectsNewToThemLock: self.objectsNewToThem = {k: v for k, v in self.objectsNewToThem.iteritems() if v >= deadline} @@ -88,9 +85,8 @@ class ObjectTracker(object): if hashId in Dandelion().hashMap: Dandelion().fluffTrigger(hashId) if hashId not in missingObjects: - missingObjects[hashId] = time.time() - ObjectTracker.initialTimeOffset - with self.objectsNewToMeLock: - self.objectsNewToMe[hashId] = True + missingObjects[hashId] = True + self.objectsNewToMe[hashId] = True def hasAddr(self, addr): if haveBloom: diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py new file mode 100644 index 00000000..466acc41 --- /dev/null +++ b/src/randomtrackingdict.py @@ -0,0 +1,118 @@ +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 __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.len += 1 + + def __delitem__(self, key): + if not key in self.dictionary: + raise KeyError + with self.lock: + index = self.dictionary[key][0] + self.indexDict[index] = self.indexDict[self.len - 1] + self.dictionary[self.indexDict[index]][0] = index + # 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 + if index >= self.len - self.pendingLen: + self.pendingLen -= 1 + + def setMaxPending(self, maxPending): + self.maxPending = maxPending + + def setPendingTimeout(self, pendingTimeout): + self.pendingTimeout = pendingTimeout + + def randomKeys(self, count=1): + if self.lastPoll + self.pendingTimeout < time(): + with self.lock: + self.pendingLen = 0 + if self.len == 0 or self.pendingLen >= self.maxPending: + raise KeyError + with self.lock: + available = self.len - self.pendingLen + if count > available: + count = available + retval = random.sample(self.indexDict[:self.len - self.pendingLen], count) + for i in retval[::-1]: + # swap with one below lowest pending + self.pendingLen += 1 + swapKey = self.indexDict[-self.pendingLen] + curIndex = self.dictionary[i][0] + self.indexDict[-self.pendingLen] = i + self.indexDict[curIndex] = swapKey + self.dictionary[i][0] = self.len - self.pendingLen + self.dictionary[swapKey][0] = curIndex + 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]) -- 2.45.1 From 8d057424366b9ace958696f699995c5ab2633cd3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 12:20:41 +0100 Subject: [PATCH 1056/1102] Typo --- src/network/objectracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index a786c696..044d11a2 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -5,7 +5,7 @@ from threading import RLock from debug import logger from inventory import Inventory from network.dandelion import Dandelion -from randomtrakcingdict import RandomTrackingDict +from randomtrackingdict import RandomTrackingDict from state import missingObjects haveBloom = False -- 2.45.1 From c5dc7fc903146128a88af1e3edd36617b387b9f0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 12:26:54 +0100 Subject: [PATCH 1057/1102] Typo --- src/network/downloadthread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index ec921c58..d81b06e8 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -55,7 +55,7 @@ class DownloadThread(threading.Thread, StoppableThread): payload.extend(addresses.encodeVarint(len(request))) for chunk in request: payload.extend(chunk) - missingObjects[k] = now + missingObjects[chunk] = now 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) -- 2.45.1 From 290b87a49f9f64714862522227af04cf4b76bbb3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 12:48:14 +0100 Subject: [PATCH 1058/1102] Download fixes - don't expire too quickly - ignore connections that haven't been fully established yet --- src/network/downloadthread.py | 3 +-- src/network/objectracker.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index d81b06e8..f3beb77c 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -38,7 +38,7 @@ class DownloadThread(threading.Thread, StoppableThread): while not self._stopped: requested = 0 # Choose downloading peers randomly - connections = BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values() + 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) @@ -46,7 +46,6 @@ class DownloadThread(threading.Thread, StoppableThread): requestChunk = 1 for i in connections: now = time.time() - timedOut = now - DownloadThread.requestTimeout try: request = i.objectsNewToMe.randomKeys(requestChunk) except KeyError: diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 044d11a2..327304d9 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -85,7 +85,7 @@ class ObjectTracker(object): if hashId in Dandelion().hashMap: Dandelion().fluffTrigger(hashId) if hashId not in missingObjects: - missingObjects[hashId] = True + missingObjects[hashId] = time.time() self.objectsNewToMe[hashId] = True def hasAddr(self, addr): -- 2.45.1 From 167d946435c67aeed5afa38e5dbb62bfa48d4a81 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 14:43:14 +0100 Subject: [PATCH 1059/1102] RandomTrackingDict now tracks properly - it didn't put the correct keys at the end --- src/randomtrackingdict.py | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py index 466acc41..8c3fa6aa 100644 --- a/src/randomtrackingdict.py +++ b/src/randomtrackingdict.py @@ -31,21 +31,37 @@ class RandomTrackingDict(object): self.dictionary[key] = [self.len, value] self.len += 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 __delitem__(self, key): if not key in self.dictionary: raise KeyError with self.lock: index = self.dictionary[key][0] - self.indexDict[index] = self.indexDict[self.len - 1] - self.dictionary[self.indexDict[index]][0] = index + # 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 - if index >= self.len - self.pendingLen: - self.pendingLen -= 1 def setMaxPending(self, maxPending): self.maxPending = maxPending @@ -63,16 +79,13 @@ class RandomTrackingDict(object): available = self.len - self.pendingLen if count > available: count = available - retval = random.sample(self.indexDict[:self.len - self.pendingLen], count) - for i in retval[::-1]: + 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 - swapKey = self.indexDict[-self.pendingLen] - curIndex = self.dictionary[i][0] - self.indexDict[-self.pendingLen] = i - self.indexDict[curIndex] = swapKey - self.dictionary[i][0] = self.len - self.pendingLen - self.dictionary[swapKey][0] = curIndex self.lastPoll = time() return retval -- 2.45.1 From 2f150dcdd781c04cc119a553619e854f83746df5 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 1 Feb 2018 19:17:51 +0100 Subject: [PATCH 1060/1102] Auto-updated language eo from transifex --- src/translations/bitmessage_eo.qm | Bin 88527 -> 87188 bytes src/translations/bitmessage_eo.ts | 804 ++++++++++++++++-------------- 2 files changed, 434 insertions(+), 370 deletions(-) diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 018a268ec83772d69447e5484473f13f7826df76..ea03b1b524bfce42b917b716e22c049b8ed25dfd 100644 GIT binary patch delta 5072 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 R6FSHLD8IGChO^bC{|PSl!65(u delta 5395 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 Uk=h3%npS-vx+RJpY_a2i0WC6As{jB1 diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index c662b0b5..beff4aca 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry Aldoni novan elementon - + Label Etikedo - + Address Adreso @@ -20,70 +20,99 @@ EmailGatewayDialog - + Email gateway Retpoŝta kluzo - + Register on email gateway - Registri je retpoŝta kluzo + 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: - Registrado malsukcesis: + - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi alian. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: + Email gateway registration - Registrado je retpoŝta kluzo + 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: - Retpoŝta kluzo ebligas al vi komunikadi kun retpoŝtaj uzantoj. Nuntempe, nur la retpoŝta kluzo de Mailchuck (@mailchuck.com) estas disponebla. -Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: + Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -166,52 +195,52 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: MainWindow - + Reply to sender Respondi al sendinto - + Reply to channel Respondi al kanalo - + 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 - Malforviŝi + Malforigi - + View HTML code as formatted text Montri HTML-n kiel aranĝitan tekston - + Save message as... Konservi mesaĝon kiel… - + Mark Unread Marki kiel nelegitan - + New Nova @@ -236,12 +265,12 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube:Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso… - + Email gateway Retpoŝta kluzo @@ -251,37 +280,37 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: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 - + 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. @@ -291,17 +320,17 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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 @@ -311,77 +340,77 @@ Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: - + 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. @@ -390,17 +419,17 @@ It is important that you back up this file. 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.) @@ -409,37 +438,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -509,22 +538,22 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 @@ -532,17 +561,17 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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. @@ -587,57 +616,57 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + 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 @@ -647,9 +676,9 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos - + Sending email gateway registration request - Sendado de peto pri registrado je retpoŝta kluzo + @@ -662,430 +691,430 @@ Estas grava, ke vi faru sekurkopion de tiu dosiero. Ĉu vi volas malfermi la dos 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 vian prokurilon (proxy) ekde nun, sed eble vi volas permane restartigi Bitmesaĝon nun, por ke ĝi fermu eblajn ekzistajn konektojn. + 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 - Sendado de peto pri malregistrado de retpoŝta kluzo + - + Sending email gateway status request - Sendado de peto pri stato de retpoŝta kluzo + - + Passphrase mismatch Pasfrazoj malsamas - + The passphrase you entered twice doesn't match. Try again. - La pasfrazo kiun vi duoble enmetis malsamas. Provu denove. + 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. - Aldonis elementon al adresaro. Redaktu la etikedon laŭvole. + - + 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. - Malforviŝis elementon. + 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 forviŝos 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. + 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 forviŝi la abonon? +Ĉ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 forviŝos 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. + 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 forviŝi la kanalon? +Ĉ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. - Tio ĉi estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. + - + The address should start with ''BM-'' - La adreso komencu kun "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). + 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 tiun, kiun la programo poveblas subteni. Bonvolu ĝisdatigi Bitmesaĝon. + 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. - Kelkaj datumoj koditaj en la adreso estas tro mallongaj. + 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. - Some data encoded in the address is too long. - Kelkaj datumoj koditaj en la adreso estas tro longaj. - - - - Some data encoded in the address is malformed. - Kelkaj datumoj koditaj en la adreso estas misformitaj. - - - Enter an address above. - Enmetu adreson supre. + - + Address is an old type. We cannot display its past broadcasts. - Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. + 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). - Vi uzas TCP-pordon %1 (tio ĉi estas ŝanĝebla en la agordoj). + - + 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 @@ -1110,67 +1139,67 @@ Are you sure you want to delete the channel? Aldoni novan elementon - + Display the %1 recent broadcast(s) from this address. - Montri la %1 lasta(j)n elsendo(j)n de tiu adreso. + Montri %1 lasta(j)n elsendo(j)n de tiu ĉi adreso. - + 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 - + Waiting for PoW to finish... %1% Atendado ĝis laborpruvo finiĝos… %1% - + Shutting down Pybitmessage... %1% Fermado de PyBitmessage… %1% - + Waiting for objects to be sent... %1% Atendado ĝis objektoj estos senditaj… %1% - + Saving settings... %1% Konservado de agordoj… %1% - + Shutting down core... %1% Fermado de kerno… %1% - + Stopping notifications... %1% Haltigado de sciigoj… %1% - + Shutdown imminent... %1% Fermado tuj… %1% - + %n hour(s) %n horo%n horoj - + %n day(s) %n tago%n tagoj - + Shutting down PyBitmessage... %1% Fermado de PyBitmessage… %1% - + Sent Senditaj @@ -1215,86 +1244,86 @@ Are you sure you want to delete the channel? Atentu: Via disko aŭ subdisko estas plenplena. Bitmesaĝo fermiĝos. - + 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. - + Doing work necessary to send broadcast... Kalkulado de laborpruvo, kiu endas por sendi elsendon… - + Broadcast sent on %1 Elsendo sendita je %1 - + Encryption key was requested earlier. Peto pri ĉifroŝlosilo jam sendita. - + Sending a request for the recipient's encryption key. Sendado de peto pri ĉifroŝlosilo de ricevonto. - + 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. - + 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. - + Sending public key request. Waiting for reply. Requested at %1 Sendado de peto pri publika ĉifroŝlosilo. Atendado je respondo. Petis je %1 @@ -1309,44 +1338,44 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 UPnP pord-mapigo forigita - + Mark all messages as read Marki ĉiujn mesaĝojn kiel legitajn - + Are you sure you would like to mark all messages read? Ĉu vi certe volas marki ĉiujn mesaĝojn kiel legitajn? - + Doing work necessary to send broadcast. Kalkulado de laborpruvo, kiu endas por sendi elsendon. - + 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 - + Wait until these tasks finish? Ĉu atendi ĝis tiujn taskojn finos? Problem communicating with proxy: %1. Please check your network settings. - Eraro dum komunikado kun prokurilo: %1. Bonvolu kontroli viajn retajn agordojn. + Eraro dum komunikado kun retperanto: %1. Bonvolu kontroli viajn retajn agordojn. @@ -1404,12 +1433,12 @@ Ricevonto postulas malfacilaĵon: %1 kaj %2 Via(j) vidprocesoro(j) ne kalkulis senerare, malaktiviganta OpenCL. Bonvolu raporti tion al programistoj. - + Set notification sound... Agordi sciigan sonon… - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1423,120 +1452,140 @@ Bonvenon al facila kaj sekura Bitmesaĝo * babili kun aliaj uloj en mesaĝ-kanaloj - + not recommended for chans malkonsilinda por kanaloj - + + Quiet Mode + Silenta reĝimo + + + Problems connecting? Try enabling UPnP in the Network Settings Ĉu problemo kun konektado? Provu aktivigi UPnP en retaj agordoj. - + 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 @@ -1559,99 +1608,99 @@ Eble vi devas ĝisdatigi Bitmesaĝon. NewAddressDialog - + Create new Address 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 kreado kaj forlasado de adresoj 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: + 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 keys.dat dosiero 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> + <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 fari la adreso(j)n 1 aŭ 2 signoj pli mallongaj + 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 - + Number of addresses to make based on your passphrase: Nombro da farotaj adresoj bazante sur via pasfrazo: - + Stream number: 1 - Fluo numero: 1 + Numero de fluo: 1 - + Retype passphrase - Reenmeti pasfrazon + 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 tiun ĉi estas la unuan de ĉiuj adresojn vi kreos) + (plej bone se ĝi estas la unua de ĉiuj adresojn vi kreos) - + Use the same stream as an existing address - Uzi saman fluon kiel ekzistan adreson + Uzi la saman fluon kiel ekzistan adreson - + (saves you some bandwidth and processing power) (konservas iomete da ret-trafiko kaj komput-povo) @@ -1659,78 +1708,83 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj NewSubscriptionDialog - + Add new entry Aldoni novan elementon - + Label Etikedo - + Address Adreso - + Enter an address above. - Enmetu adreson supre. + Entajpu adreson supre. 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 la kvazaŭ-dissendlisto: + 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 ? - versio ? + - + <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"; 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> + <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. @@ -1739,10 +1793,10 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj <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>Kopirajto &copy; 2012-2016 Jonathan WARREN<br/>Kopirajto &copy; 2013-2016 La programistoj de Bitmesaĝo</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> @@ -1786,40 +1840,45 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj connectDialog - + Bitmessage Bitmesaĝo - + Bitmessage won't connect to anyone until you let it. Bitmesaĝo ne konektos antaŭ vi permesos al ĝi. - + Connect now Konekti nun - + Let me configure special network settings first - Lasu min unue fari specialajn retajn agordojn + Ebligi al mi unue alĝustigi specialajn agordojn de reto + + + + Work offline + Funkcii eksterrete 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> - + 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: @@ -1827,30 +1886,35 @@ 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. - + 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 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. You are using TCP port ?. (This can be changed in the settings). - Vi uzas TCP-pordon ?. (Ĝi 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 @@ -1860,37 +1924,37 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Ĉ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 # @@ -1900,112 +1964,112 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj - + 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 @@ -2064,7 +2128,7 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj - Chan passhphrase/name: + Chan passphrase/name: Kanala pasfrazo/nomo: @@ -2086,7 +2150,7 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj newchandialog - + Successfully created / joined chan %1 Sukcese kreis / aniĝis al la kanalo %1 @@ -2130,54 +2194,54 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj regenerateAddressesDialog - + Regenerate Existing Addresses Regeneri ekzistantajn adresojn - + Regenerate existing addresses Regeneri ekzistantajn adresojn - + Passphrase Pasfrazo - + Number of addresses to make based on your passphrase: Nombro da farotaj adresoj bazante sur via pasfrazo: - + Address version number: Numero de adresversio: - + Stream number: - Fluo numero: + Numero de fluo: - + 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 la adreso(j)n 1 aŭ 2 signoj pli mallongaj + Pasigi kelkajn minutojn aldone kompute por krei adreso(j)n mallongaj je 1 aŭ 2 signoj - + 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) ĉi tiun markobutonon samkiel vi faris kiam vi generis vian adreson unuafoje. + Vi devas marki (aŭ ne marki) tiun ĉi mark-butonon samkiel vi faris kiam vi generis vian adresojn unuafoje. - + 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 ĉi tie. Se vi uzis la generilo de hazardnombroj por krei vian adreson tiu formularo ne taŭgos por vi. + 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. @@ -2291,7 +2355,7 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Proxy server / Tor - Prokurila (proxy) servilo / Tor + Retperanta (proxy) servilo / Tor @@ -2326,7 +2390,7 @@ La ‘hazardnombra’ adreso estas antaŭagordita, sed antaŭkalkuleblaj adresoj Listen for incoming connections when using proxy - Aŭskulti pri alvenaj konektoj kiam dum uzado de prokurilo + Aŭskulti pri alvenaj konektoj kiam dum uzado de retperanto -- 2.45.1 From 283696a05331e4a76f96531eec33e23cbb157b93 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Thu, 1 Feb 2018 20:19:08 +0100 Subject: [PATCH 1061/1102] Auto-updated language pl from transifex --- src/translations/bitmessage_pl.qm | Bin 91798 -> 90637 bytes src/translations/bitmessage_pl.ts | 758 ++++++++++++++++-------------- 2 files changed, 411 insertions(+), 347 deletions(-) diff --git a/src/translations/bitmessage_pl.qm b/src/translations/bitmessage_pl.qm index 1b51288030ccc843e1f67e161a1c72f4791723d1..3b9a0dcc6170060a14593fb1df4a4daac69cf226 100644 GIT binary patch delta 4475 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 YzsR9OP<%{^E;S}SJ-*DtnceOCFT;wrl>h($ diff --git a/src/translations/bitmessage_pl.ts b/src/translations/bitmessage_pl.ts index c0025336..c97cb4bb 100644 --- a/src/translations/bitmessage_pl.ts +++ b/src/translations/bitmessage_pl.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry - Dodaj adres + Dodaj nowy wpis - + Label - Nazwa + Etykieta - + Address Adres @@ -20,70 +20,99 @@ 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: - Rejestracja nie powiodła się: + - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - Wybrany adres e-mail nie jest dostępny, proszę spróbować inny. Wpisz adres poniżej (razem z końcówką @mailchuck.com): + Email gateway registration - Rejestracja u przekaźnika e-mail + 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: - Przekaźnik e-mail umożliwia komunikację z użytkownikami e-maili. Obecnie usługa ta oferowana jest tylko przez bramkę Mailchuck (@mailchuck.com). -Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: + Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -170,52 +199,52 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: 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 @@ -240,12 +269,12 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej:Kopiuj adres do schowka - + Special address behavior... Specjalne zachowanie adresu… - + Email gateway Przekaźnik e-mail @@ -255,37 +284,37 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: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. @@ -295,17 +324,17 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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 @@ -315,77 +344,77 @@ Wprowadź wybrany adres e-mail (razem z końcówką @mailchuck.com) poniżej: - + 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. @@ -394,17 +423,17 @@ It is important that you back up this file. 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.) @@ -413,37 +442,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -513,22 +542,22 @@ Zaleca się zrobienie kopii zapasowej tego pliku. Czy chcesz otworzyć ten plik - + 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 @@ -539,17 +568,17 @@ Im dłuższy TTL, tym więcej pracy będzie musiał wykonac komputer wysyłając 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. @@ -594,57 +623,57 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + 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ść @@ -654,9 +683,9 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. - + Sending email gateway registration request - Wysyłanie zapytania o rejestrację na bramce poczty + @@ -669,142 +698,142 @@ Zwykle 4-5 dniowy TTL jest odpowiedni. 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 - Wysyłanie zapytania o wyrejestrowanie z bramki poczty + - + Sending email gateway status request - Wysyłanie zapytania o stan bramki poczty + - + 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. - Dodano wpis do książki adresowej. Można teraz zmienić jego nazwę. + - + 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óć wiadomość. + 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? @@ -813,7 +842,7 @@ Are you sure you want to delete the subscription? 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? @@ -822,277 +851,277 @@ Are you sure you want to delete the channel? 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. - To jest adres kanału. Nie możesz go użyć jako pseudo-listy-dyskusyjnej. + - + The address should start with ''BM-'' - Adres powinien zaczynać sie od "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. - Wprowadź adres powyżej. + - + Address is an old type. We cannot display its past broadcasts. - Adres starego typu + 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 przekazów do wyświetlenia. + Brak niedawnych wiadomości subskrypcji do wyświetlenia. - + 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). + - + 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ł @@ -1117,67 +1146,67 @@ Czy na pewno chcesz usunąć ten kanał? Dodaj nowy wpis - + Display the %1 recent broadcast(s) from this address. - Pokaż %1 ostatnich wiadomości przekazów z tego adresu. + 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 @@ -1222,86 +1251,86 @@ Czy na pewno chcesz usunąć ten kanał? 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 - Przekaz wysłane o %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 @@ -1316,37 +1345,37 @@ Odbiorca wymaga trudności: %1 i %2 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? @@ -1411,12 +1440,12 @@ Odbiorca wymaga trudności: %1 i %2 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 @@ -1430,120 +1459,140 @@ Witamy w przyjaznym i bezpiecznym Bitmessage * 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 @@ -1566,178 +1615,183 @@ Prawdopodobnie powinieneś zaktualizować Bitmessage. 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: + 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> + <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 procesora) + (oszczędza trochę transferu i mocy procesora) NewSubscriptionDialog - + Add new entry - Dodaj subskrypcję + Dodaj nowy wpis - + Label Etykieta - + Address Adres - + Enter an address above. - Wpisz adres powyżej. + Wprowadź adres powyżej. SpecialAddressBehaviorDialog - + Special Address Behavior Specjalne zachowanie adresu - + Behave as a normal address - Zachowuj się jako normalny adres + Zachowuj się jak normalny adres - + Behave as a pseudo-mailing-list address - Zachowuj się jako pseudo-lista-dyskusyjna + 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 - PyBitmessage + - + version ? - wersja ? + - + <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. @@ -1746,10 +1800,10 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ <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>Prawa autorskie &copy; 2012-2016 Jonathan Warren<br/>Prawa autorskie &copy; 2013-2016 Programiści Bitmessage</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> @@ -1793,40 +1847,45 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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: @@ -1834,30 +1893,35 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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). - Używasz portu TCP ?. (Możesz go zmienić w ustawieniach.) + - + 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 @@ -1867,37 +1931,37 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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 przekazów. + 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ń # @@ -1907,112 +1971,112 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - + 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ść przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów.Przetworzono %n wiadomości przekazów. + 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 @@ -2071,8 +2135,8 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ - Chan passhphrase/name: - Wpisz hasło/nazwę: + Chan passphrase/name: + Nazwa/hasło kanału: @@ -2093,7 +2157,7 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ newchandialog - + Successfully created / joined chan %1 Pomyślnie utworzono / dołączono do kanału %1 @@ -2137,52 +2201,52 @@ Generowanie adresów 'losowych' jest wybrane domyślnie, jednak determ 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. -- 2.45.1 From 8a5ec29540e8b4620553af5d2ce4d1fbd4b3f985 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 21:24:50 +0100 Subject: [PATCH 1062/1102] Store object hash as binary in sqlite (inventory) --- src/storage/sqlite.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index 7c9e8822..f4107241 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -18,13 +18,13 @@ class SqliteInventory(InventoryStorage): with self.lock: if hash in self._inventory: return True - return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', hash)) + return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', sqlite3.Binary(hash))) 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=?', 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]) @@ -62,14 +62,14 @@ class SqliteInventory(InventoryStorage): 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 += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, 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 (?, ?, ?, ?, ?, ?)', objectHash, *value) + sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', sqlite3.Binary(objectHash), *value) self._inventory.clear() def clean(self): -- 2.45.1 From 451174b56683288dd134f9e19c43bb41e2ce5d91 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 22:31:45 +0100 Subject: [PATCH 1063/1102] Download tracking fix - don't reset tracking too early - handle inserts when tracking objects --- src/randomtrackingdict.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py index 8c3fa6aa..e1616c2c 100644 --- a/src/randomtrackingdict.py +++ b/src/randomtrackingdict.py @@ -22,15 +22,6 @@ class RandomTrackingDict(object): def __getitem__(self, key): return self.dictionary[key][1] - 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.len += 1 - def _swap(self, i1, i2): with self.lock: key1 = self.indexDict[i1] @@ -42,6 +33,16 @@ class RandomTrackingDict(object): # 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 @@ -70,12 +71,13 @@ class RandomTrackingDict(object): self.pendingTimeout = pendingTimeout def randomKeys(self, count=1): - if self.lastPoll + self.pendingTimeout < time(): - with self.lock: - self.pendingLen = 0 - if self.len == 0 or self.pendingLen >= self.maxPending: + if self.len == 0 or (self.pendingLen >= self.maxPending 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 -- 2.45.1 From dcce7ed4c548ad1def3b03771dee29740a95c2d4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 22:33:28 +0100 Subject: [PATCH 1064/1102] Typo --- src/randomtrackingdict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py index e1616c2c..a7961528 100644 --- a/src/randomtrackingdict.py +++ b/src/randomtrackingdict.py @@ -72,7 +72,7 @@ class RandomTrackingDict(object): def randomKeys(self, count=1): if self.len == 0 or (self.pendingLen >= self.maxPending and - self.lastPoll + self.pendingTimeout > time(): + self.lastPoll + self.pendingTimeout > time()): raise KeyError # reset if we've requested all with self.lock: -- 2.45.1 From 8498143783cb98dca28d80a4e3dc4ef997538e4b Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 22:58:04 +0100 Subject: [PATCH 1065/1102] Download fixes - check if already have object before requesting --- src/network/downloadthread.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index f3beb77c..6da5b838 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -5,6 +5,7 @@ import time import addresses from debug import logger from helper_threading import StoppableThread +from inventory import Inventory from network.connectionpool import BMConnectionPool import protocol from state import missingObjects @@ -53,6 +54,9 @@ class DownloadThread(threading.Thread, StoppableThread): payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) for chunk in request: + if chunk in Inventory(): + del i.objectsNewToMe[chunk] + continue payload.extend(chunk) missingObjects[chunk] = now i.append_write_buf(protocol.CreatePacket('getdata', payload)) -- 2.45.1 From 57c8c7c07c0dd9b96d869b21780a195a3a802001 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 1 Feb 2018 23:18:08 +0100 Subject: [PATCH 1066/1102] Download thread exception handling --- src/network/downloadthread.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 6da5b838..37e36398 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -55,7 +55,10 @@ class DownloadThread(threading.Thread, StoppableThread): payload.extend(addresses.encodeVarint(len(request))) for chunk in request: if chunk in Inventory(): - del i.objectsNewToMe[chunk] + try: + del i.objectsNewToMe[chunk] + except KeyError: + pass continue payload.extend(chunk) missingObjects[chunk] = now -- 2.45.1 From 053f434e0466f503fba8b41d3d7f82aa6450a7be Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 2 Feb 2018 12:44:43 +0100 Subject: [PATCH 1067/1102] Download fixes - don't make empty requests - don't make requests if all objects are pending already --- src/network/downloadthread.py | 2 ++ src/randomtrackingdict.py | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/network/downloadthread.py b/src/network/downloadthread.py index 37e36398..88f7c12e 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -62,6 +62,8 @@ class DownloadThread(threading.Thread, StoppableThread): 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) diff --git a/src/randomtrackingdict.py b/src/randomtrackingdict.py index a7961528..83d35cdf 100644 --- a/src/randomtrackingdict.py +++ b/src/randomtrackingdict.py @@ -71,8 +71,9 @@ class RandomTrackingDict(object): self.pendingTimeout = pendingTimeout def randomKeys(self, count=1): - if self.len == 0 or (self.pendingLen >= self.maxPending and - self.lastPoll + self.pendingTimeout > time()): + 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: -- 2.45.1 From 96b8cff0d13a44898322753a1c7d5704448c3186 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 2 Feb 2018 14:33:29 +0100 Subject: [PATCH 1068/1102] Inventory checking performance optimisation - caching of whether an object exists in inventory was somehow removed since storage refactoring (or it never worked). Now existence checking is cached in the sqlite storage backend --- src/storage/sqlite.py | 20 ++++++++++---------- src/storage/storage.py | 3 --- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/storage/sqlite.py b/src/storage/sqlite.py index f4107241..438cbdcb 100644 --- a/src/storage/sqlite.py +++ b/src/storage/sqlite.py @@ -11,14 +11,18 @@ 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._streams = collections.defaultdict(set) # 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. + 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._inventory: + if hash in self._objects: return True - return bool(sqlQuery('SELECT 1 FROM inventory WHERE hash=?', sqlite3.Binary(hash))) + 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: @@ -33,7 +37,7 @@ class SqliteInventory(InventoryStorage): with self.lock: value = InventoryItem(*value) self._inventory[hash] = value - self._streams[value.stream].add(hash) + self._objects[hash] = value.stream def __delitem__(self, hash): raise NotImplementedError @@ -54,10 +58,6 @@ class SqliteInventory(InventoryStorage): 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 hashes_by_stream(self, stream): - with self.lock: - return self._streams[stream] - def unexpired_hashes_by_stream(self, stream): with self.lock: t = int(time.time()) @@ -75,7 +75,7 @@ class SqliteInventory(InventoryStorage): def clean(self): with self.lock: sqlExecute('DELETE FROM inventory WHERE expirestime Date: Fri, 2 Feb 2018 18:31:07 +0200 Subject: [PATCH 1069/1102] Set fixed size for simple dialogs --- src/bitmessageqt/dialogs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/dialogs.py b/src/bitmessageqt/dialogs.py index 80bffed4..cb82f348 100644 --- a/src/bitmessageqt/dialogs.py +++ b/src/bitmessageqt/dialogs.py @@ -44,7 +44,7 @@ class AboutDialog(QtGui.QDialog, RetranslateMixin): except AttributeError: pass - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + self.setFixedSize(QtGui.QWidget.sizeHint(self)) class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): @@ -59,18 +59,18 @@ class IconGlossaryDialog(QtGui.QDialog, RetranslateMixin): "iconGlossaryDialog", "You are using TCP port %1. (This can be changed in the settings)." ).arg(config.getint('bitmessagesettings', 'port'))) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + 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) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(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) - QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + self.setFixedSize(QtGui.QWidget.sizeHint(self)) -- 2.45.1 From ec30472dd8dd0e7eab9db68a5ac84fd7f2d350cc Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Fri, 2 Feb 2018 18:31:53 +0200 Subject: [PATCH 1070/1102] AboutDialog formatting fix (hope) --- src/bitmessageqt/about.ui | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/bitmessageqt/about.ui b/src/bitmessageqt/about.ui index 099875c0..8ec7159c 100644 --- a/src/bitmessageqt/about.ui +++ b/src/bitmessageqt/about.ui @@ -22,9 +22,6 @@ :/newPrefix/images/can-icon-24px.png - - true - Qt::AlignCenter @@ -42,7 +39,7 @@ <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::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignCenter -- 2.45.1 From d03d4a374e46720d4a35014b76d0aedc45eeb8cd Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 2 Feb 2018 18:29:41 +0100 Subject: [PATCH 1071/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 98493 -> 96660 bytes src/translations/bitmessage_de.ts | 668 ++++++++++++++++-------------- 2 files changed, 361 insertions(+), 307 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index c04e1950848d63fcd660fbaab722484281145989..9fa26fae11ce88ebd486bcc7bd5f502ddad73991 100644 GIT binary patch delta 3948 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 diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 1dd83139..4e4db13e 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -2,17 +2,17 @@ AddAddressDialog - + Add new entry Neuen Eintrag erstellen - + Label Name oder Bezeichnung - + Address Adresse @@ -20,70 +20,99 @@ 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 + + + + + Registration failed: + Registrierung fehlgeschlagen: + + + + The requested email address is not available, please try a new one. + + + + + 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: - Registrierung fehlgeschlagen: + - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: + Email gateway registration - E-Mail Schnittstellen Registrierung + 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: - Die E-Mail Schnittstelle ermöglicht es, mit anderen E-Mail-Nutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mail-Schnittstelle verfügbar (@mailchuck.com). -Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: + Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -174,52 +203,52 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 @@ -244,12 +273,12 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + Email gateway E-Mail Schnittstelle @@ -259,37 +288,37 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: 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 - + 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. @@ -299,17 +328,17 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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 @@ -319,77 +348,77 @@ Bitte geben Sie die gewünschte E-Mail-Adresse (inkl. @mailchuck.com) unten ein: - + 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. @@ -398,17 +427,17 @@ It is important that you back up this file. 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.) @@ -418,12 +447,12 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di (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? @@ -438,17 +467,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -518,22 +547,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -541,17 +570,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -596,57 +625,57 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -656,9 +685,9 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + Sending email gateway registration request - Der Registrierungsantrag für die E-Mail Schnittstelle wird versandt. + @@ -671,142 +700,142 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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 - E-Mail Schnittestellen-Abmeldeantrag wird versandt + - + Sending email gateway status request - E-Mail Schnittestellen Statusantrag wird versandt + - + 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 wirklich ein Kennwort. + 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. - Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. + - + 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? @@ -815,7 +844,7 @@ Are you sure you want to delete the subscription? 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? @@ -824,277 +853,277 @@ Are you sure you want to delete the channel? 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. - Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. + - + 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. + 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 codierten Daten sind zu kurz. + Die in der Adresse kodierten Daten sind zu kurz. - + Some data encoded in the address is too long. - Die in der Adresse codierten Daten sind zu lang. + 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. - Eine Addresse oben ausfüllen. + - + 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). - Sie benutzen TCP-Port %1 (Dieser kann in den Einstellungen verändert werden). + - + 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 @@ -1119,67 +1148,67 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. - + 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. - + 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 - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1224,85 +1253,85 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Warnung: Datenträger ist voll. Bitmessage wird jetzt beendet. - + 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. - + Doing work necessary to send broadcast... Arbeit wird verrichtet, um Rundruf zu verschicken... - + Broadcast sent on %1 Rundruf verschickt um %1 - + Encryption key was requested earlier. Verschlüsselungscode wurde früher angefordert. - + Sending a request for the recipient's encryption key. Anfrage nach dem Verschlüsselungscode des Empfängers wird versendet. - + 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... - + 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. - + 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 @@ -1317,37 +1346,37 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1412,12 +1441,12 @@ Receiver's required difficulty: %1 and %2 Ihre Grafikkarte hat inkorrekt berechnet, OpenCL wird deaktiviert. Bitte benachrichtigen Sie die Entwickler. - + Set notification sound... Benachrichtigungsklang einstellen ... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1431,130 +1460,140 @@ Willkommen zu einfachem und sicherem Bitmessage * diskutieren Sie mit anderen Leuten in Chans - + not recommended for chans für Chans nicht empfohlen - + Quiet Mode - + stiller Modus - + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + 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? + + + Go online + Mit dem Netzwerk verbinden + + + + Go offline + Trennen vom Netzwerk + 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 @@ -1577,99 +1616,99 @@ Womöglich sollten Sie Bitmessage upgraden. 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: - + <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 - + 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) @@ -1677,22 +1716,22 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi NewSubscriptionDialog - + Add new entry Neuen Eintrag erstellen - + Label Name oder Bezeichnung - + Address Adresse - + Enter an address above. Bitte geben Sie oben eine Adresse ein. @@ -1700,55 +1739,60 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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). - + 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 ? + - + <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> - + This is Beta software. Dies ist Beta-Software. @@ -1757,10 +1801,10 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi <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 Die Bitmessage-Entwickler</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> @@ -1804,40 +1848,45 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi connectDialog - + Bitmessage Bitmessage - + 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 + 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> - + 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: @@ -1845,30 +1894,35 @@ 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. 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 @@ -1953,7 +2007,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Herunter: 0 kB/s - + Network Status Netzwerkstatus @@ -2109,12 +2163,12 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi Chan %1 erfolgreich erstellt/beigetreten - + Chan creation / joining failed Chan-erstellung/-beitritt fehlgeschlagen - + Chan creation / joining cancelled Chan-erstellung/-beitritt abgebrochen @@ -2148,52 +2202,52 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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 der Adressen, die basierend auf diesem Kennwortsatz erzeugt werden sollen: + Anzahl Adressen die basierend auf diesem Kennwortsatz erzeugt werden sollen: - + Address version number: Adress-Versionsnummer: - + 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. - + 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. -- 2.45.1 From 9db0f5bcb3521222f6518bd2226131fd7db11f7d Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Fri, 2 Feb 2018 19:22:18 +0100 Subject: [PATCH 1072/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 89951 -> 88287 bytes src/translations/bitmessage_sk.ts | 750 +++++++++++++++++------------- 2 files changed, 417 insertions(+), 333 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 525f4b38b7718e499d3278aec4920621a50ed13a..228eff26de773d42b59882b0de916e0c870184f6 100644 GIT binary patch delta 4544 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 efWQIa AddAddressDialog - + Add new entry Pridať nový záznam - + Label Označenie - + Address Adresa @@ -20,70 +20,99 @@ 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: - Registrácia zlyhala: + - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - Požadovaná e-mailová adresa nie je k dispozícii, skúste znova. Vyplňte novú požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: + Email gateway registration - Registrácia na e-mailovej bráne + 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: - 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). -Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: + Mailchuck - + # You can use this to configure your email gateway account # Uncomment the setting you want to use # Here are the options: @@ -171,52 +200,52 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: 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á @@ -241,12 +270,12 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie:Kopírovať adresu do clipboardu - + Special address behavior... Zvláštne správanie adresy... - + Email gateway E-mailová brána @@ -256,37 +285,37 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: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. @@ -296,17 +325,17 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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 @@ -316,77 +345,77 @@ Vyplňte požadovanú e-mailovú adresu (vrátane @mailchuck.com) nižšie: - + 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. @@ -395,17 +424,17 @@ It is important that you back up this file. 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.) @@ -414,37 +443,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -514,22 +543,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -537,17 +566,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -592,69 +621,69 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 - Od + - + Sending email gateway registration request - Odosielam požiadavku o registráciu na e-mailovej bráne + @@ -667,142 +696,142 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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 - Odosielam žiadosť o odhlásenie z e-mailovej brány + - + Sending email gateway status request - Odosielam požiadavku o stave e-mailovej brány + - + 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. - Záznam pridaný do adresára. Upravte označenie podľa vašich predstáv. + - + 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? @@ -811,7 +840,7 @@ Are you sure you want to delete the subscription? 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? @@ -820,277 +849,277 @@ Are you sure you want to delete the channel? 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. - Toto je adresa kanálu. Nie je možné ju používať ako pseudo poštový zoznam. + - + 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. - Zadajte adresu vyššie. + - + 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). - Používate port TCP %1. (Možno zmeniť v nastaveniach). + - + 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 @@ -1115,67 +1144,67 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. Zobraziť posledných %1 hromadných správ z tejto adresy. - + 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é @@ -1220,86 +1249,86 @@ Ste si istý, že chcete kanál odstrániť? 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 @@ -1314,37 +1343,37 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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? @@ -1404,12 +1433,17 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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 @@ -1424,105 +1458,140 @@ Vitajte v jednoduchom a bezpečnom Bitmessage - + 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ť? + + + + Go online + Pripojiť k sieti + + + + Go offline + Odpojiť od siete + 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 @@ -1545,99 +1614,99 @@ Možno by ste mali inovovať Bitmessage. 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) @@ -1645,22 +1714,22 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr NewSubscriptionDialog - + Add new entry Pridať nový záznam - + Label Označenie - + Address Adresa - + Enter an address above. Zadajte adresu vyššie. @@ -1668,55 +1737,60 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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 - PyBitmessage + - + version ? - verzia ? + - + <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. @@ -1725,10 +1799,10 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr <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 Vývojári Bitmessage</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> @@ -1772,40 +1846,45 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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: @@ -1813,30 +1892,35 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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). - Používate port TCP ?. (Možno zmeniť v nastaveniach). + - + 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 @@ -1846,37 +1930,37 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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 # @@ -1886,112 +1970,112 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - + 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 + 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 @@ -2050,7 +2134,7 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - Chan passhphrase/name: + Chan passphrase/name: Názov kanálu: @@ -2072,7 +2156,7 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr newchandialog - + Successfully created / joined chan %1 Kanál %1 úspešne vytvorený/pripojený @@ -2090,17 +2174,17 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. @@ -2116,54 +2200,54 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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ý. + -- 2.45.1 From fd1a6c1fa14ab719f43d97ad52f464826fb32b4c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 3 Feb 2018 11:46:39 +0100 Subject: [PATCH 1073/1102] Dandelion update - dandelion fixes - try to wait as long as possible before expiration if there are no outbound connections - expire in invThread rather than singleCleaner thread - deduplication of code in inv and dinv command methods - turn on by default, seems to work correctly now - turn off dandelion if outbound connections are disabled - start tracking downloads earlier, and faster download loop - remove some obsolete lines - minor PEP8 updates --- src/bitmessagemain.py | 5 ++ src/bmconfigparser.py | 2 +- src/class_singleCleaner.py | 3 -- src/network/bmobject.py | 2 +- src/network/bmproto.py | 43 +++++++-------- src/network/connectionpool.py | 51 +++++------------- src/network/dandelion.py | 98 ++++++++++++++++++++--------------- src/network/downloadthread.py | 5 +- src/network/invthread.py | 33 ++++++------ src/network/objectracker.py | 37 +++++++++---- src/network/tcp.py | 2 +- src/protocol.py | 4 +- src/state.py | 2 + 13 files changed, 149 insertions(+), 138 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 74011f29..accd5740 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -232,6 +232,11 @@ class Main: 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 + helper_bootstrap.knownNodes() # Start the address generation thread addressGeneratorThread = addressGenerator() diff --git a/src/bmconfigparser.py b/src/bmconfigparser.py index bb4377a2..6a598955 100644 --- a/src/bmconfigparser.py +++ b/src/bmconfigparser.py @@ -20,7 +20,7 @@ BMConfigDefaults = { }, "network": { "bind": '', - "dandelion": 0, + "dandelion": 90, }, "inventory": { "storage": "sqlite", diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index 1def6cdb..ca77881c 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -10,7 +10,6 @@ from helper_sql import * from helper_threading import * from inventory import Inventory from network.connectionpool import BMConnectionPool -from network.dandelion import Dandelion from debug import logger import knownnodes import queues @@ -133,8 +132,6 @@ class singleCleaner(threading.Thread, StoppableThread): # inv/object tracking for connection in BMConnectionPool().inboundConnections.values() + BMConnectionPool().outboundConnections.values(): connection.clean() - # dandelion fluff trigger by expiration - Dandelion().expire() # discovery tracking exp = time.time() - singleCleaner.expireDiscoveredPeers diff --git a/src/network/bmobject.py b/src/network/bmobject.py index 267cac58..2e7dd092 100644 --- a/src/network/bmobject.py +++ b/src/network/bmobject.py @@ -74,7 +74,7 @@ class BMObject(object): def checkAlreadyHave(self): # if it's a stem duplicate, pretend we don't have it - if self.inventoryHash in Dandelion().hashMap: + if Dandelion().hasHash(self.inventoryHash): return if self.inventoryHash in Inventory(): raise BMObjectAlreadyHaveError() diff --git a/src/network/bmproto.py b/src/network/bmproto.py index 4bf63bca..28277f52 100644 --- a/src/network/bmproto.py +++ b/src/network/bmproto.py @@ -66,8 +66,6 @@ class BMProto(AdvancedDispatcher, ObjectTracker): self.payloadOffset = 0 self.expectBytes = protocol.Header.size self.object = None - self.dandelionRoutes = [] - self.dandelionRefresh = 0 def state_bm_header(self): self.magic, self.command, self.payloadLength, self.checksum = protocol.Header.unpack(self.read_buf[:protocol.Header.size]) @@ -282,8 +280,8 @@ class BMProto(AdvancedDispatcher, ObjectTracker): #TODO make this more asynchronous random.shuffle(items) for i in map(str, items): - if i in Dandelion().hashMap and \ - self != Dandelion().hashMap[i]: + 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 @@ -298,41 +296,36 @@ class BMProto(AdvancedDispatcher, ObjectTracker): # when using random reordering, as the recipient won't know exactly which objects we refuse to deliver return True - def bm_command_inv(self): + def _command_inv(self, dandelion=False): items = self.decode_payload_content("l32s") if len(items) >= BMProto.maxObjectCount: - logger.error("Too many items in inv message!") + 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 """ - items = self.decode_payload_content("l32s") - - if len(items) >= BMProto.maxObjectCount: - logger.error("Too many items in dinv message!") - raise BMProtoExcessiveDataError() - else: - pass - - # ignore command if dandelion turned off - if BMConfigParser().safeGetBoolean("network", "dandelion") == 0: - return True - - for i in map(str, items): - self.handleReceivedInventory(i) - Dandelion().addHash(i, self) - - return True + return self._command_inv(True) def bm_command_object(self): objectOffset = self.payloadOffset @@ -368,8 +361,12 @@ class BMProto(AdvancedDispatcher, ObjectTracker): 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 diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 2f34e485..2c3b5054 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -8,10 +8,10 @@ from bmconfigparser import BMConfigParser from debug import logger import helper_bootstrap from network.proxy import Proxy -import network.bmproto +from network.bmproto import BMProto from network.dandelion import Dandelion -import network.tcp -import network.udp +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 @@ -33,31 +33,6 @@ class BMConnectionPool(object): self.spawnWait = 2 self.bootstrapped = False - def handleReceivedObject(self, streamNumber, hashid, connection = None): - for i in self.inboundConnections.values() + self.outboundConnections.values(): - if not isinstance(i, network.bmproto.BMProto): - continue - if not i.fullyEstablished: - continue - try: - del i.objectsNewToMe[hashid] - except KeyError: - with i.objectsNewToThemLock: - i.objectsNewToThem[hashid] = time.time() - if i == connection: - try: - with i.objectsNewToThemLock: - del i.objectsNewToThem[hashid] - except KeyError: - pass - if hashid in Dandelion().fluff: - Dandelion().removeHash(hashid) - - def reRandomiseDandelionStems(self): - # Choose 2 peers randomly - # TODO: handle streams - Dandelion().reRandomiseStems(self.outboundConnections.values()) - def connectToStream(self, streamNumber): self.streams.append(streamNumber) @@ -88,7 +63,7 @@ class BMConnectionPool(object): return False def addConnection(self, connection): - if isinstance(connection, network.udp.UDPSocket): + if isinstance(connection, UDPSocket): return if connection.isOutbound: self.outboundConnections[connection.destination] = connection @@ -99,9 +74,9 @@ class BMConnectionPool(object): self.inboundConnections[connection.destination.host] = connection def removeConnection(self, connection): - if isinstance(connection, network.udp.UDPSocket): + if isinstance(connection, UDPSocket): del self.udpSockets[connection.listening.host] - elif isinstance(connection, network.tcp.TCPServer): + elif isinstance(connection, TCPServer): del self.listeningSockets[state.Peer(connection.destination.host, connection.destination.port)] elif connection.isOutbound: try: @@ -135,18 +110,18 @@ class BMConnectionPool(object): bind = self.getListeningIP() port = BMConfigParser().safeGetInt("bitmessagesettings", "port") # correct port even if it changed - ls = network.tcp.TCPServer(host=bind, port=port) + ls = TCPServer(host=bind, port=port) self.listeningSockets[ls.destination] = ls def startUDPSocket(self, bind=None): if bind is None: host = self.getListeningIP() - udpSocket = network.udp.UDPSocket(host=host, announcing=True) + udpSocket = UDPSocket(host=host, announcing=True) else: if bind is False: - udpSocket = network.udp.UDPSocket(announcing=False) + udpSocket = UDPSocket(announcing=False) else: - udpSocket = network.udp.UDPSocket(host=bind, announcing=True) + udpSocket = UDPSocket(host=bind, announcing=True) self.udpSockets[udpSocket.listening.host] = udpSocket def loop(self): @@ -192,11 +167,11 @@ class BMConnectionPool(object): # continue try: if (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): - self.addConnection(network.tcp.Socks5BMConnection(chosen)) + self.addConnection(Socks5BMConnection(chosen)) elif (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a"): - self.addConnection(network.tcp.Socks4aBMConnection(chosen)) + self.addConnection(Socks4aBMConnection(chosen)) elif not chosen.host.endswith(".onion"): - self.addConnection(network.tcp.TCPConnection(chosen)) + self.addConnection(TCPConnection(chosen)) except socket.error as e: if e.errno == errno.ENETUNREACH: continue diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 3e49d906..edd4fb5b 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,62 +1,78 @@ -from random import choice, shuffle +from collections import namedtuple +from random import choice, sample 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 -FLUFF_TRIGGER_TIMEOUT = 300 +# trigger fluff due to expiration in 2 minutes +FLUFF_TRIGGER_TIMEOUT = 120 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 = {} - self.fluff = {} - self.timeout = {} + # when to rerandomise routes self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() - def addHash(self, hashId, source): - if BMConfigParser().safeGetInt('network', 'dandelion') == 0: + def addHash(self, hashId, source=None, stream=1): + if not state.dandelion: return with self.lock: - self.hashMap[hashId] = self.getNodeStem(source) - self.timeout[hashId] = time() + FLUFF_TRIGGER_TIMEOUT + self.hashMap[hashId] = Stem( + self.getNodeStem(source), + stream, + time() + FLUFF_TRIGGER_TIMEOUT) - def removeHash(self, hashId): + def setHashStream(self, hashId, stream=1): + with self.lock: + if hashId in self.hashMap: + self.hashMap[hashId] = Stem( + self.hashMap[hashId].child, + stream, + time() + FLUFF_TRIGGER_TIMEOUT) + + 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 - try: - del self.timeout[hashId] - except KeyError: - pass - try: - del self.fluff[hashId] - except KeyError: - pass - def fluffTrigger(self, hashId): - with self.lock: - self.fluff[hashId] = None + 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) - # active mappings pointing nowhere - for k in (k for k, v in self.nodeMap.iteritems() if self.nodeMap[k] is None): + for k in (k for k, v in self.nodeMap.iteritems() if v is None): self.nodeMap[k] = connection - for k in (k for k, v in self.hashMap.iteritems() if self.hashMap[k] is None): - self.hashMap[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, time() + FLUFF_TRIGGER_TIMEOUT) + invQueue.put((v.stream, k, v.child)) + def maybeRemoveStem(self, connection): # is the stem active? @@ -64,12 +80,10 @@ class Dandelion(): 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 self.nodeMap[k] == connection): + for k in (k for k, v in self.nodeMap.iteritems() if v == connection): self.nodeMap[k] = None - for k in (k for k, v in self.hashMap.iteritems() if self.hashMap[k] == connection): - self.hashMap[k] = None - if len(self.stem) < MAX_STEMS: - self.stem.append(connection) + 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, time() + FLUFF_TRIGGER_TIMEOUT) def pickStem(self, parent=None): try: @@ -92,26 +106,26 @@ class Dandelion(): try: return self.nodeMap[node] except KeyError: - self.nodeMap[node] = self.pickStem() + self.nodeMap[node] = self.pickStem(node) return self.nodeMap[node] - def getHashStem(self, hashId): - with self.lock: - return self.hashMap[hashId] - def expire(self): with self.lock: deadline = time() - toDelete = [k for k, v in self.hashMap.iteritems() if self.timeout[k] < deadline] - for k in toDelete: - del self.timeout[k] - del self.hashMap[k] + # 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, connections): - shuffle(connections) + def reRandomiseStems(self): with self.lock: - # random two connections - self.stem = connections[:MAX_STEMS] + 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 index 88f7c12e..7eee2761 100644 --- a/src/network/downloadthread.py +++ b/src/network/downloadthread.py @@ -3,6 +3,7 @@ import threading import time import addresses +from dandelion import Dandelion from debug import logger from helper_threading import StoppableThread from inventory import Inventory @@ -54,7 +55,7 @@ class DownloadThread(threading.Thread, StoppableThread): payload = bytearray() payload.extend(addresses.encodeVarint(len(request))) for chunk in request: - if chunk in Inventory(): + if chunk in Inventory() and not Dandelion().hasHash(chunk): try: del i.objectsNewToMe[chunk] except KeyError: @@ -70,4 +71,4 @@ class DownloadThread(threading.Thread, StoppableThread): if time.time() >= self.lastCleaned + DownloadThread.cleanInterval: self.cleanPending() if not requested: - self.stop.wait(5) + self.stop.wait(1) diff --git a/src/network/invthread.py b/src/network/invthread.py index 5852df0b..d0d758fb 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -18,26 +18,28 @@ class InvThread(threading.Thread, StoppableThread): 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: - Dandelion().addHash(data[1], None) - BMConnectionPool().handleReceivedObject(data[0], data[1]) - # came over the network - else: - source = BMConnectionPool().getConnectionByAddr(data[2]) - BMConnectionPool().handleReceivedObject(data[0], data[1], source) + if len(data) == 2 or data[2] is None: + self.handleLocallyGenerated(data[0], data[1]) except Queue.Empty: break - # connection not found, handle it as if generated locally - except KeyError: - BMConnectionPool().handleReceivedObject(data[0], data[1]) if chunk: for connection in BMConnectionPool().inboundConnections.values() + \ @@ -53,12 +55,13 @@ class InvThread(threading.Thread, StoppableThread): except KeyError: continue try: - if connection == Dandelion().hashMap[inv[1]]: + if connection == Dandelion().objectChildStem(inv[1]): # Fluff trigger by RNG # auto-ignore if config set to 0, i.e. dandelion is off - # send a normal inv if stem node doesn't support dandelion - if randint(1, 100) < BMConfigParser().safeGetBoolean("network", "dandelion") and \ - connection.services | protocol.NODE_DANDELION > 0: + 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]) @@ -79,6 +82,6 @@ class InvThread(threading.Thread, StoppableThread): invQueue.task_done() if Dandelion().refresh < time(): - BMConnectionPool().reRandomiseDandelionStems() + Dandelion().reRandomiseStems() self.stop.wait(1) diff --git a/src/network/objectracker.py b/src/network/objectracker.py index 327304d9..66b0685b 100644 --- a/src/network/objectracker.py +++ b/src/network/objectracker.py @@ -1,9 +1,8 @@ -from Queue import Queue import time from threading import RLock -from debug import logger from inventory import Inventory +import network.connectionpool from network.dandelion import Dandelion from randomtrackingdict import RandomTrackingDict from state import missingObjects @@ -80,13 +79,32 @@ class ObjectTracker(object): del self.objectsNewToThem[hashId] except KeyError: pass - # Fluff trigger by cycle detection - if hashId not in Inventory() or hashId in Dandelion().hashMap: - if hashId in Dandelion().hashMap: - Dandelion().fluffTrigger(hashId) - if hashId not in missingObjects: - missingObjects[hashId] = time.time() - self.objectsNewToMe[hashId] = True + 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: @@ -109,4 +127,3 @@ class ObjectTracker(object): # tracking inv # - per node hash of items that neither the remote node nor we have # - diff --git a/src/network/tcp.py b/src/network/tcp.py index 5a27aca3..33c4b6ca 100644 --- a/src/network/tcp.py +++ b/src/network/tcp.py @@ -168,7 +168,7 @@ class TCPConnection(BMProto, TLSDispatcher): with self.objectsNewToThemLock: for objHash in Inventory().unexpired_hashes_by_stream(stream): # don't advertise stem objects on bigInv - if objHash in Dandelion().hashMap: + if Dandelion().hasHash(objHash): continue bigInvList[objHash] = 0 self.objectsNewToThem[objHash] = time.time() diff --git a/src/protocol.py b/src/protocol.py index ef31b6c1..e5b2c5c2 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -196,7 +196,7 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server payload += pack('>q', NODE_NETWORK | (NODE_SSL if haveSSL(server) else 0) | - (NODE_DANDELION if BMConfigParser().safeGetInt('network', 'dandelion') > 0 else 0) + (NODE_DANDELION if state.dandelion else 0) ) payload += pack('>q', int(time.time())) @@ -213,7 +213,7 @@ def assembleVersionMessage(remoteHost, remotePort, participatingStreams, server payload += pack('>q', NODE_NETWORK | (NODE_SSL if haveSSL(server) else 0) | - (NODE_DANDELION if BMConfigParser().safeGetInt('network', 'dandelion') > 0 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. diff --git a/src/state.py b/src/state.py index 32433e2d..73e4f789 100644 --- a/src/state.py +++ b/src/state.py @@ -53,3 +53,5 @@ def resetNetworkProtocolAvailability(): networkProtocolAvailability = {'IPv4': None, 'IPv6': None, 'onion': None} resetNetworkProtocolAvailability() + +dandelion = 0 -- 2.45.1 From a646ec49029f65608286cbf6295f1cf574d7e1d3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 4 Feb 2018 21:03:54 +0100 Subject: [PATCH 1074/1102] Allow separate proxy for onions - new options in network section: onionsocksproxytype, onionsockshostname and onionsocksport. These allow to separate connectivity types for onion and non-onion addresses, e.g. connect to clear nodes over clearnet and onions over tor - also remove some obsolete imports --- src/network/connectionpool.py | 26 +++++++++++++++++++++----- src/network/proxy.py | 26 +++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 2c3b5054..9b91386e 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -1,3 +1,4 @@ +from ConfigParser import NoOptionError, NoSectionError import errno import socket import time @@ -8,8 +9,6 @@ from bmconfigparser import BMConfigParser from debug import logger import helper_bootstrap from network.proxy import Proxy -from network.bmproto import BMProto -from network.dandelion import Dandelion from network.tcp import TCPServer, Socks5BMConnection, Socks4aBMConnection, TCPConnection from network.udp import UDPSocket from network.connectionchooser import chooseConnection @@ -143,6 +142,15 @@ class BMConnectionPool(object): 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").beginswith("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"): @@ -166,15 +174,23 @@ class BMConnectionPool(object): # if chosen.host == c.destination.host: # continue try: - if (BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS5"): + 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"): + elif BMConfigParser().safeGet("bitmessagesettings", "socksproxytype") == "SOCKS4a": self.addConnection(Socks4aBMConnection(chosen)) - elif not chosen.host.endswith(".onion"): + 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: diff --git a/src/network/proxy.py b/src/network/proxy.py index 96930c18..43298f63 100644 --- a/src/network/proxy.py +++ b/src/network/proxy.py @@ -37,6 +37,8 @@ class Proxy(AdvancedDispatcher): # instances should change too _proxy = ("127.0.0.1", 9050) _auth = None + _onion_proxy = None + _onion_auth = None _remote_dns = True @property @@ -58,6 +60,25 @@ class Proxy(AdvancedDispatcher): 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 @@ -66,7 +87,10 @@ class Proxy(AdvancedDispatcher): self.isOutbound = True self.fullyEstablished = False self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.connect(self.proxy) + 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") -- 2.45.1 From 03f08b3cfdaafd1ee9eeda286fc7bbe8c828c820 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 4 Feb 2018 21:16:30 +0100 Subject: [PATCH 1075/1102] Typo --- src/network/connectionpool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/connectionpool.py b/src/network/connectionpool.py index 9b91386e..408d56e0 100644 --- a/src/network/connectionpool.py +++ b/src/network/connectionpool.py @@ -145,7 +145,7 @@ class BMConnectionPool(object): # TODO AUTH # TODO reset based on GUI settings changes try: - if not BMConfigParser().get("network", "onionsocksproxytype").beginswith("SOCKS"): + if not BMConfigParser().get("network", "onionsocksproxytype").startswith("SOCKS"): raise NoOptionError Proxy.onionproxy = (BMConfigParser().get("network", "onionsockshostname"), BMConfigParser().getint("network", "onionsocksport")) -- 2.45.1 From 85cce42de08034b426954b02b516d817f35e1707 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 5 Feb 2018 14:39:32 +0200 Subject: [PATCH 1076/1102] Update "Network Status" information only when the tab selected --- src/bitmessageqt/__init__.py | 10 ++++++++++ src/bitmessageqt/networkstatus.py | 14 +++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3422664b..f370f3b8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -686,6 +686,10 @@ class MyForm(settingsmixin.SMainWindow): "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 + ) # Put the colored icon on the status bar # self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) @@ -4012,6 +4016,12 @@ class MyForm(settingsmixin.SMainWindow): completerList[i] = item.label + " <" + item.address + ">" self.ui.lineEditTo.completer().model().setStringList(completerList) + def tabWidgetCurrentChanged(self, n): + if n == self.ui.tabWidget.indexOf(self.ui.networkstatus): + self.ui.networkstatus.startUpdate() + else: + self.ui.networkstatus.stopUpdate() + def writeNewAddressToTable(self, label, address, streamNumber): self.rerenderTabTreeMessages() self.rerenderTabTreeSubscriptions() diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 67284495..02c0deaf 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -39,10 +39,18 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): "updateNumberOfBroadcastsProcessed()"), self.updateNumberOfBroadcastsProcessed) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "updateNetworkStatusTab(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.updateNetworkStatusTab) - + self.timer = QtCore.QTimer() - self.timer.start(2000) # milliseconds - QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + + QtCore.QObject.connect( + self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + + def startUpdate(self): + 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"]: -- 2.45.1 From 4a3f8f4806c38d404053617db2071d69ad367dda Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 6 Feb 2018 15:48:56 +0200 Subject: [PATCH 1077/1102] Change unread status of message in "All Accounts" when it changed in "Chans" and vice versa (#1044, #884) --- src/bitmessageqt/__init__.py | 158 ++++++++++++++++++++--------------- 1 file changed, 89 insertions(+), 69 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f370f3b8..76940ec0 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -911,6 +911,46 @@ class MyForm(settingsmixin.SMainWindow): 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") @@ -2583,7 +2623,7 @@ class MyForm(settingsmixin.SMainWindow): ), QtGui.QMessageBox.Yes | QtGui.QMessageBox.No ) != QtGui.QMessageBox.Yes: return - addressAtCurrentRow = self.getCurrentAccount() + # addressAtCurrentRow = self.getCurrentAccount() tableWidget = self.getCurrentMessagelist() idCount = tableWidget.rowCount() @@ -2610,8 +2650,8 @@ class MyForm(settingsmixin.SMainWindow): ) if markread > 0: - self.propagateUnreadCount( - addressAtCurrentRow, self.getCurrentFolder(), None, 0) + self.propagateUnreadCount() + # addressAtCurrentRow, self.getCurrentFolder(), None, 0) def click_NewAddressDialog(self): dialogs.NewAddressDialog(self) @@ -2844,36 +2884,32 @@ class MyForm(settingsmixin.SMainWindow): tableWidget = self.getCurrentMessagelist() if not tableWidget: return - font = QtGui.QFont() - font.setBold(True) - inventoryHashesToMarkUnread = [] - modified = 0 + + msgids = set() + # modified = 0 for row in tableWidget.selectedIndexes(): currentRow = row.row() - inventoryHashToMarkUnread = str(tableWidget.item( + msgid = str(tableWidget.item( currentRow, 3).data(QtCore.Qt.UserRole).toPyObject()) - if inventoryHashToMarkUnread in inventoryHashesToMarkUnread: - # it returns columns as separate items, so we skip dupes - continue - if not tableWidget.item(currentRow, 0).unread: - modified += 1 - inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) - tableWidget.item(currentRow, 0).setUnread(True) - tableWidget.item(currentRow, 1).setUnread(True) - tableWidget.item(currentRow, 2).setUnread(True) - tableWidget.item(currentRow, 3).setFont(font) + msgids.add(msgid) + # if not tableWidget.item(currentRow, 0).unread: + # modified += 1 + self.updateUnreadStatus(tableWidget, currentRow, msgid, False) + # for 1081 - idCount = len(inventoryHashesToMarkUnread) - rowcount = sqlExecuteChunked( + idCount = len(msgids) + # rowcount = + sqlExecuteChunked( '''UPDATE inbox SET read=0 WHERE msgid IN ({0}) AND read=1''', - idCount, *inventoryHashesToMarkUnread + idCount, *msgids ) - 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) + 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) # 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. @@ -3953,54 +3989,38 @@ class MyForm(settingsmixin.SMainWindow): messageTextedit = self.getCurrentMessageTextedit() if not messageTextedit: return - queryreturn = [] - message = "" - if folder == 'sent': - ackdata = self.getCurrentMessageId() - if ackdata and messageTextedit: - queryreturn = sqlQuery( - '''select message, 1 from sent where ackdata=?''', ackdata) + msgid = self.getCurrentMessageId() + if msgid: + queryreturn = sqlQuery( + '''SELECT message FROM %s WHERE %s=?''' % ( + ('sent', 'ackdata') if folder == 'sent' + else ('inbox', 'msgid') + ), msgid + ) + + try: + message = queryreturn[-1][0] + except NameError: + message = "" + except IndexError: + message = _translate( + "MainWindow", + "Error occurred: could not load message from disk." + ) else: - msgid = self.getCurrentMessageId() - if msgid and messageTextedit: - queryreturn = sqlQuery( - '''select message, read from inbox where msgid=?''', msgid) - - if queryreturn != []: - refresh = False - propagate = False tableWidget = self.getCurrentMessagelist() currentRow = tableWidget.currentRow() - for row in queryreturn: - message, read = row - if tableWidget.item(currentRow, 0).unread == True: - refresh = True - if folder != 'sent': - markread = sqlExecute( - '''UPDATE inbox SET read = 1 WHERE msgid = ? AND read=0''', msgid) - if markread > 0: - propagate = True - if refresh: - if not tableWidget: - return - font = QtGui.QFont() - font.setBold(False) -# inventoryHashesToMarkRead = [] -# inventoryHashToMarkRead = str(tableWidget.item( -# currentRow, 3).data(Qt.UserRole).toPyObject()) -# inventoryHashesToMarkRead.append(inventoryHashToMarkRead) - tableWidget.item(currentRow, 0).setUnread(False) - tableWidget.item(currentRow, 1).setUnread(False) - tableWidget.item(currentRow, 2).setUnread(False) - tableWidget.item(currentRow, 3).setFont(font) - if propagate: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(QtCore.Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + # 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() - else: - data = self.getCurrentMessageId() - if data != False: - message = "Error occurred: could not load message from disk." messageTextedit.setCurrentFont(QtGui.QFont()) messageTextedit.setTextColor(QtGui.QColor()) messageTextedit.setContent(message) -- 2.45.1 From 3b3e4de9d7fc22e7ff011c38043e6904844fd051 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 6 Feb 2018 17:33:19 +0200 Subject: [PATCH 1078/1102] Zero Inventory().numberOfInventoryLookupsPerformed before update started because "Inventory lookups per second" is calculated by /2 (for 2 sec) --- src/bitmessageqt/networkstatus.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 02c0deaf..06b1e0ce 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -46,6 +46,7 @@ class NetworkStatus(QtGui.QWidget, RetranslateMixin): self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) def startUpdate(self): + Inventory().numberOfInventoryLookupsPerformed = 0 self.runEveryTwoSeconds() self.timer.start(2000) # milliseconds -- 2.45.1 From d083c53e1b0c1c6470086fe87514afd1204b6c07 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 5 Feb 2018 16:40:43 +0200 Subject: [PATCH 1079/1102] New button "Clear" on tab "Send" to clear all fields (#919) --- src/bitmessageqt/__init__.py | 9 ++++++++- src/bitmessageqt/bitmessageui.py | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 76940ec0..51d26388 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -147,6 +147,8 @@ class MyForm(settingsmixin.SMainWindow): "clicked()"), self.click_pushButtonAddSubscription) 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.pushButtonFetchNamecoinID, QtCore.SIGNAL( @@ -1840,7 +1842,6 @@ class MyForm(settingsmixin.SMainWindow): def rerenderSubscriptions(self): self.rerenderTabTreeSubscriptions() - 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. @@ -1848,6 +1849,12 @@ class MyForm(settingsmixin.SMainWindow): 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) + def click_pushButtonSend(self): encoding = 3 if QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier else 2 diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index f5d28a7f..cb3578c0 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -337,6 +337,9 @@ class Ui_MainWindow(object): 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) @@ -701,6 +704,7 @@ class Ui_MainWindow(object): 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)) -- 2.45.1 From 3d1fa473fb270339d8b326a31f2357f20fb71d9d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Feb 2018 22:28:56 +0100 Subject: [PATCH 1080/1102] Dandelion updates - expiration now uses poisson distribution just like in the bitcoin version --- src/network/dandelion.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/network/dandelion.py b/src/network/dandelion.py index edd4fb5b..bee01d73 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -1,5 +1,5 @@ from collections import namedtuple -from random import choice, sample +from random import choice, sample, expovariate from threading import RLock from time import time @@ -12,8 +12,11 @@ import state # randomise routes after 600 seconds REASSIGN_INTERVAL = 600 -# trigger fluff due to expiration in 2 minutes -FLUFF_TRIGGER_TIMEOUT = 120 + +# trigger fluff due to expiration +FLUFF_TRIGGER_FIXED_DELAY = 10 +FLUFF_TRIGGER_MEAN_DELAY = 30 + MAX_STEMS = 2 Stem = namedtuple('Stem', ['child', 'stream', 'timeout']) @@ -31,6 +34,14 @@ class Dandelion(): self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() + @staticmethod + def poissonTimeout(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 @@ -38,7 +49,7 @@ class Dandelion(): self.hashMap[hashId] = Stem( self.getNodeStem(source), stream, - time() + FLUFF_TRIGGER_TIMEOUT) + Dandelion.poissonTimeout()) def setHashStream(self, hashId, stream=1): with self.lock: @@ -46,7 +57,7 @@ class Dandelion(): self.hashMap[hashId] = Stem( self.hashMap[hashId].child, stream, - time() + FLUFF_TRIGGER_TIMEOUT) + Dandelion.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) @@ -70,7 +81,7 @@ class Dandelion(): 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, time() + FLUFF_TRIGGER_TIMEOUT) + self.hashMap[k] = Stem(connection, v.stream, Dandelion.poissionTimeout()) invQueue.put((v.stream, k, v.child)) @@ -83,7 +94,7 @@ class Dandelion(): 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, time() + FLUFF_TRIGGER_TIMEOUT) + self.hashMap[k] = Stem(None, v.stream, Dandelion.poissonTimeout()) def pickStem(self, parent=None): try: -- 2.45.1 From c6834093ee07406b385a81c5994977fab8a42b1e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 6 Feb 2018 23:55:41 +0100 Subject: [PATCH 1081/1102] QT sqlite conversion fix - QByteArray will be stored as str in the db --- src/bitmessageqt/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 51d26388..9fb5fb29 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -33,6 +33,7 @@ from pyelliptic.openssl import OpenSSL import textwrap import debug import random +from sqlite3 import register_adapter import string from datetime import datetime, timedelta from helper_ackPayload import genAckPayload @@ -1328,6 +1329,10 @@ class MyForm(settingsmixin.SMainWindow): 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): @@ -4396,6 +4401,7 @@ def run(): app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() + myapp.sqlInit() myapp.appIndicatorInit(app) myapp.indicatorInit() myapp.notifierInit() -- 2.45.1 From 08bb85a95254a54cf9182d0f452b29bf904f5100 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 7 Feb 2018 17:22:26 +0100 Subject: [PATCH 1082/1102] Dandelion staticmethod fix --- src/network/dandelion.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/network/dandelion.py b/src/network/dandelion.py index bee01d73..098a9a22 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -34,8 +34,7 @@ class Dandelion(): self.refresh = time() + REASSIGN_INTERVAL self.lock = RLock() - @staticmethod - def poissonTimeout(start=None, average=0): + def poissonTimeout(self, start=None, average=0): if start is None: start = time() if average == 0: @@ -49,7 +48,7 @@ class Dandelion(): self.hashMap[hashId] = Stem( self.getNodeStem(source), stream, - Dandelion.poissonTimeout()) + self.poissonTimeout()) def setHashStream(self, hashId, stream=1): with self.lock: @@ -57,7 +56,7 @@ class Dandelion(): self.hashMap[hashId] = Stem( self.hashMap[hashId].child, stream, - Dandelion.poissonTimeout()) + 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) @@ -81,7 +80,7 @@ class Dandelion(): 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, Dandelion.poissionTimeout()) + self.hashMap[k] = Stem(connection, v.stream, self.poissionTimeout()) invQueue.put((v.stream, k, v.child)) @@ -94,7 +93,7 @@ class Dandelion(): 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, Dandelion.poissonTimeout()) + self.hashMap[k] = Stem(None, v.stream, self.poissonTimeout()) def pickStem(self, parent=None): try: -- 2.45.1 From f870bcc6f7bc03ae4fa4380aa8647c60d44ec190 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 8 Feb 2018 06:52:33 +0100 Subject: [PATCH 1083/1102] More lightweight URI regexp - the old one can take a lot of resources and be misused for a DoS - this still nees to be tested if it is flexible enough - also fix link click popup --- src/bitmessageqt/messageview.py | 2 +- src/bitmessageqt/safehtmlparser.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index de357e23..751d4ff7 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -70,7 +70,7 @@ class MessageView(QtGui.QTextBrowser): 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(str(link.toString())), + 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) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 88431855..d1d7910c 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -22,7 +22,8 @@ class SafeHTMLParser(HTMLParser): 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'(?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' Date: Thu, 8 Feb 2018 12:58:38 +0200 Subject: [PATCH 1084/1102] Fixed trailing '>' in message view which appeared after HTLM rendering --- src/bitmessageqt/messageview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 751d4ff7..4d2e768d 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -103,7 +103,7 @@ class MessageView(QtGui.QTextBrowser): if self.mode == MessageView.MODE_HTML: pos = self.out.find(">", self.outpos) if pos > self.outpos: - self.outpos = pos + 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) -- 2.45.1 From 066b419e16d8a04eb7b54590e864f95f99ce6d09 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 9 Feb 2018 00:49:08 +0100 Subject: [PATCH 1085/1102] Bugfixes - typo in dandelion - stealth ackdata fix for broadcasts and mailing lists --- src/bitmessageqt/__init__.py | 1 + src/class_objectProcessor.py | 8 +++++--- src/network/dandelion.py | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9fb5fb29..3230a803 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2095,6 +2095,7 @@ class MyForm(settingsmixin.SMainWindow): # 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 ripe = '' diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index addcb24b..6387f6a7 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -553,7 +553,9 @@ 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 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. + # 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 = '[Broadcast subscribers]' ripe = '' @@ -568,7 +570,7 @@ class objectProcessor(threading.Thread): fromAddress, subject, message, - ackdataForBroadcast, + ackdata, int(time.time()), # sentTime (this doesn't change) int(time.time()), # lastActionTime 0, @@ -580,7 +582,7 @@ class objectProcessor(threading.Thread): helper_sent.insert(t) queues.UISignalQueue.put(('displayNewSentMessage', ( - toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdataForBroadcast))) + toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdata))) queues.workerQueue.put(('sendbroadcast', '')) # Don't send ACK if invalid, blacklisted senders, invisible messages, disabled or chan diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 098a9a22..06ecca24 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -80,7 +80,7 @@ class Dandelion(): 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.poissionTimeout()) + self.hashMap[k] = Stem(connection, v.stream, self.poissonTimeout()) invQueue.put((v.stream, k, v.child)) -- 2.45.1 From cf8ed3624021db78bc15ed5f96f4314f795ba0eb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 9 Feb 2018 11:11:48 +0100 Subject: [PATCH 1086/1102] Windows Qt refactoring fix --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3230a803..7bbd7dd9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -598,7 +598,7 @@ class MyForm(settingsmixin.SMainWindow): 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 = QSettings(RUN_PATH, QSettings.NativeFormat) + self.settings = QtCore.QSettings(RUN_PATH, QtCore.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'): @@ -2546,7 +2546,7 @@ class MyForm(settingsmixin.SMainWindow): 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 = QSettings(RUN_PATH, QSettings.NativeFormat) + self.settings = QtCore.QSettings(RUN_PATH, QtCore.QSettings.NativeFormat) if BMConfigParser().getboolean('bitmessagesettings', 'startonlogon'): self.settings.setValue("PyBitmessage", sys.argv[0]) else: -- 2.45.1 From a69daa13b9d6e8c89fc41e856bc8385fc6cff17e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 12 Feb 2018 13:48:59 +0100 Subject: [PATCH 1087/1102] Pluralisation --- src/bitmessageqt/address_dialogs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index 7b619625..6bb5028b 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -194,7 +194,7 @@ class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): self.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate( "MainWindow", - "Display the %1 recent broadcast(s) from this address." + "Display the %n recent broadcast(s) from this address." ).arg(count)) -- 2.45.1 From eefc967737c90c3f715153aad113f2bb71fa1fca Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 12 Feb 2018 14:10:51 +0100 Subject: [PATCH 1088/1102] Pluralisation --- src/bitmessageqt/address_dialogs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index 6bb5028b..71219a01 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -194,8 +194,11 @@ class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): self.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate( "MainWindow", - "Display the %n recent broadcast(s) from this address." - ).arg(count)) + "Display the %n recent broadcast(s) from this address.", + None, + QtCore.QCoreApplication.CodecForTr, + count + ) class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): -- 2.45.1 From 2bc2b6bc5be3eabce07bc83284582b642a9b4061 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 12 Feb 2018 14:49:43 +0100 Subject: [PATCH 1089/1102] Typo --- src/bitmessageqt/address_dialogs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/address_dialogs.py b/src/bitmessageqt/address_dialogs.py index 71219a01..2ea5cef8 100644 --- a/src/bitmessageqt/address_dialogs.py +++ b/src/bitmessageqt/address_dialogs.py @@ -198,7 +198,7 @@ class NewSubscriptionDialog(AddressDataDialog, RetranslateMixin): None, QtCore.QCoreApplication.CodecForTr, count - ) + )) class RegenerateAddressesDialog(QtGui.QDialog, RetranslateMixin): -- 2.45.1 From eb97face6170984a579cb5c597998357eacb9c50 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 12 Feb 2018 17:07:54 +0100 Subject: [PATCH 1090/1102] Show traceback in protocol parser error handler --- src/network/advanceddispatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/advanceddispatcher.py b/src/network/advanceddispatcher.py index 31555c62..6f857398 100644 --- a/src/network/advanceddispatcher.py +++ b/src/network/advanceddispatcher.py @@ -61,7 +61,7 @@ class AdvancedDispatcher(asyncore.dispatcher): if not getattr(self, "state_" + str(self.state))(): break except AttributeError: - logger.error("Unknown state %s", self.state) + logger.error("Unknown state %s", self.state, exc_info=True) raise except BusyError: return False -- 2.45.1 From 6bcbad63b9f2a385b421eeb8a4db2404b0ab198f Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Mon, 12 Feb 2018 13:21:31 +0200 Subject: [PATCH 1091/1102] Marked folder names for translation --- src/bitmessageqt/foldertree.py | 39 ++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 7cc42229..11227fca 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,12 +1,20 @@ 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 -class AccountMixin (object): +# for pylupdate +_translate("MainWindow", "inbox") +_translate("MainWindow", "new") +_translate("MainWindow", "sent") +_translate("MainWindow", "trash") + + +class AccountMixin(object): ALL = 0 NORMAL = 1 CHAN = 2 @@ -97,7 +105,8 @@ class AccountMixin (object): retval, = row retval = unicode(retval, 'utf-8') elif self.address is None or self.type == AccountMixin.ALL: - return unicode(str(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') + return unicode( + str(_translate("MainWindow", "All accounts")), 'utf-8') if retval is None: return unicode(self.address, 'utf-8') else: @@ -115,17 +124,16 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): def setFolderName(self, fname): self.folderName = str(fname) - + def data(self, column, role): if column == 0: if role == QtCore.Qt.DisplayRole: - return QtGui.QApplication.translate("MainWindow", self.folderName) + (" (" + str(self.unreadCount) + ")" if self.unreadCount > 0 else "") - elif role == QtCore.Qt.EditRole: - return QtGui.QApplication.translate("MainWindow", self.folderName) - elif role == QtCore.Qt.ToolTipRole: - return QtGui.QApplication.translate("MainWindow", self.folderName) - elif role == QtCore.Qt.DecorationRole: - pass + 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) @@ -166,16 +174,19 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): self.setEnabled(enabled) self.setUnreadCount(unreadCount) self.setType() - + def _getLabel(self): if self.address is None: - return unicode(QtGui.QApplication.translate("MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') + return unicode(_translate( + "MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') else: try: - return unicode(BMConfigParser().get(self.address, 'label'), 'utf-8', 'ignore') + 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: -- 2.45.1 From 022ee0917709852799f774e50faa87bc796efa96 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 12 Feb 2018 21:33:30 +0100 Subject: [PATCH 1092/1102] Auto-updated language sk from transifex --- src/translations/bitmessage_sk.qm | Bin 88287 -> 90043 bytes src/translations/bitmessage_sk.ts | 431 ++++++++++++++++-------------- 2 files changed, 233 insertions(+), 198 deletions(-) diff --git a/src/translations/bitmessage_sk.qm b/src/translations/bitmessage_sk.qm index 228eff26de773d42b59882b0de916e0c870184f6..26c2a24d6b127a7fe5aa2c47d03ac662cf8029e2 100644 GIT binary patch delta 4825 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.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 @@ -200,52 +200,52 @@ Please type the desired email address (including @mailchuck.com) below: 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á @@ -270,12 +270,12 @@ Please type the desired email address (including @mailchuck.com) below: Kopírovať adresu do clipboardu - + Special address behavior... Zvláštne správanie adresy... - + Email gateway E-mailová brána @@ -285,37 +285,37 @@ Please type the desired email address (including @mailchuck.com) below: 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. @@ -325,17 +325,17 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -345,77 +345,77 @@ Please type the desired email address (including @mailchuck.com) below: - + 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. @@ -424,17 +424,17 @@ It is important that you back up this file. 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.) @@ -443,37 +443,37 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -543,22 +543,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -566,17 +566,17 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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. @@ -621,57 +621,57 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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 @@ -696,47 +696,47 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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é. @@ -771,22 +771,22 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne 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". @@ -796,42 +796,42 @@ Tento súbor je dôležité zálohovať. Chcete tento súbor teraz otvoriť? (Ne - + 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? @@ -840,7 +840,7 @@ Are you sure you want to delete the subscription? 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? @@ -849,32 +849,32 @@ Are you sure you want to delete the channel? 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... @@ -939,192 +939,192 @@ Ste si istý, že chcete kanál odstrániť? - + 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 @@ -1144,67 +1144,67 @@ Ste si istý, že chcete kanál odstrániť? Pridať nový záznam - + Display the %1 recent broadcast(s) from this address. - Zobraziť posledných %1 hromadných správ z tejto adresy. + - + 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é @@ -1308,7 +1308,7 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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... @@ -1318,7 +1318,7 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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. @@ -1343,37 +1343,37 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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? @@ -1438,12 +1438,12 @@ Priímcova požadovaná obtiažnosť: %1 a %2 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 @@ -1458,120 +1458,155 @@ Vitajte v jednoduchom a bezpečnom Bitmessage - + 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 @@ -1762,7 +1797,7 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. @@ -1970,27 +2005,27 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr - + 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 @@ -2005,32 +2040,32 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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. @@ -2242,12 +2277,12 @@ Predvoľba je pomocou generátora náhodných čísiel, ale deterministické adr 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ý. -- 2.45.1 From e5428ee0640bb2e4483b7f12643768f1f8be475e Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 12 Feb 2018 21:50:45 +0100 Subject: [PATCH 1093/1102] Auto-updated language de from transifex --- src/translations/bitmessage_de.qm | Bin 96660 -> 97474 bytes src/translations/bitmessage_de.ts | 431 ++++++++++++++++-------------- 2 files changed, 233 insertions(+), 198 deletions(-) diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 9fa26fae11ce88ebd486bcc7bd5f502ddad73991..ef443a619e0e40e55aede8479d45b488e57652f4 100644 GIT binary patch delta 3931 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 delta 3494 zcmX9>d0b8T8-Bj`oOACz_ndq0$j(QYY*DF*mQe^vTuY=#B}Ixzwn8^TSyEKwN-9~0 zP_hrQ%vj5ssjNd|hRPCIeum#mf4$xFJ?Hzr@AE$I^S+(?B&631sm+Xz0PMhe-Us;g zz|@<7Z~!QJ3=Fjbtd;{~{{R-*1Aa}x%ufIly90*>AZ!p=L=^ZNoq=h8g0GkaOg9H# zV+%ys{;*7)2O;7dSc`B7Yk6Q@JcP{8K;8%lS%Uy$dJz3F7T8n+VP8I&{}%|yR)Gco z0_7f#9BhTkXE4|dHN?TkDUb=!<&^>++t6fiJy5#?O%81UYhQ@ga0Na+MVpv)z`
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(): + pass + + def createPassphrase(): + pass + + def broadcastAddress(): + pass + + def registerMailchuck(): + pass + + def waitRegistration(): + 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() -- 2.45.1 From f2e9b3467fde3b376976166573c469aec5058760 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:08:12 +0200 Subject: [PATCH 0020/1102] Address tree sorting Sorts addresses in the address tree --- src/bitmessageqt/__init__.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8580d206..d2404636 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -168,6 +168,28 @@ def change_translation(locale): qtranslator.load(translationpath) QtGui.QApplication.installTranslator(qtranslator) +def address_compare(x, y): + if x == "bitmessagesettings": + return -1 + elif y == "bitmessagesettings": + return 1 + if shared.config.getboolean(x, 'enabled') == shared.config.getboolean(y, 'enabled'): + if shared.config.get(x, 'label'): + x1 = shared.config.get(x, 'label') + else: + x1 = x + if shared.config.get(y, 'label'): + y1 = shared.config.get(y, 'label') + else: + y1 = y + if x1 > y1: + return 1 + elif x1 < y1: + return -1 + else: + return 0 + else: + return (1 if shared.config.getboolean(x, 'enabled') else '-1') class MyForm(QtGui.QMainWindow): @@ -536,7 +558,7 @@ class MyForm(QtGui.QMainWindow): def rerenderTabTreeChans(self): self.rerenderTabTree('chan') - + def rerenderTabTree(self, tab): folders = ['inbox', 'sent', 'trash'] if tab == 'messages': @@ -553,7 +575,7 @@ class MyForm(QtGui.QMainWindow): toaddress, folder, cnt = row cntUnreadMsg[toaddress + folder] = cnt - configSections = shared.config.sections() + configSections = sorted(shared.config.sections(), cmp=address_compare) for addressInKeysFile in configSections: if addressInKeysFile != 'bitmessagesettings': isEnabled = shared.config.getboolean( -- 2.45.1 From cae03d66df0a32ecba50a4136f429a648b8ab48a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:10:30 +0200 Subject: [PATCH 0021/1102] Typo fix --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index d2404636..1ab25448 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -189,7 +189,7 @@ def address_compare(x, y): else: return 0 else: - return (1 if shared.config.getboolean(x, 'enabled') else '-1') + return (1 if shared.config.getboolean(x, 'enabled') else -1) class MyForm(QtGui.QMainWindow): -- 2.45.1 From 9ab9984283f1062568785ecba422121ac570ab70 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:12:01 +0200 Subject: [PATCH 0022/1102] Order reverse Disabled addresses should go at the end, not at the beginning. --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1ab25448..32e6e103 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -189,7 +189,7 @@ def address_compare(x, y): else: return 0 else: - return (1 if shared.config.getboolean(x, 'enabled') else -1) + return (-1 if shared.config.getboolean(x, 'enabled') else 1) class MyForm(QtGui.QMainWindow): -- 2.45.1 From a961ad1d842ff567c4a8811ad73c4f564399aa60 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:15:23 +0200 Subject: [PATCH 0023/1102] Formatting --- src/bitmessageqt/__init__.py | 83 ++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 32e6e103..fd8d8e1e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -577,53 +577,54 @@ class MyForm(QtGui.QMainWindow): configSections = sorted(shared.config.sections(), cmp=address_compare) for addressInKeysFile in configSections: - if addressInKeysFile != 'bitmessagesettings': - isEnabled = shared.config.getboolean( - addressInKeysFile, 'enabled') - isChan = shared.safeConfigGetBoolean( - addressInKeysFile, 'chan') - isMaillinglist = shared.safeConfigGetBoolean( - addressInKeysFile, 'mailinglist') + if addressInKeysFile == 'bitmessagesettings': + continue + isEnabled = shared.config.getboolean( + addressInKeysFile, 'enabled') + isChan = shared.safeConfigGetBoolean( + addressInKeysFile, 'chan') + isMaillinglist = shared.safeConfigGetBoolean( + addressInKeysFile, 'mailinglist') - if tab == 'messages': - if isChan: - continue - elif tab == 'chan': - if not isChan: - continue + if tab == 'messages': + if isChan: + continue + elif tab == 'chan': + if not isChan: + continue - newItem = QtGui.QTreeWidgetItem(treeWidget) - newItem.setExpanded(True) - newItem.setIcon(0, avatarize(addressInKeysFile)) - newItem.setText(0, unicode( - shared.config.get(addressInKeysFile, 'label'), 'utf-8)') - + ' (' + addressInKeysFile + ')') - newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"]) - #set text color - if isEnabled: - if isMaillinglist: - brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) - else: - brush = QtGui.QBrush(QApplication.palette().text().color()) + newItem = QtGui.QTreeWidgetItem(treeWidget) + newItem.setExpanded(True) + newItem.setIcon(0, avatarize(addressInKeysFile)) + newItem.setText(0, unicode( + shared.config.get(addressInKeysFile, 'label'), 'utf-8)') + + ' (' + addressInKeysFile + ')') + newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"]) + #set text color + if isEnabled: + if isMaillinglist: + brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) else: - brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - brush.setStyle(QtCore.Qt.NoBrush) - newItem.setForeground(0, brush) + brush = QtGui.QBrush(QApplication.palette().text().color()) + else: + brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + brush.setStyle(QtCore.Qt.NoBrush) + newItem.setForeground(0, brush) - for folder in folders: - newSubItem = QtGui.QTreeWidgetItem(newItem) + for folder in folders: + newSubItem = QtGui.QTreeWidgetItem(newItem) - cnt = cntUnreadMsg.get(addressInKeysFile + folder, False) - if cnt: - unreadText = " (" + str(cnt) + ")" - font = QtGui.QFont() - font.setBold(True) - newSubItem.setFont(0, font) - else: - unreadText = "" + cnt = cntUnreadMsg.get(addressInKeysFile + folder, False) + if cnt: + unreadText = " (" + str(cnt) + ")" + font = QtGui.QFont() + font.setBold(True) + newSubItem.setFont(0, font) + else: + unreadText = "" - newSubItem.setText(0, _translate("MainWindow", folder) + unreadText) - newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder]) + newSubItem.setText(0, _translate("MainWindow", folder) + unreadText) + newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder]) def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) -- 2.45.1 From fd7ed893a7466c6753b4fc6ce896a3726e79e310 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:18:33 +0200 Subject: [PATCH 0024/1102] Collapse disabled accounts --- src/bitmessageqt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fd8d8e1e..cba78d68 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -608,6 +608,7 @@ class MyForm(QtGui.QMainWindow): brush = QtGui.QBrush(QApplication.palette().text().color()) else: brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + newItem.setExpanded(False) brush.setStyle(QtCore.Qt.NoBrush) newItem.setForeground(0, brush) -- 2.45.1 From 8043f1ae60ad70bc2b7e453fa70a631b2408fd51 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 1 Oct 2015 10:25:31 +0200 Subject: [PATCH 0025/1102] Address tree order sort case insensitive --- src/bitmessageqt/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cba78d68..47e41cbe 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -175,13 +175,13 @@ def address_compare(x, y): return 1 if shared.config.getboolean(x, 'enabled') == shared.config.getboolean(y, 'enabled'): if shared.config.get(x, 'label'): - x1 = shared.config.get(x, 'label') + x1 = shared.config.get(x, 'label').decode('utf-8').lower() else: - x1 = x + x1 = x.decode('utf-8').lower() if shared.config.get(y, 'label'): - y1 = shared.config.get(y, 'label') + y1 = shared.config.get(y, 'label').decode('utf-8').lower() else: - y1 = y + y1 = y.decode('utf-8').lower() if x1 > y1: return 1 elif x1 < y1: -- 2.45.1 From 9075f3f5e6e331b7c61964757f4ad542c4a558d0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 2 Oct 2015 15:04:16 +0200 Subject: [PATCH 0026/1102] OpenCL Fixes Still not fully working and hardcoded device number --- src/openclpow.py | 33 +++++++++++++++------------------ src/proofofwork.py | 9 +++++++-- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/openclpow.py b/src/openclpow.py index 65449b85..7ab4dba8 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -1,31 +1,28 @@ -import numpy +#!/usr/bin/env python2.7 from struct import pack, unpack import time import hashlib import random -import pyopencl as cl +import os -hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) ctx = False queue = False program = False try: - if (len(cl.get_platforms()) > 0): - ctx = cl.create_some_context() - queue = cl.CommandQueue(ctx) - - #f = open('/usr/src/PyBitmessage/src/kernel.cl', 'r') - import os - print "working directory: " + os.getcwd() -# time.sleep(5) - f = open('kernel.cl', 'r') - fstr = ''.join(f.readlines()) - program = cl.Program(ctx, fstr).build() + import numpy + import pyopencl as cl + hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) + if (len(cl.get_platforms()) > 0): + ctx = cl.create_some_context() + queue = cl.CommandQueue(ctx) + full_path = os.path.dirname(os.path.realpath(__file__)) + f = open(os.path.join(full_path, 'kernel.cl'), 'r') + fstr = ''.join(f.readlines()) + program = cl.Program(ctx, fstr).build(options="") except Exception as e: - print "opencl fail:" + str(e) -# time.sleep(5) - ctx = False + print "opencl fail:" + str(e) + ctx = False def has_opencl(): return (ctx != False) @@ -43,7 +40,7 @@ def do_opencl_pow(hash, target): 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, cl.get_platforms()[0].get_devices()[0]) + worksize = kernel.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, cl.get_platforms()[0].get_devices()[1]) kernel.set_arg(0, hash_buf) kernel.set_arg(1, dest_buf) diff --git a/src/proofofwork.py b/src/proofofwork.py index 85f79430..81f7e3df 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -73,7 +73,7 @@ def _doFastPoW(target, initialHash): return result[0], result[1] time.sleep(0.2) -def _doGPUPow(target, initialHash): +def _doGPUPoW(target, initialHash): print "GPU POW\n" nonce = openclpow.do_opencl_pow(initialHash.encode("hex"), target) trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) @@ -83,7 +83,12 @@ def _doGPUPow(target, initialHash): def run(target, initialHash): target = int(target) if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): - return _doGPUPow(target, initialHash) +# 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] + return _doGPUPoW(target, initialHash) elif frozen == "macosx_app" or not frozen: return _doFastPoW(target, initialHash) else: -- 2.45.1 From 3a294ac672154890b80562c096cc60d8daf5d648 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 2 Oct 2015 15:04:47 +0200 Subject: [PATCH 0027/1102] Fixes Some pages were initialised with incorrect number of parameters. --- src/bitmessageqt/migrationwizard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/migrationwizard.py b/src/bitmessageqt/migrationwizard.py index 945adefa..6e80f1dc 100644 --- a/src/bitmessageqt/migrationwizard.py +++ b/src/bitmessageqt/migrationwizard.py @@ -72,9 +72,9 @@ class Ui_MigrationWizard(QtGui.QWizard): page = MigrationWizardIntroPage() self.setPage(0, page) self.setStartId(0) - page = MigrationWizardAddressesPage() + page = MigrationWizardAddressesPage(addresses) self.setPage(1, page) - page = MigrationWizardGPUPage(addresses) + page = MigrationWizardGPUPage() self.setPage(2, page) page = MigrationWizardConclusionPage() self.setPage(10, page) -- 2.45.1 From 83a069d1f627afc0cf2c8c81e3a8d6b2ae500928 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 2 Oct 2015 15:05:47 +0200 Subject: [PATCH 0028/1102] Migration Wizard - Not fully working yet - show this wizard and connection confirmation dialog before showing the main window, and don't open main window until these two have finished or were canceled --- src/bitmessageqt/__init__.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 47e41cbe..c95d7579 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1627,6 +1627,13 @@ class MyForm(QtGui.QMainWindow): 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) @@ -4148,12 +4155,20 @@ def run(): app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() - 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 + + try: + if shared.config.get('bitmessagesettings', 'mailchuck') < 1: + myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) + except: + myapp.showMigrationWizard(0) + + # only show after wizards and connect dialogs have completed + if not shared.config.getboolean('bitmessagesettings', 'startintray'): + myapp.show() + sys.exit(app.exec_()) -- 2.45.1 From 83109796fe4b2846fe580468d0e334b21fb363d2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 2 Oct 2015 22:24:46 +0200 Subject: [PATCH 0029/1102] Address Tree updates The Address tree now is sorted and updates when number of unread messages changes. --- src/bitmessageqt/__init__.py | 279 +++++++++++---------------------- src/bitmessageqt/foldertree.py | 133 ++++++++++++++++ src/bitmessageqt/utils.py | 104 ++++++++++++ 3 files changed, 328 insertions(+), 188 deletions(-) create mode 100644 src/bitmessageqt/foldertree.py create mode 100644 src/bitmessageqt/utils.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c95d7579..76acb328 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -6,6 +6,21 @@ try: except ImportError: MessagingMenu = None +try: + 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 + from addresses import * import shared from bitmessageui import * @@ -13,6 +28,7 @@ from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newaddresswizard import * from migrationwizard import * +from foldertree import * from addaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * @@ -38,125 +54,12 @@ import subprocess import datetime from helper_sql import * import l10n - -try: - 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 +from utils import * +from collections import OrderedDict def _translate(context, text): return QtGui.QApplication.translate(context, text) - -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 = shared.config.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 = 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() @@ -168,29 +71,6 @@ def change_translation(locale): qtranslator.load(translationpath) QtGui.QApplication.installTranslator(qtranslator) -def address_compare(x, y): - if x == "bitmessagesettings": - return -1 - elif y == "bitmessagesettings": - return 1 - if shared.config.getboolean(x, 'enabled') == shared.config.getboolean(y, 'enabled'): - if shared.config.get(x, 'label'): - x1 = shared.config.get(x, 'label').decode('utf-8').lower() - else: - x1 = x.decode('utf-8').lower() - if shared.config.get(y, 'label'): - y1 = shared.config.get(y, 'label').decode('utf-8').lower() - else: - y1 = y.decode('utf-8').lower() - if x1 > y1: - return 1 - elif x1 < y1: - return -1 - else: - return 0 - else: - return (-1 if shared.config.getboolean(x, 'enabled') else 1) - class MyForm(QtGui.QMainWindow): # sound type constants @@ -566,25 +446,21 @@ class MyForm(QtGui.QMainWindow): elif tab == 'chan': treeWidget = self.ui.treeWidgetChans - treeWidget.clear() + #treeWidget.clear() - # get number of (unread) messages - cntUnreadMsg = {} - 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 - cntUnreadMsg[toaddress + folder] = cnt - - configSections = sorted(shared.config.sections(), cmp=address_compare) - for addressInKeysFile in configSections: - if addressInKeysFile == 'bitmessagesettings': + # init dictionary + db = {} + enabled = {} + + for toAddress in shared.config.sections(): + if toAddress == 'bitmessagesettings': continue isEnabled = shared.config.getboolean( - addressInKeysFile, 'enabled') + toAddress, 'enabled') isChan = shared.safeConfigGetBoolean( - addressInKeysFile, 'chan') + toAddress, 'chan') isMaillinglist = shared.safeConfigGetBoolean( - addressInKeysFile, 'mailinglist') + toAddress, 'mailinglist') if tab == 'messages': if isChan: @@ -593,39 +469,65 @@ class MyForm(QtGui.QMainWindow): if not isChan: continue - newItem = QtGui.QTreeWidgetItem(treeWidget) - newItem.setExpanded(True) - newItem.setIcon(0, avatarize(addressInKeysFile)) - newItem.setText(0, unicode( - shared.config.get(addressInKeysFile, 'label'), 'utf-8)') - + ' (' + addressInKeysFile + ')') - newItem.setData(0, Qt.UserRole, [str(addressInKeysFile), "inbox"]) - #set text color - if isEnabled: - if isMaillinglist: - brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) - else: - brush = QtGui.QBrush(QApplication.palette().text().color()) - else: - brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - newItem.setExpanded(False) - brush.setStyle(QtCore.Qt.NoBrush) - newItem.setForeground(0, brush) - + db[toAddress] = {} for folder in folders: - newSubItem = QtGui.QTreeWidgetItem(newItem) + db[toAddress][folder] = 0 + + enabled[toAddress] = isEnabled - cnt = cntUnreadMsg.get(addressInKeysFile + folder, False) - if cnt: - unreadText = " (" + str(cnt) + ")" - font = QtGui.QFont() - font.setBold(True) - newSubItem.setFont(0, font) - else: - unreadText = "" + # get number of (unread) messages + 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 + if toaddress in db and folder in db[toaddress]: + db[toaddress][folder] = cnt + + if treeWidget.isSortingEnabled(): + treeWidget.setSortingEnabled(False) + + widgets = {} + for i in range (0, treeWidget.topLevelItemCount()): + widget = treeWidget.topLevelItem(i) + toAddress = widget.address + + if not toAddress in db: + treeWidget.takeTopLevelItem(i) + i -= 1 + continue + unread = 0 + for j in range (0, widget.childCount()): + subwidget = widget.child(j) + try: + subwidget.setUnreadCount(db[toAddress][subwidget.folderName]) + unread += db[toAddress][subwidget.folderName] + db[toAddress].pop(subwidget.folderName, None) + except: + widget.takeChild(i) + j -= 1 - newSubItem.setText(0, _translate("MainWindow", folder) + unreadText) - newSubItem.setData(0, Qt.UserRole, [str(addressInKeysFile), folder]) + # add missing folders + if len(db[toAddress]) > 0: + i = 0 + for f, c in db[toAddress].iteritems(): + print "adding %s, %i" % (f, c) + subwidget = Ui_FolderWidget(widget, i, toAddress, f, c) + i += 1 + widget.setUnreadCount(unread) + db.pop(toAddress, None) + + i = 0 + for toAddress in db: + widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]) + j = 0 + unread = 0 + for folder in folders: + subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]) + unread += db[toAddress][folder] + j += 1 + widget.setUnreadCount(unread) + i += 1 + + treeWidget.setSortingEnabled(True) def __init__(self, parent=None): QtGui.QWidget.__init__(self, parent) @@ -1851,6 +1753,12 @@ class MyForm(QtGui.QMainWindow): def changedInboxUnread(self): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) + if self.ui.tabWidget.currentIndex() == 0: + self.rerenderTabTreeMessages() + elif self.ui.tabWidget.currentIndex() == 2: + self.rerenderTabTreeSubscriptions() + elif self.ui.tabWidget.currentIndex() == 3: + self.rerenderTabTreeChans() def findInboxUnreadCount(self): queryreturn = sqlQuery('''SELECT count(*) from inbox WHERE folder='inbox' and read=0''') @@ -3615,12 +3523,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) self.changedInboxUnread() -# if self.ui.tabWidget.currentIndex() == 0: -# self.rerenderTabTreeMessages() -# elif self.ui.tabWidget.currentIndex() == 2: -# self.rerenderTabTreeSubscriptions() -# elif self.ui.tabWidget.currentIndex() == 3: -# self.rerenderTabTreeChans() + else: data = self.getCurrentMessageId() if data != False: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py new file mode 100644 index 00000000..ca90ad60 --- /dev/null +++ b/src/bitmessageqt/foldertree.py @@ -0,0 +1,133 @@ +from PyQt4 import QtCore, QtGui + +from utils import * +import shared + +class Ui_FolderWidget(QtGui.QTreeWidgetItem): + folderWeight = {"inbox": 1, "sent": 2, "trash": 3} + def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0): + super(QtGui.QTreeWidgetItem, self).__init__() + self.address = address + self.folderName = folderName + self.unreadCount = unreadCount + parent.insertChild(pos, self) + self.updateText() + + def setAddress(self, address): + self.address = str(address) + self.updateText() + + def setUnreadCount(self, cnt): + self.unreadCount = int(cnt) + self.updateText() + + def setFolderName(self, fname): + self.folderName = str(fname) + self.updateText() + + def updateText(self): + text = QtGui.QApplication.translate("MainWindow", self.folderName) + font = QtGui.QFont() + if self.unreadCount > 0: + text += " (" + str(self.unreadCount) + ")" + font.setBold(True) + else: + font.setBold(False) + self.setFont(0, font) + self.setText(0, text) + self.setToolTip(0, text) + self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName]) + + # 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 = 4 + if other.folderName in self.folderWeight: + y = self.folderWeight[other.folderName] + else: + y = 4 + + if x == y: + return self.folderName > other.folderName + else: + return x > y + + return super(QtGui.QTreeWidgetItem, self).__lt__(other) + + +class Ui_AddressWidget(QtGui.QTreeWidgetItem): + def __init__(self, parent, pos = 0, address = "", unreadCount = 0): + super(QtGui.QTreeWidgetItem, self).__init__() + self.address = address + self.unreadCount = unreadCount + parent.insertTopLevelItem(pos, self) + # only set default when creating + #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + self.setExpanded(shared.safeConfigGetBoolean(self.address, 'enabled')) + self.updateText() + + def setAddress(self, address): + self.address = str(address) + self.updateText() + + def setUnreadCount(self, cnt): + self.unreadCount = int(cnt) + self.updateText() + + def updateText(self): + text = QtGui.QApplication.translate("MainWindow", + unicode(shared.config.get(self.address, 'label'), 'utf-8)') + + ' (' + self.address + ')') + + font = QtGui.QFont() + if self.unreadCount > 0: + # only show message count if the child doesn't show + if not self.isExpanded(): + text += " (" + str(self.unreadCount) + ")" + font.setBold(True) + else: + font.setBold(False) + self.setFont(0, font) + + #set text color + if shared.safeConfigGetBoolean(self.address, 'enabled'): + if shared.safeConfigGetBoolean(self.address, 'mailinglist'): + brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) + else: + brush = QtGui.QBrush(QtGui.QApplication.palette().text().color()) + #self.setExpanded(True) + else: + brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + #self.setExpanded(False) + brush.setStyle(QtCore.Qt.NoBrush) + self.setForeground(0, brush) + + self.setIcon(0, avatarize(self.address)) + self.setText(0, text) + self.setToolTip(0, text) + self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) + + def setExpanded(self, expand): + super(Ui_AddressWidget, self).setExpanded(expand) + self.updateText() + + # label (or address) alphabetically, disabled at the end + def __lt__(self, other): + if (isinstance(other, Ui_AddressWidget)): + if shared.config.getboolean(self.address, 'enabled') == shared.config.getboolean(other.address, 'enabled'): + if shared.config.get(self.address, 'label'): + x = shared.config.get(self.address, 'label').decode('utf-8').lower() + else: + x = self.address.decode('utf-8').lower() + if shared.config.get(other.address, 'label'): + y = shared.config.get(other.address, 'label').decode('utf-8').lower() + else: + y = other.address.decode('utf-8').lower() + return y < x +# else: + return (False if shared.config.getboolean(self.address, 'enabled') else True) + + return super(QtGui.QTreeWidgetItem, self).__lt__(other) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py new file mode 100644 index 00000000..af58fd37 --- /dev/null +++ b/src/bitmessageqt/utils.py @@ -0,0 +1,104 @@ +from PyQt4 import QtGui +import hashlib +import os +import shared +from addresses import addBMIfNotPresent + +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 = shared.config.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 = 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) -- 2.45.1 From 033be9b5bf30f416d5700a651ed576d31545d97f Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 3 Oct 2015 01:17:47 +0200 Subject: [PATCH 0030/1102] Email Gateway UI implementation First steps, only a tiny part works --- src/bitmessageqt/__init__.py | 47 ++++++++++++++++--------- src/bitmessageqt/account.py | 63 ++++++++++++++++++++++++++++++++++ src/bitmessageqt/foldertree.py | 4 +-- 3 files changed, 96 insertions(+), 18 deletions(-) create mode 100644 src/bitmessageqt/account.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 76acb328..187b0192 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -56,6 +56,7 @@ from helper_sql import * import l10n from utils import * from collections import OrderedDict +from account import * def _translate(context, text): return QtGui.QApplication.translate(context, text) @@ -1004,9 +1005,13 @@ class MyForm(QtGui.QMainWindow): font = QFont() font.setBold(True) queryreturn = sqlQuery(sqlStatement, account, folder, what) + acct = None for row in queryreturn: msgid, toAddress, fromAddress, subject, received, read = row + if acct is None: + acct = accountClass(toAddress) subject = shared.fixPotentiallyInvalidUTF8Data(subject) + acct.parseMessage(toAddress, fromAddress, subject, "") try: if toAddress == self.str_broadcast_subscribers: toLabel = self.str_broadcast_subscribers @@ -1018,6 +1023,8 @@ class MyForm(QtGui.QMainWindow): toLabel = toAddress fromLabel = '' + if type(acct) == MailchuckAccount: + fromLabel = acct.fromAddress if shared.config.has_section(fromAddress): fromLabel = shared.config.get(fromAddress, 'label') @@ -1066,8 +1073,8 @@ class MyForm(QtGui.QMainWindow): from_item.setIcon(avatarize(fromAddress)) tableWidget.setItem(0, 1, from_item) # subject - subject_item = QtGui.QTableWidgetItem(unicode(subject, 'utf-8')) - subject_item.setToolTip(unicode(subject, 'utf-8')) + subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) + subject_item.setToolTip(unicode(acct.subject, 'utf-8')) subject_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -1751,11 +1758,12 @@ class MyForm(QtGui.QMainWindow): def drawTrayIcon(self, iconFileName, inboxUnreadCount): self.tray.setIcon(self.calcTrayIcon(iconFileName, inboxUnreadCount)) - def changedInboxUnread(self): + def changedInboxUnread(self, row = None): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) - if self.ui.tabWidget.currentIndex() == 0: - self.rerenderTabTreeMessages() - elif self.ui.tabWidget.currentIndex() == 2: + self.rerenderTabTreeMessages() + if not row is None: + row[1], row[6] + if self.ui.tabWidget.currentIndex() == 2: self.rerenderTabTreeSubscriptions() elif self.ui.tabWidget.currentIndex() == 3: self.rerenderTabTreeChans() @@ -2281,6 +2289,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f font = QFont() font.setBold(True) self.ui.tableWidgetInbox.setSortingEnabled(False) + account = accountClass(toAddress) + account.parseMessage(toAddress, fromAddress, subject, message) newItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) newItem.setToolTip(unicode(toLabel, 'utf-8')) newItem.setFont(font) @@ -2293,7 +2303,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setIcon(avatarize(toAddress)) self.ui.tableWidgetInbox.setItem(0, 0, newItem) - if fromLabel == '': + if type(account) is MailchuckAccount: + newItem = QtGui.QTableWidgetItem(unicode(account.fromAddress, 'utf-8')) + newItem.setToolTip(unicode(account.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(account.fromAddress, 'utf-8'), self.SOUND_UNKNOWN, None) + elif fromLabel == '': newItem = QtGui.QTableWidgetItem(unicode(fromAddress, 'utf-8')) newItem.setToolTip(unicode(fromAddress, 'utf-8')) if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): @@ -2308,7 +2323,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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.setToolTip(unicode(account.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) @@ -3272,25 +3287,25 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Group of functions for the Your Identities dialog box def getCurrentAccount(self): - treeWidget = self.getCurrentTreeWidget() + #treeWidget = self.getCurrentTreeWidget() + treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() if currentItem: - accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() - account = accountFolder[0] - return str(account) + account = currentItem.address + return account else: # TODO need debug msg? return False def getCurrentFolder(self): - treeWidget = self.getCurrentTreeWidget() + #treeWidget = self.getCurrentTreeWidget() + treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() if currentItem: - accountFolder = currentItem.data(0, Qt.UserRole).toPyObject() - folder = accountFolder[1] - return str(folder) + account = currentItem.folderName + return account else: # TODO need debug msg? return False diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py new file mode 100644 index 00000000..b8171bc6 --- /dev/null +++ b/src/bitmessageqt/account.py @@ -0,0 +1,63 @@ +from PyQt4 import QtCore, QtGui + +import shared +import re +import sys + +def accountClass(address): + if not shared.config.has_section(address): + return None + try: + gateway = shared.config.get(address, "gateway") + if (gateway == "mailchuck"): + return MailchuckAccount(address) + else: + return GatewayAccount(address) + except: + return BMAccount(address) + +class BMAccount(object): + def __init__(self, address): + self.address = address + + def parseMessage(self, toAddress, fromAddress, subject, message): + self.toAddress = toAddress + self.fromAddress = fromAddress + self.subject = subject + self.message = message + +class GatewayAccount(BMAccount): + def __init__(self, address): + super(BMAccount, self).__init__(address) + + def parseMessage(self, toAddress, fromAddress, subject, message): + super(BMAccount, self).parseMessage(toAddress, fromAddress, subject, message) + +class MailchuckAccount(GatewayAccount): + registrationAddress = "BM-2cVYYrhaY5Gbi3KqrX9Eae2NRNrkfrhCSA" + unregistrationAddress = "BM-2cVMAHTRjZHCTPMue75XBK5Tco175DtJ9J" + relayAddress = "BM-2cWim8aZwUNqxzjMxstnUMtVEUQJeezstf" + regExpIncoming = re.compile("(.*)MAILCHUCK-FROM::(\S+) \| (.*)") + regExpOutgoing = re.compile("(\S+) (.*)") + def __init__(self, address): + super(GatewayAccount, self).__init__(address) + + def parseMessage(self, toAddress, fromAddress, subject, message): + super(GatewayAccount, 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.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.toAddress = matches.group(1) \ No newline at end of file diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index ca90ad60..78524187 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -36,7 +36,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem): self.setFont(0, font) self.setText(0, text) self.setToolTip(0, text) - self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName]) + # self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName]) # inbox, sent, thrash first, rest alphabetically def __lt__(self, other): @@ -108,7 +108,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): self.setIcon(0, avatarize(self.address)) self.setText(0, text) self.setToolTip(0, text) - self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) +# self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) def setExpanded(self, expand): super(Ui_AddressWidget, self).setExpanded(expand) -- 2.45.1 From b4fa5d4abf3355de58ffc9f528c49629acc6a53b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 3 Oct 2015 12:12:18 +0200 Subject: [PATCH 0031/1102] Gateway update and sort fix - shows gateway parser results more accurately - gateway class assigned dynamically - inbox sort order is aware of what you click on and defaults to ascending --- src/bitmessageqt/__init__.py | 228 +++++++++++---------------------- src/bitmessageqt/account.py | 46 +++++-- src/bitmessageqt/foldertree.py | 15 ++- 3 files changed, 123 insertions(+), 166 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 187b0192..9507ea6b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -447,7 +447,9 @@ class MyForm(QtGui.QMainWindow): elif tab == 'chan': treeWidget = self.ui.treeWidgetChans - #treeWidget.clear() + # sort ascending when creating + if treeWidget.topLevelItemCount() == 0: + treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) # init dictionary db = {} @@ -860,6 +862,10 @@ class MyForm(QtGui.QMainWindow): else: where = "toaddress || fromaddress || subject || message" + tableWidget.setColumnHidden(0, False) + tableWidget.setColumnHidden(1, True) + tableWidget.setSortingEnabled(False) + sqlStatement = ''' SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime FROM sent WHERE fromaddress=? AND folder="sent" AND %s LIKE ? @@ -868,60 +874,34 @@ class MyForm(QtGui.QMainWindow): while tableWidget.rowCount() > 0: tableWidget.removeRow(0) - + acct = None queryreturn = sqlQuery(sqlStatement, account, what) for row in queryreturn: toAddress, fromAddress, subject, status, ackdata, lastactiontime = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) - - if shared.config.has_section(fromAddress): - fromLabel = shared.config.get(fromAddress, 'label') - else: - fromLabel = fromAddress - - 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 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 + if acct is None: + acct = accountClass(fromAddress) + acct.parseMessage(toAddress, fromAddress, subject, "") tableWidget.insertRow(0) - toAddressItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) - toAddressItem.setToolTip(unicode(toLabel, 'utf-8')) + toAddressItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8')) toAddressItem.setIcon(avatarize(toAddress)) toAddressItem.setData(Qt.UserRole, str(toAddress)) toAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 0, toAddressItem) - if fromLabel == '': - fromLabel = fromAddress - fromAddressItem = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) - fromAddressItem.setToolTip(unicode(fromLabel, 'utf-8')) + fromAddressItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) fromAddressItem.setIcon(avatarize(fromAddress)) fromAddressItem.setData(Qt.UserRole, str(fromAddress)) fromAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 1, fromAddressItem) - subjectItem = QtGui.QTableWidgetItem(unicode(subject, 'utf-8')) - subjectItem.setToolTip(unicode(subject, 'utf-8')) + subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) + subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) subjectItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 2, subjectItem) @@ -972,7 +952,9 @@ class MyForm(QtGui.QMainWindow): newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 3, newItem) - tableWidget.sortItems(3, Qt.DescendingOrder) + + tableWidget.setSortingEnabled(False) + tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent # Load messages from database file @@ -993,62 +975,43 @@ class MyForm(QtGui.QMainWindow): else: where = "toaddress || fromaddress || subject || message" - sqlStatement = ''' - SELECT msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE toaddress=? AND folder=? AND %s LIKE ? - ORDER BY received - ''' % (where) + if folder != False: + sqlStatement = ''' + SELECT folder, msgid, toaddress, fromaddress, subject, received, read + FROM inbox WHERE toaddress=? AND folder=? AND %s LIKE ? + ORDER BY received + ''' % (where) + queryreturn = sqlQuery(sqlStatement, account, folder, what) + else: + sqlStatement = ''' + SELECT folder, msgid, toaddress, fromaddress, subject, received, read + FROM inbox WHERE toaddress=? AND folder != "trash" AND %s LIKE ? + ORDER BY received + ''' % (where) + queryreturn = sqlQuery(sqlStatement, account, what) while tableWidget.rowCount() > 0: tableWidget.removeRow(0) + tableWidget.setColumnHidden(0, True) + tableWidget.setColumnHidden(1, False) + tableWidget.setSortingEnabled(False) + font = QFont() font.setBold(True) - queryreturn = sqlQuery(sqlStatement, account, folder, what) acct = None for row in queryreturn: - msgid, toAddress, fromAddress, subject, received, read = row + msgfolder, msgid, toAddress, fromAddress, subject, received, read = row if acct is None: acct = accountClass(toAddress) subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct.parseMessage(toAddress, fromAddress, 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 - - fromLabel = '' - if type(acct) == MailchuckAccount: - fromLabel = acct.fromAddress - 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 tableWidget.insertRow(0) # to - to_item = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) - to_item.setToolTip(unicode(toLabel, 'utf-8')) + to_item = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + to_item.setToolTip(unicode(acct.toLabel, 'utf-8')) to_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -1061,8 +1024,8 @@ class MyForm(QtGui.QMainWindow): to_item.setIcon(avatarize(toAddress)) tableWidget.setItem(0, 0, to_item) # from - from_item = QtGui.QTableWidgetItem(unicode(fromLabel, 'utf-8')) - from_item.setToolTip(unicode(fromLabel, 'utf-8')) + from_item = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + from_item.setToolTip(unicode(acct.fromLabel, 'utf-8')) from_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -1091,7 +1054,8 @@ class MyForm(QtGui.QMainWindow): time_item.setFont(font) tableWidget.setItem(0, 3, time_item) - tableWidget.sortItems(3, Qt.DescendingOrder) + tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) + tableWidget.setSortingEnabled(True) tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent # create application indicator @@ -1761,8 +1725,8 @@ class MyForm(QtGui.QMainWindow): def changedInboxUnread(self, row = None): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) self.rerenderTabTreeMessages() - if not row is None: - row[1], row[6] +# if not row is None: +# row[1], row[6] if self.ui.tabWidget.currentIndex() == 2: self.rerenderTabTreeSubscriptions() elif self.ui.tabWidget.currentIndex() == 3: @@ -2216,35 +2180,23 @@ more work your computer must do to send the message. A Time-To-Live of four or f return subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) - try: - fromLabel = shared.config.get(fromAddress, 'label') - except: - fromLabel = '' - if fromLabel == '': - fromLabel = fromAddress + acct = accountClass(fromAddress) + acct.parseMessage(toAddress, fromAddress, subject, message) self.ui.tableWidgetInbox.setSortingEnabled(False) self.ui.tableWidgetInbox.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 = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(toAddress)) newItem.setIcon(avatarize(toAddress)) self.ui.tableWidgetInbox.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 = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(fromAddress)) 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 = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) + newItem.setToolTip(unicode(acct.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.tableWidgetInbox.setItem(0, 2, newItem) # newItem = QtGui.QTableWidgetItem('Doing work necessary to send @@ -2259,40 +2211,17 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetInbox.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): - if self.getCurrentFolder() != "inbox" or self.getCurrentAccount() != toAddress: + if (self.getCurrentFolder() != "inbox" and self.getCurrentFolder() != False) or self.getCurrentAccount() != toAddress: return subject = shared.fixPotentiallyInvalidUTF8Data(subject) - fromLabel = '' - queryreturn = sqlQuery( - '''select label from addressbook where address=?''', fromAddress) - if queryreturn != []: - for row in queryreturn: - fromLabel, = row - else: - # 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 - - 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 + acct = accountClass(toAddress) + acct.parseMessage(toAddress, fromAddress, subject, message) font = QFont() font.setBold(True) self.ui.tableWidgetInbox.setSortingEnabled(False) - account = accountClass(toAddress) - account.parseMessage(toAddress, fromAddress, subject, message) - newItem = QtGui.QTableWidgetItem(unicode(toLabel, 'utf-8')) - newItem.setToolTip(unicode(toLabel, 'utf-8')) + newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setFont(font) newItem.setData(Qt.UserRole, str(toAddress)) if shared.safeConfigGetBoolean(str(toAddress), 'mailinglist'): @@ -2303,27 +2232,16 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setIcon(avatarize(toAddress)) self.ui.tableWidgetInbox.setItem(0, 0, newItem) - if type(account) is MailchuckAccount: - newItem = QtGui.QTableWidgetItem(unicode(account.fromAddress, 'utf-8')) - newItem.setToolTip(unicode(account.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(account.fromAddress, 'utf-8'), self.SOUND_UNKNOWN, None) - elif 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 = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.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(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) 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(account.subject, 'utf-8)')) + newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) + newItem.setToolTip(unicode(acct.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) @@ -2334,7 +2252,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setFont(font) self.ui.tableWidgetInbox.setItem(0, 3, newItem) self.ui.tableWidgetInbox.setSortingEnabled(True) - self.ubuntuMessagingMenuUpdate(True, newItem, toLabel) + self.ubuntuMessagingMenuUpdate(True, newItem, self.toLabel) def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) @@ -2955,11 +2873,14 @@ more work your computer must do to send the message. A Time-To-Live of four or f tableWidget = self.getCurrentMessagelist() if not tableWidget: return + unread = False while tableWidget.selectedIndexes() != []: currentRow = tableWidget.selectedIndexes()[0].row() inventoryHashToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) + if tableWidget.item(currentRow, 0).font().bold(): + unread = True self.ui.textEditInboxMessage.setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -2968,6 +2889,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f tableWidget.selectRow(currentRow) else: tableWidget.selectRow(currentRow - 1) + if unread: + changedInboxUnread() def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3303,9 +3226,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() - if currentItem: - account = currentItem.folderName - return account + if currentItem and hasattr(currentItem, 'folderName'): + return currentItem.folderName else: # TODO need debug msg? return False @@ -3518,7 +3440,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f refresh = False for row in queryreturn: message, read = row - if folder == 'inbox' and read == 0: + if folder != 'sent' and read == 0: markread = sqlQuery( '''UPDATE inbox SET read = 1 WHERE msgid = ?''', msgid) refresh = True diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index b8171bc6..0ff0fa23 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -3,30 +3,58 @@ from PyQt4 import QtCore, QtGui import shared import re import sys +import inspect +from helper_sql import * def accountClass(address): if not shared.config.has_section(address): return None try: gateway = shared.config.get(address, "gateway") - if (gateway == "mailchuck"): - return MailchuckAccount(address) - else: - return GatewayAccount(address) + 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: - return BMAccount(address) + pass + # no gateway + return BMAccount(address) class BMAccount(object): - def __init__(self, address): + def __init__(self, address = None): self.address = address + def getLabel(self, address = None): + if address is None: + address = self.address + label = address + if shared.config.has_section(address): + label = shared.config.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 self.subject = subject self.message = message + self.fromLabel = self.getLabel(fromAddress) + self.toLabel = self.getLabel(toAddress) class GatewayAccount(BMAccount): + gatewayName = None def __init__(self, address): super(BMAccount, self).__init__(address) @@ -34,6 +62,8 @@ class GatewayAccount(BMAccount): super(BMAccount, 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" @@ -53,11 +83,11 @@ class MailchuckAccount(GatewayAccount): if not matches.group(3) is None: self.subject += matches.group(3) if not matches.group(2) is None: - self.fromAddress = matches.group(2) + self.fromLabel = 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.toAddress = matches.group(1) \ No newline at end of file + self.toLabel = matches.group(1) \ No newline at end of file diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 78524187..41824b91 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -49,11 +49,13 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem): y = self.folderWeight[other.folderName] else: y = 4 - + reverse = False + if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: + reverse = True if x == y: - return self.folderName > other.folderName + return self.folderName < other.folderName else: - return x > y + return (x >= y if reverse else x < y) return super(QtGui.QTreeWidgetItem, self).__lt__(other) @@ -117,6 +119,9 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): # 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 shared.config.getboolean(self.address, 'enabled') == shared.config.getboolean(other.address, 'enabled'): if shared.config.get(self.address, 'label'): x = shared.config.get(self.address, 'label').decode('utf-8').lower() @@ -126,8 +131,8 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): y = shared.config.get(other.address, 'label').decode('utf-8').lower() else: y = other.address.decode('utf-8').lower() - return y < x + return x < y # else: - return (False if shared.config.getboolean(self.address, 'enabled') else True) + return (not reverse if shared.config.getboolean(self.address, 'enabled') else reverse) return super(QtGui.QTreeWidgetItem, self).__lt__(other) -- 2.45.1 From 2bc9c7ff4c83013cd2b7b5109dc7ff604759f2a1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 3 Oct 2015 17:24:21 +0200 Subject: [PATCH 0032/1102] Email gateway integration Sending/receiving from the send tab, reply from inbox and registration/unregistration context menu. --- src/bitmessageqt/__init__.py | 89 +++++++++++++++--- src/bitmessageqt/account.py | 52 +++++++++- src/bitmessageqt/emailgateway.py | 64 +++++++++++++ src/bitmessageqt/emailgateway.ui | 157 +++++++++++++++++++++++++++++++ 4 files changed, 347 insertions(+), 15 deletions(-) create mode 100644 src/bitmessageqt/emailgateway.py create mode 100644 src/bitmessageqt/emailgateway.ui diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9507ea6b..06ddb900 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -34,6 +34,7 @@ from newsubscriptiondialog import * from regenerateaddresses import * from newchandialog import * from specialaddressbehavior import * +from emailgateway import * from settings import * from about import * from help import * @@ -213,6 +214,10 @@ class MyForm(QtGui.QMainWindow): _translate( "MainWindow", "Special address behavior..."), self.on_action_SpecialAddressBehaviorDialog) + self.actionEmailGateway = self.ui.addressContextMenuToolbarYourIdentities.addAction( + _translate( + "MainWindow", "Email gateway"), + self.on_action_EmailGatewayDialog) self.ui.treeWidgetYourIdentities.setContextMenuPolicy( QtCore.Qt.CustomContextMenu) @@ -230,6 +235,7 @@ class MyForm(QtGui.QMainWindow): self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities) self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities) self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) + self.popMenuYourIdentities.addAction(self.actionEmailGateway) def init_chan_popup_menu(self, connectSignal=True): # Popup menu for the Channels tab @@ -902,6 +908,7 @@ class MyForm(QtGui.QMainWindow): subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) + subjectItem.setData(Qt.UserRole, str(subject)) subjectItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 2, subjectItem) @@ -1038,6 +1045,7 @@ class MyForm(QtGui.QMainWindow): # subject subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) subject_item.setToolTip(unicode(acct.subject, 'utf-8')) + subject_item.setData(Qt.UserRole, str(subject)) subject_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -1968,6 +1976,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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) toAddressesList = [s.strip() @@ -1976,6 +1986,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f 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 != '': + if toAddress.find("@") >= 0 and isinstance(acct, GatewayAccount): + acct.createMessage(toAddress, fromAddress, subject, message) + subject = acct.subject + toAddress = acct.toAddress + print "Subject: %s" % (subject) + print "address: %s" % (toAddress) status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if status != 'success': @@ -2197,6 +2213,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetInbox.setItem(0, 1, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) newItem.setToolTip(unicode(acct.subject, 'utf-8)')) + newItem.setData(Qt.UserRole, str(subject)) + #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.tableWidgetInbox.setItem(0, 2, newItem) # newItem = QtGui.QTableWidgetItem('Doing work necessary to send @@ -2242,6 +2260,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.tableWidgetInbox.setItem(0, 1, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) newItem.setToolTip(unicode(acct.subject, 'utf-8)')) + newItem.setData(Qt.UserRole, str(subject)) + #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) @@ -2631,6 +2651,30 @@ more work your computer must do to send the message. A Time-To-Live of four or f shared.writeKeysFile() self.rerenderInboxToLabels() + def on_action_EmailGatewayDialog(self): + self.dialog = EmailGatewayDialog(self) + # For Modal dialogs + if self.dialog.exec_(): + addressAtCurrentRow = self.getCurrentAccount() + acct = accountClass(addressAtCurrentRow) + if isinstance(acct, GatewayAccount) and self.dialog.ui.radioButtonUnregister.isChecked(): + print "unregister" + acct.unregister() + shared.config.remove_option(addressAtCurrentRow, 'gateway') + shared.writeKeysFile() + elif (not isinstance(acct, GatewayAccount)) and self.dialog.ui.radioButtonRegister.isChecked(): + print "register" + email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) + acct = MailchuckAccount(addressAtCurrentRow) + acct.register(email) + shared.config.set(addressAtCurrentRow, 'label', email) + shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') + shared.writeKeysFile() + else: + print "well nothing" +# shared.writeKeysFile() +# self.rerenderInboxToLabels() + def click_NewAddressDialog(self): addresses = [] configSections = shared.config.sections() @@ -2638,11 +2682,11 @@ more work your computer must do to send the message. A Time-To-Live of four or f if addressInKeysFile == 'bitmessagesettings': continue addresses.append(addressInKeysFile) - self.dialog = Ui_NewAddressWizard(addresses) - self.dialog.exec_() +# self.dialog = Ui_NewAddressWizard(addresses) +# self.dialog.exec_() # print "Name: " + self.dialog.field("name").toString() # print "Email: " + self.dialog.field("email").toString() - return +# return self.dialog = NewAddressDialog(self) # For Modal dialogs if self.dialog.exec_(): @@ -2789,6 +2833,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f currentInboxRow = tableWidget.currentRow() toAddressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 0).data(Qt.UserRole).toPyObject()) + acct = accountClass(toAddressAtCurrentInboxRow) fromAddressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 1).data(Qt.UserRole).toPyObject()) msgid = str(tableWidget.item( @@ -2798,6 +2843,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f if queryreturn != []: for row in queryreturn: messageAtCurrentInboxRow, = row + acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, str(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject()), messageAtCurrentInboxRow) if toAddressAtCurrentInboxRow == self.str_broadcast_subscribers: #TODO what does this if?.. a = a @@ -2810,7 +2856,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) - self.ui.lineEditTo.setText(str(fromAddressAtCurrentInboxRow)) + self.ui.lineEditTo.setText(str(acct.fromLabel)) # 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 shared.config.has_section(toAddressAtCurrentInboxRow): @@ -2827,12 +2873,10 @@ more work your computer must do to send the message. A Time-To-Live of four or f quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8')) self.ui.textEditMessage.setText(quotedText) - if tableWidget.item(currentInboxRow, 2).text()[0:3] in ['Re:', 'RE:']: - self.ui.lineEditSubject.setText( - tableWidget.item(currentInboxRow, 2).text()) + if acct.subject[0:3] in ['Re:', 'RE:']: + self.ui.lineEditSubject.setText(acct.subject) else: - self.ui.lineEditSubject.setText( - 'Re: ' + tableWidget.item(currentInboxRow, 2).text()) + self.ui.lineEditSubject.setText('Re: ' + acct.subject) self.ui.tabWidgetSend.setCurrentIndex(0) self.ui.tabWidget.setCurrentIndex(1) @@ -3774,6 +3818,23 @@ class SpecialAddressBehaviorDialog(QtGui.QDialog): QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) +class EmailGatewayDialog(QtGui.QDialog): + + def __init__(self, parent): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_EmailGatewayDialog() + self.ui.setupUi(self) + self.parent = parent + addressAtCurrentRow = parent.getCurrentAccount() + acct = accountClass(addressAtCurrentRow) +# if isinstance(acct, GatewayAccount): + label = shared.config.get(addressAtCurrentRow, 'label') + if label.find("@mailchuck.com") > -1: + self.ui.lineEditEmail.setText(label) + + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + class AddAddressDialog(QtGui.QDialog): def __init__(self, parent): @@ -4001,11 +4062,11 @@ def run(): if shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): myapp.showConnectDialog() # ask the user if we may connect - try: - if shared.config.get('bitmessagesettings', 'mailchuck') < 1: - myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) - except: - myapp.showMigrationWizard(0) +# try: +# if shared.config.get('bitmessagesettings', 'mailchuck') < 1: +# myapp.showMigrationWizard(shared.config.get('bitmessagesettings', 'mailchuck')) +# except: +# myapp.showMigrationWizard(0) # only show after wizards and connect dialogs have completed if not shared.config.getboolean('bitmessagesettings', 'startintray'): diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 0ff0fa23..05613e47 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -5,6 +5,9 @@ import re import sys import inspect from helper_sql import * +from addresses import decodeAddress +from pyelliptic.openssl import OpenSSL +import time def accountClass(address): if not shared.config.has_section(address): @@ -57,6 +60,31 @@ class GatewayAccount(BMAccount): gatewayName = None def __init__(self, address): super(BMAccount, self).__init__(address) + + def send(self): + status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.toAddress) + ackdata = OpenSSL.rand(32) + 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 + shared.config.getint('bitmessagesettings', 'ttl') + ) + + shared.workerQueue.put(('sendmessage', self.toAddress)) def parseMessage(self, toAddress, fromAddress, subject, message): super(BMAccount, self).parseMessage(toAddress, fromAddress, subject, message) @@ -71,6 +99,26 @@ class MailchuckAccount(GatewayAccount): regExpOutgoing = re.compile("(\S+) (.*)") def __init__(self, address): super(GatewayAccount, self).__init__(address) + + 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 parseMessage(self, toAddress, fromAddress, subject, message): super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) @@ -84,10 +132,12 @@ class MailchuckAccount(GatewayAccount): 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) \ No newline at end of file + self.toLabel = matches.group(1) + self.toAddress = matches.group(1) \ No newline at end of file diff --git a/src/bitmessageqt/emailgateway.py b/src/bitmessageqt/emailgateway.py new file mode 100644 index 00000000..0df4dd01 --- /dev/null +++ b/src/bitmessageqt/emailgateway.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'emailgateway.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_EmailGatewayDialog(object): + def setupUi(self, EmailGatewayDialog): + EmailGatewayDialog.setObjectName(_fromUtf8("EmailGatewayDialog")) + EmailGatewayDialog.resize(386, 172) + self.gridLayout = QtGui.QGridLayout(EmailGatewayDialog) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.radioButtonRegister = QtGui.QRadioButton(EmailGatewayDialog) + self.radioButtonRegister.setChecked(True) + self.radioButtonRegister.setObjectName(_fromUtf8("radioButtonRegister")) + self.gridLayout.addWidget(self.radioButtonRegister, 1, 0, 1, 1) + self.radioButtonUnregister = QtGui.QRadioButton(EmailGatewayDialog) + self.radioButtonUnregister.setObjectName(_fromUtf8("radioButtonUnregister")) + self.gridLayout.addWidget(self.radioButtonUnregister, 4, 0, 1, 1) + self.label = QtGui.QLabel(EmailGatewayDialog) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.label_2 = QtGui.QLabel(EmailGatewayDialog) + self.label_2.setObjectName(_fromUtf8("label_2")) + self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) + self.lineEditEmail = QtGui.QLineEdit(EmailGatewayDialog) + self.lineEditEmail.setEnabled(True) + self.lineEditEmail.setObjectName(_fromUtf8("lineEditEmail")) + self.gridLayout.addWidget(self.lineEditEmail, 3, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(EmailGatewayDialog) + 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(EmailGatewayDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayDialog.reject) + QtCore.QObject.connect(self.radioButtonRegister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setEnabled) + QtCore.QObject.connect(self.radioButtonUnregister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) + QtCore.QMetaObject.connectSlotsByName(EmailGatewayDialog) + EmailGatewayDialog.setTabOrder(self.radioButtonRegister, self.lineEditEmail) + EmailGatewayDialog.setTabOrder(self.lineEditEmail, self.radioButtonUnregister) + EmailGatewayDialog.setTabOrder(self.radioButtonUnregister, self.buttonBox) + + def retranslateUi(self, EmailGatewayDialog): + EmailGatewayDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonRegister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Register on email gateway", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonUnregister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Unregister from email gateway", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.", None, QtGui.QApplication.UnicodeUTF8)) + self.label_2.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Desired email address (including @mailchuck.com):", None, QtGui.QApplication.UnicodeUTF8)) + diff --git a/src/bitmessageqt/emailgateway.ui b/src/bitmessageqt/emailgateway.ui new file mode 100644 index 00000000..927df46a --- /dev/null +++ b/src/bitmessageqt/emailgateway.ui @@ -0,0 +1,157 @@ + + + EmailGatewayDialog + + + + 0 + 0 + 386 + 172 + + + + 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 + + + + + + + Email gateway alows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. + + + true + + + + + + + Unregister from email gateway + + + false + + + + + + + radioButtonRegister + lineEditEmailAddress + buttonBox + + + + + buttonBox + accepted() + EmailGatewayDialog + accept() + + + 227 + 152 + + + 157 + 171 + + + + + buttonBox + rejected() + EmailGatewayDialog + reject() + + + 295 + 158 + + + 286 + 171 + + + + + radioButtonRegister + clicked(bool) + lineEditEmailAddress + setEnabled(bool) + + + 95 + 40 + + + 94 + 123 + + + + + radioButtonUnregister + clicked(bool) + lineEditEmailAddress + setDisabled(bool) + + + 139 + 19 + + + 187 + 123 + + + + + -- 2.45.1 From 80afc489d876396b09c6b1a7a5870d7f5d5b67ab Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 4 Oct 2015 10:47:51 +0200 Subject: [PATCH 0033/1102] Editable address labels Address labels can be edited now (F2 or double click) --- src/bitmessageqt/__init__.py | 22 +++++++++++++++++++++- src/bitmessageqt/foldertree.py | 8 +++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 06ddb900..ab9ce330 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -534,8 +534,11 @@ class MyForm(QtGui.QMainWindow): unread += db[toAddress][folder] j += 1 widget.setUnreadCount(unread) + if (tab == 'messages'): + print "setting %s editable" % (toAddress) + widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) i += 1 - + treeWidget.setSortingEnabled(True) def __init__(self, parent=None): @@ -645,6 +648,8 @@ class MyForm(QtGui.QMainWindow): # 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.treeWidgetChans, QtCore.SIGNAL( @@ -3463,6 +3468,21 @@ more work your computer must do to send the message. A Time-To-Live of four or f folder = self.getCurrentFolder() self.loadMessagelist(messagelist, account, folder) + def treeWidgetItemChanged(self, item, column): + widget = self.getCurrentTreeWidget() + if item.address == widget.currentItem().address: + newLabel = str(item.text(0)) + newLabel = newLabel.replace("(" + str(item.address) + ")", '') + newLabel = newLabel.rstrip() + oldLabel = shared.config.get(str(item.address), 'label') + oldLabel = oldLabel.replace("(" + str(item.address) + ")", '') + oldLabel = oldLabel.rstrip() + if newLabel == oldLabel: + return + shared.config.set(str(item.address), 'label', newLabel) + item.updateText() + shared.writeKeysFile() + def tableWidgetInboxItemClicked(self): folder = self.getCurrentFolder() messageTextedit = self.getCurrentMessageTextedit() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 41824b91..2a907711 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -80,9 +80,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): self.updateText() def updateText(self): - text = QtGui.QApplication.translate("MainWindow", - unicode(shared.config.get(self.address, 'label'), 'utf-8)') - + ' (' + self.address + ')') + text = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' font = QtGui.QFont() if self.unreadCount > 0: @@ -116,6 +114,10 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): super(Ui_AddressWidget, self).setExpanded(expand) self.updateText() + def edit(self): + self.setText(0, shared.config.get(self.address, 'label')) + super(QtGui.QAbstractItemView, self).edit() + # label (or address) alphabetically, disabled at the end def __lt__(self, other): if (isinstance(other, Ui_AddressWidget)): -- 2.45.1 From ccae351e6536d893ba68e72740b6164c7321df4a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 4 Oct 2015 10:57:14 +0200 Subject: [PATCH 0034/1102] Fix: do not update account name from folder name Last commit caused changes in unread count of folder to change the account name. This is now fixed. --- src/bitmessageqt/__init__.py | 37 ++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ab9ce330..0c7a7e95 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -535,7 +535,6 @@ class MyForm(QtGui.QMainWindow): j += 1 widget.setUnreadCount(unread) if (tab == 'messages'): - print "setting %s editable" % (toAddress) widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) i += 1 @@ -3469,19 +3468,29 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.loadMessagelist(messagelist, account, folder) def treeWidgetItemChanged(self, item, column): - widget = self.getCurrentTreeWidget() - if item.address == widget.currentItem().address: - newLabel = str(item.text(0)) - newLabel = newLabel.replace("(" + str(item.address) + ")", '') - newLabel = newLabel.rstrip() - oldLabel = shared.config.get(str(item.address), 'label') - oldLabel = oldLabel.replace("(" + str(item.address) + ")", '') - oldLabel = oldLabel.rstrip() - if newLabel == oldLabel: - return - shared.config.set(str(item.address), 'label', newLabel) - item.updateText() - shared.writeKeysFile() + # only for manual edits. automatic edits (setText) are ignored + if column != 0: + return + # only account names + if not isinstance(item, Ui_AddressWidget): + return + # only currently selected item + if item.address != self.getCurrentTreeWidget().currentItem().address: + return + + newLabel = str(item.text(0)) + newLabel = newLabel.replace("(" + str(item.address) + ")", '') + newLabel = newLabel.rstrip() + oldLabel = shared.config.get(str(item.address), 'label') + oldLabel = oldLabel.replace("(" + str(item.address) + ")", '') + oldLabel = oldLabel.rstrip() + # unchanged, do not do anything either + if newLabel == oldLabel: + return + + shared.config.set(str(item.address), 'label', newLabel) + item.updateText() + shared.writeKeysFile() def tableWidgetInboxItemClicked(self): folder = self.getCurrentFolder() -- 2.45.1 From 1cab8bf549f25bf64986df6101fd4d5a232de55c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 4 Oct 2015 11:47:06 +0200 Subject: [PATCH 0035/1102] Fix: gateway registration updates label When registering on a gateway, the label change will be displayed immediately. --- src/bitmessageqt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0c7a7e95..3cd884c7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2673,6 +2673,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f acct.register(email) shared.config.set(addressAtCurrentRow, 'label', email) shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') + self.getCurrentTreeWidget().currentItem().updateText() shared.writeKeysFile() else: print "well nothing" -- 2.45.1 From b8baceb6296bd3c960686ea53416de6a1b35d55e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 4 Oct 2015 20:32:17 +0200 Subject: [PATCH 0036/1102] Fix: recurse prevention In case something screws up, prevent recursive changes through treeWidgetItemChagned --- src/bitmessageqt/__init__.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3cd884c7..6feb12cb 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -587,6 +587,8 @@ class MyForm(QtGui.QMainWindow): self.timer.start(2000) # milliseconds QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + self.recurDepth = 0 + self.init_file_menu() self.init_inbox_popup_menu() self.init_identities_popup_menu() @@ -595,7 +597,7 @@ class MyForm(QtGui.QMainWindow): 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() @@ -3488,10 +3490,16 @@ more work your computer must do to send the message. A Time-To-Live of four or f # unchanged, do not do anything either if newLabel == oldLabel: return - + + # recursion prevention + if self.recurDepth > 0: + return + + self.recurDepth += 1 shared.config.set(str(item.address), 'label', newLabel) item.updateText() shared.writeKeysFile() + self.recurDepth -= 1 def tableWidgetInboxItemClicked(self): folder = self.getCurrentFolder() -- 2.45.1 From 55251762160ef5571f937b0ccf62e7afd88bbdbe Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 5 Oct 2015 10:32:56 +0200 Subject: [PATCH 0037/1102] Chan updates - chans now work with the new interface, still some bugs present - chans do not have a sent folder anymore (you'll see sent messages in the sent folder of the account you're sending it from) --- src/bitmessageqt/__init__.py | 16 +++++++++------- src/bitmessageqt/foldertree.py | 14 +++++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6feb12cb..7e1b63ca 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -447,11 +447,12 @@ class MyForm(QtGui.QMainWindow): self.rerenderTabTree('chan') def rerenderTabTree(self, tab): - folders = ['inbox', 'sent', 'trash'] if tab == 'messages': treeWidget = self.ui.treeWidgetYourIdentities + folders = ['inbox', 'sent', 'trash'] elif tab == 'chan': treeWidget = self.ui.treeWidgetChans + folders = ['inbox', 'trash'] # sort ascending when creating if treeWidget.topLevelItemCount() == 0: @@ -874,6 +875,7 @@ class MyForm(QtGui.QMainWindow): else: where = "toaddress || fromaddress || subject || message" + tableWidget.setColumnHidden(0, False) tableWidget.setColumnHidden(1, True) tableWidget.setSortingEnabled(False) @@ -2248,9 +2250,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setFont(font) newItem.setData(Qt.UserRole, str(toAddress)) - if shared.safeConfigGetBoolean(str(toAddress), 'mailinglist'): + if acct.type == 'mailinglist': newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta - if shared.safeConfigGetBoolean(str(toAddress), 'chan'): + if acct.type == 'chan': newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange self.ui.tableWidgetInbox.insertRow(0) newItem.setIcon(avatarize(toAddress)) @@ -3261,8 +3263,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f # Group of functions for the Your Identities dialog box def getCurrentAccount(self): - #treeWidget = self.getCurrentTreeWidget() - treeWidget = self.ui.treeWidgetYourIdentities + treeWidget = self.getCurrentTreeWidget() + #treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() if currentItem: @@ -3474,8 +3476,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f # only for manual edits. automatic edits (setText) are ignored if column != 0: return - # only account names - if not isinstance(item, Ui_AddressWidget): + # only account names of normal addresses (no chans/mailinglists) + if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal': return # only currently selected item if item.address != self.getCurrentTreeWidget().currentItem().address: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 2a907711..cb06763b 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -63,18 +63,26 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem): class Ui_AddressWidget(QtGui.QTreeWidgetItem): def __init__(self, parent, pos = 0, address = "", unreadCount = 0): super(QtGui.QTreeWidgetItem, self).__init__() - self.address = address self.unreadCount = unreadCount parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) - self.setExpanded(shared.safeConfigGetBoolean(self.address, 'enabled')) - self.updateText() + self.setAddress(address) def setAddress(self, address): self.address = str(address) + self.setType() + self.setExpanded(shared.safeConfigGetBoolean(self.address, 'enabled')) self.updateText() + def setType(self): + if shared.safeConfigGetBoolean(self.address, 'chan'): + self.type = "chan" + elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + self.type = "mailinglist" + else: + self.type = "normal" + def setUnreadCount(self, cnt): self.unreadCount = int(cnt) self.updateText() -- 2.45.1 From 552876e43e4c26aa8ac62f9938d9d452cc6a4c13 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 5 Oct 2015 10:36:04 +0200 Subject: [PATCH 0038/1102] Gateway register/unregister changes - do not register/unregister channels or mailing lists - send registration/unregistration request irrespective of whether the client thinks it's registered or not. We don't know for sure it knows it correctly so don't assume that, it may confuse users --- src/bitmessageqt/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7e1b63ca..dfd381c1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2665,12 +2665,15 @@ more work your computer must do to send the message. A Time-To-Live of four or f if self.dialog.exec_(): addressAtCurrentRow = self.getCurrentAccount() acct = accountClass(addressAtCurrentRow) - if isinstance(acct, GatewayAccount) and self.dialog.ui.radioButtonUnregister.isChecked(): + # no chans / mailinglists + if acct.type != 'normal': + continue + if self.dialog.ui.radioButtonUnregister.isChecked(): print "unregister" acct.unregister() shared.config.remove_option(addressAtCurrentRow, 'gateway') shared.writeKeysFile() - elif (not isinstance(acct, GatewayAccount)) and self.dialog.ui.radioButtonRegister.isChecked(): + elif self.dialog.ui.radioButtonRegister.isChecked(): print "register" email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) @@ -2680,7 +2683,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.getCurrentTreeWidget().currentItem().updateText() shared.writeKeysFile() else: - print "well nothing" + pass + #print "well nothing" # shared.writeKeysFile() # self.rerenderInboxToLabels() -- 2.45.1 From 321bf9a6c99ef3c0fcdb7f201ccb5d379f8ef645 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 5 Oct 2015 17:07:23 +0200 Subject: [PATCH 0039/1102] Chan UI fix Minor chan UI fix. Still not completely smooth but mostly working. --- src/bitmessageqt/__init__.py | 7 +++++-- src/bitmessageqt/account.py | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index dfd381c1..e6544da8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2667,7 +2667,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f acct = accountClass(addressAtCurrentRow) # no chans / mailinglists if acct.type != 'normal': - continue + return if self.dialog.ui.radioButtonUnregister.isChecked(): print "unregister" acct.unregister() @@ -3481,7 +3481,10 @@ more work your computer must do to send the message. A Time-To-Live of four or f if column != 0: return # only account names of normal addresses (no chans/mailinglists) - if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal': + if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal' or self.getCurrentTreeWidget().currentItem() is None: + return + # not visible + if (not self.getCurrentAccount()) or (not isinstance (self.getCurrentAccount(), Ui_AddressWidget)): return # only currently selected item if item.address != self.getCurrentTreeWidget().currentItem().address: diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 05613e47..f140235c 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -28,6 +28,12 @@ def accountClass(address): class BMAccount(object): def __init__(self, address = None): self.address = address + self.type = 'normal' + if shared.config.has_section(address): + if shared.safeConfigGetBoolean(self.address, 'chan'): + self.type = "chan" + elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + self.type = "mailinglist" def getLabel(self, address = None): if address is None: -- 2.45.1 From e10b9cbff4e1cdad9500d2b6b0b2124926ea4429 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 6 Oct 2015 18:58:23 +0200 Subject: [PATCH 0040/1102] Resizable fields Inbox folder/message now resizable --- src/bitmessageqt/bitmessageui.py | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 36ccbbb0..7012d0d7 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -69,14 +69,15 @@ class Ui_MainWindow(object): self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) self.verticalLayout_12.addWidget(self.pushButtonNewAddress) self.horizontalLayout_3.addLayout(self.verticalLayout_12) - self.verticalLayout_7 = QtGui.QVBoxLayout() - self.verticalLayout_7.setObjectName(_fromUtf8("verticalLayout_7")) - self.horizontalLayoutSearch = QtGui.QHBoxLayout() - self.horizontalLayoutSearch.setContentsMargins(-1, 0, -1, -1) - self.horizontalLayoutSearch.setObjectName(_fromUtf8("horizontalLayoutSearch")) + self.verticalSplitter_7 = QtGui.QSplitter() + self.verticalSplitter_7.setObjectName(_fromUtf8("verticalSplitter_7")) + self.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical) + self.horizontalSplitterSearch = QtGui.QSplitter() + self.horizontalSplitterSearch.setContentsMargins(0, 0, 0, 0) + self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch")) self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox) self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit")) - self.horizontalLayoutSearch.addWidget(self.inboxSearchLineEdit) + self.horizontalSplitterSearch.addWidget(self.inboxSearchLineEdit) self.inboxSearchOption = QtGui.QComboBox(self.inbox) self.inboxSearchOption.setObjectName(_fromUtf8("inboxSearchOption")) self.inboxSearchOption.addItem(_fromUtf8("")) @@ -84,8 +85,11 @@ class Ui_MainWindow(object): self.inboxSearchOption.addItem(_fromUtf8("")) self.inboxSearchOption.addItem(_fromUtf8("")) self.inboxSearchOption.addItem(_fromUtf8("")) - self.horizontalLayoutSearch.addWidget(self.inboxSearchOption) - self.verticalLayout_7.addLayout(self.horizontalLayoutSearch) + 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 = QtGui.QTableWidget(self.inbox) self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInbox.setAlternatingRowColors(True) @@ -111,13 +115,20 @@ class Ui_MainWindow(object): self.tableWidgetInbox.horizontalHeader().setStretchLastSection(True) self.tableWidgetInbox.verticalHeader().setVisible(False) self.tableWidgetInbox.verticalHeader().setDefaultSectionSize(26) - self.verticalLayout_7.addWidget(self.tableWidgetInbox) + self.verticalSplitter_7.addWidget(self.tableWidgetInbox) self.textEditInboxMessage = QtGui.QTextEdit(self.inbox) self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessage.setReadOnly(True) self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage")) - self.verticalLayout_7.addWidget(self.textEditInboxMessage) - self.horizontalLayout_3.addLayout(self.verticalLayout_7) + 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.horizontalLayout_3.addWidget(self.verticalSplitter_7) self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/inbox.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) -- 2.45.1 From 59a562228de36727ab16ce8e6a639950e17be6b1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 6 Oct 2015 18:58:44 +0200 Subject: [PATCH 0041/1102] Fix Typo --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e6544da8..e84c1625 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2280,7 +2280,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setFont(font) self.ui.tableWidgetInbox.setItem(0, 3, newItem) self.ui.tableWidgetInbox.setSortingEnabled(True) - self.ubuntuMessagingMenuUpdate(True, newItem, self.toLabel) + self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) -- 2.45.1 From 4db1a5ea4855a91437991ac488a7f70bdf865844 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 10 Oct 2015 19:58:01 +0200 Subject: [PATCH 0042/1102] Subscriptions Initial subscription fix. Still does not always display the list from the correct folder, and it currently does not update unread count on subscriptions. --- src/bitmessageqt/__init__.py | 70 +++++++++++++-------------- src/bitmessageqt/account.py | 18 +++++-- src/bitmessageqt/foldertree.py | 88 ++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 38 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e84c1625..e015e24c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -419,26 +419,16 @@ class MyForm(QtGui.QMainWindow): treeWidget = self.ui.treeWidgetSubscriptions folders = ['inbox', 'trash'] treeWidget.clear() + treeWidget.setSortingEnabled(False) + treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') for row in queryreturn: label, address, enabled = row - newItem = QtGui.QTreeWidgetItem(treeWidget) - newItem.setExpanded(True) - newItem.setIcon(0, avatarize(address)) - newItem.setText(0, label + ' (' + address + ')') - newItem.setData(0, Qt.UserRole, [str(address), "inbox"]) - #set text color - if enabled: - brush = QtGui.QBrush(QApplication.palette().text().color()) - else: - brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - brush.setStyle(QtCore.Qt.NoBrush) - newItem.setForeground(0, brush) + newItem = Ui_SubscriptionWidget(treeWidget, 0, address, 0, label, enabled) for folder in folders: - newSubItem = QtGui.QTreeWidgetItem(newItem) - newSubItem.setText(0, _translate("MainWindow", folder)) - newSubItem.setData(0, Qt.UserRole, [str(address), folder]) + newSubItem = Ui_FolderWidget(newItem, 0, address, folder, 0) + treeWidget.setSortingEnabled(True) def rerenderTabTreeMessages(self): self.rerenderTabTree('messages') @@ -457,7 +447,6 @@ class MyForm(QtGui.QMainWindow): # sort ascending when creating if treeWidget.topLevelItemCount() == 0: treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) - # init dictionary db = {} enabled = {} @@ -989,18 +978,22 @@ class MyForm(QtGui.QMainWindow): where = "message" else: where = "toaddress || fromaddress || subject || message" - + + if tableWidget == self.ui.tableWidgetInboxSubscriptions: + xAddress = "fromaddress" + else: + xAddress = "toaddress" if folder != False: sqlStatement = ''' SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE toaddress=? AND folder=? AND %s LIKE ? + FROM inbox WHERE ''' + xAddress + '''=? AND folder=? AND %s LIKE ? ORDER BY received ''' % (where) queryreturn = sqlQuery(sqlStatement, account, folder, what) else: sqlStatement = ''' SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE toaddress=? AND folder != "trash" AND %s LIKE ? + FROM inbox WHERE ''' + xAddress + '''=? AND folder != "trash" AND %s LIKE ? ORDER BY received ''' % (where) queryreturn = sqlQuery(sqlStatement, account, what) @@ -1018,7 +1011,10 @@ class MyForm(QtGui.QMainWindow): for row in queryreturn: msgfolder, msgid, toAddress, fromAddress, subject, received, read = row if acct is None: - acct = accountClass(toAddress) + if tableWidget == self.ui.tableWidgetInboxSubscriptions: + acct = accountClass(fromAddress) + else: + acct = accountClass(toAddress) subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct.parseMessage(toAddress, fromAddress, subject, "") @@ -1794,11 +1790,12 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing - for i in range(self.ui.tableWidgetInbox.rowCount()): - if msgid == str(self.ui.tableWidgetInbox.item(i, 3).data(Qt.UserRole).toPyObject()): + inbox = self.getCurrentMessagelist + for i in range(inbox.rowCount()): + if msgid == str(inbox.item(i, 3).data(Qt.UserRole).toPyObject()): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) - self.ui.tableWidgetInbox.removeRow(i) + inbox.removeRow(i) break self.changedInboxUnread() @@ -2084,7 +2081,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.lineEditTo.setText('') self.ui.lineEditSubject.setText('') self.ui.textEditMessage.setText('') - self.ui.tabWidget.setCurrentIndex(2) + self.ui.tabWidget.setCurrentIndex(0) self.ui.tableWidgetInbox.setCurrentCell(0, 0) else: self.statusBar().showMessage(_translate( @@ -2131,7 +2128,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f self.ui.lineEditSubjectBroadcast.setText('') self.ui.textEditMessageBroadcast.setText('') self.ui.tabWidget.setCurrentIndex(1) - self.ui.tableWidgetInbox.setCurrentCell(0, 0) + self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) def click_pushButtonLoadFromAddressBook(self): self.ui.tabWidget.setCurrentIndex(5) @@ -2242,10 +2239,12 @@ more work your computer must do to send the message. A Time-To-Live of four or f subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct = accountClass(toAddress) acct.parseMessage(toAddress, fromAddress, subject, message) + + inbox = self.getCurrentMessagelist() font = QFont() font.setBold(True) - self.ui.tableWidgetInbox.setSortingEnabled(False) + inbox.setSortingEnabled(False) newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setFont(font) @@ -2254,9 +2253,9 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta if acct.type == 'chan': newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange - self.ui.tableWidgetInbox.insertRow(0) + inbox.insertRow(0) newItem.setIcon(avatarize(toAddress)) - self.ui.tableWidgetInbox.setItem(0, 0, newItem) + inbox.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) @@ -2265,21 +2264,21 @@ more work your computer must do to send the message. A Time-To-Live of four or f newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setFont(font) newItem.setIcon(avatarize(fromAddress)) - self.ui.tableWidgetInbox.setItem(0, 1, newItem) + inbox.setItem(0, 1, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) newItem.setToolTip(unicode(acct.subject, 'utf-8)')) newItem.setData(Qt.UserRole, str(subject)) #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) + inbox.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) + inbox.setItem(0, 3, newItem) + inbox.setSortingEnabled(True) self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) def click_pushButtonAddAddressBook(self): @@ -2931,7 +2930,8 @@ more work your computer must do to send the message. A Time-To-Live of four or f if not tableWidget: return unread = False - while tableWidget.selectedIndexes() != []: + currentRow = 0 + while tableWidget.selectedIndexes(): currentRow = tableWidget.selectedIndexes()[0].row() inventoryHashToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) @@ -2947,7 +2947,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f else: tableWidget.selectRow(currentRow - 1) if unread: - changedInboxUnread() + self.changedInboxUnread() def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3481,7 +3481,7 @@ more work your computer must do to send the message. A Time-To-Live of four or f if column != 0: return # only account names of normal addresses (no chans/mailinglists) - if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal' or self.getCurrentTreeWidget().currentItem() is None: + if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal' or not self.getCurrentTreeWidget() or self.getCurrentTreeWidget().currentItem() is None: return # not visible if (not self.getCurrentAccount()) or (not isinstance (self.getCurrentAccount(), Ui_AddressWidget)): diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index f140235c..3b8badaa 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -11,7 +11,9 @@ import time def accountClass(address): if not shared.config.has_section(address): - return None + subscription = SubscriptionAccount(address) + if subscription.type != 'subscription': + return None try: gateway = shared.config.get(address, "gateway") for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): @@ -24,7 +26,7 @@ def accountClass(address): pass # no gateway return BMAccount(address) - + class BMAccount(object): def __init__(self, address = None): self.address = address @@ -34,7 +36,12 @@ class BMAccount(object): self.type = "chan" elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): self.type = "mailinglist" - + else: + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', address) + if queryreturn: + self.type = 'subscription' + def getLabel(self, address = None): if address is None: address = self.address @@ -62,6 +69,11 @@ class BMAccount(object): self.fromLabel = self.getLabel(fromAddress) self.toLabel = self.getLabel(toAddress) + +class SubscriptionAccount(BMAccount): + pass + + class GatewayAccount(BMAccount): gatewayName = None def __init__(self, address): diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index cb06763b..59e2b963 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -146,3 +146,91 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): return (not reverse if shared.config.getboolean(self.address, 'enabled') else reverse) return super(QtGui.QTreeWidgetItem, self).__lt__(other) + + +class Ui_SubscriptionWidget(Ui_AddressWidget): + def __init__(self, parent, pos = 0, address = "", unreadCount = 0, label = "", enabled = ""): + super(QtGui.QTreeWidgetItem, self).__init__() + self.unreadCount = unreadCount + parent.insertTopLevelItem(pos, self) + # only set default when creating + #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + self.setEnabled(enabled) + self.setLabel(label) + self.setAddress(address) + + def setLabel(self, label): + self.label = label + + def setAddress(self, address): + self.address = str(address) + self.setType() + self.setExpanded(self.isEnabled) + self.updateText() + + def setEnabled(self, enabled): + self.isEnabled = enabled + + def setType(self): + self.type = "subscription" + + def setUnreadCount(self, cnt): + self.unreadCount = int(cnt) + self.updateText() + + def updateText(self): + text = unicode(self.label, 'utf-8)') + ' (' + self.address + ')' + + font = QtGui.QFont() + if self.unreadCount > 0: + # only show message count if the child doesn't show + if not self.isExpanded(): + text += " (" + str(self.unreadCount) + ")" + font.setBold(True) + else: + font.setBold(False) + self.setFont(0, font) + + #set text color + if self.isEnabled: + brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) + #self.setExpanded(True) + else: + brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) + #self.setExpanded(False) + brush.setStyle(QtCore.Qt.NoBrush) + self.setForeground(0, brush) + + self.setIcon(0, avatarize(self.address)) + self.setText(0, text) + self.setToolTip(0, text) +# self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) + + def setExpanded(self, expand): + super(Ui_SubscriptionWidget, self).setExpanded(expand) + self.updateText() + + def edit(self): + self.setText(0, self.label) + super(QtGui.QAbstractItemView, self).edit() + + # label (or address) alphabetically, disabled at the end + def __lt__(self, other): + if (isinstance(other, Ui_SubscriptionWidget)): + reverse = False + if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: + reverse = True + if self.isEnabled == other.isEnabled: + if self.label: + x = self.label.decode('utf-8').lower() + else: + x = self.address.decode('utf-8').lower() + if other.label: + y = other.label.decode('utf-8').lower() + else: + y = other.address.decode('utf-8').lower() + return x < y +# else: + return (not reverse if self.isEnabled else reverse) + + return super(QtGui.QTreeWidgetItem, self).__lt__(other) \ No newline at end of file -- 2.45.1 From 001ec14d72d669f6317380cc1ea63e00d5303fa0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 10 Oct 2015 19:59:44 +0200 Subject: [PATCH 0043/1102] Messages tab resizable - the separator between folder tree and message list is now resizable - the separator between list of messages and message content is resizable - only for message tab, chans, subscriptions and others are still not resizable --- src/bitmessageqt/bitmessageui.py | 34 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 7012d0d7..26493241 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -53,27 +53,32 @@ class Ui_MainWindow(object): self.inbox.setObjectName(_fromUtf8("inbox")) self.gridLayout = QtGui.QGridLayout(self.inbox) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.horizontalLayout_3 = QtGui.QHBoxLayout() - self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3")) - self.verticalLayout_12 = QtGui.QVBoxLayout() - self.verticalLayout_12.setObjectName(_fromUtf8("verticalLayout_12")) + self.horizontalSplitter_3 = QtGui.QSplitter() + self.horizontalSplitter_3.setObjectName(_fromUtf8("horizontalSplitter_3")) + self.verticalSplitter_12 = QtGui.QSplitter() + self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12")) + self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical) self.treeWidgetYourIdentities = QtGui.QTreeWidget(self.inbox) - self.treeWidgetYourIdentities.setMaximumSize(QtCore.QSize(200, 16777215)) 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.verticalLayout_12.addWidget(self.treeWidgetYourIdentities) + self.verticalSplitter_12.addWidget(self.treeWidgetYourIdentities) self.pushButtonNewAddress = QtGui.QPushButton(self.inbox) - self.pushButtonNewAddress.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonNewAddress.setObjectName(_fromUtf8("pushButtonNewAddress")) - self.verticalLayout_12.addWidget(self.pushButtonNewAddress) - self.horizontalLayout_3.addLayout(self.verticalLayout_12) + 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 = QtGui.QSplitter() self.verticalSplitter_7.setObjectName(_fromUtf8("verticalSplitter_7")) self.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical) self.horizontalSplitterSearch = QtGui.QSplitter() - self.horizontalSplitterSearch.setContentsMargins(0, 0, 0, 0) self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch")) self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox) self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit")) @@ -85,6 +90,7 @@ class Ui_MainWindow(object): 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) @@ -128,8 +134,12 @@ class Ui_MainWindow(object): self.verticalSplitter_7.setCollapsible(1, False) self.verticalSplitter_7.setCollapsible(2, False) self.verticalSplitter_7.handle(1).setEnabled(False) - self.horizontalLayout_3.addWidget(self.verticalSplitter_7) - self.gridLayout.addLayout(self.horizontalLayout_3, 0, 0, 1, 1) + 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("")) -- 2.45.1 From b776eb7f3681962abd617ba3cac1d3b54ecfa407 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 11 Oct 2015 11:18:25 +0200 Subject: [PATCH 0044/1102] Formatting change Was not folding properly in editor, made it more python-like --- src/bitmessageqt/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e015e24c..a67a62dc 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1943,10 +1943,10 @@ class MyForm(QtGui.QMainWindow): 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."), QMessageBox.Ok) + "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): self.statusBar().showMessage('') -- 2.45.1 From 3911525d75bfa92d11ab678901e2ff85cbbfd0b3 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 11 Oct 2015 11:57:58 +0200 Subject: [PATCH 0045/1102] Remember main window geometry and state on exit Main window geometry and state is saved on exit and restored on load. Uses default QSettings in python. --- src/bitmessageqt/__init__.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a67a62dc..95fc43df 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -724,6 +724,8 @@ class MyForm(QtGui.QMainWindow): QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( "valueChanged(int)"), self.updateTTL) + self.readSettings() + # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} @@ -2741,6 +2743,11 @@ class MyForm(QtGui.QMainWindow): # unregister the messaging system if self.mmapp is not None: self.mmapp.unregister() + + settings = QSettings("Mailchuck Ltd.", "PyBitmessage") + settings.setValue("geometry", self.saveGeometry()) + settings.setValue("state", self.saveState()) + self.statusBar().showMessage(_translate( "MainWindow", "All done. Closing user interface...")) os._exit(0) @@ -3584,6 +3591,20 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage(data) + def readSettings(self): + settings = QSettings("Mailchuck Ltd.", "PyBitmessage") + try: + geom = settings.value("geometry") + self.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom) + except Exception as e: + pass + + try: + state = settings.value("state") + self.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state) + except Exception as e: + pass + class helpDialog(QtGui.QDialog): -- 2.45.1 From 9d2e114712519786e52d34095c0ae1d526a5f163 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 13 Oct 2015 23:32:36 +0200 Subject: [PATCH 0046/1102] Add BroadcastAccount class This will help to distinguish between general broadcasts and subscriptions. --- src/bitmessageqt/account.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 3b8badaa..19212302 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -7,13 +7,20 @@ import inspect from helper_sql import * from addresses import decodeAddress from pyelliptic.openssl import OpenSSL +from utils import str_broadcast_subscribers import time def accountClass(address): if not shared.config.has_section(address): - subscription = SubscriptionAccount(address) - if subscription.type != 'subscription': - return None + if address == str_broadcast_subscribers: + subscription = BroadcastAccount(address) + if subscription.type != 'broadcast': + return None + else: + subscription = SubscriptionAccount(address) + if subscription.type != 'subscription': + return None + return subscription try: gateway = shared.config.get(address, "gateway") for name, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass): @@ -36,9 +43,11 @@ class BMAccount(object): self.type = "chan" elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): self.type = "mailinglist" + elif self.address == str_broadcast_subscribers: + self.type = 'broadcast' else: queryreturn = sqlQuery( - '''select label from subscriptions where address=?''', address) + '''select label from subscriptions where address=?''', self.address) if queryreturn: self.type = 'subscription' @@ -72,6 +81,10 @@ class BMAccount(object): class SubscriptionAccount(BMAccount): pass + + +class BroadcastAccount(BMAccount): + pass class GatewayAccount(BMAccount): -- 2.45.1 From 23207749d1444175aa88dad1de5e50da22035d9e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 13 Oct 2015 23:33:36 +0200 Subject: [PATCH 0047/1102] Constant in a separate file str_broadcast_subscribers should not be specific to the main UI class --- src/bitmessageqt/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/utils.py b/src/bitmessageqt/utils.py index af58fd37..79b0e2a9 100644 --- a/src/bitmessageqt/utils.py +++ b/src/bitmessageqt/utils.py @@ -4,6 +4,8 @@ import os import shared from addresses import addBMIfNotPresent +str_broadcast_subscribers = '[Broadcast subscribers]' + def identiconize(address): size = 48 -- 2.45.1 From bf9bdaadc56a50f0edd051ad5e99c7cef436a87b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 13 Oct 2015 23:36:09 +0200 Subject: [PATCH 0048/1102] Fix reply-to subscriptions and labels Closes #1 Also attempts to solve #49 but needs testing. --- src/bitmessageqt/__init__.py | 65 ++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 95fc43df..29b410d4 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -89,7 +89,6 @@ class MyForm(QtGui.QMainWindow): # the maximum frequency of message sounds in seconds maxSoundFrequencySec = 60 - str_broadcast_subscribers = '[Broadcast subscribers]' str_chan = '[chan]' def init_file_menu(self): @@ -1161,7 +1160,7 @@ class MyForm(QtGui.QMainWindow): for row in queryreturn: toAddress, read = row if not read: - if toAddress == self.str_broadcast_subscribers: + if toAddress == str_broadcast_subscribers: if self.mmapp.has_source("Subscriptions"): self.mmapp.remove_source("Subscriptions") else: @@ -1179,8 +1178,8 @@ class MyForm(QtGui.QMainWindow): msgid, toAddress, read = row try: - if toAddress == self.str_broadcast_subscribers: - toLabel = self.str_broadcast_subscribers + if toAddress == str_broadcast_subscribers: + toLabel = str_broadcast_subscribers else: toLabel = shared.config.get(toAddress, 'label') except: @@ -1189,7 +1188,7 @@ class MyForm(QtGui.QMainWindow): toLabel = toAddress if not read: - if toLabel == self.str_broadcast_subscribers: + if toLabel == str_broadcast_subscribers: # increment the unread subscriptions unreadSubscriptions = unreadSubscriptions + 1 else: @@ -1254,7 +1253,7 @@ class MyForm(QtGui.QMainWindow): return # remember this item to that the messaging menu can find it - if toLabel == self.str_broadcast_subscribers: + if toLabel == str_broadcast_subscribers: self.newBroadcastItem = newItem else: self.newMessageItem = newItem @@ -2098,7 +2097,7 @@ class MyForm(QtGui.QMainWindow): # this is a broadcast message, but we can use it to update the # user interface when the POW is done generating. ackdata = OpenSSL.rand(32) - toAddress = self.str_broadcast_subscribers + toAddress = str_broadcast_subscribers ripe = '' t = ('', # msgid. We don't know what this will be until the POW is done. toAddress, @@ -2119,7 +2118,7 @@ class MyForm(QtGui.QMainWindow): sqlExecute( '''INSERT INTO sent VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)''', *t) - toLabel = self.str_broadcast_subscribers + toLabel = str_broadcast_subscribers self.displayNewSentMessage( toAddress, toLabel, fromAddress, subject, message, ackdata) @@ -2179,15 +2178,13 @@ class MyForm(QtGui.QMainWindow): def rerenderComboBoxSendFromBroadcast(self): self.ui.comboBoxSendFromBroadcast.clear() - 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. - isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') - if isEnabled and isMaillinglist: - self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( - addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) + queryreturn = sqlQuery( + '''select label, address from subscriptions where enabled = 1''' + ) + + for row in queryreturn: + label, address = row + self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(address), unicode(label, 'utf-8'), address) self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '') if(self.ui.comboBoxSendFromBroadcast.count() == 2): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1) @@ -2863,9 +2860,19 @@ class MyForm(QtGui.QMainWindow): for row in queryreturn: messageAtCurrentInboxRow, = row acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, str(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject()), messageAtCurrentInboxRow) - if toAddressAtCurrentInboxRow == self.str_broadcast_subscribers: - #TODO what does this if?.. - a = a + widget = { + 'subject': self.ui.lineEditSubject, + 'from': self.ui.comboBoxSendFrom, + 'message': self.ui.textEditMessage + } + if toAddressAtCurrentInboxRow == str_broadcast_subscribers: + widget = { + 'subject': self.ui.lineEditSubjectBroadcast, + 'from': self.ui.comboBoxSendFromBroadcast, + 'message': self.ui.textEditMessageBroadcast + } + self.ui.tabWidgetSend.setCurrentIndex(1) + toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow 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), QMessageBox.Ok) @@ -2873,9 +2880,10 @@ class MyForm(QtGui.QMainWindow): 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."), QMessageBox.Ok) else: - self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) + #self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) + self.ui.tabWidgetSend.setCurrentIndex(0) - self.ui.lineEditTo.setText(str(acct.fromLabel)) + self.ui.lineEditTo.setText(str(acct.fromAddress)) # 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 shared.config.has_section(toAddressAtCurrentInboxRow): @@ -2883,20 +2891,19 @@ class MyForm(QtGui.QMainWindow): print 'original sent to a chan. Setting the to address in the reply to the chan address.' self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) - listOfAddressesInComboBoxSendFrom = [str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) for i in range(self.ui.comboBoxSendFrom.count())] + listOfAddressesInComboBoxSendFrom = [str(widget['from'].itemData(i).toPyObject()) for i in range(widget['from'].count())] if toAddressAtCurrentInboxRow in listOfAddressesInComboBoxSendFrom: currentIndex = listOfAddressesInComboBoxSendFrom.index(toAddressAtCurrentInboxRow) - self.ui.comboBoxSendFrom.setCurrentIndex(currentIndex) + widget['from'].setCurrentIndex(currentIndex) else: - self.ui.comboBoxSendFrom.setCurrentIndex(0) + widget['from'].setCurrentIndex(0) quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8')) - self.ui.textEditMessage.setText(quotedText) + widget['message'].setText(quotedText) if acct.subject[0:3] in ['Re:', 'RE:']: - self.ui.lineEditSubject.setText(acct.subject) + widget['subject'].setText(acct.subject) else: - self.ui.lineEditSubject.setText('Re: ' + acct.subject) - self.ui.tabWidgetSend.setCurrentIndex(0) + widget['subject'].setText('Re: ' + acct.subject) self.ui.tabWidget.setCurrentIndex(1) def on_action_InboxAddSenderToAddressBook(self): -- 2.45.1 From faeaad212db9db12154bd735832c31fdc99210fd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 14 Oct 2015 23:38:34 +0200 Subject: [PATCH 0049/1102] Replies to mailing lists Attempt to fix #49. Will close after positive feedback. --- src/bitmessageqt/__init__.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 29b410d4..fa6d77ca 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2151,13 +2151,13 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Fetched address from namecoin identity.")) - def setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(self, address): + def setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(self, address): # If this is a chan then don't let people broadcast because no one # should subscribe to chan addresses. - if shared.safeConfigGetBoolean(str(address), 'chan'): - self.ui.tabWidgetSend.setCurrentIndex(0) - else: + if shared.safeConfigGetBoolean(str(address), 'mailinglist'): self.ui.tabWidgetSend.setCurrentIndex(1) + else: + self.ui.tabWidgetSend.setCurrentIndex(0) def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() @@ -2866,13 +2866,8 @@ class MyForm(QtGui.QMainWindow): 'message': self.ui.textEditMessage } if toAddressAtCurrentInboxRow == str_broadcast_subscribers: - widget = { - 'subject': self.ui.lineEditSubjectBroadcast, - 'from': self.ui.comboBoxSendFromBroadcast, - 'message': self.ui.textEditMessageBroadcast - } - self.ui.tabWidgetSend.setCurrentIndex(1) - toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow + self.ui.tabWidgetSend.setCurrentIndex(0) +# toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow 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), QMessageBox.Ok) @@ -2880,8 +2875,15 @@ class MyForm(QtGui.QMainWindow): 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."), QMessageBox.Ok) else: - #self.setBroadcastEnablementDependingOnWhetherThisIsAChanAddress(toAddressAtCurrentInboxRow) - self.ui.tabWidgetSend.setCurrentIndex(0) + self.setBroadcastEnablementDependingOnWhetherThisIsAMailingListAddress(toAddressAtCurrentInboxRow) + if self.ui.tabWidgetSend.currentIndex() == 1: + widget = { + 'subject': self.ui.lineEditSubjectBroadcast, + 'from': self.ui.comboBoxSendFromBroadcast, + 'message': self.ui.textEditMessageBroadcast + } + self.ui.tabWidgetSend.setCurrentIndex(1) + toAddressAtCurrentInboxRow = fromAddressAtCurrentInboxRow self.ui.lineEditTo.setText(str(acct.fromAddress)) -- 2.45.1 From 5b12f2dffa14e52330c98ccf21c7fdb416385499 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 14 Oct 2015 23:43:50 +0200 Subject: [PATCH 0050/1102] Chan and subscription trash Fixes #6 --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fa6d77ca..a4d8c62f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3295,8 +3295,8 @@ class MyForm(QtGui.QMainWindow): return False def getCurrentFolder(self): - #treeWidget = self.getCurrentTreeWidget() - treeWidget = self.ui.treeWidgetYourIdentities + treeWidget = self.getCurrentTreeWidget() + #treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() if currentItem and hasattr(currentItem, 'folderName'): -- 2.45.1 From 7998d77b9c1a7d8ccdfe1d1e7906a67a52d663a7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 16 Oct 2015 20:34:15 +0200 Subject: [PATCH 0051/1102] Broadcast sending from was wrong Fixes #51 --- src/bitmessageqt/__init__.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a4d8c62f..10fe1b75 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2178,13 +2178,15 @@ class MyForm(QtGui.QMainWindow): def rerenderComboBoxSendFromBroadcast(self): self.ui.comboBoxSendFromBroadcast.clear() - queryreturn = sqlQuery( - '''select label, address from subscriptions where enabled = 1''' - ) - - for row in queryreturn: - label, address = row - self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(address), unicode(label, 'utf-8'), address) + 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. + isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + if isEnabled and isMaillinglist: + self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( + addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '') if(self.ui.comboBoxSendFromBroadcast.count() == 2): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1) -- 2.45.1 From c83255d4d4923af778bfbe9ac939e2ef7b6d7604 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 17 Oct 2015 17:11:40 +0200 Subject: [PATCH 0052/1102] Bump up version --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 5351947f..a51a2017 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.4.4' +softwareVersion = '0.4.5.3' 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. -- 2.45.1 From 343b3532c5dc3d5515701a62ed0161019817fcdc Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 18 Oct 2015 21:11:10 +0200 Subject: [PATCH 0053/1102] Show subscription unread count Subscriptions were not showing unread count. This commit implements it. --- src/bitmessageqt/__init__.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 10fe1b75..9a264ea6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -420,13 +420,30 @@ class MyForm(QtGui.QMainWindow): treeWidget.clear() treeWidget.setSortingEnabled(False) treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) + db = {} + queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt + FROM inbox, subscriptions + WHERE read = 0 AND subscriptions.address = inbox.fromaddress + GROUP BY inbox.fromaddress, folder''') + for row in queryreturn: + fromaddress, folder, cnt = row + if fromaddress not in db: + db[fromaddress] = {} + db[fromaddress][folder] = cnt queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') for row in queryreturn: label, address, enabled = row newItem = Ui_SubscriptionWidget(treeWidget, 0, address, 0, label, enabled) + unread = 0 for folder in folders: - newSubItem = Ui_FolderWidget(newItem, 0, address, folder, 0) + try: + newSubItem = Ui_FolderWidget(newItem, 0, address, folder, db[address][folder]) + unread += db[address][folder] + except KeyError: + newSubItem = Ui_FolderWidget(newItem, 0, address, folder, 0) + + newItem.setUnreadCount(unread) treeWidget.setSortingEnabled(True) def rerenderTabTreeMessages(self): -- 2.45.1 From 5ac17e456d54b222debb39d58720eae9efd46a72 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 18 Oct 2015 22:54:52 +0200 Subject: [PATCH 0054/1102] Fix reply unicode subject Fixes #62 --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9a264ea6..b896b879 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2878,7 +2878,7 @@ class MyForm(QtGui.QMainWindow): if queryreturn != []: for row in queryreturn: messageAtCurrentInboxRow, = row - acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, str(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject()), messageAtCurrentInboxRow) + acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject(), 'utf-8'), messageAtCurrentInboxRow) widget = { 'subject': self.ui.lineEditSubject, 'from': self.ui.comboBoxSendFrom, -- 2.45.1 From 059f113d954de419e0ad9e0c8b48e33134b52b03 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 17:22:37 +0200 Subject: [PATCH 0055/1102] Account labels become editable again Fixes #60 --- src/bitmessageqt/__init__.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b896b879..539a3523 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3301,17 +3301,22 @@ class MyForm(QtGui.QMainWindow): return False # Group of functions for the Your Identities dialog box - def getCurrentAccount(self): + def getCurrentItem(self): treeWidget = self.getCurrentTreeWidget() - #treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() if currentItem: - account = currentItem.address - return account - else: - # TODO need debug msg? - return False + return currentItem + return False + + def getCurrentAccount(self): + currentItem = self.getCurrentItem() + if currentItem: + account = currentItem.address + return account + else: + # TODO need debug msg? + return False def getCurrentFolder(self): treeWidget = self.getCurrentTreeWidget() @@ -3519,10 +3524,10 @@ class MyForm(QtGui.QMainWindow): if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal' or not self.getCurrentTreeWidget() or self.getCurrentTreeWidget().currentItem() is None: return # not visible - if (not self.getCurrentAccount()) or (not isinstance (self.getCurrentAccount(), Ui_AddressWidget)): + if (not self.getCurrentItem()) or (not isinstance (self.getCurrentItem(), Ui_AddressWidget)): return # only currently selected item - if item.address != self.getCurrentTreeWidget().currentItem().address: + if item.address != self.getCurrentAccount(): return newLabel = str(item.text(0)) -- 2.45.1 From afeadcf8d223722ac4a0327b55d96bbcf5513f3e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 17:37:43 +0200 Subject: [PATCH 0056/1102] Switch to tab you're replying from Fixes #64 --- src/bitmessageqt/__init__.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 539a3523..96b415ea 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -593,7 +593,11 @@ class MyForm(QtGui.QMainWindow): self.timer.start(2000) # milliseconds QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + # e.g. for editing labels self.recurDepth = 0 + + # switch back to this when replying + self.replyFromTab = None self.init_file_menu() self.init_inbox_popup_menu() @@ -2099,8 +2103,10 @@ class MyForm(QtGui.QMainWindow): self.ui.lineEditTo.setText('') self.ui.lineEditSubject.setText('') self.ui.textEditMessage.setText('') - self.ui.tabWidget.setCurrentIndex(0) - self.ui.tableWidgetInbox.setCurrentCell(0, 0) + if self.replyFromTab is not None: + self.ui.tabWidget.setCurrentIndex(self.replyFromTab) + self.replyFromTab = None + #self.ui.tableWidgetInbox.setCurrentCell(0, 0) else: self.statusBar().showMessage(_translate( "MainWindow", "Your \'To\' field is empty.")) @@ -2865,6 +2871,10 @@ class MyForm(QtGui.QMainWindow): tableWidget = self.getCurrentMessagelist() if not tableWidget: return + + # save this to return back after reply is done + self.replyFromTab = self.ui.tabWidget.currentIndex() + currentInboxRow = tableWidget.currentRow() toAddressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 0).data(Qt.UserRole).toPyObject()) -- 2.45.1 From d51431b1dc7a86d8ae7aeaae4bf8eefa8eb14eb0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 20:03:06 +0200 Subject: [PATCH 0057/1102] Account listing and sorting - account listing and sorting has now a common function to reuse - combobox send from is now sorted, Fixes #59 --- src/bitmessageqt/__init__.py | 73 +++++++++++++++--------------------- src/bitmessageqt/account.py | 7 ++++ 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 96b415ea..47979934 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -467,9 +467,7 @@ class MyForm(QtGui.QMainWindow): db = {} enabled = {} - for toAddress in shared.config.sections(): - if toAddress == 'bitmessagesettings': - continue + for toAddress in getSortedAccounts(): isEnabled = shared.config.getboolean( toAddress, 'enabled') isChan = shared.safeConfigGetBoolean( @@ -553,20 +551,18 @@ class MyForm(QtGui.QMainWindow): # Ask the user if we may delete their old version 1 addresses if they # have any. - 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() + 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: + 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 @@ -2184,15 +2180,14 @@ class MyForm(QtGui.QMainWindow): def rerenderComboBoxSendFrom(self): self.ui.comboBoxSendFrom.clear() - 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. - isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') - if isEnabled and not isMaillinglist: - self.ui.comboBoxSendFrom.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( - addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) + for addressInKeysFile in getSortedAccounts(): + 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. + isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + if isEnabled and not isMaillinglist: + self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), unicode(shared.config.get( + addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) +# self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder) self.ui.comboBoxSendFrom.insertItem(0, '', '') if(self.ui.comboBoxSendFrom.count() == 2): self.ui.comboBoxSendFrom.setCurrentIndex(1) @@ -2201,15 +2196,13 @@ class MyForm(QtGui.QMainWindow): def rerenderComboBoxSendFromBroadcast(self): self.ui.comboBoxSendFromBroadcast.clear() - 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. - isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') - if isEnabled and isMaillinglist: - self.ui.comboBoxSendFromBroadcast.insertItem(0, avatarize(addressInKeysFile), unicode(shared.config.get( - addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) + for addressInKeysFile in getSortedAccounts(): + 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. + isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') + if isEnabled and isMaillinglist: + self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), unicode(shared.config.get( + addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '') if(self.ui.comboBoxSendFromBroadcast.count() == 2): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1) @@ -2713,10 +2706,7 @@ class MyForm(QtGui.QMainWindow): def click_NewAddressDialog(self): addresses = [] - configSections = shared.config.sections() - for addressInKeysFile in configSections: - if addressInKeysFile == 'bitmessagesettings': - continue + for addressInKeysFile in getSortedAccounts(): addresses.append(addressInKeysFile) # self.dialog = Ui_NewAddressWizard(addresses) # self.dialog.exec_() @@ -4056,10 +4046,7 @@ class NewAddressDialog(QtGui.QDialog): row = 1 # Let's fill out the 'existing address' combo box with addresses from # the 'Your Identities' tab. - configSections = shared.config.sections() - for addressInKeysFile in configSections: - if addressInKeysFile == 'bitmessagesettings': - continue + for addressInKeysFile in getSortedAccounts(): self.ui.radioButtonExisting.click() self.ui.comboBoxExisting.addItem( addressInKeysFile) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 19212302..2342bcc5 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -10,6 +10,13 @@ from pyelliptic.openssl import OpenSSL from utils import str_broadcast_subscribers import time +def getSortedAccounts(): + configSections = filter(lambda x: x != 'bitmessagesettings', shared.config.sections()) + configSections.sort(cmp = + lambda x,y: cmp(unicode(shared.config.get(x, 'label'), 'utf-8').lower(), unicode(shared.config.get(y, 'label'), 'utf-8').lower()) + ) + return configSections + def accountClass(address): if not shared.config.has_section(address): if address == str_broadcast_subscribers: -- 2.45.1 From 705ffacd8b87413e1af2e8b454f4adec6c9731a6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 20:17:28 +0200 Subject: [PATCH 0058/1102] Changing label updates SendFrom combobox Fixes #2 --- src/bitmessageqt/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 47979934..e657cd8d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3548,6 +3548,10 @@ class MyForm(QtGui.QMainWindow): shared.config.set(str(item.address), 'label', newLabel) item.updateText() shared.writeKeysFile() + if item.type == 'mailinglist': + self.rerenderComboBoxSendFromBroadcast() + else: + self.rerenderComboBoxSendFrom() self.recurDepth -= 1 def tableWidgetInboxItemClicked(self): -- 2.45.1 From 3566b82c9f25eeb94bdb5db900d07420ad3850c0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 21:12:10 +0200 Subject: [PATCH 0059/1102] Special address behaviour updates send comboboxes Fixes #57 --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e657cd8d..f1bfb400 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2672,6 +2672,8 @@ class MyForm(QtGui.QMainWindow): shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str( self.dialog.ui.lineEditMailingListName.text().toUtf8())) self.setCurrentItemColor(QtGui.QColor(137, 04, 177)) #magenta + self.rerenderComboBoxSendFrom() + self.rerenderComboBoxSendFromBroadcast() shared.writeKeysFile() self.rerenderInboxToLabels() -- 2.45.1 From 7625b4f101c3fe088823b71a0a2feb90585fdd39 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 21:26:46 +0200 Subject: [PATCH 0060/1102] Version bump Just for development --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index a51a2017..e24fd10d 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.4.5.3' +softwareVersion = '0.5.0' 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. -- 2.45.1 From f47d28bb5941afbf7c94429182eca2832b54e271 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 21:30:38 +0200 Subject: [PATCH 0061/1102] There will not be a Mailchuck PyBitmessage anymore Since I'm merging my fork into normal pybitmessage, there won't be separate configs. --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f1bfb400..a89434f6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3631,7 +3631,7 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage(data) def readSettings(self): - settings = QSettings("Mailchuck Ltd.", "PyBitmessage") + settings = QSettings("Bitmessage", "PyBitmessage") try: geom = settings.value("geometry") self.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom) -- 2.45.1 From 3ffea81d02cc8fa4db9ad2f8532ca8c04351cadf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 22:02:09 +0200 Subject: [PATCH 0062/1102] No more Mailchuck Pybitmessage 2nd Last commit only changed loading, this also saving. --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a89434f6..ea16a045 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2758,7 +2758,7 @@ class MyForm(QtGui.QMainWindow): if self.mmapp is not None: self.mmapp.unregister() - settings = QSettings("Mailchuck Ltd.", "PyBitmessage") + settings = QSettings("Bitmessage", "PyBitmessage") settings.setValue("geometry", self.saveGeometry()) settings.setValue("state", self.saveState()) -- 2.45.1 From 2ec04ede404dda61fc05be13a16dc87491d3bf6d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 22:33:18 +0200 Subject: [PATCH 0063/1102] Passive version check Bitmessage will now notify you if it encounters someone with a newer version. Takes into account that it should not recommend switching from stable to unstable and vice versa. Also, temporarily treats 0.5 as a mailchuck fork. Fixes #43 --- src/bitmessageqt/__init__.py | 29 +++++++++++++++++++++++++++++ src/class_receiveDataThread.py | 11 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ea16a045..2b994dd7 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -718,6 +718,8 @@ class MyForm(QtGui.QMainWindow): "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid) + QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( + "newVersionAvailable(PyQt_PyObject)"), self.newVersionAvailable) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "displayAlert(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.displayAlert) self.UISignalThread.start() @@ -1816,6 +1818,31 @@ class MyForm(QtGui.QMainWindow): inbox.removeRow(i) break self.changedInboxUnread() + + def newVersionAvailable(self, version): +# if (not (self.windowState() & QtCore.Qt.WindowActive)) or (self.windowState() & QtCore.Qt.WindowMinimized): +# print "SHIIIIIIIIIIIIIIIIT" +# return + # only notify once until next restart + try: + if self.notifiedNewVersion: + return + except AttributeError: + pass + + self.notifiedNewVersion = ".".join(str(n) for n in version) + message = "New " + if version[1] % 2: + message += "UNSTABLE" + else: + message += "stable" + message += " version of PyBitmessage is available: " + self.notifiedNewVersion + ". Download it from https://github.com/" + if version[0] == 0 and version[1] == 5: + message += "mailchuck" + else: + message += "Bitmessage" + message += "/PyBitmessage/releases/latest" + self.displayAlert("New release of PyBitmessage available", message, False) def displayAlert(self, title, text, exitAfterUserClicksOk): self.statusBar().showMessage(text) @@ -4147,6 +4174,8 @@ class UISignaler(QThread): 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) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index ff5371ad..07569b7b 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -698,6 +698,17 @@ class receiveDataThread(threading.Thread): data[80:84]) readPosition = 80 + lengthOfUseragentVarint useragent = data[readPosition:readPosition + useragentLength] + + # version check + userAgentName, userAgentVersion = useragent[1:-1].split(":") + if userAgentName == "PyBitmessage": + myVersion = [int(n) for n in shared.softwareVersion.split(".")] + remoteVersion = [int(n) for n in userAgentVersion.split(".")] + # remote is newer, but do not cross between stable and unstable + if cmp(remoteVersion, myVersion) > 0 and \ + (myVersion[1] % 2 == remoteVersion[1] % 2): + shared.UISignalQueue.put(('newVersionAvailable', remoteVersion)) + readPosition += useragentLength numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( data[readPosition:]) -- 2.45.1 From ab113745bd829aa5fe34477954a2c9232c5bcffe Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 19 Oct 2015 22:36:30 +0200 Subject: [PATCH 0064/1102] Remove expletive That wasn't necessary. --- src/bitmessageqt/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2b994dd7..ffa0c21d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1821,7 +1821,6 @@ class MyForm(QtGui.QMainWindow): def newVersionAvailable(self, version): # if (not (self.windowState() & QtCore.Qt.WindowActive)) or (self.windowState() & QtCore.Qt.WindowMinimized): -# print "SHIIIIIIIIIIIIIIIIT" # return # only notify once until next restart try: -- 2.45.1 From 55b69f2e8bd3de7e04fcce2ca0b3be766c54b9b0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 22 Oct 2015 23:16:44 +0200 Subject: [PATCH 0065/1102] Fix keypress in chan and subscription messagelists Fixes #65 --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ffa0c21d..685af485 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1414,7 +1414,7 @@ class MyForm(QtGui.QMainWindow): def tableWidgetInboxKeyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Delete: self.on_action_InboxTrash() - return QtGui.QTableWidget.keyPressEvent(self.ui.tableWidgetInbox, event) + return QtGui.QTableWidget.keyPressEvent(self.getCurrentMessagelist(), event) # menu button 'manage keys' def click_actionManageKeys(self): -- 2.45.1 From f6bd312dc5506f365852ed9fa23c1bec8e456a2b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 22 Oct 2015 23:56:20 +0200 Subject: [PATCH 0066/1102] New message in correct tab Newly arriving messages now appear in the correct tab. Previously it assumed it was always "Messages" tab. Partially addresses #3. --- src/bitmessageqt/__init__.py | 77 ++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 685af485..097d8c29 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2240,31 +2240,33 @@ class MyForm(QtGui.QMainWindow): # 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): - if self.getCurrentFolder() != "sent" or self.getCurrentAccount() != fromAddress: - return subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) acct = accountClass(fromAddress) acct.parseMessage(toAddress, fromAddress, subject, message) + sent = self.getAccountMessagelist(acct) + treeWidget = self.getAccountTreeWidget(acct) + if self.getCurrentFolder(treeWidget) != "sent" or self.getCurrentAccount(treeWidget) != fromAddress: + return - self.ui.tableWidgetInbox.setSortingEnabled(False) - self.ui.tableWidgetInbox.insertRow(0) + sent.setSortingEnabled(False) + sent.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(toAddress)) newItem.setIcon(avatarize(toAddress)) - self.ui.tableWidgetInbox.setItem(0, 0, newItem) + sent.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setIcon(avatarize(fromAddress)) - self.ui.tableWidgetInbox.setItem(0, 1, newItem) + sent.setItem(0, 1, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) newItem.setToolTip(unicode(acct.subject, 'utf-8)')) newItem.setData(Qt.UserRole, str(subject)) #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.tableWidgetInbox.setItem(0, 2, newItem) + sent.setItem(0, 2, newItem) # newItem = QtGui.QTableWidgetItem('Doing work necessary to send # broadcast...'+ # l10n.formatTimestamp()) @@ -2272,18 +2274,18 @@ class MyForm(QtGui.QMainWindow): 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.tableWidgetInbox.setItem(0, 3, newItem) - self.ui.textEditInboxMessage.setPlainText(unicode(message, 'utf-8)')) - self.ui.tableWidgetInbox.setSortingEnabled(True) + sent.setItem(0, 3, newItem) + self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)')) + sent.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): - if (self.getCurrentFolder() != "inbox" and self.getCurrentFolder() != False) or self.getCurrentAccount() != toAddress: - return subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct = accountClass(toAddress) acct.parseMessage(toAddress, fromAddress, subject, message) - - inbox = self.getCurrentMessagelist() + inbox = self.getAccountMessagelist(acct) + treeWidget = self.getAccountTreeWidget(acct) + if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != toAddress: + return font = QFont() font.setBold(True) @@ -3266,6 +3268,17 @@ class MyForm(QtGui.QMainWindow): else: return False + def getAccountTreeWidget(self, account): + try: + if account.type == 'chan': + return self.ui.treeWidgetChans + elif account.type == 'subscription': + return self.ui.treeWidgetSubscriptions + else: + return self.ui.treeWidgetYourIdentities + except: + return self.ui.treeWidgetYourIdentities + def getCurrentMessagelist(self): currentIndex = self.ui.tabWidget.currentIndex(); messagelistList = [ @@ -3278,6 +3291,17 @@ class MyForm(QtGui.QMainWindow): return messagelistList[currentIndex] else: return False + + def getAccountMessagelist(self, account): + try: + if account.type == 'chan': + return self.ui.tableWidgetInboxChans + elif account.type == 'subscription': + return self.ui.tableWidgetInboxSubscriptions + else: + return self.ui.tableWidgetInbox + except: + return self.ui.tableWidgetInbox def getCurrentMessageId(self): messagelist = self.getCurrentMessagelist() @@ -3302,6 +3326,17 @@ class MyForm(QtGui.QMainWindow): else: return False + def getAccountTextedit(self, account): + try: + if account.type == 'chan': + return self.ui.textEditInboxMessageChans + elif account.type == 'subscription': + return self.ui.textEditInboxSubscriptions + else: + return self.ui.textEditInboxMessage + except: + return self.ui.textEditInboxMessage + def getCurrentSearchLine(self): currentIndex = self.ui.tabWidget.currentIndex(); messagelistList = [ @@ -3329,16 +3364,17 @@ class MyForm(QtGui.QMainWindow): return False # Group of functions for the Your Identities dialog box - def getCurrentItem(self): - treeWidget = self.getCurrentTreeWidget() + 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): - currentItem = self.getCurrentItem() + def getCurrentAccount(self, treeWidget = None): + currentItem = self.getCurrentItem(treeWidget) if currentItem: account = currentItem.address return account @@ -3346,8 +3382,9 @@ class MyForm(QtGui.QMainWindow): # TODO need debug msg? return False - def getCurrentFolder(self): - treeWidget = self.getCurrentTreeWidget() + def getCurrentFolder(self, treeWidget = None): + if treeWidget is None: + treeWidget = self.getCurrentTreeWidget() #treeWidget = self.ui.treeWidgetYourIdentities if treeWidget: currentItem = treeWidget.currentItem() -- 2.45.1 From 1d86f7a69925cc0800681da98447c0bd79361298 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 23 Oct 2015 07:07:38 +0200 Subject: [PATCH 0067/1102] Put mailing lists behind normal accounts Fixes #58 --- src/bitmessageqt/foldertree.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 59e2b963..71caae66 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -132,16 +132,21 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): reverse = False if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True - if shared.config.getboolean(self.address, 'enabled') == shared.config.getboolean(other.address, 'enabled'): - if shared.config.get(self.address, 'label'): - x = shared.config.get(self.address, 'label').decode('utf-8').lower() + if shared.config.getboolean(self.address, 'enabled') == \ + shared.config.getboolean(other.address, 'enabled'): + if shared.safeConfigGetBoolean(self.address, 'mailinglist') == \ + shared.safeConfigGetBoolean(other.address, 'mailinglist'): + if shared.config.get(self.address, 'label'): + x = shared.config.get(self.address, 'label').decode('utf-8').lower() + else: + x = self.address.decode('utf-8').lower() + if shared.config.get(other.address, 'label'): + y = shared.config.get(other.address, 'label').decode('utf-8').lower() + else: + y = other.address.decode('utf-8').lower() + return x < y else: - x = self.address.decode('utf-8').lower() - if shared.config.get(other.address, 'label'): - y = shared.config.get(other.address, 'label').decode('utf-8').lower() - else: - y = other.address.decode('utf-8').lower() - return x < y + return (reverse if shared.safeConfigGetBoolean(self.address, 'mailinglist') else not reverse) # else: return (not reverse if shared.config.getboolean(self.address, 'enabled') else reverse) -- 2.45.1 From 39dc34b158afdec57403b73bebc7dbea9b91835d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 23 Oct 2015 12:38:59 +0200 Subject: [PATCH 0068/1102] Sent folder for chans and subscriptions Fixes #53 --- src/bitmessageqt/__init__.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 097d8c29..2b217995 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -416,7 +416,7 @@ class MyForm(QtGui.QMainWindow): def rerenderTabTreeSubscriptions(self): treeWidget = self.ui.treeWidgetSubscriptions - folders = ['inbox', 'trash'] + folders = ['inbox', 'sent', 'trash'] treeWidget.clear() treeWidget.setSortingEnabled(False) treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) @@ -455,10 +455,9 @@ class MyForm(QtGui.QMainWindow): def rerenderTabTree(self, tab): if tab == 'messages': treeWidget = self.ui.treeWidgetYourIdentities - folders = ['inbox', 'sent', 'trash'] elif tab == 'chan': treeWidget = self.ui.treeWidgetChans - folders = ['inbox', 'trash'] + folders = ['inbox', 'sent', 'trash'] # sort ascending when creating if treeWidget.topLevelItemCount() == 0: @@ -888,10 +887,15 @@ class MyForm(QtGui.QMainWindow): tableWidget.setColumnHidden(0, False) tableWidget.setColumnHidden(1, True) tableWidget.setSortingEnabled(False) - + + if tableWidget == self.ui.tableWidgetInboxChans or tableWidget == self.ui.tableWidgetInboxSubscriptions: + xAddress = 'toaddress' + else: + xAddress = 'fromaddress' + sqlStatement = ''' SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime - FROM sent WHERE fromaddress=? AND folder="sent" AND %s LIKE ? + FROM sent WHERE ''' + xAddress + '''=? AND folder="sent" AND %s LIKE ? ORDER BY lastactiontime ''' % (where,) -- 2.45.1 From 2cc7506619a7dad3b4fa7bdf15bee9d752f0d512 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 23 Oct 2015 19:14:01 +0200 Subject: [PATCH 0069/1102] Addressbook contains chans, subscriptions and is sorted Fixes #5 --- src/bitmessageqt/__init__.py | 36 ++++++++++++++++++++------ src/bitmessageqt/foldertree.py | 46 +++++++++++++++++++++++++++++++++- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2b217995..acd0ea6d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1951,18 +1951,38 @@ class MyForm(QtGui.QMainWindow): 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) + + self.ui.tableWidgetAddressBook.setSortingEnabled(False) self.ui.tableWidgetAddressBook.setRowCount(0) + + # subscriptions + queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1') + for row in queryreturn: + label, address = row + addRow(address, label, 'subscription') + + # chans + addresses = getSortedAccounts() + for address in addresses: + account = accountClass(address) + if (account.type == 'chan'): + addRow(address, account.getLabel(), 'chan') + + # normal accounts queryreturn = sqlQuery('SELECT * FROM addressbook') for row in queryreturn: label, address = row - 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) + addRow(address, label, 'normal') + + # sort + self.ui.tableWidgetAddressBook.sortItems(0, QtCore.Qt.AscendingOrder) + self.ui.tableWidgetAddressBook.setSortingEnabled(True) def rerenderSubscriptions(self): self.rerenderTabTreeSubscriptions() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 71caae66..08cd7ff2 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -238,4 +238,48 @@ class Ui_SubscriptionWidget(Ui_AddressWidget): # else: return (not reverse if self.isEnabled else reverse) - return super(QtGui.QTreeWidgetItem, self).__lt__(other) \ No newline at end of file + return super(QtGui.QTreeWidgetItem, self).__lt__(other) + +class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem): + _types = {'normal': 0, 'chan': 1, 'subscription': 2} + + def __init__ (self, text, type = 'normal'): + super(QtGui.QTableWidgetItem, self).__init__(text) + self.label = text + try: + self.type = self._types[type] + except: + self.type = 0 + if self.type == 2: + brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) + elif self.type == 1: + brush = QtGui.QBrush(QtGui.QColor(216, 119, 0)) + else: + return + brush.setStyle(QtCore.Qt.NoBrush) + self.setForeground(brush) + + 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.decode('utf-8').lower() < other.label.decode('utf-8').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.label = label + self.setIcon(avatarize(address)) + + +class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): + def __init__ (self, address, label, type): + Ui_AddressBookWidgetItem.__init__(self, address, type) + self.label = label + self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) \ No newline at end of file -- 2.45.1 From 4522ea46d3e8a61172cc40620858e0596e017462 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 23 Oct 2015 19:23:16 +0200 Subject: [PATCH 0070/1102] Sent in chans and subscriptions columns Now it shows "from" instead of "to" column when selecting sent folder in subscriptions or chans. Fixes #53 --- src/bitmessageqt/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index acd0ea6d..a5ee6fdb 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -883,14 +883,15 @@ class MyForm(QtGui.QMainWindow): else: where = "toaddress || fromaddress || subject || message" - - tableWidget.setColumnHidden(0, False) - tableWidget.setColumnHidden(1, True) tableWidget.setSortingEnabled(False) if tableWidget == self.ui.tableWidgetInboxChans or tableWidget == self.ui.tableWidgetInboxSubscriptions: + tableWidget.setColumnHidden(0, True) + tableWidget.setColumnHidden(1, False) xAddress = 'toaddress' else: + tableWidget.setColumnHidden(0, False) + tableWidget.setColumnHidden(1, True) xAddress = 'fromaddress' sqlStatement = ''' -- 2.45.1 From 1c4015d359ea20b90d9a631d5c3aafe0cc2281fd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 27 Oct 2015 17:41:04 +0100 Subject: [PATCH 0071/1102] Spanish wrongly spelled Fixes #74 --- src/bitmessageqt/settings.py | 2 +- src/bitmessageqt/settings.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 6d854773..b9131315 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -92,7 +92,7 @@ class Ui_settingsDialog(object): self.languageComboBox.addItem(_fromUtf8("")) self.languageComboBox.setItemText(4, _fromUtf8("Deutsch")) self.languageComboBox.addItem(_fromUtf8("")) - self.languageComboBox.setItemText(5, _fromUtf8("Españl")) + self.languageComboBox.setItemText(5, _fromUtf8("Español")) self.languageComboBox.addItem(_fromUtf8("")) self.languageComboBox.setItemText(6, _fromUtf8("русский")) self.languageComboBox.addItem(_fromUtf8("")) diff --git a/src/bitmessageqt/settings.ui b/src/bitmessageqt/settings.ui index a41d7e4e..475821f8 100644 --- a/src/bitmessageqt/settings.ui +++ b/src/bitmessageqt/settings.ui @@ -153,7 +153,7 @@ - Españl + Español -- 2.45.1 From 77382a2424495c22241806ac0458b19861de2f3a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 27 Oct 2015 19:24:29 +0100 Subject: [PATCH 0072/1102] Refactoring foldertree Colors consistent Sorting more consistent Deduplication of methods Context menu enable/disable affects tree Fixes #73 --- src/bitmessageqt/__init__.py | 14 +-- src/bitmessageqt/foldertree.py | 159 +++++++++++++++------------------ 2 files changed, 82 insertions(+), 91 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a5ee6fdb..f651426f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -529,7 +529,7 @@ class MyForm(QtGui.QMainWindow): i = 0 for toAddress in db: - widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"]) + widget = Ui_AddressWidget(treeWidget, i, toAddress, db[toAddress]["inbox"], enabled[toAddress]) j = 0 unread = 0 for folder in folders: @@ -3202,7 +3202,8 @@ class MyForm(QtGui.QMainWindow): sqlExecute( '''update subscriptions set enabled=1 WHERE address=?''', address) - self.setCurrentItemColor(QApplication.palette().text().color()) + account = self.getCurrentItem() + account.setEnabled(True) shared.reloadBroadcastSendersForWhichImWatching() def on_action_SubscriptionsDisable(self): @@ -3210,7 +3211,8 @@ class MyForm(QtGui.QMainWindow): sqlExecute( '''update subscriptions set enabled=0 WHERE address=?''', address) - self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) + account = self.getCurrentItem() + account.setEnabled(False) shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): @@ -3434,7 +3436,8 @@ class MyForm(QtGui.QMainWindow): def on_action_Enable(self): addressAtCurrentRow = self.getCurrentAccount() self.enableIdentity(addressAtCurrentRow) - self.setCurrentItemColor(QApplication.palette().text().color()) + account = self.getCurrentItem() + account.setEnabled(True) def enableIdentity(self, address): shared.config.set(address, 'enabled', 'true') @@ -3444,7 +3447,8 @@ class MyForm(QtGui.QMainWindow): def on_action_Disable(self): address = self.getCurrentAccount() self.disableIdentity(address) - self.setCurrentItemColor(QtGui.QColor(128, 128, 128)) + account = self.getCurrentItem() + account.setEnabled(False) def disableIdentity(self, address): shared.config.set(str(address), 'enabled', 'false') diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 08cd7ff2..fd4bb9e8 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -3,15 +3,16 @@ from PyQt4 import QtCore, QtGui from utils import * import shared -class Ui_FolderWidget(QtGui.QTreeWidgetItem): - folderWeight = {"inbox": 1, "sent": 2, "trash": 3} - def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0): - super(QtGui.QTreeWidgetItem, self).__init__() - self.address = address - self.folderName = folderName - self.unreadCount = unreadCount - parent.insertChild(pos, self) - self.updateText() +class AccountMixin (object): + def accountColor (self): + if not self.isEnabled: + return QtGui.QBrush(QtGui.QColor(128, 128, 128)) + elif self.type == "chan": + return QtGui.QBrush(QtGui.QColor(216, 119, 0)) + elif self.type == "mailinglist" or self.type == "subscription": + return QtGui.QBrush(QtGui.QColor(137, 04, 177)) + else: + return QtGui.QBrush(QtGui.QApplication.palette().text().color()) def setAddress(self, address): self.address = str(address) @@ -21,11 +22,41 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem): self.unreadCount = int(cnt) self.updateText() + def setEnabled(self, enabled): + self.isEnabled = enabled + self.updateText() + + def setType(self): + if shared.safeConfigGetBoolean(self.address, 'chan'): + self.type = "chan" + elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + self.type = "mailinglist" + else: + self.type = "normal" + + def updateText(self): + pass + + +class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): + folderWeight = {"inbox": 1, "sent": 2, "trash": 3} + def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0): + super(QtGui.QTreeWidgetItem, self).__init__() + self.initialised = False + self.setAddress(address) + self.setFolderName(folderName) + self.setUnreadCount(unreadCount) + self.initialised = True + self.updateText() + parent.insertChild(pos, self) + def setFolderName(self, fname): self.folderName = str(fname) self.updateText() def updateText(self): + if not self.initialised: + return text = QtGui.QApplication.translate("MainWindow", self.folderName) font = QtGui.QFont() if self.unreadCount > 0: @@ -60,34 +91,23 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem): return super(QtGui.QTreeWidgetItem, self).__lt__(other) -class Ui_AddressWidget(QtGui.QTreeWidgetItem): - def __init__(self, parent, pos = 0, address = "", unreadCount = 0): +class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): + def __init__(self, parent, pos = 0, address = "", unreadCount = 0, enabled = True): super(QtGui.QTreeWidgetItem, self).__init__() - self.unreadCount = unreadCount parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) + self.initialised = False self.setAddress(address) - - def setAddress(self, address): - self.address = str(address) + self.setEnabled(enabled) + self.setUnreadCount(unreadCount) self.setType() - self.setExpanded(shared.safeConfigGetBoolean(self.address, 'enabled')) - self.updateText() - - def setType(self): - if shared.safeConfigGetBoolean(self.address, 'chan'): - self.type = "chan" - elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): - self.type = "mailinglist" - else: - self.type = "normal" + self.initialised = True + self.setExpanded(enabled) # does updateText - def setUnreadCount(self, cnt): - self.unreadCount = int(cnt) - self.updateText() - def updateText(self): + if not self.initialised: + return text = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' font = QtGui.QFont() @@ -101,15 +121,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): self.setFont(0, font) #set text color - if shared.safeConfigGetBoolean(self.address, 'enabled'): - if shared.safeConfigGetBoolean(self.address, 'mailinglist'): - brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) - else: - brush = QtGui.QBrush(QtGui.QApplication.palette().text().color()) - #self.setExpanded(True) - else: - brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - #self.setExpanded(False) + brush = self.accountColor() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(0, brush) @@ -132,10 +144,8 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): reverse = False if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True - if shared.config.getboolean(self.address, 'enabled') == \ - shared.config.getboolean(other.address, 'enabled'): - if shared.safeConfigGetBoolean(self.address, 'mailinglist') == \ - shared.safeConfigGetBoolean(other.address, 'mailinglist'): + if self.isEnabled == other.isEnabled: + if self.type == other.type: if shared.config.get(self.address, 'label'): x = shared.config.get(self.address, 'label').decode('utf-8').lower() else: @@ -146,44 +156,37 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem): y = other.address.decode('utf-8').lower() return x < y else: - return (reverse if shared.safeConfigGetBoolean(self.address, 'mailinglist') else not reverse) + return (reverse if self.type == "mailinglist" else not reverse) # else: - return (not reverse if shared.config.getboolean(self.address, 'enabled') else reverse) + return (not reverse if self.isEnabled else reverse) return super(QtGui.QTreeWidgetItem, self).__lt__(other) -class Ui_SubscriptionWidget(Ui_AddressWidget): - def __init__(self, parent, pos = 0, address = "", unreadCount = 0, label = "", enabled = ""): +class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): + def __init__(self, parent, pos = 0, address = "", unreadCount = 0, label = "", enabled = True): super(QtGui.QTreeWidgetItem, self).__init__() - self.unreadCount = unreadCount parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) - self.setEnabled(enabled) - self.setLabel(label) + self.initialised = False self.setAddress(address) + self.setEnabled(enabled) + self.setType() + self.setLabel(label) + self.setUnreadCount (unreadCount) + self.initialised = True + self.setExpanded(enabled) # does updateText def setLabel(self, label): self.label = label - def setAddress(self, address): - self.address = str(address) - self.setType() - self.setExpanded(self.isEnabled) - self.updateText() - - def setEnabled(self, enabled): - self.isEnabled = enabled - def setType(self): self.type = "subscription" - def setUnreadCount(self, cnt): - self.unreadCount = int(cnt) - self.updateText() - def updateText(self): + if not self.initialised: + return text = unicode(self.label, 'utf-8)') + ' (' + self.address + ')' font = QtGui.QFont() @@ -197,12 +200,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget): self.setFont(0, font) #set text color - if self.isEnabled: - brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) - #self.setExpanded(True) - else: - brush = QtGui.QBrush(QtGui.QColor(128, 128, 128)) - #self.setExpanded(False) + brush = self.accountColor() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(0, brush) @@ -211,14 +209,6 @@ class Ui_SubscriptionWidget(Ui_AddressWidget): self.setToolTip(0, text) # self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) - def setExpanded(self, expand): - super(Ui_SubscriptionWidget, self).setExpanded(expand) - self.updateText() - - def edit(self): - self.setText(0, self.label) - super(QtGui.QAbstractItemView, self).edit() - # label (or address) alphabetically, disabled at the end def __lt__(self, other): if (isinstance(other, Ui_SubscriptionWidget)): @@ -240,22 +230,19 @@ class Ui_SubscriptionWidget(Ui_AddressWidget): return super(QtGui.QTreeWidgetItem, self).__lt__(other) -class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem): +class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): _types = {'normal': 0, 'chan': 1, 'subscription': 2} def __init__ (self, text, type = 'normal'): super(QtGui.QTableWidgetItem, self).__init__(text) self.label = text + self.type = type try: - self.type = self._types[type] + self.typeNum = self._types[self.type] except: self.type = 0 - if self.type == 2: - brush = QtGui.QBrush(QtGui.QColor(137, 04, 177)) - elif self.type == 1: - brush = QtGui.QBrush(QtGui.QColor(216, 119, 0)) - else: - return + self.setEnabled(True) + brush = self.accountColor() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(brush) @@ -264,10 +251,10 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem): reverse = False if self.tableWidget().horizontalHeader().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True - if self.type == other.type: + if self.typeNum == other.typeNum: return self.label.decode('utf-8').lower() < other.label.decode('utf-8').lower() else: - return (not reverse if self.type < other.type else reverse) + return (not reverse if self.typeNum < other.typeNum else reverse) return super(QtGui.QTableWidgetItem, self).__lt__(other) -- 2.45.1 From 63431556be8f28f5928eb4aae8f9c313bc3d0bfd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 27 Oct 2015 19:50:52 +0100 Subject: [PATCH 0073/1102] Make subscription/chan labels editable Fixes #67 --- src/bitmessageqt/__init__.py | 28 +++++++++++++++++++++------- src/bitmessageqt/foldertree.py | 4 ++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f651426f..824c8cf8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -444,6 +444,8 @@ class MyForm(QtGui.QMainWindow): newSubItem = Ui_FolderWidget(newItem, 0, address, folder, 0) newItem.setUnreadCount(unread) + newItem.setFlags (newItem.flags() | QtCore.Qt.ItemIsEditable) + treeWidget.setSortingEnabled(True) def rerenderTabTreeMessages(self): @@ -537,8 +539,7 @@ class MyForm(QtGui.QMainWindow): unread += db[toAddress][folder] j += 1 widget.setUnreadCount(unread) - if (tab == 'messages'): - widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) + widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) i += 1 treeWidget.setSortingEnabled(True) @@ -658,8 +659,12 @@ class MyForm(QtGui.QMainWindow): "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) # Put the colored icon on the status bar # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) @@ -3615,7 +3620,7 @@ class MyForm(QtGui.QMainWindow): if column != 0: return # only account names of normal addresses (no chans/mailinglists) - if (not isinstance(item, Ui_AddressWidget)) or item.type != 'normal' or not self.getCurrentTreeWidget() or self.getCurrentTreeWidget().currentItem() is None: + 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)): @@ -3627,7 +3632,10 @@ class MyForm(QtGui.QMainWindow): newLabel = str(item.text(0)) newLabel = newLabel.replace("(" + str(item.address) + ")", '') newLabel = newLabel.rstrip() - oldLabel = shared.config.get(str(item.address), 'label') + if item.type == "subscription": + oldLabel = item.label + else: + oldLabel = shared.config.get(str(item.address), 'label') oldLabel = oldLabel.replace("(" + str(item.address) + ")", '') oldLabel = oldLabel.rstrip() # unchanged, do not do anything either @@ -3639,12 +3647,18 @@ class MyForm(QtGui.QMainWindow): return self.recurDepth += 1 - shared.config.set(str(item.address), 'label', newLabel) + if item.type == "subscription": + sqlExecute( + '''UPDATE subscriptions SET label=? WHERE address=?''', + newLabel, item.address) + item.setLabel(newLabel) + else: + shared.config.set(str(item.address), 'label', newLabel) + shared.writeKeysFile() item.updateText() - shared.writeKeysFile() if item.type == 'mailinglist': self.rerenderComboBoxSendFromBroadcast() - else: + elif item.type != "subscription": self.rerenderComboBoxSendFrom() self.recurDepth -= 1 diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index fd4bb9e8..cb8b2c81 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -183,6 +183,10 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setType(self): self.type = "subscription" + + def edit(self): + self.setText(0, self.label) + super(QtGui.QAbstractItemView, self).edit() def updateText(self): if not self.initialised: -- 2.45.1 From 6383f48ef2b588b3c3f3ae885159e0b4f3c03543 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 27 Oct 2015 20:03:46 +0100 Subject: [PATCH 0074/1102] Show tooltips on addressbook Fixes #68 --- src/bitmessageqt/foldertree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index cb8b2c81..f49b1d6d 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -265,12 +265,12 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): Ui_AddressBookWidgetItem.__init__(self, label, type) - self.label = label self.setIcon(avatarize(address)) + self.setToolTip(label + " (" + address + ")") class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): Ui_AddressBookWidgetItem.__init__(self, address, type) - self.label = label - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) \ No newline at end of file + self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.setToolTip(label + " (" + address + ")") \ No newline at end of file -- 2.45.1 From 9abc937cb3ad97bbe1ecfcac1998108a8c7441e1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 10:12:12 +0100 Subject: [PATCH 0075/1102] More unified colors in foldertree and messagelists Some parts still not colored in a unified way. Fixes #84 --- src/bitmessageqt/__init__.py | 10 ++++------ src/bitmessageqt/account.py | 19 +++++++++++++++++++ src/bitmessageqt/foldertree.py | 17 ++++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 824c8cf8..bfb71f14 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -921,6 +921,7 @@ class MyForm(QtGui.QMainWindow): toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8')) toAddressItem.setIcon(avatarize(toAddress)) toAddressItem.setData(Qt.UserRole, str(toAddress)) + toAddressItem.setTextColor(AccountColor(toAddress).accountColor()) toAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 0, toAddressItem) @@ -929,6 +930,7 @@ class MyForm(QtGui.QMainWindow): fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) fromAddressItem.setIcon(avatarize(fromAddress)) fromAddressItem.setData(Qt.UserRole, str(fromAddress)) + fromAddressItem.setTextColor(AccountColor(fromAddress).accountColor()) fromAddressItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) tableWidget.setItem(0, 1, fromAddressItem) @@ -1058,10 +1060,7 @@ class MyForm(QtGui.QMainWindow): 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.setTextColor(AccountColor(toAddress).accountColor()) to_item.setIcon(avatarize(toAddress)) tableWidget.setItem(0, 0, to_item) # from @@ -1072,8 +1071,7 @@ class MyForm(QtGui.QMainWindow): 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.setTextColor(AccountColor(fromAddress).accountColor()) from_item.setIcon(avatarize(fromAddress)) tableWidget.setItem(0, 1, from_item) # subject diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 2342bcc5..6e1083f6 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -6,6 +6,7 @@ import sys import inspect from helper_sql import * from addresses import decodeAddress +from foldertree import AccountMixin from pyelliptic.openssl import OpenSSL from utils import str_broadcast_subscribers import time @@ -41,6 +42,24 @@ def accountClass(address): # 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 shared.safeConfigGetBoolean(self.address, 'mailinglist'): + self.type = "mailinglist" + elif shared.safeConfigGetBoolean(self.address, 'chan'): + self.type = "chan" + elif sqlQuery( + '''select label from subscriptions where address=?''', self.address): + self.type = 'subscription' + else: + self.type = "normal" + else: + self.type = type + + class BMAccount(object): def __init__(self, address = None): self.address = address diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index f49b1d6d..e0ce72b8 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -6,13 +6,16 @@ import shared class AccountMixin (object): def accountColor (self): if not self.isEnabled: - return QtGui.QBrush(QtGui.QColor(128, 128, 128)) + return QtGui.QColor(128, 128, 128) elif self.type == "chan": - return QtGui.QBrush(QtGui.QColor(216, 119, 0)) + return QtGui.QColor(216, 119, 0) elif self.type == "mailinglist" or self.type == "subscription": - return QtGui.QBrush(QtGui.QColor(137, 04, 177)) + return QtGui.QColor(137, 04, 177) else: - return QtGui.QBrush(QtGui.QApplication.palette().text().color()) + return QtGui.QApplication.palette().text().color() + + def accountBrush(self): + return QtGui.QBrush(self.accountColor()) def setAddress(self, address): self.address = str(address) @@ -121,7 +124,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): self.setFont(0, font) #set text color - brush = self.accountColor() + brush = self.accountBrush() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(0, brush) @@ -204,7 +207,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): self.setFont(0, font) #set text color - brush = self.accountColor() + brush = self.accountBrush() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(0, brush) @@ -246,7 +249,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): except: self.type = 0 self.setEnabled(True) - brush = self.accountColor() + brush = self.accountBrush() brush.setStyle(QtCore.Qt.NoBrush) self.setForeground(brush) -- 2.45.1 From 7478440bd686839bd6d8c3b6695537c53e1ee981 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 15:27:07 +0100 Subject: [PATCH 0076/1102] Update unread count more efficiently Fixes #63. There are still some situations which can be improved but it appears good enough. --- src/bitmessageqt/__init__.py | 84 ++++++++++++++++++++++++++-------- src/bitmessageqt/foldertree.py | 7 ++- src/helper_inbox.py | 3 +- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index bfb71f14..740a7bc3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -594,7 +594,7 @@ class MyForm(QtGui.QMainWindow): # switch back to this when replying self.replyFromTab = None - + self.init_file_menu() self.init_inbox_popup_menu() self.init_identities_popup_menu() @@ -675,6 +675,7 @@ class MyForm(QtGui.QMainWindow): self.numberOfMessagesProcessed = 0 self.numberOfBroadcastsProcessed = 0 self.numberOfPubkeysProcessed = 0 + self.unreadCount = 0 # Set the icon sizes for the identicons identicon_size = 3*7 @@ -873,6 +874,49 @@ class MyForm(QtGui.QMainWindow): def appIndicatorChannel(self): self.appIndicatorShow() self.ui.tabWidget.setCurrentIndex(3) + + def propagateUnreadCount(self, address = None, folder = "inbox", widget = None, type = 1): + def updateUnreadCount(item, type = 1): + if type == 1: + item.setUnreadCount(item.unreadCount + 1) + if isinstance(item, Ui_AddressWidget): + self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount + 1)) + elif type == -1: + item.setUnreadCount(item.unreadCount - 1) + if isinstance(item, Ui_AddressWidget): + self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) + else: + if address and folder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE toaddress = ? AND folder = ? AND read = 0", address, folder) + elif address: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE toaddress = ? AND read = 0", address) + elif folder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", folder) + else: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") + for row in queryreturn: + item.setUnreadCount(int(row[0])) + if isinstance(item, Ui_AddressWidget): + self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) + + if widget == None: + widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] + else: + widgets = [widget] + for treeWidget in widgets: + root = treeWidget.invisibleRootItem() + for i in range(root.childCount()): + addressItem = root.child(i) + if address is not None and addressItem.data(0, QtCore.Qt.UserRole) != address: + continue + updateUnreadCount(addressItem, type) + if addressItem.childCount == 0: + continue + for j in range(addressItem.childCount()): + folderItem = addressItem.child(j) + if folder is not None and folderItem.data(0, QtCore.Qt.UserRole) != folder: + continue + updateUnreadCount(folderItem, type) # Load Sent items from database def loadSent(self, tableWidget, account, where="", what=""): @@ -1765,19 +1809,19 @@ class MyForm(QtGui.QMainWindow): def changedInboxUnread(self, row = None): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) self.rerenderTabTreeMessages() -# if not row is None: -# row[1], row[6] - if self.ui.tabWidget.currentIndex() == 2: - self.rerenderTabTreeSubscriptions() - elif self.ui.tabWidget.currentIndex() == 3: - self.rerenderTabTreeChans() + self.rerenderTabTreeSubscriptions() + self.rerenderTabTreeChans() - 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 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 updateSentItemStatusByHash(self, toRipe, textToDisplay): for i in range(self.ui.tableWidgetInbox.rowCount()): @@ -1818,14 +1862,15 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing - inbox = self.getCurrentMessagelist + inbox = self.getCurrentMessagelist() for i in range(inbox.rowCount()): if msgid == str(inbox.item(i, 3).data(Qt.UserRole).toPyObject()): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) inbox.removeRow(i) break - self.changedInboxUnread() + # this is a callback from core, not initiated by UI. We don't care about performance + self.propagateUnreadCount(None, None, None, 0) def newVersionAvailable(self, version): # if (not (self.windowState() & QtCore.Qt.WindowActive)) or (self.windowState() & QtCore.Qt.WindowMinimized): @@ -2312,6 +2357,8 @@ class MyForm(QtGui.QMainWindow): acct.parseMessage(toAddress, fromAddress, subject, message) inbox = self.getAccountMessagelist(acct) treeWidget = self.getAccountTreeWidget(acct) + self.propagateUnreadCount(toAddress) + self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != toAddress: return @@ -2352,7 +2399,6 @@ class MyForm(QtGui.QMainWindow): newItem.setFont(font) inbox.setItem(0, 3, newItem) inbox.setSortingEnabled(True) - self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) @@ -2887,7 +2933,7 @@ class MyForm(QtGui.QMainWindow): #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.propagateUnreadCount(self.getCurrentAccount(), "inbox", self.getCurrentTreeWidget(), 0) # tableWidget.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. @@ -3040,7 +3086,7 @@ class MyForm(QtGui.QMainWindow): else: tableWidget.selectRow(currentRow - 1) if unread: - self.changedInboxUnread() + self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3700,7 +3746,7 @@ class MyForm(QtGui.QMainWindow): tableWidget.item(currentRow, 1).setFont(font) tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) - self.changedInboxUnread() + self.propagateUnreadCount(self.getCurrentAccount(), folder, self.getCurrentTreeWidget(), -1) else: data = self.getCurrentMessageId() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index e0ce72b8..30fdf82a 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -40,7 +40,7 @@ class AccountMixin (object): def updateText(self): pass - + class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): folderWeight = {"inbox": 1, "sent": 2, "trash": 3} def __init__(self, parent, pos = 0, address = "", folderName = "", unreadCount = 0): @@ -55,6 +55,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): def setFolderName(self, fname): self.folderName = str(fname) + self.setData(0, QtCore.Qt.UserRole, self.folderName) self.updateText() def updateText(self): @@ -107,6 +108,10 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): self.setType() self.initialised = True self.setExpanded(enabled) # does updateText + + def setAddress(self, address): + super(Ui_AddressWidget, self).setAddress(address) + self.setData(0, QtCore.Qt.UserRole, self.address) def updateText(self): if not self.initialised: diff --git a/src/helper_inbox.py b/src/helper_inbox.py index 09c7edbc..a3ad9755 100644 --- a/src/helper_inbox.py +++ b/src/helper_inbox.py @@ -3,7 +3,8 @@ import shared def insert(t): sqlExecute('''INSERT INTO inbox VALUES (?,?,?,?,?,?,?,?,?,?)''', *t) - shared.UISignalQueue.put(('changedInboxUnread', None)) + #shouldn't emit changedInboxUnread and displayNewInboxMessage at the same time + #shared.UISignalQueue.put(('changedInboxUnread', None)) def trash(msgid): sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', msgid) -- 2.45.1 From 6123b27315795ae9b41c8243314322206ff7ced9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 18:42:44 +0100 Subject: [PATCH 0077/1102] removeInboxRowByMsgid fixes Now undertands messagelists and has better performance. Haven't tested it yet though because it's triggered through API. I think it fixes #85 --- src/bitmessageqt/__init__.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 740a7bc3..b9d95876 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1862,15 +1862,28 @@ class MyForm(QtGui.QMainWindow): self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing - inbox = self.getCurrentMessagelist() - for i in range(inbox.rowCount()): - if msgid == str(inbox.item(i, 3).data(Qt.UserRole).toPyObject()): - self.statusBar().showMessage(_translate( - "MainWindow", "Message trashed")) - inbox.removeRow(i) - break - # this is a callback from core, not initiated by UI. We don't care about performance - self.propagateUnreadCount(None, None, None, 0) + def widgetConvert (tableWidget): + if tableWidget == self.ui.tableWidgetInbox: + return self.ui.treeWidgetYourIdentities + elif tableWidget == self.ui.tableWidgetInboxSubscriptions: + return self.ui.treeWidgetSubscriptions + elif tableWidget == self.ui.tableWidgetInboxChans: + return self.ui.treeWidgetChans + else: + return None + + 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(Qt.UserRole).toPyObject()): + self.statusBar().showMessage(_translate( + "MainWindow", "Message trashed")) + treeWidget = widgetConvert(inbox) + self.propagateUnreadCount(self.getCurrentAccount(treeWidget), self.getCurrentFolder(treeWidget), treeWidget, 0) + inbox.removeRow(i) + break def newVersionAvailable(self, version): # if (not (self.windowState() & QtCore.Qt.WindowActive)) or (self.windowState() & QtCore.Qt.WindowMinimized): -- 2.45.1 From 1174fb394a05d801790d19142d632085a647f4bb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 18:48:33 +0100 Subject: [PATCH 0078/1102] Indicate message sending Fixes #83 --- src/bitmessageqt/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b9d95876..0591a884 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2214,6 +2214,8 @@ class MyForm(QtGui.QMainWindow): if self.replyFromTab is not None: self.ui.tabWidget.setCurrentIndex(self.replyFromTab) self.replyFromTab = None + self.statusBar().showMessage(_translate( + "MainWindow", "Message queued.")) #self.ui.tableWidgetInbox.setCurrentCell(0, 0) else: self.statusBar().showMessage(_translate( @@ -2261,6 +2263,8 @@ class MyForm(QtGui.QMainWindow): self.ui.textEditMessageBroadcast.setText('') self.ui.tabWidget.setCurrentIndex(1) self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) + self.statusBar().showMessage(_translate( + "MainWindow", "Broadcast queued.")) def click_pushButtonLoadFromAddressBook(self): self.ui.tabWidget.setCurrentIndex(5) -- 2.45.1 From 2adfa6a1789cd1cec49e7375cb6d272177fcf427 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 19:03:10 +0100 Subject: [PATCH 0079/1102] Ubuntu notification fixes Notification should work irrespective of whether the new message shows up in the messagelist. --- src/bitmessageqt/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0591a884..b1945db6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2375,8 +2375,9 @@ class MyForm(QtGui.QMainWindow): inbox = self.getAccountMessagelist(acct) treeWidget = self.getAccountTreeWidget(acct) self.propagateUnreadCount(toAddress) - self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != toAddress: + # Ubuntu should notify of new message irespective of whether it's in current message list or not + self.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) return font = QFont() @@ -2416,6 +2417,7 @@ class MyForm(QtGui.QMainWindow): newItem.setFont(font) inbox.setItem(0, 3, newItem) inbox.setSortingEnabled(True) + self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) -- 2.45.1 From 4c8223ae889ef5afdaba5f0e5996ceab492fdb55 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 20:04:52 +0100 Subject: [PATCH 0080/1102] Unread count performance optimisation Continuation of #63 --- src/bitmessageqt/__init__.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b1945db6..07ff8a31 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2940,10 +2940,16 @@ class MyForm(QtGui.QMainWindow): font = QFont() font.setBold(True) inventoryHashesToMarkUnread = [] + modified = 0 for row in tableWidget.selectedIndexes(): currentRow = row.row() inventoryHashToMarkUnread = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) + if inventoryHashToMarkUnread in inventoryHashesToMarkUnread: + # it returns columns as separate items, so we skip dupes + continue + if not tableWidget.item(currentRow, 0).font().bold(): + modified += 1 inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) tableWidget.item(currentRow, 0).setFont(font) tableWidget.item(currentRow, 1).setFont(font) @@ -2952,7 +2958,11 @@ class MyForm(QtGui.QMainWindow): #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.propagateUnreadCount(self.getCurrentAccount(), "inbox", self.getCurrentTreeWidget(), 0) + if modified == 1: + # performance optimisation + self.propagateUnreadCount(self.getCurrentAccount()) + else: + self.propagateUnreadCount(self.getCurrentAccount(), "inbox", self.getCurrentTreeWidget(), 0) # tableWidget.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. -- 2.45.1 From 0eb89d8af5391202ba2985be81539b21dfe306b4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 20:05:58 +0100 Subject: [PATCH 0081/1102] Subscription new messages display correctly Fixes #70 --- src/bitmessageqt/__init__.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 07ff8a31..71bb16b1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -876,7 +876,7 @@ class MyForm(QtGui.QMainWindow): self.ui.tabWidget.setCurrentIndex(3) def propagateUnreadCount(self, address = None, folder = "inbox", widget = None, type = 1): - def updateUnreadCount(item, type = 1): + def updateUnreadCount(item): if type == 1: item.setUnreadCount(item.unreadCount + 1) if isinstance(item, Ui_AddressWidget): @@ -886,10 +886,14 @@ class MyForm(QtGui.QMainWindow): if isinstance(item, Ui_AddressWidget): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) else: + if addressItem.type == 'subscription' or addressItem.type == 'mailinglist': + xAddress = "fromaddress" + else: + xAddress = "toaddress" if address and folder: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE toaddress = ? AND folder = ? AND read = 0", address, folder) + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND folder = ? AND read = 0", address, folder) elif address: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE toaddress = ? AND read = 0", address) + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND read = 0", address) elif folder: queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", folder) else: @@ -909,14 +913,14 @@ class MyForm(QtGui.QMainWindow): addressItem = root.child(i) if address is not None and addressItem.data(0, QtCore.Qt.UserRole) != address: continue - updateUnreadCount(addressItem, type) + updateUnreadCount(addressItem) if addressItem.childCount == 0: continue for j in range(addressItem.childCount()): folderItem = addressItem.child(j) if folder is not None and folderItem.data(0, QtCore.Qt.UserRole) != folder: continue - updateUnreadCount(folderItem, type) + updateUnreadCount(folderItem) # Load Sent items from database def loadSent(self, tableWidget, account, where="", what=""): @@ -2370,12 +2374,15 @@ class MyForm(QtGui.QMainWindow): def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): subject = shared.fixPotentiallyInvalidUTF8Data(subject) - acct = accountClass(toAddress) + if toAddress == str_broadcast_subscribers: + acct = accountClass(fromAddress) + else: + acct = accountClass(toAddress) acct.parseMessage(toAddress, fromAddress, subject, message) inbox = self.getAccountMessagelist(acct) treeWidget = self.getAccountTreeWidget(acct) - self.propagateUnreadCount(toAddress) - if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != toAddress: + self.propagateUnreadCount(acct.address) + if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != acct.address: # Ubuntu should notify of new message irespective of whether it's in current message list or not self.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) return -- 2.45.1 From feea1ccd8de8202cc4c68188e7964f7f7a0d606d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 20:27:28 +0100 Subject: [PATCH 0082/1102] Colors for From ComboBox Fixes #86 --- src/bitmessageqt/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 71bb16b1..e0ea3e5e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2308,6 +2308,9 @@ class MyForm(QtGui.QMainWindow): self.ui.comboBoxSendFrom.addItem(avatarize(addressInKeysFile), unicode(shared.config.get( addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) # self.ui.comboBoxSendFrom.model().sort(1, Qt.AscendingOrder) + for i in range(self.ui.comboBoxSendFrom.count()): + address = str(self.ui.comboBoxSendFrom.itemData(i, Qt.UserRole).toString()) + self.ui.comboBoxSendFrom.setItemData(i, AccountColor(address).accountColor(), Qt.ForegroundRole) self.ui.comboBoxSendFrom.insertItem(0, '', '') if(self.ui.comboBoxSendFrom.count() == 2): self.ui.comboBoxSendFrom.setCurrentIndex(1) @@ -2323,6 +2326,9 @@ class MyForm(QtGui.QMainWindow): if isEnabled and isMaillinglist: self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), unicode(shared.config.get( addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) + for i in range(self.ui.comboBoxSendFromBroadcast.count()): + address = str(self.ui.comboBoxSendFromBroadcast.itemData(i, Qt.UserRole).toString()) + self.ui.comboBoxSendFromBroadcast.setItemData(i, AccountColor(address).accountColor(), Qt.ForegroundRole) self.ui.comboBoxSendFromBroadcast.insertItem(0, '', '') if(self.ui.comboBoxSendFromBroadcast.count() == 2): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(1) -- 2.45.1 From 828bf64630b05a6b51b12b646a94cf392b979cc9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 31 Oct 2015 21:38:54 +0100 Subject: [PATCH 0083/1102] Address book better context menu Don't allow delete of chans/subscriptions. Fixes #82 --- src/bitmessageqt/__init__.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e0ea3e5e..2325a781 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -310,14 +310,6 @@ class MyForm(QtGui.QMainWindow): 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 @@ -2020,6 +2012,7 @@ class MyForm(QtGui.QMainWindow): def addRow (address, label, type): self.ui.tableWidgetAddressBook.insertRow(0) newItem = Ui_AddressBookWidgetItemLabel(address, unicode(label, 'utf-8'), type) + newItem.setData(Qt.UserRole, type) self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type) self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) @@ -3268,6 +3261,26 @@ class MyForm(QtGui.QMainWindow): self.ui.tabWidget.setCurrentIndex(4) def on_context_menuAddressBook(self, point): + if hasattr(self, "popMenuAddressBook"): + self.popMenuAddressBook.clear() + else: + 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) + normal = True + for row in self.ui.tableWidgetAddressBook.selectedIndexes(): + currentRow = row.row() + type = str(self.ui.tableWidgetAddressBook.item( + currentRow, 0).data(Qt.UserRole).toPyObject()) + if type != "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)) -- 2.45.1 From ad63e956cfbba58719dad03b0be37c54c8b0a866 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 08:29:13 +0100 Subject: [PATCH 0084/1102] accountBrush improvements Moved code into the method --- src/bitmessageqt/foldertree.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 30fdf82a..6f5ad40c 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -15,7 +15,9 @@ class AccountMixin (object): return QtGui.QApplication.palette().text().color() def accountBrush(self): - return QtGui.QBrush(self.accountColor()) + brush = QtGui.QBrush(self.accountColor()) + brush.setStyle(QtCore.Qt.NoBrush) + return brush def setAddress(self, address): self.address = str(address) @@ -129,9 +131,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): self.setFont(0, font) #set text color - brush = self.accountBrush() - brush.setStyle(QtCore.Qt.NoBrush) - self.setForeground(0, brush) + self.setForeground(0, self.accountBrush()) self.setIcon(0, avatarize(self.address)) self.setText(0, text) @@ -212,9 +212,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): self.setFont(0, font) #set text color - brush = self.accountBrush() - brush.setStyle(QtCore.Qt.NoBrush) - self.setForeground(0, brush) + self.setForeground(0, self.accountBrush()) self.setIcon(0, avatarize(self.address)) self.setText(0, text) @@ -254,9 +252,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): except: self.type = 0 self.setEnabled(True) - brush = self.accountBrush() - brush.setStyle(QtCore.Qt.NoBrush) - self.setForeground(brush) + self.setForeground(self.accountBrush()) def __lt__ (self, other): if (isinstance(other, Ui_AddressBookWidgetItem)): -- 2.45.1 From 81e8ee1f838c302212053547e9ce56d5932f3aa0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 08:30:06 +0100 Subject: [PATCH 0085/1102] Color fixes in messagelists Fixes #87 --- src/bitmessageqt/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2325a781..020ff4ae 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2393,10 +2393,7 @@ class MyForm(QtGui.QMainWindow): newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) newItem.setFont(font) newItem.setData(Qt.UserRole, str(toAddress)) - if acct.type == 'mailinglist': - newItem.setTextColor(QtGui.QColor(137, 04, 177)) # magenta - if acct.type == 'chan': - newItem.setTextColor(QtGui.QColor(216, 119, 0)) # orange + newItem.setTextColor(AccountColor(toAddress).accountColor()) inbox.insertRow(0) newItem.setIcon(avatarize(toAddress)) inbox.setItem(0, 0, newItem) @@ -2407,6 +2404,7 @@ class MyForm(QtGui.QMainWindow): self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setFont(font) + newItem.setTextColor(AccountColor(fromAddress).accountColor()) newItem.setIcon(avatarize(fromAddress)) inbox.setItem(0, 1, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) @@ -3793,12 +3791,14 @@ class MyForm(QtGui.QMainWindow): font = QFont() font.setBold(False) # inventoryHashesToMarkRead = [] - currentRow = self.getCurrentMessagelist().currentRow() + currentRow = tableWidget.currentRow() # inventoryHashToMarkRead = str(tableWidget.item( # currentRow, 3).data(Qt.UserRole).toPyObject()) # inventoryHashesToMarkRead.append(inventoryHashToMarkRead) tableWidget.item(currentRow, 0).setFont(font) + tableWidget.item(currentRow, 0).setTextColor(AccountColor(str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject())).accountColor()) tableWidget.item(currentRow, 1).setFont(font) + tableWidget.item(currentRow, 1).setTextColor(AccountColor(str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject())).accountColor()) tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) self.propagateUnreadCount(self.getCurrentAccount(), folder, self.getCurrentTreeWidget(), -1) -- 2.45.1 From b4c920316e8ad7feec668bd4a3728848b981187d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 08:46:27 +0100 Subject: [PATCH 0086/1102] Enable/disable dynamic behaviour Fixes #88 --- src/bitmessageqt/__init__.py | 69 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 020ff4ae..f36046c3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -225,17 +225,6 @@ class MyForm(QtGui.QMainWindow): 'customContextMenuRequested(const QPoint&)'), self.on_context_menuYourIdentities) - self.popMenuYourIdentities = QtGui.QMenu(self) - self.popMenuYourIdentities.addAction(self.actionNewYourIdentities) - self.popMenuYourIdentities.addSeparator() - self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities) - self.popMenuYourIdentities.addSeparator() - self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities) - self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities) - self.popMenuYourIdentities.addAction(self.actionSetAvatarYourIdentities) - self.popMenuYourIdentities.addAction(self.actionSpecialAddressBehaviorYourIdentities) - self.popMenuYourIdentities.addAction(self.actionEmailGateway) - def init_chan_popup_menu(self, connectSignal=True): # Popup menu for the Channels tab self.ui.addressContextMenuToolbar = QtGui.QToolBar() @@ -268,16 +257,6 @@ class MyForm(QtGui.QMainWindow): 'customContextMenuRequested(const QPoint&)'), self.on_context_menuChan) - 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 self.ui.addressBookContextMenuToolbar = QtGui.QToolBar() @@ -338,15 +317,6 @@ class MyForm(QtGui.QMainWindow): self.connect(self.ui.treeWidgetSubscriptions, 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 @@ -3259,10 +3229,7 @@ class MyForm(QtGui.QMainWindow): self.ui.tabWidget.setCurrentIndex(4) def on_context_menuAddressBook(self, point): - if hasattr(self, "popMenuAddressBook"): - self.popMenuAddressBook.clear() - else: - self.popMenuAddressBook = QtGui.QMenu(self) + self.popMenuAddressBook = QtGui.QMenu(self) self.popMenuAddressBook.addAction(self.actionAddressBookSend) self.popMenuAddressBook.addAction(self.actionAddressBookClipboard) self.popMenuAddressBook.addAction(self.actionAddressBookSubscribe) @@ -3318,6 +3285,17 @@ class MyForm(QtGui.QMainWindow): shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): + self.popMenuSubscriptions = QtGui.QMenu(self) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew) + self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete) + self.popMenuSubscriptions.addSeparator() + if self.getCurrentItem().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.exec_( self.ui.treeWidgetSubscriptions.mapToGlobal(point)) @@ -3652,11 +3630,34 @@ class MyForm(QtGui.QMainWindow): return True def on_context_menuYourIdentities(self, point): + self.popMenuYourIdentities = QtGui.QMenu(self) + self.popMenuYourIdentities.addAction(self.actionNewYourIdentities) + self.popMenuYourIdentities.addSeparator() + self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities) + self.popMenuYourIdentities.addSeparator() + if self.getCurrentItem().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.exec_( self.ui.treeWidgetYourIdentities.mapToGlobal(point)) # TODO make one popMenu def on_context_menuChan(self, point): + self.popMenu = QtGui.QMenu(self) + self.popMenu.addAction(self.actionNew) + self.popMenu.addSeparator() + self.popMenu.addAction(self.actionClipboard) + self.popMenu.addSeparator() + if self.getCurrentItem().isEnabled: + self.popMenu.addAction(self.actionDisable) + else: + self.popMenu.addAction(self.actionEnable) + self.popMenu.addAction(self.actionSetAvatar) + self.popMenu.addAction(self.actionSpecialAddressBehavior) self.popMenu.exec_( self.ui.treeWidgetChans.mapToGlobal(point)) -- 2.45.1 From 6a95eba8f3dd3c753bec46d44f5189805da234cb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 09:01:34 +0100 Subject: [PATCH 0087/1102] Unread count for trash MarkUnread assumed all folders are inbox. --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f36046c3..55b1da54 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2934,9 +2934,9 @@ class MyForm(QtGui.QMainWindow): "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) if modified == 1: # performance optimisation - self.propagateUnreadCount(self.getCurrentAccount()) + self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder()) else: - self.propagateUnreadCount(self.getCurrentAccount(), "inbox", self.getCurrentTreeWidget(), 0) + self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) # tableWidget.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. -- 2.45.1 From d78629a6cfd0159caea68c64bc19f972421ec825 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 09:02:20 +0100 Subject: [PATCH 0088/1102] Emptying trash updates Fixes #75, however it is quite slow --- src/bitmessageqt/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 55b1da54..2051d119 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1463,6 +1463,16 @@ class MyForm(QtGui.QMainWindow): 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 botton 'regenerate deterministic addresses' def click_actionRegenerateDeterministicAddresses(self): -- 2.45.1 From 657eeeb1ca6f5baccece899f0775924bf893bee6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 10:09:04 +0100 Subject: [PATCH 0089/1102] Clear message lists better Fixes #71 --- src/bitmessageqt/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2051d119..82139637 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -915,8 +915,7 @@ class MyForm(QtGui.QMainWindow): ORDER BY lastactiontime ''' % (where,) - while tableWidget.rowCount() > 0: - tableWidget.removeRow(0) + tableWidget.setRowCount(0) acct = None queryreturn = sqlQuery(sqlStatement, account, what) for row in queryreturn: @@ -1040,8 +1039,7 @@ class MyForm(QtGui.QMainWindow): ''' % (where) queryreturn = sqlQuery(sqlStatement, account, what) - while tableWidget.rowCount() > 0: - tableWidget.removeRow(0) + tableWidget.setRowCount(0) tableWidget.setColumnHidden(0, True) tableWidget.setColumnHidden(1, False) -- 2.45.1 From 33928f1bc7a847836d6fe31abc06351ecb405e00 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 10:56:37 +0100 Subject: [PATCH 0090/1102] Trash undelete Fixes #55 --- src/bitmessageqt/__init__.py | 49 ++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 82139637..3a3c0dfc 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -147,6 +147,9 @@ class MyForm(QtGui.QMainWindow): 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"), @@ -179,16 +182,6 @@ class MyForm(QtGui.QMainWindow): '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() @@ -3098,6 +3091,30 @@ class MyForm(QtGui.QMainWindow): tableWidget.selectRow(currentRow - 1) if unread: self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + + def on_action_TrashUndelete(self): + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + unread = False + currentRow = 0 + while tableWidget.selectedIndexes(): + currentRow = tableWidget.selectedIndexes()[0].row() + inventoryHashToTrash = str(tableWidget.item( + currentRow, 3).data(Qt.UserRole).toPyObject()) + sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) + if tableWidget.item(currentRow, 0).font().bold(): + unread = True + self.getCurrentMessageTextedit().setText("") + tableWidget.removeRow(currentRow) + self.statusBar().showMessage(_translate( + "MainWindow", "Undeleted item.")) + if currentRow == 0: + tableWidget.selectRow(currentRow) + else: + tableWidget.selectRow(currentRow - 1) + if unread: + self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3678,6 +3695,18 @@ class MyForm(QtGui.QMainWindow): 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() + self.popMenuInbox.addAction(self.actionReply) + self.popMenuInbox.addAction(self.actionAddSenderToAddressBook) + 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)) def on_context_menuSent(self, point): -- 2.45.1 From aafa7b2840d52c08899d7f6a5916a3a716425045 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 10:59:11 +0100 Subject: [PATCH 0091/1102] Deleting from sent fix Fixes #52 --- src/bitmessageqt/__init__.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3a3c0dfc..fdec6f3f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3149,19 +3149,28 @@ class MyForm(QtGui.QMainWindow): # Send item on the Sent tab to trash def on_action_SentTrash(self): - while self.ui.tableWidgetInbox.selectedIndexes() != []: - currentRow = self.ui.tableWidgetInbox.selectedIndexes()[0].row() - ackdataToTrash = str(self.ui.tableWidgetInbox.item( + currentRow = 0 + unread = False + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + while tableWidget.selectedIndexes() != []: + currentRow = tableWidget.selectedIndexes()[0].row() + ackdataToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) - self.ui.textEditSentMessage.setPlainText("") - self.ui.tableWidgetInbox.removeRow(currentRow) + if tableWidget.item(currentRow, 0).font().bold(): + unread = True + self.getCurrentMessageTextedit().setPlainText("") + tableWidget.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.")) + "MainWindow", "Moved items to trash.")) if currentRow == 0: self.ui.tableWidgetInbox.selectRow(currentRow) else: self.ui.tableWidgetInbox.selectRow(currentRow - 1) + if unread: + self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_ForceSend(self): currentRow = self.ui.tableWidgetInbox.currentRow() -- 2.45.1 From e84efecb67990e608af12a61907b5e196315f7df Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 11:08:41 +0100 Subject: [PATCH 0092/1102] getCurrentFolder should return None on unavailable I think None is better than False. --- src/bitmessageqt/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fdec6f3f..ec7e7239 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1017,7 +1017,7 @@ class MyForm(QtGui.QMainWindow): xAddress = "fromaddress" else: xAddress = "toaddress" - if folder != False: + if folder is not None: sqlStatement = ''' SELECT folder, msgid, toaddress, fromaddress, subject, received, read FROM inbox WHERE ''' + xAddress + '''=? AND folder=? AND %s LIKE ? @@ -2352,7 +2352,7 @@ class MyForm(QtGui.QMainWindow): inbox = self.getAccountMessagelist(acct) treeWidget = self.getAccountTreeWidget(acct) self.propagateUnreadCount(acct.address) - if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) != False) or self.getCurrentAccount(treeWidget) != acct.address: + if (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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) return @@ -3532,8 +3532,7 @@ class MyForm(QtGui.QMainWindow): if currentItem and hasattr(currentItem, 'folderName'): return currentItem.folderName else: - # TODO need debug msg? - return False + return None def setCurrentItemColor(self, color): treeWidget = self.getCurrentTreeWidget() @@ -3699,7 +3698,7 @@ class MyForm(QtGui.QMainWindow): tableWidget = self.getCurrentMessagelist() if tableWidget: currentFolder = self.getCurrentFolder() - if currentFolder == False: + if currentFolder is None: pass if currentFolder == 'sent': self.on_context_menuSent(point) -- 2.45.1 From 0f1d85ff89f37038f85c33a891fc2bed25c30dcb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 11:09:36 +0100 Subject: [PATCH 0093/1102] Unread count fixes --- src/bitmessageqt/__init__.py | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ec7e7239..21419487 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -832,7 +832,28 @@ class MyForm(QtGui.QMainWindow): def propagateUnreadCount(self, address = None, folder = "inbox", widget = None, type = 1): def updateUnreadCount(item): - if type == 1: + # if refreshing the account root, we need to rescan folders + if type == 0 or (folder is None and isinstance(item, Ui_FolderWidget)): + if addressItem.type == 'subscription' or addressItem.type == 'mailinglist': + xAddress = "fromaddress" + else: + xAddress = "toaddress" + xFolder = folder + if isinstance(item, Ui_FolderWidget): + xFolder = item.folderName + if address and xFolder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND folder = ? AND read = 0", address, xFolder) + elif address: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND read = 0", address) + elif xFolder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", xFolder) + else: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") + for row in queryreturn: + item.setUnreadCount(int(row[0])) + if isinstance(item, Ui_AddressWidget): + self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) + elif type == 1: item.setUnreadCount(item.unreadCount + 1) if isinstance(item, Ui_AddressWidget): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount + 1)) @@ -840,23 +861,6 @@ class MyForm(QtGui.QMainWindow): item.setUnreadCount(item.unreadCount - 1) if isinstance(item, Ui_AddressWidget): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) - else: - if addressItem.type == 'subscription' or addressItem.type == 'mailinglist': - xAddress = "fromaddress" - else: - xAddress = "toaddress" - if address and folder: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND folder = ? AND read = 0", address, folder) - elif address: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND read = 0", address) - elif folder: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", folder) - else: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") - for row in queryreturn: - item.setUnreadCount(int(row[0])) - if isinstance(item, Ui_AddressWidget): - self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) if widget == None: widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] @@ -873,7 +877,7 @@ class MyForm(QtGui.QMainWindow): continue for j in range(addressItem.childCount()): folderItem = addressItem.child(j) - if folder is not None and folderItem.data(0, QtCore.Qt.UserRole) != folder: + if folder is not None and folderItem.folderName != folder: continue updateUnreadCount(folderItem) @@ -3090,7 +3094,7 @@ class MyForm(QtGui.QMainWindow): else: tableWidget.selectRow(currentRow - 1) if unread: - self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_TrashUndelete(self): tableWidget = self.getCurrentMessagelist() -- 2.45.1 From abc2ea2427f04bf2f7c06b7628e9dd0c9b9c568e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 11:09:58 +0100 Subject: [PATCH 0094/1102] Wrong messagelist --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 21419487..ecd135c9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3085,7 +3085,7 @@ class MyForm(QtGui.QMainWindow): sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): unread = True - self.ui.textEditInboxMessage.setText("") + self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( "MainWindow", "Moved items to trash.")) -- 2.45.1 From 8eb1b7462adea4e798588ada66656609eb7e0cbe Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 11:43:05 +0100 Subject: [PATCH 0095/1102] notify of new message fixed Will notify even if not on active messagelist. --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ecd135c9..3f45e340 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2356,6 +2356,8 @@ class MyForm(QtGui.QMainWindow): inbox = self.getAccountMessagelist(acct) treeWidget = self.getAccountTreeWidget(acct) self.propagateUnreadCount(acct.address) + if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): + self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) if (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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) @@ -2375,8 +2377,6 @@ class MyForm(QtGui.QMainWindow): newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) newItem.setToolTip(unicode(acct.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(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setFont(font) newItem.setTextColor(AccountColor(fromAddress).accountColor()) -- 2.45.1 From f5f46dae450645d67aa5b038a1629d8565be3d52 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 1 Nov 2015 12:09:03 +0100 Subject: [PATCH 0096/1102] Version bump --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index e24fd10d..88c76e56 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.0' +softwareVersion = '0.5.1' 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. -- 2.45.1 From df3c662832ce43003fd4be4d0ee59b0fb73c30d7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 5 Nov 2015 17:27:35 +0100 Subject: [PATCH 0097/1102] Message status update Someone reported the exception via BM. Fixes #90 Signed-off-by: mailchuck --- src/bitmessageqt/__init__.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3f45e340..ce5e3fc4 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1794,23 +1794,25 @@ class MyForm(QtGui.QMainWindow): self.unreadCount = count return self.unreadCount - def updateSentItemStatusByHash(self, toRipe, textToDisplay): - for i in range(self.ui.tableWidgetInbox.rowCount()): - toAddress = str(self.ui.tableWidgetInbox.item( + def updateSentItemStatusByToAddress(self, toAddress, textToDisplay): + sent = self.getAccountMessagelist(toAddress) + treeWidget = self.getAccountTreeWidget(toAddress) + if self.getCurrentFolder(treeWidget) != "sent": + return + for i in range(sent.rowCount()): + rowAddress = str(sent.item( i, 0).data(Qt.UserRole).toPyObject()) - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) - if ripe == toRipe: - self.ui.tableWidgetInbox.item(i, 3).setToolTip(textToDisplay) + 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: - self.ui.tableWidgetInbox.item(i, 3).setText( + sent.item(i, 3).setText( textToDisplay[:newlinePosition]) else: - self.ui.tableWidgetInbox.item(i, 3).setText(textToDisplay) + sent.item(i, 3).setText(textToDisplay) def updateSentItemStatusByAckdata(self, ackdata, textToDisplay): for i in range(self.ui.tableWidgetInbox.rowCount()): -- 2.45.1 From e5ee7426ebb145efb39d778d4836181e9b9d414c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 5 Nov 2015 20:41:41 +0100 Subject: [PATCH 0098/1102] Support for PoW from an external library This will attempt to include a PoW library (.so on Unix, .dll on windows) to do PoW. This is done in a safe way and clean fallback to normal PoW. The code for the library will be in another commit. The code is take from https://github.com/bm-robertwhite/bitmessage-powfaster, with minor modifications. This patch also includes code to make GPU PoW have a safer fallback. --- src/proofofwork.py | 51 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 81f7e3df..93f6f2cd 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -7,7 +7,31 @@ import sys from shared import config, frozen import shared import openclpow -#import os +import os +import ctypes + +curdir = os.path.dirname(__file__) +bitmsglib = 'bitmsghash.so' +if "win32" == sys.platform: + if ctypes.sizeof(ctypes.c_voidp) == 4: + bitmsglib = 'bitmsghash32.dll' + else: + bitmsglib = 'bitmsghash64.dll' + try: + bso = ctypes.WinDLL(os.path.join(curdir, bitmsglib)) + except: + bso = None +else: + try: + bso = ctypes.CDLL(os.path.join(curdir, bitmsglib)) + except: + bso = None +if bso: + try: + bmpow = bso.BitmessagePOW + bmpow.restype = ctypes.c_ulonglong + except: + bmpow = None def _set_idle(): if 'linux' in sys.platform: @@ -72,12 +96,23 @@ def _doFastPoW(target, initialHash): 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) + print "C PoW start" + nonce = bmpow(out_h, out_m) + trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) + print "C PoW done" + return [trialValue, nonce] def _doGPUPoW(target, initialHash): - print "GPU POW\n" + print "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) + print "GPU PoW done" return [trialValue, nonce] def run(target, initialHash): @@ -88,8 +123,16 @@ def run(target, initialHash): # print "GPU: %s, %s" % (trialvalue1, nonce1) # print "Fast: %s, %s" % (trialvalue, nonce) # return [trialvalue, nonce] - return _doGPUPoW(target, initialHash) - elif frozen == "macosx_app" or not frozen: + try: + return _doGPUPoW(target, initialHash) + except: + pass # fallback to normal PoW + if frozen == "macosx_app" or not frozen: + if bmpow: + try: + return _doCPoW(target, initialHash) + except: + pass # fallback to normal PoW return _doFastPoW(target, initialHash) else: return _doSafePoW(target, initialHash) -- 2.45.1 From be55af183222fffe2623a32688a70b44427d4446 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 5 Nov 2015 20:47:30 +0100 Subject: [PATCH 0099/1102] C library for bitmessage PoW Originally from https://github.com/bm-robertwhite/bitmessage-powfaster. Modified to compile correctly on Visual Studio, and to decrease thread priority. I have not tried it on Linux yet. --- src/bitmsghash.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/bitmsghash.cpp diff --git a/src/bitmsghash.cpp b/src/bitmsghash.cpp new file mode 100644 index 00000000..9f17d5ff --- /dev/null +++ b/src/bitmsghash.cpp @@ -0,0 +1,89 @@ +// 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 + +#include "openssl/sha.h" + +#define HASH_SIZE 64 +#define BUFLEN 16384 + +#define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) ) + +unsigned long long max_val; +unsigned char *initialHash; + + +int numthreads = 8; +unsigned long long successval = 0; +#ifdef _WIN32 +DWORD WINAPI threadfunc(LPVOID lpParameter) { + DWORD incamt = (DWORD)lpParameter; +#else +void * threadfunc(void* param) { + unsigned int incamt = (unsigned int)param; +#endif + 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; + } + } + return NULL; +} + +extern "C" __declspec(dllexport) unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) +{ + successval = 0; + max_val = target; + initialHash = (unsigned char *)starthash; +# ifdef _WIN32 + HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads); +# else + pthread_t* threads = calloc(sizeof(pthread_t), numthreads); +# endif + for (int i = 0; i < numthreads; i++) { +# ifdef _WIN32 + threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)i, 0, NULL); + SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE); +# else + pthread_create(&threads[i], NULL, threadfunc, (void*)i); +# endif + } +# ifdef _WIN32 + WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE); +# else + for (int i = 0; i < numthreads; i++) { + pthread_join(threads[i], NULL); + } +# endif + free(threads); + return successval; +} \ No newline at end of file -- 2.45.1 From 286982213435d3b1b3da2361ab65a3298d01a8d0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 5 Nov 2015 22:18:53 +0100 Subject: [PATCH 0100/1102] C PoW updates Catching up with Grant Olson's fork. Reduce thread priority. --- src/bitmsghash.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/bitmsghash.cpp b/src/bitmsghash.cpp index 9f17d5ff..d7dc9973 100644 --- a/src/bitmsghash.cpp +++ b/src/bitmsghash.cpp @@ -17,6 +17,14 @@ #define HASH_SIZE 64 #define BUFLEN 16384 +#if defined(__GNUC__) + #define EXPORT __attribute__ ((__visibility__("default"))) + #define UINT intptr_t +#elif defined(WIN32) + #define EXPORT __declspec(dllexport) + #define UINT unsigned int +#endif + #define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) ) unsigned long long max_val; @@ -30,7 +38,7 @@ DWORD WINAPI threadfunc(LPVOID lpParameter) { DWORD incamt = (DWORD)lpParameter; #else void * threadfunc(void* param) { - unsigned int incamt = (unsigned int)param; + UINT incamt = (UINT)param; #endif SHA512_CTX sha; unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 }; @@ -59,7 +67,7 @@ void * threadfunc(void* param) { return NULL; } -extern "C" __declspec(dllexport) unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) +extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, unsigned long long target) { successval = 0; max_val = target; @@ -67,14 +75,17 @@ extern "C" __declspec(dllexport) unsigned long long BitmessagePOW(unsigned char # ifdef _WIN32 HANDLE* threads = (HANDLE*)calloc(sizeof(HANDLE), numthreads); # else - pthread_t* threads = calloc(sizeof(pthread_t), numthreads); + pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads); + struct sched_param schparam; + schparam.sched_priority = 0; # endif - for (int i = 0; i < numthreads; i++) { + for (UINT i = 0; i < numthreads; i++) { # ifdef _WIN32 threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)i, 0, NULL); SetThreadPriority(threads[i], THREAD_PRIORITY_IDLE); # else pthread_create(&threads[i], NULL, threadfunc, (void*)i); + pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); # endif } # ifdef _WIN32 @@ -86,4 +97,4 @@ extern "C" __declspec(dllexport) unsigned long long BitmessagePOW(unsigned char # endif free(threads); return successval; -} \ No newline at end of file +} -- 2.45.1 From 84c9b1dd3128eef2b562f8df384b7594cbbd9310 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 5 Nov 2015 22:27:34 +0100 Subject: [PATCH 0101/1102] C PoW library makefile For easy compiling with GNU make (e.g. Unix-like systems). Run as "make bitmsghash.so" --- src/Makefile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/Makefile diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..3c9c7470 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,15 @@ +all: + @echo "This compiles and tests the C PoW library, it's not necessary to run PyBitmessage" + +powtest: + ./testpow.py + +bitmsghash.so: bitmsghash.o + g++ bitmsghash.o -shared -fPIC -lpthread -lcrypto -o bitmsghash.so + +bitmsghash.o: + g++ -Wall -O3 -march=native -fPIC -c bitmsghash.cpp + +clean: + rm -f bitmsghash.o bitmsghash.so + -- 2.45.1 From 1a3794f3e3a9364c0a7e87452042c9908ea491d8 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 7 Nov 2015 18:39:55 +0100 Subject: [PATCH 0102/1102] C PoW updates - move to subdirectory - get rid of compile warnings on windows - get number of threads from affinity (Windows, Linux) or core count (BSD/OSX) --- src/{ => bitmsghash}/Makefile | 0 src/{ => bitmsghash}/bitmsghash.cpp | 58 ++++++++++++++++++++++++----- src/proofofwork.py | 4 +- 3 files changed, 50 insertions(+), 12 deletions(-) rename src/{ => bitmsghash}/Makefile (100%) rename src/{ => bitmsghash}/bitmsghash.cpp (63%) diff --git a/src/Makefile b/src/bitmsghash/Makefile similarity index 100% rename from src/Makefile rename to src/bitmsghash/Makefile diff --git a/src/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp similarity index 63% rename from src/bitmsghash.cpp rename to src/bitmsghash/bitmsghash.cpp index d7dc9973..c0a40509 100644 --- a/src/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -19,27 +19,23 @@ #if defined(__GNUC__) #define EXPORT __attribute__ ((__visibility__("default"))) - #define UINT intptr_t -#elif defined(WIN32) +#elif defined(_WIN32) #define EXPORT __declspec(dllexport) - #define UINT unsigned int #endif #define ntohll(x) ( ( (uint64_t)(ntohl( (unsigned int)((x << 32) >> 32) )) << 32) | ntohl( ((unsigned int)(x >> 32)) ) ) unsigned long long max_val; unsigned char *initialHash; - - -int numthreads = 8; unsigned long long successval = 0; +unsigned int numthreads = 0; + #ifdef _WIN32 DWORD WINAPI threadfunc(LPVOID lpParameter) { - DWORD incamt = (DWORD)lpParameter; #else void * threadfunc(void* param) { - UINT incamt = (UINT)param; #endif + unsigned int incamt = *((unsigned int*)lpParameter); SHA512_CTX sha; unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 }; unsigned char output[HASH_SIZE] = { 0 }; @@ -67,25 +63,66 @@ void * threadfunc(void* param) { return NULL; } +void getnumthreads() +{ +#ifdef _WIN32 + DWORD_PTR dwProcessAffinity, dwSystemAffinity; +#elif __linux__ + cpu_set_t dwProcessAffinity; +#else + int dwProcessAffinity = 0; + int32_t core_count = 0; +#endif + unsigned int len = sizeof(dwProcessAffinity); + if (numthreads > 0) + return; +#ifdef _WIN32 + GetProcessAffinityMask(GetCurrentProcess(), &dwProcessAffinity, &dwSystemAffinity); +#elif __linux__ + sched_getaffinity(0, len, &dwProcessAffinity); +#else + if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0)) + numthreads = core_count; +#endif + for (unsigned int i = 0; i < len * 8; i++) + if (dwProcessAffinity & (1i64 << i)) { + numthreads++; + printf("Detected core on: %u\n", i); + } + printf("Affinity: %lx\n", (unsigned long) dwProcessAffinity); + 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; +# ifdef __linux__ schparam.sched_priority = 0; +# else + schparam.sched_priority = PTHREAD_MIN_PRIORITY; # endif +# endif + unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); for (UINT i = 0; i < numthreads; i++) { + threaddata[i] = i; # ifdef _WIN32 - threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)i, 0, NULL); + 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*)i); + 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 @@ -96,5 +133,6 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un } # endif free(threads); + free(threaddata); return successval; } diff --git a/src/proofofwork.py b/src/proofofwork.py index 93f6f2cd..0aaf6487 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -18,12 +18,12 @@ if "win32" == sys.platform: else: bitmsglib = 'bitmsghash64.dll' try: - bso = ctypes.WinDLL(os.path.join(curdir, bitmsglib)) + bso = ctypes.WinDLL(os.path.join(curdir, "bitmsghash", bitmsglib)) except: bso = None else: try: - bso = ctypes.CDLL(os.path.join(curdir, bitmsglib)) + bso = ctypes.CDLL(os.path.join(curdir, "bitmsghash", bitmsglib)) except: bso = None if bso: -- 2.45.1 From 0a09d3580db51dc09a3b930f6b2f80e99a425c3d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 7 Nov 2015 19:02:53 +0100 Subject: [PATCH 0103/1102] Make building bitmsghash default --- src/bitmsghash/Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile index 3c9c7470..aac89349 100644 --- a/src/bitmsghash/Makefile +++ b/src/bitmsghash/Makefile @@ -1,5 +1,4 @@ -all: - @echo "This compiles and tests the C PoW library, it's not necessary to run PyBitmessage" +all: bitmsghash.so powtest: ./testpow.py -- 2.45.1 From d5ec69d3b7900b39964d0aaa7158f4aaad8d65e9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 7 Nov 2015 19:03:38 +0100 Subject: [PATCH 0104/1102] Bitmsghash linux compile fixes --- src/bitmsghash/bitmsghash.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index c0a40509..e05c88ae 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -31,11 +31,11 @@ unsigned long long successval = 0; unsigned int numthreads = 0; #ifdef _WIN32 -DWORD WINAPI threadfunc(LPVOID lpParameter) { +DWORD WINAPI threadfunc(LPVOID param) { #else void * threadfunc(void* param) { #endif - unsigned int incamt = *((unsigned int*)lpParameter); + unsigned int incamt = *((unsigned int*)param); SHA512_CTX sha; unsigned char buf[HASH_SIZE + sizeof(uint64_t)] = { 0 }; unsigned char output[HASH_SIZE] = { 0 }; @@ -85,11 +85,14 @@ void getnumthreads() numthreads = core_count; #endif for (unsigned int i = 0; i < len * 8; i++) +#ifdef _WIN32 if (dwProcessAffinity & (1i64 << i)) { +#else + if (CPU_ISSET(i, &dwProcessAffinity)) { +#endif numthreads++; printf("Detected core on: %u\n", i); } - printf("Affinity: %lx\n", (unsigned long) dwProcessAffinity); printf("Number of threads: %i\n", (int)numthreads); } @@ -111,7 +114,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # endif # endif unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); - for (UINT i = 0; i < numthreads; i++) { + for (unsigned int i = 0; i < numthreads; i++) { threaddata[i] = i; # ifdef _WIN32 threads[i] = CreateThread(NULL, 0, threadfunc, (LPVOID)&threaddata[i], 0, NULL); @@ -128,7 +131,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # ifdef _WIN32 WaitForMultipleObjects(numthreads, threads, TRUE, INFINITE); # else - for (int i = 0; i < numthreads; i++) { + for (unsigned int i = 0; i < numthreads; i++) { pthread_join(threads[i], NULL); } # endif -- 2.45.1 From ad33e2640c7eb81bcc07f8293611a43b58841bbf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:17:03 +0100 Subject: [PATCH 0105/1102] Move and rename OpenCL kernel --- src/{kernel.cl => bitmsghash/bitmsghash.cl} | 556 ++++++++++---------- 1 file changed, 278 insertions(+), 278 deletions(-) rename src/{kernel.cl => bitmsghash/bitmsghash.cl} (96%) diff --git a/src/kernel.cl b/src/bitmsghash/bitmsghash.cl similarity index 96% rename from src/kernel.cl rename to src/bitmsghash/bitmsghash.cl index d8db974a..9af7ca19 100644 --- a/src/kernel.cl +++ b/src/bitmsghash/bitmsghash.cl @@ -1,278 +1,278 @@ -/* -* 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, -}; - - - -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]); - } -} - +/* +* 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, +}; + + + +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]); + } +} + -- 2.45.1 From 961444a8ee654d872c0f1ea643ea315112b2216a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:18:37 +0100 Subject: [PATCH 0106/1102] OpenCL compile warning --- src/bitmsghash/bitmsghash.cl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmsghash/bitmsghash.cl b/src/bitmsghash/bitmsghash.cl index 9af7ca19..1ab5d219 100644 --- a/src/bitmsghash/bitmsghash.cl +++ b/src/bitmsghash/bitmsghash.cl @@ -112,7 +112,7 @@ __constant uint64_t k[] = { -void setup_ctx(sha512_ctx* ctx, const char * password, uint8_t pass_len) +static void setup_ctx(sha512_ctx* ctx, const char * password, uint8_t pass_len) { uint32_t* b32 = ctx->buffer; -- 2.45.1 From 53ca944483995f244d83faeef2979202bd004067 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:22:17 +0100 Subject: [PATCH 0107/1102] OSX fixes and default compile It should built on OSX 10.11 now It will build bitmsghash.so by default --- src/bitmsghash/Makefile | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bitmsghash/Makefile b/src/bitmsghash/Makefile index aac89349..88744524 100644 --- a/src/bitmsghash/Makefile +++ b/src/bitmsghash/Makefile @@ -1,13 +1,19 @@ +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 +endif + all: bitmsghash.so powtest: ./testpow.py bitmsghash.so: bitmsghash.o - g++ bitmsghash.o -shared -fPIC -lpthread -lcrypto -o bitmsghash.so + g++ bitmsghash.o -shared -fPIC -lpthread -lcrypto $(LDFLAGS) -o bitmsghash.so bitmsghash.o: - g++ -Wall -O3 -march=native -fPIC -c bitmsghash.cpp + g++ -Wall -O3 -march=native -fPIC $(CCFLAGS) -c bitmsghash.cpp clean: rm -f bitmsghash.o bitmsghash.so -- 2.45.1 From 5a681068fef3011aee4d17c1e246d1eae6de48e5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:23:41 +0100 Subject: [PATCH 0108/1102] OpenCL fixes - directory change - automatically detect all available GPUs --- src/openclpow.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/openclpow.py b/src/openclpow.py index 7ab4dba8..a2cfb068 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -13,15 +13,21 @@ try: import numpy import pyopencl as cl hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) - if (len(cl.get_platforms()) > 0): - ctx = cl.create_some_context() + gpus = [] + for platform in cl.get_platforms(): + gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) + if (len(gpus) > 0): + ctx = cl.Context(devices=gpus) queue = cl.CommandQueue(ctx) full_path = os.path.dirname(os.path.realpath(__file__)) - f = open(os.path.join(full_path, 'kernel.cl'), 'r') + f = open(os.path.join(full_path, "bitmsghash", 'bitmsghash.cl'), 'r') fstr = ''.join(f.readlines()) program = cl.Program(ctx, fstr).build(options="") + else: + print "No OpenCL GPUs found" + ctx = False except Exception as e: - print "opencl fail:" + str(e) + print "opencl fail: " + str(e) ctx = False def has_opencl(): @@ -40,7 +46,7 @@ def do_opencl_pow(hash, target): 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, cl.get_platforms()[0].get_devices()[1]) + worksize = kernel.get_work_group_info(cl.kernel_work_group_info.WORK_GROUP_SIZE, gpus[0]) kernel.set_arg(0, hash_buf) kernel.set_arg(1, dest_buf) -- 2.45.1 From 0a8fdd7effc98f5e808935b5d3df2b1714558c71 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:26:17 +0100 Subject: [PATCH 0109/1102] Compile fixes - OSX and Windows compile fixes --- src/bitmsghash/bitmsghash.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/bitmsghash/bitmsghash.cpp b/src/bitmsghash/bitmsghash.cpp index e05c88ae..4862c341 100644 --- a/src/bitmsghash/bitmsghash.cpp +++ b/src/bitmsghash/bitmsghash.cpp @@ -11,6 +11,10 @@ #include #include #include +#ifdef __APPLE__ +#include +#include +#endif #include "openssl/sha.h" @@ -23,7 +27,9 @@ #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; @@ -73,7 +79,7 @@ void getnumthreads() int dwProcessAffinity = 0; int32_t core_count = 0; #endif - unsigned int len = sizeof(dwProcessAffinity); + size_t len = sizeof(dwProcessAffinity); if (numthreads > 0) return; #ifdef _WIN32 @@ -81,14 +87,16 @@ void getnumthreads() #elif __linux__ sched_getaffinity(0, len, &dwProcessAffinity); #else - if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0)) + if (sysctlbyname("hw.logicalcpu", &core_count, &len, 0, 0) == 0) numthreads = core_count; #endif for (unsigned int i = 0; i < len * 8; i++) -#ifdef _WIN32 +#if defined(_WIN32) if (dwProcessAffinity & (1i64 << i)) { -#else +#elif defined __linux__ if (CPU_ISSET(i, &dwProcessAffinity)) { +#else + if (dwProcessAffinity & (1 << i)) { #endif numthreads++; printf("Detected core on: %u\n", i); @@ -107,11 +115,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # else pthread_t* threads = (pthread_t*)calloc(sizeof(pthread_t), numthreads); struct sched_param schparam; -# ifdef __linux__ schparam.sched_priority = 0; -# else - schparam.sched_priority = PTHREAD_MIN_PRIORITY; -# endif # endif unsigned int *threaddata = (unsigned int *)calloc(sizeof(unsigned int), numthreads); for (unsigned int i = 0; i < numthreads; i++) { @@ -124,7 +128,7 @@ extern "C" EXPORT unsigned long long BitmessagePOW(unsigned char * starthash, un # ifdef __linux__ pthread_setschedparam(threads[i], SCHED_IDLE, &schparam); # else - pthread_setschedparam(threads[i], SCHED_RR, &schparam) + pthread_setschedparam(threads[i], SCHED_RR, &schparam); # endif # endif } -- 2.45.1 From 8e650396da300fbe313b3aceccc46e81614a1f09 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 11:44:19 +0100 Subject: [PATCH 0110/1102] Missing library fix Missing library error wasn't handled correctly. --- src/proofofwork.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/proofofwork.py b/src/proofofwork.py index 0aaf6487..f7776638 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -32,6 +32,8 @@ if bso: bmpow.restype = ctypes.c_ulonglong except: bmpow = None +else: + bmpow = None def _set_idle(): if 'linux' in sys.platform: -- 2.45.1 From d5743f12b95148b27118249e5bfd97eb7a35b40f Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 21:44:02 +0100 Subject: [PATCH 0111/1102] More tabs resizable and save state Fixes #15 Addresses #12 --- src/bitmessageqt/__init__.py | 48 ++-- src/bitmessageqt/bitmessageui.py | 352 +++++++++++++++++++----------- src/bitmessageqt/settingsmixin.py | 69 ++++++ 3 files changed, 318 insertions(+), 151 deletions(-) create mode 100644 src/bitmessageqt/settingsmixin.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ce5e3fc4..9bc69d79 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -36,6 +36,7 @@ from newchandialog import * from specialaddressbehavior import * from emailgateway import * from settings import * +import settingsmixin from about import * from help import * from iconglossary import * @@ -55,6 +56,7 @@ import subprocess import datetime from helper_sql import * import l10n +import types from utils import * from collections import OrderedDict from account import * @@ -73,7 +75,7 @@ def change_translation(locale): qtranslator.load(translationpath) QtGui.QApplication.installTranslator(qtranslator) -class MyForm(QtGui.QMainWindow): +class MyForm(settingsmixin.SMainWindow): # sound type constants SOUND_NONE = 0 @@ -701,9 +703,9 @@ class MyForm(QtGui.QMainWindow): QtCore.QObject.connect(self.ui.horizontalSliderTTL, QtCore.SIGNAL( "valueChanged(int)"), self.updateTTL) - - self.readSettings() - + + self.initSettings() + # Check to see whether we can connect to namecoin. Hide the 'Fetch Namecoin ID' button if we can't. try: options = {} @@ -2860,9 +2862,9 @@ class MyForm(QtGui.QMainWindow): if self.mmapp is not None: self.mmapp.unregister() - settings = QSettings("Bitmessage", "PyBitmessage") - settings.setValue("geometry", self.saveGeometry()) - settings.setValue("state", self.saveState()) +# settings = QSettings("Bitmessage", "PyBitmessage") +# settings.setValue("geometry", self.saveGeometry()) +# settings.setValue("state", self.saveState()) self.statusBar().showMessage(_translate( "MainWindow", "All done. Closing user interface...")) @@ -2883,6 +2885,13 @@ class MyForm(QtGui.QMainWindow): # minimize the application event.ignore() else: + # save state and geometry self and all widgets + 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() # quit the application event.accept() self.quit() @@ -3887,20 +3896,17 @@ class MyForm(QtGui.QMainWindow): self.statusBar().showMessage(data) - def readSettings(self): - settings = QSettings("Bitmessage", "PyBitmessage") - try: - geom = settings.value("geometry") - self.restoreGeometry(geom.toByteArray() if hasattr(geom, 'toByteArray') else geom) - except Exception as e: - pass - - try: - state = settings.value("state") - self.restoreState(state.toByteArray() if hasattr(state, 'toByteArray') else state) - except Exception as e: - pass - + 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): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 26493241..0e719c17 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +import settingsmixin try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -53,9 +54,9 @@ class Ui_MainWindow(object): self.inbox.setObjectName(_fromUtf8("inbox")) self.gridLayout = QtGui.QGridLayout(self.inbox) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) - self.horizontalSplitter_3 = QtGui.QSplitter() + self.horizontalSplitter_3 = settingsmixin.SSplitter() self.horizontalSplitter_3.setObjectName(_fromUtf8("horizontalSplitter_3")) - self.verticalSplitter_12 = QtGui.QSplitter() + self.verticalSplitter_12 = settingsmixin.SSplitter() self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12")) self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical) self.treeWidgetYourIdentities = QtGui.QTreeWidget(self.inbox) @@ -75,10 +76,10 @@ class Ui_MainWindow(object): self.verticalSplitter_12.setCollapsible(1, False) self.verticalSplitter_12.handle(1).setEnabled(False) self.horizontalSplitter_3.addWidget(self.verticalSplitter_12) - self.verticalSplitter_7 = QtGui.QSplitter() + 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 = settingsmixin.SSplitter() self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch")) self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox) self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit")) @@ -96,7 +97,7 @@ class Ui_MainWindow(object): self.horizontalSplitterSearch.setStretchFactor(0, 1) self.horizontalSplitterSearch.setStretchFactor(1, 0) self.verticalSplitter_7.addWidget(self.horizontalSplitterSearch) - self.tableWidgetInbox = QtGui.QTableWidget(self.inbox) + self.tableWidgetInbox = settingsmixin.STableWidget(self.inbox) self.tableWidgetInbox.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.tableWidgetInbox.setAlternatingRowColors(True) self.tableWidgetInbox.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) @@ -147,18 +148,19 @@ class Ui_MainWindow(object): self.send.setObjectName(_fromUtf8("send")) self.gridLayout_7 = QtGui.QGridLayout(self.send) self.gridLayout_7.setObjectName(_fromUtf8("gridLayout_7")) - self.horizontalLayout = QtGui.QHBoxLayout() - self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) - self.verticalLayout_2 = QtGui.QVBoxLayout() - self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) - self.tableWidgetAddressBook = QtGui.QTableWidget(self.send) - self.tableWidgetAddressBook.setMaximumSize(QtCore.QSize(200, 16777215)) + 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) @@ -171,95 +173,119 @@ class Ui_MainWindow(object): self.tableWidgetAddressBook.horizontalHeader().setHighlightSections(False) self.tableWidgetAddressBook.horizontalHeader().setStretchLastSection(True) self.tableWidgetAddressBook.verticalHeader().setVisible(False) - self.verticalLayout_2.addWidget(self.tableWidgetAddressBook) + self.verticalSplitter_2.addWidget(self.tableWidgetAddressBook) self.pushButtonAddAddressBook = QtGui.QPushButton(self.send) - self.pushButtonAddAddressBook.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddAddressBook.setObjectName(_fromUtf8("pushButtonAddAddressBook")) - self.verticalLayout_2.addWidget(self.pushButtonAddAddressBook) + self.pushButtonAddAddressBook.resize(200, self.pushButtonAddAddressBook.height()) + self.verticalSplitter_2.addWidget(self.pushButtonAddAddressBook) self.pushButtonFetchNamecoinID = QtGui.QPushButton(self.send) - self.pushButtonFetchNamecoinID.setMaximumSize(QtCore.QSize(200, 16777215)) + self.pushButtonFetchNamecoinID.resize(200, self.pushButtonFetchNamecoinID.height()) font = QtGui.QFont() font.setPointSize(9) self.pushButtonFetchNamecoinID.setFont(font) self.pushButtonFetchNamecoinID.setObjectName(_fromUtf8("pushButtonFetchNamecoinID")) - self.verticalLayout_2.addWidget(self.pushButtonFetchNamecoinID) - self.horizontalLayout.addLayout(self.verticalLayout_2) - self.verticalLayout = QtGui.QVBoxLayout() - self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) + 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.tab = QtGui.QWidget() - self.tab.setObjectName(_fromUtf8("tab")) - self.gridLayout_8 = QtGui.QGridLayout(self.tab) + self.sendDirect = QtGui.QWidget() + self.sendDirect.setObjectName(_fromUtf8("sendDirect")) + self.gridLayout_8 = QtGui.QGridLayout(self.sendDirect) self.gridLayout_8.setObjectName(_fromUtf8("gridLayout_8")) - self.verticalLayout_5 = QtGui.QVBoxLayout() - self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) + 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.setObjectName(_fromUtf8("gridLayout_2")) - self.label_3 = QtGui.QLabel(self.tab) + self.label_3 = QtGui.QLabel(self.sendDirect) self.label_3.setObjectName(_fromUtf8("label_3")) self.gridLayout_2.addWidget(self.label_3, 2, 0, 1, 1) - self.label_2 = QtGui.QLabel(self.tab) + 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.tab) + 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.tab) + 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.tab) + self.comboBoxSendFrom = QtGui.QComboBox(self.sendDirect) 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.tab) + self.lineEditTo = QtGui.QLineEdit(self.sendDirect) self.lineEditTo.setObjectName(_fromUtf8("lineEditTo")) self.gridLayout_2.addWidget(self.lineEditTo, 1, 1, 1, 1) - self.verticalLayout_5.addLayout(self.gridLayout_2) - self.textEditMessage = QtGui.QTextEdit(self.tab) + self.gridLayout_2_Widget = QtGui.QWidget() + self.gridLayout_2_Widget.setLayout(self.gridLayout_2) + self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget) + self.textEditMessage = QtGui.QTextEdit(self.sendDirect) self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) - self.verticalLayout_5.addWidget(self.textEditMessage) - self.gridLayout_8.addLayout(self.verticalLayout_5, 0, 0, 1, 1) - self.tabWidgetSend.addTab(self.tab, _fromUtf8("")) - self.tab_2 = QtGui.QWidget() - self.tab_2.setObjectName(_fromUtf8("tab_2")) - self.gridLayout_9 = QtGui.QGridLayout(self.tab_2) + 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.verticalLayout_6 = QtGui.QVBoxLayout() - self.verticalLayout_6.setObjectName(_fromUtf8("verticalLayout_6")) + 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.tab_2) + 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.tab_2) + 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.tab_2) + 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.tab_2) + 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.verticalLayout_6.addLayout(self.gridLayout_5) - self.textEditMessageBroadcast = QtGui.QTextEdit(self.tab_2) + self.gridLayout_5_Widget = QtGui.QWidget() + self.gridLayout_5_Widget.setLayout(self.gridLayout_5) + self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget) + self.textEditMessageBroadcast = QtGui.QTextEdit(self.sendBroadcast) self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast")) - self.verticalLayout_6.addWidget(self.textEditMessageBroadcast) - self.gridLayout_9.addLayout(self.verticalLayout_6, 0, 0, 1, 1) - self.tabWidgetSend.addTab(self.tab_2, _fromUtf8("")) - self.verticalLayout.addWidget(self.tabWidgetSend) - self.horizontalLayout_5 = QtGui.QHBoxLayout() - self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5")) + 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.horizontalSplitter_5 = settingsmixin.SSplitter() + self.horizontalSplitter_5.setObjectName(_fromUtf8("horizontalSplitter_5")) self.pushButtonTTL = QtGui.QPushButton(self.send) - 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)) +# 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) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 0, 255)) brush.setStyle(QtCore.Qt.SolidPattern) @@ -276,32 +302,53 @@ class Ui_MainWindow(object): self.pushButtonTTL.setFont(font) self.pushButtonTTL.setFlat(True) self.pushButtonTTL.setObjectName(_fromUtf8("pushButtonTTL")) - self.horizontalLayout_5.addWidget(self.pushButtonTTL) + self.horizontalSplitter_5.addWidget(self.pushButtonTTL) 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.horizontalLayout_5.addWidget(self.horizontalSliderTTL) + self.horizontalSplitter_5.addWidget(self.horizontalSliderTTL) 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) +# 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.horizontalLayout_5.addWidget(self.labelHumanFriendlyTTLDescription) + self.horizontalSplitter_5.addWidget(self.labelHumanFriendlyTTLDescription) self.pushButtonSend = QtGui.QPushButton(self.send) - self.pushButtonSend.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.pushButtonSend.setObjectName(_fromUtf8("pushButtonSend")) - self.horizontalLayout_5.addWidget(self.pushButtonSend) - self.verticalLayout.addLayout(self.horizontalLayout_5) - self.horizontalLayout.addLayout(self.verticalLayout) - self.gridLayout_7.addLayout(self.horizontalLayout, 0, 0, 1, 1) + self.horizontalSplitter_5.addWidget(self.pushButtonSend) + self.pushButtonTTL.setMaximumSize(QtCore.QSize(32, self.pushButtonSend.height())) + self.labelHumanFriendlyTTLDescription.setMaximumSize(QtCore.QSize(45, self.pushButtonSend.height())) + self.horizontalSliderTTL.setMaximumSize(QtCore.QSize(70, self.pushButtonSend.height())) + self.horizontalSplitter_5.resize(self.horizontalSplitter_5.width(), self.pushButtonSend.height()) + self.horizontalSplitter_5.setStretchFactor(0, 0) + self.horizontalSplitter_5.setStretchFactor(1, 0) + self.horizontalSplitter_5.setStretchFactor(2, 0) + self.horizontalSplitter_5.setStretchFactor(3, 1) + self.horizontalSplitter_5.setCollapsible(0, False) + self.horizontalSplitter_5.setCollapsible(1, False) + self.horizontalSplitter_5.setCollapsible(2, False) + self.horizontalSplitter_5.setCollapsible(3, False) + self.horizontalSplitter_5.handle(1).setEnabled(False) + self.horizontalSplitter_5.handle(2).setEnabled(False) + self.horizontalSplitter_5.handle(3).setEnabled(False) + self.verticalSplitter.addWidget(self.horizontalSplitter_5) + self.verticalSplitter.setStretchFactor(0, 0) + self.verticalSplitter.setStretchFactor(1, 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) 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("")) @@ -309,32 +356,39 @@ class Ui_MainWindow(object): self.subscriptions.setObjectName(_fromUtf8("subscriptions")) self.gridLayout_3 = QtGui.QGridLayout(self.subscriptions) self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3")) - self.horizontalLayout_4 = QtGui.QHBoxLayout() - self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4")) - self.verticalLayout_3 = QtGui.QVBoxLayout() - self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_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 = QtGui.QTreeWidget(self.subscriptions) - self.treeWidgetSubscriptions.setMaximumSize(QtCore.QSize(200, 16777215)) 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.verticalLayout_3.addWidget(self.treeWidgetSubscriptions) + self.verticalSplitter_3.addWidget(self.treeWidgetSubscriptions) self.pushButtonAddSubscription = QtGui.QPushButton(self.subscriptions) - self.pushButtonAddSubscription.setMaximumSize(QtCore.QSize(200, 16777215)) self.pushButtonAddSubscription.setObjectName(_fromUtf8("pushButtonAddSubscription")) - self.verticalLayout_3.addWidget(self.pushButtonAddSubscription) - self.horizontalLayout_4.addLayout(self.verticalLayout_3) - self.verticalLayout_4 = QtGui.QVBoxLayout() - self.verticalLayout_4.setObjectName(_fromUtf8("verticalLayout_4")) - self.horizontalLayout_2 = QtGui.QHBoxLayout() - self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) + 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 = settingsmixin.SSplitter() + self.horizontalSplitter_2.setObjectName(_fromUtf8("horizontalSplitter_2")) self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions) self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions")) - self.horizontalLayout_2.addWidget(self.inboxSearchLineEditSubscriptions) + self.horizontalSplitter_2.addWidget(self.inboxSearchLineEditSubscriptions) self.inboxSearchOptionSubscriptions = QtGui.QComboBox(self.subscriptions) self.inboxSearchOptionSubscriptions.setObjectName(_fromUtf8("inboxSearchOptionSubscriptions")) self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) @@ -342,9 +396,13 @@ class Ui_MainWindow(object): self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) self.inboxSearchOptionSubscriptions.addItem(_fromUtf8("")) - self.horizontalLayout_2.addWidget(self.inboxSearchOptionSubscriptions) - self.verticalLayout_4.addLayout(self.horizontalLayout_2) - self.tableWidgetInboxSubscriptions = QtGui.QTableWidget(self.subscriptions) + 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) @@ -369,59 +427,81 @@ class Ui_MainWindow(object): self.tableWidgetInboxSubscriptions.horizontalHeader().setStretchLastSection(True) self.tableWidgetInboxSubscriptions.verticalHeader().setVisible(False) self.tableWidgetInboxSubscriptions.verticalHeader().setDefaultSectionSize(26) - self.verticalLayout_4.addWidget(self.tableWidgetInboxSubscriptions) + self.verticalSplitter_4.addWidget(self.tableWidgetInboxSubscriptions) self.textEditInboxMessageSubscriptions = QtGui.QTextEdit(self.subscriptions) self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessageSubscriptions.setReadOnly(True) self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions")) - self.verticalLayout_4.addWidget(self.textEditInboxMessageSubscriptions) - self.horizontalLayout_4.addLayout(self.verticalLayout_4) - self.gridLayout_3.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) + 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) 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.tab_3 = QtGui.QWidget() - self.tab_3.setObjectName(_fromUtf8("tab_3")) - self.gridLayout_4 = QtGui.QGridLayout(self.tab_3) + self.chans = QtGui.QWidget() + self.chans.setObjectName(_fromUtf8("chans")) + self.gridLayout_4 = QtGui.QGridLayout(self.chans) self.gridLayout_4.setObjectName(_fromUtf8("gridLayout_4")) - self.horizontalLayout_7 = QtGui.QHBoxLayout() - self.horizontalLayout_7.setObjectName(_fromUtf8("horizontalLayout_7")) - self.verticalLayout_17 = QtGui.QVBoxLayout() - self.verticalLayout_17.setObjectName(_fromUtf8("verticalLayout_17")) - self.treeWidgetChans = QtGui.QTreeWidget(self.tab_3) - self.treeWidgetChans.setMaximumSize(QtCore.QSize(200, 16777215)) + 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 = QtGui.QTreeWidget(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()) 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.verticalLayout_17.addWidget(self.treeWidgetChans) - self.pushButtonAddChan = QtGui.QPushButton(self.tab_3) - self.pushButtonAddChan.setMaximumSize(QtCore.QSize(200, 16777215)) + self.verticalSplitter_17.addWidget(self.treeWidgetChans) + self.pushButtonAddChan = QtGui.QPushButton(self.chans) self.pushButtonAddChan.setObjectName(_fromUtf8("pushButtonAddChan")) - self.verticalLayout_17.addWidget(self.pushButtonAddChan) - self.horizontalLayout_7.addLayout(self.verticalLayout_17) - self.verticalLayout_8 = QtGui.QVBoxLayout() - self.verticalLayout_8.setObjectName(_fromUtf8("verticalLayout_8")) - self.horizontalLayout_6 = QtGui.QHBoxLayout() - self.horizontalLayout_6.setObjectName(_fromUtf8("horizontalLayout_6")) - self.inboxSearchLineEditChans = QtGui.QLineEdit(self.tab_3) + 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 = settingsmixin.SSplitter() + self.horizontalSplitter_6.setObjectName(_fromUtf8("horizontalSplitter_6")) + self.inboxSearchLineEditChans = QtGui.QLineEdit(self.chans) self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans")) - self.horizontalLayout_6.addWidget(self.inboxSearchLineEditChans) - self.inboxSearchOptionChans = QtGui.QComboBox(self.tab_3) + 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.horizontalLayout_6.addWidget(self.inboxSearchOptionChans) - self.verticalLayout_8.addLayout(self.horizontalLayout_6) - self.tableWidgetInboxChans = QtGui.QTableWidget(self.tab_3) + 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) @@ -446,17 +526,28 @@ class Ui_MainWindow(object): self.tableWidgetInboxChans.horizontalHeader().setStretchLastSection(True) self.tableWidgetInboxChans.verticalHeader().setVisible(False) self.tableWidgetInboxChans.verticalHeader().setDefaultSectionSize(26) - self.verticalLayout_8.addWidget(self.tableWidgetInboxChans) - self.textEditInboxMessageChans = QtGui.QTextEdit(self.tab_3) + self.verticalSplitter_8.addWidget(self.tableWidgetInboxChans) + self.textEditInboxMessageChans = QtGui.QTextEdit(self.chans) self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessageChans.setReadOnly(True) self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans")) - self.verticalLayout_8.addWidget(self.textEditInboxMessageChans) - self.horizontalLayout_7.addLayout(self.verticalLayout_8) - self.gridLayout_4.addLayout(self.horizontalLayout_7, 0, 0, 1, 1) + 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) icon8 = QtGui.QIcon() icon8.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/can-icon-16px.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.tab_3, icon8, _fromUtf8("")) + self.tabWidget.addTab(self.chans, icon8, _fromUtf8("")) self.blackwhitelist = QtGui.QWidget() self.blackwhitelist.setObjectName(_fromUtf8("blackwhitelist")) self.gridLayout_6 = QtGui.QGridLayout(self.blackwhitelist) @@ -473,7 +564,7 @@ class Ui_MainWindow(object): self.gridLayout_6.addWidget(self.pushButtonAddBlacklist, 2, 0, 1, 1) spacerItem = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.gridLayout_6.addItem(spacerItem, 2, 1, 1, 1) - self.tableWidgetBlacklist = QtGui.QTableWidget(self.blackwhitelist) + self.tableWidgetBlacklist = settingsmixin.STableWidget(self.blackwhitelist) self.tableWidgetBlacklist.setAlternatingRowColors(True) self.tableWidgetBlacklist.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.tableWidgetBlacklist.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) @@ -504,7 +595,7 @@ class Ui_MainWindow(object): self.pushButtonStatusIcon.setIcon(icon10) self.pushButtonStatusIcon.setFlat(True) self.pushButtonStatusIcon.setObjectName(_fromUtf8("pushButtonStatusIcon")) - self.tableWidgetConnectionCount = QtGui.QTableWidget(self.networkstatus) + self.tableWidgetConnectionCount = settingsmixin.STableWidget(self.networkstatus) self.tableWidgetConnectionCount.setGeometry(QtCore.QRect(20, 70, 241, 241)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(212, 208, 200)) @@ -675,7 +766,7 @@ class Ui_MainWindow(object): "p, li { white-space: pre-wrap; }\n" "\n" "


", None)) - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.tab), _translate("MainWindow", "Send ordinary Message", None)) + 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(_translate("MainWindow", "\n" @@ -683,7 +774,7 @@ class Ui_MainWindow(object): "p, li { white-space: pre-wrap; }\n" "\n" "


", None)) - self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.tab_2), _translate("MainWindow", "Send Message to your Subscribers", None)) + self.tabWidgetSend.setTabText(self.tabWidgetSend.indexOf(self.sendBroadcast), _translate("MainWindow", "Send Message to your Subscribers", None)) self.pushButtonTTL.setText(_translate("MainWindow", "TTL:", None)) self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "X days", None)) self.pushButtonSend.setText(_translate("MainWindow", "Send", None)) @@ -723,7 +814,7 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Subject", None)) item = self.tableWidgetInboxChans.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Chans", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", 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)) @@ -765,8 +856,9 @@ import bitmessage_icons_rc if __name__ == "__main__": import sys + app = QtGui.QApplication(sys.argv) - MainWindow = QtGui.QMainWindow() + MainWindow = settingsmixin.SMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() diff --git a/src/bitmessageqt/settingsmixin.py b/src/bitmessageqt/settingsmixin.py new file mode 100644 index 00000000..301ce96e --- /dev/null +++ b/src/bitmessageqt/settingsmixin.py @@ -0,0 +1,69 @@ +#!/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): + return + self.writeState(self.horizontalHeader()) + + +class SSplitter(QtGui.QSplitter, SettingsMixin): + def loadSettings(self): + self.readState(self) + + def saveSettings(self): + return + self.writeState(self) \ No newline at end of file -- 2.45.1 From 3f96962e62b18131ed8e9068ee2feecc686f51ac Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 21:45:49 +0100 Subject: [PATCH 0112/1102] Actually enable saving states It was temporarily disabled for testing resizing. Addresses #12 --- src/bitmessageqt/settingsmixin.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bitmessageqt/settingsmixin.py b/src/bitmessageqt/settingsmixin.py index 301ce96e..75822fa4 100644 --- a/src/bitmessageqt/settingsmixin.py +++ b/src/bitmessageqt/settingsmixin.py @@ -56,7 +56,6 @@ class STableWidget(QtGui.QTableWidget, SettingsMixin): self.readState(self.horizontalHeader()) def saveSettings(self): - return self.writeState(self.horizontalHeader()) @@ -65,5 +64,4 @@ class SSplitter(QtGui.QSplitter, SettingsMixin): self.readState(self) def saveSettings(self): - return self.writeState(self) \ No newline at end of file -- 2.45.1 From 83850536cfb520a7fa2d1abb6e2eb3a83b7cf456 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 22:12:12 +0100 Subject: [PATCH 0113/1102] Do not store search splitter state It causes problems because it can't be resized through GUI. --- src/bitmessageqt/bitmessageui.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 0e719c17..d8d63f31 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -79,7 +79,7 @@ class Ui_MainWindow(object): self.verticalSplitter_7 = settingsmixin.SSplitter() self.verticalSplitter_7.setObjectName(_fromUtf8("verticalSplitter_7")) self.verticalSplitter_7.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitterSearch = settingsmixin.SSplitter() + self.horizontalSplitterSearch = QtGui.QSplitter() self.horizontalSplitterSearch.setObjectName(_fromUtf8("horizontalSplitterSearch")) self.inboxSearchLineEdit = QtGui.QLineEdit(self.inbox) self.inboxSearchLineEdit.setObjectName(_fromUtf8("inboxSearchLineEdit")) @@ -384,7 +384,7 @@ class Ui_MainWindow(object): self.verticalSplitter_4 = settingsmixin.SSplitter() self.verticalSplitter_4.setObjectName(_fromUtf8("verticalSplitter_4")) self.verticalSplitter_4.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitter_2 = settingsmixin.SSplitter() + self.horizontalSplitter_2 = QtGui.QSplitter() self.horizontalSplitter_2.setObjectName(_fromUtf8("horizontalSplitter_2")) self.inboxSearchLineEditSubscriptions = QtGui.QLineEdit(self.subscriptions) self.inboxSearchLineEditSubscriptions.setObjectName(_fromUtf8("inboxSearchLineEditSubscriptions")) @@ -483,7 +483,7 @@ class Ui_MainWindow(object): self.verticalSplitter_8 = settingsmixin.SSplitter() self.verticalSplitter_8.setObjectName(_fromUtf8("verticalSplitter_8")) self.verticalSplitter_8.setOrientation(QtCore.Qt.Vertical) - self.horizontalSplitter_6 = settingsmixin.SSplitter() + self.horizontalSplitter_6 = QtGui.QSplitter() self.horizontalSplitter_6.setObjectName(_fromUtf8("horizontalSplitter_6")) self.inboxSearchLineEditChans = QtGui.QLineEdit(self.chans) self.inboxSearchLineEditChans.setObjectName(_fromUtf8("inboxSearchLineEditChans")) -- 2.45.1 From 2921b6553bf7fd1bee86cccfc9edbbb9a9daba24 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 23:03:05 +0100 Subject: [PATCH 0114/1102] TTL/send splitter shouldn't save state Because it also cannot be resized from the UI --- src/bitmessageqt/bitmessageui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index d8d63f31..269ec099 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -278,7 +278,7 @@ class Ui_MainWindow(object): self.gridLayout_9.addWidget(self.verticalSplitter_6, 0, 0, 1, 1) self.tabWidgetSend.addTab(self.sendBroadcast, _fromUtf8("")) self.verticalSplitter.addWidget(self.tabWidgetSend) - self.horizontalSplitter_5 = settingsmixin.SSplitter() + self.horizontalSplitter_5 = QtGui.QSplitter() self.horizontalSplitter_5.setObjectName(_fromUtf8("horizontalSplitter_5")) self.pushButtonTTL = QtGui.QPushButton(self.send) # sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) -- 2.45.1 From 03f709b70d63ca1f1f15603d4e6959fa90a9e37c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 8 Nov 2015 23:03:30 +0100 Subject: [PATCH 0115/1102] Bump version get ready for 0.5.2 --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 88c76e56..92868a3c 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.1' +softwareVersion = '0.5.2' 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. -- 2.45.1 From 12878af41fffd9e8bde942244533873ea4cc982e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 17:15:05 +0100 Subject: [PATCH 0116/1102] Fix Py2Exe / Py2App Fixes the C PoW loading in frozen apps (Windows and OSX) Cleaner fallback in PoW if something goes wrong --- src/proofofwork.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index f7776638..04e07af3 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -10,7 +10,12 @@ import openclpow import os import ctypes -curdir = os.path.dirname(__file__) +if frozen == "macosx_app": + curdir = os.environ.get("RESOURCEPATH") +elif frozen: # windows + curdir = sys._MEIPASS +else: + curdir = os.path.dirname(__file__) bitmsglib = 'bitmsghash.so' if "win32" == sys.platform: if ctypes.sizeof(ctypes.c_voidp) == 4: @@ -128,13 +133,18 @@ def run(target, initialHash): try: return _doGPUPoW(target, initialHash) except: - pass # fallback to normal PoW + pass # fallback + if bmpow: + try: + return _doCPoW(target, initialHash) + except: + pass # fallback if frozen == "macosx_app" or not frozen: - if bmpow: - try: - return _doCPoW(target, initialHash) - except: - pass # fallback to normal PoW - return _doFastPoW(target, initialHash) - else: - return _doSafePoW(target, initialHash) + # on my (Peter Surda) Windows 10, Windows Defender + # does not like this and fights with PyBitmessage + # over CPU, resulting in very slow PoW + try: + return _doFastPoW(target, initialHash) + except: + pass #fallback + return _doSafePoW(target, initialHash) -- 2.45.1 From e9a908aa834da4ccab6dd509065f46b32306e1fb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 17:21:47 +0100 Subject: [PATCH 0117/1102] Sqlite secure delete Fixes #102 --- src/class_sqlThread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index f0862591..9de44a42 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -25,6 +25,8 @@ class sqlThread(threading.Thread): 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( -- 2.45.1 From b74dc569ef0fac7d76ef23ef949a1794715cbdbe Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 17:31:06 +0100 Subject: [PATCH 0118/1102] Disable "Special address behaviour" in chan Fixes #97 --- src/bitmessageqt/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9bc69d79..1831f5a2 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3705,7 +3705,6 @@ class MyForm(settingsmixin.SMainWindow): else: self.popMenu.addAction(self.actionEnable) self.popMenu.addAction(self.actionSetAvatar) - self.popMenu.addAction(self.actionSpecialAddressBehavior) self.popMenu.exec_( self.ui.treeWidgetChans.mapToGlobal(point)) -- 2.45.1 From 8103874f6e0cbc9e65f61e0f33142ff097623ba5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 18:22:38 +0100 Subject: [PATCH 0119/1102] Allow deleting channels Fixes #96 --- src/bitmessageqt/__init__.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 1831f5a2..fae731b6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -226,6 +226,9 @@ class MyForm(settingsmixin.SMainWindow): # 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) @@ -459,7 +462,10 @@ class MyForm(settingsmixin.SMainWindow): widgets = {} for i in range (0, treeWidget.topLevelItemCount()): widget = treeWidget.topLevelItem(i) - toAddress = widget.address + if widget is not None: + toAddress = widget.address + else: + toAddress = None if not toAddress in db: treeWidget.takeTopLevelItem(i) @@ -3561,6 +3567,24 @@ class MyForm(settingsmixin.SMainWindow): def on_action_YourIdentitiesNew(self): self.click_NewAddressDialog() + def on_action_YourIdentitiesDelete(self): + account = self.getCurrentItem() + if account.type == "normal": + return # maybe in the future + elif account.type == "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?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: + shared.config.remove_section(str(account.address)) + else: + return + else: + return + shared.writeKeysFile() + shared.reloadMyAddressHashes() + if account.type == "normal": + self.rerenderTabTreeMessages() + elif account.type == "chan": + self.rerenderTabTreeChans() + def on_action_Enable(self): addressAtCurrentRow = self.getCurrentAccount() self.enableIdentity(addressAtCurrentRow) @@ -3697,6 +3721,7 @@ class MyForm(settingsmixin.SMainWindow): def on_context_menuChan(self, point): self.popMenu = QtGui.QMenu(self) self.popMenu.addAction(self.actionNew) + self.popMenu.addAction(self.actionDelete) self.popMenu.addSeparator() self.popMenu.addAction(self.actionClipboard) self.popMenu.addSeparator() -- 2.45.1 From d9401c7180e783419b2f23f2b2ac947ff74f0fc5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 18:44:27 +0100 Subject: [PATCH 0120/1102] several bugfixes for rerendertabtree It was prone to infinite loops, mixing elements etc. --- src/bitmessageqt/__init__.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fae731b6..0b656fa5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -460,7 +460,8 @@ class MyForm(settingsmixin.SMainWindow): treeWidget.setSortingEnabled(False) widgets = {} - for i in range (0, treeWidget.topLevelItemCount()): + i = 0 + while i < treeWidget.topLevelItemCount(): widget = treeWidget.topLevelItem(i) if widget is not None: toAddress = widget.address @@ -469,28 +470,32 @@ class MyForm(settingsmixin.SMainWindow): if not toAddress in db: treeWidget.takeTopLevelItem(i) - i -= 1 + # no increment continue unread = 0 - for j in range (0, widget.childCount()): + j = 0 + while j < widget.childCount(): subwidget = widget.child(j) try: subwidget.setUnreadCount(db[toAddress][subwidget.folderName]) unread += db[toAddress][subwidget.folderName] db[toAddress].pop(subwidget.folderName, None) except: - widget.takeChild(i) - j -= 1 + widget.takeChild(j) + # no increment + continue + j += 1 # add missing folders if len(db[toAddress]) > 0: - i = 0 + j = 0 for f, c in db[toAddress].iteritems(): print "adding %s, %i" % (f, c) - subwidget = Ui_FolderWidget(widget, i, toAddress, f, c) - i += 1 + subwidget = Ui_FolderWidget(widget, j, toAddress, f, c) + j += 1 widget.setUnreadCount(unread) db.pop(toAddress, None) + i += 1 i = 0 for toAddress in db: -- 2.45.1 From 2783a1c1e5d7fb21fade87c87efaf6133e20b0ee Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 18:45:35 +0100 Subject: [PATCH 0121/1102] Autofold/unfold when enabling/disabling Fixes #93 --- src/bitmessageqt/foldertree.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 6f5ad40c..1aab7e0e 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -29,6 +29,8 @@ class AccountMixin (object): def setEnabled(self, enabled): self.isEnabled = enabled + if hasattr(self, "setExpanded"): + self.setExpanded(enabled) self.updateText() def setType(self): @@ -107,9 +109,8 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): self.setAddress(address) self.setEnabled(enabled) self.setUnreadCount(unreadCount) - self.setType() self.initialised = True - self.setExpanded(enabled) # does updateText + self.setType() # does updateText def setAddress(self, address): super(Ui_AddressWidget, self).setAddress(address) @@ -182,9 +183,8 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): self.setEnabled(enabled) self.setType() self.setLabel(label) - self.setUnreadCount (unreadCount) self.initialised = True - self.setExpanded(enabled) # does updateText + self.setUnreadCount (unreadCount) # does updateText def setLabel(self, label): self.label = label -- 2.45.1 From 4aaf0048c693cb398ca56c765e3069ed95bdc146 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 18:58:27 +0100 Subject: [PATCH 0122/1102] Disabled folder color Fixes #92 --- src/bitmessageqt/foldertree.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 1aab7e0e..8bbba0c9 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -14,10 +14,21 @@ class AccountMixin (object): 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): self.address = str(address) @@ -53,6 +64,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): self.setAddress(address) self.setFolderName(folderName) self.setUnreadCount(unreadCount) + self.parent = parent self.initialised = True self.updateText() parent.insertChild(pos, self) @@ -73,6 +85,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): else: font.setBold(False) self.setFont(0, font) + self.setForeground(0, self.folderBrush()) self.setText(0, text) self.setToolTip(0, text) # self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName]) -- 2.45.1 From 1a842730a2619f960b9c094169ac92e2d5327f1d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 9 Nov 2015 19:39:30 +0100 Subject: [PATCH 0123/1102] Newly sent messages and status update - newly sent messages did not appear in all tabs - message status change didn't work in all tabs - addresses #90 - however, still new sent message sender/recipient do not have the correct color --- src/bitmessageqt/__init__.py | 173 +++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 78 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0b656fa5..f73f8243 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1808,56 +1808,53 @@ class MyForm(settingsmixin.SMainWindow): return self.unreadCount def updateSentItemStatusByToAddress(self, toAddress, textToDisplay): - sent = self.getAccountMessagelist(toAddress) - treeWidget = self.getAccountTreeWidget(toAddress) - if self.getCurrentFolder(treeWidget) != "sent": - return - for i in range(sent.rowCount()): - rowAddress = str(sent.item( - i, 0).data(Qt.UserRole).toPyObject()) - 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 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 = str(sent.item( + i, 0).data(Qt.UserRole).toPyObject()) + 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) def updateSentItemStatusByAckdata(self, ackdata, textToDisplay): - for i in range(self.ui.tableWidgetInbox.rowCount()): - toAddress = str(self.ui.tableWidgetInbox.item( - i, 0).data(Qt.UserRole).toPyObject()) - tableAckdata = self.ui.tableWidgetInbox.item( - i, 3).data(Qt.UserRole).toPyObject() - status, addressVersionNumber, streamNumber, ripe = decodeAddress( - toAddress) - if ackdata == tableAckdata: - self.ui.tableWidgetInbox.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.tableWidgetInbox.item(i, 3).setText( - textToDisplay[:newlinePosition]) - else: - self.ui.tableWidgetInbox.item(i, 3).setText(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 = str(sent.item( + i, 0).data(Qt.UserRole).toPyObject()) + tableAckdata = sent.item( + i, 3).data(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) def removeInboxRowByMsgid(self, msgid): # msgid and inventoryHash are the same thing - def widgetConvert (tableWidget): - if tableWidget == self.ui.tableWidgetInbox: - return self.ui.treeWidgetYourIdentities - elif tableWidget == self.ui.tableWidgetInboxSubscriptions: - return self.ui.treeWidgetSubscriptions - elif tableWidget == self.ui.tableWidgetInboxChans: - return self.ui.treeWidgetChans - else: - return None - for inbox in ([ self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, @@ -1866,7 +1863,7 @@ class MyForm(settingsmixin.SMainWindow): if msgid == str(inbox.item(i, 3).data(Qt.UserRole).toPyObject()): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) - treeWidget = widgetConvert(inbox) + treeWidget = self.widgetConvert(inbox) self.propagateUnreadCount(self.getCurrentAccount(treeWidget), self.getCurrentFolder(treeWidget), treeWidget, 0) inbox.removeRow(i) break @@ -2327,39 +2324,43 @@ class MyForm(settingsmixin.SMainWindow): message = shared.fixPotentiallyInvalidUTF8Data(message) acct = accountClass(fromAddress) acct.parseMessage(toAddress, fromAddress, subject, message) - sent = self.getAccountMessagelist(acct) - treeWidget = self.getAccountTreeWidget(acct) - if self.getCurrentFolder(treeWidget) != "sent" or self.getCurrentAccount(treeWidget) != fromAddress: - return + for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: + 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 - sent.setSortingEnabled(False) - sent.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) - newItem.setData(Qt.UserRole, str(toAddress)) - newItem.setIcon(avatarize(toAddress)) - sent.setItem(0, 0, newItem) - newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) - newItem.setData(Qt.UserRole, str(fromAddress)) - newItem.setIcon(avatarize(fromAddress)) - sent.setItem(0, 1, newItem) - newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) - newItem.setToolTip(unicode(acct.subject, 'utf-8)')) - newItem.setData(Qt.UserRole, str(subject)) + sent.setSortingEnabled(False) + sent.insertRow(0) + newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) + newItem.setData(Qt.UserRole, str(toAddress)) + newItem.setIcon(avatarize(toAddress)) + sent.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) + newItem.setData(Qt.UserRole, str(fromAddress)) + newItem.setIcon(avatarize(fromAddress)) + sent.setItem(0, 1, newItem) + newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) + newItem.setToolTip(unicode(acct.subject, 'utf-8)')) + newItem.setData(Qt.UserRole, str(subject)) - #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. - sent.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())) - sent.setItem(0, 3, newItem) - self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)')) - sent.setSortingEnabled(True) + #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. + sent.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())) + sent.setItem(0, 3, newItem) + self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)')) + sent.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): subject = shared.fixPotentiallyInvalidUTF8Data(subject) @@ -3422,6 +3423,22 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute( '''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) + 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 twidget == self.ui.treeWidgetChans: + return self.ui.tableWidgetInboxChans + else: + return None + def getCurrentTreeWidget(self): currentIndex = self.ui.tabWidget.currentIndex(); treeWidgetList = [ -- 2.45.1 From 57575d0a399bc615a897a831388428d971949b87 Mon Sep 17 00:00:00 2001 From: Henrik Olsson Date: Mon, 9 Nov 2015 19:38:16 +0100 Subject: [PATCH 0124/1102] Fix some typos Author: Henrik Olsson --- src/class_singleWorker.py | 2 +- src/helper_startup.py | 2 +- src/translations/bitmessage_de.ts | 2 +- src/translations/bitmessage_eo.ts | 2 +- src/translations/bitmessage_zh_cn.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 327f526a..888d96f6 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -948,7 +948,7 @@ class singleWorker(threading.Thread): toAddress) shared.UISignalQueue.put(( - 'updateStatusBar', tr.translateText("MainWindow",'Broacasting the public key request. This program will auto-retry if they are offline.'))) + 'updateStatusBar', tr.translateText("MainWindow",'Broadcasting 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): diff --git a/src/helper_startup.py b/src/helper_startup.py index 778fe70a..0d4e0cb0 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -145,5 +145,5 @@ def isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections(): 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 + print "Info: we could not tell whether your OS is limited to having very few 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/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 1c817a98..3e0a2546 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -905,7 +905,7 @@ p, li { white-space: pre-wrap; } - Broacasting 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. Anfrage für den Verschlüsselungscode versendet (wird automatisch periodisch neu verschickt). diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 00e33f9e..8fac557f 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -899,7 +899,7 @@ p, li { white-space: pre-wrap; } - Broacasting 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. Anfrage für den Verschlüsselungscode versendet (wird automatisch periodisch neu verschickt). diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 40c648e9..0b580e65 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -1065,7 +1065,7 @@ Receiver's required difficulty: %1 and %2 - Broacasting 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. 正在广播公钥请求. 如果他们不在线, 这一过程将自动重试. -- 2.45.1 From 2947462d45d405f830065c681beec83bc496e000 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 10 Nov 2015 13:15:07 +0100 Subject: [PATCH 0125/1102] Unregistering of unregeistered accounts Since it's unregistered, we don't know where to unregister from. Fixes #91. --- src/bitmessageqt/__init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f73f8243..73d1fc2b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2802,7 +2802,7 @@ class MyForm(settingsmixin.SMainWindow): # no chans / mailinglists if acct.type != 'normal': return - if self.dialog.ui.radioButtonUnregister.isChecked(): + if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): print "unregister" acct.unregister() shared.config.remove_option(addressAtCurrentRow, 'gateway') @@ -4243,7 +4243,10 @@ class EmailGatewayDialog(QtGui.QDialog): self.parent = parent addressAtCurrentRow = parent.getCurrentAccount() acct = accountClass(addressAtCurrentRow) -# if isinstance(acct, GatewayAccount): + if isinstance(acct, GatewayAccount): + self.ui.radioButtonUnregister.setEnabled(True) + else: + self.ui.radioButtonUnregister.setEnabled(False) label = shared.config.get(addressAtCurrentRow, 'label') if label.find("@mailchuck.com") > -1: self.ui.lineEditEmail.setText(label) -- 2.45.1 From a85e9ed20ef5687bd47521d44b52bec8fea34b67 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 11 Nov 2015 00:51:55 +0100 Subject: [PATCH 0126/1102] Default message font Fixes #106 and Bitmesage#248 --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 73d1fc2b..447b8d9b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3915,6 +3915,8 @@ class MyForm(settingsmixin.SMainWindow): if data != False: message = "Error occurred: could not load message from disk." message = unicode(message, 'utf-8)') + messageTextedit.setCurrentFont(QtGui.QFont()) + messageTextedit.setTextColor(QtGui.QColor()) messageTextedit.setPlainText(message) def tableWidgetAddressBookItemChanged(self): -- 2.45.1 From 8f5d177690a1e416283f4d18aebbd3568c6de8c5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 11 Nov 2015 01:02:23 +0100 Subject: [PATCH 0127/1102] Enabling/disabling color propagation Fixes #105 --- src/bitmessageqt/foldertree.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 8bbba0c9..c27cf6c5 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -42,6 +42,10 @@ class AccountMixin (object): 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) self.updateText() def setType(self): -- 2.45.1 From 4b889221048cc2ab8f7d53964516555fddd7f577 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 11 Nov 2015 02:42:03 +0100 Subject: [PATCH 0128/1102] Translation directory for OSX bundles Addresses bitmessage#514 --- src/bitmessageqt/__init__.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 447b8d9b..3d68f37d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -67,11 +67,13 @@ def _translate(context, text): def change_translation(locale): global qtranslator qtranslator = QtCore.QTranslator() - translationpath = os.path.join( - getattr(sys, '_MEIPASS', sys.path[0]), - 'translations', - 'bitmessage_' + locale - ) + if shared.frozen == "macosx_app": + translationpath = os.environ.get("RESOURCEPATH") + elif shared.frozen: # windows + translationpath = sys._MEIPASS + else: + translationpath = os.path.dirname(os.path.dirname(__file__)) + translationpath = os.path.join (translationpath, 'translations', 'bitmessage_' + locale) qtranslator.load(translationpath) QtGui.QApplication.installTranslator(qtranslator) -- 2.45.1 From 5b724f366ed6727f5a0b7cc50d5463efa48f9757 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 00:33:57 +0100 Subject: [PATCH 0129/1102] Prepare for tree widgets to store settings Precursor for #12 --- src/bitmessageqt/bitmessageui.py | 6 +++--- src/bitmessageqt/foldertree.py | 3 ++- src/bitmessageqt/settingsmixin.py | 14 +++++++++++++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 269ec099..230104b3 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -59,7 +59,7 @@ class Ui_MainWindow(object): self.verticalSplitter_12 = settingsmixin.SSplitter() self.verticalSplitter_12.setObjectName(_fromUtf8("verticalSplitter_12")) self.verticalSplitter_12.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetYourIdentities = QtGui.QTreeWidget(self.inbox) + self.treeWidgetYourIdentities = settingsmixin.STreeWidget(self.inbox) self.treeWidgetYourIdentities.setObjectName(_fromUtf8("treeWidgetYourIdentities")) self.treeWidgetYourIdentities.resize(200, self.treeWidgetYourIdentities.height()) icon1 = QtGui.QIcon() @@ -361,7 +361,7 @@ class Ui_MainWindow(object): self.verticalSplitter_3 = settingsmixin.SSplitter() self.verticalSplitter_3.setObjectName(_fromUtf8("verticalSplitter_3")) self.verticalSplitter_3.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetSubscriptions = QtGui.QTreeWidget(self.subscriptions) + self.treeWidgetSubscriptions = settingsmixin.STreeWidget(self.subscriptions) self.treeWidgetSubscriptions.setAlternatingRowColors(True) self.treeWidgetSubscriptions.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.treeWidgetSubscriptions.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) @@ -458,7 +458,7 @@ class Ui_MainWindow(object): self.verticalSplitter_17 = settingsmixin.SSplitter() self.verticalSplitter_17.setObjectName(_fromUtf8("verticalSplitter_17")) self.verticalSplitter_17.setOrientation(QtCore.Qt.Vertical) - self.treeWidgetChans = QtGui.QTreeWidget(self.chans) + self.treeWidgetChans = settingsmixin.STreeWidget(self.chans) self.treeWidgetChans.setFrameShadow(QtGui.QFrame.Sunken) self.treeWidgetChans.setLineWidth(1) self.treeWidgetChans.setAlternatingRowColors(True) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index c27cf6c5..59f16667 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -2,6 +2,7 @@ from PyQt4 import QtCore, QtGui from utils import * import shared +from settingsmixin import SettingsMixin class AccountMixin (object): def accountColor (self): @@ -116,7 +117,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): return super(QtGui.QTreeWidgetItem, self).__lt__(other) -class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin): +class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def __init__(self, parent, pos = 0, address = "", unreadCount = 0, enabled = True): super(QtGui.QTreeWidgetItem, self).__init__() parent.insertTopLevelItem(pos, self) diff --git a/src/bitmessageqt/settingsmixin.py b/src/bitmessageqt/settingsmixin.py index 75822fa4..c534d1b5 100644 --- a/src/bitmessageqt/settingsmixin.py +++ b/src/bitmessageqt/settingsmixin.py @@ -64,4 +64,16 @@ class SSplitter(QtGui.QSplitter, SettingsMixin): self.readState(self) def saveSettings(self): - self.writeState(self) \ No newline at end of file + 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 -- 2.45.1 From 79e199b45a4a688fdf5350108db561ae3f1bcdd0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 00:54:22 +0100 Subject: [PATCH 0130/1102] Show sync status in Network tab Addresses Bitmessage#745 (but no API exposure yet) --- src/bitmessageqt/__init__.py | 3 +++ src/bitmessageqt/bitmessageui.py | 10 +++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3d68f37d..37892aa6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1605,14 +1605,17 @@ class MyForm(settingsmixin.SMainWindow): self.appIndicatorShowOrHideWindow() def updateNumberOfMessagesProcessed(self): + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) self.ui.labelMessageCount.setText(_translate( "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) def updateNumberOfBroadcastsProcessed(self): + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) self.ui.labelBroadcastCount.setText(_translate( "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) def updateNumberOfPubkeysProcessed(self): + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) self.ui.labelPubkeyCount.setText(_translate( "MainWindow", "Processed %1 public keys.").arg(str(shared.numberOfPubkeysProcessed))) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 230104b3..e303567f 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -639,14 +639,17 @@ class Ui_MainWindow(object): self.labelBroadcastCount = QtGui.QLabel(self.networkstatus) self.labelBroadcastCount.setGeometry(QtCore.QRect(350, 150, 351, 16)) self.labelBroadcastCount.setObjectName(_fromUtf8("labelBroadcastCount")) + self.labelSyncStatus = QtGui.QLabel(self.networkstatus) + self.labelSyncStatus.setGeometry(QtCore.QRect(350, 190, 331, 20)) + self.labelSyncStatus.setObjectName(_fromUtf8("labelSyncStatus")) self.labelLookupsPerSecond = QtGui.QLabel(self.networkstatus) - self.labelLookupsPerSecond.setGeometry(QtCore.QRect(320, 250, 291, 16)) + self.labelLookupsPerSecond.setGeometry(QtCore.QRect(320, 270, 291, 16)) self.labelLookupsPerSecond.setObjectName(_fromUtf8("labelLookupsPerSecond")) self.labelBytesRecvCount = QtGui.QLabel(self.networkstatus) - self.labelBytesRecvCount.setGeometry(QtCore.QRect(350, 210, 251, 16)) + self.labelBytesRecvCount.setGeometry(QtCore.QRect(350, 230, 251, 16)) self.labelBytesRecvCount.setObjectName(_fromUtf8("labelBytesRecvCount")) self.labelBytesSentCount = QtGui.QLabel(self.networkstatus) - self.labelBytesSentCount.setGeometry(QtCore.QRect(350, 230, 251, 16)) + self.labelBytesSentCount.setGeometry(QtCore.QRect(350, 250, 251, 16)) self.labelBytesSentCount.setObjectName(_fromUtf8("labelBytesSentCount")) icon11 = QtGui.QIcon() icon11.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) @@ -830,6 +833,7 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Connections", None)) self.labelTotalConnections.setText(_translate("MainWindow", "Total connections:", None)) self.labelStartupTime.setText(_translate("MainWindow", "Since startup:", None)) + self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced:", 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)) -- 2.45.1 From 10474b3561d19483e07017649912f968ac9da9d9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 01:00:27 +0100 Subject: [PATCH 0131/1102] Fix sync status sum Last commit was broken. --- src/bitmessageqt/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 37892aa6..e47d15ee 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1605,17 +1605,17 @@ class MyForm(settingsmixin.SMainWindow): self.appIndicatorShowOrHideWindow() def updateNumberOfMessagesProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.ui.labelMessageCount.setText(_translate( "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) def updateNumberOfBroadcastsProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.ui.labelBroadcastCount.setText(_translate( "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) def updateNumberOfPubkeysProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)))) + self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.ui.labelPubkeyCount.setText(_translate( "MainWindow", "Processed %1 public keys.").arg(str(shared.numberOfPubkeysProcessed))) -- 2.45.1 From 0e15b246af0ef1293740ab5fe7c0dfa10bf4372a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 01:42:20 +0100 Subject: [PATCH 0132/1102] Fix broadcast Any normal address should be able to broadcast. Reported over BM in one of the chans. --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e47d15ee..0da7b7a9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2307,8 +2307,8 @@ class MyForm(settingsmixin.SMainWindow): for addressInKeysFile in getSortedAccounts(): 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. - isMaillinglist = shared.safeConfigGetBoolean(addressInKeysFile, 'mailinglist') - if isEnabled and isMaillinglist: + isChan = shared.safeConfigGetBoolean(addressInKeysFile, 'chan') + if isEnabled and not isChan: self.ui.comboBoxSendFromBroadcast.addItem(avatarize(addressInKeysFile), unicode(shared.config.get( addressInKeysFile, 'label'), 'utf-8'), addressInKeysFile) for i in range(self.ui.comboBoxSendFromBroadcast.count()): -- 2.45.1 From f68627158d84924c292a01fbce4bd3906de03bae Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 01:43:06 +0100 Subject: [PATCH 0133/1102] Click on inactive tab Would cause exception. --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0da7b7a9..7c579918 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3874,6 +3874,8 @@ class MyForm(settingsmixin.SMainWindow): def tableWidgetInboxItemClicked(self): folder = self.getCurrentFolder() messageTextedit = self.getCurrentMessageTextedit() + if not messageTextedit: + return queryreturn = [] message = "" -- 2.45.1 From ceda22ec9474811d89d0082564ef19e77653937c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 12 Nov 2015 17:36:12 +0100 Subject: [PATCH 0134/1102] Private IP range update Addresses Bitmessage#768 --- src/class_receiveDataThread.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 07569b7b..19135c1f 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -485,13 +485,16 @@ class receiveDataThread(threading.Thread): def _checkIPv4Address(self, host, hostStandardFormat): # print 'hostStandardFormat', hostStandardFormat - if host[0] == '\x7F': + if host[0] == '\x7F': # 127/8 print 'Ignoring IP address in loopback range:', hostStandardFormat return False - if host[0] == '\x0A': + if host[0] == '\x0A': # 10/8 print 'Ignoring IP address in private range:', hostStandardFormat return False - if host[0:2] == '\xC0\xA8': + if host[0:2] == '\xC0\xA8': # 192.168/16 + 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 print 'Ignoring IP address in private range:', hostStandardFormat return False return True -- 2.45.1 From 25cc1dc287272bc0f2ce970f49621ca45bcaf18a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 13 Nov 2015 12:25:50 +0100 Subject: [PATCH 0135/1102] Unified code for finding source code location It is already used in 3 places so I put it into a function --- src/bitmessageqt/__init__.py | 8 +------- src/proofofwork.py | 12 +++--------- src/shared.py | 9 +++++++++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7c579918..8cd8cbda 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -67,13 +67,7 @@ def _translate(context, text): def change_translation(locale): global qtranslator qtranslator = QtCore.QTranslator() - if shared.frozen == "macosx_app": - translationpath = os.environ.get("RESOURCEPATH") - elif shared.frozen: # windows - translationpath = sys._MEIPASS - else: - translationpath = os.path.dirname(os.path.dirname(__file__)) - translationpath = os.path.join (translationpath, 'translations', 'bitmessage_' + locale) + translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + locale) qtranslator.load(translationpath) QtGui.QApplication.installTranslator(qtranslator) diff --git a/src/proofofwork.py b/src/proofofwork.py index 04e07af3..fc779467 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -4,18 +4,12 @@ import hashlib from struct import unpack, pack import sys -from shared import config, frozen +from shared import config, frozen, codePath import shared import openclpow import os import ctypes -if frozen == "macosx_app": - curdir = os.environ.get("RESOURCEPATH") -elif frozen: # windows - curdir = sys._MEIPASS -else: - curdir = os.path.dirname(__file__) bitmsglib = 'bitmsghash.so' if "win32" == sys.platform: if ctypes.sizeof(ctypes.c_voidp) == 4: @@ -23,12 +17,12 @@ if "win32" == sys.platform: else: bitmsglib = 'bitmsghash64.dll' try: - bso = ctypes.WinDLL(os.path.join(curdir, "bitmsghash", bitmsglib)) + bso = ctypes.WinDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) except: bso = None else: try: - bso = ctypes.CDLL(os.path.join(curdir, "bitmsghash", bitmsglib)) + bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) except: bso = None if bso: diff --git a/src/shared.py b/src/shared.py index 92868a3c..4877ce13 100644 --- a/src/shared.py +++ b/src/shared.py @@ -217,6 +217,15 @@ def lookupAppdataFolder(): pass dataFolder = dataFolder + '/' return dataFolder + +def codePath(): + if frozen == "macosx_app": + codePath = os.environ.get("RESOURCEPATH") + elif frozen: # windows + codePath = sys._MEIPASS + else: + codePath = os.path.dirname(__file__) + return codePath def isAddressInMyAddressBook(address): queryreturn = sqlQuery( -- 2.45.1 From 53b0d2749b4475b659f6043332c006cf73598c12 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 13 Nov 2015 12:32:10 +0100 Subject: [PATCH 0136/1102] Opportunistic encryption with TLS (1 of 2) Fixes Bitmessage#264 Fixes Bitmessage#648 --- src/class_receiveDataThread.py | 32 ++++++++++++++++++++++++++++++-- src/class_sendDataThread.py | 7 ++++++- src/shared.py | 2 +- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 19135c1f..737872d1 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,11 +1,15 @@ doTimingAttackMitigation = True +import errno import time import threading import shared import hashlib +import os +import select import socket import random +import ssl from struct import unpack, pack import sys import traceback @@ -49,6 +53,7 @@ class receiveDataThread(threading.Thread): shared.connectedHostsList[ 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 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: @@ -76,7 +81,10 @@ class receiveDataThread(threading.Thread): shared.numberOfBytesReceivedLastSecond = 0 dataLen = len(self.data) try: - dataRecv = self.sock.recv(1024) + if (self.services & 2 == 2) and self.connectionIsOrWasFullyEstablished: + dataRecv = self.sslSock.recv(1024) + else: + dataRecv = self.sock.recv(1024) self.data += 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 @@ -85,6 +93,9 @@ class receiveDataThread(threading.Thread): print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')' break except Exception as err: + if (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): + select.select([self.sslSock], [], []) + continue with shared.printLock: print 'sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID:', str(id(self)) + ').', err break @@ -252,8 +263,24 @@ class receiveDataThread(threading.Thread): # there is no reason to run this function a second time return self.connectionIsOrWasFullyEstablished = True + + self.sslSock = self.sock + if (self.services & 2 == 2): + self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_SSLv23, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') + while True: + try: + self.sslSock.do_handshake() + break + except ssl.SSLError as e: + if e.errno == 2: + select.select([self.sslSock], [self.sslSock], []) + else: + break + except: + break # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also - self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', 'no data')) + self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) + if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True shared.UISignalQueue.put(('setStatusIcon', 'green')) @@ -674,6 +701,7 @@ class receiveDataThread(threading.Thread): """ 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: diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index bb19c9f6..fedd4833 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -36,6 +36,7 @@ class sendDataThread(threading.Thread): self.sock = sock self.peer = shared.Peer(HOST, PORT) self.streamNumber = streamNumber + self.services = 0 self.remoteProtocolVersion = - \ 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.sendDataThreadQueue queue. self.lastTimeISentData = int( @@ -82,7 +83,10 @@ class sendDataThread(threading.Thread): uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 - amountSent = self.sock.send(data[:1000]) + if self.services & 2 == 2 and self.connectionIsOrWasFullyEstablished: + amountSent = self.sslSock.send(data[:1000]) + else: + 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()) @@ -178,6 +182,7 @@ class sendDataThread(threading.Thread): break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True + self.services, self.sslSock = data else: with shared.printLock: print 'sendDataThread ID:', id(self), 'ignoring command', command, 'because the thread is not in stream', deststream diff --git a/src/shared.py b/src/shared.py index 4877ce13..0b5f0c01 100644 --- a/src/shared.py +++ b/src/shared.py @@ -144,7 +144,7 @@ def encodeHost(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', 3) # bitflags of the services I offer. payload += pack('>q', int(time.time())) payload += pack( -- 2.45.1 From c804f6c181923185edff524385d8b10a56849c8e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 13 Nov 2015 12:35:28 +0100 Subject: [PATCH 0137/1102] Opportunistic encryption with TLS (2 of 2) These are dummy key and certificates. They are loaded but otherwise not used. This is a workaround against python's ssl_wrap deficiency, it won't allow to execute a server-side SSL handshake without a loaded key + cert. Since generating key/cert locally would require additional libraries, I opted for including a dummy one in the source. --- src/sslkeys/cert.pem | 15 +++++++++++++++ src/sslkeys/key.pem | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/sslkeys/cert.pem create mode 100644 src/sslkeys/key.pem diff --git a/src/sslkeys/cert.pem b/src/sslkeys/cert.pem new file mode 100644 index 00000000..a976db75 --- /dev/null +++ b/src/sslkeys/cert.pem @@ -0,0 +1,15 @@ +-----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 new file mode 100644 index 00000000..a47bcc3c --- /dev/null +++ b/src/sslkeys/key.pem @@ -0,0 +1,16 @@ +-----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----- -- 2.45.1 From 2f874e41be7aaf54d84e4e4b6e3ec7fff420877e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 13 Nov 2015 14:31:22 +0100 Subject: [PATCH 0138/1102] Fix adding/editing entries in addresbook It didn't sort correctly and didn't update the label correctly when changed. Fixes #95 --- src/bitmessageqt/__init__.py | 24 +++--------------------- src/bitmessageqt/foldertree.py | 6 ++++++ 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8cd8cbda..67838836 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2431,17 +2431,8 @@ class MyForm(settingsmixin.SMainWindow): 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.rerenderAddressBook() self.rerenderInboxFromLabels() self.rerenderSentToLabels() else: @@ -3073,20 +3064,10 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from addressbook where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - 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(1) - self.ui.tableWidgetAddressBook.setCurrentCell(0, 0) + self.rerenderAddressBook() self.statusBar().showMessage(_translate( "MainWindow", "Entry added to the Address Book. Edit the label to your liking.")) else: @@ -3928,6 +3909,7 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', str(self.ui.tableWidgetAddressBook.item(currentRow, 0).text().toUtf8()), str(addressAtCurrentRow)) + self.ui.tableWidgetAddressBook.item(currentRow, 0).setLabel(str(self.ui.tableWidgetAddressBook.item(currentRow, 0).text().toUtf8())) self.rerenderInboxFromLabels() self.rerenderSentToLabels() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 59f16667..20291c5d 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -287,9 +287,15 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): Ui_AddressBookWidgetItem.__init__(self, label, type) + self.address = address + self.label = label self.setIcon(avatarize(address)) self.setToolTip(label + " (" + address + ")") + def setLabel(self, label): + self.label = label + self.setToolTip(self.label + " (" + self.address + ")") + class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): -- 2.45.1 From c7fb9e6a4359b8ea4fca53eb5bd43da306de5478 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 13 Nov 2015 17:01:09 +0100 Subject: [PATCH 0139/1102] SSL fixes - uses constants for service flags - requires SSL to use TLSv1 version (protection against POODLE-style attacks) - retry if sock.recv incomplete --- src/class_receiveDataThread.py | 10 +++++----- src/class_sendDataThread.py | 2 +- src/shared.py | 6 +++++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 737872d1..059bce87 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -81,7 +81,7 @@ class receiveDataThread(threading.Thread): shared.numberOfBytesReceivedLastSecond = 0 dataLen = len(self.data) try: - if (self.services & 2 == 2) and self.connectionIsOrWasFullyEstablished: + if (self.services & shared.NODE_SSL == shared.NODE_SSL) and self.connectionIsOrWasFullyEstablished: dataRecv = self.sslSock.recv(1024) else: dataRecv = self.sock.recv(1024) @@ -93,11 +93,11 @@ class receiveDataThread(threading.Thread): print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')' break except Exception as err: - if (sys.platform == 'win32' and err.errno == 10035) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): + if (sys.platform == 'win32' and err.errno in ([2, 10035])) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): select.select([self.sslSock], [], []) continue with shared.printLock: - print 'sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID:', str(id(self)) + ').', err + print 'sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID:', str(id(self)) + ').', str(err.errno), "/", err break # print 'Received', repr(self.data) if len(self.data) == dataLen: # If self.sock.recv returned no data: @@ -265,8 +265,8 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.sslSock = self.sock - if (self.services & 2 == 2): - self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_SSLv23, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') + if (self.services & shared.NODE_SSL == shared.NODE_SSL): + self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') while True: try: self.sslSock.do_handshake() diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index fedd4833..4ee88399 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -83,7 +83,7 @@ class sendDataThread(threading.Thread): uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 - if self.services & 2 == 2 and self.connectionIsOrWasFullyEstablished: + if self.services & shared.NODE_SSL == shared.NODE_SSL and self.connectionIsOrWasFullyEstablished: amountSent = self.sslSock.send(data[:1000]) else: amountSent = self.sock.send(data[:1000]) diff --git a/src/shared.py b/src/shared.py index 0b5f0c01..6f6d5a1c 100644 --- a/src/shared.py +++ b/src/shared.py @@ -120,6 +120,10 @@ trustedPeer = None #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') +#Service flags +NODE_NETWORK = 1 +NODE_SSL = 2 + #Create a packet def CreatePacket(command, payload=''): payload_length = len(payload) @@ -144,7 +148,7 @@ def encodeHost(host): def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): payload = '' payload += pack('>L', 3) # protocol version. - payload += pack('>q', 3) # bitflags of the services I offer. + payload += pack('>q', NODE_NETWORK|NODE_SSL) # bitflags of the services I offer. payload += pack('>q', int(time.time())) payload += pack( -- 2.45.1 From a02ea142336e3dfdfdd4ab1578b55f90cd6027c4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 14 Nov 2015 01:14:10 +0100 Subject: [PATCH 0140/1102] Blacklist through context menu Fixes #101 --- src/bitmessageqt/__init__.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 67838836..2299c524 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -142,6 +142,10 @@ class MyForm(settingsmixin.SMainWindow): _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) @@ -3074,6 +3078,28 @@ class MyForm(settingsmixin.SMainWindow): 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 on_action_InboxAddSenderToBlackList(self): + tableWidget = self.getCurrentMessagelist() + if not tableWidget: + return + currentInboxRow = tableWidget.currentRow() + # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() + addressAtCurrentInboxRow = str(tableWidget.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=?''', + addressAtCurrentInboxRow) + if queryreturn == []: + sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', + '--New entry. Change label in Blacklist.--', + addressAtCurrentInboxRow, True) + self.rerenderBlackWhiteList() + self.statusBar().showMessage(_translate( + "MainWindow", "Entry added to the blacklist. Edit the label to your liking.")) + else: + self.statusBar().showMessage(_translate( + "MainWindow", "Error: You cannot add the same address to your blacklist 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() @@ -3751,6 +3777,8 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuInbox.addAction(self.actionReply) self.popMenuInbox.addAction(self.actionAddSenderToAddressBook) self.popMenuInbox.addSeparator() + self.popMenuInbox.addAction(self.actionAddSenderToBlackList) + self.popMenuInbox.addSeparator() self.popMenuInbox.addAction(self.actionSaveMessageAs) if currentFolder == "trash": self.popMenuInbox.addAction(self.actionUndeleteTrashedMessage) -- 2.45.1 From 664d485a660f004d35984369bf937de3aa1230c7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 14 Nov 2015 12:10:43 +0100 Subject: [PATCH 0141/1102] Don't commit DLLs --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8e9f9031..b0bf5ae4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ src/build src/dist src/.project src/.pydevproject -src/.settings/ \ No newline at end of file +src/.settings/ +*.dll \ No newline at end of file -- 2.45.1 From 1db7635893aab21a92cd80fdce627d02dc230bff Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 14 Nov 2015 13:11:33 +0100 Subject: [PATCH 0142/1102] OSX build fixes - include bitmsghash so that it bundles the C library PoW - include sslkeys so that SSL works in the bundle - PyBitmessage version now propagated from the shell build script --- osx.sh | 2 ++ src/build_osx.py | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osx.sh b/osx.sh index eaa33183..e58a49f4 100755 --- a/osx.sh +++ b/osx.sh @@ -14,6 +14,8 @@ 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/src/build_osx.py b/src/build_osx.py index ce70cd54..a5b004e6 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,7 +1,8 @@ +import os from setuptools import setup name = "Bitmessage" -version = "0.4.4" +version = os.getenv("PYBITMESSAGEVERSION", "custom") mainscript = ["bitmessagemain.py"] setup( @@ -11,7 +12,7 @@ setup( setup_requires = ["py2app"], options = dict( py2app = dict( - resources = ["images", "translations"], + resources = ["images", "translations", "bitmsghash", "sslkeys"], includes = ['sip', 'PyQt4._qt'], iconfile = "images/bitmessage.icns" ) -- 2.45.1 From 5cb02dc7838b36048599bcef7285f403b83cdeaa Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 14 Nov 2015 18:53:11 +0100 Subject: [PATCH 0143/1102] Improve blacklist autolabel --- src/bitmessageqt/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2299c524..06b56605 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3090,8 +3090,9 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) if queryreturn == []: + label = "\"" + str(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject()) + "\" in " + shared.config.get(self.getCurrentAccount(), "label") sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', - '--New entry. Change label in Blacklist.--', + label, addressAtCurrentInboxRow, True) self.rerenderBlackWhiteList() self.statusBar().showMessage(_translate( -- 2.45.1 From 049e226ddc296dc580071b716e3a309182f4e0a1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 14 Nov 2015 21:07:46 +0100 Subject: [PATCH 0144/1102] Move saving UI state quit is more appropriate than close event, but it my resurrect the issue with linux saving config data. --- src/bitmessageqt/__init__.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 06b56605..9ac08d46 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2862,6 +2862,14 @@ class MyForm(settingsmixin.SMainWindow): if reply is QtGui.QMessageBox.No: return ''' + # save state and geometry self and all widgets + 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() + shared.doCleanShutdown() self.tray.hide() # unregister the messaging system @@ -2891,13 +2899,6 @@ class MyForm(settingsmixin.SMainWindow): # minimize the application event.ignore() else: - # save state and geometry self and all widgets - 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() # quit the application event.accept() self.quit() -- 2.45.1 From 2fd85bfa69ad0a0a7e97f961323da2755ea14a57 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 15 Nov 2015 02:20:08 +0100 Subject: [PATCH 0145/1102] SSL workaround Python < 2.7.9 does not support anonymous SSL server through ssl.wrap_socket, so we have to disable it. Works fine as client. Try to prefer secp256k1 curve (again, requires python >= 2.7.9) --- src/class_receiveDataThread.py | 4 +++- src/shared.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 059bce87..582ac5b4 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -265,8 +265,10 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.sslSock = self.sock - if (self.services & shared.NODE_SSL == shared.NODE_SSL): + if (self.services & shared.NODE_SSL == shared.NODE_SSL and (self.initiatedConnection or sys.version_info >= (2, 7, 9))): self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') + if hasattr(self.sslSock, "context"): + self.sslSock.context.set_ecdh_curve("secp256k1") while True: try: self.sslSock.do_handshake() diff --git a/src/shared.py b/src/shared.py index 6f6d5a1c..4265062d 100644 --- a/src/shared.py +++ b/src/shared.py @@ -148,7 +148,8 @@ def encodeHost(host): def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): payload = '' payload += pack('>L', 3) # protocol version. - payload += pack('>q', NODE_NETWORK|NODE_SSL) # bitflags of the services I offer. + payload += pack('>q', NODE_NETWORK|(NODE_SSL if sys.version_info >= (2, 7, 9) else 0)) # bitflags of the services I offer. + # python < 2.7.9's ssl library does not support ECDSA server due to missing initialisation of available curves, but client works ok payload += pack('>q', int(time.time())) payload += pack( -- 2.45.1 From 46d647460f6e73b9aeecb1d7c93954d17e4b9caf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 15 Nov 2015 02:22:57 +0100 Subject: [PATCH 0146/1102] Version bump We have 0.5.3 now --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 4265062d..98f46413 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.2' +softwareVersion = '0.5.3' 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. -- 2.45.1 From cf610080b9744691a2927a9f869c25eec2bba546 Mon Sep 17 00:00:00 2001 From: "Denilson M. Amorim" Date: Sat, 14 Nov 2015 20:12:19 -0300 Subject: [PATCH 0147/1102] Squash: Single instance and pop up old instance --- src/bitmessagemain.py | 2 +- src/bitmessageqt/__init__.py | 85 +++++++++++++++++++++++++++++++++--- src/singleton.py | 16 ++++--- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index daae1af9..a636730d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -144,7 +144,7 @@ class Main: shared.daemon = daemon # is the application already running? If yes then exit. - thisapp = singleton.singleinstance() + thisapp = singleton.singleinstance("", daemon) import upnp upnp.createPortMapping() diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9ac08d46..382a5f0d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -56,10 +56,23 @@ import subprocess import datetime from helper_sql import * import l10n -import types -from utils import * -from collections import OrderedDict -from account import * + +try: + from PyQt4 import QtCore, QtGui + from PyQt4.QtCore import * + from PyQt4.QtGui import * + from PyQt4.QtNetwork import QLocalSocket, QLocalServer + +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) @@ -4483,8 +4496,70 @@ class UISignaler(QThread): sys.stderr.write( 'Command sent to UISignaler not recognized: %s\n' % command) + +app = None +myapp = None + +class MySingleApplication(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, singleton.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): + global myapp + if myapp: + myapp.appIndicatorShow() + +def init(): + global app + if not app: + app = MySingleApplication(sys.argv) + return app + def run(): - app = QtGui.QApplication(sys.argv) + global myapp + app = init() change_translation(l10n.getTranslationLanguage()) app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() diff --git a/src/singleton.py b/src/singleton.py index ee5c3077..f3124424 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -3,22 +3,26 @@ import sys import os import errno -import tempfile +import shared 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. + 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=""): + def __init__(self, flavor_id="", daemon=False): 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) + self.daemon = daemon; + self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) + + if not self.daemon: + # Tells the already running (if any) application to get focus. + import bitmessageqt + bitmessageqt.init() if sys.platform == 'win32': try: -- 2.45.1 From 28f46cb8b3d94a7e2977c2e9e2a97b8dbe524f2b Mon Sep 17 00:00:00 2001 From: "Denilson M. Amorim" Date: Sun, 15 Nov 2015 11:08:48 -0300 Subject: [PATCH 0148/1102] Dont run twice if daemon too --- src/bitmessagemain.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index a636730d..079ba5bd 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -44,8 +44,9 @@ from debug import logger # Helper Functions import helper_bootstrap import helper_generic -import upnp - + +# singleton lock instance +thisapp = None def connectToStream(streamNumber): shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' @@ -140,6 +141,8 @@ if shared.useVeryEasyProofOfWorkForTesting: class Main: def start(self, daemon=False): + global thisapp + _fixWinsock() shared.daemon = daemon -- 2.45.1 From 231219a1932dc7babe6300bc242864e5ebc5ce7f Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 18 Nov 2015 16:22:17 +0100 Subject: [PATCH 0149/1102] Improved logging Fixes #118 - changed almost all "print" into logger - threads have nicer names - logger can have configuration in "logger.dat" in the same directory as "keys.dat", and the logger will pick the one named "default" to replace the "console" and "file" that are in PyBitmessage otherwise Example file for logging to syslog: [loggers] keys = root,syslog [logger_root] level=NOTSET handlers=syslog [logger_syslog] level=DEBUG handlers=syslog qualname=default [handlers] keys = syslog [handler_syslog] class = handlers.SysLogHandler formatter = syslog level = DEBUG args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_LOCAL7) [formatters] keys = syslog [formatter_syslog] format=%(asctime)s %(threadName)s %(filename)s@%(lineno)d %(message)s datefmt=%b %d %H:%M:%S --- src/addresses.py | 12 +-- src/bitmessageqt/__init__.py | 45 +++++------ src/class_objectProcessor.py | 5 +- src/class_outgoingSynSender.py | 41 ++++------ src/class_receiveDataThread.py | 140 +++++++++++++-------------------- src/class_sendDataThread.py | 46 ++++------- src/class_singleCleaner.py | 6 +- src/class_singleListener.py | 14 ++-- src/class_singleWorker.py | 122 +++++++++++----------------- src/class_sqlThread.py | 2 +- src/debug.py | 40 ++++++++-- src/helper_bootstrap.py | 14 ++-- 12 files changed, 208 insertions(+), 279 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index f6fbbf73..017eaa82 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -55,7 +55,7 @@ def decodeBase58(string, alphabet=ALPHABET): def encodeVarint(integer): if integer < 0: - print 'varint cannot be < 0' + logger.error('varint cannot be < 0') raise SystemExit if integer < 253: return pack('>B',integer) @@ -66,7 +66,7 @@ def encodeVarint(integer): if integer >= 4294967296 and integer < 18446744073709551616: return pack('>B',255) + pack('>Q',integer) if integer >= 18446744073709551616: - print 'varint cannot be >= 18446744073709551616' + logger.error('varint cannot be >= 18446744073709551616') raise SystemExit class varintDecodeError(Exception): @@ -185,25 +185,25 @@ def decodeAddress(address): try: addressVersionNumber, bytesUsedByVersionNumber = decodeVarint(data[:9]) except varintDecodeError as e: - print e + logger.error(str(e)) status = 'varintmalformed' return status,0,0,"" #print 'addressVersionNumber', addressVersionNumber #print 'bytesUsedByVersionNumber', bytesUsedByVersionNumber if addressVersionNumber > 4: - print 'cannot decode address version numbers this high' + logger.error('cannot decode address version numbers this high') status = 'versiontoohigh' return status,0,0,"" elif addressVersionNumber == 0: - print 'cannot decode address version numbers of zero.' + logger.error('cannot decode address version numbers of zero.') status = 'versiontoohigh' return status,0,0,"" try: streamNumber, bytesUsedByStreamNumber = decodeVarint(data[bytesUsedByVersionNumber:]) except varintDecodeError as e: - print e + logger.error(str(e)) status = 'varintmalformed' return status,0,0,"" #print streamNumber diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 382a5f0d..87eb1083 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -12,14 +12,14 @@ try: 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 + logger.error( '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.error('Error message: ' + str(err)) sys.exit() try: _encoding = QtGui.QApplication.UnicodeUTF8 except AttributeError: - print 'QtGui.QApplication.UnicodeUTF8 error:', err + logger.error('QtGui.QApplication.UnicodeUTF8 error: ' + str(err)) from addresses import * import shared @@ -503,7 +503,6 @@ class MyForm(settingsmixin.SMainWindow): if len(db[toAddress]) > 0: j = 0 for f, c in db[toAddress].iteritems(): - print "adding %s, %i" % (f, c) subwidget = Ui_FolderWidget(widget, j, toAddress, f, c) j += 1 widget.setUnreadCount(unread) @@ -742,7 +741,7 @@ class MyForm(settingsmixin.SMainWindow): if nc.test()[0] == 'failed': self.ui.pushButtonFetchNamecoinID.hide() except: - print 'There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button' + logger.error('There was a problem testing for a Namecoin daemon. Hiding the Fetch Namecoin ID button') self.ui.pushButtonFetchNamecoinID.hide() def updateTTL(self, sliderPosition): @@ -1282,7 +1281,7 @@ class MyForm(settingsmixin.SMainWindow): # has messageing menu been installed if not withMessagingMenu: - print 'WARNING: MessagingMenu is not available. Is libmessaging-menu-dev installed?' + logger.warning('WARNING: MessagingMenu is not available. Is libmessaging-menu-dev installed?') return # create the menu server @@ -1295,7 +1294,7 @@ class MyForm(settingsmixin.SMainWindow): self.ubuntuMessagingMenuUnread(True) except Exception: withMessagingMenu = False - print 'WARNING: messaging menu disabled' + logger.warning('WARNING: messaging menu disabled') # update the Ubuntu messaging menu def ubuntuMessagingMenuUpdate(self, drawAttention, newItem, toLabel): @@ -1307,7 +1306,7 @@ class MyForm(settingsmixin.SMainWindow): # has messageing menu been installed if not withMessagingMenu: - print 'WARNING: messaging menu disabled or libmessaging-menu-dev not installed' + logger.warning('WARNING: messaging menu disabled or libmessaging-menu-dev not installed') return # remember this item to that the messaging menu can find it @@ -1401,7 +1400,7 @@ class MyForm(settingsmixin.SMainWindow): stdout=subprocess.PIPE) gst_available=True except: - print "WARNING: gst123 must be installed in order to play mp3 sounds" + logger.warning("WARNING: gst123 must be installed in order to play mp3 sounds") if not gst_available: try: subprocess.call(["mpg123", soundFilename], @@ -1409,14 +1408,14 @@ class MyForm(settingsmixin.SMainWindow): stdout=subprocess.PIPE) gst_available=True except: - print "WARNING: mpg123 must be installed in order to play mp3 sounds" + logger.warning("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" + logger.warning("WARNING: aplay must be installed in order to play WAV sounds") elif sys.platform[0:3] == 'win': # use winsound on Windows import winsound @@ -1533,7 +1532,7 @@ class MyForm(settingsmixin.SMainWindow): 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 + logger.debug('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.")) @@ -1558,7 +1557,7 @@ class MyForm(settingsmixin.SMainWindow): 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 + logger.debug('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.")) @@ -2125,13 +2124,12 @@ class MyForm(settingsmixin.SMainWindow): acct.createMessage(toAddress, fromAddress, subject, message) subject = acct.subject toAddress = acct.toAddress - print "Subject: %s" % (subject) - print "address: %s" % (toAddress) + logger.debug("Subject: %s" % (subject)) + logger.debug("address: %s" % (toAddress)) status, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if status != 'success': - with shared.printLock: - print 'Error: Could not decode', toAddress, ':', status + logger.error('Error: Could not decode ' + toAddress + ':' + status) if status == 'missingbm': self.statusBar().showMessage(_translate( @@ -2499,7 +2497,7 @@ class MyForm(settingsmixin.SMainWindow): shared.objectProcessorQueue.put((objectType,payload)) def click_pushButtonStatusIcon(self): - print 'click_pushButtonStatusIcon' + logger.debug('click_pushButtonStatusIcon') self.iconGlossaryInstance = iconGlossaryDialog(self) if self.iconGlossaryInstance.exec_(): pass @@ -2810,12 +2808,10 @@ class MyForm(settingsmixin.SMainWindow): if acct.type != 'normal': return if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): - print "unregister" acct.unregister() shared.config.remove_option(addressAtCurrentRow, 'gateway') shared.writeKeysFile() elif self.dialog.ui.radioButtonRegister.isChecked(): - print "register" email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) acct.register(email) @@ -2864,7 +2860,7 @@ class MyForm(settingsmixin.SMainWindow): 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' + logger.debug('new address dialog box rejected') # Quit selected from menu or application indicator def quit(self): @@ -3052,7 +3048,7 @@ class MyForm(settingsmixin.SMainWindow): # 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 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.' + logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) listOfAddressesInComboBoxSendFrom = [str(widget['from'].itemData(i).toPyObject()) for i in range(widget['from'].count())] @@ -3727,7 +3723,7 @@ class MyForm(settingsmixin.SMainWindow): if sourcefile != '': copied = QtCore.QFile.copy(sourcefile, destination) if not copied: - print 'couldn\'t copy :(' + logger.error('couldn\'t copy :(') # set the icon self.rerenderTabTreeMessages() self.rerenderTabTreeSubscriptions() @@ -3965,8 +3961,7 @@ class MyForm(settingsmixin.SMainWindow): def updateStatusBar(self, data): if data != "": - with shared.printLock: - print 'Status bar:', data + logger.info('Status bar: ' + data) self.statusBar().showMessage(data) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index f9972fe6..f7b0e893 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -29,7 +29,7 @@ class objectProcessor(threading.Thread): objecs (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. """ def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="objectProcessor") """ It may be the case that the last time Bitmessage was running, the user closed it before it finished processing everything in the @@ -741,8 +741,7 @@ class objectProcessor(threading.Thread): fromAddress = encodeAddress( sendersAddressVersion, sendersStream, calculatedRipe) - with shared.printLock: - print 'fromAddress:', fromAddress + logger.debug('fromAddress: ' + fromAddress) if messageEncodingType == 2: subject, body = self.decodeType2Message(message) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 453acfe1..732f6c9f 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -16,7 +16,7 @@ from class_receiveDataThread import * class outgoingSynSender(threading.Thread): def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="outgoingSynSender") def setup(self, streamNumber, selfInitiatedConnections): self.streamNumber = streamNumber @@ -40,6 +40,7 @@ class outgoingSynSender(threading.Thread): while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): time.sleep(2) while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): + self.name = "outgoingSynSender" maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: time.sleep(10) @@ -64,6 +65,7 @@ class outgoingSynSender(threading.Thread): shared.alreadyAttemptedConnectionsListLock.acquire() shared.alreadyAttemptedConnectionsList[peer] = 0 shared.alreadyAttemptedConnectionsListLock.release() + self.name = "outgoingSynSender-" + peer.host if peer.host.find(':') == -1: address_family = socket.AF_INET else: @@ -86,22 +88,19 @@ class outgoingSynSender(threading.Thread): 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.' + logger.debug('deleting ' + str(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 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 + logger.debug('Trying an outgoing connection to ' + str(peer)) # sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS4a': if shared.verbose >= 2: - with shared.printLock: - print '(Using SOCKS4a) Trying an outgoing connection to', peer + logger.debug ('(Using SOCKS4a) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS4 sockshostname = shared.config.get( @@ -121,8 +120,7 @@ class outgoingSynSender(threading.Thread): proxytype, sockshostname, socksport, rdns) elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': if shared.verbose >= 2: - with shared.printLock: - print '(Using SOCKS5) Trying an outgoing connection to', peer + logger.debug ('(Using SOCKS5) Trying an outgoing connection to ' + str(peer)) proxytype = socks.PROXY_TYPE_SOCKS5 sockshostname = shared.config.get( @@ -155,8 +153,7 @@ class outgoingSynSender(threading.Thread): self.selfInitiatedConnections, sendDataThreadQueue) rd.start() - with shared.printLock: - print self, 'connected to', peer, 'during an outgoing attempt.' + logger.debug(str(self) + ' connected to ' + str(peer) + ' during an outgoing attempt.') sd = sendDataThread(sendDataThreadQueue) @@ -167,8 +164,7 @@ class outgoingSynSender(threading.Thread): except socks.GeneralProxyError as err: if shared.verbose >= 2: - with shared.printLock: - print 'Could NOT connect to', peer, 'during outgoing attempt.', err + logger.debug('Could NOT connect to ' + str(peer) + ' during outgoing attempt. ' + str(err)) deletedPeer = None with shared.knownNodesLock: @@ -186,8 +182,7 @@ class outgoingSynSender(threading.Thread): del shared.knownNodes[self.streamNumber][peer] deletedPeer = peer if deletedPeer: - with shared.printLock: - print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.' + str ('deleting ' + str(peer) + ' from shared.knownNodes because it is more than 48 hours old and we could not connect to it.') except socks.Socks5AuthError as err: shared.UISignalQueue.put(( @@ -195,16 +190,15 @@ class outgoingSynSender(threading.Thread): "MainWindow", "SOCKS5 Authentication problem: %1").arg(str(err)))) except socks.Socks5Error as err: pass - print 'SOCKS5 error. (It is possible that the server wants authentication).)', str(err) + logger.error('SOCKS5 error. (It is possible that the server wants authentication).) ' + str(err)) except socks.Socks4Error as err: - print 'Socks4Error:', err + logger.error('Socks4Error: ' + str(err)) except socket.error as err: if shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS': - print 'Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err) + logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) else: if shared.verbose >= 1: - with shared.printLock: - print 'Could NOT connect to', peer, 'during outgoing attempt.', err + logger.error('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) deletedPeer = None with shared.knownNodesLock: @@ -222,12 +216,9 @@ class outgoingSynSender(threading.Thread): del shared.knownNodes[self.streamNumber][peer] deletedPeer = peer if deletedPeer: - with shared.printLock: - print 'deleting', peer, 'from shared.knownNodes because it is more than 48 hours old and we could not connect to it.' + logger.debug('deleting ' + str(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 - traceback.print_exc() + logger.exception('An exception has occurred in the outgoingSynSender thread that was not caught by other exception types:') time.sleep(0.1) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 582ac5b4..fa165401 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -29,7 +29,7 @@ from debug import logger class receiveDataThread(threading.Thread): def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="receiveData") self.data = '' self.verackSent = False self.verackReceived = False @@ -46,6 +46,7 @@ class receiveDataThread(threading.Thread): self.sock = sock self.peer = shared.Peer(HOST, port) + self.name = "receiveData-" + self.peer.host self.streamNumber = streamNumber self.objectsThatWeHaveYetToGetFromThisPeer = {} self.selfInitiatedConnections = selfInitiatedConnections @@ -62,8 +63,7 @@ class receiveDataThread(threading.Thread): self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware def run(self): - with shared.printLock: - print 'receiveDataThread starting. ID', str(id(self)) + '. The size of the shared.connectedHostsList is now', len(shared.connectedHostsList) + logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) while True: if shared.config.getint('bitmessagesettings', 'maxdownloadrate') == 0: @@ -89,36 +89,31 @@ class receiveDataThread(threading.Thread): 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: - with shared.printLock: - print 'Timeout occurred waiting for data from', self.peer, '. Closing receiveData thread. (ID:', str(id(self)) + ')' + logger.error ('Timeout occurred waiting for data from ' + str(self.peer) + '. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break except Exception as err: if (sys.platform == 'win32' and err.errno in ([2, 10035])) or (sys.platform != 'win32' and err.errno == errno.EWOULDBLOCK): select.select([self.sslSock], [], []) continue - with shared.printLock: - print 'sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID:', str(id(self)) + ').', str(err.errno), "/", err + logger.error('sock.recv error. Closing receiveData thread (' + str(self.peer) + ', Thread ID: ' + str(id(self)) + ').' + str(err.errno) + "/" + str(err)) break # print 'Received', repr(self.data) if len(self.data) == dataLen: # If self.sock.recv returned no data: - with shared.printLock: - print 'Connection to', self.peer, 'closed. Closing receiveData thread. (ID:', str(id(self)) + ')' + logger.debug('Connection to ' + str(self.peer) + ' closed. Closing receiveData thread. (ID: ' + str(id(self)) + ')') break else: self.processData() try: del self.selfInitiatedConnections[self.streamNumber][self] - with shared.printLock: - print 'removed self (a receiveDataThread) from selfInitiatedConnections' + logger.debug('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.peer.host] except Exception as err: - with shared.printLock: - print 'Could not delete', self.peer.host, 'from shared.connectedHostsList.', err + logger.error('Could not delete ' + str(self.peer.host) + ' from shared.connectedHostsList.' + str(err)) try: del shared.numberOfObjectsThatWeHaveYetToGetPerPeer[ @@ -126,8 +121,7 @@ class receiveDataThread(threading.Thread): 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) + logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) def processData(self): @@ -148,7 +142,7 @@ class receiveDataThread(threading.Thread): return payload = self.data[shared.Header.size:payloadLength + shared.Header.size] if checksum != hashlib.sha512(payload).digest()[0:4]: # test the checksum in the message. - print 'Checksum incorrect. Clearing this message.' + logger.error('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() @@ -163,8 +157,7 @@ class receiveDataThread(threading.Thread): #Strip the nulls command = command.rstrip('\x00') - with shared.printLock: - print 'remoteCommand', repr(command), ' from', self.peer + logger.debug('remoteCommand ' + repr(command) + ' from ' + str(self.peer)) try: #TODO: Use a dispatcher here @@ -202,14 +195,12 @@ class receiveDataThread(threading.Thread): 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.' + logger.debug('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.' + logger.debug('Inventory (SQL on disk) already has object listed in inv message.') del self.objectsThatWeHaveYetToGetFromThisPeer[ objectHash] else: @@ -218,8 +209,7 @@ class receiveDataThread(threading.Thread): 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' + logger.debug('(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. @@ -228,16 +218,14 @@ class receiveDataThread(threading.Thread): 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' + logger.debug('(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) + logger.debug('(concerning' + str(self.peer) + ') number of objectsThatWeHaveYetToGetFromThisPeer is now ' + str(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. @@ -245,14 +233,12 @@ class receiveDataThread(threading.Thread): def sendpong(self): - with shared.printLock: - print 'Sending pong' + logger.debug('Sending pong') self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('pong'))) def recverack(self): - with shared.printLock: - print 'verack received' + logger.debug('verack received') self.verackReceived = True if self.verackSent: # We have thus both sent and received a verack. @@ -289,11 +275,10 @@ class receiveDataThread(threading.Thread): self.sock.settimeout( 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.' + 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(shared.sendDataQueues)) + "\n" + \ + 'broadcasting addr from within connectionFullyEstablished function.') # Let all of our peers know about this new node. dataToSend = (int(time.time()), self.streamNumber, 1, self.peer.host, self.remoteNodeIncomingPort) @@ -302,8 +287,7 @@ class receiveDataThread(threading.Thread): self.sendaddr() # This is one large addr message to this one peer. if not self.initiatedConnection and len(shared.connectedHostsList) > 200: - with shared.printLock: - print 'We are connected to too many people. Closing connection.' + logger.info ('We are connected to too many people. Closing connection.') self.sendDataThreadQueue.put((0, 'shutdown','no data')) return @@ -349,8 +333,7 @@ class receiveDataThread(threading.Thread): # function for broadcasting invs to everyone in our stream. def sendinvMessageToJustThisOnePeer(self, numberOfObjects, payload): payload = encodeVarint(numberOfObjects) + payload - with shared.printLock: - print 'Sending huge inv message with', numberOfObjects, 'objects to just this one peer' + logger.debug('Sending huge inv message with ' + str(numberOfObjects) + ' objects to just this one peer') self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('inv', payload))) def _sleepForTimingAttackMitigation(self, sleepTime): @@ -358,8 +341,7 @@ class receiveDataThread(threading.Thread): # only connected to the trusted peer because we can trust the # peer not to attack if sleepTime > 0 and doTimingAttackMitigation and shared.trustedPeer == None: - with shared.printLock: - print 'Timing attack mitigation: Sleeping for', sleepTime, 'seconds.' + logger.debug('Timing attack mitigation: Sleeping for ' + str(sleepTime) + ' seconds.') time.sleep(sleepTime) def recerror(self, data): @@ -417,30 +399,27 @@ class receiveDataThread(threading.Thread): 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 + logger.debug('number of keys(hosts) in shared.numberOfObjectsThatWeHaveYetToGetPerPeer: ' + str(len(shared.numberOfObjectsThatWeHaveYetToGetPerPeer)) + "\n" + \ + 'totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers = ' + str(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): - print 'inv message doesn\'t contain enough data. Ignoring.' + logger.info('inv message doesn\'t contain enough data. Ignoring.') return 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.' + logger.debug('We already have ' + str(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.' + logger.debug('Inventory (in memory) has inventory item already.') elif shared.isInSqlInventory(data[lengthOfVarint:32 + lengthOfVarint]): - print 'Inventory (SQL on disk) has inventory item already.' + logger.debug('Inventory (SQL on disk) has inventory item already.') else: self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) else: @@ -455,8 +434,7 @@ class receiveDataThread(threading.Thread): 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.' + logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over ' + str(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. @@ -467,8 +445,7 @@ class receiveDataThread(threading.Thread): # Send a getdata message to our peer to request the object with the given # hash def sendgetdata(self, hash): - with shared.printLock: - print 'sending getdata to retrieve object with hash:', hash.encode('hex') + logger.debug('sending getdata to retrieve object with hash: ' + hash.encode('hex')) payload = '\x01' + hash self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) @@ -478,13 +455,12 @@ class receiveDataThread(threading.Thread): numberOfRequestedInventoryItems, lengthOfVarint = decodeVarint( data[:10]) if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): - print 'getdata message does not contain enough data. Ignoring.' + logger.debug('getdata message does not contain enough data. Ignoring.') return for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + ( i * 32):32 + lengthOfVarint + (i * 32)] - with shared.printLock: - print 'received getdata request for item:', hash.encode('hex') + logger.debug('received getdata request for item:' + hash.encode('hex')) shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() @@ -507,36 +483,35 @@ class receiveDataThread(threading.Thread): # Our peer has requested (in a getdata message) that we send an object. def sendObject(self, payload): - with shared.printLock: - print 'sending an object.' + logger.debug('sending an object.') self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('object',payload))) def _checkIPv4Address(self, host, hostStandardFormat): # print 'hostStandardFormat', hostStandardFormat if host[0] == '\x7F': # 127/8 - print 'Ignoring IP address in loopback range:', hostStandardFormat + logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) return False if host[0] == '\x0A': # 10/8 - print 'Ignoring IP address in private range:', hostStandardFormat + logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) return False if host[0:2] == '\xC0\xA8': # 192.168/16 - print 'Ignoring IP address in private range:', hostStandardFormat + logger.debug('Ignoring IP address in private range: ' + hostStandardFormat) return False if host[0:2] >= '\xAC\x10' and host[0:2] < '\xAC\x20': # 172.16/12 - print 'Ignoring IP address in private range:', hostStandardFormat + logger.debug('Ignoring IP address in private range:' + hostStandardFormat) return False return True def _checkIPv6Address(self, host, hostStandardFormat): if host == ('\x00' * 15) + '\x01': - print 'Ignoring loopback address:', hostStandardFormat + logger.debug('Ignoring loopback address: ' + hostStandardFormat) return False if host[0] == '\xFE' and (ord(host[1]) & 0xc0) == 0x80: - print 'Ignoring local address:', hostStandardFormat + logger.debug ('Ignoring local address: ' + hostStandardFormat) return False if (ord(host[0]) & 0xfe) == 0xfc: - print 'Ignoring unique local address:', hostStandardFormat + logger.debug ('Ignoring unique local address: ' + hostStandardFormat) return False return True @@ -546,13 +521,12 @@ class receiveDataThread(threading.Thread): data[:10]) if shared.verbose >= 1: - with shared.printLock: - print 'addr message contains', numberOfAddressesIncluded, 'IP addresses.' + logger.debug('addr message contains ' + str(numberOfAddressesIncluded) + ' IP addresses.') if numberOfAddressesIncluded > 1000 or numberOfAddressesIncluded == 0: return if len(data) != lengthOfNumberOfAddresses + (38 * numberOfAddressesIncluded): - print 'addr message does not contain the correct amount of data. Ignoring.' + logger.debug('addr message does not contain the correct amount of data. Ignoring.') return for i in range(0, numberOfAddressesIncluded): @@ -590,8 +564,7 @@ class receiveDataThread(threading.Thread): 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 + logger.debug('added new node ' + str(peerFromAddrMessage) + ' to knownNodes in stream ' + str(recaddrStream)) shared.needToWriteKnownNodesToDisk = True hostDetails = ( @@ -606,8 +579,7 @@ class receiveDataThread(threading.Thread): with shared.knownNodesLock: shared.knownNodes[recaddrStream][peerFromAddrMessage] = timeSomeoneElseReceivedMessageFromThisNode - with shared.printLock: - print 'knownNodes currently has', len(shared.knownNodes[self.streamNumber]), 'nodes for this stream.' + logger.debug('knownNodes currently has ' + str(len(shared.knownNodes[self.streamNumber])) + ' nodes for this stream.') # Send a huge addr message to our peer. This is only used @@ -706,8 +678,7 @@ class receiveDataThread(threading.Thread): 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 + logger.debug ('Closing connection to old protocol version ' + str(self.remoteProtocolVersion) + ' node: ' + str(self.peer)) return timestamp, = unpack('>Q', data[12:20]) timeOffset = timestamp - int(time.time()) @@ -748,13 +719,11 @@ class receiveDataThread(threading.Thread): readPosition += lengthOfNumberOfStreamsInVersionMessage self.streamNumber, lengthOfRemoteStreamNumber = decodeVarint( data[readPosition:]) - with shared.printLock: - print 'Remote node useragent:', useragent, ' stream number:', self.streamNumber, ' time offset:', timeOffset, 'seconds.' + logger.debug('Remote node useragent: ' + useragent + ' stream number:' + str(self.streamNumber) + ' time offset: ' + str(timeOffset) + ' seconds.') if self.streamNumber != 1: self.sendDataThreadQueue.put((0, 'shutdown','no data')) - with shared.printLock: - print 'Closed connection to', self.peer, 'because they are interested in stream', self.streamNumber, '.' + logger.debug ('Closed connection to ' + str(self.peer) + ' because they are interested in stream ' + str(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. @@ -764,8 +733,7 @@ class receiveDataThread(threading.Thread): 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 + logger.debug('Closing connection to myself: ' + str(self.peer)) return # The other peer's protocol version is of interest to the sendDataThread but we learn of it @@ -782,16 +750,14 @@ class receiveDataThread(threading.Thread): # Sends a version message def sendversion(self): - with shared.printLock: - print 'Sending version message' + logger.debug('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): - with shared.printLock: - print 'Sending verack' + logger.debug('Sending verack') self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('verack'))) self.verackSent = True if self.verackReceived: diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 4ee88399..1a839d50 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -11,13 +11,14 @@ import socket from helper_generic import addDataPadding from class_objectHashHolder import * from addresses import * +from debug import logger # Every connection to a peer has a sendDataThread (and also a # receiveDataThread). class sendDataThread(threading.Thread): def __init__(self, sendDataThreadQueue): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="sendData") self.sendDataThreadQueue = sendDataThreadQueue shared.sendDataQueues.append(self.sendDataThreadQueue) self.data = '' @@ -35,6 +36,7 @@ class sendDataThread(threading.Thread): someObjectsOfWhichThisRemoteNodeIsAlreadyAware): self.sock = sock self.peer = shared.Peer(HOST, PORT) + self.name = "sendData-" + self.peer.host self.streamNumber = streamNumber self.services = 0 self.remoteProtocolVersion = - \ @@ -42,23 +44,20 @@ class sendDataThread(threading.Thread): self.lastTimeISentData = int( time.time()) # If this value increases beyond five minutes ago, we'll send a pong message to keep the connection alive. self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware - with shared.printLock: - print 'The streamNumber of this sendDataThread (ID:', str(id(self)) + ') at setup() is', self.streamNumber + logger.debug('The streamNumber of this sendDataThread (ID: ' + str(id(self)) + ') at setup() is' + str(self.streamNumber)) def sendVersionMessage(self): datatosend = shared.assembleVersionMessage( self.peer.host, self.peer.port, self.streamNumber) # the IP and port of the remote host, and my streamNumber. - with shared.printLock: - print 'Sending version packet: ', repr(datatosend) + logger.debug('Sending version packet: ' + repr(datatosend)) try: self.sendBytes(datatosend) except Exception as err: # if not 'Bad file descriptor' in err: - with shared.printLock: - sys.stderr.write('sock.sendall error: %s\n' % err) + logger.error('sock.sendall error: %s\n' % err) self.versionSent = 1 @@ -94,15 +93,13 @@ class sendDataThread(threading.Thread): def run(self): - with shared.printLock: - print 'sendDataThread starting. ID:', str(id(self))+'. Number of queues in sendDataQueues:', len(shared.sendDataQueues) + logger.debug('sendDataThread starting. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) while True: deststream, command, data = self.sendDataThreadQueue.get() if deststream == self.streamNumber or deststream == 0: if command == 'shutdown': - with shared.printLock: - print 'sendDataThread (associated with', self.peer, ') ID:', id(self), 'shutting down now.' + logger.debug('sendDataThread (associated with ' + str(self.peer) + ') ID: ' + str(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 @@ -112,12 +109,10 @@ class sendDataThread(threading.Thread): # streamNumber of this send data thread here: elif command == 'setStreamNumber': self.streamNumber = data - with shared.printLock: - print 'setting the stream number in the sendData thread (ID:', id(self), ') to', self.streamNumber + logger.debug('setting the stream number in the sendData thread (ID: ' + str(id(self)) + ') to ' + str(self.streamNumber)) elif command == 'setRemoteProtocolVersion': specifiedRemoteProtocolVersion = data - with shared.printLock: - print 'setting the remote node\'s protocol version in the sendDataThread (ID:', id(self), ') to', specifiedRemoteProtocolVersion + logger.debug('setting the remote node\'s protocol version in the sendDataThread (ID: ' + str(id(self)) + ') to ' + str(specifiedRemoteProtocolVersion)) self.remoteProtocolVersion = specifiedRemoteProtocolVersion elif command == 'advertisepeer': self.objectHashHolderInstance.holdPeer(data) @@ -140,8 +135,7 @@ class sendDataThread(threading.Thread): try: self.sendBytes(packet) except: - with shared.printLock: - print 'sendaddr: self.sock.sendall failed' + logger.error('sendaddr: self.sock.sendall failed') break elif command == 'advertiseobject': self.objectHashHolderInstance.holdHash(data) @@ -157,35 +151,30 @@ class sendDataThread(threading.Thread): try: self.sendBytes(packet) except: - with shared.printLock: - print 'sendinv: self.sock.sendall failed' + logger.error('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. - with shared.printLock: - print 'Sending pong to', self.peer, 'to keep connection alive.' + logger.debug('Sending pong to ' + str(self.peer) + ' to keep connection alive.') packet = shared.CreatePacket('pong') try: self.sendBytes(packet) except: - with shared.printLock: - print 'send pong failed' + logger.error('send pong failed') break elif command == 'sendRawData': try: self.sendBytes(data) except: - with shared.printLock: - print 'Sending of data to', self.peer, 'failed. sendDataThread thread', self, 'ending now.' + logger.error('Sending of data to ' + str(self.peer) + ' failed. sendDataThread thread ' + str(self) + ' ending now.') break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True self.services, self.sslSock = data else: - with shared.printLock: - print 'sendDataThread ID:', id(self), 'ignoring command', command, 'because the thread is not in stream', deststream + logger.error('sendDataThread ID: ' + id(self) + ' ignoring command ' + command + ' because the thread is not in stream' + deststream) try: self.sock.shutdown(socket.SHUT_RDWR) @@ -193,6 +182,5 @@ class sendDataThread(threading.Thread): except: pass shared.sendDataQueues.remove(self.sendDataThreadQueue) - with shared.printLock: - print 'sendDataThread ending. ID:', str(id(self))+'. Number of queues in sendDataQueues:', len(shared.sendDataQueues) + logger.info('sendDataThread ending. ID: ' + str(id(self)) + '. Number of queues in sendDataQueues: ' + str(len(shared.sendDataQueues))) self.objectHashHolderInstance.close() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index b441d11c..bccf4a62 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -31,7 +31,7 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) class singleCleaner(threading.Thread): def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="singleCleaner") def run(self): timeWeLastClearedInventoryAndPubkeysTables = 0 @@ -83,9 +83,7 @@ class singleCleaner(threading.Thread): int(time.time()) - shared.maximumLengthOfTimeToBotherResendingMessages) for row in queryreturn: if len(row) < 2: - with shared.printLock: - sys.stderr.write( - 'Something went wrong in the singleCleaner thread: a query did not return the requested fields. ' + repr(row)) + logger.error('Something went wrong in the singleCleaner thread: a query did not return the requested fields. ' + repr(row)) time.sleep(3) break toAddress, ackData, status = row diff --git a/src/class_singleListener.py b/src/class_singleListener.py index a33158a3..77e6eee6 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -18,7 +18,7 @@ import re class singleListener(threading.Thread): def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="singleListener") def setup(self, selfInitiatedConnections): self.selfInitiatedConnections = selfInitiatedConnections @@ -54,8 +54,7 @@ class singleListener(threading.Thread): while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten'): time.sleep(5) - with shared.printLock: - print 'Listening for incoming connections.' + logger.info('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 @@ -82,8 +81,7 @@ class singleListener(threading.Thread): 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.' + logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') time.sleep(10) @@ -104,8 +102,7 @@ class singleListener(threading.Thread): # connection flooding. if HOST in shared.connectedHostsList: socketObject.close() - with shared.printLock: - print 'We are already connected to', HOST + '. Ignoring connection.' + logger.info('We are already connected to ' + str(HOST) + '. Ignoring connection.') else: break @@ -124,6 +121,5 @@ class singleListener(threading.Thread): socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue) rd.start() - with shared.printLock: - print self, 'connected to', HOST, 'during INCOMING request.' + logger.info('connected to ' + HOST + ' during INCOMING request.') diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 888d96f6..de8848b2 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -25,7 +25,7 @@ class singleWorker(threading.Thread): def __init__(self): # QThread.__init__(self, parent) - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="singleWorker") def run(self): @@ -49,7 +49,7 @@ class singleWorker(threading.Thread): '''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') for row in queryreturn: ackdata, = row - print 'Watching for ackdata', ackdata.encode('hex') + logger.info('Watching for ackdata ' + ackdata.encode('hex')) shared.ackdataForWhichImWatching[ackdata] = 0 time.sleep( @@ -81,9 +81,7 @@ class singleWorker(threading.Thread): elif command == 'sendOutOrStoreMyV4Pubkey': self.sendOutOrStoreMyV4Pubkey(data) else: - with shared.printLock: - sys.stderr.write( - 'Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) + logger.error('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) shared.workerQueue.task_done() @@ -114,9 +112,7 @@ class singleWorker(threading.Thread): privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as 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) + logger.error('Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return privSigningKeyHex = shared.decodeWalletImportFormat( @@ -133,10 +129,10 @@ class singleWorker(threading.Thread): # Do the POW for this pubkey message 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...' + logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce + logger.info('(For pubkey message) Found proof of work ' + str(trialValue), ' Nonce: ', str(nonce)) payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) @@ -145,8 +141,7 @@ class singleWorker(threading.Thread): objectType, streamNumber, payload, embeddedTime,'') shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'broadcasting inv with hash:', inventoryHash.encode('hex') + logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -171,8 +166,7 @@ class singleWorker(threading.Thread): #The address has been deleted. return if shared.safeConfigGetBoolean(myAddress, 'chan'): - with shared.printLock: - print 'This is a chan address. Not sending pubkey.' + logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) @@ -199,9 +193,7 @@ class singleWorker(threading.Thread): privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as 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) + logger.error('Error within sendOutOrStoreMyV3Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return @@ -228,12 +220,10 @@ class singleWorker(threading.Thread): # Do the POW for this pubkey message 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...' + logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - with shared.printLock: - print '(For pubkey message) Found proof of work. Nonce:', nonce + logger.info('(For pubkey message) Found proof of work. Nonce: ' + str(nonce)) payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) @@ -242,8 +232,7 @@ class singleWorker(threading.Thread): objectType, streamNumber, payload, embeddedTime,'') shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'broadcasting inv with hash:', inventoryHash.encode('hex') + logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -264,8 +253,7 @@ class singleWorker(threading.Thread): #The address has been deleted. return if shared.safeConfigGetBoolean(myAddress, 'chan'): - with shared.printLock: - print 'This is a chan address. Not sending pubkey.' + logger.info('This is a chan address. Not sending pubkey.') return status, addressVersionNumber, streamNumber, hash = decodeAddress( myAddress) @@ -285,9 +273,7 @@ class singleWorker(threading.Thread): privEncryptionKeyBase58 = shared.config.get( myAddress, 'privencryptionkey') except Exception as 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) + logger.error('Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return privSigningKeyHex = shared.decodeWalletImportFormat( @@ -326,10 +312,10 @@ class singleWorker(threading.Thread): # Do the POW for this pubkey message 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...' + logger.info('(For pubkey message) Doing proof of work...') initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - print '(For pubkey message) Found proof of work', trialValue, 'Nonce:', nonce + logger.info('(For pubkey message) Found proof of work ' + str(trialValue) + 'Nonce: ' + str(nonce)) payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) @@ -338,8 +324,7 @@ class singleWorker(threading.Thread): objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'broadcasting inv with hash:', inventoryHash.encode('hex') + logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -359,9 +344,7 @@ class singleWorker(threading.Thread): status, addressVersionNumber, streamNumber, ripe = decodeAddress( fromaddress) if addressVersionNumber <= 1: - with shared.printLock: - sys.stderr.write( - 'Error: In the singleWorker thread, the sendBroadcast function doesn\'t understand the address version.\n') + logger.error('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. @@ -442,12 +425,12 @@ class singleWorker(threading.Thread): dataToEncrypt, pubEncryptionKey.encode('hex')) 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...' + logger.info('(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) - print '(For broadcast message) Found proof of work', trialValue, 'Nonce:', nonce + logger.info('(For broadcast message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) payload = pack('>Q', nonce) + payload @@ -463,8 +446,7 @@ class singleWorker(threading.Thread): shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) shared.inventorySets[streamNumber].add(inventoryHash) - with shared.printLock: - print 'sending inv (within sendBroadcast function) for object:', inventoryHash.encode('hex') + logger.info('sending inv (within sendBroadcast function) for object: ' + inventoryHash.encode('hex')) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -612,8 +594,8 @@ class singleWorker(threading.Thread): shared.ackdataForWhichImWatching[ackdata] = 0 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]) + logger.info('Sending a message.') + logger.debug('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 @@ -685,8 +667,8 @@ class singleWorker(threading.Thread): requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes)).arg(l10n.formatTimestamp())))) continue else: # if we are sending a message to ourselves or a chan.. - with shared.printLock: - print 'Sending a message. First 150 characters of message:', repr(message[:150]) + logger.info('Sending a message.') + logger.debug('First 150 characters of message: ' + repr(message[:150])) behaviorBitfield = '\x00\x00\x00\x01' try: @@ -694,9 +676,7 @@ class singleWorker(threading.Thread): toaddress, 'privencryptionkey') except Exception as 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) + logger.error('Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) continue privEncryptionKeyHex = shared.decodeWalletImportFormat( privEncryptionKeyBase58).encode('hex') @@ -761,12 +741,10 @@ class singleWorker(threading.Thread): 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.' + logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') fullAckPayload = '' 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.' + logger.info('Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.') fullAckPayload = '' else: fullAckPayload = self.generateFullAckMessage( @@ -791,18 +769,16 @@ class singleWorker(threading.Thread): encryptedPayload += encodeVarint(1) # msg version encryptedPayload += encodeVarint(toStreamNumber) + encrypted target = 2 ** 64 / (requiredAverageProofOfWorkNonceTrialsPerByte*(len(encryptedPayload) + 8 + requiredPayloadLengthExtraBytes + ((TTL*(len(encryptedPayload)+8+requiredPayloadLengthExtraBytes))/(2 ** 16)))) - 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 + logger.info('(For msg message) Doing proof of work. Total required difficulty: %f. Required small message difficulty: %f.', float(requiredAverageProofOfWorkNonceTrialsPerByte) / shared.networkDefaultProofOfWorkNonceTrialsPerByte, float(requiredPayloadLengthExtraBytes) / shared.networkDefaultPayloadLengthExtraBytes) powStartTime = time.time() initialHash = hashlib.sha512(encryptedPayload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - 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 + logger.info('(For msg message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) + try: + logger.info('POW took ' + str(int(time.time() - powStartTime)) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + except: + pass encryptedPayload = pack('>Q', nonce) + encryptedPayload @@ -823,7 +799,7 @@ class singleWorker(threading.Thread): else: # not sending to a chan or one of my addresses 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') + logger.info('Broadcasting inv for my msg(within sendmsg function):' + inventoryHash.encode('hex')) shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) @@ -871,8 +847,7 @@ class singleWorker(threading.Thread): toStatus, addressVersionNumber, streamNumber, ripe = decodeAddress( toAddress) if toStatus != 'success': - with shared.printLock: - sys.stderr.write('Very abnormal error occurred in requestPubKey. toAddress is: ' + repr( + logger.error('Very abnormal error occurred in requestPubKey. toAddress is: ' + repr( toAddress) + '. Please report this error to Atheros.') return @@ -907,12 +882,10 @@ class singleWorker(threading.Thread): payload += encodeVarint(streamNumber) if addressVersionNumber <= 3: payload += ripe - with shared.printLock: - print 'making request for pubkey with ripe:', ripe.encode('hex') + logger.info('making request for pubkey with ripe:', ripe.encode('hex')) else: payload += tag - with shared.printLock: - print 'making request for v4 pubkey with tag:', tag.encode('hex') + logger.info('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.' @@ -923,8 +896,7 @@ class singleWorker(threading.Thread): 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) - with shared.printLock: - print 'Found proof of work', trialValue, 'Nonce:', nonce + logger.info('Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) payload = pack('>Q', nonce) + payload inventoryHash = calculateInventoryHash(payload) @@ -932,7 +904,7 @@ class singleWorker(threading.Thread): shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, '') shared.inventorySets[streamNumber].add(inventoryHash) - print 'sending inv (for the getpubkey message)' + logger.info('sending inv (for the getpubkey message)') shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -976,18 +948,16 @@ class singleWorker(threading.Thread): 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 + logger.info('(For ack message) Doing proof of work. TTL set to ' + str(TTL)) powStartTime = time.time() initialHash = hashlib.sha512(payload).digest() trialValue, nonce = proofofwork.run(target, initialHash) - 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 + logger.info('(For ack message) Found proof of work ' + str(trialValue) + ' Nonce: ' + str(nonce)) + try: + logger.info('POW took ' + str(time.time() - powStartTime) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + except: + pass payload = pack('>Q', nonce) + payload return shared.CreatePacket('object', payload) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 9de44a42..63621c89 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -19,7 +19,7 @@ import tr#anslate class sqlThread(threading.Thread): def __init__(self): - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="SQL") def run(self): self.conn = sqlite3.connect(shared.appdata + 'messages.dat') diff --git a/src/debug.py b/src/debug.py index 30c64ea4..d430e5e3 100644 --- a/src/debug.py +++ b/src/debug.py @@ -18,15 +18,33 @@ 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 traceback import helper_startup helper_startup.loadConfig() # TODO(xj9): Get from a config file. log_level = 'DEBUG' +def log_uncaught_exceptions(ex_cls, ex, tb): + logging.critical(''.join(traceback.format_tb(tb))) + logging.critical('{0}: {1}'.format(ex_cls, ex)) + def configureLogging(): + have_logging = False + try: + logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) + have_logging = True + except: + pass + + sys.excepthook = log_uncaught_exceptions + + if have_logging: + return False + logging.config.dictConfig({ 'version': 1, 'formatters': { @@ -69,13 +87,17 @@ def configureLogging(): 'handlers': ['console'], }, }) + return True + # TODO (xj9): Get from a config file. #logger = logging.getLogger('console_only') -configureLogging() -if '-c' in sys.argv: - logger = logging.getLogger('file_only') +if configureLogging(): + if '-c' in sys.argv: + logger = logging.getLogger('file_only') + else: + logger = logging.getLogger('both') else: - logger = logging.getLogger('both') + logger = logging.getLogger('default') def restartLoggingInUpdatedAppdataLocation(): global logger @@ -83,9 +105,11 @@ def restartLoggingInUpdatedAppdataLocation(): logger.removeHandler(i) i.flush() i.close() - configureLogging() - if '-c' in sys.argv: - logger = logging.getLogger('file_only') + if configureLogging(): + if '-c' in sys.argv: + logger = logging.getLogger('file_only') + else: + logger = logging.getLogger('both') else: - logger = logging.getLogger('both') + logger = logging.getLogger('default') diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index edeeb984..ae1adacb 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -4,6 +4,8 @@ import defaultKnownNodes import pickle import time +from debug import logger + def knownNodes(): try: # We shouldn't have to use the shared.knownNodesLock because this had @@ -26,7 +28,7 @@ def knownNodes(): except: 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.' + logger.error('Bitmessage cannot read future versions of the keys file (keys.dat). Run the newer version of Bitmessage.') raise SystemExit def dns(): @@ -39,16 +41,16 @@ def dns(): if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': try: for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): - print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' + logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) except: - print 'bootstrap8080.bitmessage.org DNS bootstrapping failed.' + logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') try: for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): - print 'Adding', item[4][0], 'to knownNodes based on DNS boostrap method' + logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) except: - print 'bootstrap8444.bitmessage.org DNS bootstrapping failed.' + logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') else: - print 'DNS bootstrap skipped because SOCKS is used.' + logger.info('DNS bootstrap skipped because SOCKS is used.') -- 2.45.1 From d7817ca2ef299134e62c97d22f1dcbdc71c44b3a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 04:05:58 +0100 Subject: [PATCH 0150/1102] Smoother rerenderTabSubscriptions Does not reset it all the time but adds/removes Fixes #109 --- src/bitmessageqt/__init__.py | 84 +++++++++++++++++++++++++----------- src/bitmessageqt/account.py | 20 +++++++++ 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 87eb1083..82dfa5ef 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -390,37 +390,73 @@ class MyForm(settingsmixin.SMainWindow): def rerenderTabTreeSubscriptions(self): treeWidget = self.ui.treeWidgetSubscriptions folders = ['inbox', 'sent', 'trash'] - treeWidget.clear() - treeWidget.setSortingEnabled(False) - treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) - db = {} - queryreturn = sqlQuery('''SELECT fromaddress, folder, count(msgid) as cnt - FROM inbox, subscriptions - WHERE read = 0 AND subscriptions.address = inbox.fromaddress - GROUP BY inbox.fromaddress, folder''') - for row in queryreturn: - fromaddress, folder, cnt = row - if fromaddress not in db: - db[fromaddress] = {} - db[fromaddress][folder] = cnt - queryreturn = sqlQuery('SELECT label, address, enabled FROM subscriptions') - for row in queryreturn: - label, address, enabled = row - newItem = Ui_SubscriptionWidget(treeWidget, 0, address, 0, label, enabled) + # sort ascending when creating + if treeWidget.topLevelItemCount() == 0: + treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) + # init dictionary + + db = getSortedSubscriptions(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]['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(): + subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count']) + 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: - newSubItem = Ui_FolderWidget(newItem, 0, address, folder, db[address][folder]) - unread += db[address][folder] + subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]['count']) + unread += db[toAddress][folder]['count'] except KeyError: - newSubItem = Ui_FolderWidget(newItem, 0, address, folder, 0) - - newItem.setUnreadCount(unread) - newItem.setFlags (newItem.flags() | QtCore.Qt.ItemIsEditable) - + subwidget = Ui_FolderWidget(widget, j, toAddress, folder, 0) + j += 1 + widget.setUnreadCount(unread) + widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) + i += 1 + treeWidget.setSortingEnabled(True) + def rerenderTabTreeMessages(self): self.rerenderTabTree('messages') diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 6e1083f6..83ce76c9 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -18,6 +18,26 @@ def getSortedAccounts(): ) 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 + WHERE read = 0 AND subscriptions.address = inbox.fromaddress + GROUP BY inbox.fromaddress, folder''') + for row in queryreturn: + address, folder, cnt = row + ret[address][folder]['count'] = cnt + return ret + def accountClass(address): if not shared.config.has_section(address): if address == str_broadcast_subscribers: -- 2.45.1 From cd9a7b51574d6c863374a56602492c6fb30f2eb7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 04:14:13 +0100 Subject: [PATCH 0151/1102] Missing folders in rerenderTabTreeSubscriptions I optimised it too much and sometimes folders were missing in the tree. --- src/bitmessageqt/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 82dfa5ef..2d591d9b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -397,6 +397,10 @@ class MyForm(settingsmixin.SMainWindow): # 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) @@ -432,7 +436,10 @@ class MyForm(settingsmixin.SMainWindow): if len(db[toAddress]) > 0: j = 0 for f, c in db[toAddress].iteritems(): - subwidget = Ui_FolderWidget(widget, j, toAddress, f, c['count']) + 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) -- 2.45.1 From dd15d1b6ed13b269c918759d11c7997549ad74e6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 17:37:34 +0100 Subject: [PATCH 0152/1102] Delete key and shift modifier Addresses #114 - delete from sent works when pressing delete key - delete from trash deletes rather than moves - delete with shift deletes rather than moves --- src/bitmessageqt/__init__.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 2d591d9b..650b83f1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1065,7 +1065,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setSortingEnabled(False) tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) - tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent + tableWidget.keyPressEvent = self.tableWidgetSentKeyPressEvent # Load messages from database file def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what=""): @@ -1497,6 +1497,12 @@ class MyForm(settingsmixin.SMainWindow): self.on_action_InboxTrash() return QtGui.QTableWidget.keyPressEvent(self.getCurrentMessagelist(), event) + # set delete key in inbox + def tableWidgetSentKeyPressEvent(self, event): + if event.key() == QtCore.Qt.Key_Delete: + self.on_action_SentTrash() + return QtGui.QTableWidget.keyPressEvent(self.getCurrentMessagelist(), event) + # menu button 'manage keys' def click_actionManageKeys(self): if 'darwin' in sys.platform or 'linux' in sys.platform: @@ -3161,11 +3167,18 @@ class MyForm(settingsmixin.SMainWindow): return unread = False currentRow = 0 + folder = self.getCurrentFolder() + shifted = QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ShiftModifier while tableWidget.selectedIndexes(): currentRow = tableWidget.selectedIndexes()[0].row() inventoryHashToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) - sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) + if folder == "trash" or shifted: + logger.debug ("deleting") + sqlExecute('''DELETE FROM inbox WHERE msgid=?''', inventoryHashToTrash) + else: + logger.debug ("moving to trash, because folder = \"%s\" and shifted = %r %x", folder, shifted) + sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): unread = True self.getCurrentMessageTextedit().setText("") @@ -3241,11 +3254,16 @@ class MyForm(settingsmixin.SMainWindow): 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(Qt.UserRole).toPyObject()) - sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) + 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).font().bold(): unread = True self.getCurrentMessageTextedit().setPlainText("") -- 2.45.1 From 8909a535ae1f8eaf2a84d43d21ad3588f0260249 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 17:42:04 +0100 Subject: [PATCH 0153/1102] Remove extra debug logging --- src/bitmessageqt/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 650b83f1..cf162b65 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3174,10 +3174,8 @@ class MyForm(settingsmixin.SMainWindow): inventoryHashToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) if folder == "trash" or shifted: - logger.debug ("deleting") sqlExecute('''DELETE FROM inbox WHERE msgid=?''', inventoryHashToTrash) else: - logger.debug ("moving to trash, because folder = \"%s\" and shifted = %r %x", folder, shifted) sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): unread = True -- 2.45.1 From 1f331f217c9057a383811d586ac7c8299ad02303 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 18:45:46 +0100 Subject: [PATCH 0154/1102] Messagelist address tooltip Fixes #108 --- src/bitmessageqt/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cf162b65..0a51b550 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -992,7 +992,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.insertRow(0) toAddressItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8')) + toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") toAddressItem.setIcon(avatarize(toAddress)) toAddressItem.setData(Qt.UserRole, str(toAddress)) toAddressItem.setTextColor(AccountColor(toAddress).accountColor()) @@ -1001,7 +1001,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setItem(0, 0, toAddressItem) fromAddressItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) + fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") fromAddressItem.setIcon(avatarize(fromAddress)) fromAddressItem.setData(Qt.UserRole, str(fromAddress)) fromAddressItem.setTextColor(AccountColor(fromAddress).accountColor()) @@ -1127,7 +1127,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.insertRow(0) # to to_item = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - to_item.setToolTip(unicode(acct.toLabel, 'utf-8')) + to_item.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") to_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -1138,7 +1138,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setItem(0, 0, to_item) # from from_item = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - from_item.setToolTip(unicode(acct.fromLabel, 'utf-8')) + from_item.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(fromAddress) + ")") from_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) if not read: @@ -2399,12 +2399,12 @@ class MyForm(settingsmixin.SMainWindow): sent.setSortingEnabled(False) sent.insertRow(0) newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") newItem.setData(Qt.UserRole, str(toAddress)) newItem.setIcon(avatarize(toAddress)) sent.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setIcon(avatarize(fromAddress)) sent.setItem(0, 1, newItem) @@ -2446,7 +2446,7 @@ class MyForm(settingsmixin.SMainWindow): font.setBold(True) inbox.setSortingEnabled(False) newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.toLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") newItem.setFont(font) newItem.setData(Qt.UserRole, str(toAddress)) newItem.setTextColor(AccountColor(toAddress).accountColor()) @@ -2455,7 +2455,7 @@ class MyForm(settingsmixin.SMainWindow): inbox.setItem(0, 0, newItem) newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.fromLabel, 'utf-8')) + newItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") newItem.setData(Qt.UserRole, str(fromAddress)) newItem.setFont(font) newItem.setTextColor(AccountColor(fromAddress).accountColor()) -- 2.45.1 From c2970cd92e99666e4d34c25b84386205e8a93cd6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 19:17:26 +0100 Subject: [PATCH 0155/1102] Update addressbook on changes Fixes #99 - enable/disable new/delete chan/subscription - also found and fixed a logger crash --- src/bitmessageqt/__init__.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0a51b550..ecce20f3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1581,7 +1581,7 @@ class MyForm(settingsmixin.SMainWindow): 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() - logger.debug('addressGeneratorReturnValue ' + addressGeneratorReturnValue) + logger.debug('addressGeneratorReturnValue ' + str(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.")) @@ -1606,7 +1606,7 @@ class MyForm(settingsmixin.SMainWindow): 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() - logger.debug('addressGeneratorReturnValue ' + addressGeneratorReturnValue) + logger.debug('addressGeneratorReturnValue ' + str(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.")) @@ -1619,6 +1619,7 @@ class MyForm(settingsmixin.SMainWindow): QMessageBox.about(self, _translate("MainWindow", "Success"), _translate( "MainWindow", "Successfully joined chan. ")) self.ui.tabWidget.setCurrentIndex(3) + self.rerenderAddressBook() def showConnectDialog(self): self.connectDialogInstance = connectDialog(self) @@ -2081,7 +2082,7 @@ class MyForm(settingsmixin.SMainWindow): addresses = getSortedAccounts() for address in addresses: account = accountClass(address) - if (account.type == 'chan'): + if (account.type == 'chan' and shared.safeConfigGetBoolean(address, 'enabled')): addRow(address, account.getLabel(), 'chan') # normal accounts @@ -2512,7 +2513,7 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',str(label),address,True) self.rerenderInboxFromLabels() shared.reloadBroadcastSendersForWhichImWatching() - + self.rerenderAddressBook() self.rerenderTabTreeSubscriptions() def click_pushButtonAddSubscription(self): @@ -3396,6 +3397,7 @@ class MyForm(settingsmixin.SMainWindow): address) self.rerenderTabTreeSubscriptions() self.rerenderInboxFromLabels() + self.rerenderAddressBook() shared.reloadBroadcastSendersForWhichImWatching() def on_action_SubscriptionsClipboard(self): @@ -3410,6 +3412,7 @@ class MyForm(settingsmixin.SMainWindow): address) account = self.getCurrentItem() account.setEnabled(True) + self.rerenderAddressBook() shared.reloadBroadcastSendersForWhichImWatching() def on_action_SubscriptionsDisable(self): @@ -3419,6 +3422,7 @@ class MyForm(settingsmixin.SMainWindow): address) account = self.getCurrentItem() account.setEnabled(False) + self.rerenderAddressBook() shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): @@ -3678,6 +3682,7 @@ class MyForm(settingsmixin.SMainWindow): return shared.writeKeysFile() shared.reloadMyAddressHashes() + self.rerenderAddressBook() if account.type == "normal": self.rerenderTabTreeMessages() elif account.type == "chan": @@ -3693,6 +3698,7 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set(address, 'enabled', 'true') shared.writeKeysFile() shared.reloadMyAddressHashes() + self.rerenderAddressBook() def on_action_Disable(self): address = self.getCurrentAccount() @@ -3704,6 +3710,7 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set(str(address), 'enabled', 'false') shared.writeKeysFile() shared.reloadMyAddressHashes() + self.rerenderAddressBook() def on_action_Clipboard(self): address = self.getCurrentAccount() -- 2.45.1 From 960d4461049d0f7ab43ca68df4c2d29f4a0ae711 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 19:28:32 +0100 Subject: [PATCH 0156/1102] Ask before deleting a subscription Fixes #120 --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ecce20f3..03ebd2a3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3392,6 +3392,8 @@ class MyForm(settingsmixin.SMainWindow): 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?"), QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: + return address = self.getCurrentAccount() sqlExecute('''DELETE FROM subscriptions WHERE address=?''', address) -- 2.45.1 From b7ad34cf15e78285fad207ded02ac73bf3606744 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 19 Nov 2015 19:48:18 +0100 Subject: [PATCH 0157/1102] Trusted peer flood protection Is not needed. Fixed Bitmessage#786 --- src/class_receiveDataThread.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index fa165401..c227648a 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -410,7 +410,7 @@ class receiveDataThread(threading.Thread): logger.info('inv message doesn\'t contain enough data. Ignoring.') return 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 + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over 1000 from this node in particular. Ignoring this inv message.') return self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware[ @@ -433,7 +433,7 @@ class receiveDataThread(threading.Thread): 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 + if totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers > 200000 and len(self.objectsThatWeHaveYetToGetFromThisPeer) > 1000 and shared.trustedPeer == None: # inv flooding attack mitigation logger.debug('We already have ' + str(totalNumberOfobjectsThatWeHaveYetToGetFromAllPeers) + ' items yet to retrieve from peers and over ' + str(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 -- 2.45.1 From 9338772b1ec021bf56fb458895e46eb07636c248 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 20 Nov 2015 08:49:44 +0100 Subject: [PATCH 0158/1102] Logging updates Came over BM (from "general" channel), I slightly modified it. --- src/bitmessageqt/__init__.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 03ebd2a3..4ac0694a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1,3 +1,4 @@ +from debug import logger withMessagingMenu = False try: from gi.repository import MessagingMenu @@ -12,14 +13,14 @@ try: from PyQt4.QtGui import * except Exception as err: - logger.error( '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.error('Error message: ' + str(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() try: _encoding = QtGui.QApplication.UnicodeUTF8 except AttributeError: - logger.error('QtGui.QApplication.UnicodeUTF8 error: ' + str(err)) + logger.exception('QtGui.QApplication.UnicodeUTF8 error', exc_info=True) from addresses import * import shared @@ -51,7 +52,6 @@ import pickle import platform import textwrap import debug -from debug import logger import subprocess import datetime from helper_sql import * @@ -3243,7 +3243,7 @@ class MyForm(settingsmixin.SMainWindow): f.write(message) f.close() except Exception, e: - sys.stderr.write('Write error: '+ e) + logger.exception('Message not saved', exc_info=True) self.statusBar().showMessage(_translate("MainWindow", "Write error.")) # Send item on the Sent tab to trash -- 2.45.1 From 0aff212a7b07003ccda2752084b96f3efba3a941 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 20 Nov 2015 19:33:21 +0100 Subject: [PATCH 0159/1102] Remove ebuildpackage Fixes Bitmessage#331 --- ebuildpackage/pybitmessage-0.3.5-1.ebuild | 32 ----------------------- 1 file changed, 32 deletions(-) delete mode 100755 ebuildpackage/pybitmessage-0.3.5-1.ebuild diff --git a/ebuildpackage/pybitmessage-0.3.5-1.ebuild b/ebuildpackage/pybitmessage-0.3.5-1.ebuild deleted file mode 100755 index 01eddc4f..00000000 --- a/ebuildpackage/pybitmessage-0.3.5-1.ebuild +++ /dev/null @@ -1,32 +0,0 @@ -# $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 -} -- 2.45.1 From 0270dc3d4ddd5321fc14c5b8fb517cab7aef5855 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 21 Nov 2015 00:39:23 +0100 Subject: [PATCH 0160/1102] Cleanup UPnP --- src/upnp.py | 68 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index 5104ea34..f1cc4635 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -118,6 +118,20 @@ class Router: if service.childNodes[0].data.find('WANIPConnection') > 0: self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data + # get local IP + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + logger.debug("Connecting to %s:%i", self.address, self.routerPath.port) + s.connect ((self.address, self.routerPath.port)) + except: + pass + self.localAddress = s.getsockname()[0] + logger.debug("Local IP: %s", self.localAddress) + try: + s.close() + except: + pass + def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ ('NewExternalPort', str(externalPort)), @@ -128,6 +142,7 @@ class Router: ('NewPortMappingDescription', str(description)), ('NewLeaseDuration', str(leaseDuration)) ]) + self.extPort = externalPort return resp def DeletePortMapping(self, externalPort, protocol): @@ -145,6 +160,7 @@ class Router: 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', @@ -159,40 +175,42 @@ class Router: dom = parseString(resp) errinfo = dom.getElementsByTagName('errorDescription') if len(errinfo) > 0: + logger.error("UPnP error: %s", resp) raise UPnPError(errinfo[0].childNodes[0].data) return resp +def createPortMappingInternal(router): + from debug import logger + + for i in range(0, 50): + try: + routerIP, = unpack('>I', socket.inet_aton(router.address)) + localIP = router.localAddress + localPort = shared.config.getint('bitmessagesettings', 'port') + if i == 0: + extPort = localPort # try same port first + else: + extPort = randint(32767, 65535) + logger.debug("Requesting UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) + router.AddPortMapping(extPort, localPort, localIP, 'TCP', 'BitMessage') + logger.info("Successfully established UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) + shared.extPort = extPort + break + except UPnPError: + logger.debug("UPnP error: ", exc_info=True) def createPortMapping(): - from struct import unpack, pack + from debug import logger global routers + routers = searchRouter() - localIPs = socket.gethostbyname_ex(socket.gethostname())[2] + logger.debug("Found %i UPnP routers", len(routers)) - 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() + for router in routers: + createPortMappingInternal(router) def deletePortMapping(): localPort = config.getint('bitmessagesettings', 'port') for router in routers: - router.DeletePortMapping(localPort, 'TCP') + if hasattr(router, "extPort"): + router.DeletePortMapping(router.extPort, 'TCP') -- 2.45.1 From aa55f45a0d06eb935e1a98de8a981e21f8441a82 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 21 Nov 2015 00:41:08 +0100 Subject: [PATCH 0161/1102] Logging fix --- src/class_sendDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 1a839d50..32049ec3 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -174,7 +174,7 @@ class sendDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.services, self.sslSock = data else: - logger.error('sendDataThread ID: ' + id(self) + ' ignoring command ' + command + ' because the thread is not in stream' + deststream) + logger.error('sendDataThread ID: ' + id(self) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) try: self.sock.shutdown(socket.SHUT_RDWR) -- 2.45.1 From 3c9df7151c313fe52ca135c670a2fc2a7c85b696 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 21 Nov 2015 10:14:30 +0100 Subject: [PATCH 0162/1102] Logging fix --- src/class_sendDataThread.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 32049ec3..665bbb1b 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -174,7 +174,7 @@ class sendDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.services, self.sslSock = data else: - logger.error('sendDataThread ID: ' + id(self) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) + logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) try: self.sock.shutdown(socket.SHUT_RDWR) -- 2.45.1 From 5432c6e0c8c2672062e04a614fd2fd23b8e3a277 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 21 Nov 2015 10:15:20 +0100 Subject: [PATCH 0163/1102] UPnP logging improvlement --- src/upnp.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index f1cc4635..8dd2a9d3 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -23,8 +23,18 @@ def searchRouter(): routers = [] sock.settimeout(0.5) try: - resp,(ip,port) = sock.recvfrom(1000) - while resp: + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) + sock.settimeout(2) + logger.debug("Sending UPnP query") + sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT)) + except: + logger.exception("UPnP sock failed") + try: + while True: + resp,(ip,port) = sock.recvfrom(1000) + if resp is None: + continue routers.append(Router(resp, ip)) resp,(ip,port) = sock.recvfrom(1000) except:pass @@ -146,10 +156,12 @@ class Router: return resp def DeletePortMapping(self, externalPort, protocol): + from debug import logger resp = self.soapRequest('WANIPConnection:1', 'DeletePortMapping', [ ('NewExternalPort', str(externalPort)), ('NewProtocol', protocol), ]) + logger.info("Removed UPnP mapping on external port %i", extPort) return resp def GetExternalIPAddress(self): -- 2.45.1 From cc848cdb655c38b375178357627d8233901bc2ee Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 21 Nov 2015 10:17:27 +0100 Subject: [PATCH 0164/1102] Typo fix --- src/upnp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upnp.py b/src/upnp.py index 8dd2a9d3..e09f6066 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -161,7 +161,7 @@ class Router: ('NewExternalPort', str(externalPort)), ('NewProtocol', protocol), ]) - logger.info("Removed UPnP mapping on external port %i", extPort) + logger.info("Removed UPnP mapping on external port %i", externalPort) return resp def GetExternalIPAddress(self): -- 2.45.1 From c03c563a7450fa22c6879aa5cec7b0260efa7fc8 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 21 Nov 2015 11:59:44 +0100 Subject: [PATCH 0165/1102] Make UPnP into a thread - UPnP is now a separate thread that will continue to setup UPnP - shutdown waits for threads that shutdown correctly (Addresses Bitmessage#549) --- src/bitmessagemain.py | 8 ++- src/shared.py | 9 ++- src/upnp.py | 157 ++++++++++++++++++++++++------------------ 3 files changed, 100 insertions(+), 74 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 079ba5bd..c27cc137 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -149,9 +149,6 @@ class Main: # is the application already running? If yes then exit. thisapp = singleton.singleinstance("", daemon) - import upnp - upnp.createPortMapping() - # get curses flag curses = False if '-c' in sys.argv: @@ -210,6 +207,11 @@ class Main: singleListenerThread.setup(selfInitiatedConnections) singleListenerThread.daemon = True # close the main program even if there are threads left singleListenerThread.start() + + if shared.safeConfigGetBoolean('bitmessagesettings','upnp'): + import upnp + upnpThread = upnp.uPnPThread() + upnpThread.start() if daemon == False and shared.safeConfigGetBoolean('bitmessagesettings', 'daemon') == False: if curses == False: diff --git a/src/shared.py b/src/shared.py index 98f46413..e3bfeafd 100644 --- a/src/shared.py +++ b/src/shared.py @@ -384,8 +384,6 @@ def doCleanShutdown(): '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: @@ -399,7 +397,12 @@ def doCleanShutdown(): # 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) + time.sleep(.25) + + for thread in threading.enumerate(): + if thread.name == "uPnPThread" or "outgoingSynSender" in thread.name: + logger.debug("Waiting for thread %s", thread.name) + thread.join() if safeConfigGetBoolean('bitmessagesettings','daemon'): logger.info('Clean shutdown complete.') diff --git a/src/upnp.py b/src/upnp.py index e09f6066..ec82caab 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -1,45 +1,10 @@ # A simple upnp module to forward port for BitMessage # Reference: http://mattscodecave.com/posts/using-python-and-upnp-to-forward-a-port import socket -import httplib -from shared import config - -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: - sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) - sock.settimeout(2) - logger.debug("Sending UPnP query") - sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT)) - except: - logger.exception("UPnP sock failed") - try: - while True: - resp,(ip,port) = sock.recvfrom(1000) - if resp is None: - continue - routers.append(Router(resp, ip)) - resp,(ip,port) = sock.recvfrom(1000) - except:pass - - return routers +from struct import unpack, pack +import threading +import time +import shared def createRequestXML(service, action, arguments=[]): from xml.dom.minidom import Document @@ -98,6 +63,8 @@ class Router: path = "" address = None routerPath = None + extPort = None + def __init__(self, ssdpResponse, address): import urllib2 from xml.dom.minidom import parseString @@ -143,6 +110,7 @@ class Router: pass def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): + from debug import logger resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ ('NewExternalPort', str(externalPort)), ('NewProtocol', protocol), @@ -153,6 +121,7 @@ class Router: ('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): @@ -191,38 +160,90 @@ class Router: raise UPnPError(errinfo[0].childNodes[0].data) return resp -def createPortMappingInternal(router): - from debug import logger +class uPnPThread(threading.Thread): + def __init__ (self): + threading.Thread.__init__(self, name="uPnPThread") + self.localPort = shared.config.getint('bitmessagesettings', 'port') + self.extPort = None + self.routers = [] + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) + self.sock.settimeout(10) + self.sendSleep = 60 + + def run(self): + from debug import logger + + logger.debug("Starting UPnP thread") + lastSent = 0 + while shared.shutdown == 0: + if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: + self.sendSearchRouter() + lastSent = time.time() + try: + while shared.shutdown == 0: + 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) + 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) + for router in self.routers: + if router.extPort is not None: + self.deletePortMapping(router) + logger.debug("UPnP thread done") + + def sendSearchRouter(self): + from debug import logger + 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" - for i in range(0, 50): try: - routerIP, = unpack('>I', socket.inet_aton(router.address)) - localIP = router.localAddress - localPort = shared.config.getint('bitmessagesettings', 'port') - if i == 0: - extPort = localPort # try same port first - else: - extPort = randint(32767, 65535) - logger.debug("Requesting UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) - router.AddPortMapping(extPort, localPort, localIP, 'TCP', 'BitMessage') - logger.info("Successfully established UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) - shared.extPort = extPort - break - except UPnPError: - logger.debug("UPnP error: ", exc_info=True) + logger.debug("Sending UPnP query") + self.sock.sendto(ssdpRequest, (SSDP_ADDR, SSDP_PORT)) + except: + logger.exception("UPnP send query failed") -def createPortMapping(): - from debug import logger - global routers + def createPortMapping(self, router): + from debug import logger + + for i in range(50): + try: + routerIP, = unpack('>I', socket.inet_aton(router.address)) + localIP = router.localAddress + if i == 0: + extPort = self.localPort # try same port first + else: + extPort = randint(32767, 65535) + logger.debug("Requesting UPnP mapping for %s:%i on external port %i", localIP, self.localPort, extPort) + router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage') + shared.extPort = extPort + break + except UPnPError: + logger.debug("UPnP error: ", exc_info=True) + + def deletePortMapping(self, router): + router.DeletePortMapping(router.extPort, 'TCP') - routers = searchRouter() - logger.debug("Found %i UPnP routers", len(routers)) - for router in routers: - createPortMappingInternal(router) -def deletePortMapping(): - localPort = config.getint('bitmessagesettings', 'port') - for router in routers: - if hasattr(router, "extPort"): - router.DeletePortMapping(router.extPort, 'TCP') -- 2.45.1 From 8c14641810aa3c7064b83e393258905b4aa72a00 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 01:07:25 +0100 Subject: [PATCH 0166/1102] Window resize on minimize bugfix Fixes Bitmessage#243 --- src/bitmessageqt/__init__.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4ac0694a..f00d76af 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -810,10 +810,6 @@ 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) @@ -1649,9 +1645,7 @@ class MyForm(settingsmixin.SMainWindow): if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: 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) + QTimer.singleShot(0, self.appIndicatorHide) elif event.oldState() & QtCore.Qt.WindowMinimized: # The window state has just been changed to # Normal/Maximised/FullScreen -- 2.45.1 From 50be5a2b4c9fb12da7769e0ad9a204d1eb3ad86e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 01:10:02 +0100 Subject: [PATCH 0167/1102] UPnP fixes --- src/upnp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/upnp.py b/src/upnp.py index ec82caab..e9851b36 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -201,6 +201,7 @@ class uPnPThread(threading.Thread): for router in self.routers: if router.extPort is None: self.createPortMapping(router) + self.sock.close() for router in self.routers: if router.extPort is not None: self.deletePortMapping(router) -- 2.45.1 From 48b9e5039793f336951f2ed10804e06805727e3b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 13:02:06 +0100 Subject: [PATCH 0168/1102] UPnP GUI Settings GUI now contains a checkbox for UPnP and auto starts/stops the thread when changed. Default UPnP socket timeout decreased for faster thread starting/stopping --- src/bitmessageqt/__init__.py | 8 ++++++++ src/bitmessageqt/settings.py | 15 +++++++++++---- src/upnp.py | 6 +++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f00d76af..10abc82d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2583,6 +2583,12 @@ class MyForm(settingsmixin.SMainWindow): "MainWindow", "You must restart Bitmessage for the port number change to take effect.")) shared.config.set('bitmessagesettings', 'port', str( self.settingsDialogInstance.ui.lineEditTCPPort.text())) + if self.settingsDialogInstance.ui.checkBoxUPnP.isChecked() != shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): + shared.config.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 shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and self.settingsDialogInstance.ui.comboBoxProxyType.currentText()[0:5] == 'SOCKS': @@ -4127,6 +4133,8 @@ class settingsDialog(QtGui.QDialog): # On the Network settings tab: self.ui.lineEditTCPPort.setText(str( shared.config.get('bitmessagesettings', 'port'))) + self.ui.checkBoxUPnP.setChecked( + shared.safeConfigGetBoolean('bitmessagesettings', 'upnp')) self.ui.checkBoxAuthentication.setChecked(shared.config.getboolean( 'bitmessagesettings', 'socksauthentication')) self.ui.checkBoxSocksListen.setChecked(shared.config.getboolean( diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index b9131315..4a1dfc7c 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -120,15 +120,21 @@ 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, 1, 1, 1) + self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1, QtCore.Qt.AlignRight) 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, 2, 1, 1) + 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_4.addWidget(self.groupBox1, 0, 0, 1, 1) self.groupBox_3 = QtGui.QGroupBox(self.tabNetworkSettings) self.groupBox_3.setObjectName(_fromUtf8("groupBox_3")) @@ -449,6 +455,7 @@ class Ui_settingsDialog(object): 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)) diff --git a/src/upnp.py b/src/upnp.py index e9851b36..62fea1b4 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -168,7 +168,7 @@ class uPnPThread(threading.Thread): self.routers = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) - self.sock.settimeout(10) + self.sock.settimeout(2) self.sendSleep = 60 def run(self): @@ -176,12 +176,12 @@ class uPnPThread(threading.Thread): logger.debug("Starting UPnP thread") lastSent = 0 - while shared.shutdown == 0: + while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: self.sendSearchRouter() lastSent = time.time() try: - while shared.shutdown == 0: + while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): resp,(ip,port) = self.sock.recvfrom(1000) if resp is None: continue -- 2.45.1 From b00c4f24eccd9f0225cffc3103efa58ec890f820 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 16:18:59 +0100 Subject: [PATCH 0169/1102] Threads close better - UPnP and outgoingSynSender threads close slightly better. - extPort initialisation was missing --- src/class_outgoingSynSender.py | 46 +++++++++++++++++++++------------- src/helper_threading.py | 10 ++++++++ src/shared.py | 15 +++++++++-- src/upnp.py | 5 +++- 4 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 src/helper_threading.py diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 732f6c9f..d011ae94 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -2,6 +2,7 @@ import threading import time import random import shared +import select import socks import socket import sys @@ -9,14 +10,16 @@ import tr from class_sendDataThread import * from class_receiveDataThread import * +from helper_threading import * # For each stream to which we connect, several outgoingSynSender threads # will exist and will collectively create 8 connections with peers. -class outgoingSynSender(threading.Thread): +class outgoingSynSender(threading.Thread, StoppableThread): def __init__(self): threading.Thread.__init__(self, name="outgoingSynSender") + self.initStop() def setup(self, streamNumber, selfInitiatedConnections): self.streamNumber = streamNumber @@ -35,15 +38,22 @@ class outgoingSynSender(threading.Thread): shared.knownNodesLock.release() return peer + + def stopThread(self): + super(outgoingSynSender, self).stopThread() + try: + self.sock.shutdown(socket.SHUT_RDWR) + except: + pass def run(self): - while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): - time.sleep(2) - while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections'): + while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and not self._stopped: + self.stop.wait(2) + while shared.safeConfigGetBoolean('bitmessagesettings', 'sendoutgoingconnections') and not self._stopped: self.name = "outgoingSynSender" maximumConnections = 1 if shared.trustedPeer else 8 # maximum number of outgoing connections = 8 while len(self.selfInitiatedConnections[self.streamNumber]) >= maximumConnections: - time.sleep(10) + self.stop.wait(10) if shared.shutdown: break random.seed() @@ -54,7 +64,9 @@ class outgoingSynSender(threading.Thread): # print 'choosing new sample' random.seed() peer = self._getPeer() - time.sleep(1) + self.stop.wait(1) + if shared.shutdown: + break # 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. @@ -71,7 +83,7 @@ class outgoingSynSender(threading.Thread): else: address_family = socket.AF_INET6 try: - sock = socks.socksocket(address_family, socket.SOCK_STREAM) + self.sock = socks.socksocket(address_family, socket.SOCK_STREAM) except: """ The line can fail on Windows systems which aren't @@ -92,8 +104,8 @@ class outgoingSynSender(threading.Thread): continue # This option apparently avoids the TIME_WAIT state so that we # can rebind faster - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.settimeout(20) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.settimeout(20) if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none' and shared.verbose >= 2: logger.debug('Trying an outgoing connection to ' + str(peer)) @@ -113,10 +125,10 @@ class outgoingSynSender(threading.Thread): 'bitmessagesettings', 'socksusername') sockspassword = shared.config.get( 'bitmessagesettings', 'sockspassword') - sock.setproxy( + self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: - sock.setproxy( + self.sock.setproxy( proxytype, sockshostname, socksport, rdns) elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': if shared.verbose >= 2: @@ -133,19 +145,19 @@ class outgoingSynSender(threading.Thread): 'bitmessagesettings', 'socksusername') sockspassword = shared.config.get( 'bitmessagesettings', 'sockspassword') - sock.setproxy( + self.sock.setproxy( proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) else: - sock.setproxy( + self.sock.setproxy( proxytype, sockshostname, socksport, rdns) try: - sock.connect((peer.host, peer.port)) + self.sock.connect((peer.host, peer.port)) rd = receiveDataThread() rd.daemon = True # close the main program even if there are threads left 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, + rd.setup(self.sock, peer.host, peer.port, self.streamNumber, @@ -157,7 +169,7 @@ class outgoingSynSender(threading.Thread): sd = sendDataThread(sendDataThreadQueue) - sd.setup(sock, peer.host, peer.port, self.streamNumber, + sd.setup(self.sock, peer.host, peer.port, self.streamNumber, someObjectsOfWhichThisRemoteNodeIsAlreadyAware) sd.start() sd.sendVersionMessage() @@ -221,4 +233,4 @@ class outgoingSynSender(threading.Thread): except Exception as err: import traceback logger.exception('An exception has occurred in the outgoingSynSender thread that was not caught by other exception types:') - time.sleep(0.1) + self.stop.wait(0.1) diff --git a/src/helper_threading.py b/src/helper_threading.py new file mode 100644 index 00000000..599d297d --- /dev/null +++ b/src/helper_threading.py @@ -0,0 +1,10 @@ +import threading + +class StoppableThread(object): + def initStop(self): + self.stop = threading.Event() + self._stopped = False + + def stopThread(self): + self._stopped = True + self.stop.set() \ No newline at end of file diff --git a/src/shared.py b/src/shared.py index e3bfeafd..afab493c 100644 --- a/src/shared.py +++ b/src/shared.py @@ -32,6 +32,7 @@ import highlevelcrypto import shared #import helper_startup from helper_sql import * +from helper_threading import * config = ConfigParser.SafeConfigParser() @@ -116,6 +117,9 @@ frozen = getattr(sys,'frozen', None) # security. trustedPeer = None +# For UPnP +extPort = None + #Compiled struct for packing/unpacking headers #New code should use CreatePacket instead of Header.pack Header = Struct('!L12sL4s') @@ -160,8 +164,10 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): 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')) + if safeConfigGetBoolean('bitmessagesettings', 'upnp' and extPort): + payload += pack('>H', extPort) + else: + payload += pack('>H', shared.config.getint('bitmessagesettings', 'port')) random.seed() payload += eightBytesOfRandomDataUsedToDetectConnectionsToSelf @@ -399,6 +405,11 @@ def doCleanShutdown(): # shutdown variable and exit. If the main thread closes before they do then they won't stop. time.sleep(.25) + from class_outgoingSynSender import outgoingSynSender + for thread in threading.enumerate(): + if thread.name == "uPnPThread" or "outgoingSynSender" in thread.name: + if thread.isAlive() and isinstance(thread, StoppableThread): + thread.stopThread() for thread in threading.enumerate(): if thread.name == "uPnPThread" or "outgoingSynSender" in thread.name: logger.debug("Waiting for thread %s", thread.name) diff --git a/src/upnp.py b/src/upnp.py index 62fea1b4..c4c40b44 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -4,6 +4,7 @@ import socket from struct import unpack, pack import threading import time +from helper_threading import * import shared def createRequestXML(service, action, arguments=[]): @@ -160,7 +161,7 @@ class Router: raise UPnPError(errinfo[0].childNodes[0].data) return resp -class uPnPThread(threading.Thread): +class uPnPThread(threading.Thread, StoppableThread): def __init__ (self): threading.Thread.__init__(self, name="uPnPThread") self.localPort = shared.config.getint('bitmessagesettings', 'port') @@ -170,6 +171,7 @@ class uPnPThread(threading.Thread): self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) self.sock.settimeout(2) self.sendSleep = 60 + self.initStop() def run(self): from debug import logger @@ -205,6 +207,7 @@ class uPnPThread(threading.Thread): for router in self.routers: if router.extPort is not None: self.deletePortMapping(router) + shared.extPort = None logger.debug("UPnP thread done") def sendSearchRouter(self): -- 2.45.1 From 74519069f0659cfca662e582d14cf91f1705b0d1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 16:42:34 +0100 Subject: [PATCH 0170/1102] outgoingSynSender thread reaping disabled It was causing delays on shutdown, worse on linux/osx --- src/shared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index afab493c..6cc29116 100644 --- a/src/shared.py +++ b/src/shared.py @@ -411,7 +411,8 @@ def doCleanShutdown(): if thread.isAlive() and isinstance(thread, StoppableThread): thread.stopThread() for thread in threading.enumerate(): - if thread.name == "uPnPThread" or "outgoingSynSender" in thread.name: + if thread.name == "uPnPThread": + #or "outgoingSynSender" in thread.name: logger.debug("Waiting for thread %s", thread.name) thread.join() -- 2.45.1 From 18f7ef06e24c423ea26ffd2cca9a6e9ea661a466 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 16:43:53 +0100 Subject: [PATCH 0171/1102] SSL fixes Handle old Python compatibility better. --- src/class_receiveDataThread.py | 9 ++++++--- src/class_sendDataThread.py | 7 +++++-- src/shared.py | 13 ++++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c227648a..c745569e 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -81,7 +81,9 @@ class receiveDataThread(threading.Thread): shared.numberOfBytesReceivedLastSecond = 0 dataLen = len(self.data) try: - if (self.services & shared.NODE_SSL == shared.NODE_SSL) and self.connectionIsOrWasFullyEstablished: + if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + shared.haveSSL(not self.initiatedConnection)): dataRecv = self.sslSock.recv(1024) else: dataRecv = self.sock.recv(1024) @@ -251,7 +253,8 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.sslSock = self.sock - if (self.services & shared.NODE_SSL == shared.NODE_SSL and (self.initiatedConnection or sys.version_info >= (2, 7, 9))): + if (self.services & shared.NODE_SSL == shared.NODE_SSL and + shared.haveSSL(not self.initiatedConnection)): self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') if hasattr(self.sslSock, "context"): self.sslSock.context.set_ecdh_curve("secp256k1") @@ -267,7 +270,7 @@ class receiveDataThread(threading.Thread): except: break # 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', (self.services, self.sslSock, self.initiatedConnection))) if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 665bbb1b..869f7425 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -39,6 +39,7 @@ class sendDataThread(threading.Thread): self.name = "sendData-" + self.peer.host self.streamNumber = streamNumber self.services = 0 + self.initiatedConnection = False self.remoteProtocolVersion = - \ 1 # This must be set using setRemoteProtocolVersion command which is sent through the self.sendDataThreadQueue queue. self.lastTimeISentData = int( @@ -82,7 +83,9 @@ class sendDataThread(threading.Thread): uploadRateLimitBytes = 999999999 # float("inf") doesn't work else: uploadRateLimitBytes = shared.config.getint('bitmessagesettings', 'maxuploadrate') * 1000 - if self.services & shared.NODE_SSL == shared.NODE_SSL and self.connectionIsOrWasFullyEstablished: + if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and + self.connectionIsOrWasFullyEstablished and + shared.haveSSL(not self.initiatedConnection)): amountSent = self.sslSock.send(data[:1000]) else: amountSent = self.sock.send(data[:1000]) @@ -172,7 +175,7 @@ class sendDataThread(threading.Thread): break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True - self.services, self.sslSock = data + self.services, self.sslSock, self.initiatedConnection = data else: logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) diff --git a/src/shared.py b/src/shared.py index 6cc29116..72a48516 100644 --- a/src/shared.py +++ b/src/shared.py @@ -149,11 +149,18 @@ def encodeHost(host): else: return socket.inet_pton(socket.AF_INET6, host) -def assembleVersionMessage(remoteHost, remotePort, myStreamNumber): +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 assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = False): payload = '' payload += pack('>L', 3) # protocol version. - payload += pack('>q', NODE_NETWORK|(NODE_SSL if sys.version_info >= (2, 7, 9) else 0)) # bitflags of the services I offer. - # python < 2.7.9's ssl library does not support ECDSA server due to missing initialisation of available curves, but client works ok + payload += pack('>q', NODE_NETWORK|(NODE_SSL if haveSSL(server) else 0)) # bitflags of the services I offer. payload += pack('>q', int(time.time())) payload += pack( -- 2.45.1 From 281630757e51dfec5dbc0b6633c712eeca1f8a21 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 17:04:51 +0100 Subject: [PATCH 0172/1102] SSL fixes --- src/class_receiveDataThread.py | 2 +- src/class_sendDataThread.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index c745569e..a8996260 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -755,7 +755,7 @@ class receiveDataThread(threading.Thread): def sendversion(self): logger.debug('Sending version message') self.sendDataThreadQueue.put((0, 'sendRawData', shared.assembleVersionMessage( - self.peer.host, self.peer.port, self.streamNumber))) + self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection))) # Sends a verack message diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 869f7425..99c51f61 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -50,7 +50,7 @@ class sendDataThread(threading.Thread): def sendVersionMessage(self): datatosend = shared.assembleVersionMessage( - self.peer.host, self.peer.port, self.streamNumber) # the IP and port of the remote host, and my streamNumber. + self.peer.host, self.peer.port, self.streamNumber, not self.initiatedConnection) # the IP and port of the remote host, and my streamNumber. logger.debug('Sending version packet: ' + repr(datatosend)) -- 2.45.1 From e4a7e7179069a879e0b5a6888494ff078239896c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 22:44:58 +0100 Subject: [PATCH 0173/1102] SSL fixes --- src/class_receiveDataThread.py | 5 +++-- src/class_sendDataThread.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index a8996260..58a54346 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -253,8 +253,9 @@ class receiveDataThread(threading.Thread): self.connectionIsOrWasFullyEstablished = True self.sslSock = self.sock - if (self.services & shared.NODE_SSL == shared.NODE_SSL and + if ((self.services & shared.NODE_SSL == shared.NODE_SSL) and shared.haveSSL(not self.initiatedConnection)): + logger.debug("Initialising TLS") self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(shared.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(shared.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') if hasattr(self.sslSock, "context"): self.sslSock.context.set_ecdh_curve("secp256k1") @@ -270,7 +271,7 @@ class receiveDataThread(threading.Thread): except: break # Command the corresponding sendDataThread to set its own connectionIsOrWasFullyEstablished variable to True also - self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock, self.initiatedConnection))) + self.sendDataThreadQueue.put((0, 'connectionIsOrWasFullyEstablished', (self.services, self.sslSock))) if not self.initiatedConnection: shared.clientHasReceivedIncomingConnections = True diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index 99c51f61..f151f55b 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -45,6 +45,10 @@ class sendDataThread(threading.Thread): self.lastTimeISentData = int( time.time()) # If this value increases beyond five minutes ago, we'll send a pong message to keep the connection alive. self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware + if self.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)) @@ -175,7 +179,7 @@ class sendDataThread(threading.Thread): break elif command == 'connectionIsOrWasFullyEstablished': self.connectionIsOrWasFullyEstablished = True - self.services, self.sslSock, self.initiatedConnection = data + self.services, self.sslSock = data else: logger.error('sendDataThread ID: ' + str(id(self)) + ' ignoring command ' + command + ' because the thread is not in stream' + str(deststream)) -- 2.45.1 From bbdfb1ea54d1b1366c069a14885ddd6f74246ba2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 23:13:26 +0100 Subject: [PATCH 0174/1102] UPnP cleaner shutdown --- src/upnp.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/upnp.py b/src/upnp.py index c4c40b44..eebf68cf 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -106,6 +106,7 @@ class Router: self.localAddress = s.getsockname()[0] logger.debug("Local IP: %s", self.localAddress) try: + s.shutdown(socket.SHUT.RDWR) s.close() except: pass @@ -203,6 +204,7 @@ class uPnPThread(threading.Thread, StoppableThread): for router in self.routers: if router.extPort is None: self.createPortMapping(router) + self.sock.shutdown(socket.SHUT.RDWR) self.sock.close() for router in self.routers: if router.extPort is not None: -- 2.45.1 From e82e33fa5126d05796b4c17093c3dfa8e71c61a4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 22 Nov 2015 23:41:03 +0100 Subject: [PATCH 0175/1102] UPnP notifications UPnP will notify you through window status bar. --- src/upnp.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/upnp.py b/src/upnp.py index eebf68cf..c8181add 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -6,6 +6,7 @@ import threading import time from helper_threading import * import shared +import tr def createRequestXML(service, action, arguments=[]): from xml.dom.minidom import Document @@ -196,6 +197,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Found UPnP router at %s", ip) self.routers.append(newRouter) self.createPortMapping(newRouter) + shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping established'))) break except socket.timeout as e: pass @@ -206,10 +208,14 @@ class uPnPThread(threading.Thread, StoppableThread): self.createPortMapping(router) self.sock.shutdown(socket.SHUT.RDWR) self.sock.close() + deleted = False for router in self.routers: if router.extPort is not None: + deleted = True self.deletePortMapping(router) shared.extPort = None + if deleted: + shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping removed'))) logger.debug("UPnP thread done") def sendSearchRouter(self): -- 2.45.1 From ec68146135b18070cd2d8a035bfba8840244ff0e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 00:03:49 +0100 Subject: [PATCH 0176/1102] Suppress error on releasing unlocked lock --- src/class_outgoingSynSender.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index d011ae94..0f201747 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -76,7 +76,10 @@ class outgoingSynSender(threading.Thread, StoppableThread): time.time()) shared.alreadyAttemptedConnectionsListLock.acquire() shared.alreadyAttemptedConnectionsList[peer] = 0 - shared.alreadyAttemptedConnectionsListLock.release() + try: + shared.alreadyAttemptedConnectionsListLock.release() + except ThreadError as e: + pass self.name = "outgoingSynSender-" + peer.host if peer.host.find(':') == -1: address_family = socket.AF_INET -- 2.45.1 From ff358b1a1f05da4f314e48b7389c38ae6e28d5e3 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 00:05:49 +0100 Subject: [PATCH 0177/1102] Typo --- src/class_outgoingSynSender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 0f201747..9b7600cd 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -78,7 +78,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.alreadyAttemptedConnectionsList[peer] = 0 try: shared.alreadyAttemptedConnectionsListLock.release() - except ThreadError as e: + except threading.ThreadError as e: pass self.name = "outgoingSynSender-" + peer.host if peer.host.find(':') == -1: -- 2.45.1 From 410c23e8c0aac88291301db4c4d61dea8c001feb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 00:08:26 +0100 Subject: [PATCH 0178/1102] Typo --- src/upnp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upnp.py b/src/upnp.py index c8181add..cdc043a5 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -107,7 +107,7 @@ class Router: self.localAddress = s.getsockname()[0] logger.debug("Local IP: %s", self.localAddress) try: - s.shutdown(socket.SHUT.RDWR) + s.shutdown(socket.SHUT_RDWR) s.close() except: pass -- 2.45.1 From 36ddbd365efd2d7c6ffecd580232a81577c15b30 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 00:26:18 +0100 Subject: [PATCH 0179/1102] Typo --- src/upnp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upnp.py b/src/upnp.py index cdc043a5..fdff04a5 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -206,7 +206,7 @@ class uPnPThread(threading.Thread, StoppableThread): for router in self.routers: if router.extPort is None: self.createPortMapping(router) - self.sock.shutdown(socket.SHUT.RDWR) + self.sock.shutdown(socket.SHUT_RDWR) self.sock.close() deleted = False for router in self.routers: -- 2.45.1 From f77afe8faee8585b69021906e5e1bbd0a8f86e48 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 01:35:11 +0100 Subject: [PATCH 0180/1102] Exception handling --- src/upnp.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index fdff04a5..abfe9e65 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -206,8 +206,14 @@ class uPnPThread(threading.Thread, StoppableThread): for router in self.routers: if router.extPort is None: self.createPortMapping(router) - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() + 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: -- 2.45.1 From 7b4264a1099988437a3b4e8fb80f3e0f78ec230c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 06:58:25 +0100 Subject: [PATCH 0181/1102] Typo --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 72a48516..e64fb29b 100644 --- a/src/shared.py +++ b/src/shared.py @@ -171,7 +171,7 @@ def assembleVersionMessage(remoteHost, remotePort, myStreamNumber, server = Fals 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. - if safeConfigGetBoolean('bitmessagesettings', 'upnp' and extPort): + if safeConfigGetBoolean('bitmessagesettings', 'upnp') and extPort: payload += pack('>H', extPort) else: payload += pack('>H', shared.config.getint('bitmessagesettings', 'port')) -- 2.45.1 From 6dbe20a25ca21cc6f6b29b5bf8d97ae9715eb23a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 23 Nov 2015 07:19:59 +0100 Subject: [PATCH 0182/1102] Version bump --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index e64fb29b..4c45daca 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.3' +softwareVersion = '0.5.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. -- 2.45.1 From d69c2e097f537b9f37bb0cdd60109ec6746d468e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 24 Nov 2015 01:55:17 +0100 Subject: [PATCH 0183/1102] Cleaner shutdown Addresses Bitmessage#549 --- src/api.py | 9 ++++++++- src/bitmessagemain.py | 23 +++++++++++++++++------ src/class_addressGenerator.py | 19 +++++++++++++++---- src/class_singleCleaner.py | 10 ++++++---- src/class_singleListener.py | 34 +++++++++++++++++++++++----------- src/class_singleWorker.py | 17 ++++++++++++++--- src/shared.py | 8 +++----- 7 files changed, 86 insertions(+), 34 deletions(-) diff --git a/src/api.py b/src/api.py index 20568ffc..7c355941 100644 --- a/src/api.py +++ b/src/api.py @@ -12,7 +12,7 @@ if __name__ == "__main__": import sys sys.exit(0) -from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler +from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer import json import shared @@ -43,6 +43,13 @@ class APIError(Exception): def __str__(self): return "API Error %04i: %s" % (self.error_number, self.error_message) + +class StoppableXMLRPCServer(SimpleXMLRPCServer): + def serve_forever(self): + while shared.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/ diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index c27cc137..aba251f9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -23,8 +23,7 @@ import sys from subprocess import call import time -from SimpleXMLRPCServer import SimpleXMLRPCServer -from api import MySimpleXMLRPCRequestHandler +from api import MySimpleXMLRPCRequestHandler, StoppableXMLRPCServer from helper_startup import isOurOperatingSystemLimitedToHavingVeryFewHalfOpenConnections import shared @@ -44,6 +43,7 @@ from debug import logger # Helper Functions import helper_bootstrap import helper_generic +from helper_threading import * # singleton lock instance thisapp = None @@ -119,13 +119,24 @@ def _fixWinsock(): socket.IPV6_V6ONLY = 27 # This thread, of which there is only one, runs the API. -class singleAPI(threading.Thread): - +class singleAPI(threading.Thread, StoppableThread): def __init__(self): - threading.Thread.__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((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + 'bitmessagesettings', 'apiport'))) + s.shutdown(socket.SHUT_RDWR) + s.close() + except: + pass def run(self): - se = SimpleXMLRPCServer((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( + se = StoppableXMLRPCServer((shared.config.get('bitmessagesettings', 'apiinterface'), shared.config.getint( 'bitmessagesettings', 'apiport')), MySimpleXMLRPCRequestHandler, True, True) se.register_introspection_functions() se.serve_forever() diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index af25b210..5d1598c4 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -8,17 +8,26 @@ import hashlib import highlevelcrypto from addresses import * from debug import logger +from helper_threading import * from pyelliptic import arithmetic import tr -class addressGenerator(threading.Thread): +class addressGenerator(threading.Thread, StoppableThread): def __init__(self): # QThread.__init__(self, parent) - threading.Thread.__init__(self) + threading.Thread.__init__(self, name="addressGenerator") + self.initStop() + + def stopThread(self): + try: + shared.addressGeneratorQueue.put(("stopThread", "data")) + except: + pass + super(addressGenerator, self).stopThread() def run(self): - while True: + while shared.shutdown == 0: queueValue = shared.addressGeneratorQueue.get() nonceTrialsPerByte = 0 payloadLengthExtraBytes = 0 @@ -54,6 +63,8 @@ class addressGenerator(threading.Thread): 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)) @@ -278,4 +289,4 @@ class addressGenerator(threading.Thread): else: raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) - + shared.apiAddressGeneratorQueue.task_done() diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index bccf4a62..f9e87b1a 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -7,6 +7,7 @@ import pickle import tr#anslate from helper_sql import * +from helper_threading import * from debug import logger """ @@ -28,10 +29,11 @@ resends msg messages in 5 days (then 10 days, then 20 days, etc...) """ -class singleCleaner(threading.Thread): +class singleCleaner(threading.Thread, StoppableThread): def __init__(self): threading.Thread.__init__(self, name="singleCleaner") + self.initStop() def run(self): timeWeLastClearedInventoryAndPubkeysTables = 0 @@ -41,7 +43,7 @@ class singleCleaner(threading.Thread): # Either the user hasn't set stopresendingafterxdays and stopresendingafterxmonths yet or the options are missing from the config file. shared.maximumLengthOfTimeToBotherResendingMessages = float('inf') - while True: + while shared.shutdown == 0: shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) with shared.inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. @@ -84,7 +86,7 @@ class singleCleaner(threading.Thread): for row in queryreturn: if len(row) < 2: logger.error('Something went wrong in the singleCleaner thread: a query did not return the requested fields. ' + repr(row)) - time.sleep(3) + self.stop.wait(3) break toAddress, ackData, status = row if status == 'awaitingpubkey': @@ -121,7 +123,7 @@ class singleCleaner(threading.Thread): os._exit(0) shared.knownNodesLock.release() shared.needToWriteKnownNodesToDisk = False - time.sleep(300) + self.stop.wait(300) def resendPubkeyRequest(address): diff --git a/src/class_singleListener.py b/src/class_singleListener.py index 77e6eee6..a571867a 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -4,6 +4,7 @@ import socket from class_sendDataThread import * from class_receiveDataThread import * import helper_bootstrap +from helper_threading import * import errno import re @@ -15,10 +16,11 @@ import re # (within the recversion function of the recieveData thread) -class singleListener(threading.Thread): +class singleListener(threading.Thread, StoppableThread): def __init__(self): threading.Thread.__init__(self, name="singleListener") + self.initStop() def setup(self, selfInitiatedConnections): self.selfInitiatedConnections = selfInitiatedConnections @@ -37,6 +39,16 @@ class singleListener(threading.Thread): 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) + try: + s.connect(('127.0.0.1', shared.config.getint('bitmessagesettings', 'port'))) + s.shutdown(socket.SHUT_RDWR) + s.close() + except: + pass def run(self): # If there is a trusted peer then we don't want to accept @@ -44,15 +56,15 @@ class singleListener(threading.Thread): if shared.trustedPeer: return - while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): - time.sleep(1) + while shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect') and shared.shutdown == 0: + self.stop.wait(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. - while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten'): - time.sleep(5) + while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and shared.shutdown == 0: + self.stop.wait(5) logger.info('Listening for incoming connections.') @@ -73,19 +85,19 @@ class singleListener(threading.Thread): # regexp to match an IPv4-mapped IPv6 address mappedAddressRegexp = re.compile(r'^::ffff:([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$') - while True: + while shared.shutdown == 0: # 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 shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten'): - time.sleep(10) - while len(shared.connectedHostsList) > 220: + while shared.config.get('bitmessagesettings', 'socksproxytype')[0:5] == 'SOCKS' and not shared.config.getboolean('bitmessagesettings', 'sockslisten') and shared.shutdown == 0: + self.stop.wait(10) + while len(shared.connectedHostsList) > 220 and shared.shutdown == 0: logger.info('We are connected to too many people. Not accepting further incoming connections for ten seconds.') - time.sleep(10) + self.stop.wait(10) - while True: + while shared.shutdown == 0: socketObject, sockaddr = sock.accept() (HOST, PORT) = sockaddr[0:2] diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index de8848b2..6a827ce2 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -15,17 +15,26 @@ from debug import logger from helper_sql import * import helper_inbox from helper_generic import addDataPadding +from helper_threading import * import l10n # This thread, of which there is only one, does the heavy lifting: # calculating POWs. -class singleWorker(threading.Thread): +class singleWorker(threading.Thread, StoppableThread): def __init__(self): # QThread.__init__(self, parent) threading.Thread.__init__(self, name="singleWorker") + self.initStop() + + def stopThread(self): + try: + shared.workerQueue.put(("stopThread", "data")) + except: + pass + super(singleWorker, self).stopThread() def run(self): @@ -52,7 +61,7 @@ class singleWorker(threading.Thread): logger.info('Watching for ackdata ' + ackdata.encode('hex')) shared.ackdataForWhichImWatching[ackdata] = 0 - time.sleep( + self.stop.wait( 10) # give some time for the GUI to start before we start on existing POW tasks. queryreturn = sqlQuery( @@ -68,7 +77,7 @@ class singleWorker(threading.Thread): # just in case there are any tasks for Broadcasts # that have yet to be sent. - while True: + while shared.shutdown == 0: command, data = shared.workerQueue.get() if command == 'sendmessage': self.sendMsg() @@ -80,6 +89,8 @@ class singleWorker(threading.Thread): self.sendOutOrStoreMyV3Pubkey(data) elif command == 'sendOutOrStoreMyV4Pubkey': self.sendOutOrStoreMyV4Pubkey(data) + elif command == 'stopThread': + return else: logger.error('Probable programming error: The command sent to the workerThread is weird. It is: %s\n' % command) diff --git a/src/shared.py b/src/shared.py index 4c45daca..c49d9457 100644 --- a/src/shared.py +++ b/src/shared.py @@ -414,12 +414,10 @@ def doCleanShutdown(): from class_outgoingSynSender import outgoingSynSender for thread in threading.enumerate(): - if thread.name == "uPnPThread" or "outgoingSynSender" in thread.name: - if thread.isAlive() and isinstance(thread, StoppableThread): - thread.stopThread() + if thread.isAlive() and isinstance(thread, StoppableThread): + thread.stopThread() for thread in threading.enumerate(): - if thread.name == "uPnPThread": - #or "outgoingSynSender" in thread.name: + if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): logger.debug("Waiting for thread %s", thread.name) thread.join() -- 2.45.1 From f9a7a5b6f2bd0d94c7588615ce6f8a67d5c42795 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 25 Nov 2015 00:18:31 +0100 Subject: [PATCH 0184/1102] Account in treeWidget more like a QT class It behaves more like a QT class is supposed to now, it's somewhat cleaner. Fixes #122 --- src/bitmessageqt/__init__.py | 13 +--- src/bitmessageqt/foldertree.py | 105 +++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 10abc82d..6d17089c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3921,14 +3921,10 @@ class MyForm(settingsmixin.SMainWindow): return newLabel = str(item.text(0)) - newLabel = newLabel.replace("(" + str(item.address) + ")", '') - newLabel = newLabel.rstrip() if item.type == "subscription": oldLabel = item.label else: oldLabel = shared.config.get(str(item.address), 'label') - oldLabel = oldLabel.replace("(" + str(item.address) + ")", '') - oldLabel = oldLabel.rstrip() # unchanged, do not do anything either if newLabel == oldLabel: return @@ -3938,14 +3934,7 @@ class MyForm(settingsmixin.SMainWindow): return self.recurDepth += 1 - if item.type == "subscription": - sqlExecute( - '''UPDATE subscriptions SET label=? WHERE address=?''', - newLabel, item.address) - item.setLabel(newLabel) - else: - shared.config.set(str(item.address), 'label', newLabel) - shared.writeKeysFile() + item.setData(0, QtCore.Qt.EditRole, newLabel) item.updateText() if item.type == 'mailinglist': self.rerenderComboBoxSendFromBroadcast() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 20291c5d..7243bbde 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -1,5 +1,6 @@ from PyQt4 import QtCore, QtGui +from helper_sql import * from utils import * import shared from settingsmixin import SettingsMixin @@ -130,6 +131,34 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): self.initialised = True self.setType() # does updateText + def data(self, column, role): + if column == 0: + if role == QtCore.Qt.DisplayRole: + if self.unreadCount > 0 and not self.isExpanded(): + return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + str(self.unreadCount) + ') (' + self.address + ')' + else: + return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' + elif role == QtCore.Qt.EditRole: + return unicode(shared.config.get(self.address, 'label'), 'utf-8') + elif role == QtCore.Qt.ToolTipRole: + return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' + elif role == QtCore.Qt.DecorationRole: + 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: + shared.config.set(str(self.address), 'label', str(value.toString())) + shared.writeKeysFile() + return + 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) @@ -137,34 +166,12 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def updateText(self): if not self.initialised: return - text = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' - - font = QtGui.QFont() - if self.unreadCount > 0: - # only show message count if the child doesn't show - if not self.isExpanded(): - text += " (" + str(self.unreadCount) + ")" - font.setBold(True) - else: - font.setBold(False) - self.setFont(0, font) - - #set text color - self.setForeground(0, self.accountBrush()) - - self.setIcon(0, avatarize(self.address)) - self.setText(0, text) - self.setToolTip(0, text) -# self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) + self.emitDataChanged() def setExpanded(self, expand): super(Ui_AddressWidget, self).setExpanded(expand) self.updateText() - def edit(self): - self.setText(0, shared.config.get(self.address, 'label')) - super(QtGui.QAbstractItemView, self).edit() - # label (or address) alphabetically, disabled at the end def __lt__(self, other): if (isinstance(other, Ui_AddressWidget)): @@ -210,32 +217,40 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setType(self): self.type = "subscription" - def edit(self): - self.setText(0, self.label) - super(QtGui.QAbstractItemView, self).edit() + def data(self, column, role): + if column == 0: + if role == QtCore.Qt.DisplayRole: + if self.unreadCount > 0 and not self.isExpanded(): + return unicode(self.label, 'utf-8)') + ' (' + str(self.unreadCount) + ') (' + self.address + ')' + else: + return unicode(self.label, 'utf-8)') + ' (' + self.address + ')' + elif role == QtCore.Qt.EditRole: + return unicode(self.label, 'utf-8') + elif role == QtCore.Qt.ToolTipRole: + return unicode(self.label, 'utf-8)') + ' (' + self.address + ')' + elif role == QtCore.Qt.DecorationRole: + 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_SubscriptionWidget, self).data(column, role) + + def setData(self, column, role, value): + if role == QtCore.Qt.EditRole: + self.setLabel(str(value.toString())) + sqlExecute( + '''UPDATE subscriptions SET label=? WHERE address=?''', + self.label, self.address) + return + return super(Ui_SubscriptionWidget, self).setData(column, role, value) def updateText(self): if not self.initialised: return - text = unicode(self.label, 'utf-8)') + ' (' + self.address + ')' - - font = QtGui.QFont() - if self.unreadCount > 0: - # only show message count if the child doesn't show - if not self.isExpanded(): - text += " (" + str(self.unreadCount) + ")" - font.setBold(True) - else: - font.setBold(False) - self.setFont(0, font) - - #set text color - self.setForeground(0, self.accountBrush()) - - self.setIcon(0, avatarize(self.address)) - self.setText(0, text) - self.setToolTip(0, text) -# self.setData(0, QtCore.Qt.UserRole, [self.address, "inbox"]) + self.emitDataChanged() # label (or address) alphabetically, disabled at the end def __lt__(self, other): -- 2.45.1 From aa97b531145b67d57f61793bc0ec16943fea22dc Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 25 Nov 2015 01:02:17 +0100 Subject: [PATCH 0185/1102] addressGenerator fixes - addressGenerator got stuck (introduced recently when cleaning up shutdown - do not put addresses into API return queue if API is inactive - improve translation --- src/class_addressGenerator.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index 5d1598c4..c48756e8 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -142,7 +142,8 @@ class addressGenerator(threading.Thread, StoppableThread): # The API and the join and create Chan functionality # both need information back from the address generator. - shared.apiAddressGeneratorReturnQueue.put(address) + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + shared.apiAddressGeneratorReturnQueue.put(address) shared.UISignalQueue.put(( 'updateStatusBar', tr.translateText("MainWindow", "Done generating address. Doing work necessary to broadcast it..."))) @@ -161,10 +162,8 @@ 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': - statusbar = 'Generating ' + str( - numberOfAddressesToMake) + ' new addresses.' shared.UISignalQueue.put(( - 'updateStatusBar', statusbar)) + 'updateStatusBar', tr.translateText("MainWindow","Generating %1 new addresses.").arg(str(numberOfAddressesToMake)))) signingKeyNonce = 0 encryptionKeyNonce = 1 listOfNewAddressesToSendOutThroughTheAPI = [ @@ -210,7 +209,8 @@ 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: - shared.apiAddressGeneratorReturnQueue.put('chan name does not match address') + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + shared.apiAddressGeneratorReturnQueue.put('chan name does not match address') saveAddressToDisk = False if command == 'getDeterministicAddress': saveAddressToDisk = False @@ -281,12 +281,13 @@ class addressGenerator(threading.Thread, StoppableThread): # Done generating addresses. - if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': - shared.apiAddressGeneratorReturnQueue.put( - listOfNewAddressesToSendOutThroughTheAPI) - elif command == 'getDeterministicAddress': - shared.apiAddressGeneratorReturnQueue.put(address) + if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): + if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': + shared.apiAddressGeneratorReturnQueue.put( + listOfNewAddressesToSendOutThroughTheAPI) + elif command == 'getDeterministicAddress': + shared.apiAddressGeneratorReturnQueue.put(address) else: raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) - shared.apiAddressGeneratorQueue.task_done() + shared.addressGeneratorQueue.task_done() -- 2.45.1 From d0b73eb211ff2a726ace90dd6f257c845b7884b2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:34:44 +0100 Subject: [PATCH 0186/1102] SMP fix for frozen Windows --- src/bitmessagemain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index aba251f9..b124e141 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -18,6 +18,7 @@ import singleton import os import socket import ctypes +from multiprocessing import Process, freeze_support from struct import pack import sys from subprocess import call @@ -265,6 +266,7 @@ class Main: return {'address':address,'port':port} if __name__ == "__main__": + freeze_support() mainprogram = Main() mainprogram.start() -- 2.45.1 From 0c19e0c2e481eeb0d167cd0e433d1ac38ecfd5e4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:35:59 +0100 Subject: [PATCH 0187/1102] Failure to connect shouln't be an error It resulted in too many errors in the logs --- src/class_outgoingSynSender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 9b7600cd..738882ef 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -213,7 +213,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): logger.error('Bitmessage MIGHT be having trouble connecting to the SOCKS server. ' + str(err)) else: if shared.verbose >= 1: - logger.error('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) + logger.debug('Could NOT connect to ' + str(peer) + 'during outgoing attempt. ' + str(err)) deletedPeer = None with shared.knownNodesLock: -- 2.45.1 From e7e245fe25d7f580c4aa1f48bc865428ee611ffa Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:37:07 +0100 Subject: [PATCH 0188/1102] OpenCL GUI settings --- src/bitmessageqt/__init__.py | 35 ++++++++++++++++++----------------- src/bitmessageqt/settings.py | 7 +++++++ 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6d17089c..4b9c5f33 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -56,23 +56,11 @@ import subprocess import datetime from helper_sql import * import l10n - -try: - from PyQt4 import QtCore, QtGui - from PyQt4.QtCore import * - from PyQt4.QtGui import * - from PyQt4.QtNetwork import QLocalSocket, QLocalServer - -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 - +import openclpow +import types +from utils import * +from collections import OrderedDict +from account import * def _translate(context, text): return QtGui.QApplication.translate(context, text) @@ -2643,6 +2631,9 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) + if openclpow.has_opencl() and self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked != shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): + shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked)) + acceptableDifficultyChanged = False if float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) >= 1 or float(self.settingsDialogInstance.ui.lineEditMaxAcceptableTotalDifficulty.text()) == 0: @@ -4170,6 +4161,16 @@ class settingsDialog(QtGui.QDialog): self.ui.lineEditMaxAcceptableSmallMessageDifficulty.setText(str((float(shared.config.getint( 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes')) / shared.networkDefaultPayloadLengthExtraBytes))) + # OpenCL + if openclpow.has_opencl(): + self.ui.checkBoxOpenCL.setEnabled(True) + else: + self.ui.checkBoxOpenCL.setEnabled(False) + if shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): + self.ui.checkBoxOpenCL.setChecked(True) + else: + self.ui.checkBoxOpenCL.setChecked(False) + # Namecoin integration tab nmctype = shared.config.get('bitmessagesettings', 'namecoinrpctype') self.ui.lineEditNamecoinHost.setText(str( diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index 4a1dfc7c..efdfc1b7 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -308,6 +308,12 @@ 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.checkBoxOpenCL = QtGui.QCheckBox(self.tabMaxAcceptableDifficulty) + self.checkBoxOpenCL.setObjectName = (_fromUtf8("checkBoxOpenCL")) + self.gridLayout_7.addWidget(self.checkBoxOpenCL, 4, 1, 1, 1) self.tabWidgetSettings.addTab(self.tabMaxAcceptableDifficulty, _fromUtf8("")) self.tabNamecoin = QtGui.QWidget() self.tabNamecoin.setObjectName(_fromUtf8("tabNamecoin")) @@ -481,6 +487,7 @@ 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)) -- 2.45.1 From 9335f74c61369d73062e04280125d2ee7077eebf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:37:52 +0100 Subject: [PATCH 0189/1102] OpenCL kernel change This makes it work on my AMD. --- src/bitmsghash/bitmsghash.cl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bitmsghash/bitmsghash.cl b/src/bitmsghash/bitmsghash.cl index 1ab5d219..3c8c21a5 100644 --- a/src/bitmsghash/bitmsghash.cl +++ b/src/bitmsghash/bitmsghash.cl @@ -24,9 +24,8 @@ /// 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) as_ulong(as_uchar8(n).s76543210) -/* #define SWAP64(n) \ (((n) << 56) \ | (((n) & 0xff00) << 40) \ @@ -36,7 +35,6 @@ | (((n) >> 24) & 0xff0000) \ | (((n) >> 40) & 0xff00) \ | ((n) >> 56)) -*/ -- 2.45.1 From 399100e6d8008d524f9c81034c5c5fc8aef9cd74 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 02:38:55 +0100 Subject: [PATCH 0190/1102] PoW support code cleanup Is now nicer and reports if OpenCL fails --- src/class_singleWorker.py | 10 ++++++-- src/openclpow.py | 53 ++++++++++++++++++++++++++------------- src/proofofwork.py | 52 ++++++++++++++++++++++++-------------- 3 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 6a827ce2..6de8703c 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -21,6 +21,12 @@ import l10n # 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): @@ -787,7 +793,7 @@ class singleWorker(threading.Thread, StoppableThread): 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 ' + str(int(time.time() - powStartTime)) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) except: pass @@ -966,7 +972,7 @@ class singleWorker(threading.Thread, StoppableThread): 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 ' + str(time.time() - powStartTime) + ' seconds. ' + str(nonce / (time.time() - powStartTime)) + ' nonce trials per second.') + logger.info('PoW took %.1f seconds, speed %s.', time.time() - powStartTime, sizeof_fmt(nonce / (time.time() - powStartTime))) except: pass diff --git a/src/openclpow.py b/src/openclpow.py index a2cfb068..426913a4 100644 --- a/src/openclpow.py +++ b/src/openclpow.py @@ -5,35 +5,49 @@ import hashlib import random import os +from shared import codePath, safeConfigGetBoolean +from debug import logger + +libAvailable = True ctx = False queue = False program = False +gpus = [] +hash_dt = None try: import numpy import pyopencl as cl - hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) - gpus = [] - for platform in cl.get_platforms(): - gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) - if (len(gpus) > 0): - ctx = cl.Context(devices=gpus) - queue = cl.CommandQueue(ctx) - full_path = os.path.dirname(os.path.realpath(__file__)) - f = open(os.path.join(full_path, "bitmsghash", 'bitmsghash.cl'), 'r') - fstr = ''.join(f.readlines()) - program = cl.Program(ctx, fstr).build(options="") - else: - print "No OpenCL GPUs found" +except: + libAvailable = False + +def initCL(): + global ctx, queue, program, gpus, hash_dt + try: + hash_dt = numpy.dtype([('target', numpy.uint64), ('v', numpy.str_, 73)]) + for platform in cl.get_platforms(): + gpus.extend(platform.get_devices(device_type=cl.device_type.GPU)) + if (len(gpus) > 0): + ctx = cl.Context(devices=gpus) + queue = cl.CommandQueue(ctx) + f = open(os.path.join(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") + ctx = False + except Exception as e: + logger.error("OpenCL fail: ", exc_info=True) ctx = False -except Exception as e: - print "opencl fail: " + str(e) - ctx = False def has_opencl(): + global ctx return (ctx != False) def do_opencl_pow(hash, target): + global ctx, queue, program, gpus, hash_dt + output = numpy.zeros(1, dtype=[('v', numpy.uint64, 1)]) if (ctx == False): return output[0][0] @@ -62,11 +76,14 @@ def do_opencl_pow(hash, target): queue.finish() progress += globamt sofar = time.time() - start - print sofar, progress / sofar, "hashes/sec" +# logger.debug("Working for %.3fs, %.2f Mh/s", sofar, (progress / sofar) / 1000000) taken = time.time() - start - print progress, taken +# logger.debug("Took %d tries.", progress) return output[0][0] +if libAvailable: + initCL() + if __name__ == "__main__": target = 54227212183L initialHash = "3758f55b5a8d902fd3597e4ce6a2d3f23daff735f65d9698c270987f4e67ad590b93f3ffeba0ef2fd08a8dc2f87b68ae5a0dc819ab57f22ad2c4c9c8618a43b3".decode("hex") diff --git a/src/proofofwork.py b/src/proofofwork.py index fc779467..8ab04820 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -4,9 +4,10 @@ import hashlib from struct import unpack, pack import sys -from shared import config, frozen, codePath -import shared +from debug import logger +from shared import config, frozen, codePath, shutdown, safeConfigGetBoolean, UISignalQueue import openclpow +import tr import os import ctypes @@ -17,12 +18,20 @@ if "win32" == sys.platform: else: bitmsglib = 'bitmsghash64.dll' try: + # MSVS bso = ctypes.WinDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) except: - bso = None + try: + # MinGW + bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) + except: + bso = None else: try: bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL %s", bitmsglib) except: bso = None if bso: @@ -58,16 +67,17 @@ def _pool_worker(nonce, initialHash, target, pool_size): return [trialValue, nonce] def _doSafePoW(target, initialHash): - print "Safe POW\n" + logger.debug("Safe PoW start") nonce = 0 trialValue = float('inf') while trialValue > target: nonce += 1 trialValue, = unpack('>Q',hashlib.sha512(hashlib.sha512(pack('>Q',nonce) + initialHash).digest()).digest()[0:8]) + logger.debug("Safe PoW done") return [trialValue, nonce] def _doFastPoW(target, initialHash): - print "Fast POW\n" + logger.debug("Fast PoW start") import time from multiprocessing import Pool, cpu_count try: @@ -85,7 +95,7 @@ def _doFastPoW(target, initialHash): for i in range(pool_size): result.append(pool.apply_async(_pool_worker, args = (i, initialHash, target, pool_size))) while True: - if shared.shutdown >= 1: + if 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 @@ -95,30 +105,38 @@ def _doFastPoW(target, initialHash): result = result[i].get() pool.terminate() pool.join() #Wait for the workers to exit... + logger.debug("Fast PoW done") 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) - print "C PoW start" + 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]) - print "C PoW done" + logger.debug("C PoW done") return [trialValue, nonce] def _doGPUPoW(target, initialHash): - print "GPU PoW start" + 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) - print "GPU PoW done" + if trialValue > target: + deviceNames = ", ".join(gpu.name for gpu in openclpow.gpus) + UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'Your GPU(s) did not calculate correctly, disabling OpenCL. Please report to the developers.'))) + logger.error("Your GPUs (%s) did not calculate correctly, disabling OpenCL. Please report to the developers.", deviceNames) + openclpow.ctx = False + raise Exception("GPU did not calculate correctly.") + logger.debug("GPU PoW done") return [trialValue, nonce] def run(target, initialHash): target = int(target) - if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): + if safeConfigGetBoolean('bitmessagesettings', 'opencl') and openclpow.has_opencl(): # trialvalue1, nonce1 = _doGPUPoW(target, initialHash) # trialvalue, nonce = _doFastPoW(target, initialHash) # print "GPU: %s, %s" % (trialvalue1, nonce1) @@ -133,12 +151,8 @@ def run(target, initialHash): return _doCPoW(target, initialHash) except: pass # fallback - if frozen == "macosx_app" or not frozen: - # on my (Peter Surda) Windows 10, Windows Defender - # does not like this and fights with PyBitmessage - # over CPU, resulting in very slow PoW - try: - return _doFastPoW(target, initialHash) - except: - pass #fallback + try: + return _doFastPoW(target, initialHash) + except: + pass #fallback return _doSafePoW(target, initialHash) -- 2.45.1 From 1e89616c0fc641a2d47f39fec5c05b1ab31b7f33 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 19:41:20 +0100 Subject: [PATCH 0191/1102] Avoid strings in account types --- src/bitmessageqt/__init__.py | 40 +++++----- src/bitmessageqt/foldertree.py | 138 ++++++++++++++------------------- 2 files changed, 79 insertions(+), 99 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4b9c5f33..0e62be5d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -886,7 +886,7 @@ class MyForm(settingsmixin.SMainWindow): def updateUnreadCount(item): # if refreshing the account root, we need to rescan folders if type == 0 or (folder is None and isinstance(item, Ui_FolderWidget)): - if addressItem.type == 'subscription' or addressItem.type == 'mailinglist': + if addressItem.type in [AccountMixin.SUBSCRIPTION, AccountMixin.MAILINGLIST]: xAddress = "fromaddress" else: xAddress = "toaddress" @@ -2058,20 +2058,20 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('SELECT label, address FROM subscriptions WHERE enabled = 1') for row in queryreturn: label, address = row - addRow(address, label, 'subscription') + addRow(address, label, AccountMixin.SUBSCRIPTION) # chans addresses = getSortedAccounts() for address in addresses: account = accountClass(address) - if (account.type == 'chan' and shared.safeConfigGetBoolean(address, 'enabled')): - addRow(address, account.getLabel(), 'chan') + if (account.type == AccountMixin.CHAN and shared.safeConfigGetBoolean(address, 'enabled')): + addRow(address, account.getLabel(), AccountMixin.CHAN) # normal accounts queryreturn = sqlQuery('SELECT * FROM addressbook') for row in queryreturn: label, address = row - addRow(address, label, 'normal') + addRow(address, label, AccountMixin.NORMAL) # sort self.ui.tableWidgetAddressBook.sortItems(0, QtCore.Qt.AscendingOrder) @@ -2846,7 +2846,7 @@ class MyForm(settingsmixin.SMainWindow): addressAtCurrentRow = self.getCurrentAccount() acct = accountClass(addressAtCurrentRow) # no chans / mailinglists - if acct.type != 'normal': + if acct.type != AccountMixin.NORMAL: return if self.dialog.ui.radioButtonUnregister.isChecked() and isinstance(acct, GatewayAccount): acct.unregister() @@ -3370,7 +3370,7 @@ class MyForm(settingsmixin.SMainWindow): currentRow = row.row() type = str(self.ui.tableWidgetAddressBook.item( currentRow, 0).data(Qt.UserRole).toPyObject()) - if type != "normal": + if type != AccountMixin.NORMAL: normal = False if normal: # only if all selected addressbook items are normal, allow delete @@ -3527,9 +3527,9 @@ class MyForm(settingsmixin.SMainWindow): def getAccountTreeWidget(self, account): try: - if account.type == 'chan': + if account.type == AccountMixin.CHAN: return self.ui.treeWidgetChans - elif account.type == 'subscription': + elif account.type == AccountMixin.SUBSCRIPTION: return self.ui.treeWidgetSubscriptions else: return self.ui.treeWidgetYourIdentities @@ -3551,9 +3551,9 @@ class MyForm(settingsmixin.SMainWindow): def getAccountMessagelist(self, account): try: - if account.type == 'chan': + if account.type == AccountMixin.CHAN: return self.ui.tableWidgetInboxChans - elif account.type == 'subscription': + elif account.type == AccountMixin.SUBSCRIPTION: return self.ui.tableWidgetInboxSubscriptions else: return self.ui.tableWidgetInbox @@ -3585,9 +3585,9 @@ class MyForm(settingsmixin.SMainWindow): def getAccountTextedit(self, account): try: - if account.type == 'chan': + if account.type == AccountMixin.CHAN: return self.ui.textEditInboxMessageChans - elif account.type == 'subscription': + elif account.type == AccountMixin.SUBSCRIPTION: return self.ui.textEditInboxSubscriptions else: return self.ui.textEditInboxMessage @@ -3664,9 +3664,9 @@ class MyForm(settingsmixin.SMainWindow): def on_action_YourIdentitiesDelete(self): account = self.getCurrentItem() - if account.type == "normal": + if account.type == AccountMixin.NORMAL: return # maybe in the future - elif account.type == "chan": + 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?"), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: shared.config.remove_section(str(account.address)) else: @@ -3676,9 +3676,9 @@ class MyForm(settingsmixin.SMainWindow): shared.writeKeysFile() shared.reloadMyAddressHashes() self.rerenderAddressBook() - if account.type == "normal": + if account.type == AccountMixin.NORMAL: self.rerenderTabTreeMessages() - elif account.type == "chan": + elif account.type == AccountMixin.CHAN: self.rerenderTabTreeChans() def on_action_Enable(self): @@ -3912,7 +3912,7 @@ class MyForm(settingsmixin.SMainWindow): return newLabel = str(item.text(0)) - if item.type == "subscription": + if item.type == AccountMixin.SUBSCRIPTION: oldLabel = item.label else: oldLabel = shared.config.get(str(item.address), 'label') @@ -3927,9 +3927,9 @@ class MyForm(settingsmixin.SMainWindow): self.recurDepth += 1 item.setData(0, QtCore.Qt.EditRole, newLabel) item.updateText() - if item.type == 'mailinglist': + if item.type == AccountMixin.MAILINGLIST: self.rerenderComboBoxSendFromBroadcast() - elif item.type != "subscription": + elif item.type != AccountMixin.SUBSCRIPTION: self.rerenderComboBoxSendFrom() self.recurDepth -= 1 diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 7243bbde..9b01b9c3 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -6,12 +6,18 @@ import shared from settingsmixin import SettingsMixin class AccountMixin (object): + ALL = 0 + NORMAL = 1 + CHAN = 2 + MAILINGLIST = 3 + SUBSCRIPTION = 4 + def accountColor (self): if not self.isEnabled: return QtGui.QColor(128, 128, 128) - elif self.type == "chan": + elif self.type == self.CHAN: return QtGui.QColor(216, 119, 0) - elif self.type == "mailinglist" or self.type == "subscription": + elif self.type in [self.MAILINGLIST, self.SUBSCRIPTION]: return QtGui.QColor(137, 04, 177) else: return QtGui.QApplication.palette().text().color() @@ -51,12 +57,14 @@ class AccountMixin (object): self.updateText() def setType(self): - if shared.safeConfigGetBoolean(self.address, 'chan'): - self.type = "chan" + if self.address is None: + self.type = self.ALL + elif shared.safeConfigGetBoolean(self.address, 'chan'): + self.type = self.CHAN elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): - self.type = "mailinglist" + self.type = self.MAILINGLIST else: - self.type = "normal" + self.type = self.NORMAL def updateText(self): pass @@ -119,7 +127,7 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): - def __init__(self, parent, pos = 0, address = "", unreadCount = 0, enabled = True): + 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 @@ -131,19 +139,39 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): self.initialised = True self.setType() # does updateText + def _getLabel(self): + if self.address is None: + label = QtGui.QApplication.translate("MainWindow", "All accounts") + else: + try: + return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + except: + return self.address + + 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 unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + str(self.unreadCount) + ') (' + self.address + ')' + return self._getLabel() + self._getAddressBracket(True) else: - return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' + return self._getLabel() + self._getAddressBracket(False) elif role == QtCore.Qt.EditRole: - return unicode(shared.config.get(self.address, 'label'), 'utf-8') + return self._getLabel() elif role == QtCore.Qt.ToolTipRole: - return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + ' (' + self.address + ')' + return self._getLabel() + self._getAddressBracket(False) elif role == QtCore.Qt.DecorationRole: - return avatarize(self.address) + if self.address is None: + return avatarize(self._getLabel()) + else: + return avatarize(self.address) elif role == QtCore.Qt.FontRole: font = QtGui.QFont() font.setBold(self.unreadCount > 0) @@ -171,6 +199,12 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def setExpanded(self, expand): super(Ui_AddressWidget, self).setExpanded(expand) self.updateText() + + def _getSortRank(self): + ret = self.type + if not self.isEnabled: + ret += 5 + return ret # label (or address) alphabetically, disabled at the end def __lt__(self, other): @@ -178,21 +212,11 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): reverse = False if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True - if self.isEnabled == other.isEnabled: - if self.type == other.type: - if shared.config.get(self.address, 'label'): - x = shared.config.get(self.address, 'label').decode('utf-8').lower() - else: - x = self.address.decode('utf-8').lower() - if shared.config.get(other.address, 'label'): - y = shared.config.get(other.address, 'label').decode('utf-8').lower() - else: - y = other.address.decode('utf-8').lower() - return x < y - else: - return (reverse if self.type == "mailinglist" else not reverse) -# else: - return (not reverse if self.isEnabled else reverse) + if self._getSortRank() == other._getSortRank(): + x = self._getLabel().decode('utf-8').lower() + y = other._getLabel().decode('utf-8').lower() + return x < y + return (not reverse if self._getSortRank() < other._getSortRank() else reverse) return super(QtGui.QTreeWidgetItem, self).__lt__(other) @@ -213,30 +237,12 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setLabel(self, label): self.label = label + + def _getLabel(self): + return unicode(self.label, 'utf-8)') def setType(self): - self.type = "subscription" - - def data(self, column, role): - if column == 0: - if role == QtCore.Qt.DisplayRole: - if self.unreadCount > 0 and not self.isExpanded(): - return unicode(self.label, 'utf-8)') + ' (' + str(self.unreadCount) + ') (' + self.address + ')' - else: - return unicode(self.label, 'utf-8)') + ' (' + self.address + ')' - elif role == QtCore.Qt.EditRole: - return unicode(self.label, 'utf-8') - elif role == QtCore.Qt.ToolTipRole: - return unicode(self.label, 'utf-8)') + ' (' + self.address + ')' - elif role == QtCore.Qt.DecorationRole: - 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_SubscriptionWidget, self).data(column, role) + self.type = self.SUBSCRIPTION def setData(self, column, role, value): if role == QtCore.Qt.EditRole: @@ -251,39 +257,13 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): if not self.initialised: return self.emitDataChanged() - - # label (or address) alphabetically, disabled at the end - def __lt__(self, other): - if (isinstance(other, Ui_SubscriptionWidget)): - reverse = False - if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: - reverse = True - if self.isEnabled == other.isEnabled: - if self.label: - x = self.label.decode('utf-8').lower() - else: - x = self.address.decode('utf-8').lower() - if other.label: - y = other.label.decode('utf-8').lower() - else: - y = other.address.decode('utf-8').lower() - return x < y -# else: - return (not reverse if self.isEnabled else reverse) - - return super(QtGui.QTreeWidgetItem, self).__lt__(other) + class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): - _types = {'normal': 0, 'chan': 1, 'subscription': 2} - - def __init__ (self, text, type = 'normal'): + def __init__ (self, text, type = AccountMixin.NORMAL): super(QtGui.QTableWidgetItem, self).__init__(text) self.label = text self.type = type - try: - self.typeNum = self._types[self.type] - except: - self.type = 0 self.setEnabled(True) self.setForeground(self.accountBrush()) @@ -292,10 +272,10 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): reverse = False if self.tableWidget().horizontalHeader().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True - if self.typeNum == other.typeNum: + if self.type == other.type: return self.label.decode('utf-8').lower() < other.label.decode('utf-8').lower() else: - return (not reverse if self.typeNum < other.typeNum else reverse) + return (not reverse if self.type < other.type else reverse) return super(QtGui.QTableWidgetItem, self).__lt__(other) -- 2.45.1 From d75533c6b60bae05ae3e828222d9147b0129b026 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 26 Nov 2015 23:45:44 +0100 Subject: [PATCH 0192/1102] DNS bootstrap over Tor If proxy type is SOCKS5, it will try to perform DNS bootstrap using the Tor RESOLVE extension. --- src/helper_bootstrap.py | 60 +++++++++++++++++++++++++++++++---------- src/socks/__init__.py | 50 ++++++++++++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 16 deletions(-) diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index ae1adacb..d0de8622 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -5,6 +5,7 @@ import pickle import time from debug import logger +import socks def knownNodes(): try: @@ -37,20 +38,51 @@ def dns(): # 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. - with shared.printLock: - if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': + if shared.config.get('bitmessagesettings', 'socksproxytype') == 'none': + try: + for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): + logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') + shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) + except: + logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') + try: + for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): + logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') + shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) + except: + logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') + elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + 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 = shared.config.get( + 'bitmessagesettings', 'sockshostname') + 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 shared.config.getboolean('bitmessagesettings', 'socksauthentication'): + socksusername = shared.config.get( + 'bitmessagesettings', 'socksusername') + sockspassword = shared.config.get( + 'bitmessagesettings', 'sockspassword') + sock.setproxy( + proxytype, sockshostname, socksport, rdns, socksusername, sockspassword) + else: + sock.setproxy( + proxytype, sockshostname, socksport, rdns) try: - for item in socket.getaddrinfo('bootstrap8080.bitmessage.org', 80): - logger.info('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][shared.Peer(item[4][0], 8080)] = int(time.time()) + ip = sock.resolve("bootstrap" + str(port) + ".bitmessage.org") + sock.shutdown(socket.SHUT_RDWR) + sock.close() except: - logger.error('bootstrap8080.bitmessage.org DNS bootstrapping failed.') - try: - for item in socket.getaddrinfo('bootstrap8444.bitmessage.org', 80): - logger.info ('Adding ' + item[4][0] + ' to knownNodes based on DNS bootstrap method') - shared.knownNodes[1][shared.Peer(item[4][0], 8444)] = int(time.time()) - except: - logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') - else: - logger.info('DNS bootstrap skipped because SOCKS is used.') + logger.error("SOCKS DNS resolving failed", exc_info=True) + if ip is not None: + logger.info ('Adding ' + ip + ' to knownNodes based on SOCKS DNS bootstrap method') + shared.knownNodes[1][shared.Peer(ip, port)] = time.time() + else: + logger.info('DNS bootstrap skipped because the proxy type does not support DNS resolution.') diff --git a/src/socks/__init__.py b/src/socks/__init__.py index ebb68f45..d5d59687 100644 --- a/src/socks/__init__.py +++ b/src/socks/__init__.py @@ -155,7 +155,7 @@ class socksocket(socket.socket): """ self.__proxy = (proxytype, addr, port, rdns, username, password) - def __negotiatesocks5(self, destaddr, destport): + def __negotiatesocks5(self): """__negotiatesocks5(self,destaddr,destport) Negotiates a connection through a SOCKS5 server. """ @@ -200,6 +200,8 @@ 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 @@ -247,6 +249,37 @@ 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. @@ -361,7 +394,8 @@ class socksocket(socket.socket): else: portnum = 1080 _orgsocket.connect(self, (self.__proxy[1], portnum)) - self.__negotiatesocks5(destpair[0], destpair[1]) + self.__negotiatesocks5() + self.__connectsocks5(destpair[0], destpair[1]) elif self.__proxy[0] == PROXY_TYPE_SOCKS4: if self.__proxy[2] != None: portnum = self.__proxy[2] @@ -380,3 +414,15 @@ class socksocket(socket.socket): _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 \ No newline at end of file -- 2.45.1 From 6ad3c956c9f1f90c1d8f028bdc797aaf9e54c599 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 00:37:44 +0100 Subject: [PATCH 0193/1102] Allow SQL arguments as a list or tuple --- src/helper_sql.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helper_sql.py b/src/helper_sql.py index 0353f9ae..c50db192 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -11,6 +11,8 @@ def sqlQuery(sqlStatement, *args): if args == (): sqlSubmitQueue.put('') + elif type(args[0]) in [list, tuple]: + sqlSubmitQueue.put(args[0]) else: sqlSubmitQueue.put(args) -- 2.45.1 From 6862952c559d126c972ad0d87baa9ff16860fbe3 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 00:44:14 +0100 Subject: [PATCH 0194/1102] Typo OpenCL config variable setter had a typo --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0e62be5d..658da6ed 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2631,8 +2631,8 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(int(float( self.settingsDialogInstance.ui.lineEditSmallMessageDifficulty.text()) * shared.networkDefaultPayloadLengthExtraBytes))) - if openclpow.has_opencl() and self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked != shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): - shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked)) + if openclpow.has_opencl() and self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked() != shared.safeConfigGetBoolean("bitmessagesettings", "opencl"): + shared.config.set('bitmessagesettings', 'opencl', str(self.settingsDialogInstance.ui.checkBoxOpenCL.isChecked())) acceptableDifficultyChanged = False -- 2.45.1 From be02116af9b9c84421aaa3125f5756856e1c8056 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 00:56:25 +0100 Subject: [PATCH 0195/1102] Global folder, global search, unread folder Fixes #38 Fixes #39 Minor unread refresh issues. --- src/bitmessageqt/__init__.py | 124 ++++++++++++++++++++------------- src/bitmessageqt/foldertree.py | 15 ++-- 2 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 658da6ed..81d9457f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -377,7 +377,8 @@ class MyForm(settingsmixin.SMainWindow): def rerenderTabTreeSubscriptions(self): treeWidget = self.ui.treeWidgetSubscriptions - folders = ['inbox', 'sent', 'trash'] + folders = Ui_FolderWidget.folderWeight.keys() + folders.remove("new") # sort ascending when creating if treeWidget.topLevelItemCount() == 0: @@ -463,8 +464,8 @@ class MyForm(settingsmixin.SMainWindow): treeWidget = self.ui.treeWidgetYourIdentities elif tab == 'chan': treeWidget = self.ui.treeWidgetChans - folders = ['inbox', 'sent', 'trash'] - + folders = Ui_FolderWidget.folderWeight.keys() + # sort ascending when creating if treeWidget.topLevelItemCount() == 0: treeWidget.header().setSortIndicator(0, Qt.AscendingOrder) @@ -494,11 +495,18 @@ class MyForm(settingsmixin.SMainWindow): 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 tab == "messages": + db[None] = {} + db[None]["inbox"] = total + db[None]["new"] = total + enabled[None] = True if treeWidget.isSortingEnabled(): treeWidget.setSortingEnabled(False) @@ -546,6 +554,10 @@ class MyForm(settingsmixin.SMainWindow): j = 0 unread = 0 for folder in folders: + if toAddress is not None and folder == "new": + continue + if toAddress is None and folder in ["trash", "sent"]: + continue subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]) unread += db[toAddress][folder] j += 1 @@ -914,22 +926,25 @@ class MyForm(settingsmixin.SMainWindow): if isinstance(item, Ui_AddressWidget): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) - if widget == None: + if widget == None or self.getCurrentAccount() == None: widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] else: widgets = [widget] + # FIXME this is a hack + if folder == "new": + folder = "inbox" for treeWidget in widgets: root = treeWidget.invisibleRootItem() for i in range(root.childCount()): addressItem = root.child(i) - if address is not None and addressItem.data(0, QtCore.Qt.UserRole) != address: + if addressItem.type != AccountMixin.ALL and address is not None and addressItem.data(0, QtCore.Qt.UserRole) != address: continue updateUnreadCount(addressItem) if addressItem.childCount == 0: continue for j in range(addressItem.childCount()): folderItem = addressItem.child(j) - if folder is not None and folderItem.folderName != folder: + if folder is not None and folderItem.folderName != folder and addressItem.type != AccountMixin.ALL: continue updateUnreadCount(folderItem) @@ -1052,46 +1067,56 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.keyPressEvent = self.tableWidgetSentKeyPressEvent # Load messages from database file - def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what=""): + def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what="", unreadOnly = False): if folder == 'sent': self.loadSent(tableWidget, account, where, what) return - what = "%" + what + "%" - if where == _translate("MainWindow", "To"): - where = "toaddress" - elif where == _translate("MainWindow", "From"): - where = "fromaddress" - elif where == _translate("MainWindow", "Subject"): - where = "subject" - elif where == _translate("MainWindow", "Message"): - where = "message" + if what != "": + what = "%" + what + "%" + if where == _translate("MainWindow", "To"): + where = "toaddress" + elif where == _translate("MainWindow", "From"): + where = "fromaddress" + elif where == _translate("MainWindow", "Subject"): + where = "subject" + elif where == _translate("MainWindow", "Message"): + where = "message" + else: + where = "toaddress || fromaddress || subject || message" else: - where = "toaddress || fromaddress || subject || message" + what = None if tableWidget == self.ui.tableWidgetInboxSubscriptions: xAddress = "fromaddress" else: xAddress = "toaddress" + sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read + FROM inbox ''' + sqlStatementParts = [] + sqlArguments = [] + if account is not None: + sqlStatementParts.append(xAddress + " = ? ") + sqlArguments.append(account) if folder is not None: - sqlStatement = ''' - SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE ''' + xAddress + '''=? AND folder=? AND %s LIKE ? - ORDER BY received - ''' % (where) - queryreturn = sqlQuery(sqlStatement, account, folder, what) - else: - sqlStatement = ''' - SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox WHERE ''' + xAddress + '''=? AND folder != "trash" AND %s LIKE ? - ORDER BY received - ''' % (where) - queryreturn = sqlQuery(sqlStatement, account, what) + sqlStatementParts.append("folder = ? ") + sqlArguments.append(folder) + 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) + queryreturn = sqlQuery(sqlStatementBase, sqlArguments) tableWidget.setRowCount(0) - - tableWidget.setColumnHidden(0, True) - tableWidget.setColumnHidden(1, False) + if account is not None: + tableWidget.setColumnHidden(0, True) + tableWidget.setColumnHidden(1, False) + else: + tableWidget.setColumnHidden(0, False) + tableWidget.setColumnHidden(1, False) tableWidget.setSortingEnabled(False) font = QFont() @@ -1911,7 +1936,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) treeWidget = self.widgetConvert(inbox) - self.propagateUnreadCount(self.getCurrentAccount(treeWidget), self.getCurrentFolder(treeWidget), treeWidget, 0) + self.propagateUnreadCount(str(inbox.item(i, 1 if inbox == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder(treeWidget), treeWidget, 0) inbox.removeRow(i) break @@ -2420,7 +2445,7 @@ class MyForm(settingsmixin.SMainWindow): self.propagateUnreadCount(acct.address) if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) - if (self.getCurrentFolder(treeWidget) != "inbox" and self.getCurrentFolder(treeWidget) is not None) or self.getCurrentAccount(treeWidget) != acct.address: + 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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) return @@ -3007,9 +3032,9 @@ class MyForm(settingsmixin.SMainWindow): "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) if modified == 1: # performance optimisation - self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder()) + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder()) else: - self.propagateUnreadCount(self.getCurrentAccount(), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) # tableWidget.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. @@ -3170,7 +3195,10 @@ class MyForm(settingsmixin.SMainWindow): else: sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): - unread = True + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) + if folder != "trash" and not shifted: + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "trash", self.getCurrentTreeWidget(), 1) + self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3179,8 +3207,6 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.selectRow(currentRow) else: tableWidget.selectRow(currentRow - 1) - if unread: - self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_TrashUndelete(self): tableWidget = self.getCurrentMessagelist() @@ -3194,7 +3220,8 @@ class MyForm(settingsmixin.SMainWindow): currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): - unread = True + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "inbox", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "trash", self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3203,8 +3230,6 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.selectRow(currentRow) else: tableWidget.selectRow(currentRow - 1) - if unread: - self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_InboxSaveMessageAs(self): tableWidget = self.getCurrentMessagelist() @@ -3255,7 +3280,7 @@ class MyForm(settingsmixin.SMainWindow): else: sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) if tableWidget.item(currentRow, 0).font().bold(): - unread = True + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setPlainText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3264,8 +3289,6 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tableWidgetInbox.selectRow(currentRow) else: self.ui.tableWidgetInbox.selectRow(currentRow - 1) - if unread: - self.propagateUnreadCount(self.getCurrentAccount(), None, self.getCurrentTreeWidget(), 0) def on_action_ForceSend(self): currentRow = self.ui.tableWidgetInbox.currentRow() @@ -3630,7 +3653,7 @@ class MyForm(settingsmixin.SMainWindow): return currentItem return False - def getCurrentAccount(self, treeWidget = None): + def getCurrentAccount(self, treeWidget = None, force = None): currentItem = self.getCurrentItem(treeWidget) if currentItem: account = currentItem.address @@ -3895,7 +3918,10 @@ class MyForm(settingsmixin.SMainWindow): if messagelist: account = self.getCurrentAccount() folder = self.getCurrentFolder() - self.loadMessagelist(messagelist, account, folder) + if folder == "new": + self.loadMessagelist(messagelist, account, None, unreadOnly = True) + else: + self.loadMessagelist(messagelist, account, folder) def treeWidgetItemChanged(self, item, column): # only for manual edits. automatic edits (setText) are ignored @@ -3977,7 +4003,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 1).setTextColor(AccountColor(str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject())).accountColor()) tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) - self.propagateUnreadCount(self.getCurrentAccount(), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) else: data = self.getCurrentMessageId() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 9b01b9c3..03477218 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -39,7 +39,10 @@ class AccountMixin (object): return brush def setAddress(self, address): - self.address = str(address) + if address is None: + self.address = None + else: + self.address = str(address) self.updateText() def setUnreadCount(self, cnt): @@ -71,7 +74,7 @@ class AccountMixin (object): class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): - folderWeight = {"inbox": 1, "sent": 2, "trash": 3} + 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.initialised = False @@ -110,11 +113,11 @@ class Ui_FolderWidget(QtGui.QTreeWidgetItem, AccountMixin): if self.folderName in self.folderWeight: x = self.folderWeight[self.folderName] else: - x = 4 + x = 99 if other.folderName in self.folderWeight: y = self.folderWeight[other.folderName] else: - y = 4 + y = 99 reverse = False if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True @@ -141,12 +144,12 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def _getLabel(self): if self.address is None: - label = QtGui.QApplication.translate("MainWindow", "All accounts") + return unicode(str(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') else: try: return unicode(shared.config.get(self.address, 'label'), 'utf-8)') except: - return self.address + return unicode(self.address, 'utf-8') def _getAddressBracket(self, unreadCount = False): ret = "" -- 2.45.1 From a3b13b70e2ec27c266b33b0b9c202e0f30095daf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 02:10:27 +0100 Subject: [PATCH 0196/1102] Add BROADCAST type also improve sorting --- src/bitmessageqt/account.py | 24 +++++++++++++----------- src/bitmessageqt/foldertree.py | 3 ++- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 83ce76c9..f881cc8c 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -42,11 +42,11 @@ def accountClass(address): if not shared.config.has_section(address): if address == str_broadcast_subscribers: subscription = BroadcastAccount(address) - if subscription.type != 'broadcast': + if subscription.type != AccountMixin.BROADCAST: return None else: subscription = SubscriptionAccount(address) - if subscription.type != 'subscription': + if subscription.type != AccountMixin.SUBSCRIPTION: return None return subscription try: @@ -67,15 +67,17 @@ class AccountColor(AccountMixin): self.isEnabled = True self.address = address if type is None: - if shared.safeConfigGetBoolean(self.address, 'mailinglist'): - self.type = "mailinglist" + if address is None: + self.type = AccountMixin.ALL + elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): + self.type = AccountMixin.MAILINGLIST elif shared.safeConfigGetBoolean(self.address, 'chan'): - self.type = "chan" + self.type = AccountMixin.CHAN elif sqlQuery( '''select label from subscriptions where address=?''', self.address): - self.type = 'subscription' + self.type = AccountMixin.SUBSCRIPTION else: - self.type = "normal" + self.type = AccountMixin.NORMAL else: self.type = type @@ -86,16 +88,16 @@ class BMAccount(object): self.type = 'normal' if shared.config.has_section(address): if shared.safeConfigGetBoolean(self.address, 'chan'): - self.type = "chan" + self.type = AccountMixin.CHAN elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): - self.type = "mailinglist" + self.type = AccountMixin.MAILINGLIST elif self.address == str_broadcast_subscribers: - self.type = 'broadcast' + self.type = AccountMixin.BROADCAST else: queryreturn = sqlQuery( '''select label from subscriptions where address=?''', self.address) if queryreturn: - self.type = 'subscription' + self.type = AccountMixin.SUBSCRIPTION def getLabel(self, address = None): if address is None: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 03477218..971cda61 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -11,6 +11,7 @@ class AccountMixin (object): CHAN = 2 MAILINGLIST = 3 SUBSCRIPTION = 4 + BROADCAST = 5 def accountColor (self): if not self.isEnabled: @@ -206,7 +207,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def _getSortRank(self): ret = self.type if not self.isEnabled: - ret += 5 + ret += 100 return ret # label (or address) alphabetically, disabled at the end -- 2.45.1 From 27c187283b53549af2b86c42cd57806b0469c5db Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 02:11:24 +0100 Subject: [PATCH 0197/1102] Unify messagelist rendering also some minor fixes --- src/bitmessageqt/__init__.py | 362 +++++++++++++++-------------------- 1 file changed, 159 insertions(+), 203 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 81d9457f..324bd137 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -926,10 +926,7 @@ class MyForm(settingsmixin.SMainWindow): if isinstance(item, Ui_AddressWidget): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) - if widget == None or self.getCurrentAccount() == None: - widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] - else: - widgets = [widget] + widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] # FIXME this is a hack if folder == "new": folder = "inbox" @@ -948,6 +945,146 @@ class MyForm(settingsmixin.SMainWindow): continue updateUnreadCount(folderItem) + def addMessageListItem(self, tableWidget, items): + tableWidget.insertRow(0) + for i in range(len(items)): + tableWidget.setItem(0, i, items[i]) + + def addMessageListItemSent(self, tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime): + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + acct = accountClass(fromAddress) + acct.parseMessage(toAddress, fromAddress, subject, "") + + items = [] + toAddressItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") + toAddressItem.setIcon(avatarize(toAddress)) + toAddressItem.setData(Qt.UserRole, str(toAddress)) + toAddressItem.setTextColor(AccountColor(toAddress).accountColor()) + toAddressItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + items.append(toAddressItem) + + fromAddressItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") + fromAddressItem.setIcon(avatarize(fromAddress)) + fromAddressItem.setData(Qt.UserRole, str(fromAddress)) + fromAddressItem.setTextColor(AccountColor(fromAddress).accountColor()) + fromAddressItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + items.append(fromAddressItem) + + subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) + subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) + subjectItem.setData(Qt.UserRole, str(subject)) + subjectItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + items.append(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) + items.append(newItem) + self.addMessageListItem(tableWidget, items) + return acct + + def addMessageListItemInbox(self, tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read): + font = QFont() + font.setBold(True) + if tableWidget == self.ui.tableWidgetInboxSubscriptions: + acct = accountClass(fromAddress) + else: + acct = accountClass(toAddress) + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + acct.parseMessage(toAddress, fromAddress, subject, "") + + items = [] + #to + to_item = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) + to_item.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") + to_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + to_item.setFont(font) + to_item.setData(Qt.UserRole, str(toAddress)) + to_item.setTextColor(AccountColor(toAddress).accountColor()) + to_item.setIcon(avatarize(toAddress)) + items.append(to_item) + # from + from_item = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) + from_item.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(fromAddress) + ")") + from_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + from_item.setFont(font) + from_item.setData(Qt.UserRole, str(fromAddress)) + from_item.setTextColor(AccountColor(fromAddress).accountColor()) + from_item.setIcon(avatarize(fromAddress)) + items.append(from_item) + # subject + subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) + subject_item.setToolTip(unicode(acct.subject, 'utf-8')) + subject_item.setData(Qt.UserRole, str(subject)) + subject_item.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + if not read: + subject_item.setFont(font) + items.append(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) + items.append(time_item) + self.addMessageListItem(tableWidget, items) + return acct + # Load Sent items from database def loadSent(self, tableWidget, account, where="", what=""): what = "%" + what + "%" @@ -984,83 +1121,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery(sqlStatement, account, what) for row in queryreturn: toAddress, fromAddress, subject, status, ackdata, lastactiontime = row - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - if acct is None: - acct = accountClass(fromAddress) - acct.parseMessage(toAddress, fromAddress, subject, "") - - tableWidget.insertRow(0) - toAddressItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - toAddressItem.setIcon(avatarize(toAddress)) - toAddressItem.setData(Qt.UserRole, str(toAddress)) - toAddressItem.setTextColor(AccountColor(toAddress).accountColor()) - toAddressItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - tableWidget.setItem(0, 0, toAddressItem) - - fromAddressItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") - fromAddressItem.setIcon(avatarize(fromAddress)) - fromAddressItem.setData(Qt.UserRole, str(fromAddress)) - fromAddressItem.setTextColor(AccountColor(fromAddress).accountColor()) - fromAddressItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - tableWidget.setItem(0, 1, fromAddressItem) - - subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) - subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) - subjectItem.setData(Qt.UserRole, str(subject)) - subjectItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - tableWidget.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) - tableWidget.setItem(0, 3, newItem) + self.addMessageListItemSent(tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime) tableWidget.setSortingEnabled(False) tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) @@ -1119,62 +1180,9 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setColumnHidden(1, False) tableWidget.setSortingEnabled(False) - font = QFont() - font.setBold(True) - acct = None for row in queryreturn: msgfolder, msgid, toAddress, fromAddress, subject, received, read = row - if acct is None: - if tableWidget == self.ui.tableWidgetInboxSubscriptions: - acct = accountClass(fromAddress) - else: - acct = accountClass(toAddress) - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - acct.parseMessage(toAddress, fromAddress, subject, "") - - # message row - tableWidget.insertRow(0) - # to - to_item = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - to_item.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - to_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - to_item.setFont(font) - to_item.setData(Qt.UserRole, str(toAddress)) - to_item.setTextColor(AccountColor(toAddress).accountColor()) - to_item.setIcon(avatarize(toAddress)) - tableWidget.setItem(0, 0, to_item) - # from - from_item = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - from_item.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(fromAddress) + ")") - from_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - from_item.setFont(font) - from_item.setData(Qt.UserRole, str(fromAddress)) - from_item.setTextColor(AccountColor(fromAddress).accountColor()) - from_item.setIcon(avatarize(fromAddress)) - tableWidget.setItem(0, 1, from_item) - # subject - subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) - subject_item.setToolTip(unicode(acct.subject, 'utf-8')) - subject_item.setData(Qt.UserRole, str(subject)) - subject_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - subject_item.setFont(font) - tableWidget.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) - tableWidget.setItem(0, 3, time_item) + self.addMessageListItemInbox(tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read) tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) tableWidget.setSortingEnabled(True) @@ -2403,45 +2411,28 @@ class MyForm(settingsmixin.SMainWindow): continue elif treeWidget in [self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] and self.getCurrentAccount(treeWidget) != toAddress: continue - - sent.setSortingEnabled(False) - sent.insertRow(0) - newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - newItem.setData(Qt.UserRole, str(toAddress)) - newItem.setIcon(avatarize(toAddress)) - sent.setItem(0, 0, newItem) - newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") - newItem.setData(Qt.UserRole, str(fromAddress)) - newItem.setIcon(avatarize(fromAddress)) - sent.setItem(0, 1, newItem) - newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) - newItem.setToolTip(unicode(acct.subject, 'utf-8)')) - newItem.setData(Qt.UserRole, str(subject)) - - #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. - sent.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())) - sent.setItem(0, 3, newItem) + + self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)')) - sent.setSortingEnabled(True) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): - subject = shared.fixPotentiallyInvalidUTF8Data(subject) if toAddress == str_broadcast_subscribers: acct = accountClass(fromAddress) else: acct = accountClass(toAddress) - acct.parseMessage(toAddress, fromAddress, subject, message) inbox = self.getAccountMessagelist(acct) - treeWidget = self.getAccountTreeWidget(acct) + ret = None + for treeWidget in [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans]: + tableWidget = self.widgetConvert(treeWidget) + if tableWidget == inbox and self.getCurrentAccount(treeWidget) == acct.address and self.getCurrentFolder(treeWidget) == "inbox": + ret = self.addMessageListItemInbox(inbox, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) + elif treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) is None: + ret = self.addMessageListItemInbox(tableWidget, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) + if ret is None: + subject = shared.fixPotentiallyInvalidUTF8Data(subject) + acct.parseMessage(toAddress, fromAddress, subject, "") + else: + acct = ret self.propagateUnreadCount(acct.address) if shared.config.getboolean('bitmessagesettings', 'showtraynotifications'): self.notifierShow(unicode(_translate("MainWindow",'New Message').toUtf8(),'utf-8'), unicode(_translate("MainWindow",'From ').toUtf8(),'utf-8') + unicode(acct.fromLabel, 'utf-8'), self.SOUND_UNKNOWN, None) @@ -2450,41 +2441,6 @@ class MyForm(settingsmixin.SMainWindow): self.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) return - font = QFont() - font.setBold(True) - inbox.setSortingEnabled(False) - newItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - newItem.setFont(font) - newItem.setData(Qt.UserRole, str(toAddress)) - newItem.setTextColor(AccountColor(toAddress).accountColor()) - inbox.insertRow(0) - newItem.setIcon(avatarize(toAddress)) - inbox.setItem(0, 0, newItem) - - newItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - newItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") - newItem.setData(Qt.UserRole, str(fromAddress)) - newItem.setFont(font) - newItem.setTextColor(AccountColor(fromAddress).accountColor()) - newItem.setIcon(avatarize(fromAddress)) - inbox.setItem(0, 1, newItem) - newItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8)')) - newItem.setToolTip(unicode(acct.subject, 'utf-8)')) - newItem.setData(Qt.UserRole, str(subject)) - - #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) - inbox.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) - inbox.setItem(0, 3, newItem) - inbox.setSortingEnabled(True) - self.ubuntuMessagingMenuUpdate(True, newItem, acct.toLabel) - def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) if self.AddAddressDialogInstance.exec_(): @@ -3530,7 +3486,7 @@ class MyForm(settingsmixin.SMainWindow): return self.ui.tableWidgetInbox elif widget == self.ui.treeWidgetSubscriptions: return self.ui.tableWidgetInboxSubscriptions - elif twidget == self.ui.treeWidgetChans: + elif widget == self.ui.treeWidgetChans: return self.ui.tableWidgetInboxChans else: return None @@ -3653,7 +3609,7 @@ class MyForm(settingsmixin.SMainWindow): return currentItem return False - def getCurrentAccount(self, treeWidget = None, force = None): + def getCurrentAccount(self, treeWidget = None): currentItem = self.getCurrentItem(treeWidget) if currentItem: account = currentItem.address -- 2.45.1 From 52fe7105a93ac27758265693ef3fa1c71e3e0158 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 12:13:10 +0100 Subject: [PATCH 0198/1102] Allow bootstrap from a Tor hidden service I run a modified node as a Tor hidden service for bootstrapping node addresses, and PyBitmessage can now connect to it. --- src/helper_bootstrap.py | 2 ++ src/shared.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/helper_bootstrap.py b/src/helper_bootstrap.py index d0de8622..fbb1a81b 100644 --- a/src/helper_bootstrap.py +++ b/src/helper_bootstrap.py @@ -52,6 +52,8 @@ def dns(): except: logger.error('bootstrap8444.bitmessage.org DNS bootstrapping failed.') elif shared.config.get('bitmessagesettings', 'socksproxytype') == 'SOCKS5': + shared.knownNodes[1][shared.Peer('quzwelsuziwqgpt2.onion', 8444)] = int(time.time()) + 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 diff --git a/src/shared.py b/src/shared.py index c49d9457..e6774f45 100644 --- a/src/shared.py +++ b/src/shared.py @@ -143,7 +143,9 @@ def isInSqlInventory(hash): return queryreturn != [] def encodeHost(host): - if host.find(':') == -1: + if host.find('.onion') > -1: + return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x7F\x00\x00\x01' + elif host.find(':') == -1: return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF' + \ socket.inet_aton(host) else: -- 2.45.1 From d54b22bb8995f1c43c7632a8e58dc9b6f528ab5c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 14:45:52 +0100 Subject: [PATCH 0199/1102] Initialise inventorySets earlier In corner cases, they may be referenced before they are populated. Probably fixes Bitmessage#530 --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index e6774f45..8dca00cb 100644 --- a/src/shared.py +++ b/src/shared.py @@ -84,7 +84,7 @@ 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. +inventorySets = {1: set()} # 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 objectProcessorQueue = Queue.Queue( -- 2.45.1 From bccc2406a25bf6c9e80a4043a361762593b44d3b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 27 Nov 2015 16:53:05 +0100 Subject: [PATCH 0200/1102] Fix double unread count in tray icon --- src/bitmessageqt/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 324bd137..aa583e99 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -915,15 +915,15 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") for row in queryreturn: item.setUnreadCount(int(row[0])) - if isinstance(item, Ui_AddressWidget): + if isinstance(item, Ui_AddressWidget) and item.type == AccountMixin.ALL: self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount()) elif type == 1: item.setUnreadCount(item.unreadCount + 1) - if isinstance(item, Ui_AddressWidget): + if isinstance(item, Ui_AddressWidget) and item.type == AccountMixin.ALL: self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount + 1)) elif type == -1: item.setUnreadCount(item.unreadCount - 1) - if isinstance(item, Ui_AddressWidget): + if isinstance(item, Ui_AddressWidget) and item.type == AccountMixin.ALL: self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] -- 2.45.1 From 1625306be3e6e73353070056803971c277a079a7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 29 Nov 2015 18:22:40 +0100 Subject: [PATCH 0201/1102] Version bump --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 8dca00cb..edc5d575 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.4' +softwareVersion = '0.5.5' 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. -- 2.45.1 From 549d91dc6827b805c98ceb7544f9bf61516b2fc9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 29 Nov 2015 19:14:26 +0100 Subject: [PATCH 0202/1102] Re-disable windows SMP frozen support The recommended workaround didn't work. --- src/bitmessagemain.py | 2 -- src/proofofwork.py | 9 +++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index b124e141..aba251f9 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -18,7 +18,6 @@ import singleton import os import socket import ctypes -from multiprocessing import Process, freeze_support from struct import pack import sys from subprocess import call @@ -266,7 +265,6 @@ class Main: return {'address':address,'port':port} if __name__ == "__main__": - freeze_support() mainprogram = Main() mainprogram.start() diff --git a/src/proofofwork.py b/src/proofofwork.py index 8ab04820..8441bdeb 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -151,6 +151,15 @@ def run(target, initialHash): return _doCPoW(target, initialHash) except: pass # fallback + if frozen == "macosx_app" or not 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: + pass #fallback try: return _doFastPoW(target, initialHash) except: -- 2.45.1 From 41ac1b89d1198d528e01c51aed8e7aad2af59604 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 29 Nov 2015 19:16:44 +0100 Subject: [PATCH 0203/1102] Frozen SMP re-disable try 2 --- src/proofofwork.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 8441bdeb..69744053 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -160,8 +160,4 @@ def run(target, initialHash): return _doFastPoW(target, initialHash) except: pass #fallback - try: - return _doFastPoW(target, initialHash) - except: - pass #fallback return _doSafePoW(target, initialHash) -- 2.45.1 From a5456f792ca1b68bb8b9cb394b22393967df34fe Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 1 Dec 2015 01:09:28 +0100 Subject: [PATCH 0204/1102] Fix Addressbook context menu delete --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index aa583e99..ee67484b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3347,8 +3347,8 @@ class MyForm(settingsmixin.SMainWindow): normal = True for row in self.ui.tableWidgetAddressBook.selectedIndexes(): currentRow = row.row() - type = str(self.ui.tableWidgetAddressBook.item( - currentRow, 0).data(Qt.UserRole).toPyObject()) + type = self.ui.tableWidgetAddressBook.item( + currentRow, 0).type if type != AccountMixin.NORMAL: normal = False if normal: -- 2.45.1 From 27b8891ab4de574a41e95ae4882daca2a019d3be Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 1 Dec 2015 01:30:38 +0100 Subject: [PATCH 0205/1102] Test commit policy commit --- src/proofofwork.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 69744053..841c7791 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -160,4 +160,4 @@ def run(target, initialHash): return _doFastPoW(target, initialHash) except: pass #fallback - return _doSafePoW(target, initialHash) + return _doSafePoW(target, initialHash) \ No newline at end of file -- 2.45.1 From d72e5647f437c0298f1907a660fb1e3ca60609b3 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 2 Dec 2015 11:12:37 +0100 Subject: [PATCH 0206/1102] Fix wrong account type initialiser Addresses #14 --- src/bitmessageqt/account.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index f881cc8c..dc21d669 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -85,7 +85,7 @@ class AccountColor(AccountMixin): class BMAccount(object): def __init__(self, address = None): self.address = address - self.type = 'normal' + self.type = AccountMixin.NORMAL if shared.config.has_section(address): if shared.safeConfigGetBoolean(self.address, 'chan'): self.type = AccountMixin.CHAN -- 2.45.1 From 082eb823bbecf286131d9d2e945e34436f8ab581 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 2 Dec 2015 22:36:19 +0100 Subject: [PATCH 0207/1102] New message appears if viewing account root Fixes #132 --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ee67484b..112f2181 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2424,7 +2424,7 @@ class MyForm(settingsmixin.SMainWindow): ret = None for treeWidget in [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans]: tableWidget = self.widgetConvert(treeWidget) - if tableWidget == inbox and self.getCurrentAccount(treeWidget) == acct.address and self.getCurrentFolder(treeWidget) == "inbox": + 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: ret = self.addMessageListItemInbox(tableWidget, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) -- 2.45.1 From bdfaa90ecb4183baf3ebd4d5cd9c3e1bf57a4722 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 2 Dec 2015 23:12:38 +0100 Subject: [PATCH 0208/1102] Auto-register for email gateway if necessary If attempting to send to an email address from an unregistered account, auto-send registration to mailchuck. Use label if possible, otherwise random 12 characater address Fixes #131 --- src/bitmessageqt/__init__.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 112f2181..68c2ccd5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -52,7 +52,9 @@ import pickle import platform import textwrap import debug +import random import subprocess +import string import datetime from helper_sql import * import l10n @@ -2185,12 +2187,24 @@ class MyForm(settingsmixin.SMainWindow): 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 != '': - if toAddress.find("@") >= 0 and isinstance(acct, GatewayAccount): - acct.createMessage(toAddress, fromAddress, subject, message) - subject = acct.subject - toAddress = acct.toAddress - logger.debug("Subject: %s" % (subject)) - logger.debug("address: %s" % (toAddress)) + if toAddress.find("@") >= 0: + if isinstance(acct, GatewayAccount): + acct.createMessage(toAddress, fromAddress, subject, message) + subject = acct.subject + toAddress = acct.toAddress + else: + 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) + shared.config.set(fromAddress, 'label', email) + shared.config.set(fromAddress, 'gateway', 'mailchuck') + shared.writeKeysFile() + self.statusBar().showMessage(_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': -- 2.45.1 From 538642f23653a6ae147b02079eda3bb696d2cb41 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 3 Dec 2015 23:14:17 +0100 Subject: [PATCH 0209/1102] Label for blacklisting sender fix It wasn't properly utf-8-ied. --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 68c2ccd5..194ba8b1 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3136,7 +3136,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - label = "\"" + str(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject()) + "\" in " + shared.config.get(self.getCurrentAccount(), "label") + label = "\"" + unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toString(), 'utf-8') + "\" in " + shared.config.get(self.getCurrentAccount(), "label") sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', label, addressAtCurrentInboxRow, True) -- 2.45.1 From 4f6fd07424bda0c31a9b7b2090f506f7bb572358 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 5 Dec 2015 11:18:51 +0100 Subject: [PATCH 0210/1102] Joining chans interface freeze Fixes #137 --- src/class_addressGenerator.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index c48756e8..b84be8e3 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -142,8 +142,7 @@ class addressGenerator(threading.Thread, StoppableThread): # The API and the join and create Chan functionality # both need information back from the address generator. - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): - shared.apiAddressGeneratorReturnQueue.put(address) + shared.apiAddressGeneratorReturnQueue.put(address) shared.UISignalQueue.put(( 'updateStatusBar', tr.translateText("MainWindow", "Done generating address. Doing work necessary to broadcast it..."))) @@ -209,8 +208,7 @@ 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: - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): - shared.apiAddressGeneratorReturnQueue.put('chan name does not match address') + shared.apiAddressGeneratorReturnQueue.put('chan name does not match address') saveAddressToDisk = False if command == 'getDeterministicAddress': saveAddressToDisk = False @@ -281,12 +279,11 @@ class addressGenerator(threading.Thread, StoppableThread): # Done generating addresses. - if shared.safeConfigGetBoolean('bitmessagesettings', 'apienabled'): - if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': - shared.apiAddressGeneratorReturnQueue.put( - listOfNewAddressesToSendOutThroughTheAPI) - elif command == 'getDeterministicAddress': - shared.apiAddressGeneratorReturnQueue.put(address) + if command == 'createDeterministicAddresses' or command == 'joinChan' or command == 'createChan': + shared.apiAddressGeneratorReturnQueue.put( + listOfNewAddressesToSendOutThroughTheAPI) + elif command == 'getDeterministicAddress': + shared.apiAddressGeneratorReturnQueue.put(address) else: raise Exception( "Error in the addressGenerator thread. Thread was given a command it could not understand: " + command) -- 2.45.1 From 5a45d7dd8f008dd91dc9648f1ece90bac4534af2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 13 Dec 2015 21:36:25 +0100 Subject: [PATCH 0211/1102] Portable mode fixes Fixes Bitmessage#379, Bitmessage#341 --- src/bitmessageqt/__init__.py | 14 +++++++------- src/class_sqlThread.py | 8 ++++---- src/helper_startup.py | 4 ++-- src/shared.py | 9 +++++++++ 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 194ba8b1..e0a594d6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2708,18 +2708,18 @@ class MyForm(settingsmixin.SMainWindow): 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('keys.dat', 'wb') as configfile: + with open(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: shared.config.write(configfile) # Write the knownnodes.dat file to disk in the new location shared.knownNodesLock.acquire() - output = open('knownnodes.dat', 'wb') + output = open(shared.lookupExeFolder() + '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 = '' + shared.appdata = shared.lookupExeFolder() debug.restartLoggingInUpdatedAppdataLocation() try: os.remove(previousAppdataLocation + 'debug.log') @@ -2740,12 +2740,12 @@ class MyForm(settingsmixin.SMainWindow): pickle.dump(shared.knownNodes, output) output.close() shared.knownNodesLock.release() - os.remove('keys.dat') - os.remove('knownnodes.dat') + os.remove(shared.lookupExeFolder() + 'keys.dat') + os.remove(shared.lookupExeFolder() + 'knownnodes.dat') debug.restartLoggingInUpdatedAppdataLocation() try: - os.remove('debug.log') - os.remove('debug.log.1') + os.remove(shared.lookupExeFolder() + 'debug.log') + os.remove(shared.lookupExeFolder() + 'debug.log.1') except: pass diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 63621c89..682cffee 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -501,8 +501,8 @@ class sqlThread(threading.Thread): return self.conn.close() shutil.move( - shared.lookupAppdataFolder() + 'messages.dat', 'messages.dat') - self.conn = sqlite3.connect('messages.dat') + shared.lookupAppdataFolder() + 'messages.dat', shared.lookupExeFolder() + 'messages.dat') + self.conn = sqlite3.connect(shared.lookupExeFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'movemessagstoappdata': @@ -520,8 +520,8 @@ class sqlThread(threading.Thread): return self.conn.close() shutil.move( - 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') - self.conn = sqlite3.connect(shared.appdata + 'messages.dat') + shared.lookupExeFolder() + 'messages.dat', shared.lookupAppdataFolder() + 'messages.dat') + self.conn = sqlite3.connect(shared.lookupAppdataFolder() + 'messages.dat') self.conn.text_factory = str self.cur = self.conn.cursor() elif item == 'deleteandvacuume': diff --git a/src/helper_startup.py b/src/helper_startup.py index 0d4e0cb0..11671481 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -35,12 +35,12 @@ def loadConfig(): needToCreateKeysFile = True else: - shared.config.read('keys.dat') + shared.config.read(shared.lookupExeFolder() + 'keys.dat')) try: shared.config.get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' needToCreateKeysFile = False - shared.appdata = '' + shared.appdata = shared.lookupExeFolder() except: # Could not load the keys.dat file in the program directory. Perhaps it # is in the appdata directory. diff --git a/src/shared.py b/src/shared.py index edc5d575..77b81322 100644 --- a/src/shared.py +++ b/src/shared.py @@ -198,6 +198,15 @@ def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): payload += errorText return CreatePacket('error', payload) +def lookupExeFolder(): + if frozen: + exeFolder = os.path.join(os.path.dirname(sys.executable), '/') + elif __file__: + exeFolder = os.path.join(os.path.dirname(__file__), '/') + else: + exeFolder = '' + return exeFolder + def lookupAppdataFolder(): APPNAME = "PyBitmessage" if "BITMESSAGE_HOME" in environ: -- 2.45.1 From 8136b022bc9a35c3f16d40b225f650250d243816 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 13 Dec 2015 22:18:31 +0100 Subject: [PATCH 0212/1102] Typos Still regarding portable mode path fixes --- src/helper_startup.py | 2 +- src/shared.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helper_startup.py b/src/helper_startup.py index 11671481..a194a574 100644 --- a/src/helper_startup.py +++ b/src/helper_startup.py @@ -35,7 +35,7 @@ def loadConfig(): needToCreateKeysFile = True else: - shared.config.read(shared.lookupExeFolder() + 'keys.dat')) + shared.config.read(shared.lookupExeFolder() + 'keys.dat') try: shared.config.get('bitmessagesettings', 'settingsversion') print 'Loading config files from same directory as program.' diff --git a/src/shared.py b/src/shared.py index 77b81322..944cb659 100644 --- a/src/shared.py +++ b/src/shared.py @@ -200,9 +200,9 @@ def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): def lookupExeFolder(): if frozen: - exeFolder = os.path.join(os.path.dirname(sys.executable), '/') - elif __file__: - exeFolder = os.path.join(os.path.dirname(__file__), '/') + exeFolder = path.dirname(sys.executable) + path.sep + elif __file__: + exeFolder = path.dirname(__file__) + path.sep else: exeFolder = '' return exeFolder -- 2.45.1 From 242c8fa9c208ddda8b99270536e2e30c1bbf413c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 13 Dec 2015 22:23:40 +0100 Subject: [PATCH 0213/1102] More portable mode fixes --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e0a594d6..13d4fa86 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4090,7 +4090,7 @@ class settingsDialog(QtGui.QDialog): curr_index = languages.index('other') self.ui.languageComboBox.setCurrentIndex(curr_index) - if shared.appdata == '': + if shared.appdata == shared.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) if 'darwin' in sys.platform: self.ui.checkBoxStartOnLogon.setDisabled(True) -- 2.45.1 From e2fb34e2fb90556c568e877c090e87e467577087 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 13 Dec 2015 22:32:01 +0100 Subject: [PATCH 0214/1102] More portable mode fixes --- src/bitmessageqt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 13d4fa86..af54b0e9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2705,7 +2705,7 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux pass - if shared.appdata != '' and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked(): # If we are NOT using portable mode now but the user selected that we should... + if shared.appdata != shared.lookupExeFolder() 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(shared.lookupExeFolder() + 'keys.dat', 'wb') as configfile: @@ -2727,7 +2727,7 @@ class MyForm(settingsmixin.SMainWindow): except: pass - 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... + if shared.appdata == shared.lookupExeFolder() 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) -- 2.45.1 From 4e32125ca317353797b8a15773ad14cfb45bd097 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 14 Dec 2015 12:21:00 +0100 Subject: [PATCH 0215/1102] Copy to clipboard in messagelists Fixes #142 --- src/bitmessageqt/__init__.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index af54b0e9..65c236cd 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3702,6 +3702,31 @@ class MyForm(settingsmixin.SMainWindow): address = self.getCurrentAccount() 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 = str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject()) + otherAddress = str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject()) + else: + myAddress = str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject()) + otherAddress = str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject()) + 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).text()) + else: + text = str(tableWidget.item(currentRow, currentColumn).data(Qt.UserRole).toPyObject()) + clipboard = QtGui.QApplication.clipboard() + clipboard.setText(str(text)) #set avatar functions def on_action_TreeWidgetSetAvatar(self): @@ -3839,6 +3864,12 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuInbox.addSeparator() 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() -- 2.45.1 From 8ff5bf046494690ab518255b936cea9f3b6741f4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 14 Dec 2015 13:07:17 +0100 Subject: [PATCH 0216/1102] Channel reply enhancement When replying to a message sent to a chan, now you can choose if you want to reply to chan or sender. Fixed #9 --- src/bitmessageqt/__init__.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 65c236cd..d35f1a8b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -91,6 +91,9 @@ class MyForm(settingsmixin.SMainWindow): maxSoundFrequencySec = 60 str_chan = '[chan]' + + REPLY_TYPE_SENDER = 0 + REPLY_TYPE_CHAN = 1 def init_file_menu(self): QtCore.QObject.connect(self.ui.actionExit, QtCore.SIGNAL( @@ -140,7 +143,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.inboxContextMenuToolbar = QtGui.QToolBar() # Actions self.actionReply = self.ui.inboxContextMenuToolbar.addAction(_translate( - "MainWindow", "Reply"), self.on_action_InboxReply) + "MainWindow", "Reply to sender"), self.on_action_InboxReply) + self.actionReplyChan = self.ui.inboxContextMenuToolbar.addAction(_translate( + "MainWindow", "Reply to channel"), self.on_action_InboxReplyChan) self.actionAddSenderToAddressBook = self.ui.inboxContextMenuToolbar.addAction( _translate( "MainWindow", "Add sender to your Address Book"), @@ -3032,11 +3037,17 @@ class MyForm(settingsmixin.SMainWindow): return quoteWrapper.fill(line) return '\n'.join([quote_line(l) for l in message.splitlines()]) + '\n\n' - def on_action_InboxReply(self): + 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() @@ -3082,10 +3093,9 @@ class MyForm(settingsmixin.SMainWindow): self.ui.lineEditTo.setText(str(acct.fromAddress)) # 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 shared.config.has_section(toAddressAtCurrentInboxRow): - if shared.safeConfigGetBoolean(toAddressAtCurrentInboxRow, 'chan'): - logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') - self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) + 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.') + self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) listOfAddressesInComboBoxSendFrom = [str(widget['from'].itemData(i).toPyObject()) for i in range(widget['from'].count())] if toAddressAtCurrentInboxRow in listOfAddressesInComboBoxSendFrom: @@ -3862,6 +3872,11 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuInbox.addAction(self.actionForceHtml) self.popMenuInbox.addAction(self.actionMarkUnread) self.popMenuInbox.addSeparator() + address = str(tableWidget.item( + tableWidget.currentRow(), 0).data(Qt.UserRole).toPyObject()) + 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( -- 2.45.1 From 751f9108d812355407bd8ae33ea2cd2f62b18fdd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 14 Dec 2015 19:43:39 +0100 Subject: [PATCH 0217/1102] HTML detector and switcher HTML messages are detected and if present, the top of the message textedit displays a clickable area that switches HTML rendering on and off. Fixes #13 --- src/bitmessageqt/__init__.py | 4 +- src/bitmessageqt/bitmessageui.py | 7 ++- src/bitmessageqt/messageview.py | 44 ++++++++++++++ src/bitmessageqt/safehtmlparser.py | 97 ++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 src/bitmessageqt/messageview.py create mode 100644 src/bitmessageqt/safehtmlparser.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index d35f1a8b..b3f700b5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -34,6 +34,7 @@ from addaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * from newchandialog import * +from safehtmlparser import * from specialaddressbehavior import * from emailgateway import * from settings import * @@ -4025,10 +4026,9 @@ class MyForm(settingsmixin.SMainWindow): data = self.getCurrentMessageId() if data != False: message = "Error occurred: could not load message from disk." - message = unicode(message, 'utf-8)') messageTextedit.setCurrentFont(QtGui.QFont()) messageTextedit.setTextColor(QtGui.QColor()) - messageTextedit.setPlainText(message) + messageTextedit.setContent(message) def tableWidgetAddressBookItemChanged(self): currentRow = self.ui.tableWidgetAddressBook.currentRow() diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index e303567f..7a565d1c 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +from messageview import MessageView import settingsmixin try: @@ -123,7 +124,7 @@ class Ui_MainWindow(object): self.tableWidgetInbox.verticalHeader().setVisible(False) self.tableWidgetInbox.verticalHeader().setDefaultSectionSize(26) self.verticalSplitter_7.addWidget(self.tableWidgetInbox) - self.textEditInboxMessage = QtGui.QTextEdit(self.inbox) + self.textEditInboxMessage = MessageView(self.inbox) self.textEditInboxMessage.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessage.setReadOnly(True) self.textEditInboxMessage.setObjectName(_fromUtf8("textEditInboxMessage")) @@ -428,7 +429,7 @@ class Ui_MainWindow(object): self.tableWidgetInboxSubscriptions.verticalHeader().setVisible(False) self.tableWidgetInboxSubscriptions.verticalHeader().setDefaultSectionSize(26) self.verticalSplitter_4.addWidget(self.tableWidgetInboxSubscriptions) - self.textEditInboxMessageSubscriptions = QtGui.QTextEdit(self.subscriptions) + self.textEditInboxMessageSubscriptions = MessageView(self.subscriptions) self.textEditInboxMessageSubscriptions.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessageSubscriptions.setReadOnly(True) self.textEditInboxMessageSubscriptions.setObjectName(_fromUtf8("textEditInboxMessageSubscriptions")) @@ -527,7 +528,7 @@ class Ui_MainWindow(object): self.tableWidgetInboxChans.verticalHeader().setVisible(False) self.tableWidgetInboxChans.verticalHeader().setDefaultSectionSize(26) self.verticalSplitter_8.addWidget(self.tableWidgetInboxChans) - self.textEditInboxMessageChans = QtGui.QTextEdit(self.chans) + self.textEditInboxMessageChans = MessageView(self.chans) self.textEditInboxMessageChans.setBaseSize(QtCore.QSize(0, 500)) self.textEditInboxMessageChans.setReadOnly(True) self.textEditInboxMessageChans.setObjectName(_fromUtf8("textEditInboxMessageChans")) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py new file mode 100644 index 00000000..94e73ff1 --- /dev/null +++ b/src/bitmessageqt/messageview.py @@ -0,0 +1,44 @@ +from PyQt4 import QtCore, QtGui + +from safehtmlparser import * + +class MessageView(QtGui.QTextEdit): + MODE_PLAIN = 0 + MODE_HTML = 1 + TEXT_PLAIN = "HTML detected, click here to display" + TEXT_HTML = "Click here to disable HTML" + + def __init__(self, parent = 0): + super(MessageView, self).__init__(parent) + self.mode = MessageView.MODE_PLAIN + self.html = None + + def mousePressEvent(self, event): + #text = textCursor.block().text() + if event.button() == QtCore.Qt.LeftButton 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 showPlain(self): + self.mode = MessageView.MODE_PLAIN + out = self.html.raw + if self.html.has_html: + out = "
" + QtGui.QApplication.translate("MessageView", MessageView.TEXT_PLAIN) + "

" + out + self.setHtml(QtCore.QString(out)) + + def showHTML(self): + self.mode = MessageView.MODE_HTML + out = self.html.sanitised + out = "
" + QtGui.QApplication.translate("MessageView", MessageView.TEXT_HTML) + "

" + out + self.setHtml(QtCore.QString(out)) + + def setContent(self, data): + self.html = SafeHTMLParser() + self.html.allow_picture = True + self.html.feed(data) + self.html.close() + self.showPlain() diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py new file mode 100644 index 00000000..e22a776f --- /dev/null +++ b/src/bitmessageqt/safehtmlparser.py @@ -0,0 +1,97 @@ +from HTMLParser import HTMLParser +import inspect +from urllib import quote, quote_plus + +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'] + def __init__(self, *args, **kwargs): + HTMLParser.__init__(self, *args, **kwargs) + self.elements = set() + self.sanitised = u"" + self.raw = u"" + self.has_html = False + + def reset_safe(self): + self.raw = u"" + self.sanitised = u"" + + def add_if_acceptable(self, tag, attrs = None): + if not tag in self.acceptable_elements: + return + self.sanitised += "<" + if inspect.stack()[1][3] == "handle_endtag": + self.sanitised += "/" + self.sanitised += tag + if attrs is not None: + for attr in attrs: + if tag == "img" and attr[0] == "src" and not self.allow_picture: + attr[1] = "" + self.sanitised += " " + quote_plus(attr[0]) + "=\"" + attr[1] + "\"" + if inspect.stack()[1][3] == "handle_startendtag": + self.sanitised += "/" + self.sanitised += ">" + + def add_raw(self, tag, attrs = None): + self.raw += "<" + if inspect.stack()[1][3] == "handle_endtag": + self.raw += "/" + self.raw += tag + if attrs is not None: + for attr in attrs: + if tag == "img" and attr[0] == "src" and not self.allow_picture: + attr[1] = "" + self.raw += " " + attr[0] + "="" + attr[1] + """ + if inspect.stack()[1][3] == "handle_startendtag": + self.raw += "/" + self.raw += ">" + + def handle_starttag(self, tag, attrs): + if tag in self.acceptable_elements: + self.has_html = True + self.add_if_acceptable(tag, attrs) + self.add_raw(tag, attrs) + + def handle_endtag(self, tag): + self.add_if_acceptable(tag) + self.add_raw(tag) + + def handle_startendtag(self, tag, attrs): + if tag in self.acceptable_elements: + self.has_html = True + self.add_if_acceptable(tag, attrs) + self.add_raw(tag, attrs) + + def handle_data(self, data): + self.sanitised += unicode(data, 'utf-8', 'replace') + tmp = data.replace("\n", "
") + self.raw += unicode(tmp, 'utf-8', 'replace') + + def handle_charref(self, name): + self.sanitised += "&#" + name + ";" + self.raw += quote("&#" + name + ";") + + def handle_entityref(self, name): + self.sanitised += "&" + name + ";" + self.raw += quote("&" + name + ";") + + def is_html(self, text = None, allow_picture = False): + if text: + self.reset() + self.reset_safe() + self.feed(text) + self.close() + self.allow_picture = allow_picture + return self.has_html \ No newline at end of file -- 2.45.1 From 6557681a6c2d010d48ad63987327b1ce08fc3d28 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 01:24:10 +0100 Subject: [PATCH 0218/1102] Message has safe link opening Links in message body (if in HTML mode) now open, but it asks for a confirmation in a dialog box. Fixes #27 --- src/bitmessageqt/messageview.py | 21 +++++++++++++++++---- src/bitmessageqt/safehtmlparser.py | 8 ++++++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 94e73ff1..049a2706 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -2,16 +2,21 @@ from PyQt4 import QtCore, QtGui from safehtmlparser import * -class MessageView(QtGui.QTextEdit): +class MessageView(QtGui.QTextBrowser): MODE_PLAIN = 0 MODE_HTML = 1 TEXT_PLAIN = "HTML detected, click here to display" TEXT_HTML = "Click here to disable HTML" + CONFIRM_TITLE = "Follow external link" + CONFIRM_TEXT = "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?" 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) def mousePressEvent(self, event): #text = textCursor.block().text() @@ -22,18 +27,26 @@ class MessageView(QtGui.QTextEdit): self.showPlain() else: super(MessageView, self).mousePressEvent(event) + + def confirmURL(self, link): + reply = QtGui.QMessageBox.question(self, + QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TITLE), + QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TEXT).arg(str(link.toString())), + QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) + if reply == QtGui.QMessageBox.Yes: + QtGui.QDesktopServices.openUrl(link) def showPlain(self): self.mode = MessageView.MODE_PLAIN out = self.html.raw if self.html.has_html: - out = "
" + QtGui.QApplication.translate("MessageView", MessageView.TEXT_PLAIN) + "

" + out - self.setHtml(QtCore.QString(out)) + out = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN) + "

" + out + self.setHtml(QtCore.QString(out)) def showHTML(self): self.mode = MessageView.MODE_HTML out = self.html.sanitised - out = "
" + QtGui.QApplication.translate("MessageView", MessageView.TEXT_HTML) + "

" + out + out = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML) + "

" + out self.setHtml(QtCore.QString(out)) def setContent(self, data): diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index e22a776f..c058dd6f 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -39,7 +39,9 @@ class SafeHTMLParser(HTMLParser): for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" - self.sanitised += " " + quote_plus(attr[0]) + "=\"" + attr[1] + "\"" + self.sanitised += " " + quote_plus(attr[0]) + if attr[1] is not None: + self.sanitised += "=\"" + attr[1] + "\"" if inspect.stack()[1][3] == "handle_startendtag": self.sanitised += "/" self.sanitised += ">" @@ -53,7 +55,9 @@ class SafeHTMLParser(HTMLParser): for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" - self.raw += " " + attr[0] + "="" + attr[1] + """ + self.raw += " " + attr[0] + if attr[1] is not None: + self.raw + "="" + attr[1] + """ if inspect.stack()[1][3] == "handle_startendtag": self.raw += "/" self.raw += ">" -- 2.45.1 From 7ef94b446d70d096dae80f0a97be890c22580f1d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 03:51:06 +0100 Subject: [PATCH 0219/1102] Lazy rendering of message contents Message will render as user is scrolling down. This prevents interface freezes on long messages (such as inline img in text mode). Fixes Bitmessage##366 Also a minor fix in text mode rendering. --- src/bitmessageqt/messageview.py | 42 ++++++++++++++++++++++++++---- src/bitmessageqt/safehtmlparser.py | 12 +++++---- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 049a2706..8d4b49c4 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -17,6 +17,11 @@ class MessageView(QtGui.QTextBrowser): self.setOpenExternalLinks(False) self.setOpenLinks(False) self.anchorClicked.connect(self.confirmURL) + self.out = "" + self.outpos = 0 + self.document().setUndoRedoEnabled(False) + self.rendering = False + self.verticalScrollBar().valueChanged.connect(self.lazyRender) def mousePressEvent(self, event): #text = textCursor.block().text() @@ -36,22 +41,49 @@ class MessageView(QtGui.QTextBrowser): if reply == QtGui.QMessageBox.Yes: QtGui.QDesktopServices.openUrl(link) + 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 + 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 = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN) + "

" + out - self.setHtml(QtCore.QString(out)) + out = "
" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_PLAIN)) + "

" + out + self.out = out + self.outpos = 0 + self.setHtml("") + self.lazyRender() def showHTML(self): self.mode = MessageView.MODE_HTML out = self.html.sanitised - out = "
" + QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML) + "

" + out - self.setHtml(QtCore.QString(out)) + out = "
" + str(QtGui.QApplication.translate(type(self).__name__, MessageView.TEXT_HTML)) + "

" + out + self.out = out + self.outpos = 0 + self.setHtml("") + self.lazyRender() def setContent(self, data): self.html = SafeHTMLParser() self.html.allow_picture = True + self.html.reset() + self.html.reset_safe() self.html.feed(data) self.html.close() - self.showPlain() + self.showPlain() \ No newline at end of file diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index c058dd6f..cc8362b3 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -25,8 +25,10 @@ class SafeHTMLParser(HTMLParser): self.has_html = False def reset_safe(self): + self.elements = set() self.raw = u"" self.sanitised = u"" + self.has_html = False def add_if_acceptable(self, tag, attrs = None): if not tag in self.acceptable_elements: @@ -35,12 +37,12 @@ class SafeHTMLParser(HTMLParser): if inspect.stack()[1][3] == "handle_endtag": self.sanitised += "/" self.sanitised += tag - if attrs is not None: + if not attrs is None: for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" self.sanitised += " " + quote_plus(attr[0]) - if attr[1] is not None: + if not (attr[1] is None): self.sanitised += "=\"" + attr[1] + "\"" if inspect.stack()[1][3] == "handle_startendtag": self.sanitised += "/" @@ -51,13 +53,13 @@ class SafeHTMLParser(HTMLParser): if inspect.stack()[1][3] == "handle_endtag": self.raw += "/" self.raw += tag - if attrs is not None: + if not attrs is None: for attr in attrs: if tag == "img" and attr[0] == "src" and not self.allow_picture: attr[1] = "" self.raw += " " + attr[0] - if attr[1] is not None: - self.raw + "="" + attr[1] + """ + if not (attr[1] is None): + self.raw += "="" + attr[1] + """ if inspect.stack()[1][3] == "handle_startendtag": self.raw += "/" self.raw += ">" -- 2.45.1 From eb35f35b834223ce6a3cf43969753045facd8991 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 04:24:35 +0100 Subject: [PATCH 0220/1102] Add system translations Items like dialog box buttons were not localised. This loads the default qt localisation, and also unloads the old localisation on locale change. Still needs to be adjusted for frozen. Addresses Bitmessage#737 --- src/bitmessageqt/__init__.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b3f700b5..5831987c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -69,11 +69,27 @@ def _translate(context, text): return QtGui.QApplication.translate(context, text) def change_translation(locale): - global qtranslator - qtranslator = QtCore.QTranslator() + global qmytranslator, qsystranslator + try: + if not qmytranslator.isEmpty(): + QtGui.QApplication.removeTranslator(qmytranslator) + except: + pass + try: + if not qsystranslator.isEmpty(): + QtGui.QApplication.removeTranslator(qsystranslator) + except: + pass + + qmytranslator = QtCore.QTranslator() translationpath = os.path.join (shared.codePath(), 'translations', 'bitmessage_' + locale) - qtranslator.load(translationpath) - QtGui.QApplication.installTranslator(qtranslator) + qmytranslator.load(translationpath) + QtGui.QApplication.installTranslator(qmytranslator) + + qsystranslator = QtCore.QTranslator() + translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + locale) + qsystranslator.load(translationpath) + QtGui.QApplication.installTranslator(qsystranslator) class MyForm(settingsmixin.SMainWindow): -- 2.45.1 From 1f525da1ff1a4a7ee6490e54fd64ffd18d9c1796 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 11:11:57 +0100 Subject: [PATCH 0221/1102] Link follow warning The message box should be a warning rather than a simple question. --- src/bitmessageqt/messageview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 8d4b49c4..1d7758e4 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -34,7 +34,7 @@ class MessageView(QtGui.QTextBrowser): super(MessageView, self).mousePressEvent(event) def confirmURL(self, link): - reply = QtGui.QMessageBox.question(self, + reply = QtGui.QMessageBox.warning(self, QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TITLE), QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TEXT).arg(str(link.toString())), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) -- 2.45.1 From 17d045da106b2265b1f0d0a9ccf5f889e0b22cf1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 12:14:21 +0100 Subject: [PATCH 0222/1102] Sensible default maximum difficulty Fixes #144 --- src/class_sqlThread.py | 8 +++++++- src/proofofwork.py | 25 +++++++++++++++++++++++++ src/shared.py | 4 ++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 682cffee..0c28bc22 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -326,7 +326,13 @@ class sqlThread(threading.Thread): shared.config.set('bitmessagesettings', 'maxdownloadrate', '0') shared.config.set('bitmessagesettings', 'maxuploadrate', '0') shared.config.set('bitmessagesettings', 'settingsversion', '10') - shared.writeKeysFile() + shared.writeKeysFile() + + # sanity check + if shared.config.getint('bitmessagesettings', 'maxacceptablenoncetrialsperbyte') == 0: + shared.config.set('bitmessagesettings','maxacceptablenoncetrialsperbyte', str(shared.ridiculousDifficulty * shared.networkDefaultProofOfWorkNonceTrialsPerByte)) + if shared.config.getint('bitmessagesettings', 'maxacceptablepayloadlengthextrabytes') == 0: + shared.config.set('bitmessagesettings','maxacceptablepayloadlengthextrabytes', str(shared.ridiculousDifficulty * shared.networkDefaultPayloadLengthExtraBytes)) # 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. diff --git a/src/proofofwork.py b/src/proofofwork.py index 841c7791..39999212 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -133,6 +133,31 @@ def _doGPUPoW(target, initialHash): raise Exception("GPU did not calculate correctly.") 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 run(target, initialHash): target = int(target) diff --git a/src/shared.py b/src/shared.py index 944cb659..c52ff3ac 100644 --- a/src/shared.py +++ b/src/shared.py @@ -91,6 +91,10 @@ objectProcessorQueue = Queue.Queue( ) # receiveDataThreads dump objects they hear on the network into this queue to be processed. streamsInWhichIAmParticipating = {} +# sanity check, prevent doing ridiculous PoW +# 20 million PoWs equals approximately 2 days on dev's dual R9 290 +ridiculousDifficulty = 20000000 + #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. -- 2.45.1 From 4c8ba431e560a7a50b59da058bdde0a5aa376f1c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 12:15:19 +0100 Subject: [PATCH 0223/1102] Add to blacklist from "All accounts" It didn't work before --- src/bitmessageqt/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 5831987c..a2e31ac8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3159,11 +3159,13 @@ class MyForm(settingsmixin.SMainWindow): # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() addressAtCurrentInboxRow = str(tableWidget.item( currentInboxRow, 1).data(Qt.UserRole).toPyObject()) + recipientAddress = str(tableWidget.item( + currentInboxRow, 0).data(Qt.UserRole).toPyObject()) # Let's make sure that it isn't already in the address book queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - label = "\"" + unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toString(), 'utf-8') + "\" in " + shared.config.get(self.getCurrentAccount(), "label") + label = "\"" + unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toString(), 'utf-8') + "\" in " + shared.config.get(recipientAddress, "label") sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', label, addressAtCurrentInboxRow, True) -- 2.45.1 From a727847e55043cb7995fb08cfb5fa58efe004d9b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 15 Dec 2015 20:30:32 +0100 Subject: [PATCH 0224/1102] Addresses can be configured not to send acks Manually by specifying "dontsendack" = true in the address section --- src/class_singleWorker.py | 20 ++++++++++---------- src/protocol.py | 14 ++++++++++++++ src/shared.py | 3 +++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 src/protocol.py diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 6de8703c..5c0ae4f4 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -17,6 +17,7 @@ import helper_inbox from helper_generic import addDataPadding from helper_threading import * import l10n +from protocol import * # This thread, of which there is only one, does the heavy lifting: # calculating POWs. @@ -121,7 +122,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). try: privSigningKeyBase58 = shared.config.get( @@ -202,7 +203,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - payload += '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + payload += getBitfield(myAddress) # bitfield of features supported by me (see the wiki). try: privSigningKeyBase58 = shared.config.get( @@ -281,8 +282,7 @@ class singleWorker(threading.Thread, StoppableThread): payload += '\x00\x00\x00\x01' # object type: pubkey payload += encodeVarint(addressVersionNumber) # Address version number payload += encodeVarint(streamNumber) - - dataToEncrypt = '\x00\x00\x00\x01' # bitfield of features supported by me (see the wiki). + dataToEncrypt = getBitfield(myAddress) try: privSigningKeyBase58 = shared.config.get( @@ -410,7 +410,7 @@ class singleWorker(threading.Thread, StoppableThread): dataToEncrypt = encodeVarint(addressVersionNumber) dataToEncrypt += encodeVarint(streamNumber) - dataToEncrypt += '\x00\x00\x00\x01' # behavior bitfield + dataToEncrypt += getBitfield(fromaddress) # behavior bitfield dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] if addressVersionNumber >= 3: @@ -686,7 +686,7 @@ class singleWorker(threading.Thread, StoppableThread): 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 = '\x00\x00\x00\x01' + behaviorBitfield = getBitfield(fromaddress) try: privEncryptionKeyBase58 = shared.config.get( @@ -707,7 +707,7 @@ class singleWorker(threading.Thread, StoppableThread): # Now we can start to assemble our message. payload = encodeVarint(fromAddressVersionNumber) payload += encodeVarint(fromStreamNumber) - 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 ) + payload += getBitfield(fromaddress) # 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. @@ -760,7 +760,7 @@ class singleWorker(threading.Thread, StoppableThread): if shared.config.has_section(toaddress): logger.info('Not bothering to include ackdata because we are sending to ourselves or a chan.') fullAckPayload = '' - elif not shared.isBitSetWithinBitfield(behaviorBitfield,31): + elif not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): logger.info('Not bothering to include ackdata because the receiver said that they won\'t relay it anyway.') fullAckPayload = '' else: @@ -811,7 +811,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') shared.inventorySets[toStreamNumber].add(inventoryHash) - if shared.config.has_section(toaddress): + if shared.config.has_section(toaddress) or shared.safeConfigGetBoolean(toaddress, 'dontsendack'): 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 @@ -821,7 +821,7 @@ class singleWorker(threading.Thread, StoppableThread): toStreamNumber, 'advertiseobject', inventoryHash)) # Update the sent message in the sent table with the necessary information. - if shared.config.has_section(toaddress): + if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): newStatus = 'msgsentnoackexpected' else: newStatus = 'msgsent' diff --git a/src/protocol.py b/src/protocol.py new file mode 100644 index 00000000..40feaaf4 --- /dev/null +++ b/src/protocol.py @@ -0,0 +1,14 @@ +import struct +import shared + +def getBitfield(address): + # bitfield of features supported by me (see the wiki). + bitfield = 0 + # send ack + if not shared.safeConfigGetBoolean(address, 'dontsendack'): + bitfield |= shared.BITFIELD_DOESACK + return struct.pack('>I', bitfield) + +def checkBitfield(bitfieldBinary, flags): + bitfield, = struct.unpack('>I', bitfieldBinary) + return (bitfield & flags) == flags \ No newline at end of file diff --git a/src/shared.py b/src/shared.py index c52ff3ac..ec46edcd 100644 --- a/src/shared.py +++ b/src/shared.py @@ -132,6 +132,9 @@ Header = Struct('!L12sL4s') NODE_NETWORK = 1 NODE_SSL = 2 +#Bitfield flags +BITFIELD_DOESACK = 1 + #Create a packet def CreatePacket(command, payload=''): payload_length = len(payload) -- 2.45.1 From 8359b8b20279f438e5aec011375d32788068f92e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 00:58:52 +0100 Subject: [PATCH 0225/1102] Contact support user interface Fixes #25 --- src/bitmessageqt/__init__.py | 6 ++ src/bitmessageqt/bitmessageui.py | 6 ++ src/bitmessageqt/support.py | 108 +++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/bitmessageqt/support.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a2e31ac8..f715a328 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -39,6 +39,7 @@ from specialaddressbehavior import * from emailgateway import * from settings import * import settingsmixin +import support from about import * from help import * from iconglossary import * @@ -152,6 +153,8 @@ class MyForm(settingsmixin.SMainWindow): "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) @@ -2555,6 +2558,9 @@ class MyForm(settingsmixin.SMainWindow): self.helpDialogInstance = helpDialog(self) self.helpDialogInstance.exec_() + def click_actionSupport(self): + support.createSupportMessage(self) + def click_actionAbout(self): self.aboutDialogInstance = aboutDialog(self) self.aboutDialogInstance.exec_() diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 7a565d1c..25cb178e 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -687,6 +687,10 @@ 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) @@ -713,6 +717,7 @@ class Ui_MainWindow(object): 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()) @@ -851,6 +856,7 @@ 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)) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py new file mode 100644 index 00000000..61892d40 --- /dev/null +++ b/src/bitmessageqt/support.py @@ -0,0 +1,108 @@ +import ctypes +from PyQt4 import QtCore, QtGui +import sys + +import account +from debug import logger +from foldertree import AccountMixin +from helper_sql import * +from l10n import getTranslationLanguage +from openclpow import has_opencl +from proofofwork import bmpow +import shared + +# this is BM support address going to Peter Surda +SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' +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 are you trying to do: + +Please describe what you expect to happen: + +Please describe what you happens instead: + + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Please write above this line and if possible, keep the information about your environment below intact. + +Operating system: {} +Architecture: {}bit +Frozen: {} +C PoW: {} +OpenCL PoW: {} +Locale: {} +SOCKS: {} +UPnP: {} +Connected hosts: {} +''' + +def checkAddressBook(myapp): + 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 shared.safeConfigGetBoolean(address, 'enabled'): + return address + return False + +def createAddressIfNeeded(myapp): + if not checkHasNormalAddress(): + shared.addressGeneratorQueue.put(('createRandomAddress', 4, 1, str(QtGui.QApplication.translate("Support", SUPPORT_MY_LABEL)), 1, "", False, shared.networkDefaultProofOfWorkNonceTrialsPerByte, shared.networkDefaultPayloadLengthExtraBytes)) + while shared.shutdown == 0 and not checkHasNormalAddress(): + time.sleep(.2) + myapp.rerenderComboBoxSendFrom() + return checkHasNormalAddress() + +def createSupportMessage(myapp): + checkAddressBook(myapp) + address = createAddressIfNeeded(myapp) + if shared.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) + + os = sys.platform + if os == "win32": + windowsversion = sys.getwindowsversion() + os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1]) + else: + unixversion = os.uname() + os = unixversion[0] + " " + unixversion[2] + architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" + frozen = "N/A" + if shared.frozen: + frozen = shared.frozen + cpow = "Yes" if bmpow else "No" + #cpow = QtGui.QApplication.translate("Support", cpow) + openclpow = "Yes" if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and has_opencl() else "No" + #openclpow = QtGui.QApplication.translate("Support", openclpow) + locale = getTranslationLanguage() + try: + socks = shared.config.get('bitmessagesettings', 'socksproxytype') + except: + socks = "N/A" + try: + upnp = shared.config.get('bitmessagesettings', 'upnp') + except: + upnp = "N/A" + connectedhosts = len(shared.connectedHostsList) + + myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(os, architecture, frozen, cpow, openclpow, locale, socks, upnp, connectedhosts)) + + # single msg tab + myapp.ui.tabWidgetSend.setCurrentIndex(0) + # send tab + myapp.ui.tabWidget.setCurrentIndex(1) -- 2.45.1 From 3e956509b2ec847f6952744d239c25eaf9519c1e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 01:05:35 +0100 Subject: [PATCH 0226/1102] Add PyBitmessage version to contact support --- src/bitmessageqt/support.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 61892d40..d3f68a2a 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -29,6 +29,7 @@ Please describe what you happens instead: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Please write above this line and if possible, keep the information about your environment below intact. +PyBitmesage version: {} Operating system: {} Architecture: {}bit Frozen: {} @@ -74,6 +75,7 @@ def createSupportMessage(myapp): myapp.ui.comboBoxSendFrom.setCurrentIndex(addrIndex) myapp.ui.lineEditTo.setText(SUPPORT_ADDRESS) + version = shared.softwareVersion os = sys.platform if os == "win32": windowsversion = sys.getwindowsversion() @@ -100,7 +102,7 @@ def createSupportMessage(myapp): upnp = "N/A" connectedhosts = len(shared.connectedHostsList) - myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(os, architecture, frozen, cpow, openclpow, locale, socks, upnp, connectedhosts)) + myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, frozen, cpow, openclpow, locale, socks, upnp, connectedhosts)) # single msg tab myapp.ui.tabWidgetSend.setCurrentIndex(0) -- 2.45.1 From 4049662a3a9dfc2d34a9dad1a88649b9bbeae5bc Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 01:15:19 +0100 Subject: [PATCH 0227/1102] Contact support updates Yes/No -> True/False Add Portable mode --- src/bitmessageqt/support.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index d3f68a2a..3073d5f7 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -33,6 +33,7 @@ PyBitmesage version: {} Operating system: {} Architecture: {}bit Frozen: {} +Portable mode: {} C PoW: {} OpenCL PoW: {} Locale: {} @@ -87,9 +88,10 @@ def createSupportMessage(myapp): frozen = "N/A" if shared.frozen: frozen = shared.frozen - cpow = "Yes" if bmpow else "No" + portablemode = "True" if shared.appdata == shared.lookupExeFolder() else "False" + cpow = "True" if bmpow else "False" #cpow = QtGui.QApplication.translate("Support", cpow) - openclpow = "Yes" if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and has_opencl() else "No" + openclpow = "True" if shared.safeConfigGetBoolean('bitmessagesettings', 'opencl') and has_opencl() else "False" #openclpow = QtGui.QApplication.translate("Support", openclpow) locale = getTranslationLanguage() try: @@ -102,7 +104,7 @@ def createSupportMessage(myapp): upnp = "N/A" connectedhosts = len(shared.connectedHostsList) - myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, frozen, cpow, openclpow, locale, socks, upnp, connectedhosts)) + myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, frozen, portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts)) # single msg tab myapp.ui.tabWidgetSend.setCurrentIndex(0) -- 2.45.1 From d0b9d75ce11ee3b36ebced478be774722f637208 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Dec 2015 02:36:45 +0100 Subject: [PATCH 0228/1102] Fix contact support unix detection --- src/bitmessageqt/support.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 3073d5f7..3d06e4d9 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,4 +1,5 @@ import ctypes +from os import uname from PyQt4 import QtCore, QtGui import sys @@ -82,7 +83,7 @@ def createSupportMessage(myapp): windowsversion = sys.getwindowsversion() os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1]) else: - unixversion = os.uname() + unixversion = uname() os = unixversion[0] + " " + unixversion[2] architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" frozen = "N/A" -- 2.45.1 From 07cee7209bef238590cdfa3e6b71f936916b1085 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 14:19:19 +0100 Subject: [PATCH 0229/1102] Contact support fixes - typos & formatting - OS detection crash fixes --- src/bitmessageqt/support.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 3d06e4d9..65bf3134 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,5 +1,4 @@ import ctypes -from os import uname from PyQt4 import QtCore, QtGui import sys @@ -17,14 +16,13 @@ SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' 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. +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 are you trying to do: Please describe what you expect to happen: -Please describe what you happens instead: +Please describe what happens instead: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,8 +81,12 @@ def createSupportMessage(myapp): windowsversion = sys.getwindowsversion() os = "Windows " + str(windowsversion[0]) + "." + str(windowsversion[1]) else: - unixversion = uname() - os = unixversion[0] + " " + unixversion[2] + 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" frozen = "N/A" if shared.frozen: -- 2.45.1 From ea37913ff14040ace8845044b9bc922425c51a89 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 14:20:51 +0100 Subject: [PATCH 0230/1102] Html parser fixes Raw mode improved, avoid HTML parser entirely and just replaces some strings. --- src/bitmessageqt/safehtmlparser.py | 38 +++++++++++------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index cc8362b3..5cd869bc 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -17,6 +17,14 @@ class SafeHTMLParser(HTMLParser): 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] + replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"]] + + @staticmethod + def multi_replace(text): + for a in SafeHTMLParser.replaces: + text = text.replace(a[0], a[1]) + return text + def __init__(self, *args, **kwargs): HTMLParser.__init__(self, *args, **kwargs) self.elements = set() @@ -48,51 +56,33 @@ class SafeHTMLParser(HTMLParser): self.sanitised += "/" self.sanitised += ">" - def add_raw(self, tag, attrs = None): - self.raw += "<" - if inspect.stack()[1][3] == "handle_endtag": - self.raw += "/" - self.raw += tag - if not attrs is None: - for attr in attrs: - if tag == "img" and attr[0] == "src" and not self.allow_picture: - attr[1] = "" - self.raw += " " + attr[0] - if not (attr[1] is None): - self.raw += "="" + attr[1] + """ - if inspect.stack()[1][3] == "handle_startendtag": - self.raw += "/" - self.raw += ">" - def handle_starttag(self, tag, attrs): if tag in self.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) - self.add_raw(tag, attrs) def handle_endtag(self, tag): self.add_if_acceptable(tag) - self.add_raw(tag) def handle_startendtag(self, tag, attrs): if tag in self.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) - self.add_raw(tag, attrs) def handle_data(self, data): self.sanitised += unicode(data, 'utf-8', 'replace') - tmp = data.replace("\n", "
") - self.raw += unicode(tmp, 'utf-8', 'replace') def handle_charref(self, name): self.sanitised += "&#" + name + ";" - self.raw += quote("&#" + name + ";") def handle_entityref(self, name): self.sanitised += "&" + name + ";" - self.raw += quote("&" + name + ";") - + + def feed(self, data): + HTMLParser.feed(self, data) + tmp = SafeHTMLParser.multi_replace(data) + self.raw += unicode(tmp, 'utf-8', 'replace') + def is_html(self, text = None, allow_picture = False): if text: self.reset() -- 2.45.1 From 4dbd444053f5f61a3d638db0abe38795a628cfe7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 15:34:16 +0100 Subject: [PATCH 0231/1102] Logging fix --- src/class_singleWorker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 5c0ae4f4..7c04558b 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -899,10 +899,10 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint(streamNumber) if addressVersionNumber <= 3: payload += ripe - logger.info('making request for pubkey with ripe:', ripe.encode('hex')) + logger.info('making request for pubkey with ripe: %s', ripe.encode('hex')) else: payload += tag - logger.info('making request for v4 pubkey with tag:', tag.encode('hex')) + logger.info('making request for v4 pubkey with tag: %s', tag.encode('hex')) # print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' -- 2.45.1 From ff207c1b56730773d8d38e23690872a8c3bb9e1a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 16 Dec 2015 16:18:38 +0100 Subject: [PATCH 0232/1102] Portable mode fix The option should not be available if the directory with the executable is not writable, such as when running from a dmg on OSX. --- src/bitmessageqt/__init__.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f715a328..53093b4e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4162,6 +4162,14 @@ class settingsDialog(QtGui.QDialog): if shared.appdata == shared.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) + else: + try: + import tempfile + file = tempfile.NamedTemporaryFile(dir=shared.lookupExeFolder(), delete=True) + file.close # should autodelete + except: + self.ui.checkBoxPortableMode.setDisabled(True) + if 'darwin' in sys.platform: self.ui.checkBoxStartOnLogon.setDisabled(True) self.ui.checkBoxStartOnLogon.setText(_translate( -- 2.45.1 From 69494594d5fbe7d786315187684309890d79e905 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Dec 2015 21:41:44 +0100 Subject: [PATCH 0233/1102] Main Window raising fixes On OSX and linux, the tray icon now raises window. Starting a new instance should raise the window too, but it may not work on linux (on my Ubuntu it just flashes the icon) Fixes Bitmessage#743 --- src/bitmessageqt/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 53093b4e..6ea7f595 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -840,6 +840,7 @@ class MyForm(settingsmixin.SMainWindow): self.show() self.setWindowState( self.windowState() & ~QtCore.Qt.WindowMinimized | QtCore.Qt.WindowActive) + self.raise_() self.activateWindow() # pointer to the application @@ -856,7 +857,7 @@ class MyForm(settingsmixin.SMainWindow): 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): -- 2.45.1 From a8053195ea5c95f62645b583681a7ff37b6b758d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 17 Dec 2015 22:58:52 +0100 Subject: [PATCH 0234/1102] Fix cdecl/stdcall DLL detection Fixes #146 --- src/proofofwork.py | 78 ++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/proofofwork.py b/src/proofofwork.py index 39999212..57c18679 100644 --- a/src/proofofwork.py +++ b/src/proofofwork.py @@ -11,38 +11,6 @@ import tr import os import ctypes -bitmsglib = 'bitmsghash.so' -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(codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL (stdcall) %s", bitmsglib) - except: - try: - # MinGW - bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL (cdecl) %s", bitmsglib) - except: - bso = None -else: - try: - bso = ctypes.CDLL(os.path.join(codePath(), "bitmsghash", bitmsglib)) - logger.info("Loaded C PoW DLL %s", bitmsglib) - except: - bso = None -if bso: - try: - bmpow = bso.BitmessagePOW - bmpow.restype = ctypes.c_ulonglong - except: - bmpow = None -else: - bmpow = None - def _set_idle(): if 'linux' in sys.platform: import os @@ -185,4 +153,48 @@ def run(target, initialHash): return _doFastPoW(target, initialHash) except: pass #fallback - return _doSafePoW(target, initialHash) \ No newline at end of file + return _doSafePoW(target, initialHash) + +# init +bitmsglib = 'bitmsghash.so' +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(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(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(codePath(), "bitmsghash", bitmsglib)) + logger.info("Loaded C PoW DLL %s", bitmsglib) + except: + bso = None +if bso: + try: + bmpow = bso.BitmessagePOW + bmpow.restype = ctypes.c_ulonglong + except: + bmpow = None +else: + bmpow = None + -- 2.45.1 From 0b4c57a5160afdf3fa1229b554bbcd536f9b94bd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 20 Dec 2015 00:59:25 +0100 Subject: [PATCH 0235/1102] Entries missing in messagelist --- src/bitmessageqt/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6ea7f595..f9d23762 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1065,6 +1065,10 @@ class MyForm(settingsmixin.SMainWindow): acct = accountClass(fromAddress) else: acct = accountClass(toAddress) + if acct is None: + acct = accountClass(fromAddress) + if acct is None: + acct = BMAccount(fromAddress) subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct.parseMessage(toAddress, fromAddress, subject, "") -- 2.45.1 From 879a6f1d68fa76a31cfb198887f8f7c1f8f5d6e8 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 20 Dec 2015 01:01:11 +0100 Subject: [PATCH 0236/1102] Messagelist loads faster Addresses #149. About 5 times faster. --- src/bitmessageqt/__init__.py | 40 +++------------------ src/bitmessageqt/foldertree.py | 63 +++++++++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 37 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f9d23762..e220c169 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -984,23 +984,9 @@ class MyForm(settingsmixin.SMainWindow): acct.parseMessage(toAddress, fromAddress, subject, "") items = [] - toAddressItem = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - toAddressItem.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - toAddressItem.setIcon(avatarize(toAddress)) - toAddressItem.setData(Qt.UserRole, str(toAddress)) - toAddressItem.setTextColor(AccountColor(toAddress).accountColor()) - toAddressItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - items.append(toAddressItem) + MessageList_AddressWidget(items, str(acct.toAddress), unicode(acct.toLabel, 'utf-8')) - fromAddressItem = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - fromAddressItem.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(acct.fromAddress) + ")") - fromAddressItem.setIcon(avatarize(fromAddress)) - fromAddressItem.setData(Qt.UserRole, str(fromAddress)) - fromAddressItem.setTextColor(AccountColor(fromAddress).accountColor()) - fromAddressItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - items.append(fromAddressItem) + MessageList_AddressWidget(items, str(acct.fromAddress), unicode(acct.fromLabel, 'utf-8')) subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) @@ -1074,27 +1060,9 @@ class MyForm(settingsmixin.SMainWindow): items = [] #to - to_item = QtGui.QTableWidgetItem(unicode(acct.toLabel, 'utf-8')) - to_item.setToolTip(unicode(acct.toLabel, 'utf-8') + " (" + str(acct.toAddress) + ")") - to_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - to_item.setFont(font) - to_item.setData(Qt.UserRole, str(toAddress)) - to_item.setTextColor(AccountColor(toAddress).accountColor()) - to_item.setIcon(avatarize(toAddress)) - items.append(to_item) + MessageList_AddressWidget(items, str(acct.toAddress), unicode(acct.toLabel, 'utf-8'), not read) # from - from_item = QtGui.QTableWidgetItem(unicode(acct.fromLabel, 'utf-8')) - from_item.setToolTip(unicode(acct.fromLabel, 'utf-8') + " (" + str(fromAddress) + ")") - from_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - from_item.setFont(font) - from_item.setData(Qt.UserRole, str(fromAddress)) - from_item.setTextColor(AccountColor(fromAddress).accountColor()) - from_item.setIcon(avatarize(fromAddress)) - items.append(from_item) + MessageList_AddressWidget(items, str(acct.fromAddress), unicode(acct.fromLabel, 'utf-8'), not read) # subject subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) subject_item.setToolTip(unicode(acct.subject, 'utf-8')) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 971cda61..a93862a3 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -261,8 +261,69 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): if not self.initialised: return self.emitDataChanged() + + +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(shared.config.getboolean(self.address, 'enabled')) + self.initialised = False + self.isEnabled = True + self.setAddress(address) + self.setLabel(label) + self.setUnread(unread) + self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.initialised = True + self.setType() # does updateText + parent.append(self) + + def setLabel(self, label = None): + if label is None: + label = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + else: + self.label = label + + 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 shared.safeConfigGetBoolean('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 + 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 Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): def __init__ (self, text, type = AccountMixin.NORMAL): super(QtGui.QTableWidgetItem, self).__init__(text) -- 2.45.1 From 4b63c4c0865ef4cdb1a3ddc5eca909c22d35792f Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 20 Dec 2015 01:21:54 +0100 Subject: [PATCH 0237/1102] Address Qt.UserData fix The previous commit broke places where UserData was read from the mesagelist line, because it's now a string rather than a QVariant. This actually simplifies things. --- src/bitmessageqt/__init__.py | 92 +++++++++++++++++----------------- src/bitmessageqt/foldertree.py | 6 ++- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e220c169..e7f63df8 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1896,8 +1896,8 @@ class MyForm(settingsmixin.SMainWindow): continue for i in range(sent.rowCount()): - rowAddress = str(sent.item( - i, 0).data(Qt.UserRole).toPyObject()) + rowAddress = sent.item( + i, 0).data(Qt.UserRole) if toAddress == rowAddress: sent.item(i, 3).setToolTip(textToDisplay) try: @@ -1916,8 +1916,8 @@ class MyForm(settingsmixin.SMainWindow): if self.getCurrentFolder(treeWidget) != "sent": continue for i in range(sent.rowCount()): - toAddress = str(sent.item( - i, 0).data(Qt.UserRole).toPyObject()) + toAddress = sent.item( + i, 0).data(Qt.UserRole) tableAckdata = sent.item( i, 3).data(Qt.UserRole).toPyObject() status, addressVersionNumber, streamNumber, ripe = decodeAddress( @@ -1944,7 +1944,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) treeWidget = self.widgetConvert(inbox) - self.propagateUnreadCount(str(inbox.item(i, 1 if inbox == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder(treeWidget), treeWidget, 0) + self.propagateUnreadCount(inbox.item(i, 1 if inbox == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder(treeWidget), treeWidget, 0) inbox.removeRow(i) break @@ -1980,8 +1980,8 @@ class MyForm(settingsmixin.SMainWindow): def rerenderInboxFromLabels(self): for i in range(self.ui.tableWidgetInbox.rowCount()): - addressToLookup = str(self.ui.tableWidgetInbox.item( - i, 1).data(Qt.UserRole).toPyObject()) + addressToLookup = self.ui.tableWidgetInbox.item( + i, 1).data(Qt.UserRole) fromLabel = '' queryreturn = sqlQuery( '''select label from addressbook where address=?''', addressToLookup) @@ -2020,8 +2020,8 @@ class MyForm(settingsmixin.SMainWindow): def rerenderInboxToLabels(self): for i in range(self.ui.tableWidgetInbox.rowCount()): - toAddress = str(self.ui.tableWidgetInbox.item( - i, 0).data(Qt.UserRole).toPyObject()) + toAddress = self.ui.tableWidgetInbox.item( + i, 0).data(Qt.UserRole) # 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') @@ -2043,8 +2043,8 @@ class MyForm(settingsmixin.SMainWindow): def rerenderSentFromLabels(self): for i in range(self.ui.tableWidgetInbox.rowCount()): - fromAddress = str(self.ui.tableWidgetInbox.item( - i, 1).data(Qt.UserRole).toPyObject()) + fromAddress = self.ui.tableWidgetInbox.item( + i, 1).data(Qt.UserRole) # 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') @@ -2057,8 +2057,8 @@ class MyForm(settingsmixin.SMainWindow): def rerenderSentToLabels(self): for i in range(self.ui.tableWidgetInbox.rowCount()): - addressToLookup = str(self.ui.tableWidgetInbox.item( - i, 0).data(Qt.UserRole).toPyObject()) + addressToLookup = self.ui.tableWidgetInbox.item( + i, 0).data(Qt.UserRole) toLabel = '' queryreturn = sqlQuery( '''select label from addressbook where address=?''', addressToLookup) @@ -3003,9 +3003,9 @@ class MyForm(settingsmixin.SMainWindow): "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) if modified == 1: # performance optimisation - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder()) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder()) else: - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) # tableWidget.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. @@ -3048,11 +3048,11 @@ class MyForm(settingsmixin.SMainWindow): self.replyFromTab = self.ui.tabWidget.currentIndex() currentInboxRow = tableWidget.currentRow() - toAddressAtCurrentInboxRow = str(tableWidget.item( - currentInboxRow, 0).data(Qt.UserRole).toPyObject()) + toAddressAtCurrentInboxRow = tableWidget.item( + currentInboxRow, 0).data(Qt.UserRole) acct = accountClass(toAddressAtCurrentInboxRow) - fromAddressAtCurrentInboxRow = str(tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole).toPyObject()) + fromAddressAtCurrentInboxRow = tableWidget.item( + currentInboxRow, 1).data(Qt.UserRole) msgid = str(tableWidget.item( currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( @@ -3114,8 +3114,8 @@ class MyForm(settingsmixin.SMainWindow): return currentInboxRow = tableWidget.currentRow() # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() - addressAtCurrentInboxRow = str(tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole).toPyObject()) + addressAtCurrentInboxRow = tableWidget.item( + currentInboxRow, 1).data(Qt.UserRole) # Let's make sure that it isn't already in the address book queryreturn = sqlQuery('''select * from addressbook where address=?''', addressAtCurrentInboxRow) @@ -3136,10 +3136,10 @@ class MyForm(settingsmixin.SMainWindow): return currentInboxRow = tableWidget.currentRow() # tableWidget.item(currentRow,1).data(Qt.UserRole).toPyObject() - addressAtCurrentInboxRow = str(tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole).toPyObject()) - recipientAddress = str(tableWidget.item( - currentInboxRow, 0).data(Qt.UserRole).toPyObject()) + addressAtCurrentInboxRow = tableWidget.item( + currentInboxRow, 1).data(Qt.UserRole) + recipientAddress = tableWidget.item( + currentInboxRow, 0).data(Qt.UserRole) # Let's make sure that it isn't already in the address book queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) @@ -3173,9 +3173,9 @@ class MyForm(settingsmixin.SMainWindow): else: sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) if folder != "trash" and not shifted: - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "trash", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), 1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) @@ -3198,8 +3198,8 @@ class MyForm(settingsmixin.SMainWindow): currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "inbox", self.getCurrentTreeWidget(), 1) - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), "trash", self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3258,7 +3258,7 @@ class MyForm(settingsmixin.SMainWindow): else: sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setPlainText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3270,8 +3270,8 @@ class MyForm(settingsmixin.SMainWindow): def on_action_ForceSend(self): currentRow = self.ui.tableWidgetInbox.currentRow() - addressAtCurrentRow = str(self.ui.tableWidgetInbox.item( - currentRow, 0).data(Qt.UserRole).toPyObject()) + addressAtCurrentRow = self.ui.tableWidgetInbox.item( + currentRow, 0).data(Qt.UserRole) toRipe = decodeAddress(addressAtCurrentRow)[3] sqlExecute( '''UPDATE sent SET status='forcepow' WHERE toripe=? AND status='toodifficult' and folder='sent' ''', @@ -3285,8 +3285,8 @@ class MyForm(settingsmixin.SMainWindow): def on_action_SentClipboard(self): currentRow = self.ui.tableWidgetInbox.currentRow() - addressAtCurrentRow = str(self.ui.tableWidgetInbox.item( - currentRow, 0).data(Qt.UserRole).toPyObject()) + addressAtCurrentRow = self.ui.tableWidgetInbox.item( + currentRow, 0).data(Qt.UserRole) clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(addressAtCurrentRow)) @@ -3721,18 +3721,18 @@ class MyForm(settingsmixin.SMainWindow): else: currentColumn = 1 if self.getCurrentFolder() == "sent": - myAddress = str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject()) - otherAddress = str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject()) + myAddress = tableWidget.item(currentRow, 1).data(Qt.UserRole) + otherAddress = tableWidget.item(currentRow, 0).data(Qt.UserRole) else: - myAddress = str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject()) - otherAddress = str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject()) + myAddress = tableWidget.item(currentRow, 0).data(Qt.UserRole) + otherAddress = tableWidget.item(currentRow, 1).data(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).text()) + text = str(tableWidget.item(currentRow, currentColumn).label) else: - text = str(tableWidget.item(currentRow, currentColumn).data(Qt.UserRole).toPyObject()) + text = tableWidget.item(currentRow, currentColumn).data(Qt.UserRole) clipboard = QtGui.QApplication.clipboard() clipboard.setText(str(text)) @@ -3870,8 +3870,8 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuInbox.addAction(self.actionForceHtml) self.popMenuInbox.addAction(self.actionMarkUnread) self.popMenuInbox.addSeparator() - address = str(tableWidget.item( - tableWidget.currentRow(), 0).data(Qt.UserRole).toPyObject()) + address = tableWidget.item( + tableWidget.currentRow(), 0).data(Qt.UserRole) account = accountClass(address) if account.type == AccountMixin.CHAN: self.popMenuInbox.addAction(self.actionReplyChan) @@ -4011,13 +4011,11 @@ class MyForm(settingsmixin.SMainWindow): # inventoryHashToMarkRead = str(tableWidget.item( # currentRow, 3).data(Qt.UserRole).toPyObject()) # inventoryHashesToMarkRead.append(inventoryHashToMarkRead) - tableWidget.item(currentRow, 0).setFont(font) - tableWidget.item(currentRow, 0).setTextColor(AccountColor(str(tableWidget.item(currentRow, 0).data(Qt.UserRole).toPyObject())).accountColor()) - tableWidget.item(currentRow, 1).setFont(font) - tableWidget.item(currentRow, 1).setTextColor(AccountColor(str(tableWidget.item(currentRow, 1).data(Qt.UserRole).toPyObject())).accountColor()) + tableWidget.item(currentRow, 0).setUnread(False) + tableWidget.item(currentRow, 1).setUnread(False) tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) - self.propagateUnreadCount(str(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole).toPyObject()), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) else: data = self.getCurrentMessageId() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index a93862a3..7336bd96 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -284,9 +284,13 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi label = unicode(shared.config.get(self.address, 'label'), 'utf-8)') else: self.label = label - + if self.initialised: + self.emitDataChanged() + def setUnread(self, unread): self.unread = unread + if self.initialised: + self.emitDataChanged() def data(self, role): if role == QtCore.Qt.DisplayRole: -- 2.45.1 From e650cff42d7dab4100f09047a6b7e0525f0d2981 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 20 Dec 2015 02:10:38 +0100 Subject: [PATCH 0238/1102] (Un)read messagelist items Previous commits broke them, now it renders correctly again. --- src/bitmessageqt/__init__.py | 4 ++-- src/bitmessageqt/foldertree.py | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index e7f63df8..c24b4554 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2994,8 +2994,8 @@ class MyForm(settingsmixin.SMainWindow): if not tableWidget.item(currentRow, 0).font().bold(): modified += 1 inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) - tableWidget.item(currentRow, 0).setFont(font) - tableWidget.item(currentRow, 1).setFont(font) + tableWidget.item(currentRow, 0).setUnread(True) + tableWidget.item(currentRow, 1).setUnread(True) tableWidget.item(currentRow, 2).setFont(font) tableWidget.item(currentRow, 3).setFont(font) #sqlite requires the exact number of ?s to prevent injection diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 7336bd96..6715b183 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -284,13 +284,9 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi label = unicode(shared.config.get(self.address, 'label'), 'utf-8)') else: self.label = label - if self.initialised: - self.emitDataChanged() def setUnread(self, unread): self.unread = unread - if self.initialised: - self.emitDataChanged() def data(self, role): if role == QtCore.Qt.DisplayRole: -- 2.45.1 From 4647fcb87605481fb7ad3f3042e132d667cd0a5f Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 20 Dec 2015 21:31:30 +0100 Subject: [PATCH 0239/1102] Disable label rerendering in messagelist It's broken and just consumes resources. I'll fix it separately. --- src/bitmessageqt/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c24b4554..a894db21 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1979,6 +1979,7 @@ class MyForm(settingsmixin.SMainWindow): os._exit(0) def rerenderInboxFromLabels(self): + return for i in range(self.ui.tableWidgetInbox.rowCount()): addressToLookup = self.ui.tableWidgetInbox.item( i, 1).data(Qt.UserRole) @@ -2019,6 +2020,7 @@ class MyForm(settingsmixin.SMainWindow): def rerenderInboxToLabels(self): + return for i in range(self.ui.tableWidgetInbox.rowCount()): toAddress = self.ui.tableWidgetInbox.item( i, 0).data(Qt.UserRole) @@ -2042,6 +2044,7 @@ class MyForm(settingsmixin.SMainWindow): i, 0).setTextColor(QApplication.palette().text().color()) def rerenderSentFromLabels(self): + return for i in range(self.ui.tableWidgetInbox.rowCount()): fromAddress = self.ui.tableWidgetInbox.item( i, 1).data(Qt.UserRole) @@ -2056,6 +2059,7 @@ class MyForm(settingsmixin.SMainWindow): i, 1).setIcon(avatarize(fromAddress)) def rerenderSentToLabels(self): + return for i in range(self.ui.tableWidgetInbox.rowCount()): addressToLookup = self.ui.tableWidgetInbox.item( i, 0).data(Qt.UserRole) -- 2.45.1 From 0f24fe5a0cd2b4b79ffd10df271140c13be6fefa Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 21 Dec 2015 15:38:45 +0100 Subject: [PATCH 0240/1102] Missing import --- src/bitmessageqt/support.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 65bf3134..6683756b 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,6 +1,7 @@ import ctypes from PyQt4 import QtCore, QtGui import sys +import time import account from debug import logger -- 2.45.1 From d6ec2a2b8daac83716bf4128a4d2dc3ab2ad35bb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 21 Dec 2015 15:58:22 +0100 Subject: [PATCH 0241/1102] Version bump --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index ec46edcd..f9ff8a96 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.5' +softwareVersion = '0.5.6' 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. -- 2.45.1 From 3b30afea29dec4d8f2cadccd956d7ec61ec13fd1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 21 Dec 2015 21:08:28 +0100 Subject: [PATCH 0242/1102] Messagelist subject class Messagelist subjects now are their own class. Fixes #153 Also fixes replies/clipboard for gatewayed messages. --- src/bitmessageqt/__init__.py | 36 ++++++++------------------ src/bitmessageqt/foldertree.py | 46 ++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 25 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a894db21..a193b1c6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -984,16 +984,9 @@ class MyForm(settingsmixin.SMainWindow): acct.parseMessage(toAddress, fromAddress, subject, "") items = [] - MessageList_AddressWidget(items, str(acct.toAddress), unicode(acct.toLabel, 'utf-8')) - - MessageList_AddressWidget(items, str(acct.fromAddress), unicode(acct.fromLabel, 'utf-8')) - - subjectItem = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) - subjectItem.setToolTip(unicode(acct.subject, 'utf-8')) - subjectItem.setData(Qt.UserRole, str(subject)) - subjectItem.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - items.append(subjectItem) + 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')) if status == 'awaitingpubkey': statusText = _translate( @@ -1060,18 +1053,11 @@ class MyForm(settingsmixin.SMainWindow): items = [] #to - MessageList_AddressWidget(items, str(acct.toAddress), unicode(acct.toLabel, 'utf-8'), not read) + MessageList_AddressWidget(items, toAddress, unicode(acct.toLabel, 'utf-8'), not read) # from - MessageList_AddressWidget(items, str(acct.fromAddress), unicode(acct.fromLabel, 'utf-8'), not read) + MessageList_AddressWidget(items, fromAddress, unicode(acct.fromLabel, 'utf-8'), not read) # subject - subject_item = QtGui.QTableWidgetItem(unicode(acct.subject, 'utf-8')) - subject_item.setToolTip(unicode(acct.subject, 'utf-8')) - subject_item.setData(Qt.UserRole, str(subject)) - subject_item.setFlags( - QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - if not read: - subject_item.setFont(font) - items.append(subject_item) + MessageList_SubjectWidget(items, str(subject), unicode(acct.subject, 'utf-8'), not read) # time received time_item = myTableWidgetItem(l10n.formatTimestamp(received)) time_item.setToolTip(l10n.formatTimestamp(received)) @@ -3000,7 +2986,7 @@ class MyForm(settingsmixin.SMainWindow): inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) tableWidget.item(currentRow, 0).setUnread(True) tableWidget.item(currentRow, 1).setUnread(True) - tableWidget.item(currentRow, 2).setFont(font) + tableWidget.item(currentRow, 2).setUnread(True) tableWidget.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)''' % ( @@ -3064,7 +3050,7 @@ class MyForm(settingsmixin.SMainWindow): if queryreturn != []: for row in queryreturn: messageAtCurrentInboxRow, = row - acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toPyObject(), 'utf-8'), messageAtCurrentInboxRow) + acct.parseMessage(toAddressAtCurrentInboxRow, fromAddressAtCurrentInboxRow, tableWidget.item(currentInboxRow, 2).subject, messageAtCurrentInboxRow) widget = { 'subject': self.ui.lineEditSubject, 'from': self.ui.comboBoxSendFrom, @@ -3148,7 +3134,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from blacklist where address=?''', addressAtCurrentInboxRow) if queryreturn == []: - label = "\"" + unicode(tableWidget.item(currentInboxRow, 2).data(Qt.UserRole).toString(), 'utf-8') + "\" in " + shared.config.get(recipientAddress, "label") + label = "\"" + tableWidget.item(currentInboxRow, 2).subject + "\" in " + shared.config.get(recipientAddress, "label") sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', label, addressAtCurrentInboxRow, True) @@ -3219,7 +3205,7 @@ class MyForm(settingsmixin.SMainWindow): return currentInboxRow = tableWidget.currentRow() try: - subjectAtCurrentInboxRow = str(tableWidget.item(currentInboxRow,2).text()) + subjectAtCurrentInboxRow = str(tableWidget.item(currentInboxRow,2).data(Qt.UserRole)) except: subjectAtCurrentInboxRow = '' @@ -4017,7 +4003,7 @@ class MyForm(settingsmixin.SMainWindow): # inventoryHashesToMarkRead.append(inventoryHashToMarkRead) tableWidget.item(currentRow, 0).setUnread(False) tableWidget.item(currentRow, 1).setUnread(False) - tableWidget.item(currentRow, 2).setFont(font) + tableWidget.item(currentRow, 2).setUnread(False) tableWidget.item(currentRow, 3).setFont(font) self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 6715b183..6d81f143 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -324,6 +324,52 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi 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(shared.config.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) -- 2.45.1 From 6f74ffc26580b9456db94e5e1840c31e884c29cd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 21 Dec 2015 21:24:06 +0100 Subject: [PATCH 0243/1102] Mac OSX portable mode path Fixes #150 --- src/shared.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index f9ff8a96..57748962 100644 --- a/src/shared.py +++ b/src/shared.py @@ -207,7 +207,11 @@ def assembleErrorMessage(fatal=0, banTime=0, inventoryVector='', errorText=''): def lookupExeFolder(): if frozen: - exeFolder = path.dirname(sys.executable) + path.sep + 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: -- 2.45.1 From d7ff86705e7e9094c1506a3fd6c67001b89d089c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Dec 2015 23:28:40 +0100 Subject: [PATCH 0244/1102] Fix frozen localisation Addresses Bitmessage#737 --- src/bitmessageqt/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a193b1c6..698604ad 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -88,7 +88,10 @@ def change_translation(locale): QtGui.QApplication.installTranslator(qmytranslator) qsystranslator = QtCore.QTranslator() - translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + locale) + if shared.frozen: + translationpath = os.path.join (shared.codePath(), 'translations', 'qt_' + locale) + else: + translationpath = os.path.join (str(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)), 'qt_' + locale) qsystranslator.load(translationpath) QtGui.QApplication.installTranslator(qsystranslator) -- 2.45.1 From e5675987a760fc0996f8c77e6be677e151d0613d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 23 Dec 2015 00:34:41 +0100 Subject: [PATCH 0245/1102] Fix frozen localisation (OSX) Fixes Bitmessage#737 --- src/build_osx.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/build_osx.py b/src/build_osx.py index a5b004e6..03293efd 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,18 +1,27 @@ import os +from PyQt4 import QtCore from setuptools import setup name = "Bitmessage" version = os.getenv("PYBITMESSAGEVERSION", "custom") mainscript = ["bitmessagemain.py"] +DATA_FILES = [ + ('', ['sslkeys', 'images']), + ('bitmsghash', ['bitmsghash/bitmsghash.cl', 'bitmsghash/bitmsghash.so']), + ('translations', glob('translations/*.qm')), + ('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", "bitmsghash", "sslkeys"], includes = ['sip', 'PyQt4._qt'], iconfile = "images/bitmessage.icns" ) -- 2.45.1 From 3f2108b36f4b4ae3e11545ec7f86db0bae2240c7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 23 Dec 2015 00:39:58 +0100 Subject: [PATCH 0246/1102] Typo --- src/build_osx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build_osx.py b/src/build_osx.py index 03293efd..778bb300 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -18,7 +18,7 @@ setup( name = name, version = version, app = mainscript, - data_files=DATA_FILES + data_files = DATA_FILES, setup_requires = ["py2app"], options = dict( py2app = dict( -- 2.45.1 From 27874df45f2264c6af29f62c5ea2ee2d7674b1e0 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 23 Dec 2015 00:42:20 +0100 Subject: [PATCH 0247/1102] Typo (missing) --- src/build_osx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/build_osx.py b/src/build_osx.py index 778bb300..fb81d4d0 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -1,3 +1,4 @@ +from glob import glob import os from PyQt4 import QtCore from setuptools import setup -- 2.45.1 From 1b36da93272ce9c8af3b4a3b8baaa82ca4a582ed Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 23 Dec 2015 13:42:48 +0100 Subject: [PATCH 0248/1102] Save UPnP port Fixes #129 --- src/upnp.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index abfe9e65..588318f4 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -167,7 +167,10 @@ class uPnPThread(threading.Thread, StoppableThread): def __init__ (self): threading.Thread.__init__(self, name="uPnPThread") self.localPort = shared.config.getint('bitmessagesettings', 'port') - self.extPort = None + try: + self.extPort = shared.config.getint('bitmessagesettings', 'extport') + except: + self.extPort = None self.routers = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) @@ -197,7 +200,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Found UPnP router at %s", ip) self.routers.append(newRouter) self.createPortMapping(newRouter) - shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping established'))) + shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping established on port {}').format(self.extPort))) break except socket.timeout as e: pass @@ -251,11 +254,15 @@ class uPnPThread(threading.Thread, StoppableThread): localIP = router.localAddress 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("Requesting UPnP mapping for %s:%i on external port %i", localIP, self.localPort, extPort) router.AddPortMapping(extPort, self.localPort, localIP, 'TCP', 'BitMessage') shared.extPort = extPort + self.extPort = extPort + shared.config.set('bitmessagesettings', 'extport', str(extPort)) break except UPnPError: logger.debug("UPnP error: ", exc_info=True) -- 2.45.1 From 4033b945ee412409872e57810eb9ed4eda5cf80a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 29 Dec 2015 16:36:14 +0100 Subject: [PATCH 0249/1102] UPnP status bar update fix --- src/upnp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upnp.py b/src/upnp.py index 588318f4..4c54ef86 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -200,7 +200,7 @@ class uPnPThread(threading.Thread, StoppableThread): logger.debug("Found UPnP router at %s", ip) self.routers.append(newRouter) self.createPortMapping(newRouter) - shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping established on port {}').format(self.extPort))) + shared.UISignalQueue.put(('updateStatusBar', tr.translateText("MainWindow",'UPnP port mapping established on port %1').arg(str(self.extPort)))) break except socket.timeout as e: pass -- 2.45.1 From 962c36e1223b9d9bcff9ce3d06e04ec4cf611160 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 4 Jan 2016 11:13:31 +0100 Subject: [PATCH 0250/1102] Allow zooming of message body Uses default system zoom settings (Ctrl-Wheel). Fixes #163 --- src/bitmessageqt/messageview.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 1d7758e4..9aa7ae54 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -21,6 +21,7 @@ class MessageView(QtGui.QTextBrowser): self.outpos = 0 self.document().setUndoRedoEnabled(False) self.rendering = False + self.defaultFontPointSize = self.currentFont().pointSize() self.verticalScrollBar().valueChanged.connect(self.lazyRender) def mousePressEvent(self, event): @@ -32,7 +33,16 @@ class MessageView(QtGui.QTextBrowser): self.showPlain() else: super(MessageView, self).mousePressEvent(event) - + + def wheelEvent(self, event): + if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: + numDegrees = event.delta() / 8 + numSteps = numDegrees / 15 + zoomDiff = numSteps + self.currentFont().pointSize() - self.defaultFontPointSize + QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1").arg(str(zoomDiff))) + # super will actually automatically take care of zooming + super(MessageView, self).wheelEvent(event) + def confirmURL(self, link): reply = QtGui.QMessageBox.warning(self, QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TITLE), -- 2.45.1 From f4c2cc5160d3f714546d0dddb46310b6c75eb2d4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 4 Jan 2016 15:43:24 +0100 Subject: [PATCH 0251/1102] Unicode - subject on replies was not parsed correctly (or should I say was parsed more than necessary) - unicode can handle invalid characters without needing a special function Fixes #164 --- src/bitmessageqt/__init__.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 698604ad..754b3a76 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -982,14 +982,13 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setItem(0, i, items[i]) def addMessageListItemSent(self, tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime): - subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct = accountClass(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')) + MessageList_SubjectWidget(items, str(subject), unicode(acct.subject, 'utf-8', 'replace')) if status == 'awaitingpubkey': statusText = _translate( @@ -1051,7 +1050,6 @@ class MyForm(settingsmixin.SMainWindow): acct = accountClass(fromAddress) if acct is None: acct = BMAccount(fromAddress) - subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct.parseMessage(toAddress, fromAddress, subject, "") items = [] @@ -1060,7 +1058,7 @@ class MyForm(settingsmixin.SMainWindow): # from MessageList_AddressWidget(items, fromAddress, unicode(acct.fromLabel, 'utf-8'), not read) # subject - MessageList_SubjectWidget(items, str(subject), unicode(acct.subject, 'utf-8'), not read) + 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)) @@ -2404,8 +2402,6 @@ class MyForm(settingsmixin.SMainWindow): # 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): - subject = shared.fixPotentiallyInvalidUTF8Data(subject) - message = shared.fixPotentiallyInvalidUTF8Data(message) acct = accountClass(fromAddress) acct.parseMessage(toAddress, fromAddress, subject, message) for sent in [self.ui.tableWidgetInbox, self.ui.tableWidgetInboxSubscriptions, self.ui.tableWidgetInboxChans]: @@ -2418,7 +2414,7 @@ class MyForm(settingsmixin.SMainWindow): continue self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) - self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)')) + self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)', 'replace')) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): if toAddress == str_broadcast_subscribers: @@ -2434,7 +2430,6 @@ class MyForm(settingsmixin.SMainWindow): elif treeWidget == self.ui.treeWidgetYourIdentities and self.getCurrentAccount(treeWidget) is None: ret = self.addMessageListItemInbox(tableWidget, "inbox", inventoryHash, toAddress, fromAddress, subject, time.time(), 0) if ret is None: - subject = shared.fixPotentiallyInvalidUTF8Data(subject) acct.parseMessage(toAddress, fromAddress, subject, "") else: acct = ret @@ -3042,10 +3037,10 @@ class MyForm(settingsmixin.SMainWindow): currentInboxRow = tableWidget.currentRow() toAddressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 0).data(Qt.UserRole) + currentInboxRow, 0).address acct = accountClass(toAddressAtCurrentInboxRow) fromAddressAtCurrentInboxRow = tableWidget.item( - currentInboxRow, 1).data(Qt.UserRole) + currentInboxRow, 1).address msgid = str(tableWidget.item( currentInboxRow, 3).data(Qt.UserRole).toPyObject()) queryreturn = sqlQuery( @@ -3093,12 +3088,12 @@ class MyForm(settingsmixin.SMainWindow): else: widget['from'].setCurrentIndex(0) - quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8')) + quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) widget['message'].setText(quotedText) if acct.subject[0:3] in ['Re:', 'RE:']: - widget['subject'].setText(acct.subject) + widget['subject'].setText(tableWidget.item(currentInboxRow, 2).label) else: - widget['subject'].setText('Re: ' + acct.subject) + widget['subject'].setText('Re: ' + tableWidget.item(currentInboxRow, 2).label) self.ui.tabWidget.setCurrentIndex(1) def on_action_InboxAddSenderToAddressBook(self): -- 2.45.1 From 46494dc3e6001ec1961b0e220e8dacfe2b1ad7b8 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 10 Jan 2016 17:45:49 +0100 Subject: [PATCH 0252/1102] "All accounts" can't be renamed Minor error --- src/bitmessageqt/__init__.py | 5 +++-- src/bitmessageqt/foldertree.py | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 754b3a76..9ae4e6cd 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -477,7 +477,6 @@ class MyForm(settingsmixin.SMainWindow): subwidget = Ui_FolderWidget(widget, j, toAddress, folder, 0) j += 1 widget.setUnreadCount(unread) - widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) i += 1 treeWidget.setSortingEnabled(True) @@ -592,7 +591,6 @@ class MyForm(settingsmixin.SMainWindow): unread += db[toAddress][folder] j += 1 widget.setUnreadCount(unread) - widget.setFlags (widget.flags() | QtCore.Qt.ItemIsEditable) i += 1 treeWidget.setSortingEnabled(True) @@ -3938,6 +3936,9 @@ class MyForm(settingsmixin.SMainWindow): # only currently selected item if item.address != self.getCurrentAccount(): return + # "All accounts" can't be renamed + if item.type == AccountMixin.ALL: + return newLabel = str(item.text(0)) if item.type == AccountMixin.SUBSCRIPTION: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 6d81f143..19d5dc12 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -61,8 +61,10 @@ class AccountMixin (object): self.updateText() 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 shared.safeConfigGetBoolean(self.address, 'chan'): self.type = self.CHAN elif shared.safeConfigGetBoolean(self.address, 'mailinglist'): @@ -246,7 +248,8 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): return unicode(self.label, 'utf-8)') def setType(self): - self.type = self.SUBSCRIPTION + super(Ui_SubscriptionWidget, self).setType() # sets it editable + self.type = self.SUBSCRIPTION # overrides type def setData(self, column, role, value): if role == QtCore.Qt.EditRole: -- 2.45.1 From b699475906dea258e9646a784ada69cd73202c2e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 10 Jan 2016 17:46:22 +0100 Subject: [PATCH 0253/1102] Clicks in empty message shouldn't produce an error --- src/bitmessageqt/messageview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 9aa7ae54..36002710 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -26,7 +26,7 @@ class MessageView(QtGui.QTextBrowser): def mousePressEvent(self, event): #text = textCursor.block().text() - if event.button() == QtCore.Qt.LeftButton and self.html.has_html and self.cursorForPosition(event.pos()).block().blockNumber() == 0: + 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: -- 2.45.1 From 43a765515a6fd2ae4a34cb26ea91574ad7efc440 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 12 Jan 2016 16:37:56 +0100 Subject: [PATCH 0254/1102] Remember current search @rainulf What's the reasoning behind resetting the search? Fixes #155 --- src/bitmessageqt/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9ae4e6cd..de2eb9bd 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3903,7 +3903,6 @@ class MyForm(settingsmixin.SMainWindow): searchOption = self.getCurrentSearchOption() if searchLine: searchKeyword = searchLine.text().toUtf8().data() - searchLine.setText(QString("")) messageTextedit = self.getCurrentMessageTextedit() if messageTextedit: messageTextedit.setPlainText(QString("")) -- 2.45.1 From 98fab9c5689d577843ef85257f213b5694c54fcb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 12 Jan 2016 16:49:04 +0100 Subject: [PATCH 0255/1102] Message body focus on reply Fixes #156 --- src/bitmessageqt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index de2eb9bd..95497099 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3093,6 +3093,7 @@ class MyForm(settingsmixin.SMainWindow): else: widget['subject'].setText('Re: ' + tableWidget.item(currentInboxRow, 2).label) self.ui.tabWidget.setCurrentIndex(1) + widget['message'].setFocus() def on_action_InboxAddSenderToAddressBook(self): tableWidget = self.getCurrentMessagelist() -- 2.45.1 From 72f9e299315db47a12ad2133cf188826b8c56224 Mon Sep 17 00:00:00 2001 From: itsexe Date: Wed, 13 Jan 2016 18:34:22 +0100 Subject: [PATCH 0256/1102] fixed some spelling errors --- src/translations/bitmessage_de.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 3e0a2546..87953ee7 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -236,7 +236,7 @@ Es ist wichtig, dass Sie diese Datei sichern. 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? +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.)
@@ -472,7 +472,7 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die datei jetzt öffn Bitmessage cannot find your address %1. Perhaps you removed it? - Bitmassage kann Ihre Adresse %1 nicht finden. Haben Sie sie gelöscht? + Bitmessage kann Ihre Adresse %1 nicht finden. Haben Sie sie gelöscht? @@ -746,7 +746,7 @@ p, li { white-space: pre-wrap; } Network Status - Netzwerk status + Netzwerkstatus @@ -1191,7 +1191,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 zu allen Abbonenten weitergeleitet (Der Inhalt ist dann öffentlich). + Nachrichten an eine Pseudo-Mailinglistenadresse werden automatisch zu allen Abonnenten weitergeleitet (Der Inhalt ist dann öffentlich). -- 2.45.1 From 6a965cd31a34870baef47cf587b9b8220f01d6d9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 17 Jan 2016 14:25:46 +0100 Subject: [PATCH 0257/1102] Don't test for Qt in daemon mode Initialisation of the daemon variable was missing at launch. Fixes #161 --- src/bitmessagemain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index aba251f9..81b8613e 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -266,7 +266,7 @@ class Main: if __name__ == "__main__": mainprogram = Main() - mainprogram.start() + mainprogram.start(shared.safeConfigGetBoolean('bitmessagesettings', 'daemon')) # So far, the creation of and management of the Bitmessage protocol and this -- 2.45.1 From b7e24fab4aa714a38e06755fe2ea65c595267469 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Wed, 20 Jan 2016 22:31:15 +0100 Subject: [PATCH 0258/1102] DLL path fix in frozen mode Addresses #152 --- src/depends.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/depends.py b/src/depends.py index 553a5031..294c6a22 100755 --- a/src/depends.py +++ b/src/depends.py @@ -87,7 +87,7 @@ def check_openssl(): paths = ['libeay32.dll'] if getattr(sys, 'frozen', False): import os.path - paths.append(os.path.join(sys._MEIPASS, 'libeay32.dll')) + paths.insert(0, os.path.join(sys._MEIPASS, 'libeay32.dll')) else: paths = ['libcrypto.so'] if sys.platform == 'darwin': -- 2.45.1 From dc34c00f3883f1ac27f7f091f2dfc3eb83ff6e97 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 21 Jan 2016 17:56:01 +0100 Subject: [PATCH 0259/1102] Improve OpenSSL library finder --- src/pyelliptic/openssl.py | 69 ++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index c6b72b65..442f5888 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -427,35 +427,44 @@ class _OpenSSL: buffer = self.create_string_buffer(size) return buffer -try: - OpenSSL = _OpenSSL('libcrypto.so') -except: - try: - OpenSSL = _OpenSSL('libeay32.dll') - except: +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.0.0.dylib') + ]) + elif 'win32' in sys.platform or win64: + lib.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.0.0'), + path.join(sys._MEIPASS, 'libssl.so.1.0.0'), + ]) + 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 'freebsd' 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.dylib') + OpenSSL = _OpenSSL(library) + return except: - 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.") + pass + raise Exception("Couldn't find and load the OpenSSL library. You must install it.") + +loadOpenSSL() \ No newline at end of file -- 2.45.1 From c137e334d227a7956b2b3949ea2d440899b4814e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 21 Jan 2016 17:57:00 +0100 Subject: [PATCH 0260/1102] OpenSSL version for support contact form --- src/bitmessageqt/support.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 6683756b..2c78ea32 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -1,5 +1,6 @@ import ctypes from PyQt4 import QtCore, QtGui +import ssl import sys import time @@ -10,6 +11,7 @@ from helper_sql import * from l10n import getTranslationLanguage from openclpow import has_opencl from proofofwork import bmpow +from pyelliptic.openssl import OpenSSL import shared # this is BM support address going to Peter Surda @@ -32,6 +34,8 @@ Please write above this line and if possible, keep the information about your en PyBitmesage version: {} Operating system: {} Architecture: {}bit +Python Version: {} +OpenSSL Version: {} Frozen: {} Portable mode: {} C PoW: {} @@ -89,6 +93,14 @@ def createSupportMessage(myapp): except: pass architecture = "32" if ctypes.sizeof(ctypes.c_voidp) == 4 else "64" + pythonversion = sys.version + + SSLEAY_VERSION = 0 + OpenSSL._lib.SSLeay.restype = ctypes.c_long + OpenSSL._lib.SSLeay_version.restype = ctypes.c_char_p + OpenSSL._lib.SSLeay_version.argtypes = [ctypes.c_int] + opensslversion = "%s (Python internal), %s (external for PyElliptic)" % (ssl.OPENSSL_VERSION, OpenSSL._lib.SSLeay_version(SSLEAY_VERSION)) + frozen = "N/A" if shared.frozen: frozen = shared.frozen @@ -108,7 +120,7 @@ def createSupportMessage(myapp): upnp = "N/A" connectedhosts = len(shared.connectedHostsList) - myapp.ui.textEditMessage.setText(str(QtGui.QApplication.translate("Support", SUPPORT_MESSAGE)).format(version, os, architecture, frozen, portablemode, cpow, openclpow, locale, socks, upnp, connectedhosts)) + 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(0) -- 2.45.1 From a0da175d45704c5ec244533cccea3b9766e85b9a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 21 Jan 2016 18:03:15 +0100 Subject: [PATCH 0261/1102] Typo --- src/pyelliptic/openssl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 442f5888..85a92f4e 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -439,7 +439,7 @@ def loadOpenSSL(): path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.dylib'), path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.0.dylib') ]) - elif 'win32' in sys.platform or win64: + elif 'win32' in sys.platform or 'win64' in sys.platform: lib.append(path.join(sys._MEIPASS, 'libeay32.dll')) else: libdir.extend([ -- 2.45.1 From 2043d796dd456004918875381cb43b59eb553926 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Thu, 21 Jan 2016 18:13:04 +0100 Subject: [PATCH 0262/1102] Typo --- src/pyelliptic/openssl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyelliptic/openssl.py b/src/pyelliptic/openssl.py index 85a92f4e..be2f2afc 100644 --- a/src/pyelliptic/openssl.py +++ b/src/pyelliptic/openssl.py @@ -440,7 +440,7 @@ def loadOpenSSL(): path.join(environ['RESOURCEPATH'], '..', 'Frameworks','libcrypto.1.0.0.dylib') ]) elif 'win32' in sys.platform or 'win64' in sys.platform: - lib.append(path.join(sys._MEIPASS, 'libeay32.dll')) + libdir.append(path.join(sys._MEIPASS, 'libeay32.dll')) else: libdir.extend([ path.join(sys._MEIPASS, 'libcrypto.so'), -- 2.45.1 From e4f31d25fc76cc9ad890295ce5e078f4283e0094 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 22 Jan 2016 11:17:10 +0100 Subject: [PATCH 0263/1102] Flood mitigation optimisation Flood mitigation was done both in the ObjectProcessorQueue as well as receiveData threads. This patch removes the mitigation in receiveData threads and cleans up the one in the ObjectProcessorQueue --- src/bitmessageqt/__init__.py | 4 +--- src/class_objectProcessor.py | 15 ++++--------- src/class_receiveDataThread.py | 2 +- src/shared.py | 39 ++++++---------------------------- 4 files changed, 13 insertions(+), 47 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 95497099..753864a3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2503,9 +2503,7 @@ class MyForm(settingsmixin.SMainWindow): for row in queryreturn: payload, = row objectType = 3 - with shared.objectProcessorQueueSizeLock: - shared.objectProcessorQueueSize += len(payload) - shared.objectProcessorQueue.put((objectType,payload)) + shared.objectProcessorQueue.put((objectType,payload)) def click_pushButtonStatusIcon(self): logger.debug('click_pushButtonStatusIcon') diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index f7b0e893..48e90a22 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -39,11 +39,9 @@ class objectProcessor(threading.Thread): """ queryreturn = sqlQuery( '''SELECT objecttype, data FROM objectprocessorqueue''') - with shared.objectProcessorQueueSizeLock: - for row in queryreturn: - objectType, data = row - shared.objectProcessorQueueSize += len(data) - shared.objectProcessorQueue.put((objectType,data)) + for row in queryreturn: + objectType, data = row + shared.objectProcessorQueue.put((objectType,data)) sqlExecute('''DELETE FROM objectprocessorqueue''') logger.debug('Loaded %s objects from disk into the objectProcessorQueue.' % str(len(queryreturn))) @@ -70,19 +68,14 @@ class objectProcessor(threading.Thread): except Exception as e: logger.critical("Critical error within objectProcessorThread: \n%s" % traceback.format_exc()) - 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 shared.objectProcessorQueueSize > 1: + while shared.objectProcessorQueue.curSize > 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)) shared.shutdown = 2 diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 58a54346..59399d7a 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,4 +1,4 @@ -doTimingAttackMitigation = True +doTimingAttackMitigation = False import errno import time diff --git a/src/shared.py b/src/shared.py index 57748962..2414945e 100644 --- a/src/shared.py +++ b/src/shared.py @@ -28,6 +28,7 @@ import traceback # Project imports. from addresses import * +from class_objectProcessorQueue import ObjectProcessorQueue import highlevelcrypto import shared #import helper_startup @@ -50,8 +51,6 @@ 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. @@ -87,8 +86,7 @@ daemon = False inventorySets = {1: set()} # 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 -objectProcessorQueue = Queue.Queue( - ) # receiveDataThreads dump objects they hear on the network into this queue to be processed. +objectProcessorQueue = ObjectProcessorQueue() # receiveDataThreads dump objects they hear on the network into this queue to be processed. streamsInWhichIAmParticipating = {} # sanity check, prevent doing ridiculous PoW @@ -397,10 +395,7 @@ 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)) + objectProcessorQueue.put(('checkShutdownVariable', 'no data')) knownNodesLock.acquire() UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) @@ -751,12 +746,7 @@ def _checkAndShareMsgWithPeers(data): broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. - # 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)) + objectProcessorQueue.put((objectType,data)) def _checkAndShareGetpubkeyWithPeers(data): if len(data) < 42: @@ -798,12 +788,7 @@ def _checkAndShareGetpubkeyWithPeers(data): broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. - # 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)) + objectProcessorQueue.put((objectType,data)) def _checkAndSharePubkeyWithPeers(data): if len(data) < 146 or len(data) > 440: # sanity check @@ -847,12 +832,7 @@ def _checkAndSharePubkeyWithPeers(data): # Now let's queue it to be processed ourselves. - # 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)) + objectProcessorQueue.put((objectType,data)) def _checkAndShareBroadcastWithPeers(data): @@ -896,12 +876,7 @@ def _checkAndShareBroadcastWithPeers(data): broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. - # 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)) + objectProcessorQueue.put((objectType,data)) def openKeysFile(): if 'linux' in sys.platform: -- 2.45.1 From 47f0df6c0bde1934126068ffb19427d4cc36e9a0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 22 Jan 2016 13:49:28 +0100 Subject: [PATCH 0264/1102] Object processor queue class Previous commit didn't include the class. This class takes care of queue size monitoring so that the system doesn't run out of memory. --- src/class_objectProcessorQueue.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/class_objectProcessorQueue.py diff --git a/src/class_objectProcessorQueue.py b/src/class_objectProcessorQueue.py new file mode 100644 index 00000000..6d3d4804 --- /dev/null +++ b/src/class_objectProcessorQueue.py @@ -0,0 +1,28 @@ +import shared + +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 and not shared.shutdown: + time.sleep(1) + if shared.shutdown: + return + with self.sizeLock: + self.curSize += len(item[1]) + Queue.Queue.put(self, item, block, timeout) + + def get(self, block = True, timeout = None): + item = Queue.Queue.get(self, block, timeout) + with self.sizeLock: + self.curSize -= len(item[1]) + return item -- 2.45.1 From ec4a16b388001edce052c8278235fc536d8512f5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 22 Jan 2016 14:12:57 +0100 Subject: [PATCH 0265/1102] objectProcessorQueue fixes - it didn't shutdown correctly - it didn't handle exception correctly (however, if I understand correctly, this will never be triggered if using blocking get, so it doesn't affect PyBitmessage) - flushing size check changed from 1 to 0 (I don't know why it was 1) --- src/class_objectProcessor.py | 2 +- src/class_objectProcessorQueue.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 48e90a22..0035dce9 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -72,7 +72,7 @@ class objectProcessor(threading.Thread): time.sleep(.5) # Wait just a moment for most of the connections to close numberOfObjectsThatWereInTheObjectProcessorQueue = 0 with SqlBulkExecute() as sql: - while shared.objectProcessorQueue.curSize > 1: + while shared.objectProcessorQueue.curSize > 0: objectType, data = shared.objectProcessorQueue.get() sql.execute('''INSERT INTO objectprocessorqueue VALUES (?,?)''', objectType,data) diff --git a/src/class_objectProcessorQueue.py b/src/class_objectProcessorQueue.py index 6d3d4804..9bf3f82a 100644 --- a/src/class_objectProcessorQueue.py +++ b/src/class_objectProcessorQueue.py @@ -13,16 +13,17 @@ class ObjectProcessorQueue(Queue.Queue): 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 and not shared.shutdown: + while self.curSize >= self.maxSize: time.sleep(1) - if shared.shutdown: - return with self.sizeLock: self.curSize += len(item[1]) Queue.Queue.put(self, item, block, timeout) def get(self, block = True, timeout = None): - item = Queue.Queue.get(self, block, timeout) + 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 -- 2.45.1 From 32b0d24be297437cbbad825d9d59566d9e0240e9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 22 Jan 2016 14:47:26 +0100 Subject: [PATCH 0266/1102] singleWorker shutdown fix if singleWorker crashed, the thread couldn't be joined. This both makes it so that it doesn't crash, as well as reorders the shutdown sequence so that it is less likely to be triggered. Fixes Bitmessage#549 --- src/class_singleWorker.py | 25 +++++++++++++------------ src/shared.py | 6 +++--- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 7c04558b..336c5059 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -71,18 +71,19 @@ class singleWorker(threading.Thread, StoppableThread): self.stop.wait( 10) # give some time for the GUI to start before we start on existing POW tasks. - queryreturn = sqlQuery( - '''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') - for row in queryreturn: - toaddress, = row - self.requestPubKey(toaddress) - - 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. + if shared.shutdown == 0: + queryreturn = sqlQuery( + '''SELECT DISTINCT toaddress FROM sent WHERE (status='doingpubkeypow' AND folder='sent')''') + for row in queryreturn: + toaddress, = row + logger.debug("c: %s", shared.shutdown) + self.requestPubKey(toaddress) + # just in case there are any pending tasks for msg + # messages that have yet to be sent. + self.sendMsg() + # just in case there are any tasks for Broadcasts + # that have yet to be sent. + self.sendBroadcast() while shared.shutdown == 0: command, data = shared.workerQueue.get() diff --git a/src/shared.py b/src/shared.py index 2414945e..2a9c3c48 100644 --- a/src/shared.py +++ b/src/shared.py @@ -396,6 +396,9 @@ def doCleanShutdown(): shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) + for thread in threading.enumerate(): + if thread.isAlive() and isinstance(thread, StoppableThread): + thread.stopThread() knownNodesLock.acquire() UISignalQueue.put(('updateStatusBar','Saving the knownNodes list of peers to disk...')) @@ -430,9 +433,6 @@ def doCleanShutdown(): time.sleep(.25) from class_outgoingSynSender import outgoingSynSender - for thread in threading.enumerate(): - if thread.isAlive() and isinstance(thread, StoppableThread): - thread.stopThread() for thread in threading.enumerate(): if thread is not threading.currentThread() and isinstance(thread, StoppableThread) and not isinstance(thread, outgoingSynSender): logger.debug("Waiting for thread %s", thread.name) -- 2.45.1 From 9353e8eff7066a779b19f747ed40c94802e9f36a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 22 Jan 2016 19:16:47 +0100 Subject: [PATCH 0267/1102] Message editor updates - Does not allow changing fonts (it's ignored once it's sent anyway), fixes #167 - Allows zooming, fixes #163 --- src/bitmessageqt/__init__.py | 4 ++-- src/bitmessageqt/bitmessageui.py | 5 +++-- src/bitmessageqt/messagecompose.py | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/bitmessageqt/messagecompose.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 753864a3..4a2c479c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2274,7 +2274,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.comboBoxSendFrom.setCurrentIndex(0) self.ui.lineEditTo.setText('') self.ui.lineEditSubject.setText('') - self.ui.textEditMessage.setText('') + self.ui.textEditMessage.reset() if self.replyFromTab is not None: self.ui.tabWidget.setCurrentIndex(self.replyFromTab) self.replyFromTab = None @@ -2324,7 +2324,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.comboBoxSendFromBroadcast.setCurrentIndex(0) self.ui.lineEditSubjectBroadcast.setText('') - self.ui.textEditMessageBroadcast.setText('') + self.ui.textEditMessageBroadcast.reset() self.ui.tabWidget.setCurrentIndex(1) self.ui.tableWidgetInboxSubscriptions.setCurrentCell(0, 0) self.statusBar().showMessage(_translate( diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 25cb178e..b50fd3fe 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -9,6 +9,7 @@ from PyQt4 import QtCore, QtGui from messageview import MessageView +from messagecompose import MessageCompose import settingsmixin try: @@ -232,7 +233,7 @@ class Ui_MainWindow(object): self.gridLayout_2_Widget = QtGui.QWidget() self.gridLayout_2_Widget.setLayout(self.gridLayout_2) self.verticalSplitter_5.addWidget(self.gridLayout_2_Widget) - self.textEditMessage = QtGui.QTextEdit(self.sendDirect) + self.textEditMessage = MessageCompose(self.sendDirect) self.textEditMessage.setObjectName(_fromUtf8("textEditMessage")) self.verticalSplitter_5.addWidget(self.textEditMessage) self.verticalSplitter_5.setStretchFactor(0, 0) @@ -268,7 +269,7 @@ class Ui_MainWindow(object): self.gridLayout_5_Widget = QtGui.QWidget() self.gridLayout_5_Widget.setLayout(self.gridLayout_5) self.verticalSplitter_6.addWidget(self.gridLayout_5_Widget) - self.textEditMessageBroadcast = QtGui.QTextEdit(self.sendBroadcast) + self.textEditMessageBroadcast = MessageCompose(self.sendBroadcast) self.textEditMessageBroadcast.setObjectName(_fromUtf8("textEditMessageBroadcast")) self.verticalSplitter_6.addWidget(self.textEditMessageBroadcast) self.verticalSplitter_6.setStretchFactor(0, 0) diff --git a/src/bitmessageqt/messagecompose.py b/src/bitmessageqt/messagecompose.py new file mode 100644 index 00000000..5718aa32 --- /dev/null +++ b/src/bitmessageqt/messagecompose.py @@ -0,0 +1,24 @@ +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: + numDegrees = event.delta() / 8 + numSteps = numDegrees / 15 + zoomDiff = numSteps + self.currentFont().pointSize() - self.defaultFontPointSize + if numSteps > 0: + self.zoomIn(numSteps) + else: + self.zoomOut(-numSteps) + QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1").arg(str(zoomDiff))) + # super will actually automatically take care of zooming + super(MessageCompose, self).wheelEvent(event) + + def reset(self): + self.setText('') -- 2.45.1 From 056512a7158e94abaa42fc5532349eb11ab62211 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Fri, 22 Jan 2016 20:21:01 +0100 Subject: [PATCH 0268/1102] Sent folder new message selection fix Fixes Bitmessage#838 --- src/bitmessageqt/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 4a2c479c..83d19a2a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2413,6 +2413,7 @@ class MyForm(settingsmixin.SMainWindow): self.addMessageListItemSent(sent, toAddress, fromAddress, subject, "msgqueued", ackdata, time.time()) self.getAccountTextedit(acct).setPlainText(unicode(message, 'utf-8)', 'replace')) + sent.setCurrentCell(0, 0) def displayNewInboxMessage(self, inventoryHash, toAddress, fromAddress, subject, message): if toAddress == str_broadcast_subscribers: -- 2.45.1 From d36d6f300e44aa3fe006417769eeb519ad0ff147 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 09:53:14 +0100 Subject: [PATCH 0269/1102] Message body display handling of spaces After the changes in the message body renderer, spaces were not correctly handled. Fixes #168 --- src/bitmessageqt/safehtmlparser.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 5cd869bc..c357662d 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -17,20 +17,19 @@ class SafeHTMLParser(HTMLParser): 'small', 'sound', 'source', 'spacer', 'span', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] - replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"]] + replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] @staticmethod def multi_replace(text): for a in SafeHTMLParser.replaces: text = text.replace(a[0], a[1]) + if len(text) > 1 and text[0] == " ": + text = " " + text[1:] return text def __init__(self, *args, **kwargs): HTMLParser.__init__(self, *args, **kwargs) - self.elements = set() - self.sanitised = u"" - self.raw = u"" - self.has_html = False + self.reset_safe() def reset_safe(self): self.elements = set() -- 2.45.1 From 2597ac63f68b855c4c6b2bc63ed54acce084994c Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 09:55:12 +0100 Subject: [PATCH 0270/1102] Zooming info percent based an single step Zooming in message body view / compose works in single steps irrespective of wheel sensitivity, and info about zoom level is displayed in percent rather than font pixel size. --- src/bitmessageqt/messagecompose.py | 12 +++++------- src/bitmessageqt/messageview.py | 8 +++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/bitmessageqt/messagecompose.py b/src/bitmessageqt/messagecompose.py index 5718aa32..ff0849a5 100644 --- a/src/bitmessageqt/messagecompose.py +++ b/src/bitmessageqt/messagecompose.py @@ -9,14 +9,12 @@ class MessageCompose(QtGui.QTextEdit): def wheelEvent(self, event): if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: - numDegrees = event.delta() / 8 - numSteps = numDegrees / 15 - zoomDiff = numSteps + self.currentFont().pointSize() - self.defaultFontPointSize - if numSteps > 0: - self.zoomIn(numSteps) + if event.delta() > 0: + self.zoomIn(1) else: - self.zoomOut(-numSteps) - QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1").arg(str(zoomDiff))) + 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))) # super will actually automatically take care of zooming super(MessageCompose, self).wheelEvent(event) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 36002710..faa21cd2 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -35,13 +35,11 @@ class MessageView(QtGui.QTextBrowser): super(MessageView, self).mousePressEvent(event) def wheelEvent(self, event): - if (QtGui.QApplication.queryKeyboardModifiers() & QtCore.Qt.ControlModifier) == QtCore.Qt.ControlModifier and event.orientation() == QtCore.Qt.Vertical: - numDegrees = event.delta() / 8 - numSteps = numDegrees / 15 - zoomDiff = numSteps + self.currentFont().pointSize() - self.defaultFontPointSize - QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1").arg(str(zoomDiff))) # 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 confirmURL(self, link): reply = QtGui.QMessageBox.warning(self, -- 2.45.1 From 484bdb07820a90f8def212464cb6e28cd17a2990 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 09:56:15 +0100 Subject: [PATCH 0271/1102] Quoting fixes Message compose sometimes misinterpreted quoted message as HTML, causing rendering screwups. Since we don't support HTML composing, we will treat all quoted messages as plain text. --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 83d19a2a..7770b98f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3086,7 +3086,7 @@ class MyForm(settingsmixin.SMainWindow): widget['from'].setCurrentIndex(0) quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) - widget['message'].setText(quotedText) + widget['message'].setPlainText(quotedText) if acct.subject[0:3] in ['Re:', 'RE:']: widget['subject'].setText(tableWidget.item(currentInboxRow, 2).label) else: -- 2.45.1 From a4c48228fc3038be57084fec8ae8f1c69abc1bfd Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 10:14:12 +0100 Subject: [PATCH 0272/1102] Messagelist subscription color Fixes Bitmessage#842 --- src/bitmessageqt/__init__.py | 2 +- src/bitmessageqt/account.py | 1 + src/bitmessageqt/foldertree.py | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7770b98f..fa099954 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1040,7 +1040,7 @@ class MyForm(settingsmixin.SMainWindow): def addMessageListItemInbox(self, tableWidget, msgfolder, msgid, toAddress, fromAddress, subject, received, read): font = QFont() font.setBold(True) - if tableWidget == self.ui.tableWidgetInboxSubscriptions: + if toAddress == str_broadcast_subscribers: acct = accountClass(fromAddress) else: acct = accountClass(toAddress) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index dc21d669..d1afd560 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -40,6 +40,7 @@ def getSortedSubscriptions(count = False): def accountClass(address): if not shared.config.has_section(address): + # FIXME: This BROADCAST section makes no sense if address == str_broadcast_subscribers: subscription = BroadcastAccount(address) if subscription.type != AccountMixin.BROADCAST: diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 19d5dc12..a9369a48 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -69,6 +69,9 @@ class AccountMixin (object): self.type = self.CHAN elif shared.safeConfigGetBoolean(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 -- 2.45.1 From e6c379cca6bd7be8635fb9f0f3350af322f2bf0e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 12:21:58 +0100 Subject: [PATCH 0273/1102] Scroll/zoom in message composing widget Fixes #169 --- src/bitmessageqt/messagecompose.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/messagecompose.py b/src/bitmessageqt/messagecompose.py index ff0849a5..f7d5dac3 100644 --- a/src/bitmessageqt/messagecompose.py +++ b/src/bitmessageqt/messagecompose.py @@ -15,8 +15,9 @@ class MessageCompose(QtGui.QTextEdit): 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))) - # super will actually automatically take care of zooming - super(MessageCompose, self).wheelEvent(event) + else: + # in QTextEdit, super does not zoom, only scroll + super(MessageCompose, self).wheelEvent(event) def reset(self): self.setText('') -- 2.45.1 From f159133f141cf26d2cc895db6df401c41ae0020b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 20:24:50 +0100 Subject: [PATCH 0274/1102] TreeWidget and Addressbook editing propagation If you change, add or remove an item in a treewidget or addressbook, messagelists will now autoupdate labels, and sender comboboxes will also update if applicable. Fixes #69 --- src/api.py | 16 +-- src/bitmessageqt/__init__.py | 196 +++++++++------------------------ src/bitmessageqt/foldertree.py | 85 +++++++++++--- 3 files changed, 131 insertions(+), 166 deletions(-) diff --git a/src/api.py b/src/api.py index 7c355941..968fb29d 100644 --- a/src/api.py +++ b/src/api.py @@ -211,8 +211,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You already have this address in your address book.') sqlExecute("INSERT INTO addressbook VALUES(?,?)", label, address) - shared.UISignalQueue.put(('rerenderInboxFromLabels','')) - shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.UISignalQueue.put(('rerenderAddressBook','')) return "Added address %s to address book" % address @@ -223,8 +223,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) self._verifyAddress(address) sqlExecute('DELETE FROM addressbook WHERE address=?', address) - shared.UISignalQueue.put(('rerenderInboxFromLabels','')) - shared.UISignalQueue.put(('rerenderSentToLabels','')) + shared.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.UISignalQueue.put(('rerenderAddressBook','')) return "Deleted address book entry for %s if it existed" % address @@ -462,8 +462,8 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): 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.UISignalQueue.put(('rerenderMessagelistFromLabels','')) + shared.UISignalQueue.put(('rerenderMessagelistToLabels','')) shared.reloadMyAddressHashes() return 'success' @@ -793,7 +793,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): raise APIError(16, 'You are already subscribed to that address.') sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',label, address, True) shared.reloadBroadcastSendersForWhichImWatching() - shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) + shared.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Added subscription.' @@ -804,7 +804,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): address = addBMIfNotPresent(address) sqlExecute('''DELETE FROM subscriptions WHERE address=?''', address) shared.reloadBroadcastSendersForWhichImWatching() - shared.UISignalQueue.put(('rerenderInboxFromLabels', '')) + shared.UISignalQueue.put(('rerenderMessagelistFromLabels', '')) shared.UISignalQueue.put(('rerenderSubscriptions', '')) return 'Deleted subscription if it existed.' diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fa099954..eeeb1526 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -763,9 +763,9 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "changedInboxUnread(PyQt_PyObject)"), self.changedInboxUnread) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderInboxFromLabels()"), self.rerenderInboxFromLabels) + "rerenderMessagelistFromLabels()"), self.rerenderMessagelistFromLabels) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderSentToLabels()"), self.rerenderSentToLabels) + "rerenderMessgelistToLabels()"), self.rerenderMessagelistToLabels) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "rerenderAddressBook()"), self.rerenderAddressBook) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -1963,142 +1963,65 @@ class MyForm(settingsmixin.SMainWindow): if exitAfterUserClicksOk: os._exit(0) - def rerenderInboxFromLabels(self): - return - for i in range(self.ui.tableWidgetInbox.rowCount()): - addressToLookup = self.ui.tableWidgetInbox.item( - i, 1).data(Qt.UserRole) - fromLabel = '' - queryreturn = sqlQuery( - '''select label from addressbook where address=?''', addressToLookup) + 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() - 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): - return - for i in range(self.ui.tableWidgetInbox.rowCount()): - toAddress = self.ui.tableWidgetInbox.item( - i, 0).data(Qt.UserRole) - # 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): - return - for i in range(self.ui.tableWidgetInbox.rowCount()): - fromAddress = self.ui.tableWidgetInbox.item( - i, 1).data(Qt.UserRole) - # 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.tableWidgetInbox.item( - i, 1).setText(unicode(fromLabel, 'utf-8')) - self.ui.tableWidgetInbox.item( - i, 1).setIcon(avatarize(fromAddress)) - - def rerenderSentToLabels(self): - return - for i in range(self.ui.tableWidgetInbox.rowCount()): - addressToLookup = self.ui.tableWidgetInbox.item( - i, 0).data(Qt.UserRole) - 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.tableWidgetInbox.item( - i, 0).setText(unicode(toLabel, 'utf-8')) + 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() def rerenderAddressBook(self): def addRow (address, label, type): self.ui.tableWidgetAddressBook.insertRow(0) newItem = Ui_AddressBookWidgetItemLabel(address, unicode(label, 'utf-8'), type) - newItem.setData(Qt.UserRole, type) self.ui.tableWidgetAddressBook.setItem(0, 0, newItem) newItem = Ui_AddressBookWidgetItemAddress(address, unicode(label, 'utf-8'), type) self.ui.tableWidgetAddressBook.setItem(0, 1, newItem) - - self.ui.tableWidgetAddressBook.setSortingEnabled(False) - self.ui.tableWidgetAddressBook.setRowCount(0) + 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, 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 - addRow(address, label, AccountMixin.SUBSCRIPTION) - + newRows[address] = [label, AccountMixin.SUBSCRIPTION] # chans addresses = getSortedAccounts() for address in addresses: account = accountClass(address) if (account.type == AccountMixin.CHAN and shared.safeConfigGetBoolean(address, 'enabled')): - addRow(address, account.getLabel(), AccountMixin.CHAN) - + newRows[address] = [account.getLabel(), AccountMixin.CHAN] # normal accounts queryreturn = sqlQuery('SELECT * FROM addressbook') for row in queryreturn: label, address = row - addRow(address, label, AccountMixin.NORMAL) + newRows[address] = [label, AccountMixin.NORMAL] + + for address in sorted(oldRows, key = lambda x: oldRows[x][2], reverse = True): + if address in newRows: + newRows.pop(address) + else: + self.ui.tableWidgetAddressBook.removeRow(oldRows[address][2]) + for address in newRows: + addRow(address, newRows[address][0], newRows[address][1]) # sort - self.ui.tableWidgetAddressBook.sortItems(0, QtCore.Qt.AscendingOrder) + self.ui.tableWidgetAddressBook.sortByColumn(0, Qt.AscendingOrder) self.ui.tableWidgetAddressBook.setSortingEnabled(True) + def rerenderSubscriptions(self): self.rerenderTabTreeSubscriptions() @@ -2459,9 +2382,9 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''select * from addressbook where address=?''', address) if queryreturn == []: sqlExecute('''INSERT INTO addressbook VALUES (?,?)''', str(label), address) + self.rerenderMessagelistFromLabels() + self.rerenderMessagelistToLabels() self.rerenderAddressBook() - 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.")) @@ -2473,7 +2396,7 @@ class MyForm(settingsmixin.SMainWindow): return #Add to database (perhaps this should be separated from the MyForm class) sqlExecute('''INSERT INTO subscriptions VALUES (?,?,?)''',str(label),address,True) - self.rerenderInboxFromLabels() + self.rerenderMessagelistFromLabels() shared.reloadBroadcastSendersForWhichImWatching() self.rerenderAddressBook() self.rerenderTabTreeSubscriptions() @@ -2818,7 +2741,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() shared.writeKeysFile() - self.rerenderInboxToLabels() + self.rerenderMessagelistToLabels() def on_action_EmailGatewayDialog(self): self.dialog = EmailGatewayDialog(self) @@ -3291,8 +3214,8 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''DELETE FROM addressbook WHERE label=? AND address=?''', str(labelAtCurrentRow), str(addressAtCurrentRow)) self.ui.tableWidgetAddressBook.removeRow(currentRow) - self.rerenderInboxFromLabels() - self.rerenderSentToLabels() + self.rerenderMessagelistFromLabels() + self.rerenderMessagelistToLabels() def on_action_AddressBookClipboard(self): fullStringOfAddresses = '' @@ -3376,7 +3299,7 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''DELETE FROM subscriptions WHERE address=?''', address) self.rerenderTabTreeSubscriptions() - self.rerenderInboxFromLabels() + self.rerenderMessagelistFromLabels() self.rerenderAddressBook() shared.reloadBroadcastSendersForWhichImWatching() @@ -3402,7 +3325,7 @@ class MyForm(settingsmixin.SMainWindow): address) account = self.getCurrentItem() account.setEnabled(False) - self.rerenderAddressBook() + self.rerenderAddressBook(address) shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): @@ -3801,10 +3724,8 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderTabTreeChans() self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - self.rerenderInboxFromLabels() - self.rerenderInboxToLabels() - self.rerenderSentFromLabels() - self.rerenderSentToLabels() + self.rerenderMessagelistFromLabels() + self.rerenderMessagelistToLabels() self.rerenderBlackWhiteList() # generate identicon return False @@ -3953,12 +3874,13 @@ class MyForm(settingsmixin.SMainWindow): return self.recurDepth += 1 - item.setData(0, QtCore.Qt.EditRole, newLabel) - item.updateText() - if item.type == AccountMixin.MAILINGLIST: + if item.type == AccountMixin.NORMAL or item.type == AccountMixin.MAILINGLIST: self.rerenderComboBoxSendFromBroadcast() - elif item.type != AccountMixin.SUBSCRIPTION: + if item.type == AccountMixin.NORMAL or item.type == AccountMixin.CHAN: self.rerenderComboBoxSendFrom() + self.rerenderMessagelistFromLabels() + if item.type != AccountMixin.SUBSCRIPTION: + self.rerenderMessagelistToLabels() self.recurDepth -= 1 def tableWidgetInboxItemClicked(self): @@ -4014,16 +3936,8 @@ class MyForm(settingsmixin.SMainWindow): messageTextedit.setContent(message) 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.ui.tableWidgetAddressBook.item(currentRow, 0).setLabel(str(self.ui.tableWidgetAddressBook.item(currentRow, 0).text().toUtf8())) - self.rerenderInboxFromLabels() - self.rerenderSentToLabels() + self.rerenderMessagelistFromLabels() + self.rerenderMessagelistToLabels() def writeNewAddressToTable(self, label, address, streamNumber): self.rerenderTabTreeMessages() @@ -4563,10 +4477,10 @@ class UISignaler(QThread): 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 == 'rerenderMessagelistFromLabels': + self.emit(SIGNAL("rerenderMessagelistFromLabels()")) + elif command == 'rerenderMessagelistToLabels': + self.emit(SIGNAL("rerenderMessagelistToLabels()")) elif command == 'rerenderAddressBook': self.emit(SIGNAL("rerenderAddressBook()")) elif command == 'rerenderSubscriptions': diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index a9369a48..efde3466 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -190,10 +190,12 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): return super(Ui_AddressWidget, self).data(column, role) def setData(self, column, role, value): - if role == QtCore.Qt.EditRole: - shared.config.set(str(self.address), 'label', str(value.toString())) + if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: + if isinstance(value, QtCore.QVariant): + shared.config.set(str(self.address), 'label', str(value.toString())) + else: + shared.config.set(str(self.address), 'label', str(value)) shared.writeKeysFile() - return return super(Ui_AddressWidget, self).setData(column, role, value) def setAddress(self, address): @@ -203,7 +205,6 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def updateText(self): if not self.initialised: return - self.emitDataChanged() def setExpanded(self, expand): super(Ui_AddressWidget, self).setExpanded(expand) @@ -252,21 +253,22 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setType(self): super(Ui_SubscriptionWidget, self).setType() # sets it editable - self.type = self.SUBSCRIPTION # overrides type + self.type = AccountMixin.SUBSCRIPTION # overrides type def setData(self, column, role, value): if role == QtCore.Qt.EditRole: - self.setLabel(str(value.toString())) + if isinstance(value, QtCore.QVariant): + self.setLabel(str(value.toString())) + else: + self.setLabel(str(value)) sqlExecute( '''UPDATE subscriptions SET label=? WHERE address=?''', self.label, self.address) - return return super(Ui_SubscriptionWidget, self).setData(column, role, value) def updateText(self): if not self.initialised: return - self.emitDataChanged() class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMixin): @@ -286,10 +288,27 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi parent.append(self) def setLabel(self, label = None): + newLabel = self.address if label is None: - label = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + queryreturn = None + if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): + try: + newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + 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, = row else: - self.label = label + newLabel = label + if hasattr(self, 'label') and newLabel == self.label: + return + self.label = newLabel def setUnread(self, unread): self.unread = unread @@ -320,7 +339,6 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi def setData(self, role, value): if role == QtCore.Qt.EditRole: self.setLabel() - return return super(MessageList_AddressWidget, self).setData(role, value) # label (or address) alphabetically, disabled at the end @@ -382,7 +400,44 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): self.label = text self.type = type self.setEnabled(True) - self.setForeground(self.accountBrush()) + + 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 shared.safeConfigGetBoolean('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 and self.type in [AccountMixin.NORMAL, AccountMixin.MAILINGLIST]: + if isinstance(value, QtCore.QVariant): + self.label = str(value.toString()) + else: + self.label = str(value) + if self.type == AccountMixin.NORMAL or self.type == AccountMixin.MAILINGLIST: + sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label ,self.address) + elif self.type == AccountMixin.SUBSCRIPTION: + pass + elif self.type == AccountMixin.CHAN: + pass + else: + pass + return super(Ui_AddressBookWidgetItem, self).setData(role, value) def __lt__ (self, other): if (isinstance(other, Ui_AddressBookWidgetItem)): @@ -401,16 +456,12 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): Ui_AddressBookWidgetItem.__init__(self, label, type) self.address = address self.label = label - self.setIcon(avatarize(address)) - self.setToolTip(label + " (" + address + ")") def setLabel(self, label): self.label = label - self.setToolTip(self.label + " (" + self.address + ")") class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): Ui_AddressBookWidgetItem.__init__(self, address, type) - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.setToolTip(label + " (" + address + ")") \ No newline at end of file + self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) \ No newline at end of file -- 2.45.1 From 4e4da254fa89e01dc23a040a9c173c486c328640 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 23 Jan 2016 22:18:07 +0100 Subject: [PATCH 0275/1102] Addressbook / Tree / Messagelist rendering Some changes that didn't propagate correctly before now do. Addresses #76 --- src/bitmessageqt/__init__.py | 12 ++++--- src/bitmessageqt/foldertree.py | 62 +++++++++++++++++++++++++--------- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index eeeb1526..9a245a77 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3861,10 +3861,8 @@ class MyForm(settingsmixin.SMainWindow): return newLabel = str(item.text(0)) - if item.type == AccountMixin.SUBSCRIPTION: - oldLabel = item.label - else: - oldLabel = shared.config.get(str(item.address), 'label') + oldLabel = item.defaultLabel() + # unchanged, do not do anything either if newLabel == oldLabel: return @@ -3881,6 +3879,8 @@ class MyForm(settingsmixin.SMainWindow): 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 tableWidgetInboxItemClicked(self): @@ -3935,7 +3935,9 @@ class MyForm(settingsmixin.SMainWindow): messageTextedit.setTextColor(QtGui.QColor()) messageTextedit.setContent(message) - def tableWidgetAddressBookItemChanged(self): + def tableWidgetAddressBookItemChanged(self, item): + if item.type == AccountMixin.CHAN: + self.rerenderComboBoxSendFrom() self.rerenderMessagelistFromLabels() self.rerenderMessagelistToLabels() diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index efde3466..8ddf711a 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -74,6 +74,30 @@ class AccountMixin (object): 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(shared.config.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(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') + if retval is None: + return unicode(self.address, 'utf-8') + else: + return retval def updateText(self): pass @@ -241,15 +265,17 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): self.setAddress(address) self.setEnabled(enabled) self.setType() - self.setLabel(label) self.initialised = True self.setUnreadCount (unreadCount) # does updateText - def setLabel(self, label): - self.label = label - def _getLabel(self): - return unicode(self.label, 'utf-8)') + queryreturn = sqlQuery( + '''select label from subscriptions where address=?''', self.address) + if queryreturn != []: + for row in queryreturn: + retval, = row + return unicode(retval, 'utf-8') + return unicode(self.address, 'utf-8') def setType(self): super(Ui_SubscriptionWidget, self).setType() # sets it editable @@ -258,12 +284,12 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setData(self, column, role, value): if role == QtCore.Qt.EditRole: if isinstance(value, QtCore.QVariant): - self.setLabel(str(value.toString())) + label = str(value.toString()) else: - self.setLabel(str(value)) + label = str(value) sqlExecute( '''UPDATE subscriptions SET label=? WHERE address=?''', - self.label, self.address) + label, self.address) return super(Ui_SubscriptionWidget, self).setData(column, role, value) def updateText(self): @@ -424,17 +450,20 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): return super(Ui_AddressBookWidgetItem, self).data(role) def setData(self, role, value): - if role == QtCore.Qt.EditRole and self.type in [AccountMixin.NORMAL, AccountMixin.MAILINGLIST]: + if role == QtCore.Qt.EditRole: if isinstance(value, QtCore.QVariant): self.label = str(value.toString()) else: self.label = str(value) - if self.type == AccountMixin.NORMAL or self.type == AccountMixin.MAILINGLIST: - sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label ,self.address) + if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): + try: + a = shared.config.get(self.address, 'label') + shared.config.set(self.address, 'label', self.label) + except: + sqlExecute('''UPDATE addressbook set label=? WHERE address=?''', self.label, self.address) elif self.type == AccountMixin.SUBSCRIPTION: - pass - elif self.type == AccountMixin.CHAN: - pass + 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) @@ -457,8 +486,9 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): self.address = address self.label = label - def setLabel(self, label): - self.label = label + def data(self, role): + self.label = self.defaultLabel() + return super(Ui_AddressBookWidgetItemLabel, self).data(role) class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): -- 2.45.1 From aae5b713b1f6e3c06399c82d000f4a380552e089 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 01:16:00 +0100 Subject: [PATCH 0276/1102] Disabling subscriptions should rerender addressbook Addresses #76 --- src/bitmessageqt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9a245a77..cf697a5d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3325,7 +3325,7 @@ class MyForm(settingsmixin.SMainWindow): address) account = self.getCurrentItem() account.setEnabled(False) - self.rerenderAddressBook(address) + self.rerenderAddressBook() shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): -- 2.45.1 From f5187e16a098f0c9d61c290862017153bb0ea8a9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 10:55:08 +0100 Subject: [PATCH 0277/1102] BlackWhitelist rerendering It used to show entries with no address. Fixes #170 --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cf697a5d..a23ecbb2 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2032,6 +2032,7 @@ class MyForm(settingsmixin.SMainWindow): queryreturn = sqlQuery('''SELECT label, address, enabled FROM blacklist''') else: queryreturn = sqlQuery('''SELECT label, address, enabled FROM whitelist''') + self.ui.tableWidgetBlacklist.setSortingEnabled(False) for row in queryreturn: label, address, enabled = row self.ui.tableWidgetBlacklist.insertRow(0) @@ -2046,6 +2047,7 @@ class MyForm(settingsmixin.SMainWindow): if not enabled: newItem.setTextColor(QtGui.QColor(128, 128, 128)) self.ui.tableWidgetBlacklist.setItem(0, 1, newItem) + self.ui.tableWidgetBlacklist.setSortingEnabled(True) def click_pushButtonTTL(self): QtGui.QMessageBox.information(self, 'Time To Live', _translate( -- 2.45.1 From 1cc4fac7f491a29004a98f75809b368c2a2d93dc Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 12:16:41 +0100 Subject: [PATCH 0278/1102] Unread count cleanup Addresses #128 --- src/bitmessageqt/__init__.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a23ecbb2..0e7e02a3 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1929,7 +1929,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Message trashed")) treeWidget = self.widgetConvert(inbox) - self.propagateUnreadCount(inbox.item(i, 1 if inbox == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder(treeWidget), treeWidget, 0) + self.propagateUnreadCount(inbox.item(i, 1 if inbox.item(i, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder(treeWidget), treeWidget, 0) inbox.removeRow(i) break @@ -2901,7 +2901,7 @@ class MyForm(settingsmixin.SMainWindow): if inventoryHashToMarkUnread in inventoryHashesToMarkUnread: # it returns columns as separate items, so we skip dupes continue - if not tableWidget.item(currentRow, 0).font().bold(): + if not tableWidget.item(currentRow, 0).unread: modified += 1 inventoryHashesToMarkUnread.append(inventoryHashToMarkUnread) tableWidget.item(currentRow, 0).setUnread(True) @@ -2913,9 +2913,9 @@ class MyForm(settingsmixin.SMainWindow): "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) if modified == 1: # performance optimisation - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder()) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder()) else: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder(), self.getCurrentTreeWidget(), 0) # tableWidget.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. @@ -3083,10 +3083,10 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''DELETE FROM inbox WHERE msgid=?''', inventoryHashToTrash) else: sqlExecute('''UPDATE inbox SET folder='trash' WHERE msgid=?''', inventoryHashToTrash) - if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + if tableWidget.item(currentRow, 0).unread: + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) if folder != "trash" and not shifted: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), 1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) @@ -3108,9 +3108,9 @@ class MyForm(settingsmixin.SMainWindow): inventoryHashToTrash = str(tableWidget.item( currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) - if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) + if tableWidget.item(currentRow, 0).unread: + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3168,8 +3168,8 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''DELETE FROM sent WHERE ackdata=?''', ackdataToTrash) else: sqlExecute('''UPDATE sent SET folder='trash' WHERE ackdata=?''', ackdataToTrash) - if tableWidget.item(currentRow, 0).font().bold(): - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + if tableWidget.item(currentRow, 0).unread: + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setPlainText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3906,20 +3906,24 @@ class MyForm(settingsmixin.SMainWindow): if queryreturn != []: refresh = False + propagate = False + tableWidget = self.getCurrentMessagelist() + currentRow = tableWidget.currentRow() for row in queryreturn: message, read = row if folder != 'sent' and read == 0: markread = sqlQuery( '''UPDATE inbox SET read = 1 WHERE msgid = ?''', msgid) + refresh = propagate = True + elif tableWidget.item(currentRow, 0).unread == True: refresh = True + propagate = False if refresh: - tableWidget = self.getCurrentMessagelist() if not tableWidget: return font = QFont() font.setBold(False) # inventoryHashesToMarkRead = [] - currentRow = tableWidget.currentRow() # inventoryHashToMarkRead = str(tableWidget.item( # currentRow, 3).data(Qt.UserRole).toPyObject()) # inventoryHashesToMarkRead.append(inventoryHashToMarkRead) @@ -3927,7 +3931,8 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 1).setUnread(False) tableWidget.item(currentRow, 2).setUnread(False) tableWidget.item(currentRow, 3).setFont(font) - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget == self.ui.tableWidgetInboxSubscriptions else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + if propagate: + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) else: data = self.getCurrentMessageId() -- 2.45.1 From 2dc230db9000f536da02a72798a087e58207030e Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 18:21:15 +0100 Subject: [PATCH 0279/1102] Tree rerendering cleanup Fixes #76 --- src/bitmessageqt/foldertree.py | 69 ++++++++++++---------------------- 1 file changed, 23 insertions(+), 46 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 8ddf711a..6fbe2ec0 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -24,7 +24,7 @@ class AccountMixin (object): return QtGui.QApplication.palette().text().color() def folderColor (self): - if not self.parent.isEnabled: + if not self.parent().isEnabled: return QtGui.QColor(128, 128, 128) else: return QtGui.QApplication.palette().text().color() @@ -44,11 +44,9 @@ class AccountMixin (object): self.address = None else: self.address = str(address) - self.updateText() def setUnreadCount(self, cnt): self.unreadCount = int(cnt) - self.updateText() def setEnabled(self, enabled): self.isEnabled = enabled @@ -58,7 +56,8 @@ class AccountMixin (object): for i in range(self.childCount()): if isinstance(self.child(i), Ui_FolderWidget): self.child(i).setEnabled(enabled) - self.updateText() + if isinstance(self, QtGui.QTreeWidgetItem) + self.emitDataChanged() def setType(self): self.setFlags(self.flags() | QtCore.Qt.ItemIsEditable) @@ -98,44 +97,37 @@ class AccountMixin (object): return unicode(self.address, 'utf-8') else: return retval - - def updateText(self): - pass 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.initialised = False self.setAddress(address) self.setFolderName(folderName) self.setUnreadCount(unreadCount) - self.parent = parent - self.initialised = True - self.updateText() parent.insertChild(pos, self) def setFolderName(self, fname): self.folderName = str(fname) - self.setData(0, QtCore.Qt.UserRole, self.folderName) - self.updateText() - def updateText(self): - if not self.initialised: - return - text = QtGui.QApplication.translate("MainWindow", self.folderName) - font = QtGui.QFont() - if self.unreadCount > 0: - text += " (" + str(self.unreadCount) + ")" - font.setBold(True) - else: - font.setBold(False) - self.setFont(0, font) - self.setForeground(0, self.folderBrush()) - self.setText(0, text) - self.setToolTip(0, text) - # self.setData(0, QtCore.Qt.UserRole, [self.address, self.folderName]) + def data(self, column, role): + if column == 0: + if role == QtCore.Qt.DisplayRole: + return QtGui.QApplication.translate("MainWindow", self.folderName) + (" (" + str(self.unreadCount) + ")" if self.unreadCount > 0 else "") + elif role == QtCore.Qt.EditRole: + return QtGui.QApplication.translate("MainWindow", self.folderName) + elif role == QtCore.Qt.ToolTipRole: + return QtGui.QApplication.translate("MainWindow", self.folderName) + elif role == QtCore.Qt.DecorationRole: + pass + 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): @@ -165,12 +157,10 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) - self.initialised = False self.setAddress(address) self.setEnabled(enabled) self.setUnreadCount(unreadCount) - self.initialised = True - self.setType() # does updateText + self.setType() def _getLabel(self): if self.address is None: @@ -226,13 +216,8 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): super(Ui_AddressWidget, self).setAddress(address) self.setData(0, QtCore.Qt.UserRole, self.address) - def updateText(self): - if not self.initialised: - return - def setExpanded(self, expand): super(Ui_AddressWidget, self).setExpanded(expand) - self.updateText() def _getSortRank(self): ret = self.type @@ -261,12 +246,10 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) - self.initialised = False self.setAddress(address) self.setEnabled(enabled) self.setType() - self.initialised = True - self.setUnreadCount (unreadCount) # does updateText + self.setUnreadCount(unreadCount) def _getLabel(self): queryreturn = sqlQuery( @@ -291,10 +274,6 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): '''UPDATE subscriptions SET label=? WHERE address=?''', label, self.address) return super(Ui_SubscriptionWidget, self).setData(column, role, value) - - def updateText(self): - if not self.initialised: - return class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMixin): @@ -303,14 +282,12 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi #parent.insertTopLevelItem(pos, self) # only set default when creating #super(QtGui.QTreeWidgetItem, self).setExpanded(shared.config.getboolean(self.address, 'enabled')) - self.initialised = False self.isEnabled = True self.setAddress(address) self.setLabel(label) self.setUnread(unread) self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - self.initialised = True - self.setType() # does updateText + self.setType() parent.append(self) def setLabel(self, label = None): -- 2.45.1 From 7c9989924826865f596ca92c25a0aa12a2346634 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 18:23:06 +0100 Subject: [PATCH 0280/1102] updateText was deleted so no need to call it --- src/bitmessageqt/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 0e7e02a3..d70a21a5 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2764,7 +2764,6 @@ class MyForm(settingsmixin.SMainWindow): acct.register(email) shared.config.set(addressAtCurrentRow, 'label', email) shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') - self.getCurrentTreeWidget().currentItem().updateText() shared.writeKeysFile() else: pass -- 2.45.1 From 66e1a26b33e37812cc45b7659e7e2ba77bcd5686 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 18:25:09 +0100 Subject: [PATCH 0281/1102] Popup menu on folders There are no functions associated with it but sometimes it popped up so disable it. --- src/bitmessageqt/__init__.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index d70a21a5..286bc75a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3330,11 +3330,14 @@ class MyForm(settingsmixin.SMainWindow): shared.reloadBroadcastSendersForWhichImWatching() def on_context_menuSubscriptions(self, point): + currentItem = self.getCurrentItem() + if not isinstance(currentItem, Ui_AddressWidget): + return self.popMenuSubscriptions = QtGui.QMenu(self) self.popMenuSubscriptions.addAction(self.actionsubscriptionsNew) self.popMenuSubscriptions.addAction(self.actionsubscriptionsDelete) self.popMenuSubscriptions.addSeparator() - if self.getCurrentItem().isEnabled: + if currentItem.isEnabled: self.popMenuSubscriptions.addAction(self.actionsubscriptionsDisable) else: self.popMenuSubscriptions.addAction(self.actionsubscriptionsEnable) @@ -3734,12 +3737,15 @@ class MyForm(settingsmixin.SMainWindow): return True def on_context_menuYourIdentities(self, point): + currentItem = self.getCurrentItem() + if not isinstance(currentItem, Ui_AddressWidget): + return self.popMenuYourIdentities = QtGui.QMenu(self) self.popMenuYourIdentities.addAction(self.actionNewYourIdentities) self.popMenuYourIdentities.addSeparator() self.popMenuYourIdentities.addAction(self.actionClipboardYourIdentities) self.popMenuYourIdentities.addSeparator() - if self.getCurrentItem().isEnabled: + if currentItem.isEnabled: self.popMenuYourIdentities.addAction(self.actionDisableYourIdentities) else: self.popMenuYourIdentities.addAction(self.actionEnableYourIdentities) @@ -3751,13 +3757,16 @@ class MyForm(settingsmixin.SMainWindow): # TODO make one popMenu def on_context_menuChan(self, point): + currentItem = self.getCurrentItem() + if not isinstance(currentItem, Ui_AddressWidget): + return self.popMenu = QtGui.QMenu(self) self.popMenu.addAction(self.actionNew) self.popMenu.addAction(self.actionDelete) self.popMenu.addSeparator() self.popMenu.addAction(self.actionClipboard) self.popMenu.addSeparator() - if self.getCurrentItem().isEnabled: + if currentItem.isEnabled: self.popMenu.addAction(self.actionDisable) else: self.popMenu.addAction(self.actionEnable) -- 2.45.1 From 140b3ddbb84fa6e38d1f9c1dc961e637337652d9 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 18:25:33 +0100 Subject: [PATCH 0282/1102] Test cleanup Safer this way --- src/bitmessageqt/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 286bc75a..3c5eaacc 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -510,10 +510,10 @@ class MyForm(settingsmixin.SMainWindow): isMaillinglist = shared.safeConfigGetBoolean( toAddress, 'mailinglist') - if tab == 'messages': + if treeWidget == self.ui.treeWidgetYourIdentities: if isChan: continue - elif tab == 'chan': + elif treeWidget == self.ui.treeWidgetChans: if not isChan: continue @@ -531,7 +531,7 @@ class MyForm(settingsmixin.SMainWindow): total += cnt if toaddress in db and folder in db[toaddress]: db[toaddress][folder] = cnt - if tab == "messages": + if treeWidget == self.ui.treeWidgetYourIdentities: db[None] = {} db[None]["inbox"] = total db[None]["new"] = total -- 2.45.1 From 8f1e753cf0428424d4d1bbf127fb65abc1dc0028 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 18:50:38 +0100 Subject: [PATCH 0283/1102] Typo --- src/bitmessageqt/foldertree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 6fbe2ec0..5fa935ea 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -56,7 +56,7 @@ class AccountMixin (object): for i in range(self.childCount()): if isinstance(self.child(i), Ui_FolderWidget): self.child(i).setEnabled(enabled) - if isinstance(self, QtGui.QTreeWidgetItem) + if isinstance(self, QtGui.QTreeWidgetItem): self.emitDataChanged() def setType(self): -- 2.45.1 From 185d212cb2f0333038d9b63a975d36f7fb2c38d4 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 21:26:42 +0100 Subject: [PATCH 0284/1102] Unread count refresh on change --- src/bitmessageqt/foldertree.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 5fa935ea..b9112b49 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -46,7 +46,11 @@ class AccountMixin (object): 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 -- 2.45.1 From 3bde549e5c60f75c9ab8a7babf58dafe887a04c5 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sun, 24 Jan 2016 22:39:46 +0100 Subject: [PATCH 0285/1102] Version bump for 0.5.7 --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 2a9c3c48..d342ddaa 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.6' +softwareVersion = '0.5.7' 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. -- 2.45.1 From 89752faceb496d64ad3272a95e71d590fcce400b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 25 Jan 2016 23:52:11 +0100 Subject: [PATCH 0286/1102] Newly arrives messages sorting There could be cases where newly arrives message is not added correctly. It won't necessarily go to the top, that depends on the sort. --- src/bitmessageqt/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3c5eaacc..41540fa9 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -975,9 +975,14 @@ class MyForm(settingsmixin.SMainWindow): updateUnreadCount(folderItem) 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) -- 2.45.1 From 47f1c0c26775ca45b9988b7f4620635d723ae0b2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 26 Jan 2016 11:54:11 +0100 Subject: [PATCH 0287/1102] Thread names for IPv6 Thread names for IPv6 contained ":". This caused problems in log parsers. --- src/class_outgoingSynSender.py | 2 +- src/class_receiveDataThread.py | 2 +- src/class_sendDataThread.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 738882ef..58db78b8 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -80,7 +80,7 @@ class outgoingSynSender(threading.Thread, StoppableThread): shared.alreadyAttemptedConnectionsListLock.release() except threading.ThreadError as e: pass - self.name = "outgoingSynSender-" + peer.host + self.name = "outgoingSynSender-" + peer.host.replace(":", ".") # log parser field separator if peer.host.find(':') == -1: address_family = socket.AF_INET else: diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 59399d7a..fbc55ae0 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -46,7 +46,7 @@ class receiveDataThread(threading.Thread): self.sock = sock self.peer = shared.Peer(HOST, port) - self.name = "receiveData-" + self.peer.host + self.name = "receiveData-" + self.peer.host.replace(":", ".") # ":" log parser field separator self.streamNumber = streamNumber self.objectsThatWeHaveYetToGetFromThisPeer = {} self.selfInitiatedConnections = selfInitiatedConnections diff --git a/src/class_sendDataThread.py b/src/class_sendDataThread.py index f151f55b..9c048d32 100644 --- a/src/class_sendDataThread.py +++ b/src/class_sendDataThread.py @@ -36,7 +36,7 @@ class sendDataThread(threading.Thread): someObjectsOfWhichThisRemoteNodeIsAlreadyAware): self.sock = sock self.peer = shared.Peer(HOST, PORT) - self.name = "sendData-" + self.peer.host + self.name = "sendData-" + self.peer.host.replace(":", ".") # log parser field separator self.streamNumber = streamNumber self.services = 0 self.initiatedConnection = False -- 2.45.1 From 4f26bf1059886efb12bb32913721677670879ef6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 26 Jan 2016 12:04:06 +0100 Subject: [PATCH 0288/1102] private IP range checks When advertising nodes and when establishing connections, private IP range checks were not done. This could cause private IPs to be advertised across the network. Also, some of the checks weren't IPv6-aware. Fixes Bitmessage#768 --- src/class_receiveDataThread.py | 39 +++++++++++++++++----------------- src/helper_generic.py | 30 ++++++++++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index fbc55ae0..d7693625 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -490,9 +490,19 @@ class receiveDataThread(threading.Thread): logger.debug('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) + 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): - # print 'hostStandardFormat', hostStandardFormat if host[0] == '\x7F': # 127/8 logger.debug('Ignoring IP address in loopback range: ' + hostStandardFormat) return False @@ -505,7 +515,7 @@ class receiveDataThread(threading.Thread): 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 True + return hostStandardFormat def _checkIPv6Address(self, host, hostStandardFormat): if host == ('\x00' * 15) + '\x01': @@ -517,7 +527,7 @@ class receiveDataThread(threading.Thread): if (ord(host[0]) & 0xfe) == 0xfc: logger.debug ('Ignoring unique local address: ' + hostStandardFormat) return False - return True + return hostStandardFormat # We have received an addr message. def recaddr(self, data): @@ -545,19 +555,9 @@ class receiveDataThread(threading.Thread): 38 * i):20 + lengthOfNumberOfAddresses + (38 * i)]) recaddrPort, = unpack('>H', data[36 + lengthOfNumberOfAddresses + ( 38 * i):38 + lengthOfNumberOfAddresses + (38 * i)]) - 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 + hostStandardFormat = self._checkIPAddress(fullHost) + if hostStandardFormat is False: + 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 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. @@ -744,9 +744,10 @@ class receiveDataThread(threading.Thread): # in this version message. Let us inform the sendDataThread. self.sendDataThreadQueue.put((0, 'setRemoteProtocolVersion', self.remoteProtocolVersion)) - with shared.knownNodesLock: - shared.knownNodes[self.streamNumber][shared.Peer(self.peer.host, self.remoteNodeIncomingPort)] = int(time.time()) - shared.needToWriteKnownNodesToDisk = True + if not isHostInPrivateIPRange(self.peer.host): + 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: diff --git a/src/helper_generic.py b/src/helper_generic.py index f3380b26..a9de6e05 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -1,6 +1,8 @@ -import shared +import socket import sys +import shared + def convertIntToString(n): a = __builtins__.hex(n) if a[-1:] == 'L': @@ -23,14 +25,24 @@ def signal_handler(signal, frame): print 'Unfortunately you cannot use Ctrl+C when running the UI because the UI captures the signal.' def isHostInPrivateIPRange(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 + 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 + else: + 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'): -- 2.45.1 From 24a2deed8f0a21780ba2ea9752be84ebf8bb7c36 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 26 Jan 2016 13:01:28 +0100 Subject: [PATCH 0289/1102] Cleanup lockfile on exit singleton.py design was broken. Fixed Bitmessage#775 --- src/bitmessagemain.py | 4 +--- src/bitmessageqt/__init__.py | 1 + src/shared.py | 4 +++- src/singleton.py | 24 ++++++++++++++---------- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 81b8613e..135d835f 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -152,13 +152,11 @@ if shared.useVeryEasyProofOfWorkForTesting: class Main: def start(self, daemon=False): - global thisapp - _fixWinsock() shared.daemon = daemon # is the application already running? If yes then exit. - thisapp = singleton.singleinstance("", daemon) + shared.thisapp = singleton.singleinstance("", daemon) # get curses flag curses = False diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 41540fa9..a635a7da 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2842,6 +2842,7 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "All done. Closing user interface...")) + shared.thisapp.cleanup() os._exit(0) # window close event diff --git a/src/shared.py b/src/shared.py index d342ddaa..f18b4066 100644 --- a/src/shared.py +++ b/src/shared.py @@ -55,6 +55,7 @@ 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. shutdown = 0 #Set to 1 by the doCleanShutdown function. Used to tell the proof of work worker threads to exit. +thisapp = None # singleton lock instance alreadyAttemptedConnectionsList = { } # This is a list of nodes to which we have already attempted a connection alreadyAttemptedConnectionsListLock = threading.Lock() @@ -392,7 +393,7 @@ def isProofOfWorkSufficient(data, return POW <= 2 ** 64 / (nonceTrialsPerByte*(len(data) + payloadLengthExtraBytes + ((TTL*(len(data)+payloadLengthExtraBytes))/(2 ** 16)))) def doCleanShutdown(): - global shutdown + global shutdown, thisapp shutdown = 1 #Used to tell proof of work worker threads and the objectProcessorThread to exit. broadcastToSendDataQueues((0, 'shutdown', 'no data')) objectProcessorQueue.put(('checkShutdownVariable', 'no data')) @@ -440,6 +441,7 @@ def doCleanShutdown(): if safeConfigGetBoolean('bitmessagesettings','daemon'): logger.info('Clean shutdown complete.') + thisapp.cleanup() os._exit(0) # If you want to command all of the sendDataThreads to do something, like shutdown or send some data, this diff --git a/src/singleton.py b/src/singleton.py index f3124424..a4b6c678 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -1,10 +1,16 @@ #! /usr/bin/env python -import sys -import os +import atexit import errno -import shared from multiprocessing import Process +import os +import sys +import shared + +try: + import fcntl # @UnresolvedImport +except: + pass class singleinstance: """ @@ -14,9 +20,8 @@ class singleinstance: which is under the Python Software Foundation License version 2 """ def __init__(self, flavor_id="", daemon=False): - import sys self.initialized = False - self.daemon = daemon; + self.daemon = daemon self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) if not self.daemon: @@ -38,7 +43,6 @@ class singleinstance: 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) @@ -46,20 +50,20 @@ class singleinstance: print 'Another instance of this application is already running' sys.exit(-1) self.initialized = True + atexit.register(self.cleanup) - def __del__(self): - import sys + def cleanup(self): if not self.initialized: return + print "Cleaning up lockfile" 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) + pass -- 2.45.1 From bcae62938a4c6bd3eb523a943a9d951d44c3422b Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 26 Jan 2016 13:02:33 +0100 Subject: [PATCH 0290/1102] Unused variable --- src/bitmessagemain.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 135d835f..50971f66 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -45,9 +45,6 @@ import helper_bootstrap import helper_generic from helper_threading import * -# singleton lock instance -thisapp = None - def connectToStream(streamNumber): shared.streamsInWhichIAmParticipating[streamNumber] = 'no data' selfInitiatedConnections[streamNumber] = {} -- 2.45.1 From 80c174e4177bd345790f39148b7db8fa6d21c097 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Fri, 12 Feb 2016 02:25:07 +0100 Subject: [PATCH 0291/1102] Save changes to blacklist labels Fixes mailchuck/PyBitmessage#175 Signed-off-by: Peter Surda --- src/bitmessageqt/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a635a7da..fa34890c 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -717,6 +717,10 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( "itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged) + # Initialize blacklist + QtCore.QObject.connect(self.ui.tableWidgetBlacklist, QtCore.SIGNAL( + "itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged) + # Put the colored icon on the status bar # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) self.statusbar = self.statusBar() @@ -3969,6 +3973,16 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() + def tableWidgetBlacklistItemChanged(self, item): + if item.column() == 0: + addressitem = self.ui.tableWidgetBlacklist.item(item.row(), 1) + if self.ui.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 updateStatusBar(self, data): if data != "": logger.info('Status bar: ' + data) -- 2.45.1 From 0bd89103a700782395fda7aaf9da696ee2c67abb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 12 Feb 2016 23:35:28 +0100 Subject: [PATCH 0292/1102] Don't send unnecessary ACKs In some situations, it's not necessary to send an ACK. For example, when the sender is blacklisted, when the message has no content, or when the address has ACK sending disabled. Also it's not necessary to rebroadcast empty messages into a mailing list. --- src/class_objectProcessor.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 0035dce9..ca96a609 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -524,7 +524,7 @@ class objectProcessor(threading.Thread): # Let us now check and see whether our receiving address is # behaving as a mailing list - if shared.safeConfigGetBoolean(toAddress, 'mailinglist'): + if shared.safeConfigGetBoolean(toAddress, 'mailinglist') and messageEncodingType != 0: try: mailingListName = shared.config.get( toAddress, 'mailinglistname') @@ -567,7 +567,11 @@ class objectProcessor(threading.Thread): toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdataForBroadcast))) shared.workerQueue.put(('sendbroadcast', '')) - if self.ackDataHasAVaildHeader(ackData): + # Don't send ACK if invalid, blacklisted senders, invisible messages or disabled + if self.ackDataHasAValidHeader(ackData) and \ + not blockMessage and \ + messageEncodingType != 0 and \ + not shared.safeConfigGetBoolean(toAddress, 'dontsendack'): shared.checkAndShareObjectWithPeers(ackData[24:]) # Display timing data @@ -814,7 +818,7 @@ class objectProcessor(threading.Thread): address) shared.workerQueue.put(('sendmessage', '')) - def ackDataHasAVaildHeader(self, ackData): + def ackDataHasAValidHeader(self, ackData): if len(ackData) < shared.Header.size: logger.info('The length of ackData is unreasonably short. Not sending ackData.') return False -- 2.45.1 From 40f0ff381ec5cb82e9f9de3d3809e1af3b877dcb Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 13 Feb 2016 00:09:42 +0100 Subject: [PATCH 0293/1102] blacklist rendering edit fix Editing of blacklist labels affected the rerendering, because it emits the changed signal too, and it caused an exception because the address field was missing at that time. This works around both. --- src/bitmessageqt/__init__.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fa34890c..d97d4629 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3976,12 +3976,13 @@ class MyForm(settingsmixin.SMainWindow): def tableWidgetBlacklistItemChanged(self, item): if item.column() == 0: addressitem = self.ui.tableWidgetBlacklist.item(item.row(), 1) - if self.ui.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())) + if isinstance(addressitem, QTableWidgetItem): + if self.ui.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 updateStatusBar(self, data): if data != "": -- 2.45.1 From f43e01ed0e6f66084536bfde55017a9e28821646 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 13 Feb 2016 00:27:37 +0100 Subject: [PATCH 0294/1102] Don't send ACK on subscribed chans If somehow you manage to send a message that includes an ACK part into a chan, the subscribers would send the ACK back. This shouldn't happen. --- src/class_objectProcessor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index ca96a609..52badd56 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -567,11 +567,12 @@ class objectProcessor(threading.Thread): toAddress, '[Broadcast subscribers]', fromAddress, subject, message, ackdataForBroadcast))) shared.workerQueue.put(('sendbroadcast', '')) - # Don't send ACK if invalid, blacklisted senders, invisible messages or disabled + # 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 shared.safeConfigGetBoolean(toAddress, 'dontsendack'): + not shared.safeConfigGetBoolean(toAddress, 'dontsendack') and \ + not shared.safeConfigGetBoolean(toAddress, 'chan'): shared.checkAndShareObjectWithPeers(ackData[24:]) # Display timing data -- 2.45.1 From 8f5d3052423fed2b85e30d9bb86b4cd7bac6dae6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 13 Feb 2016 12:54:23 +0100 Subject: [PATCH 0295/1102] Mitigate active internal intersection attack There was a report that by quickly asking a large number of nodes if they have an ACK object (which the attacker knows but it is injected into the network by the recipient of the message), it can estimate how an object propagates through the network, and eventually pinpoint an originating IP address of the injection, i.e. the IP address of the message recipient. This patch mitigates against it by stalling when asked for a nonexisting object (so that the attacker can't spam requests), and also upon connection before sending its own inventory list (so that reconnecting won't help the attacker). It estimates how long a short message takes to propagate through the network based on how many nodes are in a stream and bases the stalling time on that. Currently that is about 15 seconds. Initial connection delay takes into account the time that already passed since the connection was established. This basically gives the attacker one shot per a combination of his own nodes and the nodes he can connect to, and thus makes the attack much more difficult to succeed. --- src/class_objectHashHolder.py | 11 ++++++----- src/class_receiveDataThread.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index c91b1c23..92faaf17 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -12,13 +12,14 @@ import time import threading class objectHashHolder(threading.Thread): + size = 10 def __init__(self, sendDataThreadMailbox): 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(10): + for i in range(self.size): self.collectionOfHashLists[i] = [] self.collectionOfPeerLists[i] = [] @@ -32,14 +33,14 @@ class objectHashHolder(threading.Thread): self.sendDataThreadMailbox.put((0, 'sendaddr', self.collectionOfPeerLists[iterator])) self.collectionOfPeerLists[iterator] = [] iterator += 1 - iterator %= 10 + iterator %= self.size time.sleep(1) def holdHash(self,hash): - self.collectionOfHashLists[random.randrange(0, 10)].append(hash) + self.collectionOfHashLists[random.randrange(0, self.size)].append(hash) def holdPeer(self,peerDetails): - self.collectionOfPeerLists[random.randrange(0, 10)].append(peerDetails) + self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails) def close(self): - self.shutdown = True \ No newline at end of file + self.shutdown = True diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index d7693625..e7574bc5 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,6 +1,7 @@ doTimingAttackMitigation = False import errno +import math import time import threading import shared @@ -19,6 +20,7 @@ import traceback #import highlevelcrypto from addresses import * +from class_objectHashHolder import objectHashHolder from helper_generic import addDataPadding, isHostInPrivateIPRange from helper_sql import sqlQuery from debug import logger @@ -61,6 +63,7 @@ class receiveDataThread(threading.Thread): self.initiatedConnection = True self.selfInitiatedConnections[streamNumber][self] = 0 self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware + self.startTime = time.time() def run(self): logger.debug('receiveDataThread starting. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(len(shared.connectedHostsList))) @@ -125,6 +128,19 @@ class receiveDataThread(threading.Thread): shared.UISignalQueue.put(('updateNetworkStatusTab', 'no data')) logger.debug('receiveDataThread ending. ID ' + str(id(self)) + '. The size of the shared.connectedHostsList is now ' + str(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(len(shared.knownNodes[self.streamNumber]) + 2, 20)) * (0.2 + objectHashHolder.size/2) + # +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.info("Sleeping for %.2fs", delay - (now - self.startTime)) + time.sleep(delay - (now - self.startTime)) + elif not initial: + logger.info("Sleeping for %.2fs", delay) + time.sleep(delay) def processData(self): 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. @@ -318,6 +334,7 @@ class receiveDataThread(threading.Thread): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' + self.antiIntersectionDelay(True) # 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(): @@ -483,6 +500,7 @@ class receiveDataThread(threading.Thread): 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. -- 2.45.1 From ab974abce0794089e5392285be366325d3c9bf8c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 13 Feb 2016 19:33:50 +0100 Subject: [PATCH 0296/1102] Sent message status on ACK Fixes #176 --- src/class_singleWorker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 336c5059..e1e71734 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -812,7 +812,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, embeddedTime, '') shared.inventorySets[toStreamNumber].add(inventoryHash) - if shared.config.has_section(toaddress) or shared.safeConfigGetBoolean(toaddress, 'dontsendack'): + if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): 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 -- 2.45.1 From 218bdf38e1c3978ce908a6b668f473563df296d5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 13 Feb 2016 22:16:44 +0100 Subject: [PATCH 0297/1102] Better error reporting for log config Fixes #174 --- src/debug.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/debug.py b/src/debug.py index d430e5e3..8328e3ed 100644 --- a/src/debug.py +++ b/src/debug.py @@ -37,8 +37,10 @@ def configureLogging(): try: logging.config.fileConfig(os.path.join (shared.appdata, 'logging.dat')) have_logging = True + print "Loaded debug config from %s" % (os.path.join(shared.appdata, 'logging.dat')) except: - pass + print "Failed to load debug config from %s, using default logging config" % (os.path.join(shared.appdata, 'logging.dat')) + print sys.exc_info() sys.excepthook = log_uncaught_exceptions -- 2.45.1 From db84d699dbf02708426387e1a2d855811c709a46 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 14 Feb 2016 19:56:05 +0100 Subject: [PATCH 0298/1102] Search improvements - selecting a new folder will apply search - newly arrived message will consider search - fixes #166 --- src/bitmessageqt/__init__.py | 125 +++++++++++++---------------------- src/helper_search.py | 80 ++++++++++++++++++++++ 2 files changed, 125 insertions(+), 80 deletions(-) create mode 100644 src/helper_search.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index d97d4629..b320a774 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -59,6 +59,7 @@ import subprocess import string import datetime from helper_sql import * +import helper_search import l10n import openclpow import types @@ -1081,20 +1082,6 @@ class MyForm(settingsmixin.SMainWindow): # Load Sent items from database def loadSent(self, tableWidget, account, where="", what=""): - what = "%" + what + "%" - if where == _translate("MainWindow", "To"): - where = "toaddress" - elif where == _translate("MainWindow", "From"): - where = "fromaddress" - elif where == _translate("MainWindow", "Subject"): - where = "subject" - elif where == _translate("MainWindow", "Message"): - where = "message" - else: - where = "toaddress || fromaddress || subject || message" - - tableWidget.setSortingEnabled(False) - if tableWidget == self.ui.tableWidgetInboxChans or tableWidget == self.ui.tableWidgetInboxSubscriptions: tableWidget.setColumnHidden(0, True) tableWidget.setColumnHidden(1, False) @@ -1103,16 +1090,11 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setColumnHidden(0, False) tableWidget.setColumnHidden(1, True) xAddress = 'fromaddress' - - sqlStatement = ''' - SELECT toaddress, fromaddress, subject, status, ackdata, lastactiontime - FROM sent WHERE ''' + xAddress + '''=? AND folder="sent" AND %s LIKE ? - ORDER BY lastactiontime - ''' % (where,) + tableWidget.setSortingEnabled(False) tableWidget.setRowCount(0) - acct = None - queryreturn = sqlQuery(sqlStatement, account, what) + queryreturn = helper_search.search_sql(xAddress, account, "sent", where, what, False) + for row in queryreturn: toAddress, fromAddress, subject, status, ackdata, lastactiontime = row self.addMessageListItemSent(tableWidget, toAddress, fromAddress, subject, status, ackdata, lastactiontime) @@ -1127,52 +1109,21 @@ class MyForm(settingsmixin.SMainWindow): self.loadSent(tableWidget, account, where, what) return - if what != "": - what = "%" + what + "%" - if where == _translate("MainWindow", "To"): - where = "toaddress" - elif where == _translate("MainWindow", "From"): - where = "fromaddress" - elif where == _translate("MainWindow", "Subject"): - where = "subject" - elif where == _translate("MainWindow", "Message"): - where = "message" - else: - where = "toaddress || fromaddress || subject || message" - else: - what = None - if tableWidget == self.ui.tableWidgetInboxSubscriptions: xAddress = "fromaddress" else: xAddress = "toaddress" - sqlStatementBase = '''SELECT folder, msgid, toaddress, fromaddress, subject, received, read - FROM inbox ''' - sqlStatementParts = [] - sqlArguments = [] - if account is not None: - sqlStatementParts.append(xAddress + " = ? ") - sqlArguments.append(account) - if folder is not None: - sqlStatementParts.append("folder = ? ") - sqlArguments.append(folder) - 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) - queryreturn = sqlQuery(sqlStatementBase, sqlArguments) - - tableWidget.setRowCount(0) if account is not None: tableWidget.setColumnHidden(0, True) tableWidget.setColumnHidden(1, False) else: tableWidget.setColumnHidden(0, False) tableWidget.setColumnHidden(1, False) + tableWidget.setSortingEnabled(False) + tableWidget.setRowCount(0) + + queryreturn = helper_search.search_sql(xAddress, account, folder, where, what, unreadOnly) for row in queryreturn: msgfolder, msgid, toAddress, fromAddress, subject, received, read = row @@ -2336,7 +2287,11 @@ class MyForm(settingsmixin.SMainWindow): 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 @@ -2344,6 +2299,8 @@ class MyForm(settingsmixin.SMainWindow): 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')) @@ -2356,8 +2313,14 @@ class MyForm(settingsmixin.SMainWindow): 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: @@ -3518,8 +3481,9 @@ class MyForm(settingsmixin.SMainWindow): except: return self.ui.textEditInboxMessage - def getCurrentSearchLine(self): - currentIndex = self.ui.tabWidget.currentIndex(); + def getCurrentSearchLine(self, currentIndex = None): + if currentIndex is None: + currentIndex = self.ui.tabWidget.currentIndex(); messagelistList = [ self.ui.inboxSearchLineEdit, False, @@ -3527,12 +3491,13 @@ class MyForm(settingsmixin.SMainWindow): self.ui.inboxSearchLineEditChans, ] if currentIndex >= 0 and currentIndex < len(messagelistList): - return messagelistList[currentIndex] + return messagelistList[currentIndex].text().toUtf8().data() else: - return False + return None - def getCurrentSearchOption(self): - currentIndex = self.ui.tabWidget.currentIndex(); + def getCurrentSearchOption(self, currentIndex = None): + if currentIndex is None: + currentIndex = self.ui.tabWidget.currentIndex(); messagelistList = [ self.ui.inboxSearchOption, False, @@ -3542,7 +3507,7 @@ class MyForm(settingsmixin.SMainWindow): if currentIndex >= 0 and currentIndex < len(messagelistList): return messagelistList[currentIndex].currentText().toUtf8().data() else: - return False + return None # Group of functions for the Your Identities dialog box def getCurrentItem(self, treeWidget = None): @@ -3842,26 +3807,26 @@ class MyForm(settingsmixin.SMainWindow): def inboxSearchLineEditPressed(self): searchLine = self.getCurrentSearchLine() searchOption = self.getCurrentSearchOption() - if searchLine: - searchKeyword = searchLine.text().toUtf8().data() - messageTextedit = self.getCurrentMessageTextedit() - if messageTextedit: - messageTextedit.setPlainText(QString("")) - messagelist = self.getCurrentMessagelist() - if messagelist: - account = self.getCurrentAccount() - folder = self.getCurrentFolder() - self.loadMessagelist(messagelist, account, folder, searchOption, searchKeyword) - - def treeWidgetItemClicked(self): + messageTextedit = self.getCurrentMessageTextedit() + if messageTextedit: + messageTextedit.setPlainText(QString("")) messagelist = self.getCurrentMessagelist() if messagelist: account = self.getCurrentAccount() folder = self.getCurrentFolder() - if folder == "new": - self.loadMessagelist(messagelist, account, None, unreadOnly = True) - else: - self.loadMessagelist(messagelist, account, folder) + self.loadMessagelist(messagelist, account, folder, searchOption, searchLine) + + def treeWidgetItemClicked(self): + searchLine = self.getCurrentSearchLine() + searchOption = self.getCurrentSearchOption() + messageTextedit = self.getCurrentMessageTextedit() + if messageTextedit: + messageTextedit.setPlainText(QString("")) + messagelist = self.getCurrentMessagelist() + if messagelist: + account = self.getCurrentAccount() + folder = self.getCurrentFolder() + self.loadMessagelist(messagelist, account, folder, searchOption, searchLine) def treeWidgetItemChanged(self, item, column): # only for manual edits. automatic edits (setText) are ignored diff --git a/src/helper_search.py b/src/helper_search.py new file mode 100644 index 00000000..9ebdddbe --- /dev/null +++ b/src/helper_search.py @@ -0,0 +1,80 @@ +#!/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: + 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 -- 2.45.1 From 2b6bffc7ff6c93cb5c63702e3b8aaf4a24088f36 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 14 Feb 2016 20:13:23 +0100 Subject: [PATCH 0299/1102] Email gateway account status query - addresses #14 --- src/bitmessageqt/__init__.py | 8 ++++++++ src/bitmessageqt/account.py | 9 ++++++++- src/bitmessageqt/emailgateway.py | 9 +++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index b320a774..7d38e43b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2730,6 +2730,12 @@ class MyForm(settingsmixin.SMainWindow): acct.unregister() shared.config.remove_option(addressAtCurrentRow, 'gateway') shared.writeKeysFile() + self.statusBar().showMessage(_translate( + "MainWindow", "Sending email gateway unregistration request")) + elif self.dialog.ui.radioButtonStatus.isChecked() and isinstance(acct, GatewayAccount): + acct.status() + self.statusBar().showMessage(_translate( + "MainWindow", "Sending email gateway status request")) elif self.dialog.ui.radioButtonRegister.isChecked(): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) @@ -2737,6 +2743,8 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set(addressAtCurrentRow, 'label', email) shared.config.set(addressAtCurrentRow, 'gateway', 'mailchuck') shared.writeKeysFile() + self.statusBar().showMessage(_translate( + "MainWindow", "Sending email gateway registration request")) else: pass #print "well nothing" diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index d1afd560..0c3e95c6 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -200,6 +200,13 @@ class MailchuckAccount(GatewayAccount): 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 parseMessage(self, toAddress, fromAddress, subject, message): super(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) if fromAddress == self.relayAddress: @@ -220,4 +227,4 @@ class MailchuckAccount(GatewayAccount): self.subject = matches.group(2) if not matches.group(1) is None: self.toLabel = matches.group(1) - self.toAddress = matches.group(1) \ No newline at end of file + self.toAddress = matches.group(1) diff --git a/src/bitmessageqt/emailgateway.py b/src/bitmessageqt/emailgateway.py index 0df4dd01..61b4a7f5 100644 --- a/src/bitmessageqt/emailgateway.py +++ b/src/bitmessageqt/emailgateway.py @@ -24,9 +24,12 @@ class Ui_EmailGatewayDialog(object): self.radioButtonRegister.setChecked(True) self.radioButtonRegister.setObjectName(_fromUtf8("radioButtonRegister")) self.gridLayout.addWidget(self.radioButtonRegister, 1, 0, 1, 1) + self.radioButtonStatus = QtGui.QRadioButton(EmailGatewayDialog) + self.radioButtonStatus.setObjectName(_fromUtf8("radioButtonStatus")) + self.gridLayout.addWidget(self.radioButtonStatus, 4, 0, 1, 1) self.radioButtonUnregister = QtGui.QRadioButton(EmailGatewayDialog) self.radioButtonUnregister.setObjectName(_fromUtf8("radioButtonUnregister")) - self.gridLayout.addWidget(self.radioButtonUnregister, 4, 0, 1, 1) + self.gridLayout.addWidget(self.radioButtonUnregister, 5, 0, 1, 1) self.label = QtGui.QLabel(EmailGatewayDialog) self.label.setWordWrap(True) self.label.setObjectName(_fromUtf8("label")) @@ -43,12 +46,13 @@ class Ui_EmailGatewayDialog(object): 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.gridLayout.addWidget(self.buttonBox, 6, 0, 1, 1) self.retranslateUi(EmailGatewayDialog) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayDialog.accept) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayDialog.reject) QtCore.QObject.connect(self.radioButtonRegister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setEnabled) + QtCore.QObject.connect(self.radioButtonStatus, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) QtCore.QObject.connect(self.radioButtonUnregister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) QtCore.QMetaObject.connectSlotsByName(EmailGatewayDialog) EmailGatewayDialog.setTabOrder(self.radioButtonRegister, self.lineEditEmail) @@ -58,6 +62,7 @@ class Ui_EmailGatewayDialog(object): def retranslateUi(self, EmailGatewayDialog): EmailGatewayDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonRegister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Register on email gateway", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonStatus.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Account status at email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonUnregister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Unregister from email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Desired email address (including @mailchuck.com):", None, QtGui.QApplication.UnicodeUTF8)) -- 2.45.1 From 6b8f255a6095ee80af7f0811ad0a7bfcb0847ca8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sun, 14 Feb 2016 21:37:53 +0100 Subject: [PATCH 0300/1102] Email gateway updates - settings option available - reduce max TTL to 2 days --- src/bitmessageqt/__init__.py | 14 ++++++++++ src/bitmessageqt/account.py | 47 +++++++++++++++++++++++++++++++- src/bitmessageqt/emailgateway.py | 9 ++++-- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7d38e43b..ee018efb 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2736,6 +2736,20 @@ class MyForm(settingsmixin.SMainWindow): acct.status() self.statusBar().showMessage(_translate( "MainWindow", "Sending email gateway status request")) + elif self.dialog.ui.radioButtonSettings.isChecked() and isinstance(acct, GatewayAccount): + acct.settings() + listOfAddressesInComboBoxSendFrom = [str(self.ui.comboBoxSendFrom.itemData(i).toPyObject()) for i in range(self.ui.comboBoxSendFrom.count())] + if acct.fromAddress in listOfAddressesInComboBoxSendFrom: + currentIndex = listOfAddressesInComboBoxSendFrom.index(acct.fromAddress) + self.ui.comboBoxSendFrom.setCurrentIndex(currentIndex) + 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(0) + self.ui.tabWidget.setCurrentIndex(1) + self.ui.textEditMessage.setFocus() elif self.dialog.ui.radioButtonRegister.isChecked(): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) acct = MailchuckAccount(addressAtCurrentRow) diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 0c3e95c6..7bf897cf 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -161,7 +161,7 @@ class GatewayAccount(BMAccount): 0, # retryNumber 'sent', # folder 2, # encodingtype - shared.config.getint('bitmessagesettings', 'ttl') + min(shared.config.getint('bitmessagesettings', 'ttl'), 86400 * 2) # not necessary to have a TTL higher than 2 days ) shared.workerQueue.put(('sendmessage', self.toAddress)) @@ -207,6 +207,51 @@ class MailchuckAccount(GatewayAccount): 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(GatewayAccount, self).parseMessage(toAddress, fromAddress, subject, message) if fromAddress == self.relayAddress: diff --git a/src/bitmessageqt/emailgateway.py b/src/bitmessageqt/emailgateway.py index 61b4a7f5..7fd478ad 100644 --- a/src/bitmessageqt/emailgateway.py +++ b/src/bitmessageqt/emailgateway.py @@ -27,9 +27,12 @@ class Ui_EmailGatewayDialog(object): self.radioButtonStatus = QtGui.QRadioButton(EmailGatewayDialog) self.radioButtonStatus.setObjectName(_fromUtf8("radioButtonStatus")) self.gridLayout.addWidget(self.radioButtonStatus, 4, 0, 1, 1) + self.radioButtonSettings = QtGui.QRadioButton(EmailGatewayDialog) + self.radioButtonSettings.setObjectName(_fromUtf8("radioButtonSettings")) + self.gridLayout.addWidget(self.radioButtonSettings, 5, 0, 1, 1) self.radioButtonUnregister = QtGui.QRadioButton(EmailGatewayDialog) self.radioButtonUnregister.setObjectName(_fromUtf8("radioButtonUnregister")) - self.gridLayout.addWidget(self.radioButtonUnregister, 5, 0, 1, 1) + self.gridLayout.addWidget(self.radioButtonUnregister, 6, 0, 1, 1) self.label = QtGui.QLabel(EmailGatewayDialog) self.label.setWordWrap(True) self.label.setObjectName(_fromUtf8("label")) @@ -46,13 +49,14 @@ class Ui_EmailGatewayDialog(object): 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, 6, 0, 1, 1) + self.gridLayout.addWidget(self.buttonBox, 7, 0, 1, 1) self.retranslateUi(EmailGatewayDialog) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayDialog.accept) QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayDialog.reject) QtCore.QObject.connect(self.radioButtonRegister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setEnabled) QtCore.QObject.connect(self.radioButtonStatus, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) + QtCore.QObject.connect(self.radioButtonSettings, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) QtCore.QObject.connect(self.radioButtonUnregister, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.lineEditEmail.setDisabled) QtCore.QMetaObject.connectSlotsByName(EmailGatewayDialog) EmailGatewayDialog.setTabOrder(self.radioButtonRegister, self.lineEditEmail) @@ -63,6 +67,7 @@ class Ui_EmailGatewayDialog(object): EmailGatewayDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonRegister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Register on email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonStatus.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Account status at email gateway", None, QtGui.QApplication.UnicodeUTF8)) + self.radioButtonSettings.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Change account settings at email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.radioButtonUnregister.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Unregister from email gateway", None, QtGui.QApplication.UnicodeUTF8)) self.label.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Desired email address (including @mailchuck.com):", None, QtGui.QApplication.UnicodeUTF8)) -- 2.45.1 From 1a92db54c95651ecadffeda40f6b085f6809d031 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 15 Feb 2016 08:19:45 +0100 Subject: [PATCH 0301/1102] Process gateway registration rejections A message from gateway registration addres regarding registration rejection is processed and a dialog displayed to get a new email address. Fixes #14 --- src/bitmessageqt/__init__.py | 28 +++++++++++++++++++++++++++- src/bitmessageqt/account.py | 7 +++++++ src/bitmessageqt/emailgateway.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index ee018efb..f971728a 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2335,7 +2335,20 @@ class MyForm(settingsmixin.SMainWindow): 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.ubuntuMessagingMenuUpdate(True, None, acct.toLabel) - return + if hasattr(acct, "feedback") and acct.feedback != GatewayAccount.ALL_OK: + if acct.feedback == GatewayAccount.REGISTRATION_DENIED: + self.dialog = EmailGatewayRegistrationDialog(self, _translate("EmailGatewayRegistrationDialog", "Registration failed:"), + _translate("EmailGatewayRegistrationDialog", "The requested email address is not available, please try a new one. Fill out the new designed email address (including @mailchuck.com) below:") + ) + if self.dialog.exec_(): + email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) + # register resets address variables + acct.register(email) + shared.config.set(acct.fromAddress, 'label', email) + shared.config.set(acct.fromAddress, 'gateway', 'mailchuck') + shared.writeKeysFile() + self.statusBar().showMessage(_translate( + "MainWindow", "Sending email gateway registration request")) def click_pushButtonAddAddressBook(self): self.AddAddressDialogInstance = AddAddressDialog(self) @@ -4309,6 +4322,19 @@ class EmailGatewayDialog(QtGui.QDialog): QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) +class EmailGatewayRegistrationDialog(QtGui.QDialog): + + def __init__(self, parent, title, label): + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_EmailGatewayRegistrationDialog() + self.ui.setupUi(self) + self.parent = parent + self.setWindowTitle(title) + self.ui.label.setText(label) + + QtGui.QWidget.resize(self, QtGui.QWidget.sizeHint(self)) + + class AddAddressDialog(QtGui.QDialog): def __init__(self, parent): diff --git a/src/bitmessageqt/account.py b/src/bitmessageqt/account.py index 7bf897cf..610b9b46 100644 --- a/src/bitmessageqt/account.py +++ b/src/bitmessageqt/account.py @@ -138,6 +138,8 @@ class BroadcastAccount(BMAccount): class GatewayAccount(BMAccount): gatewayName = None + ALL_OK = 0 + REGISTRATION_DENIED = 1 def __init__(self, address): super(BMAccount, self).__init__(address) @@ -179,6 +181,7 @@ class MailchuckAccount(GatewayAccount): regExpOutgoing = re.compile("(\S+) (.*)") def __init__(self, address): super(GatewayAccount, self).__init__(address) + self.feedback = self.ALL_OK def createMessage(self, toAddress, fromAddress, subject, message): self.subject = toAddress + " " + subject @@ -273,3 +276,7 @@ class MailchuckAccount(GatewayAccount): 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/emailgateway.py b/src/bitmessageqt/emailgateway.py index 7fd478ad..664a2b44 100644 --- a/src/bitmessageqt/emailgateway.py +++ b/src/bitmessageqt/emailgateway.py @@ -72,3 +72,32 @@ class Ui_EmailGatewayDialog(object): self.label.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.", None, QtGui.QApplication.UnicodeUTF8)) self.label_2.setText(QtGui.QApplication.translate("EmailGatewayDialog", "Desired email address (including @mailchuck.com):", None, QtGui.QApplication.UnicodeUTF8)) + +class Ui_EmailGatewayRegistrationDialog(object): + def setupUi(self, EmailGatewayRegistrationDialog): + EmailGatewayRegistrationDialog.setObjectName(_fromUtf8("EmailGatewayRegistrationDialog")) + EmailGatewayRegistrationDialog.resize(386, 172) + self.gridLayout = QtGui.QGridLayout(EmailGatewayRegistrationDialog) + self.gridLayout.setObjectName(_fromUtf8("gridLayout")) + self.label = QtGui.QLabel(EmailGatewayRegistrationDialog) + self.label.setWordWrap(True) + self.label.setObjectName(_fromUtf8("label")) + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + self.lineEditEmail = QtGui.QLineEdit(EmailGatewayRegistrationDialog) + self.lineEditEmail.setObjectName(_fromUtf8("lineEditEmail")) + self.gridLayout.addWidget(self.lineEditEmail, 1, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(EmailGatewayRegistrationDialog) + 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, 7, 0, 1, 1) + + self.retranslateUi(EmailGatewayRegistrationDialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), EmailGatewayRegistrationDialog.accept) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), EmailGatewayRegistrationDialog.reject) + QtCore.QMetaObject.connectSlotsByName(EmailGatewayRegistrationDialog) + + def retranslateUi(self, EmailGatewayRegistrationDialog): + EmailGatewayRegistrationDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway registration", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.\nPlease type the desiged email address (including @mailchuck.com) below:", None, QtGui.QApplication.UnicodeUTF8)) -- 2.45.1 From 4c2ce7208ce2ad39d85cdf9411c8b61a54342bfd Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 18 Feb 2016 00:53:13 +0100 Subject: [PATCH 0302/1102] Sleep on invalid getdata - postpone initial sleep until the first getdata is received - also sleep when received a getdata request for an object that hasn't been advertised to the other node yet --- src/class_objectHashHolder.py | 6 ++++++ src/class_outgoingSynSender.py | 20 +++++++++++--------- src/class_receiveDataThread.py | 17 +++++++++++------ src/class_singleListener.py | 2 +- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/class_objectHashHolder.py b/src/class_objectHashHolder.py index 92faaf17..327656db 100644 --- a/src/class_objectHashHolder.py +++ b/src/class_objectHashHolder.py @@ -39,6 +39,12 @@ class objectHashHolder(threading.Thread): def holdHash(self,hash): self.collectionOfHashLists[random.randrange(0, self.size)].append(hash) + def hasHash(self, hash): + if hash in (hashlist for hashlist in self.collectionOfHashLists): + logger.debug("Hash in hashHolder") + return True + return False + def holdPeer(self,peerDetails): self.collectionOfPeerLists[random.randrange(0, self.size)].append(peerDetails) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 58db78b8..81403053 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -156,27 +156,29 @@ class outgoingSynSender(threading.Thread, StoppableThread): try: self.sock.connect((peer.host, peer.port)) - rd = receiveDataThread() - rd.daemon = True # close the main program even if there are threads left 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. + + sd = sendDataThread(sendDataThreadQueue) + sd.setup(self.sock, peer.host, peer.port, self.streamNumber, + someObjectsOfWhichThisRemoteNodeIsAlreadyAware) + sd.start() + + rd = receiveDataThread() + rd.daemon = True # close the main program even if there are threads left rd.setup(self.sock, peer.host, peer.port, self.streamNumber, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, - sendDataThreadQueue) + sendDataThreadQueue, + sd.objectHashHolderInstance) rd.start() - logger.debug(str(self) + ' connected to ' + str(peer) + ' during an outgoing attempt.') - - sd = sendDataThread(sendDataThreadQueue) - sd.setup(self.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 shared.verbose >= 2: logger.debug('Could NOT connect to ' + str(peer) + ' during outgoing attempt. ' + str(err)) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index e7574bc5..38b9aafe 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -44,7 +44,8 @@ class receiveDataThread(threading.Thread): streamNumber, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, selfInitiatedConnections, - sendDataThreadQueue): + sendDataThreadQueue, + objectHashHolderInstance): self.sock = sock self.peer = shared.Peer(HOST, port) @@ -63,6 +64,7 @@ class receiveDataThread(threading.Thread): self.initiatedConnection = True self.selfInitiatedConnections[streamNumber][self] = 0 self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware = someObjectsOfWhichThisRemoteNodeIsAlreadyAware + self.objectHashHolderInstance = objectHashHolderInstance self.startTime = time.time() def run(self): @@ -136,10 +138,10 @@ class receiveDataThread(threading.Thread): # 0.2 is avg message transmission time now = time.time() if initial and now - delay < self.startTime: - logger.info("Sleeping for %.2fs", delay - (now - self.startTime)) + logger.debug("Initial sleeping for %.2fs", delay - (now - self.startTime)) time.sleep(delay - (now - self.startTime)) elif not initial: - logger.info("Sleeping for %.2fs", delay) + logger.debug("Sleeping due to missing object for %.2fs", delay) time.sleep(delay) def processData(self): @@ -322,7 +324,7 @@ class receiveDataThread(threading.Thread): bigInvList = {} for row in queryreturn: hash, = row - if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware: + if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): bigInvList[hash] = 0 # We also have messages in our inventory in memory (which is a python # dictionary). Let's fetch those too. @@ -334,7 +336,6 @@ class receiveDataThread(threading.Thread): bigInvList[hash] = 0 numberOfObjectsInInvMessage = 0 payload = '' - self.antiIntersectionDelay(True) # 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(): @@ -478,6 +479,7 @@ class receiveDataThread(threading.Thread): if len(data) < lengthOfVarint + (32 * numberOfRequestedInventoryItems): logger.debug('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)] @@ -485,7 +487,10 @@ class receiveDataThread(threading.Thread): shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() - if hash in shared.inventory: + if self.objectHashHolderInstance.hasHash(hash): + shared.inventoryLock.release() + self.antiIntersectionDelay() + elif hash in shared.inventory: objectType, streamNumber, payload, expiresTime, tag = shared.inventory[hash] shared.inventoryLock.release() self.sendObject(payload) diff --git a/src/class_singleListener.py b/src/class_singleListener.py index a571867a..807570dc 100644 --- a/src/class_singleListener.py +++ b/src/class_singleListener.py @@ -130,7 +130,7 @@ class singleListener(threading.Thread, StoppableThread): rd = receiveDataThread() rd.daemon = True # close the main program even if there are threads left rd.setup( - socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue) + socketObject, HOST, PORT, -1, someObjectsOfWhichThisRemoteNodeIsAlreadyAware, self.selfInitiatedConnections, sendDataThreadQueue, sd.objectHashHolderInstance) rd.start() logger.info('connected to ' + HOST + ' during INCOMING request.') -- 2.45.1 From 9239813ebbcc3f6c121c31f3be73ee691263bcd0 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 18 Feb 2016 16:01:06 +0100 Subject: [PATCH 0303/1102] Constant time decryption Always try to decrypt with all keys. --- src/class_objectProcessor.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 52badd56..db9cc27c 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -335,11 +335,13 @@ class objectProcessor(threading.Thread): for key, cryptorObject in shared.myECCryptorObjects.items(): try: - 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 + 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.' % key.encode('hex')) except Exception as err: pass if not initialDecryptionSuccessful: @@ -615,11 +617,13 @@ class objectProcessor(threading.Thread): initialDecryptionSuccessful = False for key, cryptorObject in shared.MyECSubscriptionCryptorObjects.items(): try: - 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 + 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' % key.encode('hex')) except Exception as err: pass # print 'cryptorObject.decrypt Exception:', err -- 2.45.1 From b202ac6fab32aea8554345436595a0a57065bd6d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 20 Feb 2016 11:14:42 +0100 Subject: [PATCH 0304/1102] Do not allow port 0 Attackers injected node addresses with port 0 into the network. Port 0 is unusable on many OSes and can't be listened on. PyBitmessage won't accept nodes that have port 0 anymore. --- src/class_receiveDataThread.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 38b9aafe..e2a25a3e 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -581,6 +581,8 @@ class receiveDataThread(threading.Thread): hostStandardFormat = self._checkIPAddress(fullHost) if hostStandardFormat is False: continue + if recaddrPort == 0: + 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 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. -- 2.45.1 From f27ca0d3d678813456a95615e5fe62518d75baa3 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 25 Feb 2016 17:13:39 +0800 Subject: [PATCH 0305/1102] HTML parser updates HTML parser wasn't correctly handling img tags. Now it also by defaults disabled external schemas to prevent deanonymisation (even though the renderer actually doesn't support external schemas at the moment) Addresses #178 --- src/bitmessageqt/messageview.py | 4 ++-- src/bitmessageqt/safehtmlparser.py | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index faa21cd2..a579dd13 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -89,9 +89,9 @@ class MessageView(QtGui.QTextBrowser): def setContent(self, data): self.html = SafeHTMLParser() - self.html.allow_picture = True self.html.reset() self.html.reset_safe() + self.html.allow_picture = True self.html.feed(data) self.html.close() - self.showPlain() \ No newline at end of file + self.showPlain() diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index c357662d..79ad0f73 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -1,6 +1,7 @@ from HTMLParser import HTMLParser import inspect from urllib import quote, quote_plus +from urlparse import urlparse class SafeHTMLParser(HTMLParser): # from html5lib.sanitiser @@ -18,6 +19,7 @@ class SafeHTMLParser(HTMLParser): 'sub', 'sup', 'table', 'tbody', 'td', 'textarea', 'time', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] + src_schemes = [ "data" ] @staticmethod def multi_replace(text): @@ -36,27 +38,33 @@ class SafeHTMLParser(HTMLParser): 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 not tag in self.acceptable_elements: + if not tag in SafeHTMLParser.acceptable_elements: return self.sanitised += "<" if inspect.stack()[1][3] == "handle_endtag": self.sanitised += "/" self.sanitised += tag if not attrs is None: - for attr in attrs: - if tag == "img" and attr[0] == "src" and not self.allow_picture: - attr[1] = "" - self.sanitised += " " + quote_plus(attr[0]) - if not (attr[1] is None): - self.sanitised += "=\"" + attr[1] + "\"" + 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 self.acceptable_elements: + if tag in SafeHTMLParser.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) @@ -64,7 +72,7 @@ class SafeHTMLParser(HTMLParser): self.add_if_acceptable(tag) def handle_startendtag(self, tag, attrs): - if tag in self.acceptable_elements: + if tag in SafeHTMLParser.acceptable_elements: self.has_html = True self.add_if_acceptable(tag, attrs) @@ -86,7 +94,7 @@ class SafeHTMLParser(HTMLParser): if text: self.reset() self.reset_safe() + self.allow_picture = allow_picture self.feed(text) self.close() - self.allow_picture = allow_picture - return self.has_html \ No newline at end of file + return self.has_html -- 2.45.1 From 96a17264266d84a4d15b22796fb8ba7458b0a6c5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 29 Feb 2016 07:47:07 +0800 Subject: [PATCH 0306/1102] Clickable email and http links in plain text Email addresses and URIs are now clickable when viewing a message in plain text mode. Clicking an email address moves to the Send tab, while clicking an URI has the same result as clicking an URI in html mode, it will ask for confirmation before opening it in external handler. --- src/bitmessageqt/messageview.py | 11 +++++++++++ src/bitmessageqt/safehtmlparser.py | 11 ++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index a579dd13..66aac2cb 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -1,5 +1,6 @@ from PyQt4 import QtCore, QtGui +from urlparse import urlparse from safehtmlparser import * class MessageView(QtGui.QTextBrowser): @@ -42,6 +43,16 @@ class MessageView(QtGui.QTextBrowser): QtGui.QApplication.activeWindow().statusBar().showMessage(QtGui.QApplication.translate("MainWindow", "Zoom level %1%").arg(str(zoom))) def confirmURL(self, link): + if link.scheme() == "mailto": + QtGui.QApplication.activeWindow().ui.lineEditTo.setText(link.path()) + if link.hasQueryItem("subject"): + QtGui.QApplication.activeWindow().ui.lineEditSubject.setText(link.queryItemValue("subject")) + if link.hasQueryItem("body"): + QtGui.QApplication.activeWindow().ui.textEditMessage.setText(link.queryItemValue("body")) + QtGui.QApplication.activeWindow().ui.tabWidgetSend.setCurrentIndex(0) + QtGui.QApplication.activeWindow().ui.tabWidget.setCurrentIndex(1) + QtGui.QApplication.activeWindow().ui.textEditMessage.setFocus() + return reply = QtGui.QMessageBox.warning(self, QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TITLE), QtGui.QApplication.translate(type(self).__name__, MessageView.CONFIRM_TEXT).arg(str(link.toString())), diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 79ad0f73..78f89888 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -1,5 +1,6 @@ from HTMLParser import HTMLParser import inspect +import re from urllib import quote, quote_plus from urlparse import urlparse @@ -20,6 +21,9 @@ class SafeHTMLParser(HTMLParser): 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] src_schemes = [ "data" ] + uriregex1 = re.compile(r'(\b(?:https?|telnet|gopher|file|wais|ftp):[\w/#~:.?+=&%@!\-.:;?\\-]+?(?=[.:?\-]*(?:[^\w/#~:;.?+=&%@!\-.:?\-]|$)))') + uriregex2 = re.compile(r'\1', + unicode(tmp, 'utf-8', 'replace')) + tmp = SafeHTMLParser.uriregex2.sub(r'\1', tmp) + self.raw += tmp def is_html(self, text = None, allow_picture = False): if text: -- 2.45.1 From 976af4b3cd8ad5560ef0ab8e376c5ece79313cb4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Mar 2016 09:21:10 +0800 Subject: [PATCH 0307/1102] Empty resource loader for messageview MessageView does not currently load external resources (QTextBrowser by default interprets all external resources as local file names and tries to load them like that. This can, in the future, be implemented. For example, if SOCKS (Tor) is used, the resource could be loaded through the SOCKS too. This commit is a skeleton for it that does not actually do anything and can be filled with an implementation that does the loading. --- src/bitmessageqt/messageview.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 66aac2cb..9dd40a54 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -60,6 +60,21 @@ class MessageView(QtGui.QTextBrowser): if reply == QtGui.QMessageBox.Yes: QtGui.QDesktopServices.openUrl(link) + def loadResource (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 -- 2.45.1 From b3b69b1eac1e3a4e644e762038448994f03de265 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Mar 2016 09:25:39 +0800 Subject: [PATCH 0308/1102] deleteRowFromMessagelist implementation Rows are deleted from a message list in multiple places, and this is an attempt to refactor it so that it is done in one function. It's not used anywhere yet. --- src/bitmessageqt/__init__.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index f971728a..cbedfc17 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3073,6 +3073,24 @@ class MyForm(settingsmixin.SMainWindow): self.statusBar().showMessage(_translate( "MainWindow", "Error: You cannot add the same address to your blacklist twice. Try renaming the existing one if you want.")) + def deleteRowFromMessagelist(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(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(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(Qt.UserRole).toPyObject() == ackData: + messageList.removeRow(i) + # Send item on the Inbox tab to trash def on_action_InboxTrash(self): tableWidget = self.getCurrentMessagelist() -- 2.45.1 From 9e2ae4eeb54f01d5925d83e420009f6953c83c4f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Mar 2016 09:50:31 +0800 Subject: [PATCH 0309/1102] Allow close to tray PyBitmessage can now close to tray. Even though the main code was there, the UI and config variable were missing. Fixes Bitmessage#564 --- src/bitmessageqt/__init__.py | 12 ++++++++---- src/bitmessageqt/settings.py | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cbedfc17..99449da6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2440,6 +2440,8 @@ class MyForm(settingsmixin.SMainWindow): self.settingsDialogInstance.ui.checkBoxStartOnLogon.isChecked())) shared.config.set('bitmessagesettings', 'minimizetotray', str( self.settingsDialogInstance.ui.checkBoxMinimizeToTray.isChecked())) + shared.config.set('bitmessagesettings', 'trayonclose', str( + self.settingsDialogInstance.ui.checkBoxTrayOnClose.isChecked())) shared.config.set('bitmessagesettings', 'showtraynotifications', str( self.settingsDialogInstance.ui.checkBoxShowTrayNotifications.isChecked())) shared.config.set('bitmessagesettings', 'startintray', str( @@ -2850,15 +2852,15 @@ class MyForm(settingsmixin.SMainWindow): # window close event def closeEvent(self, event): self.appIndicatorHide() - minimizeonclose = False + trayonclose = False try: - minimizeonclose = shared.config.getboolean( - 'bitmessagesettings', 'minimizeonclose') + trayonclose = shared.config.getboolean( + 'bitmessagesettings', 'trayonclose') except Exception: pass - if minimizeonclose: + if trayonclose: # minimize the application event.ignore() else: @@ -4069,6 +4071,8 @@ class settingsDialog(QtGui.QDialog): shared.config.getboolean('bitmessagesettings', 'startonlogon')) self.ui.checkBoxMinimizeToTray.setChecked( shared.config.getboolean('bitmessagesettings', 'minimizetotray')) + self.ui.checkBoxTrayOnClose.setChecked( + shared.safeConfigGetBoolean('bitmessagesettings', 'trayonclose')) self.ui.checkBoxShowTrayNotifications.setChecked( shared.config.getboolean('bitmessagesettings', 'showtraynotifications')) self.ui.checkBoxStartInTray.setChecked( diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index efdfc1b7..e6fbbc66 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -44,13 +44,22 @@ 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.checkBoxStartInTray = QtGui.QCheckBox(self.tabUserInterface) + 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.setObjectName(_fromUtf8("checkBoxStartInTray")) - self.formLayout.setWidget(1, QtGui.QFormLayout.SpanningRole, self.checkBoxStartInTray) - self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.tabUserInterface) + self.formLayoutTray.setWidget(0, QtGui.QFormLayout.SpanningRole, self.checkBoxStartInTray) + self.checkBoxMinimizeToTray = QtGui.QCheckBox(self.groupBoxTray) self.checkBoxMinimizeToTray.setChecked(True) self.checkBoxMinimizeToTray.setObjectName(_fromUtf8("checkBoxMinimizeToTray")) - self.formLayout.setWidget(2, QtGui.QFormLayout.LabelRole, self.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.checkBoxShowTrayNotifications = QtGui.QCheckBox(self.tabUserInterface) self.checkBoxShowTrayNotifications.setObjectName(_fromUtf8("checkBoxShowTrayNotifications")) self.formLayout.setWidget(3, QtGui.QFormLayout.LabelRole, self.checkBoxShowTrayNotifications) @@ -446,8 +455,10 @@ 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.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)) -- 2.45.1 From af193a1bcac469ceae656c2be1dbe2a74800668f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Mar 2016 15:23:51 +0800 Subject: [PATCH 0310/1102] Keybindings - delete key now works when message body is focused as well - N for next message (down) - P for previous message (up) - R for reply - C for compose - F for find - Find is now dynamic if the search text is least 3 characters long Fixes Bitmessage#655 Addresses #155 --- src/bitmessageqt/__init__.py | 149 ++++++++++++++++++++++++++++------- 1 file changed, 121 insertions(+), 28 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 99449da6..8deb166b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -28,6 +28,7 @@ from bitmessageui import * from namecoin import namecoinConnection, ensureNamecoinOptions from newaddressdialog import * from newaddresswizard import * +from messageview import MessageView from migrationwizard import * from foldertree import * from addaddressdialog import * @@ -680,11 +681,17 @@ class MyForm(settingsmixin.SMainWindow): # Initialize the inbox search QtCore.QObject.connect(self.ui.inboxSearchLineEdit, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditPressed) + "returnPressed()"), self.inboxSearchLineEditReturnPressed) QtCore.QObject.connect(self.ui.inboxSearchLineEditSubscriptions, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditPressed) + "returnPressed()"), self.inboxSearchLineEditReturnPressed) QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL( - "returnPressed()"), self.inboxSearchLineEditPressed) + "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) # Initialize the Blacklist or Whitelist if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': @@ -785,6 +792,21 @@ class MyForm(settingsmixin.SMainWindow): "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. @@ -1101,7 +1123,6 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.setSortingEnabled(False) tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) - tableWidget.keyPressEvent = self.tableWidgetSentKeyPressEvent # Load messages from database file def loadMessagelist(self, tableWidget, account, folder="inbox", where="", what="", unreadOnly = False): @@ -1131,7 +1152,7 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.horizontalHeader().setSortIndicator(3, Qt.DescendingOrder) tableWidget.setSortingEnabled(True) - tableWidget.keyPressEvent = self.tableWidgetInboxKeyPressEvent + tableWidget.selectRow(0) # create application indicator def appIndicatorInit(self, app): @@ -1453,17 +1474,65 @@ class MyForm(settingsmixin.SMainWindow): else: self.tray.showMessage(title, subtitle, 1, 2000) - # set delete key in inbox - def tableWidgetInboxKeyPressEvent(self, event): - if event.key() == QtCore.Qt.Key_Delete: - self.on_action_InboxTrash() - return QtGui.QTableWidget.keyPressEvent(self.getCurrentMessagelist(), event) + # tree + def treeWidgetKeyPressEvent(self, event): + return self.handleKeyPress(event, self.getCurrentTreeWidget()) - # set delete key in inbox - def tableWidgetSentKeyPressEvent(self, event): + # 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() if event.key() == QtCore.Qt.Key_Delete: - self.on_action_SentTrash() - return QtGui.QTableWidget.keyPressEvent(self.getCurrentMessagelist(), event) + if isinstance (focus, MessageView) or isinstance(focus, QtGui.QTableWidget): + if folder == "sent": + self.on_action_SentTrash() + else: + self.on_action_InboxTrash() + event.ignore() + elif 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(0) + self.ui.tabWidget.setCurrentIndex(1) + 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) # menu button 'manage keys' def click_actionManageKeys(self): @@ -2952,6 +3021,21 @@ 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) @@ -3012,12 +3096,7 @@ class MyForm(settingsmixin.SMainWindow): logger.debug('original sent to a chan. Setting the to address in the reply to the chan address.') self.ui.lineEditTo.setText(str(toAddressAtCurrentInboxRow)) - listOfAddressesInComboBoxSendFrom = [str(widget['from'].itemData(i).toPyObject()) for i in range(widget['from'].count())] - if toAddressAtCurrentInboxRow in listOfAddressesInComboBoxSendFrom: - currentIndex = listOfAddressesInComboBoxSendFrom.index(toAddressAtCurrentInboxRow) - widget['from'].setCurrentIndex(currentIndex) - else: - widget['from'].setCurrentIndex(0) + self.setSendFromComboBox(toAddressAtCurrentInboxRow) quotedText = self.quoted_text(unicode(messageAtCurrentInboxRow, 'utf-8', 'replace')) widget['message'].setPlainText(quotedText) @@ -3536,7 +3615,7 @@ class MyForm(settingsmixin.SMainWindow): except: return self.ui.textEditInboxMessage - def getCurrentSearchLine(self, currentIndex = None): + def getCurrentSearchLine(self, currentIndex = None, retObj = False): if currentIndex is None: currentIndex = self.ui.tabWidget.currentIndex(); messagelistList = [ @@ -3546,7 +3625,10 @@ class MyForm(settingsmixin.SMainWindow): self.ui.inboxSearchLineEditChans, ] if currentIndex >= 0 and currentIndex < len(messagelistList): - return messagelistList[currentIndex].text().toUtf8().data() + if retObj: + return messagelistList[currentIndex] + else: + return messagelistList[currentIndex].text().toUtf8().data() else: return None @@ -3859,17 +3941,28 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuSent.exec_(self.ui.tableWidgetInbox.mapToGlobal(point)) - def inboxSearchLineEditPressed(self): - searchLine = self.getCurrentSearchLine() - searchOption = self.getCurrentSearchOption() - messageTextedit = self.getCurrentMessageTextedit() - if messageTextedit: - messageTextedit.setPlainText(QString("")) + 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() -- 2.45.1 From 113ceb08684f47de9c2192a937d5ef51fd0b155d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 1 Mar 2016 15:24:34 +0800 Subject: [PATCH 0311/1102] Email links "From" Clicking email links now sets "From" based on the message the link is in. --- src/bitmessageqt/messageview.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index 9dd40a54..a987d3ba 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -49,6 +49,7 @@ class MessageView(QtGui.QTextBrowser): QtGui.QApplication.activeWindow().ui.lineEditSubject.setText(link.queryItemValue("subject")) if link.hasQueryItem("body"): QtGui.QApplication.activeWindow().ui.textEditMessage.setText(link.queryItemValue("body")) + QtGui.QApplication.activeWindow().setSendFromComboBox() QtGui.QApplication.activeWindow().ui.tabWidgetSend.setCurrentIndex(0) QtGui.QApplication.activeWindow().ui.tabWidget.setCurrentIndex(1) QtGui.QApplication.activeWindow().ui.textEditMessage.setFocus() -- 2.45.1 From a79f6cce3babc7dff5f244c909fd49159faf11e2 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 08:49:20 +0100 Subject: [PATCH 0312/1102] Clipboard copy unicode Copying unicode subjects to clipboard didn't work. Fixes #183 --- src/bitmessageqt/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8deb166b..9a8e113f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3758,8 +3758,9 @@ class MyForm(settingsmixin.SMainWindow): text = str(tableWidget.item(currentRow, currentColumn).label) else: text = tableWidget.item(currentRow, currentColumn).data(Qt.UserRole) + text = unicode(str(text), 'utf-8', 'ignore') clipboard = QtGui.QApplication.clipboard() - clipboard.setText(str(text)) + clipboard.setText(text) #set avatar functions def on_action_TreeWidgetSetAvatar(self): -- 2.45.1 From ed5c8a01ef302e2988b35ca1bfbb27dbbd0700a7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 09:07:16 +0100 Subject: [PATCH 0313/1102] loadResource incorrect parameters --- src/bitmessageqt/messageview.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/messageview.py b/src/bitmessageqt/messageview.py index a987d3ba..c322e421 100644 --- a/src/bitmessageqt/messageview.py +++ b/src/bitmessageqt/messageview.py @@ -61,7 +61,7 @@ class MessageView(QtGui.QTextBrowser): if reply == QtGui.QMessageBox.Yes: QtGui.QDesktopServices.openUrl(link) - def loadResource (restype, name): + def loadResource (self, restype, name): if restype == QtGui.QTextDocument.ImageResource and name.scheme() == "bmmsg": pass # QImage correctImage; -- 2.45.1 From 2adafdaadc057790cf06c16fa0840ee741f55a54 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 09:07:39 +0100 Subject: [PATCH 0314/1102] Improved URI detector --- src/bitmessageqt/safehtmlparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index 78f89888..e56fd14c 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -21,7 +21,7 @@ class SafeHTMLParser(HTMLParser): 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] src_schemes = [ "data" ] - uriregex1 = re.compile(r'(\b(?:https?|telnet|gopher|file|wais|ftp):[\w/#~:.?+=&%@!\-.:;?\\-]+?(?=[.:?\-]*(?:[^\w/#~:;.?+=&%@!\-.:?\-]|$)))') + uriregex1 = re.compile(r'(?i)\b((?:(https?|ftp):(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?]))') uriregex2 = re.compile(r' Date: Sat, 12 Mar 2016 09:15:08 +0100 Subject: [PATCH 0315/1102] Email gateway interface usability improvements - don't allow status request / settings unless registered already - if registered, status request is the default selected option Fixes #182 --- src/bitmessageqt/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9a8e113f..7266d83f 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4429,7 +4429,12 @@ class EmailGatewayDialog(QtGui.QDialog): acct = accountClass(addressAtCurrentRow) if isinstance(acct, GatewayAccount): self.ui.radioButtonUnregister.setEnabled(True) + self.ui.radioButtonStatus.setEnabled(True) + self.ui.radioButtonStatus.setChecked(True) + self.ui.radioButtonSettings.setEnabled(True) else: + self.ui.radioButtonStatus.setEnabled(False) + self.ui.radioButtonSettings.setEnabled(False) self.ui.radioButtonUnregister.setEnabled(False) label = shared.config.get(addressAtCurrentRow, 'label') if label.find("@mailchuck.com") > -1: -- 2.45.1 From 47bc85f0b60ef6ae4a095ddc091808247d40e2bf Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 09:58:16 +0100 Subject: [PATCH 0316/1102] Sent folder in chans extended Previously, it only showed message sent to the selected chan address. Now it shows both those sent to and sent from the chan address. Fixes #181 --- src/bitmessageqt/__init__.py | 6 +++++- src/helper_search.py | 9 +++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 7266d83f..8b103c92 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1104,10 +1104,14 @@ class MyForm(settingsmixin.SMainWindow): # Load Sent items from database def loadSent(self, tableWidget, account, where="", what=""): - if tableWidget == self.ui.tableWidgetInboxChans or tableWidget == self.ui.tableWidgetInboxSubscriptions: + 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' else: tableWidget.setColumnHidden(0, False) tableWidget.setColumnHidden(1, True) diff --git a/src/helper_search.py b/src/helper_search.py index 9ebdddbe..2217974f 100644 --- a/src/helper_search.py +++ b/src/helper_search.py @@ -41,8 +41,13 @@ def search_sql(xAddress = "toaddress", account = None, folder = "inbox", where = sqlStatementParts = [] sqlArguments = [] if account is not None: - sqlStatementParts.append(xAddress + " = ? ") - sqlArguments.append(account) + 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" -- 2.45.1 From da036c6b6bcbd891217bad55d230ebb9d5c0aee1 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 10:58:48 +0100 Subject: [PATCH 0317/1102] UTF fixes Label edits now accept and save utf8 characters. Addresses #180 Still need to check how it behaves on invalid chars. --- src/bitmessageqt/__init__.py | 2 +- src/bitmessageqt/foldertree.py | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 8b103c92..6f52a98d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3998,7 +3998,7 @@ class MyForm(settingsmixin.SMainWindow): if item.type == AccountMixin.ALL: return - newLabel = str(item.text(0)) + newLabel = unicode(item.text(0), 'utf-8', 'ignore') oldLabel = item.defaultLabel() # unchanged, do not do anything either diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index b9112b49..370e372f 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -171,7 +171,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): return unicode(str(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') else: try: - return unicode(shared.config.get(self.address, 'label'), 'utf-8)') + return unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') except: return unicode(self.address, 'utf-8') @@ -210,7 +210,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def setData(self, column, role, value): if role == QtCore.Qt.EditRole and self.type != AccountMixin.SUBSCRIPTION: if isinstance(value, QtCore.QVariant): - shared.config.set(str(self.address), 'label', str(value.toString())) + shared.config.set(str(self.address), 'label', str(value.toString().toUtf8())) else: shared.config.set(str(self.address), 'label', str(value)) shared.writeKeysFile() @@ -236,8 +236,8 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): if self.treeWidget().header().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True if self._getSortRank() == other._getSortRank(): - x = self._getLabel().decode('utf-8').lower() - y = other._getLabel().decode('utf-8').lower() + x = self._getLabel().lower() + y = other._getLabel().lower() return x < y return (not reverse if self._getSortRank() < other._getSortRank() else reverse) @@ -261,7 +261,7 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): if queryreturn != []: for row in queryreturn: retval, = row - return unicode(retval, 'utf-8') + return unicode(retval, 'utf-8', 'ignore') return unicode(self.address, 'utf-8') def setType(self): @@ -270,10 +270,11 @@ class Ui_SubscriptionWidget(Ui_AddressWidget, AccountMixin): def setData(self, column, role, value): if role == QtCore.Qt.EditRole: + from debug import logger if isinstance(value, QtCore.QVariant): - label = str(value.toString()) + label = str(value.toString().toUtf8()).decode('utf-8', 'ignore') else: - label = str(value) + label = unicode(value, 'utf-8', 'ignore') sqlExecute( '''UPDATE subscriptions SET label=? WHERE address=?''', label, self.address) @@ -300,7 +301,7 @@ class MessageList_AddressWidget(QtGui.QTableWidgetItem, AccountMixin, SettingsMi queryreturn = None if self.type in (AccountMixin.NORMAL, AccountMixin.CHAN, AccountMixin.MAILINGLIST): try: - newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8)') + newLabel = unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') except: queryreturn = sqlQuery( '''select label from addressbook where address=?''', self.address) @@ -455,7 +456,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): if self.tableWidget().horizontalHeader().sortIndicatorOrder() == QtCore.Qt.DescendingOrder: reverse = True if self.type == other.type: - return self.label.decode('utf-8').lower() < other.label.decode('utf-8').lower() + 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) -- 2.45.1 From 8d8cfe85559c21dcd54d7f679bb5391c8d9bcabb Mon Sep 17 00:00:00 2001 From: mailchuck Date: Sat, 12 Mar 2016 11:03:08 +0100 Subject: [PATCH 0318/1102] More unicode fixes Addresses #180 --- src/bitmessageqt/foldertree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index 370e372f..f9ab7717 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -434,7 +434,7 @@ class Ui_AddressBookWidgetItem(QtGui.QTableWidgetItem, AccountMixin): def setData(self, role, value): if role == QtCore.Qt.EditRole: if isinstance(value, QtCore.QVariant): - self.label = str(value.toString()) + self.label = str(value.toString().toUtf8()) else: self.label = str(value) if self.type in (AccountMixin.NORMAL, AccountMixin.MAILINGLIST, AccountMixin.CHAN): -- 2.45.1 From a30d5af9488eef05b69ae1dfbf252a18e1bef1a8 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Mar 2016 18:30:47 +0100 Subject: [PATCH 0319/1102] Global Sent and Trash folders --- src/bitmessageqt/__init__.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6f52a98d..fc046642 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -537,6 +537,8 @@ class MyForm(settingsmixin.SMainWindow): db[None] = {} db[None]["inbox"] = total db[None]["new"] = total + db[None]["sent"] = 0 + db[None]["trash"] = 0 enabled[None] = True if treeWidget.isSortingEnabled(): @@ -587,8 +589,6 @@ class MyForm(settingsmixin.SMainWindow): for folder in folders: if toAddress is not None and folder == "new": continue - if toAddress is None and folder in ["trash", "sent"]: - continue subwidget = Ui_FolderWidget(widget, j, toAddress, folder, db[toAddress][folder]) unread += db[toAddress][folder] j += 1 @@ -992,13 +992,19 @@ class MyForm(settingsmixin.SMainWindow): addressItem = root.child(i) if addressItem.type != AccountMixin.ALL and address is not None and addressItem.data(0, QtCore.Qt.UserRole) != address: continue - updateUnreadCount(addressItem) + if folder not in ["trash"]: + updateUnreadCount(addressItem) if addressItem.childCount == 0: continue for j in range(addressItem.childCount()): folderItem = addressItem.child(j) if folder is not None and folderItem.folderName != folder and addressItem.type != AccountMixin.ALL: continue + if addressItem.type == AccountMixin.ALL: + if folder in ["sent", "trash"] and folderItem.folderName != folder: + continue + if folder in ["inbox", "new"] and folderItem.folderName not in ["inbox", "new"]: + continue updateUnreadCount(folderItem) def addMessageListItem(self, tableWidget, items): @@ -1114,7 +1120,10 @@ class MyForm(settingsmixin.SMainWindow): xAddress = 'both' else: tableWidget.setColumnHidden(0, False) - tableWidget.setColumnHidden(1, True) + if account is None: + tableWidget.setColumnHidden(1, False) + else: + tableWidget.setColumnHidden(1, True) xAddress = 'fromaddress' tableWidget.setSortingEnabled(False) @@ -2396,7 +2405,7 @@ class MyForm(settingsmixin.SMainWindow): 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: + 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, "") -- 2.45.1 From 2e47ab0cd20789b3166d9ed3c21f09bc0b08a46c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 16 Mar 2016 18:42:08 +0100 Subject: [PATCH 0320/1102] Keyboard modifiers with quick navigation The quick navigation key disrupted keybindings with keyboard modifiers, like Ctrl-C for copy. This restricts the quick navigation only where no keyboard modifiers are active. Fixes #184 --- src/bitmessageqt/__init__.py | 59 ++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index fc046642..3b6fb1bc 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1509,35 +1509,36 @@ class MyForm(settingsmixin.SMainWindow): else: self.on_action_InboxTrash() event.ignore() - elif 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(0) - self.ui.tabWidget.setCurrentIndex(1) - self.ui.lineEditTo.setFocus() - event.ignore() - elif event.key() == QtCore.Qt.Key_F: - searchline = self.getCurrentSearchLine(retObj = True) - if searchline: - searchline.setFocus() - 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(0) + self.ui.tabWidget.setCurrentIndex(1) + 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): -- 2.45.1 From c5363c3c5ec227be943d8ee1a0e5b4176e3cdf1d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 18 Mar 2016 14:09:28 +0100 Subject: [PATCH 0321/1102] Add bitcoin URI handler for message viewer --- src/bitmessageqt/safehtmlparser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/safehtmlparser.py b/src/bitmessageqt/safehtmlparser.py index e56fd14c..77fc9d70 100644 --- a/src/bitmessageqt/safehtmlparser.py +++ b/src/bitmessageqt/safehtmlparser.py @@ -21,7 +21,7 @@ class SafeHTMLParser(HTMLParser): 'th', 'thead', 'tr', 'tt', 'u', 'ul', 'var', 'video'] replaces = [["&", "&"], ["\"", """], ["<", "<"], [">", ">"], ["\n", "
"], ["\t", "    "], [" ", "  "], [" ", "  "], ["
", "
 "]] src_schemes = [ "data" ] - uriregex1 = re.compile(r'(?i)\b((?:(https?|ftp):(?:/{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'(?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`!()\[\]{};:\'".,<>?]))') uriregex2 = re.compile(r'
Date: Fri, 18 Mar 2016 16:39:29 +0100 Subject: [PATCH 0322/1102] Preliminary Tor hidden service support --- src/class_outgoingSynSender.py | 13 +++++++++---- src/class_receiveDataThread.py | 5 +++++ src/shared.py | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/class_outgoingSynSender.py b/src/class_outgoingSynSender.py index 81403053..0fa74ad8 100644 --- a/src/class_outgoingSynSender.py +++ b/src/class_outgoingSynSender.py @@ -29,14 +29,19 @@ 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 - shared.knownNodesLock.acquire() if shared.trustedPeer: + shared.knownNodesLock.acquire() peer = shared.trustedPeer shared.knownNodes[self.streamNumber][peer] = time.time() + shared.knownNodesLock.release() else: - peer, = random.sample(shared.knownNodes[self.streamNumber], 1) - shared.knownNodesLock.release() - + while True: + shared.knownNodesLock.acquire() + peer, = random.sample(shared.knownNodes[self.streamNumber], 1) + shared.knownNodesLock.release() + if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none' or peer.host.find(".onion") == -1: + break + time.sleep(1) return peer def stopThread(self): diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index e2a25a3e..aec343d8 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -1,5 +1,6 @@ doTimingAttackMitigation = False +import base64 import errno import math import time @@ -517,6 +518,10 @@ class receiveDataThread(threading.Thread): 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 == "": diff --git a/src/shared.py b/src/shared.py index f18b4066..b6ed64e4 100644 --- a/src/shared.py +++ b/src/shared.py @@ -9,6 +9,7 @@ useVeryEasyProofOfWorkForTesting = False # If you set this to True while on the # Libraries. +import base64 import collections import ConfigParser import os @@ -150,7 +151,7 @@ def isInSqlInventory(hash): def encodeHost(host): if host.find('.onion') > -1: - return '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x7F\x00\x00\x01' + 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) -- 2.45.1 From 3fcaa4723210d9ebcb26affcdbfa3d2ccce2d8c1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 18 Mar 2016 17:37:38 +0100 Subject: [PATCH 0323/1102] Ack received translation typo Fixes Bitmessage#644 --- src/class_objectProcessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index db9cc27c..485e5be9 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -324,7 +324,7 @@ class objectProcessor(threading.Thread): 'ackreceived', int(time.time()), data[-32:]) - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (data[-32:], tr.translateText("MainWindow",'Acknowledgement of the message received. %1').arg(l10n.formatTimestamp())))) + 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.') -- 2.45.1 From d63ecfc566c7ab13d8fd0b7038cbd0df29bcdba7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 18 Mar 2016 18:56:40 +0100 Subject: [PATCH 0324/1102] Translation update - typos - updated German translation - Fixes Bitmessage#844 --- src/bitmessageqt/__init__.py | 2 +- src/class_objectProcessor.py | 2 +- src/class_singleWorker.py | 2 +- src/translations/bitmessage_de.pro | 6 + src/translations/bitmessage_de.qm | Bin 62989 -> 70557 bytes src/translations/bitmessage_de.ts | 993 ++++++++++++++++++++--------- 6 files changed, 688 insertions(+), 317 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3b6fb1bc..16cd780e 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2421,7 +2421,7 @@ class MyForm(settingsmixin.SMainWindow): if hasattr(acct, "feedback") and acct.feedback != GatewayAccount.ALL_OK: if acct.feedback == GatewayAccount.REGISTRATION_DENIED: self.dialog = EmailGatewayRegistrationDialog(self, _translate("EmailGatewayRegistrationDialog", "Registration failed:"), - _translate("EmailGatewayRegistrationDialog", "The requested email address is not available, please try a new one. Fill out the new designed email address (including @mailchuck.com) below:") + _translate("EmailGatewayRegistrationDialog", "The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below:") ) if self.dialog.exec_(): email = str(self.dialog.ui.lineEditEmail.text().toUtf8()) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 485e5be9..a2402643 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -26,7 +26,7 @@ import l10n class objectProcessor(threading.Thread): """ The objectProcessor thread, of which there is only one, receives network - objecs (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. + objects (msg, broadcast, pubkey, getpubkey) from the receiveDataThreads. """ def __init__(self): threading.Thread.__init__(self, name="objectProcessor") diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index e1e71734..421612db 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -813,7 +813,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType, toStreamNumber, encryptedPayload, embeddedTime, '') shared.inventorySets[toStreamNumber].add(inventoryHash) if shared.config.has_section(toaddress) or not checkBitfield(behaviorBitfield, shared.BITFIELD_DOESACK): - shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent on %1").arg(l10n.formatTimestamp())))) + shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Sent at %1").arg(l10n.formatTimestamp())))) else: # not sending to a chan or one of my addresses shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) diff --git a/src/translations/bitmessage_de.pro b/src/translations/bitmessage_de.pro index 56e2b4f1..b5f58227 100644 --- a/src/translations/bitmessage_de.pro +++ b/src/translations/bitmessage_de.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 400ac465d38753ea85fe826bdc11a1e30678d9e5..dfe5c804b9e1d80210c241045aa1a19c5445e10c 100644 GIT binary patch delta 12414 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 KVuVG;F#iqTl&A&( diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 87953ee7..a091370f 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -1,5 +1,6 @@ - + + AddAddressDialog @@ -18,200 +19,310 @@ Adresse + + EmailGatewayDialog + + + Email gateway + E-Mail Schnittstelle + + + + Register on email gateway + An E-Mailschnittstelle registrieren + + + + Account status at email gateway + Statusanfrage der E-Mailschnittstelle + + + + Change account settings at email gateway + E-Mailschnittstelleneinstellungen ändern + + + + Unregister from email gateway + Von der E-Mailschnittstelle abmelden + + + + Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. + E-Mailschnittstelle ermöglicht es mit anderen E-Mailnutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mailschnittstelle (@mailchuck.com) verfügbar. + + + + Desired email address (including @mailchuck.com): + Gewünschte E-Mailaddresse (inkl. @mailchuck.com): + + + + EmailGatewayRegistrationDialog + + + Registration failed: + Registrierung fehlgeschlagen: + + + + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: + Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: + + + + Email gateway registration + E-Mailschnittstellenregistrierung + + + + Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. +Please type the desiged email address (including @mailchuck.com) below: + E-Mailschnittstelle ermöglicht es mit anderen E-Mailnutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mailschnittstelle (@mailchuck.com) verfügbar. +Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: + + + + 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 - + 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 - Antworten + Antworten - + Add sender to your Address Book Absender zum Adressbuch hinzufügen - + Move to Trash In den Papierkorb verschieben - + View HTML code as formatted text HTML als formatierten Text anzeigen - + Save message as... Nachricht speichern unter... - + New Neu - + Enable Aktivieren - + Disable Deaktivieren - + Copy address to clipboard Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + 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 - + Add new entry Neuen Eintrag erstellen - + Waiting for their encryption key. Will request it again soon. Warte auf den Verschlüsselungscode. Wird bald erneut angefordert. - + Encryption key request queued. Verschlüsselungscode-Anforderung steht aus. - + Queued. In Warteschlange. - + Message sent. Waiting for acknowledgement. Sent at %1 - Nachricht gesendet. Warten auf Bestätigung. Gesendet %1 + Nachricht gesendet. Warte 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 + 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. @@ -220,17 +331,17 @@ It is important that you back up this file. 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.) @@ -240,97 +351,97 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn (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". @@ -345,32 +456,32 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. @@ -380,52 +491,52 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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 + 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. + 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. @@ -435,77 +546,77 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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? 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + Moved items to trash. Objekt in den Papierkorb verschoben. - + Save As... Speichern unter... - + Write error. Fehler beim speichern. - + No addresses selected. Keine Adresse ausgewählt. @@ -516,89 +627,89 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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 + Posteingang Load from Address book - Aus Adressbuch wählen + Aus Adressbuch wählen Message: - Nachricht: + Nachricht: - + Subject: Betreff: Send to one or more specific people - Nachricht an eine oder mehrere spezifische Personen + Nachricht an eine oder mehrere spezifische Personen @@ -614,277 +725,277 @@ p, li { white-space: pre-wrap; } <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 + 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. + Beachten Sie, dass Rundrufe nur mit Ihrer Adresse verschlüsselt werden. Jeder, der Ihre Adresse kennt, kann diese Nachrichten lesen. Status - Status + Status Sent - Gesendet + Gesendet Label (not shown to anyone) - Bezeichnung (wird niemandem gezeigt) + Bezeichnung (wird niemandem gezeigt) - + Address Adresse Stream - Datenstrom + Datenstrom Your Identities - Ihre Identitäten + Ihre Identitäten 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). + 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). - + Add new Subscription Neues Abonnement anlegen Label - Bezeichnung + Bezeichnung - + Subscriptions Abonnements 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. + 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. - + Name or Label Name oder Bezeichnung - + 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 + Verbindungen insgesamt: 0 Since startup at asdf: - Seit start um asdf: + Seit start um asdf: Processed 0 person-to-person message. - 0 Person-zu-Person-Nachrichten verarbeitet. + 0 Person-zu-Person-Nachrichten verarbeitet. Processed 0 public key. - 0 öffentliche Schlüssel verarbeitet. + 0 öffentliche Schlüssel verarbeitet. Processed 0 broadcast. - 0 Rundrufe verarbeitet. + 0 Rundrufe verarbeitet. - + Network Status Netzwerkstatus - + 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 @@ -914,133 +1025,404 @@ p, li { white-space: pre-wrap; } Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - + Mark Unread Als ungelesen markieren - + Fetched address from namecoin identity. Adresse aus Namecoin Identität geholt. - + Testing... teste... - + Fetch Namecoin ID Hole Namecoin ID - + Ctrl+Q Strg+Q - + F1 F1 - + Set avatar... Avatar wählen... - + Bad address version number - + Falsche Addressenversionnummer - + Your address version number must be a number: either 3 or 4. - + Die Addressenversionnummer muss eine Zahl sein, entweder 3 oder 4. - + Your address version number must be either 3 or 4. - + Die Addressenversionnnummer muss entweder 3 oder 4 sein. - + Inventory lookups per second: %1 Inventory lookups pro Sekunde: %1 - + 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 als die, die Bitmessage auf das erste Wiederversenden wartet. Deswegen werden Ihre Nachrichten nie wiederversendet. - + 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 unterstützt + 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. - + Enter an address above. - + Eine Addresse oben ausfüllen. - + Address is an old type. We cannot display its past broadcasts. - + Alter Addressentyp. Wir können deren vorige Rundruf-Nachrichten nicht anzeigen. - + 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 + Inventory lookups pro Sekunde: 0 + + + + Reply to sender + Dem Absender Antworten + + + + Reply to channel + Antworten ins Chan + + + + Add sender to your Blacklist + Absender in die Blacklist eintragen + + + + Undelete + Wiederherstellen + + + + Email gateway + E-Mail Schnittstelle + + + + 1 hour + 1 Stunde + + + + %1 hours + %1 Stunden + + + + %1 days + %1 Tage + + + + Channel + Chan + + + + Objects to be synced: %1 + Zu synchronisierende Objektanzahl: %1 + + + + Down: %1/s Total: %2 + Herunter: %1/s Insg.: %2 + + + + Up: %1/s Total: %2 + Hoch: %1/s Insg.: %2 + + + + 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 + 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. + + + + + 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. + + + + Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + Nachricht befindet sich in der Warteschleife. + + + + Sending email gateway registration request + E-Mailschnittstelle-Registrierungsantrag wird versandt. + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + Fehler: Dieselbe Addresse kann nicht doppelt in die Abonnements eingetragen werden. Alternativ können Sie die bestehende umbenennen. + + + + Number needed + Zahl erforderlich + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + E-Mailschnittestelle-Abmeldeantrag wird versandt + + + + Sending email gateway status request + E-Mailschnittstelle Statusantrag wird versandt + + + + 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. Alternativ können Sie die bestehende umbenennen. + + + + Undeleted item. + Nachricht wiederhergestellt. + + + + 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, die bereits erhaltene Nachrichten werden unaufrufbar. Überlegen Sie sich vielleicht das Abonnement statdessen zu deaktivieren. 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. Überlegen Sie sich vielleicht das Chan statdessen zu deaktivieren. 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? + + + + Some data encoded in the address is malformed. + + + + + Identities + Identitäten + + + + New Identity + Neue Identität + + + + Messages + Nachrichten + + + + Address book + Addressbuch + + + + Add Contact + Kontakt hinzufügen + + + <!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;"> +</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> - - Inventory lookups per second: 0 - Inventory lookups pro Sekunde: 0 + + Send ordinary Message + Ordentliche Nachricht senden + + + + Send Message to your Subscribers + Nachricht an Abonnenten senden + + + + TTL: + + + + + X days + X Tage + + + + Chans + Chans + + + + Add Chan + Chan hinzufügen + + + + Total connections: + Verbindungen insgesamt: + + + + Since startup: + Seit Start: + + + + Objects to be synced: + Zu synchronisierende Objektanzahl: + + + + 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. + + + + Down: 0 KB/s + Herunter: 0 KB/s + + + + Up: 0 KB/s + Hoch: 0 KB/s + + + + Contact support + Unterstütung anfordern + + + + All accounts + + + + + Zoom level %1% + @@ -1191,7 +1573,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 zu allen Abonnenten weitergeleitet (Der Inhalt ist dann öffentlich). + Nachrichten an eine Pseudo-Mailinglistenadresse werden automatisch an alle Abonnenten weitergeleitet (Der Inhalt ist dann öffentlich). @@ -1216,7 +1598,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei version ? Version ? - + Copyright © 2013 Jonathan Warren Copyright © 2013 Jonathan Warren @@ -1233,7 +1615,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1270,13 +1652,18 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei <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> + <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: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1415,207 +1802,207 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei settingsDialog - + Settings Einstellungen - + Start Bitmessage on user login Bitmessage nach dem Hochfahren automatisch starten - + Start Bitmessage in the tray (don't show main window) Bitmessage minimiert starten (zeigt das Hauptfenster nicht an) - + Minimize to tray In den Systemtray minimieren - + 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. - + User Interface Benutzerinterface - + Listening port TCP-Port - + Listen for connections on port: Wartet auf Verbindungen auf Port: - + Proxy server / Tor Proxy-Server / Tor - + Type: Typ: - + none keiner - + SOCKS4a SOCKS4a - + SOCKS5 SOCKS5 - + Server hostname: Servername: - + Port: Port: - + Authentication Authentifizierung - + Username: Benutzername: - + Pass: Kennwort: - + Network Settings Netzwerkeinstellungen - + 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 - + 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 @@ -1625,124 +2012,102 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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) + Benutze Identicons (Automatisch generierte Icons zu einer Bitcoinadresse) - + Interface Language - Sprachauswahl + Sprachauswahl - + System Settings system - + Vom System übernehmen - - 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 - + Andere (in keys.dat einstellen) - + <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>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 Neusendung - + Reply below Quote Antworte unter zitierter Nachricht - + 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 + + + Tray + + + + + Close to tray + + + + + UPnP: + UPnP: + + + + Hardware GPU acceleration (OpenCL) + Hardwaregrafikkartenbeschleunigung (OpenCL) + -- 2.45.1 From f8dcb965ea619afcc717aabbf1591e8cfaa07de4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 18 Mar 2016 18:59:20 +0100 Subject: [PATCH 0325/1102] Grammar fix - Fixes #179 - Thanks to @Erkan-Yilmaz --- src/bitmessageqt/support.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index 2c78ea32..4742e175 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -21,7 +21,7 @@ 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 are you trying to do: +Please describe what you are trying to do: Please describe what you expect to happen: -- 2.45.1 From e03803e4e8674d42b26d4ac81ad13bf7d668535e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 18 Mar 2016 20:27:06 +0100 Subject: [PATCH 0326/1102] Translations update Updated translation source files --- src/translations/bitmessage_ar.qm | Bin 52231 -> 42268 bytes src/translations/bitmessage_ar.ts | 1057 ++++++++++++------ src/translations/bitmessage_cs.pro | 6 + src/translations/bitmessage_cs.qm | Bin 64901 -> 58855 bytes src/translations/bitmessage_cs.ts | 885 +++++++++++----- src/translations/bitmessage_de.ts | 7 +- src/translations/bitmessage_en_pirate.pro | 6 + src/translations/bitmessage_en_pirate.qm | Bin 17397 -> 17029 bytes src/translations/bitmessage_en_pirate.ts | 1019 +++++++++++------- src/translations/bitmessage_eo.pro | 6 + src/translations/bitmessage_eo.qm | Bin 42295 -> 35103 bytes src/translations/bitmessage_eo.ts | 954 ++++++++++++----- src/translations/bitmessage_fr.pro | 6 + src/translations/bitmessage_fr.qm | Bin 49460 -> 42212 bytes src/translations/bitmessage_fr.ts | 953 ++++++++++++----- src/translations/bitmessage_ja.pro | 7 + src/translations/bitmessage_ja.qm | Bin 41367 -> 36035 bytes src/translations/bitmessage_ja.ts | 1122 +++++++++++++++----- src/translations/bitmessage_nl.pro | 6 + src/translations/bitmessage_nl.qm | Bin 7430 -> 9241 bytes src/translations/bitmessage_nl.ts | 986 +++++++++++------ src/translations/bitmessage_no.pro | 6 + src/translations/bitmessage_no.qm | Bin 57925 -> 56716 bytes src/translations/bitmessage_no.ts | 1176 ++++++++++++++------- src/translations/bitmessage_ru.pro | 6 + src/translations/bitmessage_ru.qm | Bin 60311 -> 52407 bytes src/translations/bitmessage_ru.ts | 953 ++++++++++++----- src/translations/bitmessage_zh_cn.pro | 6 + src/translations/bitmessage_zh_cn.qm | Bin 42405 -> 36289 bytes src/translations/bitmessage_zh_cn.ts | 1010 ++++++++++++------ 30 files changed, 7115 insertions(+), 3062 deletions(-) diff --git a/src/translations/bitmessage_ar.qm b/src/translations/bitmessage_ar.qm index 477a758648f4438322b521954e9cb83112704535..d35714c22d74ed8bb7d553b32c2e48987065f1ba 100644 GIT binary patch delta 2297 zcmX9+a6CXI2t&{WM7czW2m*;{Puq_#JPyH?WotnaTf5 z;y*h6wA6J@eD6a1-uAnT0L4oH?m+esz|{Z~lL7u1upj~mnoiF)z=z)fE<{u=)KZP$oS#zI4Y1c1w+>c z0ssFpsy)vDn_|Yno+fwR%(#e?f#?FpBmQ?F<-CdU%%{XvW0<)%l)xj0Ss3k27fp=u zHeDF;B@-Xj41Daur2Eq3v$ruNG1ORi08?XU1?Dy|yN}W&wWpYKErj6g@yzQ!g2VSO z=AA5n9!|^Tb=0uW9NCOMLV9YwENw?RAbQL4{zC(dH8sjAJ{ctZ^s@cYbTF}Bwm+j4 z8091DjHl?%$bQbdLXefqdbMi+&nVd=E)!TgTlPo&7}7@yE0*(wTn($ab%Ng8SY2@! zoj0+1ivd`Cl%3V}H6T1^=Vasqg=%)5Q4iERvJ2yS08_{|wkful#Po`76N$?*Bipf) z-kt8TRz(s)-#;9a@3K9EwSX*^{XLQz^*qZCW>Lc6U)Yyt!hz}Fba6ys$$f70;V58X z3^(s|Ah4sD3osrcp+4b)I*E#j6&oS3CaH4mNx`d#B(mI#R}L8+*ef$ z#hs^ z5Z4!Y-wqPv#?AcPWTM7<1Hb5*5zzj~FYD_jYSZ}G{F5XuPk~R2BuHoZ@EJ`K6?Er| z3TX0*2YiDs6xl<+oB9JT#7kT`~CSXH?eBE0@F8io_bG3=YQ#nR%3H}w>y-42jZ}RlC zF!^EqdHRC0T&f%i#5>7P|4qfZm-6nzwq%4I7TTKH@{ZZk!l%N*(DMEX! z)ZlzYL^bV%HQ|aR_x0qO2Z~$=ExF`^Vq3^q61z!Jc5edk*;z%6sf`Z!PDNvCE8s9) z(VV@N#BxmWRe3*g?K&J2PAV>YQRilF#cxJ}&c;FU!igFTZ&muppAb@ql`9M%QDYC4 zQRi#vUYjyE$w-ULpe+5@Dj+gMS>s9?SiV|$!j|r3+AF^~XP`y2L22qZc$J{Pro3UA z05GhwcNfL+ua!fEp8|2WmH)d-(XL%J>d^{9uv|6nz;i0NOyzuo3On1Xyrb6wj#E^b zM#?j(Ue)-M7jf;Q+T;I@wqmpD-PuZD#tXG`5jCDNS)DWxLdacGCnq-1;=6BBr}WW< zm}A2+-&Xy(4|TTWqPo@ankG`I&kE0o<4*Ni%Tw~PQr*6u&fQYfR|+I5bY1<&&U~QA zNnk<=!MQPlDx0Vp*(0dgTjYwr1m|bx$(EA@m-bi^>kVQ4NTOg-kzfoaw?v!zhad9h z3E}SuqS8cRZSF!+^8ukOr-%wi2-O#QsSqPHb_I|K69kLOlc0MpTrVJQgT4^1KcK>X zBZQxK5#$A(LQnP}O=ctX2Gx-WyM?~Jq@fYN2?MrMfc5u;0X>PeaD_N4f*LY;#fS^0 z69TcZ;`{aKG}(~2GB1^=I4&kWkE7MB7nACn$OYYE>QVY}D*RO}yH-t*r-`-m?P>Ac z6KfNK$=@#GiN7f{Y!J_65GC=g;yEUhHe&B^tc(}iM^S@W{o>6OiitkrE!`mbf2yx| zC%20d8N?SKQX%_9@kJL+@Lq#P`RF8xhSO-5(EC`8X55B{v?r=G&buhFQ;=qc`7n^Q zTN8J17d2L;Ngc`uK5)|H1XK|PWt!U^ZnOahG!Ls12+0b~tK8T_81EZ zxr@Wm6s_$`j0HyL=seOllkFzzysi@>#iMo0PEli1M(V;^3_zHxZq@PgKzf+2b?GE6 z{kT-<&NwuYdb@O&?WnVP|J1#%ARAWJ5y6%rsaZ&nN$+cm<s5dox4=h zH1{K{+2A$P?C8D3e9-%j)ZjaVF_-%Vn>GF`WbiR3_|MV9O-Z{4a{99i&G;-SQNMmu zQd*{dQ-*%i#x=UFZ{ZMMz-0fy0}TmS$7 delta 10191 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 - - + + + AddAddressDialog + + + Add new entry + + + + + Label + + + + + Address + + + + + 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: + + + MainWindow - + Bitmessage Bitmessage - + To إلى - + From من - + Subject الموضوع - + Received تاريخ الإستلام Inbox - البريد الوارد + البريد الوارد Load from Address book - تحميل من دفتر العناوين + تحميل من دفتر العناوين 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 - إرسال لجميع المتابعين + إرسال لجميع المتابعين - + Send إرسال 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 العنوان 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 القائمة السوداء @@ -195,195 +216,195 @@ p, li { white-space: pre-wrap; } Total connections: 0 - إجمالي الروابط + إجمالي الروابط Since startup at asdf: - منذ بداية التشغيل: + منذ بداية التشغيل: Processed 0 person-to-person message. - تم معالجة 0 رسالة -شخص إلى شخص-. + تم معالجة 0 رسالة -شخص إلى شخص-. Processed 0 public key. - تم معالجة 0 مفتاح علني. + تم معالجة 0 مفتاح علني. Processed 0 broadcast. - تم معالجة 0 بث. + تم معالجة 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 + تم إرسال الرسالة، بانتظار إشعار الإستلام، تم الإرسال في %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. @@ -392,12 +413,12 @@ 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. 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.) @@ -406,107 +427,107 @@ It is important that you back up this file. Would you like to open the file now? مهم جداً أن تحتفظ بنسخة إضافية من هذا الملف. هل ترغب بفتح الملف الآن؟ تأكد من إغلاق البرنامج Bitmessage قبل تعديل الملف. - + 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? هل أنت متأكد من رغبتك في حذف كل الرسائل من سلة المهملات؟ - + You must type your passphrase. If you don't have one then this is not the form for you. يجب إدخال عبارة المرور، إن لم تكن لديك عبارة مرور، إذاً هذه ليست الطريقة المناسبة لك - + Delete trash? حذف سلة المهملات؟ - + Open keys.dat? فتح ملف keys.dat؟ - + bad passphrase عبارة المرور غير جيدة - + Restart إعادة تشغيل - + You must restart Bitmessage for the port number change to take effect. لتفعيل تغيير رقم نقطة العبور (port) يجب عليك إعادة تشغيل برنامج Bitmessage. @@ -516,77 +537,77 @@ It is important that you back up this file. Would you like to open the file now? 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. خطأ: لا يمكنك إضافة نفس العنوان مرتين إلى القائمة، يمكنك إعادة تسمية العنوان. - + The address you entered was invalid. Ignoring it. العنوان الذي أدخلته غير صالح، سيتم تجاهله. - + 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. تم إضافة جهة الاتصال لدفتر العناوين، يمكنك تعديل الإسم المستعار إذا أحببت. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. خطأ: لا يمكنك إضافة نفس العنوان إلى دفتر العناوين مرتين، يمكنك إعادة تسمية العنوان. - + Moved items to trash. تم نقل المادة لسلة المهملات. - + No addresses selected. لم يتم اختيار عناوين @@ -596,152 +617,152 @@ It is important that you back up this file. Would you like to open the file now? 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-'' العنوان يجب أن يبدأ ب "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. بعض البيانات المشفرة ضمن العنوان طويلة جداً. - + Address is valid. العنوان صحيح - + You are using TCP port %1. (This can be changed in the settings). أنت تستخدم نقطة عبور TCP %1 - يمكنك تغييره في قائمة الضبط. - + Error: Bitmessage addresses start with BM- Please check %1 خطأ: عناوين ال Bitmessage تبدأ ب BM-، يرجى فحص %1 - + Error: The address %1 contains invalid characters. Please check it. خطأ: العنوان %1 يحتوي على حروف غير صالحة، يرجى فحصه. - + 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 لا يمكنه معالجة رسالئه، يرجى تشغيل عميل ثاني في حاسوب آخر أو ضمن حاسوب إفتراضي. + خطأ: عنوان من العناوين المرسل إليها، %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 تم فقد الاتصال @@ -753,8 +774,7 @@ It is important that you back up this file. Would you like to open the file now? Reply - . - رد + رد @@ -816,12 +836,12 @@ Difficulté requise par le destinataire : %1 et %2 Work is queued. - تم إدراج العمل ضمن قائمة الإنتظار. + تم إدراج العمل ضمن قائمة الإنتظار. Work is queued. %1 - تم إدراج العمل ضمن قائمة الإنتظار. %1 + تم إدراج العمل ضمن قائمة الإنتظار. %1 @@ -831,185 +851,541 @@ There is no required difficulty for version 2 addresses like this. 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 الكل - + Message الرسالة - + Fetch Namecoin ID إحضار هوية namecoin - + Stream # المجرى # - + Connections الروابط - + Ctrl+Q Ctrl+Q - + F1 F1 - + Join / Create chan إنضمام / تكوين زمرة + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Waiting for their encryption key. Will request it again soon. + + + + + Message sent. Waiting for acknowledgement. Sent at %1 + + + + + Channel + + + + + 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. + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + Inventory lookups per second: %1 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + 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 + + + + + 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. + + + + + Undeleted item. + + + + + 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. + + + + + 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. + + + + + Display the %1 recent broadcasts from this address. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + MainWindows @@ -1061,7 +1437,7 @@ The 'Random Number' option is selected by default but deterministic ad Address version number: 3 - رقم إصدار العنوان: 3 + رقم إصدار العنوان: 3 @@ -1118,24 +1494,57 @@ The 'Random Number' option is selected by default but deterministic ad (saves you some bandwidth and processing power) يوفر عليك بعض النطاق و القوة المعالجة + + + Address version number: 4 + رقم إصدار العنوان: 4 + + + + NewGroupDialog + + + Add new entry + إضافة مدخل جديد + + + + Label + الإسم المستعار + + + + Address + العنوان + + + + Group Name + إسم المجموعة + NewSubscriptionDialog - + Add new entry إضافة مدخل جديد - + Label إسم مستعار - + Address عنوان + + + CheckBox + + SpecialAddressBehaviorDialog @@ -1168,35 +1577,40 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog - + PyBitmessage PyBitmessage - + version ? الإصدار ؟ - + About عن البرنامج - + Copyright © 2013 Jonathan Warren - حقوق الحفظ © 2013 Warren Jonathan + حقوق الحفظ © 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. هذه نسخة تجريبة للبرنامج + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + connectDialog @@ -1221,6 +1635,44 @@ The 'Random Number' option is selected by default but deterministic ad أسمح لي بتعديل ضبط الشبكة الخاص أولاً + + hashtagDialog + + + Hashtag + هاشتاق + + + + Trending Hashtags + الهاشتاقات النشطة + + + + Day + يوم + + + + Week + أسبوع + + + + Month + شهر + + + + All Time + كل الأوقات + + + + Popularity + الشعبية + + helpDialog @@ -1228,16 +1680,16 @@ The 'Random Number' option is selected by default but deterministic ad Help مساعدة - - - <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 هو مشروع تعاوني، يمكنك إيجاد المساعدة في Bitmessage Wiki: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1366,315 +1818,322 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings الضبط - + Start Bitmessage on user login إبدأ برنامج Bitmessage عند نقطة ولوج المستخدم - + Start Bitmessage in the tray (don't show main window) تشغيل البرنامج في شريط المهام - + Minimize 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. - + User Interface واجهة المستخدم - + Use Identicons استخدم Identicons - + Interface Language لغة العرض - + Listening port نقطة عبور للإستماع - + Listen for connections on port: استماع للروابط في نقطة عبور: - + Proxy server / 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. - + 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 الصعوبة القصوى المقبولة - + 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'-: + تجاهل تحديد اللغة الآلي - استخدم رمز البلد أو رمز اللغة مثل '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. + يستطيع برنامج Bitmessage استخدام برنامج مختلف يعتمد على Bitcoin و يسمى Namecoin لإنتاج عناوين سهله التداول بين البشر، على سيبل المثال بدلاً من أن تقوم بإخبار صديقك عن عنوانك Bitmessage الطويل، بإمكانك أن تطلب منه إرسال رسالة للإختبار، إدخال عنوانك الخاص إلى Namecoin يبقى صعب بالمقارنة. برنامج Bitmessage إما أن يستخدم namecoind مباشره أو يقوم بتشغيل طلب nmcontrol. - + Host: المضيف: - + Password: كلمة العبور: - + Test اختبار - + Connect to: متصل ب: - + Namecoind Namecoind - + NMControl NMControl - + Namecoin integration دمج Namecoin 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 يوم إلخ حتى يقوم المستلم بإرسال إشعار استلام الرسائل، هنا يمكنك تغيير أسلوب إعادة الإرسال و التوقف بعد عدة أيام أو شهور، أترك هذه الخانات فارغة لتفعيل الأسلوب الإفتراضي. + إفتراضياً إذا أرسلت رسالة لشخص و هو غير متصل لأكثر من يومين سيقوم البرنامج بإرسال الرسالة مرة أخرى بعد يومين إضافيين، ستستمر عملية إعادة الإرسال بصور متباعده زمنياً، و عليه سيتم إعادة إرسال الرسائل بعد 5، 10، 20 يوم إلخ حتى يقوم المستلم بإرسال إشعار استلام الرسائل، هنا يمكنك تغيير أسلوب إعادة الإرسال و التوقف بعد عدة أيام أو شهور، أترك هذه الخانات فارغة لتفعيل الأسلوب الإفتراضي. - + Give up after توقف بعد - + and و - + days أيام - + months. شهور. - + Resends Expire إنتهاء صلاحية إعادة الإرسال - - - hashtagDialog - - Hashtag - هاشتاق + + Tray + - - Trending Hashtags - الهاشتاقات النشطة + + Close to tray + - - Day - يوم + + Reply below Quote + - - Week - أسبوع + + System Settings + system + - - Month - شهر + + Pirate English + en_pirate + - - All Time - كل الأوقات + + Other (set in keys.dat) + other + - - Popularity - الشعبية - - - - NewGroupDialog - - - Add new entry - إضافة مدخل جديد + + UPnP: + - - Label - الإسم المستعار + + Bandwidth limit + - - Address - العنوان + + Maximum download rate (kB/s): [0: unlimited] + - - Group Name - إسم المجموعة + + Maximum upload rate (kB/s): [0: unlimited] + + + + + 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>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> + diff --git a/src/translations/bitmessage_cs.pro b/src/translations/bitmessage_cs.pro index db58da97..8b0094be 100755 --- a/src/translations/bitmessage_cs.pro +++ b/src/translations/bitmessage_cs.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_cs.qm b/src/translations/bitmessage_cs.qm index 6aadf62b4ade329e8df070554028d78acc3f909d..06170de01d5476f3236a4640d2a6441f6ab3a360 100644 GIT binary patch delta 2624 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 W$85FR4EWZF#m82l@yLc=WB(WH`IavL diff --git a/src/translations/bitmessage_cs.ts b/src/translations/bitmessage_cs.ts index 438e5907..a925d7a1 100755 --- a/src/translations/bitmessage_cs.ts +++ b/src/translations/bitmessage_cs.ts @@ -1,6 +1,5 @@ - - + AddAddressDialog @@ -19,210 +18,319 @@ Adresa + + 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 desiged 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 - + 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 + 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 Address Book - Adresář + 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. @@ -231,17 +339,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.) @@ -250,762 +358,762 @@ 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. - + 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 - + 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: 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. - + 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 + Práce je zařazena ve frontě. %1 - + New Message Nová zpráva - + From Od - + 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 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. + 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). - + 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. - + 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í. - + Moved items to trash. Položky byly přesunuty do koše. - + Save As... Uložit jako... - + Write error. Chyba zápisu. - + No addresses selected. Není vybrána žádná adresa. - + 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á. - + 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 - + Search Hledej - + All Vše - + To Komu - + From Od - + Subject Předmět - + Message Zpráva - + Received Doručeno Inbox - Doručené + Doručené Load from Address book - Vybrat z adresáře + Vybrat z adresáře - + Fetch Namecoin ID Načíst Namecoin ID Message: - Zpráva: + Zpráva: - + Subject: Předmět: Send to one or more specific people - Poslat jednomu nebo více konkrétním lidem + Poslat jednomu nebo více konkrétním lidem - + To: Komu: - + From: Od: Broadcast to everyone who is subscribed to your address - Rozeslat všem, kteří odebírají Vaši adresu + Rozeslat všem, kteří odebírají Vaši adresu 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. + 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. Status - Stav + Stav Sent - Odeslané + Odeslané Label (not shown to anyone) - Popiska (nikomu se neukazuje) + Popiska (nikomu se neukazuje) - + Address Adresa Stream - Proud + Proud Your Identities - Vaše identity + 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. + 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 Label - Popiska + Popiska - + 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. + 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 + Celkový počet připojení: 0 Since startup at asdf: - Od spuštění v asdf: + Od spuštění v asdf: Processed 0 person-to-person message. - Zpracováno 0 osobních zpráv. + Zpracováno 0 osobních zpráv. Processed 0 public key. - Zpracováno 0 veřejných klíčů. + Zpracováno 0 veřejných klíčů. Processed 0 broadcast. - Zpracováno 0 hromadných zpráv. + 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 - + 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 - + Set avatar... Nastavit avatar... - + 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. - + Inventory lookups per second: %1 Počet kontrol inventáře za sekundu: %1 - + 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. - + 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. - + 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. - + Display the %1 recent broadcast from this address. Zobrazit %1 zprávu nedávno rozeslanou z této adresy. - + Display the %1 recent broadcasts from this address. Zobrazit %1 zpráv nedávno rozeslaných z této adresy. - + Inventory lookups per second: 0 Počet kontrol inventáře za sekundu: 0 - + Down: %1/s Total: %2 Stahování: %1/s Celkem: %2 - + Up: %1/s Total: %2 Odesílání: %1/s Celkem: %2 - + 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: 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á. - + Number needed Je třeba zadat číslo - + 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. - + Some data encoded in the address is malformed. Některá data zakódovaná v této adrese mají neplatný formát. @@ -1016,22 +1124,248 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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"> + <!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> - + Down: 0 KB/s Stahování: 0 KB/s - + Up: 0 KB/s Odesílání: 0 KB/s + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + 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. + + + + + 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. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% + + NewAddressDialog @@ -1213,12 +1547,12 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - <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 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> - <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 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> @@ -1255,13 +1589,18 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi <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> + <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: Protože Bitmessage je společně tvořený projekt, nápovědu najdete na webu na Bitmessage Wiki: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1390,222 +1729,222 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi settingsDialog - + Settings Nastavení - + Start Bitmessage on user login Spustit Bitmessage po přihlášení uživatele - + 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 - + 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 - + Interface Language Jazyk pro rozhraní - + System Settings system Dle nastavení systému @@ -1624,7 +1963,7 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - Français + Français fr Français @@ -1636,13 +1975,13 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - Españl + Españl es Españl - русский язык + русский язык ru русский язык @@ -1653,66 +1992,86 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Norsk - + Pirate English en_pirate Pirate English - + Other (set in keys.dat) other Jiný (nastavený v keys.dat) - + <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í] + + + Tray + + + + + Close to tray + + + + + UPnP: + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index a091370f..f6065b4e 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -1,6 +1,5 @@ - - + AddAddressDialog @@ -1598,7 +1597,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei version ? Version ? - + Copyright © 2013 Jonathan Warren Copyright © 2013 Jonathan Warren @@ -1615,7 +1614,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei - <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 The Bitmessage Developers</p></body></html> diff --git a/src/translations/bitmessage_en_pirate.pro b/src/translations/bitmessage_en_pirate.pro index acc712ee..618b6695 100644 --- a/src/translations/bitmessage_en_pirate.pro +++ b/src/translations/bitmessage_en_pirate.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_en_pirate.qm b/src/translations/bitmessage_en_pirate.qm index 24feb4b9601e2819fefbd3df187196b492938884..1c33bafd281c3c444bbb0a1c6b60271ff32a87e1 100644 GIT binary patch delta 728 zcmYk4ZAepL7>4h6=WJ*0oHIWuozC1Ozbe1AjS?+2L}a9hQ3S1=l@jV)p+>s!qYtxM zO+_stmQX3tkNq&rpp2kQEYK2v1VK>{VTHLM5PRbEBRHJvyytzN`?;U{oRzbzyPJ6; z+>HP-0CPO}ujv45Ru~(AP*n`%KSOBoG7u4ot#3Pl^)skwnWUOa3ZsHh)l&zgUBI5& zlf*~Zujv6SlQ>mB45Vr?*b)oG?P5t%JP7Uhu)?`36p&nj#!Hq;wV{f_vY;bB$c*sCT zjAmS*gT^w={Ad^%`6g6(+Gz3$;Y?W+kU1%g^?slPDiyL2g^|<3R1WFn`n49#4{CH@ z+jDClAlbE7Qpgxv)CM}7z`BB<=-Vr_UlMe4`fYx7;cpZstxG^wmsGHs>LYrkngP<|8l}E`10}Rg z>N`|Q$%IG`8mh@azx0q%vdl+x(?dps^tz6O49#-%v5yqpd3lR>ls-w3eBjOyuu0J4 zF*Pt(>PrG-C}}}IbKOdbne?-1lnC&TQwk%U`bAp@83`y%^aSTTk0qVz;NKU!sNZNU z{a8OaDl~hK8}h`E9S#RwO*Jl;_lY6x|Mk`AWd85A_n=|7cV6Z5k8nmE%l1ymX1Y6N TgMUq)4fUH$=Xig4!iez?Ua`So delta 1036 zcmb7BYe-XJ7=F&qZo1>~k~M8!=4Q1dJ+?V-O>5OaB2JedMiJ@Mlg`x5&83F6Fs-m6 z<4CAQ*af{fRJh3RN(7ytwx`dU(eG&SBCHc=lJW8us|C{Dpx%Rd7t$C;diRA?Jv z%6DD_lGZS1Z;?>JxMH&X5eW|}J}Lu1!flp2p(5c@Ho9v9NVK!L-h;p@6I&!2>3m9A zG`f)*&M7yD*MQhcW%KV1fX<`5af%_s9jbyS-zadF>hK{6Ay~Jl`U+M8ish<-8ERk& zsLTE50pn_Qu!js-JJq8ai42XYUtN!*WIHsaJ?+4f`v`&5aY&BrJw8Ay@Oz zPW*g>Hedan_TzKH&jVU8161Z$r(P3)=BO~EeRz~M;YoU zS>$X~rhFYR3`Lb)?Wa+Dc|4#7=6ig}4>FXomVb7x07#wU#|4@Q5Jvqw{*BlH#8-sT zG8b)soI?Dk(LYai(o@HIz{0s(-pqcGlh_n_mW>(CRwhR>Hd*9NjBU7){}h`x4hP&Y zq6U6Q*oz{VXx~Ji4}}mQ$Yu7$`Yd?qzMB4<;lVyy0=A-c;m%No5@Oa-y$Qwt#|{1C zI!MutV(mgeHLYrg+gRh5_7<6Hnwortg0SAxR4)Yr?rJH^>#r7?J^MVu*4BTgWhGLb z&s6+B)ecs07t6l1_~D(#W6EeKVEfyjrgXt#X033_FJl(TnS4y9h#=}wL1FzU{9CAZ fR#o}Qm~p@44|u!{Mlo1lA^GJ&i+Ok|{c`djo977H diff --git a/src/translations/bitmessage_en_pirate.ts b/src/translations/bitmessage_en_pirate.ts index 02330897..55e4021f 100644 --- a/src/translations/bitmessage_en_pirate.ts +++ b/src/translations/bitmessage_en_pirate.ts @@ -18,959 +18,1225 @@ 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 desiged 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 - + 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 - - 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. - + 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 - + 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: 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. - + 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 - + 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 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). - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - + 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. - + Moved items to trash. - + 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 - - - - - Label (not shown to anyone) - - - - + Address 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 - Label + 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. - - - - + 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 - - - - - Since startup at asdf: - - - - - Processed 0 person-to-person message. - - - - - Processed 0 public key. - - - - - Processed 0 broadcast. - - - - + Network Status - + File - + Settings Settings - + Help Help - + Import keys - + Manage keys - + Ctrl+Q Ctrrl+Q - + F1 - + About - + Regenerate deterministic addresses - + Delete all trashed messages - + 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. - + + Inventory lookups per second: 0 + + + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + <!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;"> +</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> - - Inventory lookups per second: 0 + + Send ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% @@ -1164,7 +1430,7 @@ T' 'Random Number' option be selected by default but deterministi - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1201,13 +1467,18 @@ T' 'Random Number' option be selected by default but deterministi <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> + <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 be project of many, a pirates help can be found online in the Bitmessage Wiki: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1351,309 +1622,307 @@ T' 'Random Number' option be selected by default but deterministi settingsDialog - + Settings Settings - + Start Bitmessage on user login Start yee Bitmessage on userrr login - + 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 - + 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 - + 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> - + Give up after - + and - + days - + months. - + Resends Expire + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_eo.pro b/src/translations/bitmessage_eo.pro index 1e9492cd..0d103003 100644 --- a/src/translations/bitmessage_eo.pro +++ b/src/translations/bitmessage_eo.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index cfa0a6dcc1aca21de3084ce3cee454e2e3b8a91b..ccca8ff375699286396d18dd74ae80afd437bf00 100644 GIT binary patch delta 2029 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 diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 8fac557f..84a54878 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -18,201 +18,309 @@ Adreso + + 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 desiged 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 - + 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 - Respondi + Respondi - + Add sender to your Address Book Aldoni sendinton al via adresaro - + Move to Trash Movi al rubujo - + View HTML code as formatted text Montri HTML-n kiel aranĝita teksto - + Save message as... Konservi mesaĝon kiel... - + New Nova - + Enable Ŝalti - + Disable Malŝalti - + Copy address to clipboard Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso... - + 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 - + Add new entry Aldoni novan elementon - + 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. - + Encryption key request queued. Peto por ĉifroŝlosilo envicigita. - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Need to do work to send message. Work is queued. Devas labori por sendi mesaĝon. Laboro en atendovico. - + 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 - + 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 + 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. @@ -221,17 +329,17 @@ It is important that you back up this file. 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.) @@ -240,97 +348,97 @@ It is important that you back up this file. Would you like to open the file now? 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". @@ -345,32 +453,32 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. @@ -380,52 +488,52 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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 + 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. 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. + Eraro: Vi ne povas duoble aboni la saman adreson. Provu renomi la jaman 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. @@ -435,164 +543,164 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. Movis elementojn al rubujo. - + 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 + Ricevujo Load from Address book - Ŝarĝi el adresaro + Ŝarĝi el adresaro Message: - Mesaĝo: + Mesaĝo: - + Subject: Temo: Send to one or more specific people - Sendi al unu aŭ pli specifaj personoj + Sendi al unu aŭ pli specifaj personoj @@ -608,277 +716,277 @@ p, li { white-space: pre-wrap; } <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 + 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. + Sciu ke elsendoj estas sole ĉifrita kun via adreso. Iu ajn povas legi ĝin se tiu scias vian adreson. Status - Stato + Stato Sent - Sendita + Sendita Label (not shown to anyone) - Etikdeo (ne montrita al iu ajn) + Etikdeo (ne montrita al iu ajn) - + Address Adreso Stream - Fluo + Fluo Your Identities - Via identigoj + Via identigoj 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". + Ĉi tie vi povas aboni "elsendajn mesaĝojn" elsendita de aliaj uzantoj. Adresoj ĉi tie transpasas tiujn sur la langeto "Nigara listo". - + Add new Subscription Aldoni novan Abonon Label - Etikedo + Etikedo - + Subscriptions Abonoj 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. + 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. - + Name or Label Nomo aŭ Etikedo - + 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 + Totalaj konektoj: 0 Since startup at asdf: - Ekde lanĉo de la programo je asdf: + Ekde lanĉo de la programo je asdf: Processed 0 person-to-person message. - Pritraktis 0 inter-personajn mesaĝojn. + Pritraktis 0 inter-personajn mesaĝojn. Processed 0 public key. - Pritraktis 0 publikajn ŝlosilojn. + Pritraktis 0 publikajn ŝlosilojn. Processed 0 broadcast. - Pritraktis 0 elsendojn. + 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 @@ -908,132 +1016,399 @@ p, li { white-space: pre-wrap; } Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - + Mark Unread Marki nelegita - + Fetched address from namecoin identity. Venigis adreson de Namecoin identigo. - + Testing... Testante... - + Fetch Namecoin ID Venigu Namecoin ID - + Ctrl+Q Stir+Q - + F1 F1 - + 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 + + + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + <!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;"> +</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> - - Inventory lookups per second: 0 + + Send ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% @@ -1221,7 +1596,7 @@ The 'Random Number' option is selected by default but deterministic ad - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1258,13 +1633,18 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1403,207 +1783,207 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings Agordoj - + Start Bitmessage on user login Startigi Bitmesaĝon dum ensaluto de uzanto - + Start Bitmessage in the tray (don't show main window) Startigi Bitmesaĝon en la taskopleto (tray) ne montrante tiun fenestron - + Minimize to tray Plejetigi al taskopleto - + Show notification when message received Montri sciigon kiam mesaĝo alvenas - + Run in Portable Mode 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. - + 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 - + <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 @@ -1613,104 +1993,102 @@ The 'Random Number' option is selected by default but deterministic ad Transpasi la automatan reconon de locala lingvo (uzu landokodon aŭ lingvokodon, ekz. 'en_US' aŭ 'en'): - + 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> - + Give up after - + and - + days - + months. - + Resends Expire + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_fr.pro b/src/translations/bitmessage_fr.pro index 0e56c016..9e004955 100644 --- a/src/translations/bitmessage_fr.pro +++ b/src/translations/bitmessage_fr.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 12247227f582cc62ce8b01975b65d72d3b7705ae..04b2666c2c3e180a22f2e862c5c5884107360c60 100644 GIT binary patch delta 1935 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 EA6)!a3IG5A diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index a5483303..0a525ac1 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -18,57 +18,166 @@ Adresse + + 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 desiged 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 - + Bitmessage Bitmessage - + To Vers - + From De - + Subject Sujet - + Received Reçu Inbox - Boîte de réception + Boîte de réception Load from Address book - Charger depuis carnet d'adresses + Charger depuis carnet d'adresses Message: - Message : + Message : - + Subject: Sujet : Send to one or more specific people - Envoyer à une ou plusieurs personne(s) + Envoyer à une ou plusieurs personne(s) @@ -84,117 +193,117 @@ p, li { white-space: pre-wrap; } <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 : - + From: De : Broadcast to everyone who is subscribed to your address - Diffuser à chaque abonné de cette adresse + Diffuser à chaque abonné de cette adresse - + Send Envoyer 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. + Gardez en tête que les diffusions sont seulement chiffrées avec votre adresse. Quiconque disposant de votre adresse peut les lire. Status - Statut + Statut Sent - Envoyé + Envoyé - + New Nouveau Label (not shown to anyone) - Label (seulement visible par vous) + Label (seulement visible par vous) - + Address Adresse Stream - Flux + Flux Your Identities - Vos identités + Vos identités 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. + 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. - + Add new Subscription Ajouter un nouvel abonnement Label - Label + Label - + Subscriptions Abonnements 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. + 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. - + Add new entry Ajouter une nouvelle entrée - + Name or Label Nom ou Label Address Book - Carnet d'adresses + Carnet d'adresses - + 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) - + 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) - + Blacklist Liste noire @@ -211,180 +320,180 @@ p, li { white-space: pre-wrap; } Total connections: 0 - Nombre de connexions total : 0 + Nombre de connexions total : 0 Since startup at asdf: - Depuis le lancement à asdf : + Depuis le lancement à asdf : Processed 0 person-to-person message. - 0 message de pair à pair traité. + 0 message de pair à pair traité. Processed 0 public key. - 0 clé publique traitée. + 0 clé publique traitée. Processed 0 broadcast. - 0 message de diffusion traité. + 0 message de diffusion traité. - + Network Status État du réseau - + File Fichier - + Settings Paramètres - + Help Aide - + Import keys Importer les clés - + Manage keys Gérer les clés - + Quit Quitter - + About À propos - + Regenerate deterministic addresses Regénérer les clés déterministes - + Delete all trashed messages Supprimer tous les messages dans la corbeille - + Total Connections: %1 Nombre total de connexions : %1 - + Not Connected Déconnecté - + Connected Connecté - + Show Bitmessage Afficher Bitmessage - + Subscribe S'abonner - + Processed %1 person-to-person messages. %1 messages de pair à pair traités. - + Processed %1 broadcast messages. %1 messages de diffusion traités. - + Processed %1 public keys. %1 clés publiques traitées. - + Since startup on %1 Depuis lancement le %1 - + 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. Demande de clé de chiffrement en attente. - + Queued. En attente. - + Need to do work to send message. Work is queued. Travail nécessaire pour envoyer le message. Travail en attente. - + Acknowledgement of the message received %1 Accusé de réception reçu le %1 - + Broadcast queued. Message de diffusion en attente. - + Broadcast on %1 Message de diffusion à %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 - + Forced difficulty override. Send should start soon. Neutralisation forcée de la difficulté. L'envoi devrait bientôt commencer. - + 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. @@ -393,12 +502,12 @@ It is important that you back up this file. 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.) @@ -407,97 +516,97 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -507,77 +616,77 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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. Messages déplacés dans la corbeille. - + No addresses selected. Aucune adresse sélectionnée. @@ -587,82 +696,82 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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: 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'. @@ -677,62 +786,62 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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. - + 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. - + 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. + 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 @@ -744,7 +853,7 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o Reply - Répondre + Répondre @@ -811,7 +920,7 @@ Difficulté requise par le destinataire : %1 et %2 Work is queued. %1 - Travail en attente. %1 + Travail en attente. %1 @@ -821,277 +930,544 @@ There is no required difficulty for version 2 addresses like this. 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. - + + Inventory lookups per second: 0 + + + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + <!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;"> +</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> - - Inventory lookups per second: 0 + + Send ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% @@ -1293,7 +1669,7 @@ L'option 'Nombre Aléatoire' est sélectionnée par défaut mais - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1330,13 +1706,18 @@ L'option 'Nombre Aléatoire' est sélectionnée par défaut mais <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> + <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 : + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1475,309 +1856,307 @@ L'option 'Nombre Aléatoire' est sélectionnée par défaut mais settingsDialog - + Settings Paramètres - + Start Bitmessage on user login Démarrer Bitmessage à la connexion de l'utilisateur - + 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 - + Show notification when message received 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. - + User Interface Interface utilisateur - + Listening port Port d'écoute - + Listen for connections on port: Écouter les connexions sur le port : - + Proxy server / Tor Serveur proxy / Tor - + Type: Type : - + 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 - + 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. - + 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é. - + 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é 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. - + Maximum acceptable total difficulty: Difficulté maximale acceptée : - + Maximum acceptable small message difficulty: Difficulté maximale pour les messages courts acceptée : - + Max acceptable difficulty Difficulté acceptée max - + 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> - + Host: - + Password: - + Test - + Connect to: - + Namecoind - + NMControl - + Namecoin integration - + 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> - + Give up after - + and - + days - + months. - + Resends Expire + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_ja.pro b/src/translations/bitmessage_ja.pro index f6e5ad63..fbf5b646 100644 --- a/src/translations/bitmessage_ja.pro +++ b/src/translations/bitmessage_ja.pro @@ -17,14 +17,21 @@ SOURCES = ../addresses.py\ ../shared.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ + ../bitmessageqt/account.py\ + ../bitmessageqt/addaddressdialog.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 0d78d13d3cfdb36cace31497c506fe601741935e..352b77f25c3d8b7d988b9e11e85953df13df5ca2 100644 GIT binary patch delta 2331 zcmZWqYgAKb7CrZso8;ak0%8#y9x@=HLQn*Jp@zdegcyh=pjL~C-1_-Z0AMBzBm#9KrOC`KR=>nAw&@j@izj9M$IR_`%R+Xg%RIpL~I(0X;Vqq!4m}@B%y9LQSc}djx`c( zjv~=vo9HjV~D*$(RD4H2c z-17?xEuq93En*oZWfv0_Jf)PPFL17KC?@xlxgwjWXc?tu;rpUXwB&RQk-CW-%T*Ob zj`g(R1rk{2ki8+4Xhas39Cm;SD{ao*PqeX%_7!;(EsdhKi|IseIn-g;LFDU2J*`b( zi!8O^~*MEW$w#}gg4IiYG zalUmiL{VRI#?F&Onx|Z3UMW$&z)d^WvD#jfZknl`}Ir@swg@!UBX5^n0@+V*1Y z@V>ycgJu#R3`O%#TzCI&BDRRTp9-WQaa?~95>EY$d(xat-@{XyJ<*+ab+K{%93LWJu+Yjr)ik zWT@bem#4z*46oD;huNm{m->Q{@E(7~9sr8$e3$EG6v`2p??Z{CaYEED`=IS!VR9SH zmp)RMk_k!1Z53ucG7-rM!u;NEA!WXhUV0i*wFs6}Fc~-?(XhQ$*f%*C zCX0O{?0<*@S$)ERcab>gq0qElfOfZpb8As>>`bA(G8-L73O5c$5OIaVKT`2M=PnFz z(Av8~7@X|_GqkHR3hIf{8dYmwg0VFdRd4NrXY5Z@b@Tp>DI-O zkGkT+r9^X8>go_^A3I-t$`$9+cc{N;i2>zn)NP+!fw@VdL+ zG@h$=Jimso5c5mg^I13$P^WF(s-RGt_QBp#jMEv3Nd$$Vk0p&AQVmOz zv|I<#@6A%+qYLoDODX7lIvNqB8E%kZQi)`mhbc)+9EzFEQt~S>v`H(iE{TPigQd#i za@2L~ly+V0L7_3y{?0g<@Xu16CIZxbC0*SLZ6`mLuKtL^VKvgtT2P*2k-F{u(DN`NFLEQ)HtVfI=?GGsl4elSQ6elZ(81dC8U>NbyLv zJYIqMSC5dbHTCd9ro4NGCpPZNyI0L4ntw|^^;)wDF>-SrBv|Mzw=g!0)2^XdJY7CN z9DuA_VZpA0HK)ykjGf+x2t_oD^bX{$s(2R6^#_+lW9$~_zp0yy@wDjM!ypmt zjfnALnuj)$bM@V(GEmht6tk1{y_R$$*TsfOSHXlW*f9SLfcacEBsInm#q=4Lp16QN zrH6(i*Ip8>a~PW9^=PES(CkwWvmP~Eb_c-lj}6b>!`KzCgPz-d;81y(^@K6iID4N^ z==91NEe(scSnw*a+HB6moM4yVtY>GfT$i`j=?L}t|6Sz=?M+5`AQuQueTYuUbZcOh z_eZpdPH(?S$~51nq7o4NN6y(jKH51obgpwz*r2o1IM2B-JTl6|*kEil{>|8HeBbz) z@n0n;jYanVrhI2))vt+B;q9K7S7^2PW^J^txA|_&^W9jm(w6D$Ft{rX6T&&=N~9;} z)J%P@jGq?DIzwmJl>Ql&jM5RS=AB`4J(V-@ExdAKK@_VLB>6K+XmY$pIleSsWFnk? jt48DVPs==&^i_79;;|u!Rd(BA^h!qAB^SkgPnrBbt=pkq delta 6442 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 diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 08061f61..294672d4 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -1,893 +1,1384 @@ - - + + + 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 desiged 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 - + 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のアドレスはサポートが終了しています。すぐに削除しますか? 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 on acknowledgement. Sent at %1 - メッセージは送信されました。確認街です。送信先: %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 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 購読 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. パスフレーズを入力してください。パスフレーズがない場合は入力する必要はありません。 - + 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 メッセージが削除されました - + 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クライアントは自分自身へのメッセージを処理できません。別のPCか仮想マシン上でクライアントを立ち上げてください。 + エラー: 送信先アドレス %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はメッセージの処理を行いますが、ネットワークに接続するまで送信はされません。 - + 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 + 処理がキューに入りました。 %1 - + New Message 新規メッセージ - + From 送信元 - + 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 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を再起動してください。既に接続がある場合は切断されます。 - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. エラー: 同じアドレスを複数リストに追加する事はできません。既存の項目をリネームしてください。 - + 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. アドレス帳に項目が追加されました。ラベルは自由に編集できます。 - + Moved items to trash. アイテムをゴミ箱へ移動。 - + 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上で未実装、または実装できないためオプションは無効化されました。 + 現在の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はあなたのアドレスのみで暗号化されます。あなたのアドレスを知っている人は全て読むことができます。 + broadcastはあなたのアドレスのみで暗号化されます。あなたのアドレスを知っている人は全て読むことができます。 Status - 状態 + 状態 Sent - 送信済み + 送信済み 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. - 他のユーザが送信した「broadcastメッセージ」を購読できます。メッセージは受信箱に表示されます。このリストのアドレスはブラックリストより優先されます。 + 他のユーザが送信した「broadcastメッセージ」を購読できます。メッセージは受信箱に表示されます。このリストのアドレスはブラックリストより優先されます。 - + 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アドレスにラベルや名前をつけることで受信箱を見やすくします。「追加」ボタンを押すか受信箱でメッセージを右クリックしてください。 + アドレス帳は他のユーザの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 + 接続数: 0 Since startup at asdf: - 起動してから asdf: + 起動してから asdf: Processed 0 person-to-person message. - 0 通の1対1のメッセージを処理しました。 + 0 通の1対1のメッセージを処理しました。 Processed 0 public key. - 0 件の公開鍵を処理しました。 + 0 件の公開鍵を処理しました。 Processed 0 broadcast. - 0 件のBroadcastメッセージを処理しました。 + 0 件のBroadcastメッセージを処理しました。 - + Network Status ネットワークの状態 - + File ファイル - + Settings 設定 - + Help ヘルプ - + Import keys 鍵をインポート - + Manage keys 鍵を管理 - + Ctrl+Q Ctrrl+Q - + F1 - + About 概要 - + Regenerate deterministic addresses - 「決定論的アドレス」ともヤクセルが deterministicアドレスを再生成 - + Delete all trashed messages ゴミ箱のメッセージを全て削除する - + Join / Create chan chanに参加 / 作成 + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Set avatar... + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Waiting for their encryption key. Will request it again soon. + + + + + Message sent. Waiting for acknowledgement. Sent at %1 + + + + + Channel + + + + + 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. + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + Inventory lookups per second: %1 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + 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 + + + + + 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. + + + + + Undeleted item. + + + + + 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. + + + + + 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. + + + + + Display the %1 recent broadcasts from this address. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + 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 + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% + + NewAddressDialog @@ -930,7 +1421,7 @@ The 'Random Number' option is selected by default but deterministic ad Address version number: 3 - アドレスのバージョン番号: 3 + アドレスのバージョン番号: 3 @@ -992,24 +1483,34 @@ The 'Random Number' option is selected by default but deterministic ad Use a passphrase to make addresses アドレスの作成にパスフレーズを使う + + + Address version number: 4 + アドレスのバージョン番号: 4 + NewSubscriptionDialog - + Add new entry 新しい項目を追加 - + Label ラベル - + Address アドレス + + + CheckBox + + SpecialAddressBehaviorDialog @@ -1042,35 +1543,35 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog - + PyBitmessage - + version ? Version ? - + About 概要 - - 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> - + This is Beta software. このソフトウェアはベータ版です。 + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + connectDialog @@ -1105,13 +1606,18 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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は協働プロジェクトです。ヘルプはBitmessage Wikiを参照してください: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1192,272 +1698,370 @@ The 'Random Number' option is selected by default but deterministic ad regenerateAddressesDialog - + Regenerate Existing Addresses 既存のアドレスを再生成する - + Regenerate existing addresses 既存のアドレスを再生成する - + Passphrase パスフレーズ - + Number of addresses to make based on your passphrase: パスフレーズから生成されたアドレスの数: Address version Number: - アドレスのバージョン番号: + アドレスのバージョン番号: - - 3 - - - - + Stream number: ストリーム数: - + 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アドレスを作ったことがあり、何かしらのトラブル(ハードディスクの故障のような)でそれを紛失していた場合、ここで再生成することができます。もし乱数でアドレスを作っていたのであればこのフォームは再生成には使えません。 + + + Address version number: + + settingsDialog - + Settings 設定 - + Start Bitmessage on user login ユーザのログイン時にBitmessageを起動 - + Start Bitmessage in the tray (don't show main window) Bitmessageをトレイ内で起動する(メインウィンドウを表示しない) - + Minimize 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です。この値を変更すると新しいアドレスではこのデフォルト値を引き上げることができます。その場合、新しいアドレスはメッセージの送信者により高い難易度を要求します。例外もあります: 友人や知り合いをアドレス帳に登録すると、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」): + 自動的に設定された言語・地域を上書きする(国コード、または言語コードを入力。例:「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 許可する最大の難易度 - + <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連携 + + + Tray + + + + + Close to tray + + + + + Use Identicons + + + + + Reply below Quote + + + + + Interface Language + + + + + System Settings + system + + + + + Pirate English + en_pirate + + + + + Other (set in keys.dat) + other + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + + + + <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_nl.pro b/src/translations/bitmessage_nl.pro index 950eefba..ad292f0e 100644 --- a/src/translations/bitmessage_nl.pro +++ b/src/translations/bitmessage_nl.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_nl.qm b/src/translations/bitmessage_nl.qm index aefebc30905f61282e9e23c351a86dcf87904163..fa7b228075d3c7a64c51a8ea62564f2d0d8ac7c3 100644 GIT binary patch delta 2927 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 diff --git a/src/translations/bitmessage_nl.ts b/src/translations/bitmessage_nl.ts index 46969c0d..3112b9c4 100644 --- a/src/translations/bitmessage_nl.ts +++ b/src/translations/bitmessage_nl.ts @@ -1,6 +1,5 @@ - - + AddAddressDialog @@ -19,959 +18,1285 @@ Adres + + 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 desiged 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 - + 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 + 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. - + Encryption key request queued. - + 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 Address Book - Adresboek + 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. - + 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 - + 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: 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. - + 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 - + 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 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). - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - + 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. - + Moved items to trash. - + 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 + Postvak IN Load from Address book - Laden uit adresboek + Laden uit adresboek - + Fetch Namecoin ID Ophalen Namecoin ID Message: - Bericht: + 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 + Status Sent - Verzonden + Verzonden - - Label (not shown to anyone) - - - - + Address Adres - - - Stream - - Your Identities - Uw identiteiten + 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. - - - - + Add new Subscription Label - Label + 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. - - - - + 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 Zwarte lijst - + Stream # - + Connections Verbindingen Total connections: 0 - Aantal Connecties: 0 - - - - Since startup at asdf: - + Aantal Connecties: 0 Processed 0 person-to-person message. - Verwerkt 0 peer-to-peer-bericht. + Verwerkt 0 peer-to-peer-bericht. Processed 0 public key. - Verwerkt 0 broadcast-bericht. + Verwerkt 0 broadcast-bericht. Processed 0 broadcast. - Verwerkt 0 publieke sleutel. + Verwerkt 0 publieke sleutel. - + Network Status netwerkstatus - + File Bestand - + Settings Instellingen - + Help Help - + Import keys Importeer sleutels - + Manage keys - + Ctrl+Q Ctrl+Q - + F1 F1 - + About Over - + Regenerate deterministic addresses - + Delete all trashed messages - + Join / Create chan - + Set avatar... - + 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. - + 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 + + + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + <!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;"> +</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> - - Inventory lookups per second: 0 + + Send ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% @@ -1164,7 +1489,7 @@ The 'Random Number' option is selected by default but deterministic ad - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1201,13 +1526,18 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1351,309 +1681,307 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings Instellingen - + Start Bitmessage on user login Start Bitmessage bij user login - + Start Bitmessage in the tray (don't show main window) - + Minimize 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 - + Interface Language Interface Taal - + 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> - + Give up after Opgeven na - + and en - + days dagen - + months. maanden. - + Resends Expire + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_no.pro b/src/translations/bitmessage_no.pro index d34ad2f9..6edd63b5 100644 --- a/src/translations/bitmessage_no.pro +++ b/src/translations/bitmessage_no.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_no.qm b/src/translations/bitmessage_no.qm index e0b248c617c665bd8db84706ba481c3c4eed76e8..d390813fe33e9b4ae8a736675d304b18da7f70f7 100644 GIT binary patch delta 7919 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 F{|6hemp=di delta 8811 zcmaJ`34B!5)jw~RB(o$TkPt$IJcA*kStcw3Aw(cyH3?x6L?L04c}a#@-Z1k*7*IyU z1zBXd>>^c5MZi*Jw6&t32vxBn{9K{6Mg3fAl`bN-_A7q>^Ij$a_4obwW!`)Do_o%@ z=lsudFKZ5&j~_Fy&y2lFL}f%z2t0@2d5p-ifyng&k@Z(Z4Va%)MC6!DH1idr(RUNw zb{)q5MwU|rSbB^sXXX(N{v%nwbb-Y@%)*dJ*6;^&EO@EgxHB{XZ*0-{%bN3*@4 zd$pWyd8U$L)YDD3yfTt#atX~%T19l~0?qrjnW*M8`OYmPQUrzm3jzBFQ}odiqCs|A z`dEx8?L6Hc+(GoxcG|YMKhcg)>BNx+q5=z@PG3V*kw#}n&%q~^<4u8;L88njOm}>aofH|8iJ#S(Dyjk7}#ai0TuGm{oLEx?CA@@U|yvKZlx{T=1ljhNN zG8P^(k8M0d6f~JPe3V1v-DKX?a1TJZ&-|PdSUCQf`NURykC4nKlNF+jDaLd2O!JxZ zn}|{tn!lJ0#p@n5pI;2V{{H5FJv)tPoX3*h2v;AQVu|(MH-~8cbj#@9R1+ONYpJT+ zOLX^rmPv2GN3M@7J_mNXDQ@ZbFHE-VjAilelSH{wEO%u9GdJwA>|ZAlUA5TqMA0ws z+-v#OirMgWA4_~^CQ*~e^3s=sh+ZzR9E%nZ_50lNZqK7cjTf!bA4-UN2V&N=!eId0 zDC_XQZvz%iSVx`!svo{+EpLMlr+sK0ccG3b`(x`(=iY|zJ=TV0&mfE*v3h31)RXpF z)m?E2e&4Dsy$-Ip+q&XTSmL$0)@>spxP6Uv$Jd}cINbW+O7OqQZ{4>VE~{_1?q7We zp0UTQ2ky5*lU~;6TA@+B*?MyI0%*M5dg|e!M7Ec#@6X1(t=xLi42%pvWc{`}17Y}u z_4}&xL?x?}%wGqADoUCk-i0VgO=`UaQ$JCY)V>~Id~HM0&MBV|z27fs_aEOR8e>U% z?AK?pfxjm0lMf^Q_a8}$KhTS4<(Z`4un#w>NpJ7#iTLy7j7a(ic63e3__SPDqDRV{!WEU`OS!l95`6wy%Br8=ik%Hj z*>D}Oq-{<)*c0m?c_`)iLzQruE#<`H0Po~mQ(lkt$Ig=8NIAQ`KT*;0l#6#Qge6v{ zd^-dS(hsKm?+5tKJ7vrKbOumA(w4jD8(8LL+rZbM$cSOK;d7gj=~mk!bzoTbl`Rqi zp9z1l?RW>6nzrAz^Qs1-ty66eSA0*jImhYyft4!S?-c zA0VoJ(>`zocD!YcUHP&Grk`SO^Xx*d{)K(PIWW98YCNB6u-`tS5_#c1`+>^ukWw$% zf9tpafi?Eu?))10WVQVTFXqSJVt@J0IKFSPf3{ zG*MNXW8j6uNEq`R*S^qz1oJz`jlJMI_gqKa6vXL0KR2FF#vIeWhe?mU=V)F!7Gad* zSiNKgK>Lnk{Skm_+7ic(x2lMqI^fu88wyivj#oc|z&S~d_qNv&J)Pq?6Fm=1eC0Sh zX*1-dI%4M@0r+yxJHG5$h@DS#d?^F{hyLSq&4MCRr#r_KVdwX`oRhZ%v7_&tx7^_a zR_=9rzG+0lxzDL=*+sOd#<}UnzDQV6=ccA9L@R#n+`ITWfKxaRa)zCIm-E-d9)`mA zJD*kIvilc14@nV3!Tgx<^4eMF3z^Vxf5>@i0iJ7jI8UcT)6t(h-?|D2H+Z(nl=I719zt8`aed3ilh$Q4#vX+sl{R+YQ)0SG5<&dCc>$W zk8g(yMyGmeUjlY^r1~x{BU%{yB(?n{UWTknT~f6UKADpG?uioQ<~^zZv#tpywWt2O zZ4AJ(DUDu)pkFqmrC7>P75|-f9T%M&QqxN69z+xjPMdUb6;b?nT0OxP`%a{-`y1xx zy_@#%Z6lC!Ded<=kukTwly4x}HLm`1d|J^k6dU1&gD=|{7m;BCj#zgv4Z zs%IXO!I`;cBJ)wIpsT5xrcxEnq&ZYi<4LATc(0|2HF&M3o1tJ0O$LEX`BY4$_%|E< zP?i2x4btkaCA?xNm5@uH8&7puA&aziIaM84Q9>$(sTFfGX*zzVLs%6!wvk2w@?#~h zi{L9vUTVg(ggp55fJ-IW#fJ}N$10(4fE0|nAuEVq{u&L6g`KOIn?j563)$eJf{I7@ zm+8v%@ltTC&}Bs-SplU+Q3`ePN^mH}`Uw8%@-bV~0zyBOlW8gbI-t5&XI>1V5R_>K zgL2G-pp1g8b>Qj7*C>qLL3W5VHfRWC6-vQF0gXpjs0r$NC@RvQ?pNEQZ_W#OQSdB; zM`nP_44vMOQ5lB!!<;e=#w<%{>D(-9bxA?u-Cr z__5a5U+pLv%G*5n|y@CfTE7}ydr?MiTXl^;^4k)AZ7lNiuiz$n>e7RW-YD!QWonMwO zmsVCpw5VT^wP*-r8VE|8BN1>470G_Dyj1RJ^J+?QB;;;Z%H>d4DeefnL!;z7>=lrV zm6a8xhO{Qt6P5L$(fM)ToP~d)*d?|WUhaaan=aAz=ojWD*LV6EzF4Z3Y zb6TS$)rcE=jF)7wqQ^w(DzU!jNMXtNSo~?DE&k7p4wFktqgnK+4kRB?$-yFn?;`N$ zH#eZjx$P7E%R}vAepPll&v4Lkt^%EqGJE9&@$RE`jPo*n|Inv$~ zX%2gvur18;ri4^?ReXD&>rys4E#hqc*?9kJ&Pjcw6Epz=SP?D><8|A*X^}{aif_7KO5dw^N&rZuWbT6ac!mU{KYN71d^Nk-Y%3+7V2!1ebch;*J3E;iw#L4+ag15d|68lVG9- zp@hfV(xQZQo@yY}t|?(z4eL?h<>^_qVtL{6xNqP=JKS)ct03!#u+%{*=DWs9s(8G# z)Tx8c8`8XLFcN>qHNj$%D#atuW#|0lLYTQwJiIDPypxw5LvvunEf+P;EWn`t%ijjJ zxTv+mV@60Y0&8`@7}#vpea7HnuW?xMlQTgC@9a~9j^7y}dXB^#^BGG+E>E8Z2D#&5 zh$Pr0QlHUzKqc|!tpzdee+;;FgJSn2Se0F>Cy1^{WIPmhWuPv96&k6D^AYfY92J#S zcs?w*M-;|HtpSw?9D`!!4uuqVScZf2L^X19ut{BvJY^&-fDS7GMP!4p*TY#)1rp$G z9ZP<9v(N91XtL&R;&dgh8dl#w4Q=yf2I+#fRc9@pO3M_DH#CY3EAzSFNF&4}cMf+9 z>LSY(-{09+8l=;m@8h(#z-Vq!drcp?i==lAvaZ|`Rs#t=?E7t@E0QqcrK z%(fe9%WL6k4|0GK(DRKJc1PMuib1%@t8^If(aDSCrgjZ1 zI1fcM1{v_;@kV^Iw?&TT0mh6?j}i$fVI(Hz(5mPQnt&(0?2Rj5W{N*k`Jxn)oSnwv zZSu*7HBa;miF(dmE+0vF!(7LCSKV|xYM7QI)}SyP#|ASpG^z{U6UJ=Sk>Llg7!xo{ zp6X8XKW5jBj-OJ>i;@w-dOk5QN5fOyiW$ko*Z`j!c(eLeW7um19S$c6Ufk`el~awp zD7U#6DRPsd=r(pY`Qg4MrP+;W=O9Htf-VHn51R)IHI8?`x0%T}H(x=>jF=<}XXyOA zfl$6*2_T7pCklz-V^wz>$5SL40Zw#>EgBQHIL6@&ZM1bw;&fG(1^ zZq0gRGbgq3YE1OFr z+Fd^q9#wZRcleOE?joJeQzz4+zNvPIEpd+a+T z@hj>j=VxSzmUh1$+&H5!#Q3C*1~4r9-A#&LF9JsUpaWJZj9lJAcAjgnAfg&=N1{s! zqdja5;%v-GC;;ro0DiQQI7)Xl8(yQ=nA6$VfEf-?xCcmd9qkbv^H94G{YW8~6-^Bm zv2uFx*E<%S2{$?V!M7MqZL^P;=^ZJy!fkO$GHy&~1vBDDrk%1#>&3#^>*MBI@}=Bz zT*@(s_{5ZelJVsi4G-lG;3JHy3*ebERn6_^n}?v%tT(0QvP*~icXQg!j*9L+BffNA zKa+U`Q2v|pej;g9zLYMej2d9B>>A0*18baox|sKzt%gw{Bl5y_rCsrqh*QI|voaB8 ze8e?MUJE>qRy2Oq{5z!h!KNLOv_sT-28j=v>cyz$6{6>YrQ)K}Gne}c1fTfL-VqWrNxgze{J?^%EoL0i#EJg>bGmd+ zhwH-fWWHNKhowY>l-@f&HI!nK{J6I)7Wah5B-cZIl_K%C!yih?Rd@|jM7$loI{vYC z+A0kZ&n(Hu?~%Lu#{aqGXLdMe<2{YGMDraM=kDqkPruh?5^HSv;*Hn5wc!Xp+Z{%+6d4<{#77&dQN|YH$XLFypO~}pNog)0#zmf(7;h5|?14)U zTrKWeo0;8x(c1xK_;6T?i{vPiXEdTfaeRmLJ4a(QJJ#0OW`y(`Q8!g~Y1dlemfONg z%jm?tS@*F`zdP&j`n;v}(eBa4Ns2#|U)g!f);<3JP*?ORbyp%V$c|gBP_@_XS6d}q zkK@1od52?Owup0^R@!9Td+XZ~?VI=5`k=Y@u@l9hEmb(h1-48RyXRjm{<@__+9alL zy|EW}V%$p^hi^X0c*M4?hpaU?-?xkXd-FucwsAR}^o;iRN?I*`blVDxG)qi)X!K99 zim!TTg$;#m`PytzuqRvGzT74z?s4_%2^4T0;6UczMbL1~p0`q+km}V(Rovj*`S{P$ zOf;m+%mAMJp@d_L#-Q!=J?$9Wh(uCy)Krl5rUS zVPJHgT=0=@#ht5iVtfT2MiS=4i(4{XmT^u@T+qmLEwE{vHI1m^dR2`5U!L;2`LKPt z<>aE!g78(q)i_rc;yp->_}_^c`uP^?V-Rb!4aQ_44Z_7scf`A=CXR0Ic3d91HMAan zcd)e`X;H@Apxf_Vf|;Pvf=F zG^kv-kM$ArPV^Nwp14(fbmIQ_)33+P@gr|OX%R2Jy;&-c&w3|nmWtvh-~YxeZuwy7 F{{axjXT<;j diff --git a/src/translations/bitmessage_no.ts b/src/translations/bitmessage_no.ts index 0b12acfb..7b1899a9 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,57 +18,166 @@ Adresse + + 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 desiged 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 - + Bitmessage Bitmessage - + To Til - + From Fra - + Subject Emne - + Received Mottatt Inbox - Innboks + Innboks Load from Address book - Velg fra adresseboka + Velg fra adresseboka Message: - Beskjed: + Beskjed: - + Subject: Emne: Send to one or more specific people - Send til en eller flere bestemte kontakter + Send til en eller flere bestemte kontakter @@ -84,124 +193,124 @@ p, li { white-space: pre-wrap; } <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: - + From: Fra: Broadcast to everyone who is subscribed to your address - Kringkast til alle som abonnerer på din adresse + Kringkast til alle som abonnerer på din adresse - + Send Send 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. + 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. Status - Status + Status Sent - Sendt + Sendt - + New Ny Label (not shown to anyone) - Etikett (ikke vist til noen) + Etikett (ikke vist til noen) - + Address Adresse Stream - Strøm + Strøm Your Identities - Dine identiteter + 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. + 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 + 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. + 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 + Legg til ny oppføring - + Name or Label Navn eller etikett Address Book - Adressebok + Adressebok - + Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Bruk svarteliste (tillat beskjeder fra alle adresser unntatt de på svartelisten) + 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) + Bruk hviteliste (blokker beskjeder fra alle adresser unntatt de på hvitelisten) - + Blacklist Svarteliste Stream Number - Strømnummer + Strømnummer @@ -211,373 +320,373 @@ p, li { white-space: pre-wrap; } Total connections: 0 - Totalt antall tilkoblinger: 0 + Totalt antall tilkoblinger: 0 Since startup at asdf: - Siden oppstart på asdf: + Siden oppstart på asdf: Processed 0 person-to-person message. - Har bearbeidet 0 beskjeder for person-til-person. + Har bearbeidet 0 beskjeder for person-til-person. Processed 0 public key. - Har bearbeidet 0 offentlige nøkler. + Har bearbeidet 0 offentlige nøkler. Processed 0 broadcast. - Har bearbeidet 0 kringkastninger. + Har bearbeidet 0 kringkastninger. - + Network Status Nettverksstatus - + File Fil - + Settings Innstillinger - + Help Hjelp - + Import keys - Importer inn nøkler + Importer inn nøkler - + Manage keys - Administrer nøkler + 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. + 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. + Venter på krypteringsnøkkel. Sender straks en ny forespørsel. - + Encryption key request queued. - Forespørsel for å finne krypteringsnøkkel er satt i kø. + Forespørsel for å finne krypteringsnøkkel er satt i kø. - + Queued. - Satt i kø. + 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ø. + Trenger å utføre arbeidsoppgave for sende beskjed. Denne er satt i kø. - + Acknowledgement of the message received %1 - Bekreftelse på beskjeden mottatt %1 + Bekreftelse på beskjeden mottatt %1 - + Broadcast queued. - Kringkasting satt i kø. + Kringkasting satt i kø. - + Broadcast on %1 - Kringkasting på %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: 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 + 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. + 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 + 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.) + 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 + 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.) +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? + 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. + 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? + Åpne keys.dat? - + bad passphrase - Dårlig passordfrase + 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. + 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. + 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. + 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. + 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. + 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. + 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. Kastet innholdet. - + No addresses selected. Ingen adresse valgt. @@ -587,84 +696,84 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne 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-'' + 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. + 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). + 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. + 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. + Feil: Du må oppgi en avsenderadresse. Hvis du ikke har en gå til 'Dine identiteter'-fanen. @@ -674,65 +783,65 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne 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. + 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. + Angående adressen %1, Bitmessage forstår ikke adressetypenumre for %2. Oppdater Bitmessage til siste versjon. - + Stream number - Strømnummer + 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. + 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. + 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'. + 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. + 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? + 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 @@ -744,7 +853,7 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne Reply - Svar + Svar @@ -754,189 +863,189 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne Done generating address. Doing work necessary to broadcast it... - Ferdig med å generere adresse. Utfører nødvendig arbeidsoppgave for å kringkaste den ... + Ferdig med å generere adresse. Utfører nødvendig arbeidsoppgave for å kringkaste den ... Done generating address - Ferdig med å generere adresse + Ferdig med å generere adresse Message sent. Waiting on acknowledgement. Sent on %1 - Beskjed sendt, venter på bekreftelse. Sendt %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. + 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 ... + Utfører nødvendig arbeidsoppgave for å kringkaste ... Broadcast sent on %1 - Kringkastet på %1 + Kringkastet på %1 Looking up the receiver's public key - Gjør oppslag for å finne mottakers offentlige nøkkel + Gjør oppslag for å finne mottakers offentlige nøkkel 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.) + 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. Receiver's required difficulty: %1 and %2 - Utfører nødvendig arbeidsoppgave for å sende beskjeden. + 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. - Problem: Arbeidsoppgaven som kreves utført av mottaker (%1 og %2) er mer krevende enn det du har satt som akseptabelt. + Problem: Arbeidsoppgaven som kreves utført av mottaker (%1 og %2) er mer krevende enn det du har satt som akseptabelt. Work is queued. - Arbeidsoppgave er satt i kø. + Arbeidsoppgave er satt i kø. Work is queued. %1 - Arbeidsoppgave er satt i kø. %1 + Arbeidsoppgave er satt i kø. %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. + Utfører nødvendig arbeidsoppgave for å sende beskjeden. Det er ingen krevd vanskelighet for adresser av type to som benyttet her. - + 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 + Problem: Mottakerens nøkkel kunne ikke brukes til å kryptere beskjeden. %1 - + Save message as... Lagre beskjed som ... - + Mark Unread Merk som ulest - + Subscribe to this address - Abonner på denne adressen + Abonner på denne adressen - + Message sent. Sent at %1 Beskjed sendt. Sendt %1 - + Chan name needed - Kanalnavn nødvendig + 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. + 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'. + 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. + 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. + 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). + 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. @@ -946,151 +1055,151 @@ Det er ingen krevd vanskelighet for adresser av type to som benyttet her.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 + Søk - + All Alle - + Message Beskjed - + Fetch Namecoin ID Hent Namecoin-id - + Stream # - Strøm # + 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 + 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.) +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. + 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. + 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. + 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. + 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. + 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. + 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. + 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. @@ -1101,17 +1210,293 @@ Det er viktig at du tar sikkerhetskopi av denne filen. Vil du åpne denne fi 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"> + <!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 + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% + + MainWindows @@ -1132,28 +1517,28 @@ p, li { white-space: pre-wrap; } 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 @@ -1168,7 +1553,7 @@ The 'Random Number' option is selected by default but deterministic ad 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: @@ -1178,12 +1563,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 @@ -1203,22 +1588,22 @@ 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) @@ -1231,7 +1616,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 @@ -1254,27 +1639,27 @@ 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: + Navnet på pseudo-epostlista: @@ -1312,7 +1697,7 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <html><head/><body><p>Kopirett © 2012-2014 Jonathan Warren<br/>Kopirett © 2013-2014 Bitmessage-utviklerne</p></body></html> @@ -1325,17 +1710,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 @@ -1348,12 +1733,17 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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: + + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + @@ -1371,12 +1761,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). @@ -1409,7 +1799,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> @@ -1419,7 +1809,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> @@ -1447,7 +1837,7 @@ 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: @@ -1462,7 +1852,7 @@ The 'Random Number' option is selected by default but deterministic ad Stream number: - Strømnummer: + Strømnummer: @@ -1472,17 +1862,17 @@ 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. @@ -1493,227 +1883,227 @@ The 'Random Number' option is selected by default but deterministic ad 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 + Vis varsel når beskjed mottas - + Run in Portable Mode - Kjør i flyttbar modus + 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. + 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: + 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 - + 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. + 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. + '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. + '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. + 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 + 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'):) + 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 + 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> + <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 - + Use Identicons Bruk identikoner - + Interface Language - Grensesnittspråk + Grensesnittspråk - + System Settings system Systeminnstillinger @@ -1722,85 +2112,125 @@ The 'Random Number' option is selected by default but deterministic ad English en - Engelsk + Engelsk Esperanto eo - Esperanto + Esperanto Français fr - Fransk + Fransk Deutsch de - Tysk + Tysk Españl es - Spansk + Spansk русский язык ru - Russisk + Russisk Norwegian no - Norsk + Norsk - + Pirate English en_pirate Piratengelsk - + Other (set in keys.dat) other Annet (sett inn keys.dat) - + <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 + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_ru.pro b/src/translations/bitmessage_ru.pro index 5d74581c..2215cfbf 100644 --- a/src/translations/bitmessage_ru.pro +++ b/src/translations/bitmessage_ru.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index f0bd634285c369e6704195da736297715118a88a..ed40e6ae0e320841907572095db65a92a28bbe1c 100644 GIT binary patch delta 2792 zcmZ`)X;@X|7Jm11rhNuM1|`K)A}TVepbUBhaZ2Gh25QIC$VLsrye90c^wRxih) zgx%zaz>4h{-1Z!BtHTJFR$$^}j4G-G!na`T)jVM3kCRn>h=S1<63&yNF7n{lh+(-(Uj7w_%M|6abB%Vfi2Aptu3q zRo;MWAy)6P0_wfUNwER@o$+CoE3jb)&Yg|{ToQ1}unF+|3^$r<0Yxx+KJNy?4m0YV zkAS}8nL#d;@rW;(VcNk!>UCyR+&y4j5960h{^aXSkR5#&5N%~bqsP*RK8*P)ePBPD ziCa(wtonxeU=aaX)R!r8Yz0DJW6BQ_^2TLMV>Jf^4rQKoQi36g%nLRQU@}=n2>~?4 zv0j}-txrETxN{xg@hiJ*V+x>aXV?6jfDb5UH!tr7X7ywDMAN#vHG$oeS_?QWXD`H& z9dm`fwx$_4bdbHFj|YNAvK{C96Lll`;8%)jOU0L`#|;O6AV& zpaqX`u2pFPG&6dwwViA4E(W-9+`TA598}14XOY7;`lK0UZOsfpLT&HaToceA|+@Y!)N|Mj4k<|&#G>P6@AdIS2W!q^8NQY|(#fZeY`Ol|{7*C8ZE5tCz_gw#rzip()s$XiPp z*IR@S11V5!wP1Tl2g;p<@{Qy;pjoK>K%hX|g-;e!z~FmAYhf~FJXpB6(~ny8ZQ*(p z?Q=f}JsfF2yjyrO$&QNScZFRt`DyrE5tmj8w}dM?X3jVP8qpv4Yg^k(lRoMx~5#YdXS!&d8m9ZoNDOEd}ZNxuE5sA%A!wbUGZ3H zvo5U#22W8|WpAKjiBRs}bc>Kj_gYTdYcm~{XZ$IH6Yk1?nTbmK&y`Px5YR<+ssP2$ zl!=#W!Kq?mz@}PlF$1ats)Ah$fh3cv$b)JiCSO%=Pv;8EcP=W1F=f)bVW zyw#Q3=Yr}+8QE8xR6XlgQ06w(?;T{FZ>b&b%muujs$co|F)`4jc0W%6J+`UGMkmm~ zxus4wlcS-1)V3@Bq`9AZ=Qx^<)}87XC$<27uWH=$2=KbO8cSC=P9{eRswMa+TsZ=G&m+|i{F|Kq(o}# zUrIK4y7qV~Nsv*hZDi7^t*U!%{ax)z2Le?5Q2WL98e;OM_F^)?vqxQ)> z@;h*&_DNee^}o?gr@GTXMPk(Hr_g}`jP8|pZqtCs)47+CnQ*#Zt7=&m@S^E-}+N4wb7LA`kikEQ2Qn7zp4nNK7C8y>O)#lWBqAa?_T@v5q-OP zJ&=~xYs(MoI}>AoerFA%QdR={S`7YYiJ6*I!;GT@&@;&}v)TkK{LZkj?i7&UXxMk* zIZ%1YP&-u*tbW~ae9&u^RK4+r#tcF_Bgb&Yk?f>phG(0p9c6bCxHJ+w(JEZG8{F(UO{OQJC;!?G;hn2~DCNQ+NjA{7mEl$)mP;^mv+ z4!j&VXCNchIq=e!x#O5q()qcg>*tlT(zB?|^7Hw_S^51p7YR~Pf)_JeKAkW{A;lzb zpp0)N=hOY~6P)F>OMhauE0%#~+lMhN7o zGRMp^Ur6_JQ&@hqyuf;$kyfs=Fiq08>wIMG`ffGjC;e9V8r{EN?;;0mvU8HpRt;sC z_oTy)&XTg)EJP4%CV5VE8YB1nI7gKF)bmoxJcYFP3sKrz@4*@!}wSX&NXUX?BqPo3xA^c5=7CJd^I8NmG$HV@M)TIkq`m#WET4#jipb*`f8O z;GD(}Ad!OjQ2wQCzI-qrPW54uirPG+Pj8FT!5e*~NtZ3o=Kp)HzkL3(n}JX~xD~0C I@_)4d52z|svj6}9 delta 8835 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 Mbm|3V>xqf~2Xnrtp#T5? diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 04ef8ab4..936bd4c1 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -1,6 +1,5 @@ - - + AddAddressDialog @@ -19,201 +18,310 @@ Адрес + + 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 desiged 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 - + 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 больше не поддерживаются. Хотите ли Вы удалить его сейчас? Reply - Ответить + Ответить - + Add sender to your Address Book Добавить отправителя в адресную книгу - + Move to Trash Поместить в корзину - + View HTML code as formatted text Просмотреть HTML код как отформатированный текст - + Save message as... Сохранить сообщение как ... - + 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 Добавить новую запись - + Waiting for their encryption key. Will request it again soon. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. - + Encryption key request queued. Запрос ключа шифрования поставлен в очередь. - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. 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 - + Since startup on %1 С начала работы в %1 - + Not Connected Не соединено - + Show Bitmessage Показать Bitmessage - + Send Отправить - + Subscribe Подписки 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. @@ -222,19 +330,19 @@ 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.) @@ -244,97 +352,97 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. Вы должны ввести секретную фразу. Если Вы не хотите этого делать, то Вы выбрали неправильную опцию. - + Processed %1 person-to-person messages. Обработано %1 сообщений. - + Processed %1 broadcast messages. Обработано %1 рассылок. - + Processed %1 public keys. Обработано %1 открытых ключей. - + 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. Вы должны указать адрес в поле "От кого". Вы можете найти Ваш адрес во вкладе "Ваши Адреса". @@ -349,32 +457,32 @@ It is important that you back up this file. Would you like to open the file now? Ошибка: Один из адресов, на который Вы отправляете сообщение, %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. Вы не заполнили поле 'Кому'. @@ -384,52 +492,52 @@ It is important that you back up this file. Would you like to open the file now? Вычисления поставлены в очередь. - + Right click one or more entries in your address book and select 'Send message to this address'. Нажмите правую кнопку мыши на каком-либо адресе и выберите "Отправить сообщение на этот адрес". Work is queued. %1 - Вычисления поставлены в очередь. %1 + Вычисления поставлены в очередь. %1 - + New Message Новое сообщение - + From От - + Address is valid. Адрес введен правильно. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Ошибка: Вы не можете добавлять один и тот же адрес в Адресную Книгу несколько раз. Попробуйте переименовать существующий адрес. - + The address you entered was invalid. Ignoring it. Вы ввели неправильный адрес. Это адрес проигнорирован. 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, чтобы смена номера порта имела эффект. @@ -439,77 +547,77 @@ It is important that you back up this file. Would you like to open the file now? Bitmessage будет использовать Ваш прокси в дальнейшем, тем не менее, мы рекомендуем перезапустить Bitmessage вручную, чтобы закрыть уже существующие соединения. - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. Ошибка: Вы не можете добавлять один и тот же адрес в список несколько раз. Просто переименуйте существующий адрес. - + 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. Запись добавлена в Адресную Книгу. Вы можете её отредактировать. - + Moved items to trash. Удалено в корзину. - + Save As... Сохранить как ... - + Write error. Ошибка записи. - + No addresses selected. Вы не выбрали адрес. @@ -519,89 +627,89 @@ It is important that you back up this file. Would you like to open the file now? Опции были отключены, потому что они либо не подходят, либо еще не выполнены под Вашу операционную систему. - + 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). Вы используете TCP порт %1. (Его можно поменять в настройках). - + Bitmessage Bitmessage - + To Кому - + From От кого - + Subject Тема - + Received Получено Inbox - Входящие + Входящие Load from Address book - Взять из адресной книги + Взять из адресной книги Message: - Сообщение: + Сообщение: - + Subject: Тема: Send to one or more specific people - Отправить одному или нескольким указанным получателям + Отправить одному или нескольким указанным получателям @@ -617,307 +725,307 @@ p, li { white-space: pre-wrap; } <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. - Пожалуйста, учитывайте, что рассылки шифруются лишь Вашим адресом. Любой человек, который знает Ваш адрес, сможет прочитать Вашу рассылку. + Пожалуйста, учитывайте, что рассылки шифруются лишь Вашим адресом. Любой человек, который знает Ваш адрес, сможет прочитать Вашу рассылку. Status - Статус + Статус Sent - Отправленные + Отправленные 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 Подписки 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 адресам Ваших друзей. Вы можете добавлять новые записи с помощью кнопки "Добавить новую запись", или же правым кликом мыши на сообщения. + Адресная книга удобна для присвоения осмысленных имен 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 + Всего соединений: 0 Since startup at asdf: - С начала работы программы в asdf: + С начала работы программы в asdf: Processed 0 person-to-person message. - Обработано 0 сообщений. + Обработано 0 сообщений. Processed 0 public key. - Обработано 0 открытых ключей. + Обработано 0 открытых ключей. Processed 0 broadcast. - Обработано 0 рассылок. + Обработано 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 @@ -928,102 +1036,378 @@ p, li { white-space: pre-wrap; } 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"> + <!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 + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% + + NewAddressDialog @@ -1240,7 +1624,7 @@ The 'Random Number' option is selected by default but deterministic ad version ? версия ? - + Copyright © 2013 Jonathan Warren Копирайт © 2013 Джонатан Уоррен @@ -1257,7 +1641,7 @@ The 'Random Number' option is selected by default but deterministic ad - <html><head/><body><p>Copyright © 2012-2013 Jonathan Warren<br/>Copyright © 2013 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1294,13 +1678,18 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1444,217 +1833,217 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings Настройки - + Start Bitmessage on user login Запускать Bitmessage при входе в систему - + Start Bitmessage in the tray (don't show main window) Запускать Bitmessage в свернутом виде (не показывать главное окно) - + Minimize 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 Специально прикреплять незашифрованный адрес получателя, когда посылаем на мобильное устройство - + <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 - + Interface Language Язык интерфейса - + System Settings system Язык по умолчанию @@ -1663,102 +2052,124 @@ The 'Random Number' option is selected by default but deterministic ad English en - English + English Esperanto eo - Esperanto + Esperanto - Français + Français fr - Francais + Francais Deutsch de - Deutsch + Deutsch - Español + Español es Espanol - Русский + Русский ru Русский - + Pirate English en_pirate Pirate English - + Other (set in keys.dat) other Другие (настроено в keys.dat) - + Use Identicons - - Españl - es - - - - - русский язык - ru - - - - - Norsk - no - - - - + <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 + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + diff --git a/src/translations/bitmessage_zh_cn.pro b/src/translations/bitmessage_zh_cn.pro index cde33c9f..7f8b8293 100644 --- a/src/translations/bitmessage_zh_cn.pro +++ b/src/translations/bitmessage_zh_cn.pro @@ -19,14 +19,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ ../bitmessageqt/addaddressdialog.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index 3f894afd7087d156a33a57fbe1448e33852bd982..c32579a585c53fcea6ecdf21a17e750e13615eda 100644 GIT binary patch delta 2488 zcmX9=cU)9w7CrCHdoyq5O<54IMZf|os33xZD8;f?Ml3sE0UInu11cy@84`5Yjyg&d zS=J~TLL%-uF?KYTUCUZADi~Z6jppYnW)(|Z%O2&A`JMN^_x z2OUUickXfdrVE`vIyU3;qm4rVXuFP>O}~;rIATf-#Mu~^o)2WV$AsJ?+&35Y4-ezRU|X3E z#P4H5WjUs4R|58}nD>SOk|L0|or&FFqhOaE&?#7)Q3fo$kIlKBz?7>vcPtTTvjA5t zs{!wHG@PuVVl8Ow$oR=C@%(f%#SIno+gboqv0d=$KuNs9g&xMPz*vV6G~)p<*&+lN zGH}5LVW0~G^c02YX#-gK4}$eN_Z#bk8I!jI6VrrQFaurOg^VyN(eo!^MM57Ss!&+( zeh~=RB5d8wg6z|U!B?R%lxQr=>bT*g#=AU% z1hO=Nb$@5#{hI!ng}{OU&0woHP?V{Oo?Z_O-m2O1nuPrCX(|$zk@!5#xzC865t@s- zWVYsXE5@DB)HiPgM62dO90~g!(=_KY-k=iA%LC(KN4ILpGMzonStof^)A1pFq`~`# z0gI}nq1G?il3;1%1@@}LS}A!?ADVN6G)HBnaYLn?Hvy@wTk-fYneN`d==K0ds zy>=3}OM8mr=$R*yv)m2nKSTQNVNb^WQ9709L&d(4uDhO~iGuIS!Yu|id@B$5bu+#2 zKn^=c*CxD`2d1)Ty`$wJEmlC?C68&k#@_Fc6ASmTk`Z!J93|~uDrZ(Wnee<^6htB! z2j$`-Dv`d&xS-!Z6?#%I*FK-J5 zG+pGIaoiwYlAmkn2~UIkVwekEb3*Hq&OnQIYiBH|pxeW=DQ_udvbXl*KW4Cy`P$6y zgDCxC?ZS05UH%zu`RJd4;xDw7KU@O3`Dm-XYpKW{t#fS~!1`Ld-~PT=ws+cV)vg@7 z4cbN<3FUUvxvrx!UAySQN3a!!a9vD2E9-GVXIr-f77mziU>O;`Na zNJ=_M_ouNmTS0?v)oo8;W`u72A%2%_y0SSnK)V~d?RiV-sTI1fR^MSkgLL)}4`R30 zh1dhS6CtduaGvhIl~S9+bT53!IO>WLs{Jo3nyO5U_ydVHDwAtBQlX7X&hS2LS%FfJ zYz4Gam6bcD0HXqw^?vlukXXfWoCKmfDtlcSCox4i5+BWj=$>-qa0FXtuq)@PPVwQs za^CLAc}!3mwh-HClt-^B0GCkZ`KR+K)j{QTBhl5Mce^){Zg!MB(N#@j0msYy(< z#MO}A#Emf%S~0b=VR2{#0}V3NM7(0fL572B3(%|9aIpL-1MW8*P2+dpDTb3pPQL%y z@aVHbAj_x7-8Z=h`pIEhBSq8loullysa@;$qJ&q=F{#}aH$TsX* z$Qji-nqxS&sTEVo)$#8rVb0I$>;g&_+*@6hUrYjV>bheM#9!31x}kJ+f?BQ*rh+Nz znId{3+(SL{(|ZDs)Eir@Kzcj1KChXkwW$pwH<7@PYSZU5pGj38x_0OM$7iY!c}`rxU z`EFt0PB%@x9o4)O6w~;$3`+mNG`(sI36`1WJTC+yFPrj*mT=w6bp2c(p0HJ>yCwEn zlybT0x6~+_qs5Hl44iz++;xbRuB|lty}v{{Z8DF1z7j~gY>ow`pZ(HY@|f%WZ02oK zLpj$O=7Vou^7?&b{#SVzFRwS|ivesYkE9PMl(%ARj=A2-yT$6#ifLZvrrAk}baja( zC}Sb7(P~S`8A_Ht$};9#GWPbijH`?w^Ki?Qzt!^3M!u!`!dv#V(NZ(Q%u0`24tQ12 z<(n;svzvLu?y;P3C-$wfyjsIKF9@X}mOggWs(#L~h907Gr!hx%K6ia0I7;1@Ixl(T zX&pN6rH=o2Uv;K**{X9~>Z)`8+fUIr+ya6e^8%hYvisg~R0kC~s{2Jb+6M0o@kn@5 zcq#9H6RI}nEoz<+XuF-<2<_CK? zkA*}^4k>(>W6_{}j`oo*j;x3lM|{+6XJYg#!EtTaUz~@A-xQqpMwDut{bH6%&X?mw Z$vMJSr8s@2SGqcVvSMZD*}Nb8{}0u1%>n=b delta 7134 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 diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 0b580e65..9bb0e3e3 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -1,6 +1,5 @@ - - + AddAddressDialog @@ -19,399 +18,499 @@ 地址 + + 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 desiged 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 - + 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:'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> - - - - + To: 至: - + From: 来自: Broadcast to everyone who is subscribed to your address - 广播给全部订阅到您的地址的人 + 广播给全部订阅到您的地址的人 - + Send 发送 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 订阅 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 + 总连接数: 0 Since startup at asdf: - 自启动于 asdf: + 自启动于 asdf: Processed 0 person-to-person message. - 处理了 0 个点对点消息。 + 处理了 0 个点对点消息。 Processed 0 public key. - 处理了 0 个公匙。 + 处理了 0 个公匙。 Processed 0 broadcast. - 处理了 0 个广播。 + 处理了 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 @@ -421,12 +520,12 @@ p, li { white-space: pre-wrap; } 正在等待他们的加密密钥,我们会在稍后再次请求。 - + Encryption key request queued. 加密密钥请求已经添加到队列中。 - + Queued. 已经添加到队列。 @@ -436,642 +535,918 @@ p, li { white-space: pre-wrap; } 消息已经发送. 正在等待回执. 发送于 %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 消息已经移入回收站 - + 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: 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. 警告: 您尚未连接。 比特信将做足够的功来发送消息,但是消息不会被发出直到您连接。 - + 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 + 做工已经添加到队列中。 %1 - + New Message 新消息 - + From 来自 - + 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 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). 比特信将会从现在开始使用代理,但是您可能想手动重启比特信以便使之前的连接关闭(如果有的话)。 - + 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. 请注意,您所输入的时间限制小于比特信的最小重试时间,因此您将永远不会重发消息。 - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. 错误:您无法将一个地址添加到您的列表两次,也许您想重命名已经存在的那个。 - + 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. 条目已经添加到地址本。您可以去修改您的标签。 - + Moved items to trash. 已经移动项目到回收站。 - + Save As... 另存为... - + Write error. 写入失败。 - + No addresses selected. 没有选择地址。 - + 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. 在这个地址中编码的部分信息过长。 - + 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 。(可以在设置中修改)。 - + Waiting for their encryption key. Will request it again soon. 正在等待他们的加密密钥,我们会在稍后再次请求。 - + Message sent. Waiting for acknowledgement. Sent at %1 消息已经发送. 正在等待回执. 发送于 %1 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 + 广播发送于 %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版的地址那样. Doing work necessary to send message. Receiver's required difficulty: %1 and %2 - 正在做一些必要的工作来发送消息. + 正在做一些必要的工作来发送消息. 接收者要求的难度为: %1 和 %2 Problem: The work demanded by the recipient (%1 and %2) is more difficult than you are willing to do. - 错误: 收件人要求的做工量(%1 和 %2)大于我们的最大接受做工量. + 错误: 收件人要求的做工量(%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 + 消息已经发送. 发送于 %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. - 正在广播公钥请求. 如果他们不在线, 这一过程将自动重试. + 正在广播公钥请求. 如果他们不在线, 这一过程将自动重试. Sending public key request. Waiting for reply. Requested at %1 - 正在发送公钥请求. 等待回应中. 请求于 %1 + 正在发送公钥请求. 等待回应中. 请求于 %1 + + + + Reply to sender + + + + + Reply to channel + + + + + Add sender to your Blacklist + + + + + Undelete + + + + + Email gateway + + + + + 1 hour + + + + + %1 hours + + + + + %1 days + + + + + Channel + + + + + Objects to be synced: %1 + + + + + Down: %1/s Total: %2 + + + + + Up: %1/s Total: %2 + + + + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + + + + + Message queued. + + + + + Sending email gateway registration request + + + + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + + + + + Number needed + + + + + Your maximum download and upload rate must be numbers. Ignoring what you typed. + + + + + Sending email gateway unregistration request + + + + + Sending email gateway status request + + + + + 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. + + + + + Undeleted item. + + + + + 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? + + + + + Some data encoded in the address is malformed. + + + + + Identities + + + + + New Identity + + + + + Messages + + + + + Address book + + + + + Add Contact + + + + + <!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 ordinary Message + + + + + Send Message to your Subscribers + + + + + TTL: + + + + + X days + + + + + Chans + + + + + Add Chan + + + + + Total connections: + + + + + Since startup: + + + + + Objects to be synced: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Contact support + + + + + All accounts + + + + + Zoom level %1% + @@ -1243,8 +1618,8 @@ The 'Random Number' option is selected by default but deterministic ad - <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>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> @@ -1256,6 +1631,11 @@ The 'Random Number' option is selected by default but deterministic ad This is Beta software. 本软件处于Beta阶段。 + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + connectDialog @@ -1290,13 +1670,18 @@ The 'Random Number' option is selected by default but deterministic ad <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> + <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: 鉴于比特信是一个共同完成的项目,您可以在比特信的Wiki上了解如何帮助比特信: + + + <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> + + iconGlossaryDialog @@ -1425,310 +1810,307 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings 设置 - + Start Bitmessage on user login 在用户登录时启动比特信 - + Start Bitmessage in the tray (don't show main window) 启动比特信到托盘 (不要显示主窗口) - + Minimize 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 用户身份 - + 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: 监听连接于端口: - + 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 最大可接受难度 - + <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 - + 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 重发超时 + + + Tray + + + + + Close to tray + + + + + Reply below Quote + + + + + UPnP: + + + + + Bandwidth limit + + + + + Maximum download rate (kB/s): [0: unlimited] + + + + + Maximum upload rate (kB/s): [0: unlimited] + + + + + Hardware GPU acceleration (OpenCL) + + -- 2.45.1 From a1b44aab4456f95d65685fd16e466ba939cf9d57 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Mon, 21 Mar 2016 21:52:10 +0100 Subject: [PATCH 0327/1102] UPnP fixes - UPnP handles errors better - it tries to bind external interface (previously sometimes it searched on 127.0.0.1 resulting in no routers being detected) --- src/upnp.py | 67 ++++++++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index 4c54ef86..5f952c73 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -94,24 +94,10 @@ class Router: service_types = dom.getElementsByTagName('serviceType') for service in service_types: - if service.childNodes[0].data.find('WANIPConnection') > 0: + if service.childNodes[0].data.find('WANIPConnection') > 0 or \ + service.childNodes[0].data.find('WANPPPConnection') > 0: self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data - # get local IP - s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - try: - logger.debug("Connecting to %s:%i", self.address, self.routerPath.port) - s.connect ((self.address, self.routerPath.port)) - except: - pass - self.localAddress = s.getsockname()[0] - logger.debug("Local IP: %s", self.localAddress) - try: - s.shutdown(socket.SHUT_RDWR) - s.close() - except: - pass - def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): from debug import logger resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ @@ -155,15 +141,27 @@ class Router: 'Content-Type': 'text/xml' } ) - resp = conn.getresponse().read() - dom = parseString(resp) - errinfo = dom.getElementsByTagName('errorDescription') - if len(errinfo) > 0: - logger.error("UPnP error: %s", resp) - raise UPnPError(errinfo[0].childNodes[0].data) + 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) 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") self.localPort = shared.config.getint('bitmessagesettings', 'port') @@ -171,10 +169,12 @@ class uPnPThread(threading.Thread, StoppableThread): self.extPort = shared.config.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, 10000)) self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) - self.sock.settimeout(2) + self.sock.settimeout(5) self.sendSleep = 60 self.initStop() @@ -182,6 +182,7 @@ class uPnPThread(threading.Thread, StoppableThread): from debug import logger logger.debug("Starting UPnP thread") + logger.debug("Local IP: %s", self.localIP) lastSent = 0 while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: @@ -227,21 +228,23 @@ class uPnPThread(threading.Thread, StoppableThread): shared.UISignalQueue.put(('updateStatusBar', tr.translateText("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 - 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) + \ + "HOST: %s:%d\r\n" % (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT) + \ "MAN: \"ssdp:discover\"\r\n" + \ - "MX: %d\r\n" % (SSDP_MX, ) + \ - "ST: %s\r\n" % (SSDP_ST, ) + "\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, (SSDP_ADDR, SSDP_PORT)) + self.sock.sendto(ssdpRequest, (uPnPThread.SSDP_ADDR, uPnPThread.SSDP_PORT)) except: logger.exception("UPnP send query failed") @@ -251,7 +254,7 @@ class uPnPThread(threading.Thread, StoppableThread): for i in range(50): try: routerIP, = unpack('>I', socket.inet_aton(router.address)) - localIP = router.localAddress + localIP = self.localIP if i == 0: extPort = self.localPort # try same port first elif i == 1 and self.extPort: -- 2.45.1 From 1b50f3898a16e8970c4dfdd727b62083c3c7fe34 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 21 Mar 2016 22:22:36 +0100 Subject: [PATCH 0328/1102] UPnP fixes: - external port iterator fix - error handler fix --- src/upnp.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index 5f952c73..a0c843d2 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -152,7 +152,7 @@ class Router: logger.error("UPnP error: %s", respData) raise UPnPError(errinfo[0].childNodes[0].data) except: - raise UPnPError("Unable to parse SOAP error: %s", respData) + raise UPnPError("Unable to parse SOAP error: %s" %(respData)) return resp class uPnPThread(threading.Thread, StoppableThread): @@ -186,7 +186,10 @@ class uPnPThread(threading.Thread, StoppableThread): lastSent = 0 while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): if time.time() - lastSent > self.sendSleep and len(self.routers) == 0: - self.sendSearchRouter() + try: + self.sendSearchRouter() + except: + pass lastSent = time.time() try: while shared.shutdown == 0 and shared.safeConfigGetBoolean('bitmessagesettings', 'upnp'): @@ -261,7 +264,7 @@ class uPnPThread(threading.Thread, StoppableThread): extPort = self.extPort # try external port from last time next else: extPort = randint(32767, 65535) - logger.debug("Requesting UPnP mapping for %s:%i on external port %i", localIP, self.localPort, extPort) + 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 -- 2.45.1 From 0ab0e6757a460e1704478d8a2785048443ad39d6 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Mar 2016 14:47:18 +0100 Subject: [PATCH 0329/1102] Restrict pending parallel requests on proxy This saves some network resources if using Tor, for example. --- src/bitmessagemain.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 50971f66..43db5ae1 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -59,6 +59,12 @@ def connectToStream(streamNumber): maximumNumberOfHalfOpenConnections = 9 else: maximumNumberOfHalfOpenConnections = 64 + try: + # don't overload Tor + if shared.config.get('bitmessagesettings', 'socksproxytype') != 'none': + maximumNumberOfHalfOpenConnections = 4 + except: + pass for i in range(maximumNumberOfHalfOpenConnections): a = outgoingSynSender() a.setup(streamNumber, selfInitiatedConnections) -- 2.45.1 From a63f9054f4b0e59f89d5c446bc15edf1dd4bf66a Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Mar 2016 16:30:12 +0100 Subject: [PATCH 0330/1102] Global Sent fix --- src/bitmessageqt/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 16cd780e..a5facbb2 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1019,6 +1019,8 @@ class MyForm(settingsmixin.SMainWindow): 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 = [] -- 2.45.1 From 8172fce7302bde868ec42c3cc63ef28af7e1201d Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Mar 2016 16:30:51 +0100 Subject: [PATCH 0331/1102] Typos --- src/bitmessageqt/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index a5facbb2..641d9838 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -3231,8 +3231,8 @@ class MyForm(settingsmixin.SMainWindow): currentRow, 3).data(Qt.UserRole).toPyObject()) sqlExecute('''UPDATE inbox SET folder='inbox' WHERE msgid=?''', inventoryHashToTrash) if tableWidget.item(currentRow, 0).unread: - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) - self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "inbox", self.getCurrentTreeWidget(), 1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), "trash", self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( @@ -3291,7 +3291,7 @@ class MyForm(settingsmixin.SMainWindow): 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(curentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) + self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), folder, self.getCurrentTreeWidget(), -1) self.getCurrentMessageTextedit().setPlainText("") tableWidget.removeRow(currentRow) self.statusBar().showMessage(_translate( -- 2.45.1 From 66824c32d1971c625a177ec2caae40a5c0b5cbd7 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Mar 2016 17:17:45 +0100 Subject: [PATCH 0332/1102] sqlExecute now returns rowcount This allows tracking of how many rows were changed, for example for UPDATE, DELETE, INSERT. --- src/class_sqlThread.py | 4 +++- src/helper_sql.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py index 0c28bc22..c0b74794 100644 --- a/src/class_sqlThread.py +++ b/src/class_sqlThread.py @@ -546,10 +546,12 @@ class sqlThread(threading.Thread): return else: parameters = shared.sqlSubmitQueue.get() + rowcount = 0 # 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.') @@ -564,5 +566,5 @@ class sqlThread(threading.Thread): os._exit(0) - shared.sqlReturnQueue.put(self.cur.fetchall()) + shared.sqlReturnQueue.put((self.cur.fetchall(), rowcount)) # shared.sqlSubmitQueue.task_done() diff --git a/src/helper_sql.py b/src/helper_sql.py index c50db192..d27401cf 100644 --- a/src/helper_sql.py +++ b/src/helper_sql.py @@ -16,7 +16,7 @@ def sqlQuery(sqlStatement, *args): else: sqlSubmitQueue.put(args) - queryreturn = sqlReturnQueue.get() + queryreturn, rowcount = sqlReturnQueue.get() sqlLock.release() return queryreturn @@ -30,9 +30,10 @@ def sqlExecute(sqlStatement, *args): else: sqlSubmitQueue.put(args) - sqlReturnQueue.get() + queryreturn, rowcount = sqlReturnQueue.get() sqlSubmitQueue.put('commit') sqlLock.release() + return rowcount def sqlStoredProcedure(procName): sqlLock.acquire() -- 2.45.1 From 4f56e49a30bc64b51c848f46f92fbb8d82c1ba57 Mon Sep 17 00:00:00 2001 From: mailchuck Date: Tue, 22 Mar 2016 17:18:35 +0100 Subject: [PATCH 0333/1102] Unread count refresh updates --- src/bitmessageqt/__init__.py | 52 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 641d9838..3cf8ad4b 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -961,14 +961,18 @@ class MyForm(settingsmixin.SMainWindow): xFolder = folder if isinstance(item, Ui_FolderWidget): xFolder = item.folderName - if address and xFolder: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND folder = ? AND read = 0", address, xFolder) - elif address: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND read = 0", address) - elif xFolder: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", xFolder) + if xFolder == "new": + xFolder = "inbox" + if addressItem.type == AccountMixin.ALL: + if xFolder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE folder = ? AND read = 0", xFolder) + else: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") else: - queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE read = 0") + if address and xFolder: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND folder = ? AND read = 0", address, xFolder) + elif address: + queryreturn = sqlQuery("SELECT COUNT(*) FROM inbox WHERE " + xAddress + " = ? AND read = 0", address) for row in queryreturn: item.setUnreadCount(int(row[0])) if isinstance(item, Ui_AddressWidget) and item.type == AccountMixin.ALL: @@ -983,9 +987,6 @@ class MyForm(settingsmixin.SMainWindow): self.drawTrayIcon(self.currentTrayIconFileName, self.findInboxUnreadCount(self.unreadCount -1)) widgets = [self.ui.treeWidgetYourIdentities, self.ui.treeWidgetSubscriptions, self.ui.treeWidgetChans] - # FIXME this is a hack - if folder == "new": - folder = "inbox" for treeWidget in widgets: root = treeWidget.invisibleRootItem() for i in range(root.childCount()): @@ -998,13 +999,16 @@ class MyForm(settingsmixin.SMainWindow): continue for j in range(addressItem.childCount()): folderItem = addressItem.child(j) - if folder is not None and folderItem.folderName != folder and addressItem.type != AccountMixin.ALL: + if folderItem.folderName == "new" and (folder is None or folder in ["inbox", "new"]): + updateUnreadCount(folderItem) + continue + if folder is None and folderItem.folderName != "inbox": + continue + if folder is not None and ((folder == "new" and folderItem.folderName != "inbox") or \ + (folder != "new" and folderItem.folderName != folder)): + continue + if folder in ["sent", "trash"] and folderItem.folderName != folder: continue - if addressItem.type == AccountMixin.ALL: - if folder in ["sent", "trash"] and folderItem.folderName != folder: - continue - if folder in ["inbox", "new"] and folderItem.folderName not in ["inbox", "new"]: - continue updateUnreadCount(folderItem) def addMessageListItem(self, tableWidget, items): @@ -3003,9 +3007,9 @@ class MyForm(settingsmixin.SMainWindow): tableWidget.item(currentRow, 2).setUnread(True) tableWidget.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)''' % ( + rowcount = sqlExecute('''UPDATE inbox SET read=0 WHERE msgid IN (%s) AND read=1''' % ( "?," * len(inventoryHashesToMarkUnread))[:-1], *inventoryHashesToMarkUnread) - if modified == 1: + if rowcount == 1: # performance optimisation self.propagateUnreadCount(tableWidget.item(currentRow, 1 if tableWidget.item(currentRow, 1).type == AccountMixin.SUBSCRIPTION else 0).data(Qt.UserRole), self.getCurrentFolder()) else: @@ -4059,13 +4063,13 @@ class MyForm(settingsmixin.SMainWindow): currentRow = tableWidget.currentRow() for row in queryreturn: message, read = row - if folder != 'sent' and read == 0: - markread = sqlQuery( - '''UPDATE inbox SET read = 1 WHERE msgid = ?''', msgid) - refresh = propagate = True - elif tableWidget.item(currentRow, 0).unread == True: + if tableWidget.item(currentRow, 0).unread == True: refresh = True - propagate = False + if folder != 'sent': + markread = sqlExecute( + '''UPDATE inbox SET read = 1 WHERE msgid = ? AND read=0''', msgid) + if markread > 0: + propagate = True if refresh: if not tableWidget: return -- 2.45.1 From 64fce79321904cd7791a18bdea7b57f0d111b1c8 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Wed, 16 Mar 2016 18:04:18 +0100 Subject: [PATCH 0334/1102] Refactor status icon --- src/bitmessageqt/__init__.py | 20 +++++++++++++------- src/bitmessageqt/bitmessageui.py | 9 --------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 3cf8ad4b..c373e459 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -152,8 +152,6 @@ class MyForm(settingsmixin.SMainWindow): "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( @@ -730,9 +728,17 @@ class MyForm(settingsmixin.SMainWindow): "itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged) # Put the colored icon on the status bar - # self.ui.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) + # self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) self.statusbar = self.statusBar() - self.statusbar.insertPermanentWidget(0, self.ui.pushButtonStatusIcon) + + self.pushButtonStatusIcon = QtGui.QPushButton(self) + self.pushButtonStatusIcon.setText('') + self.pushButtonStatusIcon.setIcon(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.ui.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( l10n.formatTimestamp())) self.numberOfMessagesProcessed = 0 @@ -1814,7 +1820,7 @@ class MyForm(settingsmixin.SMainWindow): global withMessagingMenu # print 'setting status icon color' if color == 'red': - self.ui.pushButtonStatusIcon.setIcon( + self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/redicon.png")) shared.statusIconColor = 'red' # if the connection is lost then show a notification @@ -1831,7 +1837,7 @@ class MyForm(settingsmixin.SMainWindow): 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().showMessage('') - self.ui.pushButtonStatusIcon.setIcon(QIcon( + self.pushButtonStatusIcon.setIcon(QIcon( ":/newPrefix/images/yellowicon.png")) shared.statusIconColor = 'yellow' # if a new connection has been established then show a notification @@ -1848,7 +1854,7 @@ class MyForm(settingsmixin.SMainWindow): 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().showMessage('') - self.ui.pushButtonStatusIcon.setIcon( + self.pushButtonStatusIcon.setIcon( QIcon(":/newPrefix/images/greenicon.png")) shared.statusIconColor = 'green' if not self.connected: diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index b50fd3fe..355cc51b 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -589,14 +589,6 @@ class Ui_MainWindow(object): self.tabWidget.addTab(self.blackwhitelist, icon9, _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("")) - icon10 = QtGui.QIcon() - icon10.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/redicon.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.pushButtonStatusIcon.setIcon(icon10) - self.pushButtonStatusIcon.setFlat(True) - self.pushButtonStatusIcon.setObjectName(_fromUtf8("pushButtonStatusIcon")) self.tableWidgetConnectionCount = settingsmixin.STableWidget(self.networkstatus) self.tableWidgetConnectionCount.setGeometry(QtCore.QRect(20, 70, 241, 241)) palette = QtGui.QPalette() @@ -739,7 +731,6 @@ class Ui_MainWindow(object): 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)) -- 2.45.1 From a23022b2db4f36a62d00876fe01c84219d69fdd2 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Wed, 16 Mar 2016 19:27:12 +0100 Subject: [PATCH 0335/1102] Refactor Network Status tab --- src/bitmessageqt/__init__.py | 168 +--------------------- src/bitmessageqt/bitmessageui.py | 78 +--------- src/bitmessageqt/networkstatus.py | 115 +++++++++++++++ src/bitmessageqt/networkstatus.ui | 232 ++++++++++++++++++++++++++++++ src/bitmessageqt/uisignaler.py | 77 ++++++++++ src/bitmessageqt/widgets.py | 14 ++ 6 files changed, 443 insertions(+), 241 deletions(-) create mode 100644 src/bitmessageqt/networkstatus.py create mode 100644 src/bitmessageqt/networkstatus.ui create mode 100644 src/bitmessageqt/uisignaler.py create mode 100644 src/bitmessageqt/widgets.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c373e459..6740c7cf 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -632,14 +632,6 @@ class MyForm(settingsmixin.SMainWindow): # startup for linux pass - - self.totalNumberOfBytesReceived = 0 - self.totalNumberOfBytesSent = 0 - - self.timer = QtCore.QTimer() - self.timer.start(2000) # milliseconds - QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) - # e.g. for editing labels self.recurDepth = 0 @@ -739,8 +731,6 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.pushButtonStatusIcon, QtCore.SIGNAL( "clicked()"), self.click_pushButtonStatusIcon) - self.ui.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( - l10n.formatTimestamp())) self.numberOfMessagesProcessed = 0 self.numberOfBroadcastsProcessed = 0 self.numberOfPubkeysProcessed = 0 @@ -755,7 +745,7 @@ class MyForm(settingsmixin.SMainWindow): self.ui.tableWidgetAddressBook.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.tableWidgetBlacklist.setIconSize(QtCore.QSize(identicon_size, identicon_size)) - self.UISignalThread = UISignaler() + self.UISignalThread = UISignaler.get() QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "writeNewAddressToTable(PyQt_PyObject,PyQt_PyObject,PyQt_PyObject)"), self.writeNewAddressToTable) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -768,14 +758,6 @@ 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( @@ -1719,21 +1701,6 @@ class MyForm(settingsmixin.SMainWindow): self.actionShow.setChecked(not self.actionShow.isChecked()) self.appIndicatorShowOrHideWindow() - def updateNumberOfMessagesProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) - self.ui.labelMessageCount.setText(_translate( - "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) - - def updateNumberOfBroadcastsProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) - self.ui.labelBroadcastCount.setText(_translate( - "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) - - def updateNumberOfPubkeysProcessed(self): - self.ui.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) - 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: @@ -1745,74 +1712,6 @@ class MyForm(settingsmixin.SMainWindow): 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): - 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 @@ -4631,70 +4530,7 @@ class myTableWidgetItem(QTableWidgetItem): def __lt__(self, other): return int(self.data(33).toPyObject()) < int(other.data(33).toPyObject()) -class UISignaler(QThread): - - 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 == '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) +from uisignaler import UISignaler app = None diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 355cc51b..63b10e3c 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -11,6 +11,7 @@ from PyQt4 import QtCore, QtGui from messageview import MessageView from messagecompose import MessageCompose import settingsmixin +from networkstatus import NetworkStatus try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -587,67 +588,8 @@ class Ui_MainWindow(object): icon9 = QtGui.QIcon() icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tabWidget.addTab(self.blackwhitelist, icon9, _fromUtf8("")) - self.networkstatus = QtGui.QWidget() - self.networkstatus.setObjectName(_fromUtf8("networkstatus")) - self.tableWidgetConnectionCount = settingsmixin.STableWidget(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.labelSyncStatus = QtGui.QLabel(self.networkstatus) - self.labelSyncStatus.setGeometry(QtCore.QRect(350, 190, 331, 20)) - self.labelSyncStatus.setObjectName(_fromUtf8("labelSyncStatus")) - self.labelLookupsPerSecond = QtGui.QLabel(self.networkstatus) - self.labelLookupsPerSecond.setGeometry(QtCore.QRect(320, 270, 291, 16)) - self.labelLookupsPerSecond.setObjectName(_fromUtf8("labelLookupsPerSecond")) - self.labelBytesRecvCount = QtGui.QLabel(self.networkstatus) - self.labelBytesRecvCount.setGeometry(QtCore.QRect(350, 230, 251, 16)) - self.labelBytesRecvCount.setObjectName(_fromUtf8("labelBytesRecvCount")) - self.labelBytesSentCount = QtGui.QLabel(self.networkstatus) - self.labelBytesSentCount.setGeometry(QtCore.QRect(350, 250, 251, 16)) - self.labelBytesSentCount.setObjectName(_fromUtf8("labelBytesSentCount")) - icon11 = QtGui.QIcon() - icon11.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/networkstatus.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.networkstatus, icon11, _fromUtf8("")) + self.networkstatus = NetworkStatus() + self.tabWidget.addTab(self.networkstatus, QtGui.QIcon(":/newPrefix/images/networkstatus.png"), "") self.gridLayout_10.addWidget(self.tabWidget, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtGui.QMenuBar(MainWindow) @@ -730,7 +672,6 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.radioButtonBlacklist, self.radioButtonWhitelist) MainWindow.setTabOrder(self.radioButtonWhitelist, self.pushButtonAddBlacklist) MainWindow.setTabOrder(self.pushButtonAddBlacklist, self.tableWidgetBlacklist) - MainWindow.setTabOrder(self.tableWidgetBlacklist, self.tableWidgetConnectionCount) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) @@ -825,19 +766,6 @@ class Ui_MainWindow(object): 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.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced:", 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)) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py new file mode 100644 index 00000000..96bc46f6 --- /dev/null +++ b/src/bitmessageqt/networkstatus.py @@ -0,0 +1,115 @@ +from PyQt4 import QtCore, QtGui +import shared +from tr import _translate +import l10n +from uisignaler import UISignaler +import widgets + + +class NetworkStatus(QtGui.QWidget): + def __init__(self, parent=None): + super(NetworkStatus, self).__init__(parent) + widgets.load('networkstatus.ui', self) + + self.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( + l10n.formatTimestamp())) + + 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()"), self.updateNetworkStatusTab) + + self.totalNumberOfBytesReceived = 0 + self.totalNumberOfBytesSent = 0 + + self.timer = QtCore.QTimer() + self.timer.start(2000) # milliseconds + QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + + def updateNumberOfMessagesProcessed(self): + self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelMessageCount.setText(_translate( + "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) + + def updateNumberOfBroadcastsProcessed(self): + self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelBroadcastCount.setText(_translate( + "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) + + def updateNumberOfPubkeysProcessed(self): + self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelPubkeyCount.setText(_translate( + "MainWindow", "Processed %1 public keys.").arg(str(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( + "MainWindow", "Down: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesReceived/2), self.formatBytes(self.totalNumberOfBytesReceived))) + self.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): + 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.tableWidgetConnectionCount.rowCount() > 0: + self.tableWidgetConnectionCount.removeRow(0) + for streamNumber, connectionCount in streamNumberTotals.items(): + self.tableWidgetConnectionCount.insertRow(0) + if streamNumber == 0: + newItem = QtGui.QTableWidgetItem("?") + else: + newItem = QtGui.QTableWidgetItem(str(streamNumber)) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.tableWidgetConnectionCount.setItem(0, 0, newItem) + newItem = QtGui.QTableWidgetItem(str(connectionCount)) + newItem.setFlags( + QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + self.tableWidgetConnectionCount.setItem(0, 1, newItem) + """for currentRow in range(self.tableWidgetConnectionCount.rowCount()): + rowStreamNumber = int(self.tableWidgetConnectionCount.item(currentRow,0).text()) + if streamNumber == rowStreamNumber: + foundTheRowThatNeedsUpdating = True + self.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.tableWidgetConnectionCount.insertRow(0) + newItem = QtGui.QTableWidgetItem(str(streamNumber)) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + self.tableWidgetConnectionCount.setItem(0,0,newItem) + newItem = QtGui.QTableWidgetItem(str(connectionCount)) + newItem.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) + self.tableWidgetConnectionCount.setItem(0,1,newItem) + totalNumberOfConnectionsFromAllStreams += connectionCount""" + self.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.window().setStatusIcon('yellow') + elif len(shared.connectedHostsList) == 0: + self.window().setStatusIcon('red') + + # timer driven + def runEveryTwoSeconds(self): + self.labelLookupsPerSecond.setText(_translate( + "MainWindow", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) + shared.numberOfInventoryLookupsPerformed = 0 + self.updateNumberOfBytes() diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui new file mode 100644 index 00000000..afc8b976 --- /dev/null +++ b/src/bitmessageqt/networkstatus.ui @@ -0,0 +1,232 @@ + + + NetworkStatus + + + + 0 + 0 + 731 + 493 + + + + + + 20 + 30 + 401 + 16 + + + + Total connections: + + + + + + 320 + 110 + 331 + 20 + + + + Since startup: + + + + + + 350 + 130 + 361 + 16 + + + + Processed 0 person-to-person messages. + + + + + + 350 + 170 + 331 + 16 + + + + Processed 0 public keys. + + + + + + 350 + 150 + 351 + 16 + + + + Processed 0 broadcasts. + + + + + + 320 + 270 + 291 + 16 + + + + Inventory lookups per second: 0 + + + + + + 350 + 220 + 251 + 16 + + + + Down: 0 KB/s + + + + + + 350 + 240 + 251 + 16 + + + + Up: 0 KB/s + + + + + + 350 + 190 + 331 + 16 + + + + Objects to be synced: + + + + + + 20 + 70 + 241 + 241 + + + + + + + + + + + + 212 + 208 + 200 + + + + + + + + + 212 + 208 + 200 + + + + + + + + + 212 + 208 + 200 + + + + + + + + QFrame::Box + + + QFrame::Plain + + + false + + + true + + + QAbstractItemView::NoSelection + + + true + + + false + + + true + + + false + + + + Stream # + + + + + Connections + + + + + + + + + + STableWidget + QTableWidget +
bitmessageqt/settingsmixin.h
+
+
+ + + + +
diff --git a/src/bitmessageqt/uisignaler.py b/src/bitmessageqt/uisignaler.py new file mode 100644 index 00000000..ea18f0b0 --- /dev/null +++ b/src/bitmessageqt/uisignaler.py @@ -0,0 +1,77 @@ + +from PyQt4.QtCore import QThread, SIGNAL +import shared +import sys + + +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 = 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 == '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/widgets.py b/src/bitmessageqt/widgets.py new file mode 100644 index 00000000..7919d7f9 --- /dev/null +++ b/src/bitmessageqt/widgets.py @@ -0,0 +1,14 @@ +from PyQt4 import uic +import os.path +import sys + + +def resource_path(path): + try: + return os.path.join(sys._MEIPASS, path) + except: + return os.path.join(os.path.dirname(__file__), path) + + +def load(path, widget): + uic.loadUi(resource_path(path), widget) -- 2.45.1 From 69aa618890641c3038b7eaf3f467dd3cccf41350 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Wed, 16 Mar 2016 23:27:41 +0100 Subject: [PATCH 0336/1102] Combine all translation project files into one --- .../{bitmessage_ar.pro => bitmessage.pro} | 18 +++++++- src/translations/bitmessage_cs.pro | 41 ------------------- src/translations/bitmessage_de.pro | 41 ------------------- src/translations/bitmessage_en_pirate.pro | 41 ------------------- src/translations/bitmessage_eo.pro | 41 ------------------- src/translations/bitmessage_fr.pro | 41 ------------------- src/translations/bitmessage_ja.pro | 40 ------------------ src/translations/bitmessage_nl.pro | 41 ------------------- src/translations/bitmessage_no.pro | 41 ------------------- src/translations/bitmessage_ru.pro | 41 ------------------- src/translations/bitmessage_zh_cn.pro | 41 ------------------- 11 files changed, 16 insertions(+), 411 deletions(-) rename src/translations/{bitmessage_ar.pro => bitmessage.pro} (75%) delete mode 100755 src/translations/bitmessage_cs.pro delete mode 100644 src/translations/bitmessage_de.pro delete mode 100644 src/translations/bitmessage_en_pirate.pro delete mode 100644 src/translations/bitmessage_eo.pro delete mode 100644 src/translations/bitmessage_fr.pro delete mode 100644 src/translations/bitmessage_ja.pro delete mode 100644 src/translations/bitmessage_nl.pro delete mode 100644 src/translations/bitmessage_no.pro delete mode 100644 src/translations/bitmessage_ru.pro delete mode 100644 src/translations/bitmessage_zh_cn.pro diff --git a/src/translations/bitmessage_ar.pro b/src/translations/bitmessage.pro similarity index 75% rename from src/translations/bitmessage_ar.pro rename to src/translations/bitmessage.pro index 1cd8dd64..45d701fd 100644 --- a/src/translations/bitmessage_ar.pro +++ b/src/translations/bitmessage.pro @@ -30,6 +30,20 @@ SOURCES = ../addresses.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py - -TRANSLATIONS = bitmessage_ar.ts +FORMS = \ + ../bitmessageqt/networkstatus.ui + +TRANSLATIONS = \ + bitmessage_ar.ts \ + bitmessage_cs.ts \ + bitmessage_de.ts \ + bitmessage_en_pirate.ts \ + bitmessage_eo.ts \ + bitmessage_fr.ts \ + bitmessage_ja.ts \ + bitmessage_nl.ts \ + bitmessage_no.ts \ + bitmessage_ru.ts \ + bitmessage_zh_cn.ts + CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_cs.pro b/src/translations/bitmessage_cs.pro deleted file mode 100755 index 8b0094be..00000000 --- a/src/translations/bitmessage_cs.pro +++ /dev/null @@ -1,41 +0,0 @@ -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/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_cs.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_de.pro b/src/translations/bitmessage_de.pro deleted file mode 100644 index b5f58227..00000000 --- a/src/translations/bitmessage_de.pro +++ /dev/null @@ -1,41 +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_sent.py\ - ../helper_startup.py\ - ../shared.py\ - ../bitmessageqt/__init__.py\ - ../bitmessageqt/about.py\ - ../bitmessageqt/addaddressdialog.py\ - ../bitmessageqt/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_de.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_en_pirate.pro b/src/translations/bitmessage_en_pirate.pro deleted file mode 100644 index 618b6695..00000000 --- a/src/translations/bitmessage_en_pirate.pro +++ /dev/null @@ -1,41 +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_sent.py\ - ../helper_startup.py\ - ../shared.py\ - ../bitmessageqt/__init__.py\ - ../bitmessageqt/about.py\ - ../bitmessageqt/addaddressdialog.py\ - ../bitmessageqt/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_en_pirate.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_eo.pro b/src/translations/bitmessage_eo.pro deleted file mode 100644 index 0d103003..00000000 --- a/src/translations/bitmessage_eo.pro +++ /dev/null @@ -1,41 +0,0 @@ -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/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_eo.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_fr.pro b/src/translations/bitmessage_fr.pro deleted file mode 100644 index 9e004955..00000000 --- a/src/translations/bitmessage_fr.pro +++ /dev/null @@ -1,41 +0,0 @@ -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/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_fr.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_ja.pro b/src/translations/bitmessage_ja.pro deleted file mode 100644 index fbf5b646..00000000 --- a/src/translations/bitmessage_ja.pro +++ /dev/null @@ -1,40 +0,0 @@ -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/account.py\ - ../bitmessageqt/addaddressdialog.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_ja.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_nl.pro b/src/translations/bitmessage_nl.pro deleted file mode 100644 index ad292f0e..00000000 --- a/src/translations/bitmessage_nl.pro +++ /dev/null @@ -1,41 +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_sent.py\ - ../helper_startup.py\ - ../shared.py\ - ../bitmessageqt/__init__.py\ - ../bitmessageqt/about.py\ - ../bitmessageqt/addaddressdialog.py\ - ../bitmessageqt/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_nl.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_no.pro b/src/translations/bitmessage_no.pro deleted file mode 100644 index 6edd63b5..00000000 --- a/src/translations/bitmessage_no.pro +++ /dev/null @@ -1,41 +0,0 @@ -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/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_no.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_ru.pro b/src/translations/bitmessage_ru.pro deleted file mode 100644 index 2215cfbf..00000000 --- a/src/translations/bitmessage_ru.pro +++ /dev/null @@ -1,41 +0,0 @@ -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/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_ru.ts -CODECFORTR = UTF-8 diff --git a/src/translations/bitmessage_zh_cn.pro b/src/translations/bitmessage_zh_cn.pro deleted file mode 100644 index 7f8b8293..00000000 --- a/src/translations/bitmessage_zh_cn.pro +++ /dev/null @@ -1,41 +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_sent.py\ - ../helper_startup.py\ - ../shared.py\ - ../bitmessageqt/__init__.py\ - ../bitmessageqt/about.py\ - ../bitmessageqt/addaddressdialog.py\ - ../bitmessageqt/account.py\ - ../bitmessageqt/bitmessageui.py\ - ../bitmessageqt/connect.py\ - ../bitmessageqt/emailgateway.py\ - ../bitmessageqt/foldertree.py\ - ../bitmessageqt/help.py\ - ../bitmessageqt/iconglossary.py\ - ../bitmessageqt/messagecompose.py\ - ../bitmessageqt/messageview.py\ - ../bitmessageqt/newaddressdialog.py\ - ../bitmessageqt/newchandialog.py\ - ../bitmessageqt/newsubscriptiondialog.py\ - ../bitmessageqt/regenerateaddresses.py\ - ../bitmessageqt/safehtmlparser.py\ - ../bitmessageqt/settings.py\ - ../bitmessageqt/specialaddressbehavior.py - - -TRANSLATIONS = bitmessage_zh_cn.ts -CODECFORTR = UTF-8 -- 2.45.1 From 24ae23946b54b7351870c68f36dded8c80b4c481 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 23 Mar 2016 09:33:26 +0100 Subject: [PATCH 0337/1102] Translations config file update --- src/translations/bitmessage.pro | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 45d701fd..87913801 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -18,15 +18,21 @@ SOURCES = ../addresses.py\ ../shared.py\ ../bitmessageqt/__init__.py\ ../bitmessageqt/about.py\ + ../bitmessageqt/account.py\ ../bitmessageqt/addaddressdialog.py\ ../bitmessageqt/bitmessageui.py\ ../bitmessageqt/connect.py\ + ../bitmessageqt/emailgateway.py\ + ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/messagecompose.py\ + ../bitmessageqt/messageview.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ ../bitmessageqt/regenerateaddresses.py\ + ../bitmessageqt/safehtmlparser.py\ ../bitmessageqt/settings.py\ ../bitmessageqt/specialaddressbehavior.py @@ -37,6 +43,7 @@ TRANSLATIONS = \ bitmessage_ar.ts \ bitmessage_cs.ts \ bitmessage_de.ts \ + bitmessage_en.ts \ bitmessage_en_pirate.ts \ bitmessage_eo.ts \ bitmessage_fr.ts \ -- 2.45.1 From 337cf93b4ba4e0fb4bb72eaff9ad9b891965e823 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Thu, 17 Mar 2016 19:03:17 +0100 Subject: [PATCH 0338/1102] Fix byte formatting --- src/bitmessageqt/__init__.py | 11 ----------- src/bitmessageqt/networkstatus.py | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6740c7cf..c6d15007 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -1701,17 +1701,6 @@ class MyForm(settingsmixin.SMainWindow): self.actionShow.setChecked(not self.actionShow.isChecked()) self.appIndicatorShowOrHideWindow() - 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 - # Indicates whether or not there is a connection to the Bitmessage network connected = False diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index 96bc46f6..cadff96a 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -31,6 +31,17 @@ class NetworkStatus(QtGui.QWidget): self.timer.start(2000) # milliseconds QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.runEveryTwoSeconds) + 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 updateNumberOfMessagesProcessed(self): self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.labelMessageCount.setText(_translate( -- 2.45.1 From 7800272d3a0d9a371ee1ac544ad8ef73287119b5 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Thu, 17 Mar 2016 22:09:46 +0100 Subject: [PATCH 0339/1102] Refactor Blacklist tab --- src/bitmessageqt/__init__.py | 265 +----------------------------- src/bitmessageqt/bitmessageui.py | 59 +------ src/bitmessageqt/blacklist.py | 241 +++++++++++++++++++++++++++ src/bitmessageqt/blacklist.ui | 108 ++++++++++++ src/bitmessageqt/dialogs.py | 42 +++++ src/bitmessageqt/networkstatus.ui | 4 +- 6 files changed, 407 insertions(+), 312 deletions(-) create mode 100644 src/bitmessageqt/blacklist.py create mode 100644 src/bitmessageqt/blacklist.ui create mode 100644 src/bitmessageqt/dialogs.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index c6d15007..430deac6 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -31,7 +31,6 @@ from newaddresswizard import * from messageview import MessageView from migrationwizard import * from foldertree import * -from addaddressdialog import * from newsubscriptiondialog import * from regenerateaddresses import * from newchandialog import * @@ -67,6 +66,7 @@ import types from utils import * from collections import OrderedDict from account import * +from dialogs import AddAddressDialog def _translate(context, text): return QtGui.QApplication.translate(context, text) @@ -140,18 +140,12 @@ class MyForm(settingsmixin.SMainWindow): "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.pushButtonSend, QtCore.SIGNAL( "clicked()"), self.click_pushButtonSend) 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.actionSettings, QtCore.SIGNAL( "triggered()"), self.click_actionSettings) QtCore.QObject.connect(self.ui.actionAbout, QtCore.SIGNAL( @@ -365,46 +359,6 @@ class MyForm(settingsmixin.SMainWindow): # self.popMenuSent.addAction( self.actionSentClipboard ) # self.popMenuSent.addAction( self.actionTrashSentMessage ) - 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 rerenderTabTreeSubscriptions(self): treeWidget = self.ui.treeWidgetSubscriptions folders = Ui_FolderWidget.folderWeight.keys() @@ -645,8 +599,7 @@ class MyForm(settingsmixin.SMainWindow): 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() @@ -683,12 +636,6 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.ui.inboxSearchLineEditChans, QtCore.SIGNAL( "textChanged(QString)"), self.inboxSearchLineEditUpdated) - # Initialize the Blacklist or Whitelist - if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': - self.ui.tabWidget.setTabText(6, 'Whitelist') - self.ui.radioButtonWhitelist.click() - self.rerenderBlackWhiteList() - # Initialize addressbook QtCore.QObject.connect(self.ui.tableWidgetAddressBook, QtCore.SIGNAL( "itemChanged(QTableWidgetItem *)"), self.tableWidgetAddressBookItemChanged) @@ -715,10 +662,6 @@ class MyForm(settingsmixin.SMainWindow): QtCore.QObject.connect(self.ui.treeWidgetChans, QtCore.SIGNAL( "itemChanged (QTreeWidgetItem *, int)"), self.treeWidgetItemChanged) - # Initialize blacklist - QtCore.QObject.connect(self.ui.tableWidgetBlacklist, QtCore.SIGNAL( - "itemChanged(QTableWidgetItem *)"), self.tableWidgetBlacklistItemChanged) - # Put the colored icon on the status bar # self.pushButtonStatusIcon.setIcon(QIcon(":/newPrefix/images/yellowicon.png")) self.statusbar = self.statusBar() @@ -743,7 +686,6 @@ class MyForm(settingsmixin.SMainWindow): self.ui.treeWidgetYourIdentities.setIconSize(QtCore.QSize(identicon_size, identicon_size)) self.ui.treeWidgetSubscriptions.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() QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -770,8 +712,6 @@ class MyForm(settingsmixin.SMainWindow): "rerenderAddressBook()"), self.rerenderAddressBook) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "rerenderSubscriptions()"), self.rerenderSubscriptions) - QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( - "rerenderBlackWhiteList()"), self.rerenderBlackWhiteList) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( "removeInboxRowByMsgid(PyQt_PyObject)"), self.removeInboxRowByMsgid) QtCore.QObject.connect(self.UISignalThread, QtCore.SIGNAL( @@ -1684,7 +1624,7 @@ class MyForm(settingsmixin.SMainWindow): self.init_addressbook_popup_menu(False) self.init_subscriptions_popup_menu(False) self.init_sent_popup_menu(False) - self.init_blacklist_popup_menu(False) + self.ui.blackwhitelist.init_blacklist_popup_menu(False) if event.type() == QtCore.QEvent.WindowStateChange: if self.windowState() & QtCore.Qt.WindowMinimized: if shared.config.getboolean('bitmessagesettings', 'minimizetotray') and not 'darwin' in sys.platform: @@ -1968,29 +1908,6 @@ class MyForm(settingsmixin.SMainWindow): def rerenderSubscriptions(self): self.rerenderTabTreeSubscriptions() - 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''') - self.ui.tableWidgetBlacklist.setSortingEnabled(False) - 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) - self.ui.tableWidgetBlacklist.setSortingEnabled(True) def click_pushButtonTTL(self): QtGui.QMessageBox.information(self, 'Time To Live', _translate( @@ -2630,64 +2547,6 @@ class MyForm(settingsmixin.SMainWindow): 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): self.dialog = SpecialAddressBehaviorDialog(self) # For Modal dialogs @@ -3061,7 +2920,7 @@ class MyForm(settingsmixin.SMainWindow): sqlExecute('''INSERT INTO blacklist VALUES (?,?, ?)''', label, addressAtCurrentInboxRow, True) - self.rerenderBlackWhiteList() + self.ui.blackwhitelist.rerenderBlackWhiteList() self.statusBar().showMessage(_translate( "MainWindow", "Entry added to the blacklist. Edit the label to your liking.")) else: @@ -3368,69 +3227,6 @@ class MyForm(settingsmixin.SMainWindow): self.popMenuSubscriptions.exec_( self.ui.treeWidgetSubscriptions.mapToGlobal(point)) - # 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: - sqlExecute( - '''DELETE FROM whitelist WHERE label=? AND address=?''', - str(labelAtCurrentRow), str(addressAtCurrentRow)) - self.ui.tableWidgetBlacklist.removeRow(currentRow) - - 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: - sqlExecute( - '''UPDATE whitelist SET enabled=1 WHERE address=?''', - str(addressAtCurrentRow)) - - 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: - sqlExecute( - '''UPDATE whitelist SET enabled=0 WHERE address=?''', str(addressAtCurrentRow)) - def widgetConvert (self, widget): if widget == self.ui.tableWidgetInbox: return self.ui.treeWidgetYourIdentities @@ -3684,9 +3480,6 @@ class MyForm(settingsmixin.SMainWindow): def on_action_AddressBookSetAvatar(self): self.on_action_SetAvatar(self.ui.tableWidgetAddressBook) - def on_action_BlacklistSetAvatar(self): - self.on_action_SetAvatar(self.ui.tableWidgetBlacklist) - def on_action_SetAvatar(self, thisTableWidget): currentRow = thisTableWidget.currentRow() addressAtCurrentRow = thisTableWidget.item( @@ -3757,7 +3550,7 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFromBroadcast() self.rerenderMessagelistFromLabels() self.rerenderMessagelistToLabels() - self.rerenderBlackWhiteList() + self.ui.blackwhitelist.rerenderBlackWhiteList() # generate identicon return False @@ -4001,17 +3794,6 @@ class MyForm(settingsmixin.SMainWindow): self.rerenderComboBoxSendFrom() self.rerenderComboBoxSendFromBroadcast() - def tableWidgetBlacklistItemChanged(self, item): - if item.column() == 0: - addressitem = self.ui.tableWidgetBlacklist.item(item.row(), 1) - if isinstance(addressitem, QTableWidgetItem): - if self.ui.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 updateStatusBar(self, data): if data != "": logger.info('Status bar: ' + data) @@ -4370,43 +4152,6 @@ class EmailGatewayRegistrationDialog(QtGui.QDialog): 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): diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 63b10e3c..b8547c22 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -12,6 +12,8 @@ from messageview import MessageView from messagecompose import MessageCompose import settingsmixin from networkstatus import NetworkStatus +from blacklist import Blacklist +import shared try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -551,43 +553,13 @@ class Ui_MainWindow(object): 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 = 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) - spacerItem = QtGui.QSpacerItem(689, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) - self.gridLayout_6.addItem(spacerItem, 2, 1, 1, 1) - self.tableWidgetBlacklist = settingsmixin.STableWidget(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) - icon9 = QtGui.QIcon() - icon9.addPixmap(QtGui.QPixmap(_fromUtf8(":/newPrefix/images/blacklist.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) - self.tabWidget.addTab(self.blackwhitelist, icon9, _fromUtf8("")) + self.blackwhitelist = Blacklist() + self.tabWidget.addTab(self.blackwhitelist, QtGui.QIcon(":/newPrefix/images/blacklist.png"), "") + # Initialize the Blacklist or Whitelist + if shared.config.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) @@ -668,10 +640,6 @@ class Ui_MainWindow(object): MainWindow.setTabOrder(self.lineEditTo, self.lineEditSubject) MainWindow.setTabOrder(self.lineEditSubject, self.textEditMessage) MainWindow.setTabOrder(self.textEditMessage, self.pushButtonAddSubscription) - MainWindow.setTabOrder(self.pushButtonAddSubscription, self.radioButtonBlacklist) - MainWindow.setTabOrder(self.radioButtonBlacklist, self.radioButtonWhitelist) - MainWindow.setTabOrder(self.radioButtonWhitelist, self.pushButtonAddBlacklist) - MainWindow.setTabOrder(self.pushButtonAddBlacklist, self.tableWidgetBlacklist) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(_translate("MainWindow", "Bitmessage", None)) @@ -757,15 +725,6 @@ class Ui_MainWindow(object): item = self.tableWidgetInboxChans.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", 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)) 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)) diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py new file mode 100644 index 00000000..11fdb201 --- /dev/null +++ b/src/bitmessageqt/blacklist.py @@ -0,0 +1,241 @@ +from PyQt4 import QtCore, QtGui +import shared +from tr import _translate +import l10n +from uisignaler import UISignaler +import widgets +from addresses import addBMIfNotPresent +from dialogs import AddAddressDialog +from helper_sql import sqlExecute, sqlQuery +from utils import avatarize +from uisignaler import UISignaler + + +class Blacklist(QtGui.QWidget): + 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 shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white': + shared.config.set('bitmessagesettings', 'blackwhitelist', 'black') + shared.writeKeysFile() + # self.tableWidgetBlacklist.clearContents() + self.tableWidgetBlacklist.setRowCount(0) + self.rerenderBlackWhiteList() + + def click_radioButtonWhitelist(self): + if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black': + shared.config.set('bitmessagesettings', 'blackwhitelist', 'white') + shared.writeKeysFile() + # 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 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.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 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 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 shared.config.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 = 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''') + 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 shared.config.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 shared.config.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 shared.config.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 new file mode 100644 index 00000000..80993fac --- /dev/null +++ b/src/bitmessageqt/blacklist.ui @@ -0,0 +1,108 @@ + + + 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/dialogs.py b/src/bitmessageqt/dialogs.py new file mode 100644 index 00000000..d8133eb1 --- /dev/null +++ b/src/bitmessageqt/dialogs.py @@ -0,0 +1,42 @@ +from PyQt4 import QtCore, QtGui +from addaddressdialog import Ui_AddAddressDialog +from addresses import decodeAddress +from tr import _translate + + +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.")) diff --git a/src/bitmessageqt/networkstatus.ui b/src/bitmessageqt/networkstatus.ui index afc8b976..07b0a36a 100644 --- a/src/bitmessageqt/networkstatus.ui +++ b/src/bitmessageqt/networkstatus.ui @@ -1,7 +1,7 @@ - NetworkStatus - + networkstatus + 0 -- 2.45.1 From 554627dd929cc6ec2878002c276232c0d2670940 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Fri, 18 Mar 2016 02:01:59 +0100 Subject: [PATCH 0340/1102] Refactor Inventory --- src/api.py | 2 - src/bitmessagemain.py | 5 -- src/bitmessageqt/__init__.py | 23 +++--- src/class_receiveDataThread.py | 45 ++---------- src/class_singleCleaner.py | 32 +-------- src/class_singleWorker.py | 49 ++++--------- src/shared.py | 127 ++++++++++++++++++++++----------- 7 files changed, 116 insertions(+), 167 deletions(-) diff --git a/src/api.py b/src/api.py index 968fb29d..edae0dc5 100644 --- a/src/api.py +++ b/src/api.py @@ -850,7 +850,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 2.5 * 24 * 60 * 60 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):', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( @@ -898,7 +897,6 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): TTL = 28 * 24 * 60 * 60 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:', inventoryHash.encode('hex') shared.broadcastToSendDataQueues(( diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index 43db5ae1..abbcfff4 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -48,12 +48,7 @@ from helper_threading import * def connectToStream(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. maximumNumberOfHalfOpenConnections = 9 diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 430deac6..cfc5ceec 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2305,16 +2305,12 @@ class MyForm(settingsmixin.SMainWindow): # in the objectProcessorQueue to be processed if self.NewSubscriptionDialogInstance.ui.checkBoxDisplayMessagesAlreadyInInventory.isChecked(): status, addressVersion, streamNumber, ripe = decodeAddress(address) - shared.flushInventory() + shared.inventory.flush() 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 - shared.objectProcessorQueue.put((objectType,payload)) + for value in shared.inventory.by_type_and_tag(3, tag): + shared.objectProcessorQueue.put((value.type, value.payload)) def click_pushButtonStatusIcon(self): logger.debug('click_pushButtonStatusIcon') @@ -4196,23 +4192,22 @@ class NewSubscriptionDialog(QtGui.QDialog): self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate("MainWindow", "Address is an old type. We cannot display its past broadcasts.")) else: - shared.flushInventory() + shared.inventory.flush() 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: + count = len(shared.inventory.by_type_and_tag(3, tag)) + if count == 0: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate("MainWindow", "There are no recent broadcasts from this address to display.")) - elif len(queryreturn) == 1: + elif count == 1: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "Display the %1 recent broadcast from this address.").arg(str(len(queryreturn)))) + _translate("MainWindow", "Display the %1 recent broadcast from this address.").arg(count)) else: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "Display the %1 recent broadcasts from this address.").arg(str(len(queryreturn)))) + _translate("MainWindow", "Display the %1 recent broadcasts from this address.").arg(count)) class NewAddressDialog(QtGui.QDialog): diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index aec343d8..a8854e47 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -216,14 +216,8 @@ class receiveDataThread(threading.Thread): objectHash, = random.sample( self.objectsThatWeHaveYetToGetFromThisPeer, 1) if objectHash in shared.inventory: - logger.debug('Inventory (in memory) already has object listed in inv message.') - del self.objectsThatWeHaveYetToGetFromThisPeer[ - objectHash] - elif shared.isInSqlInventory(objectHash): - if shared.verbose >= 3: - logger.debug('Inventory (SQL on disk) already has object listed in inv message.') - del self.objectsThatWeHaveYetToGetFromThisPeer[ - objectHash] + logger.debug('Inventory 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) @@ -318,23 +312,10 @@ class receiveDataThread(threading.Thread): 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 row in queryreturn: - hash, = row + for hash in shared.inventory.unexpired_hashes_by_stream(self.streamNumber): if hash not in self.someObjectsOfWhichThisRemoteNodeIsAlreadyAware and not self.objectHashHolderInstance.hasHash(hash): 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,9 +421,7 @@ class receiveDataThread(threading.Thread): data[lengthOfVarint:32 + lengthOfVarint]] = 0 shared.numberOfInventoryLookupsPerformed += 1 if data[lengthOfVarint:32 + lengthOfVarint] in shared.inventory: - logger.debug('Inventory (in memory) has inventory item already.') - elif shared.isInSqlInventory(data[lengthOfVarint:32 + lengthOfVarint]): - logger.debug('Inventory (SQL on disk) has inventory item already.') + logger.debug('Inventory has inventory item already.') else: self.sendgetdata(data[lengthOfVarint:32 + lengthOfVarint]) else: @@ -453,7 +432,7 @@ class receiveDataThread(threading.Thread): advertisedSet = set() for i in range(numberOfItemsInInv): advertisedSet.add(data[lengthOfVarint + (32 * i):32 + lengthOfVarint + (32 * i)]) - objectsNewToMe = advertisedSet - shared.inventorySets[self.streamNumber] + objectsNewToMe = advertisedSet - shared.inventory.hashes_by_stream(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 and shared.trustedPeer == None: # inv flooding attack mitigation @@ -491,20 +470,10 @@ class receiveDataThread(threading.Thread): if self.objectHashHolderInstance.hasHash(hash): shared.inventoryLock.release() self.antiIntersectionDelay() - elif hash in shared.inventory: - objectType, streamNumber, payload, expiresTime, tag = shared.inventory[hash] - shared.inventoryLock.release() - self.sendObject(payload) else: 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) + if hash in shared.inventory: + self.sendObject(shared.inventory[hash].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,)) diff --git a/src/class_singleCleaner.py b/src/class_singleCleaner.py index f9e87b1a..3467da96 100644 --- a/src/class_singleCleaner.py +++ b/src/class_singleCleaner.py @@ -46,19 +46,7 @@ class singleCleaner(threading.Thread, StoppableThread): while shared.shutdown == 0: shared.UISignalQueue.put(( 'updateStatusBar', 'Doing housekeeping (Flushing inventory in memory to disk...)')) - 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.inventory.flush() shared.UISignalQueue.put(('updateStatusBar', '')) shared.broadcastToSendDataQueues(( @@ -70,9 +58,7 @@ class singleCleaner(threading.Thread, StoppableThread): shared.UISignalQueue.queue.clear() if timeWeLastClearedInventoryAndPubkeysTables < int(time.time()) - 7380: timeWeLastClearedInventoryAndPubkeysTables = int(time.time()) - sqlExecute( - '''DELETE FROM inventory WHERE expirestime t] + hashes += (payload for payload, in sqlQuery('SELECT hash FROM inventory WHERE streamnumber=? AND expirestime>?', stream, t)) + return hashes + + def flush(self): + with inventoryLock: # If you use both the inventoryLock and the sqlLock, always use the inventoryLock OUTSIDE of the sqlLock. + with SqlBulkExecute() as sql: + for hash, value in self._inventory.items(): + sql.execute('INSERT INTO inventory VALUES (?, ?, ?, ?, ?, ?)', hash, *value) + self._inventory.clear() + + def clean(self): + with inventoryLock: + sqlExecute('DELETE FROM inventory WHERE expirestime -1: @@ -417,8 +494,8 @@ def doCleanShutdown(): UISignalQueue.put(( 'updateStatusBar', 'Flushing inventory in memory out to disk. This should normally only take a second...')) - flushInventory() - + 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 shutdown == 1: @@ -452,15 +529,6 @@ 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: @@ -703,14 +771,9 @@ def _checkAndShareUndefinedObjectWithPeers(data): 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] = ( objectType, streamNumber, data, embeddedTime,'') - inventorySets[streamNumber].add(inventoryHash) inventoryLock.release() logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -735,15 +798,10 @@ def _checkAndShareMsgWithPeers(data): 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] = ( objectType, streamNumber, data, embeddedTime,'') - inventorySets[streamNumber].add(inventoryHash) inventoryLock.release() logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -776,15 +834,10 @@ def _checkAndShareGetpubkeyWithPeers(data): 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] = ( 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' % inventoryHash.encode('hex')) @@ -820,14 +873,9 @@ def _checkAndSharePubkeyWithPeers(data): 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] = ( 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' % inventoryHash.encode('hex')) @@ -864,15 +912,10 @@ def _checkAndShareBroadcastWithPeers(data): 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] = ( 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' % inventoryHash.encode('hex')) -- 2.45.1 From 491579c3680281ee6be2b87a850375a2c5bffbca Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 23 Mar 2016 10:15:31 +0100 Subject: [PATCH 0341/1102] Translations update source files --- src/translations/bitmessage_ar.qm | Bin 42268 -> 40538 bytes src/translations/bitmessage_ar.ts | 636 +++++++++++++---------- src/translations/bitmessage_cs.qm | Bin 58855 -> 56716 bytes src/translations/bitmessage_cs.ts | 515 +++++++++--------- src/translations/bitmessage_de.qm | Bin 70557 -> 68129 bytes src/translations/bitmessage_de.ts | 494 ++++++++++-------- src/translations/bitmessage_en_pirate.qm | Bin 17029 -> 16943 bytes src/translations/bitmessage_en_pirate.ts | 569 +++++++++----------- src/translations/bitmessage_eo.qm | Bin 35103 -> 33666 bytes src/translations/bitmessage_eo.ts | 536 ++++++++++--------- src/translations/bitmessage_fr.qm | Bin 42212 -> 40335 bytes src/translations/bitmessage_fr.ts | 539 ++++++++++--------- src/translations/bitmessage_ja.qm | Bin 36035 -> 34722 bytes src/translations/bitmessage_ja.ts | 533 ++++++++++--------- src/translations/bitmessage_nl.qm | Bin 9241 -> 8651 bytes src/translations/bitmessage_nl.ts | 554 +++++++++----------- src/translations/bitmessage_no.qm | Bin 56716 -> 54889 bytes src/translations/bitmessage_no.ts | 527 +++++++++---------- src/translations/bitmessage_ru.qm | Bin 52407 -> 50648 bytes src/translations/bitmessage_ru.ts | 533 ++++++++++--------- src/translations/bitmessage_zh_cn.qm | Bin 36289 -> 35054 bytes src/translations/bitmessage_zh_cn.ts | 527 +++++++++---------- 22 files changed, 3001 insertions(+), 2962 deletions(-) diff --git a/src/translations/bitmessage_ar.qm b/src/translations/bitmessage_ar.qm index d35714c22d74ed8bb7d553b32c2e48987065f1ba..77ec5d7fc511ad99b10bff05a9a1d92f0190c132 100644 GIT binary patch delta 2107 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 GL;nGun?^DK diff --git a/src/translations/bitmessage_ar.ts b/src/translations/bitmessage_ar.ts index de97c3d5..ce6b83f7 100644 --- a/src/translations/bitmessage_ar.ts +++ b/src/translations/bitmessage_ar.ts @@ -18,43 +18,139 @@
+ + 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 desiged 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 - + Bitmessage Bitmessage - + To إلى - + From من - + Subject الموضوع - + Received تاريخ الإستلام @@ -74,7 +170,7 @@ الرسالة: - + Subject: الموضوع: @@ -84,12 +180,12 @@ إرسال لشخص أو عدة أشخاص - + To: إلى: - + From: من: @@ -99,7 +195,7 @@ إرسال لجميع المتابعين - + Send إرسال @@ -119,7 +215,7 @@ البريد المرسل - + New جديد @@ -129,7 +225,7 @@ إسم مستعار خاص - غير مرئي للآخرين - + Address العنوان @@ -154,7 +250,7 @@ هنا يمكن التسجيل لمتابعة مشاركات الآخرين، الرسائل ستظهر في البريد الوارد، و العناوين هنا تبطل العناوين في القائمة السوداء. - + Add new Subscription إدخال إشتراك جديدة @@ -164,7 +260,7 @@ إسم مستعار - + Subscriptions الإشتراكات @@ -176,12 +272,12 @@ Add new entry - إضافة جهة اتصال جديدة + إضافة جهة اتصال جديدة Name or Label - إسم مستعار + إسم مستعار @@ -191,17 +287,17 @@ 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 - القائمة السوداء + القائمة السوداء @@ -241,20 +337,20 @@ Inventory lookups per second: 0 - معدل البحث ضمن المخزن لكل ثانية: 0 + معدل البحث ضمن المخزن لكل ثانية: 0 - + Network Status حالة الشبكة - + File ملف - + Settings الضبط @@ -269,84 +365,84 @@ هاشتاق - + Help مساعدة - + Import keys إدراج المفاتيح - + Manage keys إدارة المفاتيح - + Quit الخروج - + About عن - + Regenerate deterministic addresses إعادة إنتاج عناوين حتمية - غير عشوائية - + Delete all trashed messages حذف سلة المهملات Total Connections: %1 - إجمالي الروابط %1 + إجمالي الروابط %1 - + Not Connected غير متصل - + Connected متصل - + Show Bitmessage إظهار Bitmessage - + Subscribe إشتراك Processed %1 person-to-person messages. - تم معالجة %1 من رسالة - شخص إلى شخص + تم معالجة %1 من رسالة - شخص إلى شخص Processed %1 broadcast messages. - تم معالجة %1 من رسائل البث + تم معالجة %1 من رسائل البث Processed %1 public keys. - تم معالجة %1 من المفاتيح العامة + تم معالجة %1 من المفاتيح العامة Since startup on %1 - منذ بداية التشغيل في %1 + منذ بداية التشغيل في %1 @@ -354,42 +450,42 @@ بانتظار مفتاح التشفير، سيتم طلبه مرة أخرى قريباً - + 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. تم تجازو الصعوبة قصراً، ستبدأ الإرسال قريباً @@ -399,12 +495,12 @@ تم إرسال الرسالة، بانتظار إشعار الإستلام، تم الإرسال في %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. @@ -413,12 +509,12 @@ 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. 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.) @@ -427,42 +523,42 @@ It is important that you back up this file. Would you like to open the file now? مهم جداً أن تحتفظ بنسخة إضافية من هذا الملف. هل ترغب بفتح الملف الآن؟ تأكد من إغلاق البرنامج Bitmessage قبل تعديل الملف. - + 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 أرسل رسالة لهذا العنوان @@ -472,62 +568,62 @@ It is important that you back up this file. Would you like to open the file now? أرسل رسالة لهذه المجموعة - + Set avatar... تغيير الصورة الرمزية - + Add New Address إضافة جهة إتصال - + Delete حذف - + Copy destination address to clipboard نسخ عنوان المرسل إليه إلى الحافظة - + Force send إرسال قصري - + Are you sure you want to delete all trashed messages? هل أنت متأكد من رغبتك في حذف كل الرسائل من سلة المهملات؟ - + You must type your passphrase. If you don't have one then this is not the form for you. يجب إدخال عبارة المرور، إن لم تكن لديك عبارة مرور، إذاً هذه ليست الطريقة المناسبة لك - + Delete trash? حذف سلة المهملات؟ - + Open keys.dat? فتح ملف keys.dat؟ - + bad passphrase عبارة المرور غير جيدة - + Restart إعادة تشغيل - + You must restart Bitmessage for the port number change to take effect. لتفعيل تغيير رقم نقطة العبور (port) يجب عليك إعادة تشغيل برنامج Bitmessage. @@ -539,75 +635,75 @@ It is important that you back up this file. Would you like to open the file now? Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - خطأ: لا يمكنك إضافة نفس العنوان مرتين إلى القائمة، يمكنك إعادة تسمية العنوان. + خطأ: لا يمكنك إضافة نفس العنوان مرتين إلى القائمة، يمكنك إعادة تسمية العنوان. - + The address you entered was invalid. Ignoring it. العنوان الذي أدخلته غير صالح، سيتم تجاهله. - + 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. تم إضافة جهة الاتصال لدفتر العناوين، يمكنك تعديل الإسم المستعار إذا أحببت. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. خطأ: لا يمكنك إضافة نفس العنوان إلى دفتر العناوين مرتين، يمكنك إعادة تسمية العنوان. - + Moved items to trash. تم نقل المادة لسلة المهملات. - + No addresses selected. لم يتم اختيار عناوين @@ -617,82 +713,82 @@ It is important that you back up this file. Would you like to open the file now? 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-'' العنوان يجب أن يبدأ ب "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. بعض البيانات المشفرة ضمن العنوان طويلة جداً. - + Address is valid. العنوان صحيح - + You are using TCP port %1. (This can be changed in the settings). أنت تستخدم نقطة عبور TCP %1 - يمكنك تغييره في قائمة الضبط. - + Error: Bitmessage addresses start with BM- Please check %1 خطأ: عناوين ال Bitmessage تبدأ ب BM-، يرجى فحص %1 - + Error: The address %1 contains invalid characters. Please check it. خطأ: العنوان %1 يحتوي على حروف غير صالحة، يرجى فحصه. - + 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. خطأ: يجب اختيار عنوان للإرسال منه، إن لم يكن لديك واحد إذهب إلى تبويب "هوياتك". @@ -707,37 +803,37 @@ It is important that you back up this file. Would you like to open the file now? خطأ: عنوان من العناوين المرسل إليها، %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'. أنقر يميناً على واحد أو أكثر من جهات الاتصال في دفتر العناوين و اختر "إرسال رسالة لهذا العنوان". @@ -747,22 +843,22 @@ It is important that you back up this file. Would you like to open the file now? خطأ: لا يمكنك إضافة نفس العنوان إلى الإشتراكات مرتين، يمكنك إعادة تسمية العنوان. - + 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 تم فقد الاتصال @@ -851,122 +947,122 @@ There is no required difficulty for version 2 addresses like this. 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. خطأ كتابة. @@ -976,152 +1072,132 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2.تم تعطيل الخيارات لأنه إما أنها غير قابلة للتطبيق أو لم يتم برمجتها لنظام التشغيل الخاص بك. - + Testing... اختبار... - + This is a chan address. You cannot use it as a pseudo-mailing list. هذا عنوان الزمرة، لا يمكنك إستخدامه كقائمة بريدية مستعاره. - + Search بحث - + All الكل - + Message الرسالة - + Fetch Namecoin ID إحضار هوية namecoin Stream # - المجرى # + المجرى # Connections - الروابط + الروابط - + Ctrl+Q Ctrl+Q - + F1 F1 - + Join / Create chan إنضمام / تكوين زمرة - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Waiting for their encryption key. Will request it again soon. - + Message sent. Waiting for acknowledgement. Sent at %1 - + Channel - + 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. - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Inventory lookups per second: %1 - - - - + 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 @@ -1129,181 +1205,181 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2. - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + 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 - + 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. - + Undeleted item. - + 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. - + 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. - + Display the %1 recent broadcasts from this address. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1312,80 +1388,50 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support + + + All accounts + + + + + Zoom level %1% + + MainWindows @@ -1719,6 +1765,64 @@ 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 + معدل البحث ضمن المخزن لكل ثانية: 0 + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Objects to be synced: + + + + + Stream # + المجرى # + + + + Connections + الروابط + + newChanDialog diff --git a/src/translations/bitmessage_cs.qm b/src/translations/bitmessage_cs.qm index 06170de01d5476f3236a4640d2a6441f6ab3a360..fe3ca8e9782c0318ba64a3f3afd3cfcc89724f14 100644 GIT binary patch delta 2484 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 BLHPgx diff --git a/src/translations/bitmessage_cs.ts b/src/translations/bitmessage_cs.ts index a925d7a1..cadbd648 100755 --- a/src/translations/bitmessage_cs.ts +++ b/src/translations/bitmessage_cs.ts @@ -59,12 +59,12 @@ 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: @@ -130,7 +130,7 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + 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? @@ -140,177 +140,177 @@ Please type the desiged email address (including @mailchuck.com) below: 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 + Přidat novou položku Since startup on %1 - Od spuštění v %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 @@ -320,17 +320,17 @@ Please type the desiged email address (including @mailchuck.com) below: 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. @@ -339,17 +339,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.) @@ -358,202 +358,202 @@ 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. - + 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. + Zpracováno %1 osobních zpráv. Processed %1 broadcast messages. - Zpracováno %1 hromadných zpráv. + Zpracováno %1 hromadných zpráv. Processed %1 public keys. - Zpracováno %1 veřejných klíčů. + Zpracováno %1 veřejných klíčů. Total Connections: %1 - Celkový počet připojení: %1 + Celkový počet připojení: %1 - + Connection lost Připojení ztraceno - + Connected Připojeno - + Message trashed Zpráva byla vyhozena do koše - + 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: 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. - + 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. @@ -563,27 +563,27 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Práce je zařazena ve frontě. %1 - + New Message Nová zpráva - + From Od - + 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. @@ -593,177 +593,177 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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). 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. + Chyba: Nemůžete na listinu přidat adresu, která tam již je. Můžete ale tu existující přejmenovat. - + 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í. - + Moved items to trash. Položky byly přesunuty do koše. - + Save As... Uložit jako... - + Write error. Chyba zápisu. - + No addresses selected. Není vybrána žádná adresa. - + 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á. - + 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 - + Search Hledej - + All Vše - + To Komu - + From Od - + Subject Předmět - + Message Zpráva - + Received Doručeno @@ -778,7 +778,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Vybrat z adresáře - + Fetch Namecoin ID Načíst Namecoin ID @@ -788,7 +788,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Zpráva: - + Subject: Předmět: @@ -798,12 +798,12 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Poslat jednomu nebo více konkrétním lidem - + To: Komu: - + From: Od: @@ -833,7 +833,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Popiska (nikomu se neukazuje) - + Address Adresa @@ -853,7 +853,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 @@ -863,7 +863,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Popiska - + Subscriptions Odběry @@ -875,32 +875,32 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Name or Label - Jméno nebo popiska + 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ě) + 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ě) + Použít bílou listinu (blokovat všechny příchozí zprávy kromě těch od adres na bílé listině) Blacklist - Černá listina + Černá listina Stream # - Číslo proudu + Číslo proudu Connections - Připojení + Připojení @@ -928,192 +928,192 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 - + 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 - + Set avatar... Nastavit avatar... - + 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. Inventory lookups per second: %1 - Počet kontrol inventáře za sekundu: %1 + Počet kontrol inventáře za sekundu: %1 - + 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. - + 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. - + 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. - + Display the %1 recent broadcast from this address. Zobrazit %1 zprávu nedávno rozeslanou z této adresy. - + Display the %1 recent broadcasts from this address. Zobrazit %1 zpráv nedávno rozeslaných z této adresy. Inventory lookups per second: 0 - Počet kontrol inventáře za sekundu: 0 + Počet kontrol inventáře za sekundu: 0 Down: %1/s Total: %2 - Stahování: %1/s Celkem: %2 + Stahování: %1/s Celkem: %2 Up: %1/s Total: %2 - Odesílání: %1/s Celkem: %2 + Odesílání: %1/s Celkem: %2 - + 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: 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á. - + Number needed Je třeba zadat číslo - + 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. - + Some data encoded in the address is malformed. Některá data zakódovaná v této adrese mají neplatný formát. @@ -1133,65 +1133,60 @@ p, li { white-space: pre-wrap; } Down: 0 KB/s - Stahování: 0 KB/s + Stahování: 0 KB/s Up: 0 KB/s - Odesílání: 0 KB/s + Odesílání: 0 KB/s - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - + 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 @@ -1199,91 +1194,91 @@ p, li { white-space: pre-wrap; } - + 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. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1292,67 +1287,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - + Contact support @@ -1630,6 +1595,64 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Ú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. + + networkstatus + + + Total connections: + + + + + Since startup: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Inventory lookups per second: 0 + Počet kontrol inventáře za sekundu: 0 + + + + Down: 0 KB/s + Stahování: 0 KB/s + + + + Up: 0 KB/s + Odesílání: 0 KB/s + + + + Objects to be synced: + + + + + Stream # + Číslo proudu + + + + Connections + Připojení + + newChanDialog diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index dfe5c804b9e1d80210c241045aa1a19c5445e10c..0e85dff8922e72f4adb46764142fa1bbe3f60dcc 100644 GIT binary patch delta 2926 zcmZ8jdt6L;8~>g;=ggd$bLLF9&Ekz#3+x6g$Ae6!7^Gn9&BzA4dCeK$s`cX$kJmAi%u>Tx}rWVFs?n zfoy8GE&K%h4i1>hfzP7*fs??W%m<#ohw?Z}-%o(bZxUeWJO%ZnOTbJ^m`-{L>~Dfi z^?Sh84j=cSq{1UHa!)o8{Tj|Si9pUdxb>oB+|n_5-wi;@>9)tK;nhS*TNPva-shBv z8>a8mkX?cq;cJ2V;rKl6G8LQIZ4cSPFDV=bG^fCSDP4H#hB@clfj-5U7wrmkL?S?$ zMAjWE-jSnHXRPT*6)f0|_(S#t+Mif=!~lHghA$&Cfrp7mkLw4VK8oC>X23ijlz$%t z3{S+p>xG1*8|wOo6VjdND5U}-+8A|CJ2|k)XZrWyfN2AnA(9OxXvd5UZU#V3rRP_Ljc8IFN}PLx=^}GTQ>} zfz3OaJs(s8OUE$#Pf?+-9x%oEL_y#)=8B`?IH0&oKgbS_WZu*hLSZ|ZPQ^q(`yYjJ zFIBX7hT`LKe*oUHVt73vFiWFwh}{IlTvNE!Zv>{AD#AQo5rSokvvt2k9jlJLrG_-RQ^@MoFMguqHb~}w-Gv{kX+$e`|p{MO> zJfgV>kq{~HcLg7nZKQxj{DzT~SWP*fxPcOB z9m1!Np@7@G`OKGeucD6Mzm@z4TJT4@=6=muzHl2)WBPq~2c$2Goa31za#oUhzY z;x^Iuw`H10A7 zvezpwba7h%-;FOC)O&nWE#`i=Ty!bs`Qdli9g zQI%qu2VC$~o!Ie^<}bM0>dtoC+{dbtQB-L=tGeSC1PGm~$9kf~##;4y&{bfIwJ`d) z4IsW1T$C?>mgmB3cVDvZ!rZHAgy0?_c9K2m%Y9*8C=jzyWCKHX z2_2hO5`xyk+d8tt{#08$noV!UVRhf5qzf&HYTH|snD;*Q$n4 zOk4qtPCX5sK->s*w4MUG|E*3n;eepu)S17IqGlYf&N@%`iVD>^pVGa8W9sj6XOOmc zs+)Y?5*0f&;!0{dv}w#kD*@I~Gk|Fz0n69eCK6I7eKmgDPEsL^CM1&z)h^J4woC(> z9%u|&i6wzFBt+Fd2 zTg~+iMoO?sb7u>2?U}A={U(6~twUs{7n0;cRL4_K*(Qq`whHi16hF+2q~@*?ZQHMs zfDJH+L#_l7gzrVYHwi@M>26!zDbDI7YMNrj?Q0V$&@wUk`+Jl?hnQJCk;ckL%u+ki z7>*HdZlI=H*Gs(lpetaNcsD~2{M=uxjc=o-dnewTvKKI`5bJZP$uF3QEoOrW5slbl zP1E+fAyjhcYN~~cB@a77AS*zcvp#~j{!R*cwSdN`S_<8l4J27e5vL|lW#-ZfuLHp2 zGHH8hGC9nX(#G{6DLpTxE%XM`Q>5c@gwV8X>C9M}gz2VqrmJ_BUzaXM5$6ZJrD7(U zbYxJsHMAa)u2@jUrLj_3$}t){jdUlR)_EmTm5wTynJ3l0vZ8=G>HfNEdX96X*FKbx zLyh#hn$8_BYK2GVsEM7l@@KRjF<#qu8F8OdrM1nVKwkFR;i(0{;aIKbTrX-qOYMSV z8C3ZxZA3=`&HqqVC3RdG|9q zkD4lHoF!_R1UYBEi-DBrikxdr83)_T6iKr>>wzn6{ z^&v#r$7S-fSp%sOQ8!``QJ~(X8yOixe?**gqiz!9^^0^<&nJ)&4baWVcLx&Z=;nQU z75KJM7o7PONqU*C;I`{~;Lc55;bfWqNEmb%`)32=Cg_S+x6xm&-nx@}^~KT=sRts)_WWX2j7!fg aeVkLzt&cYQ^xUfadUTI1qx$DG&wl_}*q1f{ delta 3971 zcmb7G2~<qwjdt%3m}0b-&gihvrcwRIMKYLy~I zi>PQ(Or3E8Z50)9!eZ50t5*Ha16r2DKY?od+y1}SU#xK6efOSepMB1KYnHLA*R$D; zY%2k@2Tq*<*d;&@lH3*`V=vIxA83>c4F8^fgMp9R(EF=^Ap(rV3v5+Opl1!(nlV7H z=3wszk<4$9do#c-U;*7!aJdnHejm8a1wfquqK!h*{|Mr!-e7E!5=eXRCI?gC-1`Zz zF$m5jOM$87@HzV$=-w4=y($4qHG-Gq0iT4SbM-9Xn^)-OaUTd>hdwI~1B(0xxw8rS z-5Lfo8-&Q^4=JF&h+H8fX~m$FOyG8V44qO+N$1o{8@8AbH7^BtvI5b`bl_ zU`?_M5Pt#{2V#Lh8BVJg07Hv#vAmd&U5?95Qb@5%h}t8R$)qSon*S7Nk;ydoVu8Uy zjGw{>SZ`&5$KC<<3}-q_CkM|rG9k`nK<~r!9NihP9%Z!EblykAj2*cau=i);p#nzi zU<@xwFUEs0btUAIhcI);1OQ9VGfUhmfwVQum*3bZ8^P982qj(Si%p%7Mp+1Q%60ASGCE`M4*QteM~@YXP==FSxhD18_YfR4m}Y zAW5h^y^SDlDpb!t3v7)Nx^DZ05W6eXrk_Y?iR%3tC5B z6IP1#fak*oxvQz^1>V z66Jr+PARAaTDq`vI#Fq&kFlE;Gk~u@ySX(5mbI1L?7xoIW7sXTqN(j|@3HpWMu6=S zd+2U!;C@&3a7IfiK|i+Ig^-v!hGTvVpmw^=b$&>*V#rahYX!Ac`4TR~AOuXOx$vi2 zK=UIv;OaTx{S#d5^zB5pD_mkUl}2}qGw0dKVKz4-m;(E$lAASy0;%=qR(2(SwiQdc zoF{bf{LkE%bI5^y0ar)^0<+4v;<+3-p2mGUg4VrGa(j{}5aWkj<@^*1bT?O(-vMyG z%>58e=bU?RwL;1`avt|Q!kJ2SLgbu6c7H1rjZMn~_C6LRy(Z{SO%shDX96-$iOlDN zVS{IuXi_#oTB{SynM?<|EEeVVzX3*6B`Uad3K(@jRHWHYegB=vzQ`5WbVRh%QRAI` zMdymBzn@MNU5=u_9=8y?WK%njbP{)#QKne41_clug&-rXnIGyX~8elr(+wWld3^(2^5!g%mZGD#Z^(UfaHz%S1pyur&j#D zB_+fgB%L3XH!b+2%q9564JKV|oGuswJg+L#g&1Bo!MDQ~UZ#j@z06Dy`(= zDw3UENv>ax1-h-3+_Tl?0d3qQwKFFYvHbpvE6SIO>%+YR!(L^iccDDde$S#f9`&7~^YZuwL4+eWrK_X!Qm zEZM$f+KCCW_Cm23Oc_*nnEL7o%JhrFQ*J<5_N zWKl&jCGz>1vw-od<=F==Qed(2oU^^C>0;!$QfeYyiTvmc;^dq-`O#~|Ho9%Q$}g
}4!8Z&o+R+9Jii zMih8umg2jm8>l-~imDV^m&g>S)%WSH;uJN{yvd=f;>WDBbgLIAo)4#hg2yPHpQZhd zVM>YZ=5`|YRHf=8dJ%L~*~ECANbjliT}6%}LzM0KB4FDAWyHvS#6@>y+=f+zK#4N7 zb~>Jd!oF)IG##yN%`Ue=?lD-zZrS}yRuX`NPeoU zDoJB4HSuUaCqOWO0S6MmrNIa%qs&DXOc9 zu|T^>o9e-k7L<`%9oW(fkS?TqoKJ}xx$2^muYsBq>f$~s`X2dSy{ma1b>$%SUh92ehE84PMsl*hy7C;|O)-nr zH@e@T&yVZsx`m`)D|(PjH`{f-bd%OTN0y}GgBr{DicLNE?SW4A2aSJHws1i>jL;zg zsU(wOfmPzjP((jzxKWpoYE0&tRCjx&ZzmDcm@n~n;}Z`x}n37_7=TXD^mo;13%ANoDkf|O7@v!q8pSZb$N~zV2*K5pant{4_ zz0nba{ZfoO$Lq?H9S52Id_q}-Q$uR+%n=@CZu}cxcl+Zp5{`>-RzHY32mI#iCE7EH&|IW?f=}&SKS!r+2y}y@g-n?Z!pbtMw`G{#H%d>d$KY*7D|j zp|_K`Z#}FU{^3?P{-A+fdbrVB1y9dED`+N6iZ>=FXj1hV^$z&UWyATprcQiB`Fw{V z{#v=&A?x-#DPbyzJJ)7u_qsU3Lr^EQaAmKVJ z*_5EySgg7<>!b<%OJ6TO@$d)r5Wh&>BOvBH^z-1$4twy+$GF(PHMLPN9qP%X-Xr2A zM_k|ki#@k`I%s;CO(uPUHQ8*kgb>aiOu(O%8q8nGe9C;}M=UfGi4DJV>@EBLJNH~i zO!#N!X^*sbFwgbeA0(^K*a!=s?dic6cW<}VS I9LbLOH?%~ZH~;_u diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index f6065b4e..2e9611cd 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -59,12 +59,12 @@ EmailGatewayRegistrationDialog - + Registration failed: Registrierung fehlgeschlagen: - + The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: Die gewünschte E-Mailaddresse ist nicht verfügbar, bitte probieren Sie eine neue. Die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten ausfüllen: @@ -131,7 +131,7 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: MainWindow - + 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? @@ -141,167 +141,167 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Antworten - + Add sender to your Address Book Absender zum Adressbuch hinzufügen - + Move to Trash In den Papierkorb verschieben - + View HTML code as formatted text HTML als formatierten Text anzeigen - + Save message as... Nachricht speichern unter... - + New Neu - + Enable Aktivieren - + Disable Deaktivieren - + Copy address to clipboard Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + 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 Add new entry - Neuen Eintrag erstellen + Neuen Eintrag erstellen - + Waiting for their encryption key. Will request it again soon. Warte auf den Verschlüsselungscode. Wird bald erneut angefordert. - + Encryption key request queued. Verschlüsselungscode-Anforderung steht aus. - + Queued. In Warteschlange. - + Message sent. Waiting for acknowledgement. Sent at %1 Nachricht gesendet. Warte 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 + Seit Start der Anwendung am %1 - + Not Connected Nicht verbunden - + Show Bitmessage Bitmessage anzeigen - + Send Senden - + Subscribe Abonnieren @@ -311,17 +311,17 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: 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. @@ -330,17 +330,17 @@ It is important that you back up this file. 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.) @@ -350,97 +350,97 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn (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. + %1 Person-zu-Person-Nachrichten bearbeitet. Processed %1 broadcast messages. - %1 Rundruf-Nachrichten bearbeitet. + %1 Rundruf-Nachrichten bearbeitet. Processed %1 public keys. - %1 öffentliche Schlüssel bearbeitet. + %1 öffentliche Schlüssel bearbeitet. Total Connections: %1 - Verbindungen insgesamt: %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". @@ -455,32 +455,32 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. @@ -490,7 +490,7 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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". @@ -500,27 +500,27 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. @@ -530,12 +530,12 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. @@ -547,75 +547,75 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. + 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? 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. Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - + Moved items to trash. Objekt in den Papierkorb verschoben. - + Save As... Speichern unter... - + Write error. Fehler beim speichern. - + No addresses selected. Keine Adresse ausgewählt. @@ -626,62 +626,62 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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 @@ -701,7 +701,7 @@ Optionen wurden deaktiviert, da sie für Ihr Betriebssystem nicht relevant, oder Nachricht: - + Subject: Betreff: @@ -724,12 +724,12 @@ p, li { white-space: pre-wrap; } <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: @@ -759,7 +759,7 @@ p, li { white-space: pre-wrap; } Bezeichnung (wird niemandem gezeigt) - + Address Adresse @@ -779,7 +779,7 @@ p, li { white-space: pre-wrap; } 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). - + Add new Subscription Neues Abonnement anlegen @@ -789,7 +789,7 @@ p, li { white-space: pre-wrap; } Bezeichnung - + Subscriptions Abonnements @@ -801,32 +801,32 @@ p, li { white-space: pre-wrap; } Name or Label - Name oder Bezeichnung + Name oder Bezeichnung 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) + 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) + Liste als Whitelist verwenden (Erlaubt keine eingehenden Nachrichten, außer von Adressen auf der Whitelist) Blacklist - Blacklist + Blacklist Stream # - Datenstrom # + Datenstrom # Connections - Verbindungen + Verbindungen @@ -854,147 +854,147 @@ p, li { white-space: pre-wrap; } 0 Rundrufe verarbeitet. - + Network Status Netzwerkstatus - + 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 @@ -1024,187 +1024,187 @@ p, li { white-space: pre-wrap; } Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - + Mark Unread Als ungelesen markieren - + Fetched address from namecoin identity. Adresse aus Namecoin Identität geholt. - + Testing... teste... - + Fetch Namecoin ID Hole Namecoin ID - + Ctrl+Q Strg+Q - + F1 F1 - + Set avatar... Avatar wählen... - + Bad address version number Falsche Addressenversionnummer - + Your address version number must be a number: either 3 or 4. Die Addressenversionnummer muss eine Zahl sein, entweder 3 oder 4. - + Your address version number must be either 3 or 4. Die Addressenversionnnummer muss entweder 3 oder 4 sein. Inventory lookups per second: %1 - Inventory lookups pro Sekunde: %1 + Inventory lookups pro Sekunde: %1 - + 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 als die, die Bitmessage auf das erste Wiederversenden wartet. Deswegen werden Ihre Nachrichten nie wiederversendet. - + 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. - + Enter an address above. Eine Addresse oben ausfüllen. - + Address is an old type. We cannot display its past broadcasts. Alter Addressentyp. Wir können deren vorige Rundruf-Nachrichten nicht anzeigen. - + 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 - Inventory lookups pro Sekunde: 0 + Inventory lookups pro Sekunde: 0 - + Reply to sender Dem Absender Antworten - + Reply to channel Antworten ins Chan - + Add sender to your Blacklist Absender in die Blacklist eintragen - + Undelete Wiederherstellen - + Email gateway E-Mail Schnittstelle - + 1 hour 1 Stunde - + %1 hours %1 Stunden - + %1 days %1 Tage - + Channel Chan Objects to be synced: %1 - Zu synchronisierende Objektanzahl: %1 + Zu synchronisierende Objektanzahl: %1 Down: %1/s Total: %2 - Herunter: %1/s Insg.: %2 + Herunter: %1/s Insg.: %2 Up: %1/s Total: %2 - Hoch: %1/s Insg.: %2 + Hoch: %1/s Insg.: %2 - + 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 @@ -1212,77 +1212,77 @@ p, li { white-space: pre-wrap; } - + 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. - + 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. - + Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. Nachricht befindet sich in der Warteschleife. - + Sending email gateway registration request E-Mailschnittstelle-Registrierungsantrag wird versandt. - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. Fehler: Dieselbe Addresse kann nicht doppelt in die Abonnements eingetragen werden. Alternativ können Sie die bestehende umbenennen. - + Number needed Zahl erforderlich - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request E-Mailschnittestelle-Abmeldeantrag wird versandt - + Sending email gateway status request E-Mailschnittstelle Statusantrag wird versandt - + 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. Alternativ können Sie die bestehende umbenennen. - + Undeleted item. Nachricht wiederhergestellt. - + 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? @@ -1291,7 +1291,7 @@ Are you sure you want to delete the subscription? 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? @@ -1300,37 +1300,37 @@ Are you sure you want to delete the channel? Sind Sie sicher, dass Sie das Chan löschen möchten? - + Some data encoded in the address is malformed. - + Identities Identitäten - + New Identity Neue Identität - + Messages Nachrichten - + Address book Addressbuch - + Add Contact Kontakt hinzufügen - + <!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; } @@ -1339,77 +1339,77 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message Ordentliche Nachricht senden - + Send Message to your Subscribers Nachricht an Abonnenten senden - + TTL: - + X days X Tage - + Chans Chans - + Add Chan Chan hinzufügen Total connections: - Verbindungen insgesamt: + Verbindungen insgesamt: Since startup: - Seit Start: + Seit Start: Objects to be synced: - Zu synchronisierende Objektanzahl: + Zu synchronisierende Objektanzahl: Processed 0 person-to-person messages. - 0 Person-zu-Person-Nachrichten verarbeitet. + 0 Person-zu-Person-Nachrichten verarbeitet. Processed 0 public keys. - 0 öffentliche Schlüssel verarbeitet. + 0 öffentliche Schlüssel verarbeitet. Processed 0 broadcasts. - 0 Rundrufe verarbeitet. + 0 Rundrufe verarbeitet. Down: 0 KB/s - Herunter: 0 KB/s + Herunter: 0 KB/s Up: 0 KB/s - Hoch: 0 KB/s + Hoch: 0 KB/s - + Contact support Unterstütung anfordern @@ -1692,6 +1692,64 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Sie haben Verbindungen mit anderen Netzwerkteilnehmern und Ihre Firewall ist richtig konfiguriert. + + 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 + + + + Down: 0 KB/s + Herunter: 0 KB/s + + + + Up: 0 KB/s + Hoch: 0 KB/s + + + + Objects to be synced: + Zu synchronisierende Objektanzahl: + + + + Stream # + Datenstrom # + + + + Connections + Verbindungen + + newChanDialog diff --git a/src/translations/bitmessage_en_pirate.qm b/src/translations/bitmessage_en_pirate.qm index 1c33bafd281c3c444bbb0a1c6b60271ff32a87e1..18432860923466bd214912537edf9b6344b66411 100644 GIT binary patch delta 669 zcmXYve@IhN9L3MudwXyCo>Q0BbhhS}<}`IKXB#ywO%jPgA(kOzrJyn%(Z)DVAm?< zJD&l0i;7QNE1>Th!78WV>0X%K$iXIOpUpI$z3_xkiA*5w7h| z86b{xV|@$-jVc{8-)TUDvgb?#U>Q^nILv^;tsGivg%_ER`MTpbD4~fz5u^Z?Iet>0 zgK2;H*P|Mm=%!E|?4-##;oP1S!0Hjkdf$_A)qhUQ)OHBdHu5QIP}%t(O3d)~RWDUh8rxV;!Yxl?o8Q@}>hm%)K8vnOs#5b@ zW=4v*ca@Ct`oy6KO_*6I&JVhPtdHWt$#0}Dl6Gt+eNwU1aFzU6qtsuLO3i(h`j1os z3DeU3mZQMh-O?08%`#O)FZ~pxOD~(rDAgRNbAO=fw#DU!Mgd(k?ofD;s(zrxQ@X&& zt1F@uDC>fH_PPVmN7Qrq)CeF`Yf>+`x+y?d=BCnk+Y3FAlN`Tt$w&9pHqnE+!;-*= dov5eJ5UOEqp;?75bU?Q;w9F<XPdfFIzQ4$>a6^BZImCRhKLOkQHr3IT1{lrB&Lxr<`!gD zi<#((2)igJ;e{858H5&;Nd;E2iy$ZpBCN0$1jAl9UH#5E|MNc2^FHUy_?X|%0(wt3 zfMURy4f(esfVm}RM8UVz0aZ_tShoS_ld=2V5U_OxO??YAb46lG99o7ufx=5@b(|$W z!V%>#U|GO9X9y@zVZ1K`$lTBJ#B3mGjFs5G0_iVU*&v;JN^H!2Xc9zwoJgIJ$2_aDD1VaCjB5DK zVL-I2uH{oO7EwjLJ;0XgxYWD9>AXJf_TEho83p1`wbNjkI==HmIiPzhF~=;}8mLO0 zPU7~H!of`vDtIr1R%yc=udp^@15Bktq<;^^@P zY9>K^;A*1)*Tsj7nq`wj4_y?y#Mhl9WN@ofyFO8M7uCChVfrMs>ZA82fE~OBkIBH; ztf`Mupu9EB%1tXZmZf=FNR0shxhOHYM-#DmDM(aeZa`c9EQ55~w0|%A$S>@mAL|!K lgT`RkP!W70^9832l|uZ1V-9Dl!`bd~2V(})Y!|mw`46;@vsC~9 diff --git a/src/translations/bitmessage_en_pirate.ts b/src/translations/bitmessage_en_pirate.ts index 55e4021f..988b6d15 100644 --- a/src/translations/bitmessage_en_pirate.ts +++ b/src/translations/bitmessage_en_pirate.ts @@ -59,12 +59,12 @@ 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: @@ -130,646 +130,616 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? - + 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 + 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 - + 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. - + 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 - + 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: 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. - + 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 - + 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. - + 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). - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - + 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. - + Moved items to trash. - + 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 - + Fetch Namecoin ID - + Subject: - + To: - + From: - + Address Address - + Add new Subscription @@ -779,252 +749,197 @@ It is important that you back up this file. Would you like to open the file now? Label - + Subscriptions - - 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 - - - - + Network Status - + File - + Settings Settings - + Help Help - + Import keys - + Manage keys - + Ctrl+Q Ctrrl+Q - + F1 - + About - + Regenerate deterministic addresses - + Delete all trashed messages - + 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. - - Inventory lookups per second: 0 - - - - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1032,121 +947,121 @@ It is important that you back up this file. Would you like to open the file now? - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1155,77 +1070,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1513,6 +1388,64 @@ T' 'Random Number' option be selected by default but deterministi + + 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 + + + newChanDialog diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index ccca8ff375699286396d18dd74ae80afd437bf00..8c48a1ef6db99c24bedca1da0f65c8dd53a4d029 100644 GIT binary patch delta 1738 zcmZ8ic~n$&7`<=ad$YZnHx1&F9)Uv8Tn5w>6eJBy5@!q-&_pDcP)JY#SzLzHQd1LD zT#!T5nanLr#}yUVl2B2zEI3(n!c){C!cF3IL0&Hb{hvTCivet{koUWQrGPGBG|_{=o6i8ho#@xS4seDQV$9ZyETYbf@vC4j zX=T7!ux~XI*I|5G0kE(J6Y@^++*U8z8UWT5jMG+d};$G6e;bqf&QBp530 z1D0Nbe|L5iR3HpW`HO7K7lvDT&XyvKN($q-48d`WeszJcb~+P{-6Irtt^gOX0aD8W7fMv?YGP;9|`HkBb%cv1=kc?*qNgYv!-X0L=X~%bHkFH>+mD zf)*g^U(K#0+5;S#U73}DPmt!vWfy?Ob(+7oc4fgv(X?J>$FoH9jYE7-5Ch7{#E7Y4 z=*@$GsZku7xtt7+5=YIb2S&dxmM4F}k?t3(Oioh2xJazsMnf-uu}(J!FdDo#;bXDB zWecEb68}nM0im75mOKWEP7)s;j|ckZNF$EL068I2>{T-5|5!>_SYZ4;DfcNmjr&u| zbJdZ-3TfX)0eGQE+TZ_k;yLNS%0y~zhU9jZ`2vx8>0*8mU~Q9b`JAW7_R3+c+e!H? zc~~vAkklj(pGztSeJjU#z9-c~<>ciQX2=D3c48JVAVtnBcQf#Pd1WCR$nPST-lKhf zp}cbqq^QS~Q#A3NkbOC|&a(j%G!+NMqSyT=r z^wy?6W5;t#v^hl-S$>?>_4760l^X5dfNI+H+G8Dz#UIdqzt@K%e4@Rbzyym!bUsBL zqb=4&j3Gnj)jE4UnXq-$E%8@@;5E7r$Gr#?eBjir`^68Kc~w_jMTd5pZr}Pw7Le>k z%~3Dfcj^9cbaZ}7*B->gaWCt`wReHMU-VO}x3Gbc`XzH5fZkVs$cO%9z5dk6D6V0Z zzIHc9Jm9wevXgm)U-b<;h&@N^pWI#ubaE~>`2IeTVi;xU@x=oM%rpdFX5e1&hOner zT)*E8Sq=tx$!aM5VF*XC%}^2f9GEcK7`&1NO+0U$(>#tExNA)F&~KN#_})R|(r^|K zRbZ@)dQ4{Gj3<=)ydQ2nQFf2&pKiQR$dNe*2PuNRlIzksiGp-T?X)E5Y}x zIitf$pVP@yy-RV7@vB}|m2cs}jKKqX4EPj7bSRGI_Q zxHhXyp$RM?^pa`HvUF}kxM}u-8QhW>)0Wq|bL}cjCxtAE@nbLMSDQ}zGC}G&(>I%T zv-7p48q00#s;MqyCLiq4YQ2Ns_Y9rtnaxgpCtHTp_yLPv zu*4l@A;Er@@vbQT4<=dO{;C?7VzX3^Q2|GQ<+y)2wK2tVGMj}&Zm^v1OdRI2Jl?R1 z+tNDqxhfWpU4Z|7*cWcC9!=^Wq p-5*pMI;Wx6b6PFWCj&b#-(XvBmo_@ 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 ue`=qv_)@)Dg;tk^yG*@FHixxq5Bn$C5b_rQ diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 84a54878..62ffb858 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -59,12 +59,12 @@ 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: @@ -130,7 +130,7 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + 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? @@ -140,167 +140,167 @@ Please type the desiged email address (including @mailchuck.com) below: Respondi - + Add sender to your Address Book Aldoni sendinton al via adresaro - + Move to Trash Movi al rubujo - + View HTML code as formatted text Montri HTML-n kiel aranĝita teksto - + Save message as... Konservi mesaĝon kiel... - + New Nova - + Enable Ŝalti - + Disable Malŝalti - + Copy address to clipboard Kopii adreson al tondejo - + Special address behavior... Speciala sinteno de adreso... - + 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 Add new entry - Aldoni novan elementon + Aldoni novan elementon - + Waiting for their encryption key. Will request it again soon. Atendante al ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. - + Encryption key request queued. Peto por ĉifroŝlosilo envicigita. - + Queued. En atendovico. - + Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 - + Need to do work to send message. Work is queued. Devas labori por sendi mesaĝon. Laboro en atendovico. - + 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 Since startup on %1 - Ekde lanĉo de la programo je %1 + Ekde lanĉo de la programo je %1 - + Not Connected Ne konektita - + Show Bitmessage Montri Bitmesaĝon - + Send Sendi - + Subscribe Aboni @@ -310,17 +310,17 @@ Please type the desiged email address (including @mailchuck.com) below: 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. @@ -329,17 +329,17 @@ It is important that you back up this file. 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.) @@ -348,97 +348,97 @@ It is important that you back up this file. Would you like to open the file now? 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. + Pritraktis %1 inter-personajn mesaĝojn. Processed %1 broadcast messages. - Pritraktis %1 elsendojn. + Pritraktis %1 elsendojn. Processed %1 public keys. - Pritraktis %1 publikajn ŝlosilojn. + Pritraktis %1 publikajn ŝlosilojn. Total Connections: %1 - Totalaj Konektoj: %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". @@ -453,32 +453,32 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. @@ -488,7 +488,7 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier Laboro en atendovico. - + Right click one or more entries in your address book and select 'Send message to this address'. @@ -498,27 +498,27 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. @@ -528,12 +528,12 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier Eraro: Vi ne povas duoble aboni la saman adreson. Provu renomi la jaman 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. @@ -543,137 +543,132 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. Movis elementojn al rubujo. - + 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 @@ -693,7 +688,7 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier Mesaĝo: - + Subject: Temo: @@ -716,12 +711,12 @@ p, li { white-space: pre-wrap; } <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: @@ -751,7 +746,7 @@ p, li { white-space: pre-wrap; } Etikdeo (ne montrita al iu ajn) - + Address Adreso @@ -771,7 +766,7 @@ p, li { white-space: pre-wrap; } Ĉi tie vi povas aboni "elsendajn mesaĝojn" elsendita de aliaj uzantoj. Adresoj ĉi tie transpasas tiujn sur la langeto "Nigara listo". - + Add new Subscription Aldoni novan Abonon @@ -781,7 +776,7 @@ p, li { white-space: pre-wrap; } Etikedo - + Subscriptions Abonoj @@ -793,32 +788,32 @@ p, li { white-space: pre-wrap; } Name or Label - Nomo aŭ Etikedo + Nomo aŭ Etikedo 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) + 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) + Uzi Blankan Liston (bloki ĉiujn alvenintajn mesaĝojn escepte tiuj en la Blanka Listo) Blacklist - Nigra Listo + Nigra Listo Stream # - Fluo # + Fluo # Connections - Konetkoj + Konetkoj @@ -846,147 +841,147 @@ p, li { white-space: pre-wrap; } 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 @@ -1016,187 +1011,162 @@ p, li { white-space: pre-wrap; } Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - + Mark Unread Marki nelegita - + Fetched address from namecoin identity. Venigis adreson de Namecoin identigo. - + Testing... Testante... - + Fetch Namecoin ID Venigu Namecoin ID - + Ctrl+Q Stir+Q - + F1 F1 - + 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 - - - - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1204,121 +1174,121 @@ p, li { white-space: pre-wrap; } - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1327,77 +1297,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1674,6 +1604,64 @@ The 'Random Number' option is selected by default but deterministic ad Vi havas konektojn al aliaj samtavolanoj kaj via fajroŝirmilo estas ĝuste agordita. + + 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 # + Fluo # + + + + Connections + Konetkoj + + newChanDialog diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 04b2666c2c3e180a22f2e862c5c5884107360c60..7d7adbd0ff6d06b36a7d953f74bb9e5539a193e1 100644 GIT binary patch delta 1597 zcmX9-c~De!9RIxC_jcdzd%I6T6g)sg6hsbDKtc@!1&_9Y94@&eoCHKlLJoyBP*LPk zkV|6J$g{}UyaK_1$}l+w#R0PzC3GA`jccZ{>}&hi=e^&1zwhVxeSSl~$ch_f`W08> z%sXDx9J_5jyCvr2^#`i~t{cD-Af=F=zX6ur2R8i-*t7tf7XfZ8*lt_E(gAFLBw&>X z_L&RefDscz!45zW$+rHA_-I1i~`}$VAK0AFuM^B`k9@8OE6rI)B+wB z@aW40qOZZfyq!e!8FAY!yjQL!f_em{H_`ejBW{_3;QRz&e>OtmGYLl#p~we{FC*iW z6EI^8yHD%MggN%?s0MPDqB7kQ*xrebmMFmVJoE!?^#EIhi62MEbStAeF$QQ%7^|7& zz&eSs6K#O7AjUQ3DUcvB%d%t_o|oJ` zIUCqhCSR$W3zQs|`$YEx-VO3jUGk?PBw%r_d?cMVtZHJVXo_&3GrRJN zA4PVZ_0^pNLfhCxfrP~Sv1$L1lb}HMLNP;0-C)03{3YQl)=)Ezx^a~K;h8;<%d_nn zwqziP?K5embytqL?*#B^oX5*bO7<@2+3^z4?;PM(kLdul8@FNb4n@gxQQ4PBkTVw- zLQd^Xx#U^{pta+2_mc8FE3VR$2m%7Q>QVZheuS$(#L-}Z`~D*$a1y!B!_tgDEukaH+oY)btqWL?sxTCpLXXG`iYsp;iHG9Oc@yBkLZwLwm1cg8 zGPop*%D6O$MR}p%5tVS85oJ$|7}KL{bt9s}&y|mLZ;ccwCvBUl z3l02o#VeZom=9|%1LU*${4c^O!6yF5qH{##pT##duA=Lb#&?`;C&y*{Exjcvf6fn7 z5zbo3Pvm?8LV!dB4?k(dw2SI%f_{u5>r=PwrHGwV)z2%kfh-?El|hL}=7L(@ z11xkB7K}BM@;1TldK55anxI=x9SQ3);;wr_;2Y}5z6PPBWq{@=gz8@ENIEOjsFsnj zA>roUc)+VmxcRW2zF!gURnd`Wjtc$yj1f|%6$S#15ka!(5=;b+{-XC{Qo1=)49!Xe zWT9f*cr>8!6t|Yw0_&!WW$(_UR<9AuV%Gy9-D1Pr#FmDLSCc7;s9>>?p>8;g88PpS z_|ws|bbDIG?gS!^{Z8zWh}Y(YsGr^f> zXiiGAHeiAh%dF6z*u0#|*RK7w#*<2!tJiiqQ>kd{{}>ae?bqdy^M^*vu+$F5MbVj$ zOKvyGp*~02aG40_IZE%>tpa?1m%=YL14*x?dVejjHA}i`RZAT>DK&md#O~Hos~Mqd zf%JFbK5G9kokK;foCw|Fg9Mb;@f!`53Wcme^@ufCYxkNNX4sB!hII~|oZ+ae$d=yl XNGOf8kPN9F?tJMS?-;|~)l%$#`q9eW delta 2718 zcmb_cdsGzn75;X2W?wVAt0Jh7>iB?w0-~q{@dfxu(5&wVQITaCVPV<9-6aB67Gs*D zs309gMZ>X%rc^67ZlfYmjM~N+C31WnF}9p&O=1&68Xu=UP3;}Fl0(v-{?k2Y_x^sr z*?aHzefRrKRg3!Whic!XKYX8z*j?G!*831AFRS^=Ky)t#yOjZ=H-X(d9T+_bx+OD!`aJZV@hxEc z0>iKT6Byi%QNGYNVBBVmt*!^AgdpMiMqu?(%&I*{Ag%|ZbRI9)8mYlKEGT}D&i4mm zt_e#j@_?=Du+&jXu?s7-1iIFblKrv3z#6Q3+eaiy@l#hFusII9iU$Lpk8q(i1L&Uy zU%O>1FrpP5XPW?~3y**Q02u#BW!U!+Fdb112_+`OH>x7};XvkG)!5AYz#3jPu8ay+ z$*SZP3G{zaWxY=S<2zNE>HC5FuT`5@5`dTcsP-HpV72M0mIe(ek*0d8P6bp|>X^<3 zQuL@#oz%Gj70)_!>Lf0;m`Y&wag)X4v2AlHG3K*}kvpcVnw2f>=*}DXcVY8PK zsoqZw&a)fKi9qFZ?5;#=Fn0!9_bom5RkBT+SyJ>Mdm@MGkDbc4Z6U8zNbHm8 zeQ5+nZKk^(KDa;87Hy{)RnFHoeDX06`LWht83bfEYL6+(NZ)C%9_R;b8=>pBoy-*R zShr;RdNOIOZrubqBZJA+zQNq9!d6bJ}!g z#@7Qib-K^2SE-;WR`(?Q6q)6){srwf)ab50{ZtL0DbrWH^$JPatgjwPQd>*)@3l-J z=5zEH8qbjz9Qu!ZgNeyk`i|Wc!#>bIer*i_pR51JZHj#x4E^sdB!HIECXJj!Wl|PG0SnzsA&hHHgORTPmvkJxyX|lWa8g( zQ-esUBpYWs{=f%M3V6Eyst{ zlWC4wTD$~c@?guEV2Tr3Eq~ueZm+yUbE)4WTURgfPt$7E@`BY1J^|``WjN4HhaF);ql7tVg3D4rt)A_mpnf#NIp5tD8~3iI5O zUG#XwY$1G%kmZ(a*>)S@D4;W2j_8rUF$S|UpH*9~a4zgFEgl>2eRk2YO0of4c4X+N0nD~Qw!HXoX%_*cxE|+NcIwY58A`L(p zpe!V1YEEOZ96e{y^F3an^d7I#I+Ds4Q4@(;5)FA4H_8_PuZ&qCp->Z1+)b>I_R825 zT}8?(rj>`HGDC&F@~epP15YEWhyLuv9#OCfJ>C`~lbud!tzdIH1rkOoaJZs!dPXUT z#dfif%$zGxn&hH|_^Gpy?n0 diff --git a/src/translations/bitmessage_fr.ts b/src/translations/bitmessage_fr.ts index 0a525ac1..48d7db51 100644 --- a/src/translations/bitmessage_fr.ts +++ b/src/translations/bitmessage_fr.ts @@ -59,12 +59,12 @@ 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: @@ -130,27 +130,27 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + Bitmessage Bitmessage - + To Vers - + From De - + Subject Sujet - + Received Reçu @@ -170,7 +170,7 @@ Please type the desiged email address (including @mailchuck.com) below: Message : - + Subject: Sujet : @@ -193,12 +193,12 @@ p, li { white-space: pre-wrap; } <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 : - + From: De : @@ -208,7 +208,7 @@ p, li { white-space: pre-wrap; } Diffuser à chaque abonné de cette adresse - + Send Envoyer @@ -228,7 +228,7 @@ p, li { white-space: pre-wrap; } Envoyé - + New Nouveau @@ -238,7 +238,7 @@ p, li { white-space: pre-wrap; } Label (seulement visible par vous) - + Address Adresse @@ -258,7 +258,7 @@ p, li { white-space: pre-wrap; } 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. - + Add new Subscription Ajouter un nouvel abonnement @@ -268,7 +268,7 @@ p, li { white-space: pre-wrap; } Label - + Subscriptions Abonnements @@ -280,12 +280,12 @@ p, li { white-space: pre-wrap; } Add new entry - Ajouter une nouvelle entrée + Ajouter une nouvelle entrée Name or Label - Nom ou Label + Nom ou Label @@ -295,17 +295,17 @@ p, li { white-space: pre-wrap; } 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) + Utiliser une liste noire (autoriser tous les messages entrants exceptés ceux sur la liste noire) 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) + Utiliser une liste blanche (refuser tous les messages entrants exceptés ceux sur la liste blanche) Blacklist - Liste noire + Liste noire @@ -343,157 +343,157 @@ p, li { white-space: pre-wrap; } 0 message de diffusion traité. - + Network Status État du réseau - + File Fichier - + Settings Paramètres - + Help Aide - + Import keys Importer les clés - + Manage keys Gérer les clés - + Quit Quitter - + About À propos - + Regenerate deterministic addresses Regénérer les clés déterministes - + Delete all trashed messages Supprimer tous les messages dans la corbeille Total Connections: %1 - Nombre total de connexions : %1 + Nombre total de connexions : %1 - + Not Connected Déconnecté - + Connected Connecté - + Show Bitmessage Afficher Bitmessage - + Subscribe S'abonner Processed %1 person-to-person messages. - %1 messages de pair à pair traités. + %1 messages de pair à pair traités. Processed %1 broadcast messages. - %1 messages de diffusion traités. + %1 messages de diffusion traités. Processed %1 public keys. - %1 clés publiques traitées. + %1 clés publiques traitées. Since startup on %1 - Depuis lancement le %1 + Depuis lancement le %1 - + 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. Demande de clé de chiffrement en attente. - + Queued. En attente. - + Need to do work to send message. Work is queued. Travail nécessaire pour envoyer le message. Travail en attente. - + Acknowledgement of the message received %1 Accusé de réception reçu le %1 - + Broadcast queued. Message de diffusion en attente. - + Broadcast on %1 Message de diffusion à %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 - + Forced difficulty override. Send should start soon. Neutralisation forcée de la difficulté. L'envoi devrait bientôt commencer. - + 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. @@ -502,12 +502,12 @@ It is important that you back up this file. 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.) @@ -516,97 +516,97 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -618,75 +618,75 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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. + 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. Messages déplacés dans la corbeille. - + No addresses selected. Aucune adresse sélectionnée. @@ -696,82 +696,82 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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: 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'. @@ -786,37 +786,37 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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. - + 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. - + 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'. @@ -826,22 +826,22 @@ Il est important de faire des sauvegardes de ce fichier. Souhaitez-vous l'o 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 @@ -930,332 +930,297 @@ There is no required difficulty for version 2 addresses like this. 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. - - Inventory lookups per second: 0 - - - - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1263,121 +1228,121 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2. - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1386,77 +1351,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1747,6 +1672,64 @@ L'option 'Nombre Aléatoire' est sélectionnée par défaut mais Vous avez des connexions avec d'autres pairs et votre pare-feu est configuré correctement. + + 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 + + + newChanDialog diff --git a/src/translations/bitmessage_ja.qm b/src/translations/bitmessage_ja.qm index 352b77f25c3d8b7d988b9e11e85953df13df5ca2..d838fc11e765ad36d95310c4503efe8c17813040 100644 GIT binary patch delta 2039 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 diff --git a/src/translations/bitmessage_ja.ts b/src/translations/bitmessage_ja.ts index 294672d4..e6518561 100644 --- a/src/translations/bitmessage_ja.ts +++ b/src/translations/bitmessage_ja.ts @@ -59,12 +59,12 @@ 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: @@ -130,7 +130,7 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + 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のアドレスはサポートが終了しています。すぐに削除しますか? @@ -140,94 +140,94 @@ Please type the desiged email address (including @mailchuck.com) below: 返信 - + 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 + 起動日時 %1 @@ -235,12 +235,12 @@ Please type the desiged email address (including @mailchuck.com) below: 暗号化キーを待っています。再度リクエストします。 - + Encryption key request queued. 暗号鍵のリクエストはキューに入りました。 - + Queued. キューに入りました。 @@ -250,67 +250,67 @@ Please type the desiged email address (including @mailchuck.com) below: メッセージは送信されました。確認街です。送信先: %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 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 購読 @@ -320,196 +320,196 @@ Please type the desiged email address (including @mailchuck.com) below: アドレス帳 - + 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. パスフレーズを入力してください。パスフレーズがない場合は入力する必要はありません。 - + 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のメッセージを処理しました。 + %1 通の1対1のメッセージを処理しました。 Processed %1 broadcast messages. - %1 件のBroadcastメッセージを処理しました。 + %1 件のBroadcastメッセージを処理しました。 Processed %1 public keys. - %1 件の公開鍵を処理しました。 + %1 件の公開鍵を処理しました。 Total Connections: %1 - 接続数: %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. エラー: 送信元アドレスを指定してください。まだ作成していない場合には「アドレス一覧」のタブを開いてください。 @@ -524,32 +524,32 @@ It is important that you back up this file. Would you like to open the file now? エラー: 送信先アドレス %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はメッセージの処理を行いますが、ネットワークに接続するまで送信はされません。 - + Your 'To' field is empty. 宛先が指定されていません。 @@ -559,12 +559,12 @@ It is important that you back up this file. Would you like to open the file now? 処理がキューに入りました。 - + Right click one or more entries in your address book and select 'Send message to this address'. アドレス帳から一つ、または複数のアドレスを右クリックして「このアドレスへ送信」を選んでください。 - + Fetched address from namecoin identity. namecoin IDからアドレスを取得。 @@ -574,27 +574,27 @@ It is important that you back up this file. Would you like to open the file now? 処理がキューに入りました。 %1 - + New Message 新規メッセージ - + From 送信元 - + 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. エラー: 同じアドレスを複数アドレス帳に追加する事はできません。既存の項目をリネームしてください。 @@ -604,92 +604,92 @@ It is important that you back up this file. Would you like to open the file now? エラー: 同じアドレスを複数購読リストに追加する事はできません。既存の項目をリネームしてください。 - + 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を再起動してください。既に接続がある場合は切断されます。 Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - エラー: 同じアドレスを複数リストに追加する事はできません。既存の項目をリネームしてください。 + エラー: 同じアドレスを複数リストに追加する事はできません。既存の項目をリネームしてください。 - + 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. アドレス帳に項目が追加されました。ラベルは自由に編集できます。 - + Moved items to trash. アイテムをゴミ箱へ移動。 - + Save As... 形式を選択して保存 - + Write error. 書き込みエラー。 - + No addresses selected. アドレスが未選択です。 @@ -699,87 +699,87 @@ It is important that you back up this file. Would you like to open the file now? 現在の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 受信日時 @@ -794,7 +794,7 @@ It is important that you back up this file. Would you like to open the file now? アドレス帳から読み込み - + Fetch Namecoin ID namecoin IDを取得 @@ -804,7 +804,7 @@ It is important that you back up this file. Would you like to open the file now? メッセージ: - + Subject: 題名: @@ -814,12 +814,12 @@ It is important that you back up this file. Would you like to open the file now? 一人、または複数のユーザーへ送信 - + To: 宛先: - + From: 送信元: @@ -849,7 +849,7 @@ It is important that you back up this file. Would you like to open the file now? ラベル(他の人からは見えません) - + Address アドレス @@ -869,7 +869,7 @@ It is important that you back up this file. Would you like to open the file now? 他のユーザが送信した「broadcastメッセージ」を購読できます。メッセージは受信箱に表示されます。このリストのアドレスはブラックリストより優先されます。 - + Add new Subscription 購読先を追加 @@ -879,7 +879,7 @@ It is important that you back up this file. Would you like to open the file now? ラベル - + Subscriptions 購読リスト @@ -891,32 +891,32 @@ It is important that you back up this file. Would you like to open the file now? 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 - 接続 + 接続 @@ -944,162 +944,142 @@ It is important that you back up this file. Would you like to open the file now? 0 件のBroadcastメッセージを処理しました。 - + Network Status ネットワークの状態 - + File ファイル - + Settings 設定 - + Help ヘルプ - + Import keys 鍵をインポート - + Manage keys 鍵を管理 - + Ctrl+Q Ctrrl+Q - + F1 - + About 概要 - + Regenerate deterministic addresses deterministicアドレスを再生成 - + Delete all trashed messages ゴミ箱のメッセージを全て削除する - + Join / Create chan chanに参加 / 作成 - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Set avatar... - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Waiting for their encryption key. Will request it again soon. - + Message sent. Waiting for acknowledgement. Sent at %1 - + Channel - + 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. - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - - Inventory lookups per second: %1 - - - - + 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 @@ -1107,181 +1087,181 @@ It is important that you back up this file. Would you like to open the file now? - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + 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 - + 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. - + Undeleted item. - + 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. - + 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. - + Display the %1 recent broadcasts from this address. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1290,82 +1270,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - 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 - - - - + Contact support @@ -1652,6 +1587,64 @@ The 'Random Number' option is selected by default but deterministic ad 発信接続のために1つ以上のピアへ接続を行っていますが、まだ着信接続を受け取っていません。ファイアーウォールかホームルーターが外部からこのコンピューターへのTCP接続を受け取れるように設定されていないかも知れません。Bitmessageは正常に動作しますが、外部からの接続を許可してより良く接続されたノードになることはBitmessageネットワークへの助けになります。 + + 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 + 接続 + + newChanDialog diff --git a/src/translations/bitmessage_nl.qm b/src/translations/bitmessage_nl.qm index fa7b228075d3c7a64c51a8ea62564f2d0d8ac7c3..2199f678ae031db5a36a608d817464468cb16299 100644 GIT binary patch delta 903 zcmX9+eMp>j9RED`{GPXa?p04uPq#!iN8!S3YHV#ux+ZKVY%a&@8pIOvEDusKWqIoj z=1Wb{-P$_F$xPbY8C|hNTd|CR(y62iN5ny41Z{2XvM7dq;{N*ZeSY8X_xZeh&(zJ; z40^)V03HLp-vD9=P5(z$^ove}vy3058`98^$3PHUpY~Sb2fi z4e>jBw0|?`ZGbW$0NYPcqU?A0pHIgtc$)kZ6%)#L^Ts zD?Q{R5o?vS-5m$)H>CQTtc5NOpWZQs3C5mic{FL>mTol~}WV__bP!Et-EuTB`E*%TVv!{vr*K$&8 z0_33#db7pOtF_!WChERRhiQ3SG)+88OC-_xfCM}aap|PQ7@iZCOFts^i$v4|Wc7-f zuFdSP7dNx6vwm2qy88i@^(%W*j7v@`M|wU7oMp<}$N9s8Ugg6Re0LNo3$bk!_NB5W zQ<&ba{8j6wqY*W<94_bJCbeUbRu)`S$9|lr@&@(l|BQ1Z>e9t5TKu=>UrExsx3o(G zKXVWnl-|o=&Y#+^^&}ty`V;Cs?%A(TPtg%uOrQODhI4g>XSIPue=|zv_^zjos=!fV ziP09WXM7TASTqFL>n_;<&xL<|L!J?ksQZ;G+3v z<`*1xDw`7Ha$FuB(cVwIq}S?+$Fq8sgfH(|Ww=-`ci3B-+B-w9wY0Ur*xu2W2yU2A F{{t!O-W~YuO@VG*kT5CY$?1P1En(^L^(#zsI@v zRKcso9dUsg02=`NcYxFh7%hN22*iF36sH4*-+{7E0L$CJ{p)}@Gf-0qtoRhtR2u7_ zfi(L7<7G%ct_Mte!_htlxm5xpet_J~`lw1MZ-~6N2xCPN;BX?k=w~31kc`{A#z~?! z922Ke^3p{%N<&E(!A#q5@1rMpo)eCVhf%S=7D(}6ySth3d+bp51F65^G4CND`8F(m ze1QTo1hr>@V(t=FB$0@DM97OC03xS_(lgAZVxcpB5&^{Y3Zs2w7WIO#WGDcHY(vI; zA7E`W+%*3Lpk6Y3vG*ea#TtI}M21Mz#r9K8id+9kfW z^JzMER-Aa5QOy@8jT#_!hNHbj+B959q7zc_XA1#Zw_ef)Gik|csqqgISk@#RYZu6T zPI@!_2%y-cq3$?ZzaWh_r7@q9&cuAk{GgnB@f8BurhdDL2Ys%ImGos<_v3NtOrzZOQ*(Jn=w31pGk^-4nrtz3Ri>6`nU%4d|}5M#Tb zO!vodKh;<=J4x%>jjuO7#rjF(vDR%m)+IP)j1@9HF+&}JPKe6;q@a7@j$o{r>w>q?vHJVy{eW=r;*BjIRUb3r=^6h>xw z8`$R;H|N|T(mFG?pc?hTO1piiMH~>*6H$pqI8hHjG&taao8N>FepAS4g?}~Q<8;+| z+&+JBn;aKRHy#MiC1nN6<*1?ejD;q>5EZ;x&n}_0j(r?R^}4g#<@EU-4|C7?kmkz_kqB)4SIph) z7(&Qkcb)6i{QrN48NWce!5D)2n5UI=;~YlgF^##hMd&sN61wlGYt*o zr15DD^M7i#UyIyO<#D?lby`zcZ1C 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: @@ -130,7 +130,7 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? @@ -140,177 +140,167 @@ Please type the desiged email address (including @mailchuck.com) below: 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. - + Encryption key request queued. - + 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 @@ -320,436 +310,431 @@ Please type the desiged email address (including @mailchuck.com) below: 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. - + 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). + Verwerkt %1 peer-to-peer-bericht(en). Processed %1 broadcast messages. - Verwerkt %1 broadcast-bericht(en). + Verwerkt %1 broadcast-bericht(en). Processed %1 public keys. - Verwerkt %1 publieke sleutel(s). + Verwerkt %1 publieke sleutel(s). Total Connections: %1 - Aantal Connecties: %1 + Aantal Connecties: %1 - + Connection lost Verbinding verloren - + Connected Verbonden - + Message trashed Bericht weggegooit - + 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: 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. - + 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 Nieuw Bericht - + From Van - + 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. - + 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). - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - - - - + 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. - + Moved items to trash. - + 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 @@ -764,7 +749,7 @@ It is important that you back up this file. Would you like to open the file now? Laden uit adresboek - + Fetch Namecoin ID Ophalen Namecoin ID @@ -774,17 +759,17 @@ It is important that you back up this file. Would you like to open the file now? Bericht: - + Subject: Onderwerp: - + To: Naar: - + From: Van: @@ -799,7 +784,7 @@ It is important that you back up this file. Would you like to open the file now? Verzonden - + Address Adres @@ -809,7 +794,7 @@ It is important that you back up this file. Would you like to open the file now? Uw identiteiten - + Add new Subscription @@ -819,39 +804,19 @@ It is important that you back up this file. Would you like to open the file now? Label - + Subscriptions - - - 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 - Zwarte lijst - - - - Stream # - + Zwarte lijst Connections - Verbindingen + Verbindingen @@ -874,217 +839,192 @@ It is important that you back up this file. Would you like to open the file now? Verwerkt 0 publieke sleutel. - + Network Status netwerkstatus - + File Bestand - + Settings Instellingen - + Help Help - + Import keys Importeer sleutels - + Manage keys - + Ctrl+Q Ctrl+Q - + F1 F1 - + About Over - + Regenerate deterministic addresses - + Delete all trashed messages - + Join / Create chan - + Set avatar... - + 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. - - 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 - - - - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1092,121 +1032,121 @@ It is important that you back up this file. Would you like to open the file now? - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1215,77 +1155,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1572,6 +1472,64 @@ 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 + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Objects to be synced: + + + + + Stream # + + + + + Connections + Verbindingen + + newChanDialog diff --git a/src/translations/bitmessage_no.qm b/src/translations/bitmessage_no.qm index d390813fe33e9b4ae8a736675d304b18da7f70f7..a47e912ada7d2720d72337e55a47f4d5376034ab 100644 GIT binary patch delta 2345 zcmZ8jX;f9`72WsUd*5{Ld#@tk47yk%qB2!vP%(%KMR>%aAj%XYQ9(fkMI3l4YK#*Y zltBq1rPdh5%5y+bBu;fGsEb64#4ch|hb#qC4W`zi+w!aZb=EiBbN1P1pYz?V_2T10 zVxgmLIRIav%pZ_;07D7@`3Mlnb;NK$dj**O7r^^CFw2ws3BbGwK$8*D&B1_2F{IW+ zU}z1bCq96ucemXT0(q+h1gwHw&ildDkPlS@jaq2G6#4x~=wc@Vwx+%4G4VOD!~?zT zA;793aBF!BxF^D0&vir!hV^X*CiH{%RWHE#CH!_&0MWle!0misSvbOrFEWYdZo5{G z=v~hU=nkTbjRYhjCT#^!YrxdyXLzr;+vc<*c5@nRIK2RI^Le3uC}tdIK(z`9+Rebl z^;qQ;n7Bz#y=d31QTO$hEm2f;2vXhHx# zR0Qj7e&En4q{LSND-Q{?VFr8}gp43EFgil`EYS-{3=noWH3MNPBdc#37O31n=SSdp}WB5V^+tE}~@kHu>xTo2nTHtSLWWlOhR*IR7u*a>JJi9f{= z@EA9-V>$iCP7;5un*xlyBUzGJ+LM>1u_q@0Ct@XAnDt8_vr~#_VvU9zlTwd(QJtw$ zy21?CE|qfLkh-)`X?b-s;21A`RUiOPpGt>@|B<#%I+7m;l0<6+GG&x*JDlhKELmuyUrU1=@T?T@lI5Ul6zSHTHaU16Yc+1YJpP3h=rK~B-2M$~ zeq2t0T&08qSlTPx@%8_jKK>2TRJQr<8C*N{ zqoZ>*+LR>~z=nG5+_$8#v_re_lMMF%Ms4P|ex%$*yR?vEJ9AZA9{CU8`fF|VcQ;6} zr}p5$2Hua>+PC)vvO~2e-vo*xxh_xl z)z%-FKti|G9P73@F}m~qOyqpJ?xB^;_8g~sIhX(wPv`@+KePYOBMHlQ+3mnEi3YYZJkQtxx4f~K-t|AMv=NI<%W@D?67jhwuUvHwnw>g zp8>-Pl{;ltpmMX)n%hAU4p#0)>|&r?rF|d8w9Q+2;xL36o0KO5spguys!uEdjA>Cn z7|x8Bl&UjUr?daZsB?Zvrbw@-sl^q*NBhfFMoc36t=53)40x!Qg2xZ)TfWy zwz7qz_k{X#Is*>8qrPn6zFVS6|KK<^Q*JU(;@Wk#so#Phf%$DF_cHn)rr1m)iVkwN zyP2lU&j5OzFeM)-Bhvn+^sYRL*S0to`=j4U7N||DD#IP^(E8I1)bdgU8uQoRv_Cn%Y5q1uRxA% zyZNu>LG1H%bF(+wio^K7c3FqH)ylVF$%}5g*Vo)WCkg2PTZ>=DQs7vl#s3N!s~v5b ze1br|f-EuBA^b;BEi?bz0DM|yIoR|TsB*Q`gqwlYjg~ss3O>skOMP|+5EX1W??h{v z6k~a{Z9QMVI0~WZW|5Z?X&+2vovL7exgDtuF)>3R)i+;1&Wg!4TwCiAdcQp$bN+ zC`(b%TB_JKW2;qA#3w4%VlCL(QfpnegZ7~!I#&0D>|i_N?Ck7h$hrTY|3BwD-*?Wr z{A&-t;t;>m+0q3d2za+25L5xa^8w*LAkF|x8wH3xfrL{)@G)S4AMI}fGA09^=OMV@ z1^6w2pnDPUNIB^PKxs-w- zQ|3CS_6=zqXVtIn75w- zD*CZdv=%r!71_U&gSrwFY^T64?LyHm3n2RtZyL4$hq|yi-xFB30PRN>1D^G`sIDL~ zV{oOdiI|&)s~(v^y)XJs+y-WxWTf?X0p}`axH~Zuu#@poj39^k)0yBUKLOE7r86l|0U>7@!#H9hqMs>Sqyf@?W2#&_ zNVW)O>t0Hz{T6emfvAqKFb{hu@u@qRC%kBYSV*u1scq?vFX6zZ>+u65)`OUmt3u)iCgSX4r1h_l#&MzT5aVGDp6>Y%L zG~N}J7MRq@yLxsQt=o7v1UaN}7w=ZJ8z9Q%D=LJ#3k`CZKL`wz?kLaz%f>SWTorA*-3 zNR>ZliD2TVlY!=8g6P=yfxJe+wDY8yZ?S;ervWbc2(sjqaao`s?{}hd*&{)ILkHjz zAoyTC1Gp{{>>0I_>^i}|(j@9CoxoP>48)rRt-ZeFH%)N7zzZ1GBe*=2I%DF-{nkLE24j7DnBT1%{j!&g{8FH85ScxOhKNTqaCQB5EgW z5E|=j6tG#iGMIogT^E+FBnH}&gqz1vz>ICeEqCbL&Me{9HRM0SSJ+f0Bx(DFpQTgW zD9ajQM>$n#bC>W!{b-s2>x5lNbU+{$_VKAUG_Jz?lZR0C^ofRKlB1K$L`zI{z}w43 z>5qxZcRvy>eZv6E4iFi?3?}N$qTEU8y1=P*ci&}j7I#=Sfbk5MSS0j5Od2UV@1DGM#ClX;ja^FjZ{>7BzaRb)W<(dinv%nS|eGz<8{E4B&qVF+DUJeSdS6_u3Pf)Q1Y|!C&}S? zk-(_slEa6>f$_gd+IJtPOeeZY&RRUFFS{jIYRG!OD7p2pj@qk5(zj|EQT2i3(N(f9 z1WTQ7#8cJhNj=`XM?hMn-e(DzrcxTZFqIs8OJnc^nAaf9i9JrExlFp{%P~|#f0x!z zp#8GV(kBPk0by}6?@~&zTq)yvEipuSnJgoX0-o%bW%kg8f?9`d*dTjzY&ba#lr@Dv zqzRcWJ1Dk9^pjV&CQg@&Y*V8Kk2YLZ1Oozh{_|b z^3)=tF7AlDys#9A{zzVVokSITW%?{v<{HvN+ z;JsP$?t(2>B})AC-Hx?ul56oH8ZDDo@Cq*25~ zVZ35`H6b2fsF=4R3*c=~q}@xVcZ8>ctF8ldT1D30D9U)8qWnZ9N${&;V}v^mtQQp< zQ)U3myA>bXrHz@QIAA1+-rTA<#N<%>PIK6{FD;5@XF^!lsyMk}H&MJpaUqk|C1S-z zH6af1R(xI5Nh7mBaX*0q{$;P?ekbj}9HNxm*iS{4q*T31Yj&*CLw}tHQnk{%h64DX zR{C2TfmPos=jaT;^A*bE-8Gcpcgn23Vj#6$Ss1;Zq_G4jFSl!G^v+gZU!OwM-cUZs zm_&>?sc@7W*Kbgbh>8W?*sb!jzg+xvs%d>|fn5(&vq2KnxvAFwO#88gs`>?Esn1uc z4*pL6OIW6>&ee{iIpMA92q0;x@dhk!g2NWSuj-DacaEiSpW|WYT~$xoV&FxoI@pj) zuh&xbnA1evfye5ZpAh1}K6P9}IFNEm{rZP3!1_h%#`BMX-PhDjQ&qs~BK3jcbyW4| z)Q8NsY2@BhA9Eo)bB+4p+tl~R-Kj7xS^0#-4>917P9GN5N=umS8%ZByearHyb*Jh% z+ZVDC3Z*OJu^d{MUX6XKU4z2$%_0dG$D@7lI^qRz&p2TH~rc zt;Zr}-=UmCMQD(paw`HpOJrrlo2L`%>D| zrgJ&gIesqIj?p5QXFE(zbP=<714fvvY>ijYQ^zC!q^9;RwC~{mA-H`cI<_`*W1s6umB$&Eg6MaND{fz86e*{K+0ac=>cFX5aKmvKP`_K#h#uvjAE zNBVxYcLRI}fzEs_hhw$uVDYm)k$Sx`kJak+ED>g0sxzbyD#~*Csa!Tye}<8684YTB z;-231wQf^62i5%{y9~-sN2u&X{V}%`S{o_JzQ;Z3AvHB!_|8u{tfvp)f)f+ diff --git a/src/translations/bitmessage_no.ts b/src/translations/bitmessage_no.ts index 7b1899a9..046ba7e1 100644 --- a/src/translations/bitmessage_no.ts +++ b/src/translations/bitmessage_no.ts @@ -59,12 +59,12 @@ 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: @@ -130,27 +130,27 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + Bitmessage Bitmessage - + To Til - + From Fra - + Subject Emne - + Received Mottatt @@ -170,7 +170,7 @@ Please type the desiged email address (including @mailchuck.com) below: Beskjed: - + Subject: Emne: @@ -193,12 +193,12 @@ p, li { white-space: pre-wrap; } <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: - + From: Fra: @@ -208,7 +208,7 @@ p, li { white-space: pre-wrap; } Kringkast til alle som abonnerer på din adresse - + Send Send @@ -228,7 +228,7 @@ p, li { white-space: pre-wrap; } Sendt - + New Ny @@ -238,7 +238,7 @@ p, li { white-space: pre-wrap; } Etikett (ikke vist til noen) - + Address Adresse @@ -258,7 +258,7 @@ p, li { white-space: pre-wrap; } 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 @@ -268,7 +268,7 @@ p, li { white-space: pre-wrap; } Etikett - + Subscriptions Abonnement @@ -280,12 +280,12 @@ p, li { white-space: pre-wrap; } Add new entry - Legg til ny oppføring + Legg til ny oppføring Name or Label - Navn eller etikett + Navn eller etikett @@ -295,17 +295,17 @@ p, li { white-space: pre-wrap; } Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Bruk svarteliste (tillat beskjeder fra alle adresser unntatt de på svartelisten) + 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) + Bruk hviteliste (blokker beskjeder fra alle adresser unntatt de på hvitelisten) Blacklist - Svarteliste + Svarteliste @@ -343,157 +343,157 @@ p, li { white-space: pre-wrap; } 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 + 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. + Bearbeidet %1 beskjeder for person-til-person. Processed %1 broadcast messages. - Bearbeidet %1 kringkastede beskjeder. + Bearbeidet %1 kringkastede beskjeder. Processed %1 public keys. - Bearbeidet %1 offentlige nøkler. + Bearbeidet %1 offentlige nøkler. Since startup on %1 - Siden oppstart %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. @@ -502,7 +502,7 @@ It is important that you back up this file. 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.) @@ -516,97 +516,97 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -618,75 +618,75 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne fil 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. + 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. Kastet innholdet. - + No addresses selected. Ingen adresse valgt. @@ -696,82 +696,82 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne fil 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. @@ -786,37 +786,37 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne fil 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'. @@ -826,22 +826,22 @@ Det er viktig at du tar en sikkerhetskopi av denne filen. Vil du åpne denne fil 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 @@ -930,122 +930,122 @@ There is no required difficulty for version 2 addresses like this. Det er ingen krevd vanskelighet for adresser av type to som benyttet her. - + 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 - + Save message as... Lagre beskjed som ... - + Mark Unread Merk som ulest - + Subscribe to this address Abonner på denne adressen - + Message sent. Sent at %1 Beskjed sendt. Sendt %1 - + 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. - + 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. @@ -1055,67 +1055,67 @@ Det er ingen krevd vanskelighet for adresser av type to som benyttet her.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 # + Strøm # Connections - Tilkoblinger + 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.) @@ -1124,82 +1124,82 @@ It is important that you back up this file. Would you like to open the file now? 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 + 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. @@ -1219,70 +1219,55 @@ p, li { white-space: pre-wrap; } Inventory lookups per second: 0 - Inventaroppslag per sekund: 0 + Inventaroppslag per sekund: 0 - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1290,121 +1275,121 @@ p, li { white-space: pre-wrap; } - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1413,77 +1398,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1774,6 +1719,64 @@ The 'Random Number' option is selected by default but deterministic ad Du har aktive tilkoblinger til andre og riktig konfigurert brannmur. + + networkstatus + + + Total connections: + + + + + Since startup: + + + + + Processed 0 person-to-person messages. + + + + + Processed 0 public keys. + + + + + Processed 0 broadcasts. + + + + + Inventory lookups per second: 0 + Inventaroppslag per sekund: 0 + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Objects to be synced: + + + + + Stream # + Strøm # + + + + Connections + Tilkoblinger + + newChanDialog diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index ed40e6ae0e320841907572095db65a92a28bbe1c..64d1f7314d430510e1b8205dabb0378a02ed186a 100644 GIT binary patch delta 2083 zcmZ8iYgkof8eRMBz0Ym$bB-YB6PD7bsEDWx1ehQyCQ_a>eZUJMl8gu@82E5gj)r+x zP%a75@rH;uoH*iLDs9Rn5Qjv;ES{MnGg3zo8lTiz&iU7`wZCtF`+e8D-t~U_bg6i2 zi&)@h+Y4YUkpD3t?EnT>0`du9vL_JX!{@`m?5}{4Ujy^Kxjzk3(@Cp&; z{0hGvc3{d@1h(V>%YVVtk}pW^k`ps(F}?U96M15KiIEtIx0AAgeJAlw<^`VH>BLkk zqBbW1haVt%Dc>Kd!kpSrK=4dZh?Fi?c+$?o#v6s_n#q8Wq0ttT*f_0bR68a0snopQz7`mMR`cG*<$!6TX7ybX z9#E&*mP(@2`e`a-xIbjDrZS}(a4*v|#1a3hYHqH+OohBOcj|2~@gYakA*BJSd79r! z`m<84sBV=hRg!4BUc>b~(ehz4utF<(mWKjUH;H4KKLONU@wJp(z`kA#v3dfh4C2Iv zt-y>((H{FD2@2vll`X8gD_;GG>*1={s7s*IkDZu#Q*5=}F9I|j;=O1xeJxSEpUHsM zm&M=D%mhZylPn9_vqKA{kkjG7!B%Oqm4-~5AVoB=1%vCQWQ7%F`b!y4snDVyq|Ay& zw&tmHG+zMR1nHR1L86~@A}^XIH%g9jH=6ji^m*q9pwd^eeUUYk(j-VNu9x^?r7Ya` z1d<(B+r`?u`nA~`m?7Zb<^eHZ?h)DRVbyYPxC_njht?&Dflh>K4t@!R5;9IIa;#o(xJG74NeSu}aYEQptLB>Pvw?|w#9kw>@ohTBh+MshS zpc#Gc>0X~osZ9rT(_0(KG(s0uu$tqzK$kFfDO=#C%Nb+_yw~d1zeVpHzpmTz{Xk%o zw{FKd?rZnxj&A)oiN-ilbIOUSeRY=tNVsN??q}-@^P#+8PUx>z(OiDt=<96*IUNo9 zwo;;JhrZ{76|8iZ{*ODv{w9N4$1Gl8>kR`AJ!YN&gI7KC4WD5MjCq&y?{&bCW@Vru zO@^`?0YFfjVek0oG?m@xl}D!8GmQzIZ&9IX#>B;TN?&hGYUjD6QBEwh8&?I9P{c7~ zb?6gH`l|7)(#<$I#j`aq`kd;8m-A5@#@j5Uj zUh(R#WACe!;TL0pexns@B;CI>+KD?I%FO3f;?N^yOLiWWn6DIk+QvkOm9l2Kzpz^= zH~3SLe#(_KY*pmX%9VdHQAn(Evy_UKe4?~w-3O|VD{T?Q%oDG)@3YYq>pYZB*I__b zx6b*nznl)uIU=yeH19Me&iq zlG$p_i&lg^RL`Wm3%pmPo)^-1k==IUv3T{O8;NXRrhd7zib~B_n`}wkSW&57w~(37 zG_`j&1HW9O_BL}p$ZFDe)Ux*jP3AYa9x&20VA+qH^R*_gQU)FtZyHs2gjZ>_X<=0< zrG3Se+>^^6)(unkj4He-p!4Xn!+4W4!!Ev(5X()$7$| zj_BD;iRPPUfRb*zV$OfS{YgRQz4L=OMvu(jlm~O%;>?Ys>3ZG}|HqUXbF1|ODwOKP zVsCT%;#ivQk;QNMO8!eiECE-j$iBOlH&2n6_Xx||6`{ba?=18FUI*l!4X_+(cn0i> zv{X+u1L;#OX9n5%TYc4XKAjB1vn`k0iD7*$PqwY&eD7gn>(s(9W27TSe^+pn8NW6< z4!Zv?Ic|Hb?c?~;$3^cj1o-M4+e6Muj(wA^364YIp-SPz8Gmzhy%QQ%Sne^}Y+9a> bo{{o?a$5SL^p$Ca$>BbK+H#C4+#LKruWf4< delta 3245 zcmb7Gdt6jy8h&QZcjk8HqJSdW;&BxOg5e^_O-3#%Du~xW4TTXV8G#vOFhG;h$kxCV z9Hc;&pBcJjipoT4m~CpCYe|}=;;t=~xn0byG_-!D`wml7yT9$X{W0e~-#O=dpZ9s* z=l$SPEqADitMjto0T2!}jssXd;CBt+_XDY`f$70?e-BvjI-rjS9t@)A&w`!x1N=V% z>sY~M$fcNa^#+c+S0yyV+HBAA#jxhG8lB;``sHY(7ND-G!*X+uXy zmAM0zHd;>35Q7uVWP z0Q>hzFKdlJT)6bg8$KkRRCCe!6m5BFVV!}lyAgVwWz zLsNjgxhy5)Ig&n!O+P~|@fTR3Kn(2@S^4**Si$?OqOFHob)G%HMFMzTWP5{m0mBr` zzP~yP*jCS+EndLPE9}+lft0X|ovidDsp8oMkK+V%KQH;49?;(5qrZ5Xyx`5po+dNa zl=E=~)S`qUKKWJ#Frw5cuinN+}jt=yxIOd6Ukk5473wej*< zy**UuP(}TXRy-#tp+dv0Vh2nJkNov71#T#~C znw~R?%S{x=998r`x{~m1&5G}?tOUG2RC-;T4}{!Nj{4Krq`*<7{~H7tRHuy2&Z7h8 zL!~W)5{)0CY<@S2dLF6VF^Nt``wr#3Bb$N9F)IIRDtP^TmFapq&~a8(kl#ut-#pcd zKKg!Ts5>_MsUC@;!e)1`5({aY)FRNz+oY z$Q_&Fgt_-fp^i!+Z%q;%-vT3BAIsA0(Dp> z6%-$%C^jTXww)C<=Z0@BCS`S!1KX#O{ zb*HOmQ)j9VTd4(Qjp}ZRjmE0Y9Xmf!zwAW?HQZGHWotVr`GNZE3R+jRtIz4EKz+CR z_5#ZLyN&AG=V>jD(6vW4ciOLO70o=&{CHCMMRBjxHf-xMSgV;?R4ObHtw&<44V@W2V$ z>HRf8%Lm#yAY~h7Yq$K1o=@AV-SJ=yjbFa@&6Zdi(`9yTPbl?@25TTn_3rra3)^1|i_&wd?1IK_3-MT$z z?gFjnbRDT$V9gBO;nA&RUZbwNj0#PAM0b1`#VOii-M3HDJUacU(I*{_qVkzerubOm zC@G)j@KX+PURVBAr60-0v$-shC9pIW3y~$U$t;Gh1{SAq6)&ToGP%f@S6F1Wl{ugB zQuB^Wwfcbs`+U|9kz94`3MdqQw#|`b^A1U5VJsSYN;sO58z^BiGtg=>i=uTDK}@1+ z0!v}BEZK3zbCjbYaD-&JV_#tCNEeV;R&LHS>BTvw(gI_NO)NE8jKwDBcY!GiUl|)g zyJruUr^%pKqP0{^H!d?3ImRfxoRcH;@`ZZl%fbmQjIIX44OrSS*fpzCU@MFg1XAklayh!hjK63PrIHag%vdC*SS=P)UYXfyvBkMS923$W;*PQrj`h#_M5q2Q_foC^CK8$G0mDrv zq-2)vBI2sT@!4J<$Ed?vO)x!iX=rd6(s3}x)9%ud$dVB5xu7?+`qAKVEDC{xBBVWF zGl@oVa6ZIBF|Jp)-JHpE~|xZOh0W6l+&cCW*Hp; zO3jb#V#7(B`2U{F0dC=L;}S1d^%2DMxAAl5{y*4d6`0FR149{*Tx88F{0-~|xBke^ UY;goB1!q&5A<;Q+)8n!K2J~%Q*Z=?k diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 936bd4c1..0918037e 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -59,12 +59,12 @@ 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: @@ -130,7 +130,7 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + 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 больше не поддерживаются. Хотите ли Вы удалить его сейчас? @@ -140,167 +140,167 @@ Please type the desiged email address (including @mailchuck.com) below: Ответить - + Add sender to your Address Book Добавить отправителя в адресную книгу - + Move to Trash Поместить в корзину - + View HTML code as formatted text Просмотреть HTML код как отформатированный текст - + Save message as... Сохранить сообщение как ... - + 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 - Добавить новую запись + Добавить новую запись - + Waiting for their encryption key. Will request it again soon. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. - + Encryption key request queued. Запрос ключа шифрования поставлен в очередь. - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. 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 Since startup on %1 - С начала работы в %1 + С начала работы в %1 - + Not Connected Не соединено - + Show Bitmessage Показать Bitmessage - + Send Отправить - + Subscribe Подписки @@ -310,18 +310,18 @@ Please type the desiged email address (including @mailchuck.com) below: Адресная книга - + 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. @@ -330,19 +330,19 @@ 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.) @@ -352,97 +352,97 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. Вы должны ввести секретную фразу. Если Вы не хотите этого делать, то Вы выбрали неправильную опцию. Processed %1 person-to-person messages. - Обработано %1 сообщений. + Обработано %1 сообщений. Processed %1 broadcast messages. - Обработано %1 рассылок. + Обработано %1 рассылок. Processed %1 public keys. - Обработано %1 открытых ключей. + Обработано %1 открытых ключей. Total Connections: %1 - Всего соединений: %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. Вы должны указать адрес в поле "От кого". Вы можете найти Ваш адрес во вкладе "Ваши Адреса". @@ -457,32 +457,32 @@ It is important that you back up this file. Would you like to open the file now? Ошибка: Один из адресов, на который Вы отправляете сообщение, %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. Вы не заполнили поле 'Кому'. @@ -492,7 +492,7 @@ It is important that you back up this file. Would you like to open the file now? Вычисления поставлены в очередь. - + Right click one or more entries in your address book and select 'Send message to this address'. Нажмите правую кнопку мыши на каком-либо адресе и выберите "Отправить сообщение на этот адрес". @@ -502,27 +502,27 @@ It is important that you back up this file. Would you like to open the file now? Вычисления поставлены в очередь. %1 - + New Message Новое сообщение - + From От - + Address is valid. Адрес введен правильно. - + Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. Ошибка: Вы не можете добавлять один и тот же адрес в Адресную Книгу несколько раз. Попробуйте переименовать существующий адрес. - + The address you entered was invalid. Ignoring it. Вы ввели неправильный адрес. Это адрес проигнорирован. @@ -532,12 +532,12 @@ It is important that you back up this file. Would you like to open the file now? Ошибка: Вы не можете добавлять один и тот же адрес в подписку несколько раз. Просто переименуйте существующую подписку. - + Restart Перезапустить - + You must restart Bitmessage for the port number change to take effect. Вы должны перезапустить Bitmessage, чтобы смена номера порта имела эффект. @@ -549,75 +549,75 @@ It is important that you back up this file. Would you like to open the file now? Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - Ошибка: Вы не можете добавлять один и тот же адрес в список несколько раз. Просто переименуйте существующий адрес. + Ошибка: Вы не можете добавлять один и тот же адрес в список несколько раз. Просто переименуйте существующий адрес. - + 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. Запись добавлена в Адресную Книгу. Вы можете её отредактировать. - + Moved items to trash. Удалено в корзину. - + Save As... Сохранить как ... - + Write error. Ошибка записи. - + No addresses selected. Вы не выбрали адрес. @@ -627,62 +627,62 @@ It is important that you back up this file. Would you like to open the file now? Опции были отключены, потому что они либо не подходят, либо еще не выполнены под Вашу операционную систему. - + 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). Вы используете TCP порт %1. (Его можно поменять в настройках). - + Bitmessage Bitmessage - + To Кому - + From От кого - + Subject Тема - + Received Получено @@ -702,7 +702,7 @@ It is important that you back up this file. Would you like to open the file now? Сообщение: - + Subject: Тема: @@ -725,12 +725,12 @@ p, li { white-space: pre-wrap; } <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: От: @@ -760,7 +760,7 @@ p, li { white-space: pre-wrap; } Имя (не показывается никому) - + Address Адрес @@ -780,7 +780,7 @@ p, li { white-space: pre-wrap; } Здесь Вы можете подписаться на рассылки от других пользователей. Все рассылки будут появляться у Вас во Входящих. Вы будете следить за всеми адресами, указанными здесь, даже если они в чёрном списке. - + Add new Subscription Добавить новую подписку @@ -790,7 +790,7 @@ p, li { white-space: pre-wrap; } Имя - + Subscriptions Подписки @@ -802,32 +802,32 @@ p, li { white-space: pre-wrap; } 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 - Соединений + Соединений @@ -855,177 +855,177 @@ p, li { white-space: pre-wrap; } Обработано 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 @@ -1043,157 +1043,132 @@ p, li { white-space: pre-wrap; } <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 - - - - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1201,121 +1176,121 @@ p, li { white-space: pre-wrap; } - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1324,77 +1299,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1719,6 +1654,64 @@ 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 + + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Objects to be synced: + + + + + Stream # + № потока + + + + Connections + Соединений + + newChanDialog diff --git a/src/translations/bitmessage_zh_cn.qm b/src/translations/bitmessage_zh_cn.qm index c32579a585c53fcea6ecdf21a17e750e13615eda..4114166d8a54dcaa91757eeb6fc62efaabc2ae81 100644 GIT binary patch delta 2323 zcmZ8id015U6+Lg>yqP!i-pmNWxS)ayBPxqQ5fsI^f&ya&1yKZ42nq@j5Kxq%p<34h zL5(0qOx)sviBqdaMdQ*KQK}(o(PHOoqVe-X5KSNqqQ`7QUJd+xcv_vKDa zTe+sp%{~XfJ3#V7KwA#E_9!Yyx$Ie>=a^g3|yu>W3pKo z*z_9cIR#cZ6!7=Pu-=V;PdWU*_5;j6BA~nm2#^tUy9Aitg0StENWQ8IXYNJRwx3Ak z9-_7zNkqhq^i@FCK13Is;kl(<7%3xmV>*yqj<_YOU`Os#%sI}4ax@Zj8-YS^yx++H zNex)}F%x%BN8vs@p!)`^Gpm5*x!6(A5173hSI;E^u1?&&SVyJm(c;d)3wogaavR{g zMljSq2h^v6M{g?8*GKSH2LfRWg@EM8K+Jt%WKk6Z=X(faTo}OXq%a{Nh!^_{w%fd* zW(mph9|N{vVIj{92c&Jt5>tqW&YBa<1KLADunh>Y`_duV+nq})V0YkZF%_COiHbS%I z{Wc&_quH0h^>DpY6gPS z#mWv6@lFtH64#RPF!Aa~#6JFFqdpbTmv&)vx!Byc70~n)AIFjC;6SmhfboJ7#a~X& z1O}vPElF%?PG9Y~6O)1LKsX+Xf_OQ=hny{PpXh|HW#jbT!yK!**wO_V!QnE9(msWaFp#j?4t`|5Z z4%xdX z>MsPckd>YKA8c=w-LHS)MS>x_sQ$8tS7*=Q|cMKL+X#VJfsu*;b4{kpc*)#KH#VFon zWs1_XDiaU~DAwoo#2*yzvx%&zO|ebqIE5YU!bL-rnZHt@oNQ&&suC)5UMV|wmkE58 zs-{W6qQ^?Lf#w_3SGiKm)&@RMuKb(%d;*j^l{O%CuhMK^*~Z>}r`!$S#zcn{=Wd!P zew5PcI+&G)Dy^P$@v^7t@K_QUyjy+O=S{^m>YOzhl)PF^`8kQ^tXEUF*8rhC)r=z( zSy`I8>2ew4q^VoS_vX8DMcuk^Ixsa`J@%$meoNJpSyX)b0M&k4$l=(1qyC0@+tssf zWR@(bH`0lb9qLUB33|*^?-e#NP^|i578AKOs4tqh{&t#4et4W7d}K0D<^Q)XncSCt zPwy-@St}XW{cDqN#X%tIj%ntSOqzL)Dd|8Z2@W=8v=;$mcG*p!Ijq#QOoQxfUY zPD?=M3XWlrCGZNR%DQcd_$!(AbFs|W6H3NL%iPcEf!Jx5gV$dJ@1M-@7rGODpIBaQ`2*jL%QQgoYLN_#%U(s-rhb;TAg@hEh27Z8(IMvv zjswOM`UH>0Av(5=*d;hp18ejZVdKs^ zMvd2bS2(+Sm`$0fx%pYy89BKNa#!S3bhAeM|B`p0)$M;z31lOTtniHVaipikS^o=a CJdJw* delta 3084 zcmb7GYgAKL7T!0>&Fkh-5Kv-;>jMOohlmwKk%!iI1ffKHAR*j=KujnBc`30)JH9Gl z)GD&5W2vRI;!M+4@YPo9jMdRfskUP2!q#e+OR0{itxILTNXO;s{FpUASUcz3v-ke? zx4(T3y>+6`c8O}e9Bo82j!4KLlGG9D%tY*dqVZRVW{$<)S)#Om5DlMAv^az)N=B47 zjc82*NzMfj4UH$s#ic~gdy(Wu1nlbrHsb=Zn7;xyhhS@#qc+i zEPXnWW6j^mWBMJUd24B8=VKz@w<%B_M-=%ZjnN@_#9RvhB8*7;3Psj65>1Sui5IGg zk~K7A`{w{(KVZ`@(7bK803ep;ZCApYXnuYLQL!&AC_9XEmI0d*L+KmxiOMBpFjtU+ z%5!MpM@T4NM@ys|fM^#LK0<(;I4a+R#NH37a<79(Ca0CwdZLnRw4=XS^O zK}FP|-9*IaQ`hlUFxE%iLy@X^2L6Gu9X|5&Q$QerXs{ zd=*pYeU>PEC$noGDt0Vm4mE+|;BCx<9uyuvnCTZK5itQG={5ily(|jtK`Vy;D2ga` zyh;=uDT?iRg~;!aX!$xTk>ajs)z7HR>xAg_!d{|D<3)RyU|;vGXs@l6=(%punJm~K z579TPjuVyHL|qyqQHVp-ecBi67SUCSohZd3y19KY7%_-dn^>aNBC)#T1FUPr+O?hd zeq78u8sY%JE{^E@8xkK7zhJ8(Dhd}*(erSyi4&GxB$~2Iyz?Odjkzjr%v=lPh2m3h z!1~3B&&mX}=EQ(C91~yc-AW|Vi?161IOG#?ZyDlEt`Yy*mO?bDMWS7X7MIpad|Dv* z31Je)lmpX9N`aRy z|C1G!yezeyj|BBAr6sixUByXh!|b1ks^5_|efK4(4v@C+N5RN`scZ8fBK(bhL}fu|Wa+i5h~^)Z3FB}nt%#9T z`fD&|yJgjHP6efDve)K9Y?WQIjo@v5)JuAwx@gzG__v#-liW> z(BuIt8Z}^(+hoTkG-Cd%3T4;ypjsUxyB`3=@g4GL>1|ZBSe_d95|DPwGmdTrLtEvg z)5FlSN_nNACz39fZ+L4F(X4QJT?n+3m@IdG3IGX14(aPh~+mQG!l74%kRDVGN@{oKkSC}R4Tl#rb6xBilOh^ z1t1?q;AsH!%Tr8TVnW~#6?3VdC}xYou1DaZxr+Mp6QCh)#qP=2H`FQm+cy&hvdX|} z6u7WSnU{k+t2~wYJvcXS0jvW*@`fu{Mgw8YWMymI15_NTZ0Guj#vWC+H{3zM1Ii<2 zd=FftJigk6^`DhD->4$8t2ky}D=wI9PEn5DY7LxH+(8tO%nhlxLR<^Ez`moH_hDSn zkxUf0nwvTZEt_zX)6d2j&h6p!4)>4T1}>!^6qf$PnJPh9R4BKxq8b1UTWtF_);}%I}isRRxMmrfZlwi%DKA?>h4ns+Z&0J zW~mDHCBm^wwedtP(Xgqity6Wlpkh^9vu6{{c}w+yyQh((Rc$u3W`3&b5M#&KK0jb9 z6{;g%0GLy(I+qW-AXL?%1<>KU9jZ%}ofv~JRQJ=6$a|^kekVTo{HB&){RpD+Rcl_v z+ACc>)N%zE&>nT*P6QtItvb}%f;T~~PBB|S{dM)S=A8gouP(S(MKtxCx+19t`~K<+ zr^0ZfiF>p^ZKbeTuk(yXdb+@y|wuw&l!Y^t4;s zIzxj>Kh?JRH$vq*w1~>PvDrP$~Wti58=&z+$!+JL_V+U8g)!#m@JQeoq{Rc{g&-YyQJM z7YtsPryo@?ykDhXwy`a%IqQy7$NMw6&PjZ@&h5(=mzqsN7@sT@$E5;nGF$LA^r*7~0^d{(T{A58PeYEJE_W!xn6E1rUy^O9ZQ zjr>!o@IeU{i>;J5S}Z)^+LoKGx&PtT&I@HGp%9YDv%$+|#Sg*lDjSelu)B+nFgKPJ ztK3rTm+Mcs(HMST>y`f-i6PHiEIbijP@=_VD)>K;JaJ{+zQL}#7+sKviE>`Hj&;3} HZ3z4~Y`=5Q diff --git a/src/translations/bitmessage_zh_cn.ts b/src/translations/bitmessage_zh_cn.ts index 9bb0e3e3..282d2578 100644 --- a/src/translations/bitmessage_zh_cn.ts +++ b/src/translations/bitmessage_zh_cn.ts @@ -59,12 +59,12 @@ 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: @@ -130,42 +130,42 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - + Bitmessage 比特信 - + Search 搜索 - + All 全部 - + To - + From 来自 - + Subject 标题 - + Message 消息 - + Received 接收时间 @@ -180,7 +180,7 @@ Please type the desiged email address (including @mailchuck.com) below: 从地址本中选择 - + Fetch Namecoin ID 接收Namecoin ID @@ -190,7 +190,7 @@ Please type the desiged email address (including @mailchuck.com) below: 消息: - + Subject: 标题: @@ -200,12 +200,12 @@ Please type the desiged email address (including @mailchuck.com) below: 发送给一个或更多指定的人 - + To: 至: - + From: 来自: @@ -215,7 +215,7 @@ Please type the desiged email address (including @mailchuck.com) below: 广播给全部订阅到您的地址的人 - + Send 发送 @@ -235,7 +235,7 @@ Please type the desiged email address (including @mailchuck.com) below: 已发送 - + New 新建 @@ -245,7 +245,7 @@ Please type the desiged email address (including @mailchuck.com) below: 标签(只有您看的到) - + Address 地址 @@ -265,7 +265,7 @@ Please type the desiged email address (including @mailchuck.com) below: 您可以在这里订阅到广播地址,接收来自其他用户的广播。消息将出现在您的收件箱。您的黑名单对在这里的地址无效。 - + Add new Subscription 添加新的订阅 @@ -275,7 +275,7 @@ Please type the desiged email address (including @mailchuck.com) below: 标签 - + Subscriptions 订阅 @@ -287,12 +287,12 @@ Please type the desiged email address (including @mailchuck.com) below: Add new entry - 添加新条目 + 添加新条目 Name or Label - 名称或标签 + 名称或标签 @@ -302,27 +302,27 @@ Please type the desiged email address (including @mailchuck.com) below: 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 - 连接 + 连接 @@ -352,70 +352,70 @@ Please type the desiged email address (including @mailchuck.com) below: Inventory lookups per second: 0 - 每秒种的同步请求数: 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 加入或创建一个频道 @@ -425,94 +425,94 @@ Please type the desiged email address (including @mailchuck.com) below: 回复 - + 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 + 自启动于 %1 @@ -520,12 +520,12 @@ Please type the desiged email address (including @mailchuck.com) below: 正在等待他们的加密密钥,我们会在稍后再次请求。 - + Encryption key request queued. 加密密钥请求已经添加到队列中。 - + Queued. 已经添加到队列。 @@ -535,311 +535,311 @@ Please type the desiged email address (including @mailchuck.com) below: 消息已经发送. 正在等待回执. 发送于 %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 个点对点消息。 + 处理了 %1 个点对点消息。 Processed %1 broadcast messages. - 处理了 %1 个广播。 + 处理了 %1 个广播。 Processed %1 public keys. - 处理了 %1 个公匙。 + 处理了 %1 个公匙。 Total Connections: %1 - 总连接数: %1 + 总连接数: %1 Inventory lookups per second: %1 - 每秒种的同步请求数: %1 + 每秒种的同步请求数: %1 - + Connection lost 连接已丢失 - + Connected 已经连接 - + Message trashed 消息已经移入回收站 - + 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: 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. 警告: 您尚未连接。 比特信将做足够的功来发送消息,但是消息不会被发出直到您连接。 - + 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接收了地址。 @@ -849,27 +849,27 @@ It is important that you back up this file. Would you like to open the file now? 做工已经添加到队列中。 %1 - + New Message 新消息 - + From 来自 - + 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. 错误:您无法将一个地址添加到您的地址本两次,请尝试重命名已经存在的那个。 @@ -879,207 +879,207 @@ It is important that you back up this file. Would you like to open the file now? 错误:您无法将一个地址添加到您的订阅两次,也许您想重命名已经存在的那个。 - + 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). 比特信将会从现在开始使用代理,但是您可能想手动重启比特信以便使之前的连接关闭(如果有的话)。 - + 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. 请注意,您所输入的时间限制小于比特信的最小重试时间,因此您将永远不会重发消息。 Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - 错误:您无法将一个地址添加到您的列表两次,也许您想重命名已经存在的那个。 + 错误:您无法将一个地址添加到您的列表两次,也许您想重命名已经存在的那个。 - + 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. 条目已经添加到地址本。您可以去修改您的标签。 - + Moved items to trash. 已经移动项目到回收站。 - + Save As... 另存为... - + Write error. 写入失败。 - + No addresses selected. 没有选择地址。 - + 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. 在这个地址中编码的部分信息过长。 - + 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 。(可以在设置中修改)。 - + Waiting for their encryption key. Will request it again soon. 正在等待他们的加密密钥,我们会在稍后再次请求。 - + Message sent. Waiting for acknowledgement. Sent at %1 消息已经发送. 正在等待回执. 发送于 %1 @@ -1173,67 +1173,52 @@ Receiver's required difficulty: %1 and %2 正在发送公钥请求. 等待回应中. 请求于 %1 - + Reply to sender - + Reply to channel - + Add sender to your Blacklist - + Undelete - + Email gateway - + 1 hour - + %1 hours - + %1 days - + Channel - - Objects to be synced: %1 - - - - - Down: %1/s Total: %2 - - - - - Up: %1/s Total: %2 - - - - + 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 @@ -1241,121 +1226,121 @@ Receiver's required difficulty: %1 and %2 - + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Message queued. - + Sending email gateway registration request - + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - + Number needed - + Your maximum download and upload rate must be numbers. Ignoring what you typed. - + Sending email gateway unregistration request - + Sending email gateway status request - + 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. - + Undeleted item. - + 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? - + Some data encoded in the address is malformed. - + Identities - + New Identity - + Messages - + Address book - + Add Contact - + <!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; } @@ -1364,77 +1349,37 @@ p, li { white-space: pre-wrap; } - + Send ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Chans - + Add Chan - - Total connections: - - - - - Since startup: - - - - - Objects to be synced: - - - - - Processed 0 person-to-person messages. - - - - - Processed 0 public keys. - - - - - Processed 0 broadcasts. - - - - - Down: 0 KB/s - - - - - Up: 0 KB/s - - - - + Contact support @@ -1711,6 +1656,64 @@ 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 + 每秒种的同步请求数: 0 + + + + Down: 0 KB/s + + + + + Up: 0 KB/s + + + + + Objects to be synced: + + + + + Stream # + 节点流 # + + + + Connections + 连接 + + newChanDialog -- 2.45.1 From 0f267c94c7fa6bfb14234ebf84de994b32161eba Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 23 Mar 2016 10:16:17 +0100 Subject: [PATCH 0342/1102] Translations update - added Danish translation (thanks @mirrorwish) - added English translation (to serve as a source for other translations) --- src/translations/bitmessage.pro | 1 + src/translations/bitmessage_da.qm | Bin 0 -> 53492 bytes src/translations/bitmessage_da.ts | 1954 +++++++++++++++++++++++++++++ src/translations/bitmessage_en.qm | Bin 0 -> 23 bytes src/translations/bitmessage_en.ts | 1820 +++++++++++++++++++++++++++ 5 files changed, 3775 insertions(+) create mode 100644 src/translations/bitmessage_da.qm create mode 100644 src/translations/bitmessage_da.ts create mode 100644 src/translations/bitmessage_en.qm create mode 100644 src/translations/bitmessage_en.ts diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 87913801..9e5dc7d9 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -42,6 +42,7 @@ FORMS = \ TRANSLATIONS = \ bitmessage_ar.ts \ bitmessage_cs.ts \ + bitmessage_da.ts \ bitmessage_de.ts \ bitmessage_en.ts \ bitmessage_en_pirate.ts \ diff --git a/src/translations/bitmessage_da.qm b/src/translations/bitmessage_da.qm new file mode 100644 index 0000000000000000000000000000000000000000..844be3adc37c4a037467a02eb7d39d8238e1a7f0 GIT binary patch literal 53492 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
-%D?U^C8fkCPO9a7N}Mv_KF@u{8C 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 BYfAtC literal 0 HcmV?d00001 diff --git a/src/translations/bitmessage_da.ts b/src/translations/bitmessage_da.ts new file mode 100644 index 00000000..60145cef --- /dev/null +++ b/src/translations/bitmessage_da.ts @@ -0,0 +1,1954 @@ + + + + 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 desiged 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 + + + + Add new entry + Tilføj nyt element + + + + 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? + + + + Since startup on %1 + Siden opstart + + + + 1 hour + 1 time + + + + %1 hours + %1 timer + + + + %1 days + %1 dage + + + + 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 + + + + Objects to be synced: %1 + Objekter der skal synkroniseres: %1 + + + + Processed %1 person-to-person messages. + %1 person-til-person-beskeder behandlet. + + + + Processed %1 broadcast messages. + %1 broadcast-beskeder behandlet. + + + + Processed %1 public keys. + %1 offentlige nøgler behandlet. + + + + Down: %1/s Total: %2 + Download: %1/s Total: %2 + + + + Up: %1/s Total: %2 + Upload: %1/s Total: %2 + + + + Total Connections: %1 + Totalt antal forbindelser: %1 + + + + Inventory lookups per second: %1 + Opslag i objektdatabasen per sekund: %1 + + + + 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. + + + + All done. Closing user interface... + Udført. Afslutter brugergrænseflade... + + + + 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 + + + + Display the %1 recent broadcast from this address. + Vis den %1 nyeste broadcast-besked fra denne adresse. + + + + Display the %1 recent broadcasts from this address. + Vis de %1 nyeste 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: + + + + <!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 ordinary Message + Send almindelig besked + + + + Send Message to your Subscribers + Send besked til dine abonnenter + + + + TTL: + TTL: + + + + X days + X dage + + + + Subscriptions + Abonnementer + + + + Add new Subscription + Tilføj nyt abonnement + + + + Chans + Kanaler + + + + Add Chan + TIlføj kanal + + + + Use a Blacklist (Allow all incoming messages except those on the Blacklist) + Brug en sortliste (Tillad beskeder fra alle afsendere bortset fra dem på din sortliste) + + + + Use a Whitelist (Block all incoming messages except those on the Whitelist) + Brug en hvidliste (Bloker beskeder fra alle afsendere bortset fra dem på din hvidliste) + + + + Name or Label + Navn eller beskrivelse + + + + Blacklist + Sortliste + + + + Stream # + Flod # + + + + Connections + Forbindelser + + + + Total connections: + Totalt antal forbindelser: + + + + Since startup: + Siden opstart: + + + + Objects to be synced: + Objekter der skal synkroniseres: + + + + Processed 0 person-to-person messages. + 0 person-til-person-beskeder behandlet. + + + + Processed 0 public keys. + 0 offentlige nøgler behandlet. + + + + Processed 0 broadcasts. + 0 broadcast-beskeder behandlet. + + + + Inventory lookups per second: 0 + Opslag i objektdatabasen per sekund: 0 + + + + Down: 0 KB/s + Download: 0 KB/s + + + + Up: 0 KB/s + Upload: 0 KB/s + + + + Network Status + Netværksstatus + + + + 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% + + + + 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 + + + + CheckBox + + + + + 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: + + + + aboutDialog + + + About + Om + + + + PyBitmessage + PyBitmessage + + + + version ? + version ? + + + + <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 Bitmessage-udviklerne</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>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. + + + + 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: + Totalt antal forbindelser: + + + + Since startup: + Siden opstart: + + + + Processed 0 person-to-person messages. + 0 person-til-person-beskeder behandlet. + + + + Processed 0 public keys. + 0 offentlige nøgler behandlet. + + + + Processed 0 broadcasts. + 0 broadcast-beskeder behandlet. + + + + Inventory lookups per second: 0 + Opslag i objektdatabasen per sekund: 0 + + + + Down: 0 KB/s + Download: 0 KB/s + + + + Up: 0 KB/s + Upload: 0 KB/s + + + + Objects to be synced: + Objekter der skal synkroniseres: + + + + Stream # + Flod # + + + + Connections + Forbindelser + + + + 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 + + + + Pirate English + en_pirate + Piratengelsk + + + + Other (set in keys.dat) + other + Andet (indstillet i keys.dat) + + + + 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_en.qm b/src/translations/bitmessage_en.qm new file mode 100644 index 0000000000000000000000000000000000000000..9dad8dffceb9623e88f8b96d9cd0caf25574c6fa GIT binary patch literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ literal 0 HcmV?d00001 diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts new file mode 100644 index 00000000..51336976 --- /dev/null +++ b/src/translations/bitmessage_en.ts @@ -0,0 +1,1820 @@ + + + + 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 desiged 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. + + + + + Display the %1 recent broadcast from this address. + + + + + Display the %1 recent broadcasts from this address. + + + + + 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: + + + + + <!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 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% + + + + + 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 + + + + + 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: + + + + + 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. + + + + + 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 + + + + + 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 + + + + -- 2.45.1 From 8b605a874aab66c5a8ad056559cd090f28ed7a2e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 10:46:26 +0100 Subject: [PATCH 0343/1102] Translation updates - add missing files into translation definition - refresh english strings - change context for "networkstatus" --- src/bitmessageqt/networkstatus.py | 22 +++--- src/translations/bitmessage.pro | 3 + src/translations/bitmessage_en.ts | 107 ++++++++++++++++++++++++++++-- 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index cadff96a..b51714d6 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -11,7 +11,7 @@ class NetworkStatus(QtGui.QWidget): super(NetworkStatus, self).__init__(parent) widgets.load('networkstatus.ui', self) - self.labelStartupTime.setText(_translate("MainWindow", "Since startup on %1").arg( + self.labelStartupTime.setText(_translate("networkstatus", "Since startup on %1").arg( l10n.formatTimestamp())) self.UISignalThread = UISignaler.get() @@ -43,19 +43,19 @@ class NetworkStatus(QtGui.QWidget): return "%4.0f KB" % num def updateNumberOfMessagesProcessed(self): - self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelSyncStatus.setText(_translate("networkstatus", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.labelMessageCount.setText(_translate( - "MainWindow", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) + "networkstatus", "Processed %1 person-to-person messages.").arg(str(shared.numberOfMessagesProcessed))) def updateNumberOfBroadcastsProcessed(self): - self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelSyncStatus.setText(_translate("networkstatus", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.labelBroadcastCount.setText(_translate( - "MainWindow", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) + "networkstatus", "Processed %1 broadcast messages.").arg(str(shared.numberOfBroadcastsProcessed))) def updateNumberOfPubkeysProcessed(self): - self.labelSyncStatus.setText(_translate("MainWindow", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) + self.labelSyncStatus.setText(_translate("networkstatus", "Objects to be synced: %1").arg(str(sum(shared.numberOfObjectsThatWeHaveYetToGetPerPeer.itervalues())))) self.labelPubkeyCount.setText(_translate( - "MainWindow", "Processed %1 public keys.").arg(str(shared.numberOfPubkeysProcessed))) + "networkstatus", "Processed %1 public keys.").arg(str(shared.numberOfPubkeysProcessed))) def updateNumberOfBytes(self): """ @@ -63,9 +63,9 @@ class NetworkStatus(QtGui.QWidget): sent and received by 2. """ self.labelBytesRecvCount.setText(_translate( - "MainWindow", "Down: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesReceived/2), self.formatBytes(self.totalNumberOfBytesReceived))) + "networkstatus", "Down: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesReceived/2), self.formatBytes(self.totalNumberOfBytesReceived))) self.labelBytesSentCount.setText(_translate( - "MainWindow", "Up: %1/s Total: %2").arg(self.formatByteRate(shared.numberOfBytesSent/2), self.formatBytes(self.totalNumberOfBytesSent))) + "networkstatus", "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 @@ -112,7 +112,7 @@ class NetworkStatus(QtGui.QWidget): self.tableWidgetConnectionCount.setItem(0,1,newItem) totalNumberOfConnectionsFromAllStreams += connectionCount""" self.labelTotalConnections.setText(_translate( - "MainWindow", "Total Connections: %1").arg(str(len(shared.connectedHostsList)))) + "networkstatus", "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.window().setStatusIcon('yellow') elif len(shared.connectedHostsList) == 0: @@ -121,6 +121,6 @@ class NetworkStatus(QtGui.QWidget): # timer driven def runEveryTwoSeconds(self): self.labelLookupsPerSecond.setText(_translate( - "MainWindow", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) + "networkstatus", "Inventory lookups per second: %1").arg(str(shared.numberOfInventoryLookupsPerformed/2))) shared.numberOfInventoryLookupsPerformed = 0 self.updateNumberOfBytes() diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 9e5dc7d9..875388f4 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -21,6 +21,7 @@ SOURCES = ../addresses.py\ ../bitmessageqt/account.py\ ../bitmessageqt/addaddressdialog.py\ ../bitmessageqt/bitmessageui.py\ + ../bitmessageqt/blacklist.py\ ../bitmessageqt/connect.py\ ../bitmessageqt/emailgateway.py\ ../bitmessageqt/foldertree.py\ @@ -28,6 +29,7 @@ SOURCES = ../addresses.py\ ../bitmessageqt/iconglossary.py\ ../bitmessageqt/messagecompose.py\ ../bitmessageqt/messageview.py\ + ../bitmessageqt/networkstatus.py\ ../bitmessageqt/newaddressdialog.py\ ../bitmessageqt/newchandialog.py\ ../bitmessageqt/newsubscriptiondialog.py\ @@ -37,6 +39,7 @@ SOURCES = ../addresses.py\ ../bitmessageqt/specialaddressbehavior.py FORMS = \ + ../bitmessageqt/blacklist.ui\ ../bitmessageqt/networkstatus.ui TRANSLATIONS = \ diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index 51336976..701d8671 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -180,22 +180,22 @@ Please type the desiged email address (including @mailchuck.com) below: - + Enable - + Disable - + Set avatar... - + Copy address to clipboard @@ -210,7 +210,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Delete @@ -627,12 +627,12 @@ It is important that you back up this file. Would you like to open the file now? - + Address is valid. - + The address you entered was invalid. Ignoring it. @@ -1104,6 +1104,16 @@ p, li { white-space: pre-wrap; } 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 + + NewAddressDialog @@ -1288,6 +1298,44 @@ The 'Random Number' option is selected by default but deterministic ad + + 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 @@ -1414,6 +1462,51 @@ The 'Random Number' option is selected by default but deterministic ad 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 -- 2.45.1 From ecfa18b1c6d8dfd565ab625b3bb600d2d792310f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 10:49:03 +0100 Subject: [PATCH 0344/1102] Change UI loading for frozen --- src/bitmessageqt/widgets.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bitmessageqt/widgets.py b/src/bitmessageqt/widgets.py index 7919d7f9..02394296 100644 --- a/src/bitmessageqt/widgets.py +++ b/src/bitmessageqt/widgets.py @@ -1,14 +1,13 @@ from PyQt4 import uic import os.path import sys +from shared import codePath +def resource_path(resFile): + baseDir = 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 resource_path(path): - try: - return os.path.join(sys._MEIPASS, path) - except: - return os.path.join(os.path.dirname(__file__), path) - - -def load(path, widget): - uic.loadUi(resource_path(path), widget) +def load(resFile, widget): + uic.loadUi(resource_path(resFile), widget) -- 2.45.1 From 412e175f27cb7a9bc7f9161fb2b1515188c05c0d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 13:33:03 +0100 Subject: [PATCH 0345/1102] Translation updates Added a RetranslateMixin. Since PyQT does not support automated language changes of UI files (like the C++ QT does), this implements something similar. It assumes that the UI file has the same name as the class, but lowercase. Added RetraslateMixin to the new blacklist and networkstatus interfaces. --- src/bitmessageqt/bitmessageui.py | 2 ++ src/bitmessageqt/blacklist.py | 3 ++- src/bitmessageqt/networkstatus.py | 3 ++- src/bitmessageqt/retranslateui.py | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/bitmessageqt/retranslateui.py diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index b8547c22..5a8ae31f 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -726,6 +726,8 @@ class Ui_MainWindow(object): item.setText(_translate("MainWindow", "Received", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.chans), _translate("MainWindow", "Chans", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.networkstatus), _translate("MainWindow", "Network Status", None)) + self.blackwhitelist.retranslateUi() + self.networkstatus.retranslateUi() self.menuFile.setTitle(_translate("MainWindow", "File", None)) self.menuSettings.setTitle(_translate("MainWindow", "Settings", None)) self.menuHelp.setTitle(_translate("MainWindow", "Help", None)) diff --git a/src/bitmessageqt/blacklist.py b/src/bitmessageqt/blacklist.py index 11fdb201..1e4be35a 100644 --- a/src/bitmessageqt/blacklist.py +++ b/src/bitmessageqt/blacklist.py @@ -7,11 +7,12 @@ import widgets from addresses import addBMIfNotPresent 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): +class Blacklist(QtGui.QWidget, RetranslateMixin): def __init__(self, parent=None): super(Blacklist, self).__init__(parent) widgets.load('blacklist.ui', self) diff --git a/src/bitmessageqt/networkstatus.py b/src/bitmessageqt/networkstatus.py index b51714d6..574af66b 100644 --- a/src/bitmessageqt/networkstatus.py +++ b/src/bitmessageqt/networkstatus.py @@ -2,11 +2,12 @@ from PyQt4 import QtCore, QtGui import shared from tr import _translate import l10n +from retranslateui import RetranslateMixin from uisignaler import UISignaler import widgets -class NetworkStatus(QtGui.QWidget): +class NetworkStatus(QtGui.QWidget, RetranslateMixin): def __init__(self, parent=None): super(NetworkStatus, self).__init__(parent) widgets.load('networkstatus.ui', self) diff --git a/src/bitmessageqt/retranslateui.py b/src/bitmessageqt/retranslateui.py new file mode 100644 index 00000000..e9d5bb3a --- /dev/null +++ b/src/bitmessageqt/retranslateui.py @@ -0,0 +1,18 @@ +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()) -- 2.45.1 From c30433cdaa595b480003163d4937e9a1d925e3e4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 14:04:00 +0100 Subject: [PATCH 0346/1102] "All accounts" internationalisation fix --- src/bitmessageqt/foldertree.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitmessageqt/foldertree.py b/src/bitmessageqt/foldertree.py index f9ab7717..c815b421 100644 --- a/src/bitmessageqt/foldertree.py +++ b/src/bitmessageqt/foldertree.py @@ -168,7 +168,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): def _getLabel(self): if self.address is None: - return unicode(str(QtGui.QApplication.translate("MainWindow", "All accounts")), 'utf-8') + return unicode(QtGui.QApplication.translate("MainWindow", "All accounts").toUtf8(), 'utf-8', 'ignore') else: try: return unicode(shared.config.get(self.address, 'label'), 'utf-8', 'ignore') @@ -196,7 +196,7 @@ class Ui_AddressWidget(QtGui.QTreeWidgetItem, AccountMixin, SettingsMixin): return self._getLabel() + self._getAddressBracket(False) elif role == QtCore.Qt.DecorationRole: if self.address is None: - return avatarize(self._getLabel()) + return avatarize(self._getLabel().encode('utf8')) else: return avatarize(self.address) elif role == QtCore.Qt.FontRole: @@ -476,4 +476,4 @@ class Ui_AddressBookWidgetItemLabel(Ui_AddressBookWidgetItem): class Ui_AddressBookWidgetItemAddress(Ui_AddressBookWidgetItem): def __init__ (self, address, label, type): Ui_AddressBookWidgetItem.__init__(self, address, type) - self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) \ No newline at end of file + self.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) -- 2.45.1 From de14730ad946c9ffab47d42731c1f071260de4d5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 14:24:57 +0100 Subject: [PATCH 0347/1102] Translations update - synced with Transifex --- src/translations/bitmessage_cs.qm | Bin 56716 -> 56765 bytes src/translations/bitmessage_cs.ts | 1296 ++++++++++------------ src/translations/bitmessage_de.qm | Bin 68129 -> 74934 bytes src/translations/bitmessage_de.ts | 1714 ++++++++++++----------------- src/translations/bitmessage_en.ts | 66 +- 5 files changed, 1324 insertions(+), 1752 deletions(-) mode change 100755 => 100644 src/translations/bitmessage_cs.ts diff --git a/src/translations/bitmessage_cs.qm b/src/translations/bitmessage_cs.qm index fe3ca8e9782c0318ba64a3f3afd3cfcc89724f14..4ae7368554f3829ec93566c69067fadfcb2273c4 100644 GIT binary patch delta 2616 zcmb7Gdst2B8vm`m*4nqV_TDrlVrUR1l}e(FO*c_&aw#Lyb-L(+q>|c{OC^*oL^_Sz zam{7BCDO=*8XeR`IcUxqW_YTZW5^uGW!~)PIrE%9&ma5wJ>R#!@4fuq-}`>Mpo+a* z#TJ_De+J+Ll#K?@hR|1$+SqjL!yNO6RrJ;E(MG>fS(lm<5{6APe*X^v!zo_W2D+%Yvm* z3uN14NYi^@L^p=XX+2{-Mp`ujQ>!uRrUTH|49-Pm6qF;zw&Vb-w!nA$HGs)5;fB7L zUi>QsatzbAD+!x1BW@*d?j2^OU7}>SnlP&`0`udbN6jMy#nORqc3|FFa;VC~0%<E0~@ONPpw z(6ez)itv7E$dlwR8QF ztAS5vaud#b1684%myW1hk;F~8MYXgI;-XGCkcz#y#R6r#p_og3N0csU;L`RtQmt=r zxvs>h>jv)V76#~ZhC60=fba=-A}0vgbBr^Vngg?%^xQWcpOb@1?pnGHQ5ej%m{F#) z(s||qIq3D6AN%W0>d-vit)5i9^*-+&L$&q3&U?Pp0cLr;e|s}&#Dx#ZI!l^(#zzJb z)#IP@No7XBasa>DnF2a)$>*#lCTg?!oo?hWCY0ax8=c#yPvdvzk^}7~z9Nq&hsFHG zXmaeC&Npr(6<>1VZ&|KsLJk607cduB_G zn?C_o-jts2so91AY4Z^?YRj9_hk+E(m27F3lnnacm6;V%*SJ2AjrXO}^m3FRUnTvQ;L`EHPp38rjt`l-bQ<*-yG2s%vDgZ7ASKZ@KH?A;f^We4O-Ol$oD= zwstOc%S!o|)!T@v8S+#g3f%FSJR?d6Ctv?-ub2s=s#TEoxPM8TOoh@ zkZ?eX!u;uM>Vlz){(tRh+sBGw4HTF|wPNgo2*BP+F%2Jppj(P$9oZiluh{jyehi5z zMN$3*ec13?IV^`V%zLYh>X=59dn;oi$Hg zP^xet=8VFP)l~cWV}u+3Acs@kgnK1A;6T36n%+esRS0cUiph^o=r9{jiJleo9oD4s zGghKwAUXE9C{D8L$+Sb9m${e*#b`0|)gl@o2gIoDWk4(^ExC zt!N-+i`&BefRu9abWh22?&5_cqC8`oSj8k$Tb?xGHK};noC4Y-7wfhjBIf+`;_W!v z&=-n#G!)_JTVm_0Pl3xR;)9GPn&o%J*K^46kU;Tu6MeUNp^`s6OX9IpsVCF=v&X9b z@juewiBJtIAxHKvRQ84=^j6rb0%8;CwQNu=I#fadho}~JX93}rsw6!Ppi$3ME4{W* zDfF9FE%gpGa*I?yZV3mx>Qw)ZnFQp%P@{$%lr^b`cY*Bw#>PGWGp>7;SZ3mc8^4Nr#?k3ddI;dN9 z*+BXf6YhJZZjTHB2Hscy5-^lzf1SoTF$Jis){MD9)Se%$@jpkIINj6C*sle`?rY|s ztOhn)X^z}_4;=hSQ{k%ya_Th~29=S@Pid-_cLB3QHCHVNr{`(jY+6gNtrrQU`6SO$ zXd?`_l@^8%YaI;kiuKWb;DZE&Ar|qlMmUz?2P7g)-jjrsekz}Yu-JI(=&UfpACEr(a|!l= delta 2768 zcmaJ@dstL;8h+25bLMu=%p@X)nog1=UI1AQZ=m8Gb-Y8CH(IzupscpDUD6=(%V z2^CpGCDYQ9H7^LLn3Wc*i&;?agS)A%31%vqPwKu%kI%EaPy5HrH^1Nc{l4%0-tYas zGZp1xZn>D}?fwQpAE4L=kn(}GOod|_A&7C0r=~=whckg4mAXmhM>;_f%YbZnZU9!7+r9h zXwSCVwHGj9^G^g~$AkhS?OT|buoU?CJ4{(}oaZ*S+T|Azm7M@LPE;T|o(E1Y#;b=I zP+fzW+HBz5DkMFkgQ9nkUc$hBK3G=j28`pe+_4on+Kj>_oq?R`I9oLv=;Dp~>iuM_ z5|=wBkkQd-{-g;Q+b9@z+y%V*2wggmk-#THchwI_tq?-y-k`&E^+Mm3ba?uRFt80B z4E|9VHZznL-xO?@c%f~)Fn2}?nOP*vgBkckAHgwz421g%>t_W5^HvM_?P`G0al*C_ zn8>*Rp?nu94l5NNHZb8)rNR@lM{N z)nm=&bH2cd37TtC3b4YgX)I_@JzW*mTp9R6FPbhKBtv1MWo<2=ZxOBTqHtikEWX%( zC*YC9;M$KEI8A)Txe_RwD~8#uy!eqgY)&08%PnsCm4Jqoh{dzlGJ{d#F_pEiIw78Y zo9o^q#TuO*Q0BMVtm|T3($}AVMl7b^ z$ilY_V5yfwe<}omBjf>Rsp5Q-JTOiKhG)nTcWpqMHS)NIi_}DrJbUFKYM?}pjV9Ft zcgoJEbt8Dye5MlKw{fD3%(t#^2CXSBR+9sP%mlJ~Ed8PA<3A6vk{ z!$Rbm9IE#CbMpBeeK`w!jvoDb8r&aXn)B@eWzc@$%Hfwm~}D)6_X+FjrMm6V&bd#z-8dx*B|Pi@)% z>8rJeTWXeN)Lz`{#Wvidy&OeARWaHoEgeSY=)CgSCH*$(290KEEIoA->T1{}rMjrR z6~NLHI(wgZ;8?b9Sr;>BnMRlS=OMuJ8M>_T6yqm7bUAT=!vZbUrqk-oq7HZuy)PYs{WE}5a9 zQMri>Me5T=1_D8L{W7}^F!<`TcfLk#T-E3IpoZS)q4%6%;Q90Q2fgUWGev*AJRBHs zOMiCHX~rL9)t_^BCbf0?`YZ=)`m?@%3)lX0^otnRvbdM+1e#W?12Kv-&OlaW2#gAKUNuhCh|8P2b&bUAPA^ZBa@u+eah^RIm zExN-&5@M{*D5K+t#>Tf-0)M%p2ov^m5cO0H=`5*FonjO(0R6vEp5MyEq&UU@ZYAe| zN9kTM8|Ve8E7`yZ70F`F51tkUof#g@NEx#{&X z@W&ga6rYVo90CVt{LjVmQs$tqaJax6ia2bTu5O_<6CX@RkgyK z0E@1xXEyGk*aO_^`2=pP9IIZi5OGMBT6gaSpkkW(?Xp_V@{iQ}(+HreMZI6k=P&Iu z>8~9E>{m_ZQCwRKO&u40PqB3}`EOyMUi(bFJ$u=$8Ui8`5k zw7g_`^)-)a&L+ie&6B{A6!kN2xW)a6-sT;z_h)}6n2$bs04(2N{-S6A=R>%;CWvjw zq5jk^yJN1i@tw0oXtmCr7tIZ^vw;`#&9^4M#G353gg8?9dfjg6_Zg`?>}47EF_8!7 zStjlZ2j=EmUi+{T$en1}`{iSx^o(WyXfv=n({iLsG1Z=6DR(vT|ADXNR6E-75tfH< zt>N3XD}{1#gXfAe#uI7CDqCfY70L#v*L=!i{Aw2o-kw!K-kzj9gD1D0rR-|H$LNL^ zCJ8eTk0dye06QFL)VE}!yg2=6|mq4h9F*Pa0 znq*J5rr76OosL){`kmyS7gW!xR3G; Email gateway - + Email brána @@ -130,25 +130,35 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - - 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 to sender + - - Reply - Odpovědět + + 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 @@ -170,17 +180,22 @@ Please type the desiged email address (including @mailchuck.com) below: Nové - + Enable Zapnout - + Disable Vypnout - + + Set avatar... + Nastavit avatar... + + + Copy address to clipboard Zkopírovat adresu do clipboardu @@ -189,6 +204,16 @@ Please type the desiged email address (including @mailchuck.com) below: Special address behavior... Speciální chování adresy... + + + Email gateway + Email brána + + + + Delete + Odstranit + Send message to this address @@ -204,11 +229,6 @@ Please type the desiged email address (including @mailchuck.com) below: Add New Address Přidat novou adresu - - - Delete - Odstranit - Copy destination address to clipboard @@ -220,14 +240,24 @@ Please type the desiged email address (including @mailchuck.com) below: Přesto odeslat - - Add new entry - Přidat novou položku + + 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? - - Since startup on %1 - Od spuštění v %1 + + 1 hour + 1 hodina + + + + %1 hours + + + + + %1 days + %1 dní @@ -315,12 +345,12 @@ Please type the desiged email address (including @mailchuck.com) below: Přihlásit se k odběru - - Address Book - Adresář + + Channel + - + Quit Ukončit @@ -377,6 +407,21 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 @@ -442,26 +487,6 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 @@ -477,6 +502,29 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 @@ -507,6 +555,11 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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. @@ -542,6 +595,11 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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. @@ -557,11 +615,6 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 @@ -573,12 +626,17 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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í. @@ -588,9 +646,9 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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 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. + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + @@ -608,9 +666,34 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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). - - 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. + + Number needed + Je třeba zadat číslo + + + + 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 + @@ -662,11 +745,26 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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. + + + + + 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... @@ -682,6 +780,45 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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... @@ -722,6 +859,36 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev 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. + + + + Display the %1 recent broadcast from this address. + Zobrazit %1 zprávu nedávno rozeslanou z této adresy. + + + + Display the %1 recent broadcasts from this address. + Zobrazit %1 zpráv nedávno rozeslaných z této adresy. + You are using TCP port %1. (This can be changed in the settings). @@ -732,6 +899,16 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Bitmessage Bitmessage + + + Identities + + + + + New Identity + + Search @@ -767,501 +944,6 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev Received Doručeno - - - Inbox - Doručené - - - - Load from Address book - Vybrat z adresáře - - - - Fetch Namecoin ID - Načíst Namecoin ID - - - - Message: - Zpráva: - - - - Subject: - Předmět: - - - - Send to one or more specific people - Poslat jednomu nebo více konkrétním lidem - - - - To: - Komu: - - - - From: - Od: - - - - Broadcast to everyone who is subscribed to your address - Rozeslat všem, kteří odebírají Vaši adresu - - - - 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. - - - - 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 - - - - Label - Popiska - - - - 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 - - - - 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 - - - - Set avatar... - Nastavit avatar... - - - - 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. - - - - Inventory lookups per second: %1 - Počet kontrol inventáře za sekundu: %1 - - - - 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. - - - - 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. - - - - 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. - - - - Display the %1 recent broadcast from this address. - Zobrazit %1 zprávu nedávno rozeslanou z této adresy. - - - - Display the %1 recent broadcasts from this address. - Zobrazit %1 zpráv nedávno rozeslaných z této adresy. - - - - Inventory lookups per second: 0 - Počet kontrol inventáře za sekundu: 0 - - - - Down: %1/s Total: %2 - Stahování: %1/s Celkem: %2 - - - - Up: %1/s Total: %2 - Odesílání: %1/s Celkem: %2 - - - - 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: 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á. - - - - Number needed - Je třeba zadat číslo - - - - 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. - - - - Some data encoded in the address is malformed. - Některá data zakódovaná v této adrese mají neplatný formát. - - - - <!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> - - - - Down: 0 KB/s - Stahování: 0 KB/s - - - - Up: 0 KB/s - Odesílání: 0 KB/s - - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Blacklist - - - - - Undelete - - - - - Email gateway - - - - - 1 hour - - - - - %1 hours - - - - - %1 days - - - - - Channel - - - - - 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. - - - - - 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. - - - - - Message queued. - - - - - Sending email gateway registration request - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - 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. - - - - - Undeleted item. - - - - - 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? - - - - - Identities - - - - - New Identity - - Messages @@ -1272,11 +954,36 @@ Are you sure you want to delete the channel? Address book + + + Address + Adresa + Add Contact + + + Fetch Namecoin ID + Načíst Namecoin ID + + + + Subject: + Předmět: + + + + From: + Od: + + + + To: + Komu: + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> @@ -1306,6 +1013,16 @@ p, li { white-space: pre-wrap; } X days + + + Subscriptions + Odběry + + + + Add new Subscription + Přidat nový odběr + Chans @@ -1316,11 +1033,71 @@ p, li { white-space: pre-wrap; } Add Chan + + + 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 @@ -1331,6 +1108,16 @@ p, li { white-space: pre-wrap; } 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 + Přidat novou položku + NewAddressDialog @@ -1356,6 +1143,11 @@ 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 @@ -1366,6 +1158,11 @@ 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: @@ -1421,16 +1218,6 @@ 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 @@ -1485,6 +1272,11 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi aboutDialog + + + About + O aplikaci + PyBitmessage @@ -1496,9 +1288,9 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi verze ? - - About - O aplikaci + + <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> @@ -1510,15 +1302,43 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi This is Beta software. Toto je Beta software. + + + 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 Blacklist (Allow all incoming messages except those on the Blacklist) + - - <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> + + 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 + @@ -1553,19 +1373,14 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - <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> + <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: Protože Bitmessage je společně tvořený projekt, nápovědu najdete na webu na Bitmessage Wiki: - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - iconGlossaryDialog @@ -1579,6 +1394,11 @@ 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). @@ -1589,11 +1409,6 @@ 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. - - - 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. - networkstatus @@ -1625,17 +1440,17 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Inventory lookups per second: 0 - Počet kontrol inventáře za sekundu: 0 + Down: 0 KB/s - Stahování: 0 KB/s + Up: 0 KB/s - Odesílání: 0 KB/s + @@ -1645,12 +1460,57 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Stream # - Číslo proudu + Connections - Připojení + + + + + 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 + @@ -1718,6 +1578,11 @@ 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: @@ -1743,11 +1608,6 @@ 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 @@ -1761,6 +1621,11 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Start Bitmessage on user login Spustit Bitmessage po přihlášení uživatele + + + Tray + + Start Bitmessage in the tray (don't show main window) @@ -1771,6 +1636,11 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Minimize to tray Minimalizovat na lištu + + + Close to tray + + Show notification when message received @@ -1786,6 +1656,44 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi 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. + + + 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í + + + + Use Identicons + Používat identikony + + + + Reply below Quote + Odpověď pod citací + + + + Interface Language + Jazyk pro rozhraní + + + + System Settings + system + Dle nastavení systému + + + + Pirate English + en_pirate + Pirate English + + + + Other (set in keys.dat) + other + Jiný (nastavený v keys.dat) + User Interface @@ -1801,6 +1709,26 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Listen for connections on port: Naslouchat příchozím připojením na portu: + + + 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 @@ -1811,21 +1739,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Type: Typ: - - - none - žádný - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - Server hostname: @@ -1851,51 +1764,61 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi 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ě - - - 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: + + + 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í. - - - 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. @@ -1916,6 +1839,11 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi 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> @@ -1956,76 +1884,6 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Namecoin integration Integrace s Namecoin - - - Use Identicons - Používat identikony - - - - Interface Language - Jazyk pro rozhraní - - - - System Settings - system - Dle nastavení systému - - - - English - en - English - - - - Esperanto - eo - Esperanto - - - - Français - fr - Français - - - - Deutsch - de - Deutsch - - - - Españl - es - Españl - - - - русский язык - ru - русский язык - - - - Norsk - no - Norsk - - - - Pirate English - en_pirate - Pirate English - - - - Other (set in keys.dat) - other - Jiný (nastavený v keys.dat) - <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> @@ -2056,45 +1914,5 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi 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í] - - - - Tray - - - - - Close to tray - - - - - UPnP: - - - - - Hardware GPU acceleration (OpenCL) - - diff --git a/src/translations/bitmessage_de.qm b/src/translations/bitmessage_de.qm index 0e85dff8922e72f4adb46764142fa1bbe3f60dcc..44b0b06fb601ae1d251bf45863f3dc338d68973a 100644 GIT binary patch delta 7536 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 E4VZoC4gdfE delta 3366 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 Lr&@Oq_No2_7uVuy diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 2e9611cd..802f8774 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -131,25 +131,35 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: MainWindow - - 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 sender + Dem Absender Antworten - - Reply - Antworten + + Reply to channel + Antworten ins Chan 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 @@ -160,23 +170,33 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: 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 @@ -185,6 +205,16 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Special address behavior... Spezielles Verhalten der Adresse... + + + Email gateway + E-Mail Schnittstelle + + + + Delete + Löschen + Send message to this address @@ -200,11 +230,6 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Add New Address Neue Adresse hinzufügen - - - Delete - Löschen - Copy destination address to clipboard @@ -216,9 +241,24 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Senden erzwingen - - Add new entry - Neuen Eintrag erstellen + + 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? + + + + 1 hour + 1 Stunde + + + + %1 hours + %1 Stunden + + + + %1 days + %1 Tage @@ -240,6 +280,11 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Message sent. Waiting for acknowledgement. Sent at %1 Nachricht gesendet. Warte auf Bestätigung. Gesendet %1 + + + Message sent. Sent at %1 + Nachricht gesendet. gesendet am %1 + Need to do work to send message. Work is queued. @@ -280,11 +325,6 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Unknown status: %1 %2 Unbekannter Status: %1 %2 - - - Since startup on %1 - Seit Start der Anwendung am %1 - Not Connected @@ -306,12 +346,12 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Abonnieren - - Address Book - Adressbuch + + Channel + Chan - + Quit Schließen @@ -370,538 +410,19 @@ Es ist wichtig, dass Sie diese Datei sichern. Möchten Sie die Datei jetzt öffn 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. + + Bad address version number + Falsche Addressenversionnummer - - Processed %1 broadcast messages. - %1 Rundruf-Nachrichten bearbeitet. + + Your address version number must be a number: either 3 or 4. + Die Addressenversionnummer muss eine Zahl sein, entweder 3 oder 4. - - 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? - 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. - Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. - - - - Moved items to trash. - Objekt in den Papierkorb verschoben. - - - - 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 - - - - Label (not shown to anyone) - Bezeichnung (wird niemandem gezeigt) - - - - Address - Adresse - - - - Stream - Datenstrom - - - - Your Identities - Ihre Identitäten - - - - 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). - - - - Add new Subscription - Neues Abonnement anlegen - - - - Label - Bezeichnung - - - - Subscriptions - Abonnements - - - - 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. - - - - Name or Label - Name oder Bezeichnung - - - - 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 - Netzwerkstatus - - - - 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 + + Your address version number must be either 3 or 4. + Die Addressenversionnnummer muss entweder 3 oder 4 sein. @@ -969,64 +490,127 @@ p, li { white-space: pre-wrap; } 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. + + Connection lost + Verbindung verloren - - 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. + + Connected + Verbunden - - Search - Suchen + + Message trashed + Nachricht in den Papierkorb verschoben - - All - Alle + + 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. + Der Ablauf, oder Time-To-Live, ist die Dauer, für die das Netzwerk die Nachricht speichern wird. Der Empfänger muss es 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. Ein Time-To-Live von vier oder fünf Tage ist meist ausreichend. - - Message - Nachricht + + Message too long + Narchricht zu lang - - Join / Create chan - Chan beitreten / erstellen + + 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 versuchen zu senden ist %1 Byte zu lange. (Maximum 261.644 Bytes). Bitte kürzen Sie sie vor dem Senden ab. - - Encryption key was requested earlier. - Verschlüsselungscode wurde bereits angefragt. + + 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. - - Sending a request for the recipient's encryption key. - Sende eine Anfrage für den Verschlüsselungscode des Empfängers. + + Error: Bitmessage addresses start with BM- Please check %1 + Fehler: Bitmessage Adressen starten mit BM- Bitte überprüfen Sie %1 - - Doing work necessary to request encryption key. - Verrichte die benötigte Arbeit um den Verschlüsselungscode anzufragen. + + 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. - - Broadcasting 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). + + Error: The address %1 contains invalid characters. Please check it. + Fehler: Die Adresse %1 beinhaltet ungültig Zeichen. Bitte überprüfen. - - Sending public key request. Waiting for reply. Requested at %1 - Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 + + 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. - - Mark Unread - Als ungelesen markieren + + 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. + Fehler: Einige codierte Daten in der Adresse %1 sind ungültig. Es könnte etwas mit der Software Ihres Bekannten sein. + + + + 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". + + + + 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. + + + + 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 eine oder mehrere Einträge aus Ihrem Adressbuch und wählen Sie "Nachricht an diese Adresse senden". @@ -1034,49 +618,64 @@ p, li { white-space: pre-wrap; } Adresse aus Namecoin Identität geholt. - - Testing... - teste... + + New Message + Neue Nachricht - - Fetch Namecoin ID - Hole Namecoin ID + + From + Von - - Ctrl+Q - Strg+Q + + Sending email gateway registration request + E-Mailschnittstelle-Registrierungsantrag wird versandt. - - F1 - F1 + + Address is valid. + Adresse ist gültig. - - Set avatar... - Avatar wählen... + + The address you entered was invalid. Ignoring it. + Die von Ihnen eingegebene Adresse ist ungültig, sie wird ignoriert. - - Bad address version number - Falsche Addressenversionnummer + + 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. - - Your address version number must be a number: either 3 or 4. - Die Addressenversionnummer muss eine Zahl sein, entweder 3 oder 4. + + Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. + Fehler: Dieselbe Addresse kann nicht doppelt in die Abonnements eingetragen werden. Alternativ können Sie die bestehende umbenennen. - - Your address version number must be either 3 or 4. - Die Addressenversionnnummer muss entweder 3 oder 4 sein. + + Restart + Neustart - - Inventory lookups per second: %1 - Inventory lookups pro Sekunde: %1 + + 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. @@ -1088,6 +687,119 @@ p, li { white-space: pre-wrap; } 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 als die, die Bitmessage auf das erste Wiederversenden wartet. Deswegen werden Ihre Nachrichten nie wiederversendet. + + + Sending email gateway unregistration request + E-Mailschnittestelle-Abmeldeantrag wird versandt + + + + Sending email gateway status request + E-Mailschnittstelle Statusantrag wird versandt + + + + 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? + 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. + Eintrag dem Adressbuch hinzugefügt. Editieren Sie den Eintrag nach Belieben. + + + + 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. Alternativ können Sie die bestehende umbenennen. + + + + Moved items to trash. + Objekt 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, die bereits erhaltene Nachrichten werden unaufrufbar. Überlegen Sie sich vielleicht das Abonnement statdessen zu deaktivieren. 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. Überlegen Sie sich vielleicht das Chan statdessen zu deaktivieren. 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? @@ -1113,6 +825,51 @@ p, li { white-space: pre-wrap; } 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. + Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. + + + + 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. + + + + Some data encoded in the address is malformed. + Einige in der Adresse kodierten Daten sind ungültig. + Enter an address above. @@ -1121,188 +878,32 @@ p, li { white-space: pre-wrap; } Address is an old type. We cannot display its past broadcasts. - Alter Addressentyp. Wir können deren vorige Rundruf-Nachrichten nicht anzeigen. + 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. Display the %1 recent broadcast from this address. - + Die letzte %1 Rundrufe von dieser Addresse anzeigen. Display the %1 recent broadcasts from this address. - + Die letzten %1 Rundrufe von dieser Addresse anzeigen. - - Inventory lookups per second: 0 - Inventory lookups pro Sekunde: 0 + + 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). - - Reply to sender - Dem Absender Antworten - - - - Reply to channel - Antworten ins Chan - - - - Add sender to your Blacklist - Absender in die Blacklist eintragen - - - - Undelete - Wiederherstellen - - - - Email gateway - E-Mail Schnittstelle - - - - 1 hour - 1 Stunde - - - - %1 hours - %1 Stunden - - - - %1 days - %1 Tage - - - - Channel - Chan - - - - Objects to be synced: %1 - Zu synchronisierende Objektanzahl: %1 - - - - Down: %1/s Total: %2 - Herunter: %1/s Insg.: %2 - - - - Up: %1/s Total: %2 - Hoch: %1/s Insg.: %2 - - - - 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 - 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. - - - - - 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-Mailschnittstelle registriert. Registrierung als %1 wird versandt, bitte vor einem erneutem Sendeversuch auf die Registrierungsverarbeitung warten. - - - - Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Message queued. - Nachricht befindet sich in der Warteschleife. - - - - Sending email gateway registration request - E-Mailschnittstelle-Registrierungsantrag wird versandt. - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - Fehler: Dieselbe Addresse kann nicht doppelt in die Abonnements eingetragen werden. Alternativ können Sie die bestehende umbenennen. - - - - Number needed - Zahl erforderlich - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Sending email gateway unregistration request - E-Mailschnittestelle-Abmeldeantrag wird versandt - - - - Sending email gateway status request - E-Mailschnittstelle Statusantrag wird versandt - - - - 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. Alternativ können Sie die bestehende umbenennen. - - - - Undeleted item. - Nachricht wiederhergestellt. - - - - 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, die bereits erhaltene Nachrichten werden unaufrufbar. Überlegen Sie sich vielleicht das Abonnement statdessen zu deaktivieren. 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. Überlegen Sie sich vielleicht das Chan statdessen zu deaktivieren. 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? - - - - Some data encoded in the address is malformed. - + + Bitmessage + Bitmessage @@ -1314,6 +915,41 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? New Identity Neue Identität + + + Search + Suchen + + + + All + Alle + + + + To + An + + + + From + Von + + + + Subject + Betreff + + + + Message + Nachricht + + + + Received + Erhalten + Messages @@ -1324,11 +960,36 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Address book Addressbuch + + + Address + Adresse + Add Contact Kontakt hinzufügen + + + Fetch Namecoin ID + Hole Namecoin ID + + + + Subject: + Betreff: + + + + From: + Von: + + + + To: + An: + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> @@ -1346,17 +1007,27 @@ p, li { white-space: pre-wrap; } Send Message to your Subscribers - Nachricht an Abonnenten senden + Rundruf an Ihre Abonnenten senden TTL: - + Ablauf: X days - X Tage + X Tage + + + + Subscriptions + Abonnements + + + + Add new Subscription + Neues Abonnement anlegen @@ -1369,59 +1040,89 @@ p, li { white-space: pre-wrap; } Chan hinzufügen - - Total connections: - Verbindungen insgesamt: + + Network Status + Netzwerkstatus - - Since startup: - Seit Start: + + File + Datei - - Objects to be synced: - Zu synchronisierende Objektanzahl: - - - - 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. - - - - Down: 0 KB/s - Herunter: 0 KB/s - - - - Up: 0 KB/s - Hoch: 0 KB/s + + Settings + Einstellungen + Help + Hilfe + + + + Import keys + Schlüssel importieren + + + + Manage keys + Schlüssel verwalten + + + + Ctrl+Q + Strg+Q + + + + F1 + F1 + + + Contact support Unterstütung 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 @@ -1465,8 +1166,8 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei - Address version number: 3 - Adress-Versionsnummer: 3 + Address version number: 4 + Adress-Versionsnummer: 4 @@ -1523,11 +1224,6 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei (saves you some bandwidth and processing power) (Dies erspart Ihnen etwas an Bandbreite und Rechenleistung) - - - Address version number: 4 - Adress-Versionsnummer: 4 - NewSubscriptionDialog @@ -1597,10 +1293,10 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei version ? Version ? - - - Copyright © 2013 Jonathan Warren - Copyright © 2013 Jonathan Warren + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + @@ -1612,10 +1308,43 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei This is Beta software. Dies ist Beta-Software. + + + blacklist - - <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> - + + 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 + + + + Whitelist + Whitelist @@ -1650,19 +1379,14 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei - <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> + <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: Bitmessage ist ein kollaboratives Projekt. Hilfe finden Sie online im Bitmessage-Wiki: - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - iconGlossaryDialog @@ -1697,57 +1421,102 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Total connections: - Verbindungen insgesamt: + Verbindungen insgesamt: Since startup: - Seit Start: + Seit Start: Processed 0 person-to-person messages. - 0 Person-zu-Person-Nachrichten verarbeitet. + 0 Person-zu-Person-Nachrichten verarbeitet. Processed 0 public keys. - 0 öffentliche Schlüssel verarbeitet. + 0 öffentliche Schlüssel verarbeitet. Processed 0 broadcasts. - 0 Rundrufe verarbeitet. + 0 Rundrufe verarbeitet. Inventory lookups per second: 0 - Inventory lookups pro Sekunde: 0 + Inventory lookups pro Sekunde: 0 Down: 0 KB/s - Herunter: 0 KB/s + Herunter: 0 KB/s Up: 0 KB/s - Hoch: 0 KB/s + Hoch: 0 KB/s Objects to be synced: - Zu synchronisierende Objektanzahl: + Zu synchronisierende Objektanzahl: Stream # - Datenstrom # + Datenstrom # Connections - Verbindungen + Verbindungen + + + + Since startup on %1 + Seit Start der Anwendung am %1 + + + + Objects to be synced: %1 + Zu synchronisierende Objektanzahl: %1 + + + + 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. + + + + 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 @@ -1772,6 +1541,11 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Create a chan Chan erstellen + + + <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> + Chan name: @@ -1787,11 +1561,6 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Chan bitmessage address: Chan-Bitmessage-Adresse: - - - <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 @@ -1816,14 +1585,9 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Anzahl der Adressen, die basierend auf diesem Kennwortsatz erzeugt werden sollen: - - Address version Number: - Adress-Versionsnummer: - - - - 3 - 3 + + Address version number: + Adress-Versionsnummer: @@ -1850,11 +1614,6 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 @@ -1868,6 +1627,11 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Start Bitmessage on user login Bitmessage nach dem Hochfahren automatisch starten + + + Tray + Infobereich (Taskleiste) + Start Bitmessage in the tray (don't show main window) @@ -1878,6 +1642,11 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Minimize to tray In den Systemtray minimieren + + + Close to tray + Schliessen ins Infobereich + Show notification when message received @@ -1893,6 +1662,44 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 Bitcoinadresse) + + + + Reply below Quote + Antworte unter zitierter Nachricht + + + + Interface Language + Sprachauswahl + + + + System Settings + system + Vom System übernehmen + + + + Pirate English + en_pirate + Piraten-Englisch + + + + Other (set in keys.dat) + other + Andere (in keys.dat einstellen) + User Interface @@ -1908,6 +1715,26 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 @@ -1918,21 +1745,6 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Type: Typ: - - - none - keiner - - - - SOCKS4a - SOCKS4a - - - - SOCKS5 - SOCKS5 - Server hostname: @@ -1958,36 +1770,56 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 + Network Settings Netzwerkeinstellungen - - - 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: + + + 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. + 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 @@ -2014,14 +1846,9 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Maximale akzeptierte Schwierigkeit - - 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 + + Hardware GPU acceleration (OpenCL) + Hardwaregrafikkartenbeschleunigung (OpenCL) @@ -2063,43 +1890,10 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 - Vom System übernehmen - - - - Pirate English - en_pirate - - - - - Other (set in keys.dat) - other - Andere (in keys.dat einstellen) - <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>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> + <html><head/><body><p>Wenn der Empfänger eine Nachricht nicht bis zum Ablauf herunterlädt, zum Beisplel 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 Viederersandversuche 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> @@ -2124,47 +1918,7 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Resends Expire - Neusendung - - - - Reply below Quote - Antworte unter zitierter Nachricht - - - - 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 - - - - Tray - - - - - Close to tray - - - - - UPnP: - UPnP: - - - - Hardware GPU acceleration (OpenCL) - Hardwaregrafikkartenbeschleunigung (OpenCL) + Neusendungsablauf diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index 701d8671..2d24a692 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -180,22 +180,22 @@ Please type the desiged email address (including @mailchuck.com) below: - + Enable - + Disable - + Set avatar... - + Copy address to clipboard @@ -210,7 +210,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Delete @@ -350,7 +350,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Quit @@ -627,12 +627,12 @@ It is important that you back up this file. Would you like to open the file now? - + Address is valid. - + The address you entered was invalid. Ignoring it. @@ -1035,62 +1035,62 @@ p, li { white-space: pre-wrap; } - + File - + Settings - + Help - + Import keys - + Manage keys - + Ctrl+Q - + F1 - + Contact support - + About - + Regenerate deterministic addresses - + Delete all trashed messages - + Join / Create chan @@ -1105,12 +1105,12 @@ p, li { white-space: pre-wrap; } - + Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - + Add new entry @@ -1326,12 +1326,12 @@ The 'Random Number' option is selected by default but deterministic ad - + Blacklist - + Whitelist @@ -1463,47 +1463,47 @@ The 'Random Number' option is selected by default but deterministic ad - + 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 -- 2.45.1 From 858e93befd7b0cadf11227364832d89e71bfffb1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 15:29:21 +0100 Subject: [PATCH 0348/1102] Update build scripts - PyInstaller script (e.g. for Windows) - build_osx.sh for OSX --- pyinstaller/bitmessagemain.spec | 58 +++++++++++++++++++++++++++++++++ src/build_osx.py | 1 + 2 files changed, 59 insertions(+) create mode 100644 pyinstaller/bitmessagemain.spec diff --git a/pyinstaller/bitmessagemain.spec b/pyinstaller/bitmessagemain.spec new file mode 100644 index 00000000..0b41bb00 --- /dev/null +++ b/pyinstaller/bitmessagemain.spec @@ -0,0 +1,58 @@ +srcPath = "C:\\src\\PyBitmessage\\src\\" +qtPath = "C:\\Qt\\4.8.6\\" +openSSLPath = "C:\\OpenSSL-1.0.2e\\" +outPath = "C:\\src\\PyInstaller\\bitmessagemain" + +# -*- mode: python -*- +a = Analysis([srcPath + 'bitmessagemain.py'], + pathex=[outPath], + hiddenimports=[], + hookspath=None, + runtime_hooks=None) + +# fix duplicates +for d in a.datas: + if 'pyconfig' in d[0]: + a.datas.remove(d) + break + +def addTranslations(): + import os + extraDatas = [] + for file in os.listdir(srcPath + 'translations'): + if file[-3:] != ".qm": + continue + extraDatas.append(('translations\\'+file, srcPath + 'translations\\' + file, 'DATA')) + for file in os.listdir(qtPath + 'translations'): + if file[0:3] != "qt_" or file[5:8] != ".qm": + continue + extraDatas.append(('translations\\'+file, 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(('ui\\'+file, srcPath + 'bitmessageqt\\' + file, 'DATA')) + return extraDatas + +# append the translations directory +a.datas += addTranslations() +a.datas += addUIs() + +a.binaries.append(('msvcr120.dll', 'C:\\WINDOWS\\system32\\msvcr120.dll', 'BINARY')) + +pyz = PYZ(a.pure) +exe = EXE(pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas, + a.binaries + [('libeay32.dll', openSSLPath + 'libeay32.dll', 'BINARY'), ('bitmsghash\\bitmsghash32.dll', srcPath + 'bitmsghash\\bitmsghash32.dll', 'BINARY'), ('bitmsghash\\bitmsghash.cl', srcPath + 'bitmsghash\\bitmsghash.cl', 'BINARY'), ('sslkeys\\cert.pem', srcPath + 'sslkeys\\cert.pem', 'BINARY'), ('sslkeys\\key.pem', srcPath + 'sslkeys\\key.pem', 'BINARY')], + name='Bitmessage.exe', + debug=False, + strip=None, + upx=False, + console=False, icon= srcPath + 'images\\can-icon.ico') diff --git a/src/build_osx.py b/src/build_osx.py index fb81d4d0..1d8f470e 100644 --- a/src/build_osx.py +++ b/src/build_osx.py @@ -11,6 +11,7 @@ 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')), ] -- 2.45.1 From d25a1302ce0607681d8c17b5704107f1abf2e5e6 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 15:30:32 +0100 Subject: [PATCH 0349/1102] Version bump --- src/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared.py b/src/shared.py index 7ad4d452..9c4c90b7 100644 --- a/src/shared.py +++ b/src/shared.py @@ -1,6 +1,6 @@ from __future__ import division -softwareVersion = '0.5.7' +softwareVersion = '0.5.8' 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. -- 2.45.1 From e9f62efa4bd7201bf8b9ee079c2a30455462ecdc Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 24 Mar 2016 23:05:16 +0100 Subject: [PATCH 0350/1102] Default compose body "untranslate" There is no reason to retranslate the default message/broadcast body, and the default was just confusing HTML with no content. --- src/bitmessageqt/bitmessageui.py | 12 +---- src/translations/bitmessage_en.ts | 73 ++++++++++++++----------------- 2 files changed, 34 insertions(+), 51 deletions(-) diff --git a/src/bitmessageqt/bitmessageui.py b/src/bitmessageqt/bitmessageui.py index 5a8ae31f..6f50f7a1 100644 --- a/src/bitmessageqt/bitmessageui.py +++ b/src/bitmessageqt/bitmessageui.py @@ -671,19 +671,11 @@ class Ui_MainWindow(object): 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(_translate("MainWindow", "\n" -"\n" -"


", 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(_translate("MainWindow", "\n" -"\n" -"


", 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)) self.labelHumanFriendlyTTLDescription.setText(_translate("MainWindow", "X days", None)) diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index 2d24a692..aca9387b 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -335,7 +335,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Send @@ -350,7 +350,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Quit @@ -906,37 +906,37 @@ Are you sure you want to delete the channel? - + Search - + All - + To - + From - + Subject - + Message - + Received @@ -966,12 +966,12 @@ Are you sure you want to delete the channel? - + Subject: - + From: @@ -981,116 +981,107 @@ Are you sure you want to delete the channel? - - <!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 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 -- 2.45.1 From baff42f578677da4b427a0e3e20298ca9a91038d Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 25 Mar 2016 13:15:04 +0100 Subject: [PATCH 0351/1102] Typo String typo, also updated translation source. --- src/bitmessageqt/emailgateway.py | 2 +- src/translations/bitmessage_en.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/emailgateway.py b/src/bitmessageqt/emailgateway.py index 664a2b44..54ca4529 100644 --- a/src/bitmessageqt/emailgateway.py +++ b/src/bitmessageqt/emailgateway.py @@ -100,4 +100,4 @@ class Ui_EmailGatewayRegistrationDialog(object): def retranslateUi(self, EmailGatewayRegistrationDialog): EmailGatewayRegistrationDialog.setWindowTitle(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway registration", None, QtGui.QApplication.UnicodeUTF8)) - self.label.setText(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.\nPlease type the desiged email address (including @mailchuck.com) below:", None, QtGui.QApplication.UnicodeUTF8)) + self.label.setText(QtGui.QApplication.translate("EmailGatewayRegistrationDialog", "Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available.\nPlease type the desired email address (including @mailchuck.com) below:", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index aca9387b..d5157f5a 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -76,7 +76,7 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: +Please type the desired email address (including @mailchuck.com) below: -- 2.45.1 From ca11852632655a5dc360849f0bd90643771b3663 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 26 Mar 2016 13:33:31 +0100 Subject: [PATCH 0352/1102] Translation source update NewSubscriptionDialog missing string updated. --- src/bitmessageqt/newsubscriptiondialog.py | 2 +- src/translations/bitmessage_en.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitmessageqt/newsubscriptiondialog.py b/src/bitmessageqt/newsubscriptiondialog.py index d71eec0c..a63cce4a 100644 --- a/src/bitmessageqt/newsubscriptiondialog.py +++ b/src/bitmessageqt/newsubscriptiondialog.py @@ -65,5 +65,5 @@ class Ui_NewSubscriptionDialog(object): 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)) + self.checkBoxDisplayMessagesAlreadyInInventory.setText(_translate("NewSubscriptionDialog", "Enter an address above.", None)) diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index d5157f5a..5199274f 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -1224,7 +1224,7 @@ The 'Random Number' option is selected by default but deterministic ad - CheckBox + Enter an address above. -- 2.45.1 From d625659cc6657dd96bd1e52e6b6a5d0e58aa36c4 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 26 Mar 2016 18:42:22 +0100 Subject: [PATCH 0353/1102] User agent parser fix --- src/class_receiveDataThread.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index a8854e47..d63b19eb 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -707,14 +707,24 @@ class receiveDataThread(threading.Thread): useragent = data[readPosition:readPosition + useragentLength] # version check - userAgentName, userAgentVersion = useragent[1:-1].split(":") + try: + userAgentName, userAgentVersion = useragent[1:-1].split(":", 2) + except: + userAgentName = useragent + userAgentVersion = "0.0.0" if userAgentName == "PyBitmessage": myVersion = [int(n) for n in shared.softwareVersion.split(".")] - remoteVersion = [int(n) for n in userAgentVersion.split(".")] + try: + remoteVersion = [int(n) for n in userAgentVersion.split(".")] + except: + remoteVersion = 0 # remote is newer, but do not cross between stable and unstable - if cmp(remoteVersion, myVersion) > 0 and \ - (myVersion[1] % 2 == remoteVersion[1] % 2): - shared.UISignalQueue.put(('newVersionAvailable', remoteVersion)) + try: + if cmp(remoteVersion, myVersion) > 0 and \ + (myVersion[1] % 2 == remoteVersion[1] % 2): + shared.UISignalQueue.put(('newVersionAvailable', remoteVersion)) + except: + pass readPosition += useragentLength numberOfStreamsInVersionMessage, lengthOfNumberOfStreamsInVersionMessage = decodeVarint( -- 2.45.1 From d46fd6f48657aad680c0735312ffde61b8dc548e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 26 Mar 2016 19:17:26 +0100 Subject: [PATCH 0354/1102] Translation fix Plural form fix --- src/bitmessageqt/__init__.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index cfc5ceec..6e2ae623 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -4200,14 +4200,10 @@ class NewSubscriptionDialog(QtGui.QDialog): if count == 0: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( _translate("MainWindow", "There are no recent broadcasts from this address to display.")) - elif count == 1: - self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) - self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "Display the %1 recent broadcast from this address.").arg(count)) else: self.ui.checkBoxDisplayMessagesAlreadyInInventory.setEnabled(True) self.ui.checkBoxDisplayMessagesAlreadyInInventory.setText( - _translate("MainWindow", "Display the %1 recent broadcasts from this address.").arg(count)) + _translate("MainWindow", "Display the %1 recent broadcast(s) from this address.").arg(count)) class NewAddressDialog(QtGui.QDialog): -- 2.45.1 From be16be2bb4a8cb1b7ca845f88f9b678e6194e2ec Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 26 Mar 2016 19:29:38 +0100 Subject: [PATCH 0355/1102] Translation update Updated English source strings. --- src/translations/bitmessage_en.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index 5199274f..cd552a9d 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -876,17 +876,7 @@ Are you sure you want to delete the channel? - - Display the %1 recent broadcast from this address. - - - - - Display the %1 recent broadcasts from this address. - - - - + You are using TCP port %1. (This can be changed in the settings). @@ -1105,6 +1095,11 @@ Are you sure you want to delete the channel? Add new entry + + + Display the %1 recent broadcast(s) from this address. + + NewAddressDialog -- 2.45.1 From a7ec4c0555523020e3ff4e142cb5eaddb2bf9556 Mon Sep 17 00:00:00 2001 From: mirrorwish Date: Wed, 23 Mar 2016 23:26:57 +0100 Subject: [PATCH 0356/1102] Some preparations for python 3 --- src/addresses.py | 13 ++-- src/api.py | 29 +++++---- src/class_addressGenerator.py | 7 +- src/class_objectProcessor.py | 29 +++++---- src/class_receiveDataThread.py | 7 +- src/class_singleWorker.py | 113 +++++++++++++++++---------------- src/helper_generic.py | 7 +- src/highlevelcrypto.py | 3 +- src/message_data_reader.py | 7 +- src/shared.py | 29 +++++---- 10 files changed, 127 insertions(+), 117 deletions(-) diff --git a/src/addresses.py b/src/addresses.py index 017eaa82..fa87677a 100644 --- a/src/addresses.py +++ b/src/addresses.py @@ -1,6 +1,7 @@ import hashlib from struct import * from pyelliptic import arithmetic +from binascii import hexlify, unhexlify @@ -10,9 +11,9 @@ def convertIntToString(n): if a[-1:] == 'L': a = a[:-1] if (len(a) % 2) == 0: - return a[2:].decode('hex') + return unhexlify(a[2:]) else: - return ('0'+a[2:]).decode('hex') + return unhexlify('0'+a[2:]) ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" @@ -142,7 +143,7 @@ def encodeAddress(version,stream,ripe): sha.update(currentHash) checksum = sha.digest()[0:4] - asInt = int(storedBinaryData.encode('hex') + checksum.encode('hex'),16) + asInt = int(hexlify(storedBinaryData) + hexlify(checksum),16) return 'BM-'+ encodeBase58(asInt) def decodeAddress(address): @@ -165,7 +166,7 @@ def decodeAddress(address): #print 'hexdata', hexdata - data = hexdata.decode('hex') + data = unhexlify(hexdata) checksum = data[-4:] sha = hashlib.new('sha512') @@ -268,7 +269,7 @@ if __name__ == "__main__": ripe.update(sha.digest()) addressVersionNumber = 2 streamNumber = 1 - print 'Ripe digest that we will encode in the address:', ripe.digest().encode('hex') + print 'Ripe digest that we will encode in the address:', hexlify(ripe.digest()) returnedAddress = encodeAddress(addressVersionNumber,streamNumber,ripe.digest()) print 'Encoded address:', returnedAddress status,addressVersionNumber,streamNumber,data = decodeAddress(returnedAddress) @@ -277,5 +278,5 @@ if __name__ == "__main__": print 'addressVersionNumber', addressVersionNumber print 'streamNumber', streamNumber print 'length of data(the ripe hash):', len(data) - print 'ripe data:', data.encode('hex') + print 'ripe data:', hexlify(data) diff --git a/src/api.py b/src/api.py index edae0dc5..37e80421 100644 --- a/src/api.py +++ b/src/api.py @@ -14,6 +14,7 @@ if __name__ == "__main__": from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler, SimpleXMLRPCServer import json +from binascii import hexlify import shared import time @@ -477,7 +478,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - data += json.dumps({'msgid': msgid.encode('hex'), 'toAddress': toAddress, 'fromAddress': fromAddress, 'subject': subject.encode( + data += json.dumps({'msgid': hexlify(msgid), 'toAddress': toAddress, 'fromAddress': fromAddress, 'subject': subject.encode( 'base64'), 'message': message.encode('base64'), 'encodingType': encodingtype, 'receivedTime': received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -490,7 +491,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid = row[0] if len(data) > 25: data += ',' - data += json.dumps({'msgid': msgid.encode('hex')}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid': hexlify(msgid)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -515,7 +516,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid, toAddress, fromAddress, subject, received, message, encodingtype, read = row subject = shared.fixPotentiallyInvalidUTF8Data(subject) message = shared.fixPotentiallyInvalidUTF8Data(message) - 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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received, 'read': read}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -528,7 +529,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - 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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -539,7 +540,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): msgid = row[0] if len(data) > 25: data += ',' - data += json.dumps({'msgid':msgid.encode('hex')}, indent=4, separators=(',', ': ')) + data += json.dumps({'msgid':hexlify(msgid)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -555,7 +556,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - 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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'receivedTime':received}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -569,7 +570,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':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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -586,7 +587,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): message = shared.fixPotentiallyInvalidUTF8Data(message) if len(data) > 25: data += ',' - 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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -601,7 +602,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':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 += json.dumps({'msgid':hexlify(msgid), 'toAddress':toAddress, 'fromAddress':fromAddress, 'subject':subject.encode('base64'), 'message':message.encode('base64'), 'encodingType':encodingtype, 'lastActionTime':lastactiontime, 'status':status, 'ackData':hexlify(ackdata)}, indent=4, separators=(',', ': ')) data += ']}' return data @@ -694,7 +695,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.workerQueue.put(('sendmessage', toAddress)) - return ackdata.encode('hex') + return hexlify(ackdata) def HandleSendBroadcast(self, params): if len(params) == 0: @@ -751,7 +752,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): toAddress, toLabel, fromAddress, subject, message, ackdata))) shared.workerQueue.put(('sendbroadcast', '')) - return ackdata.encode('hex') + return hexlify(ackdata) def HandleGetStatus(self, params): if len(params) != 1: @@ -851,7 +852,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.inventory[inventoryHash] = ( objectType, toStreamNumber, encryptedPayload, int(time.time()) + TTL,'') with shared.printLock: - print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', inventoryHash.encode('hex') + print 'Broadcasting inv for msg(API disseminatePreEncryptedMsg command):', hexlify(inventoryHash) shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) @@ -898,7 +899,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): shared.inventory[inventoryHash] = ( objectType, pubkeyStreamNumber, payload, int(time.time()) + TTL,'') with shared.printLock: - print 'broadcasting inv within API command disseminatePubkey with hash:', inventoryHash.encode('hex') + print 'broadcasting inv within API command disseminatePubkey with hash:', hexlify(inventoryHash) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -933,7 +934,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): payload, = row if len(data) > 25: data += ',' - data += json.dumps({'data':payload.encode('hex')}, indent=4, separators=(',', ': ')) + data += json.dumps({'data':hexlify(payload)}, indent=4, separators=(',', ': ')) data += ']}' return data diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py index b84be8e3..28f329ea 100644 --- a/src/class_addressGenerator.py +++ b/src/class_addressGenerator.py @@ -11,6 +11,7 @@ from debug import logger from helper_threading import * from pyelliptic import arithmetic import tr +from binascii import hexlify class addressGenerator(threading.Thread, StoppableThread): @@ -104,7 +105,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' % ripe.digest().encode('hex')) + logger.info('Generated address with ripe digest: %s' % hexlify(ripe.digest())) 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: @@ -196,7 +197,7 @@ class addressGenerator(threading.Thread, StoppableThread): break - logger.info('Generated address with ripe digest: %s' % ripe.digest().encode('hex')) + logger.info('Generated address with ripe digest: %s' % hexlify(ripe.digest())) 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: @@ -262,7 +263,7 @@ class addressGenerator(threading.Thread, StoppableThread): listOfNewAddressesToSendOutThroughTheAPI.append( address) shared.myECCryptorObjects[ripe.digest()] = highlevelcrypto.makeCryptor( - potentialPrivEncryptionKey.encode('hex')) + hexlify(potentialPrivEncryptionKey)) shared.myAddressesByHash[ripe.digest()] = address tag = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersionNumber) + encodeVarint(streamNumber) + ripe.digest()).digest()).digest()[32:] diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index a2402643..6885db8c 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -8,6 +8,7 @@ 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 @@ -106,7 +107,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' % requestedHash.encode('hex')) + logger.info('the hash requested in this getpubkey request is: %s' % hexlify(requestedHash)) if requestedHash in shared.myAddressesByHash: # if this address hash is one of mine myAddress = shared.myAddressesByHash[requestedHash] elif requestedAddressVersionNumber >= 4: @@ -114,7 +115,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' % requestedTag.encode('hex')) + logger.debug('the tag requested in this getpubkey request is: %s' % hexlify(requestedTag)) if requestedTag in shared.myAddressesByTag: myAddress = shared.myAddressesByTag[requestedTag] @@ -199,9 +200,9 @@ class objectProcessor(threading.Thread): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - ripe.encode('hex'), - publicSigningKey.encode('hex'), - publicEncryptionKey.encode('hex') + hexlify(ripe), + hexlify(publicSigningKey), + hexlify(publicEncryptionKey) ) ) @@ -240,7 +241,7 @@ class objectProcessor(threading.Thread): data[readPosition:readPosition + 10]) readPosition += signatureLengthLength signature = data[readPosition:readPosition + signatureLength] - if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, publicSigningKey.encode('hex')): + if highlevelcrypto.verify(data[8:endOfSignedDataPosition], signature, hexlify(publicSigningKey)): logger.debug('ECDSA verify passed (within processpubkey)') else: logger.warning('ECDSA verify failed (within processpubkey)') @@ -258,9 +259,9 @@ class objectProcessor(threading.Thread): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - ripe.encode('hex'), - publicSigningKey.encode('hex'), - publicEncryptionKey.encode('hex') + hexlify(ripe), + hexlify(publicSigningKey), + hexlify(publicEncryptionKey) ) ) @@ -341,7 +342,7 @@ class objectProcessor(threading.Thread): 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')) + logger.info('EC decryption successful using key associated with ripe hash: %s.' % hexlify(key)) except Exception as err: pass if not initialDecryptionSuccessful: @@ -393,7 +394,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' % (toRipe.encode('hex'), decryptedData[readPosition:readPosition + 20].encode('hex')) + embedded destination toRipe: %s' % (hexlify(toRipe), hexlify(decryptedData[readPosition:readPosition + 20])) ) return readPosition += 20 @@ -419,7 +420,7 @@ class objectProcessor(threading.Thread): readPosition:readPosition + signatureLength] signedData = data[8:20] + encodeVarint(1) + encodeVarint(streamNumberAsClaimedByMsg) + decryptedData[:positionOfBottomOfAckData] - if not highlevelcrypto.verify(signedData, signature, pubSigningKey.encode('hex')): + if not highlevelcrypto.verify(signedData, signature, hexlify(pubSigningKey)): logger.debug('ECDSA verify failed') return logger.debug('ECDSA verify passed') @@ -623,7 +624,7 @@ class objectProcessor(threading.Thread): 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')) + logger.info('EC decryption successful using key associated with ripe hash: %s' % hexlify(key)) except Exception as err: pass # print 'cryptorObject.decrypt Exception:', err @@ -718,7 +719,7 @@ class objectProcessor(threading.Thread): signature = decryptedData[ readPosition:readPosition + signatureLength] signedData += decryptedData[:readPositionAtBottomOfMessage] - if not highlevelcrypto.verify(signedData, signature, sendersPubSigningKey.encode('hex')): + if not highlevelcrypto.verify(signedData, signature, hexlify(sendersPubSigningKey)): logger.debug('ECDSA verify failed') return logger.debug('ECDSA verify passed') diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index d63b19eb..5883ab42 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -15,6 +15,7 @@ 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 @@ -374,7 +375,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" % inventoryVector.encode('hex') + message += " This concerns object %s" % hexlify(inventoryVector) if banTime > 0: message += " Remote node says that the ban time is %s" % banTime logger.error(message) @@ -447,7 +448,7 @@ class receiveDataThread(threading.Thread): # Send a getdata message to our peer to request the object with the given # hash def sendgetdata(self, hash): - logger.debug('sending getdata to retrieve object with hash: ' + hash.encode('hex')) + logger.debug('sending getdata to retrieve object with hash: ' + hexlify(hash)) payload = '\x01' + hash self.sendDataThreadQueue.put((0, 'sendRawData', shared.CreatePacket('getdata', payload))) @@ -463,7 +464,7 @@ class receiveDataThread(threading.Thread): for i in xrange(numberOfRequestedInventoryItems): hash = data[lengthOfVarint + ( i * 32):32 + lengthOfVarint + (i * 32)] - logger.debug('received getdata request for item:' + hash.encode('hex')) + logger.debug('received getdata request for item:' + hexlify(hash)) shared.numberOfInventoryLookupsPerformed += 1 shared.inventoryLock.acquire() diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py index 73127adf..169b40c0 100644 --- a/src/class_singleWorker.py +++ b/src/class_singleWorker.py @@ -18,6 +18,7 @@ from helper_generic import addDataPadding from helper_threading import * import l10n from protocol import * +from binascii import hexlify, unhexlify # This thread, of which there is only one, does the heavy lifting: # calculating POWs. @@ -58,14 +59,14 @@ class singleWorker(threading.Thread, StoppableThread): toAddressVersionNumber) + encodeVarint(toStreamNumber) + toRipe).digest()).digest() privEncryptionKey = doubleHashOfAddressData[:32] # Note that this is the first half of the sha512 hash. tag = doubleHashOfAddressData[32:] - 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. + shared.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. # Initialize the shared.ackdataForWhichImWatching data structure queryreturn = sqlQuery( '''SELECT ackdata FROM sent where (status='msgsent' OR status='doingmsgpow')''') for row in queryreturn: ackdata, = row - logger.info('Watching for ackdata ' + ackdata.encode('hex')) + logger.info('Watching for ackdata ' + hexlify(ackdata)) shared.ackdataForWhichImWatching[ackdata] = 0 self.stop.wait( @@ -134,14 +135,14 @@ class singleWorker(threading.Thread, StoppableThread): logger.error('Error within doPOWForMyV2Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return - privSigningKeyHex = shared.decodeWalletImportFormat( - privSigningKeyBase58).encode('hex') - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') - pubSigningKey = highlevelcrypto.privToPub( - privSigningKeyHex).decode('hex') - pubEncryptionKey = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex') + privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( + privSigningKeyBase58)) + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) + pubSigningKey = unhexlify(highlevelcrypto.privToPub( + privSigningKeyHex)) + pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex)) payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] @@ -159,7 +160,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') - logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) + logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -215,14 +216,14 @@ class singleWorker(threading.Thread, StoppableThread): return - privSigningKeyHex = shared.decodeWalletImportFormat( - privSigningKeyBase58).encode('hex') - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') - pubSigningKey = highlevelcrypto.privToPub( - privSigningKeyHex).decode('hex') - pubEncryptionKey = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex') + privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( + privSigningKeyBase58)) + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) + pubSigningKey = unhexlify(highlevelcrypto.privToPub( + privSigningKeyHex)) + pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex)) payload += pubSigningKey[1:] payload += pubEncryptionKey[1:] @@ -249,7 +250,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime,'') - logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) + logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -292,14 +293,14 @@ class singleWorker(threading.Thread, StoppableThread): logger.error('Error within sendOutOrStoreMyV4Pubkey. Could not read the keys from the keys.dat file for a requested address. %s\n' % err) return - privSigningKeyHex = shared.decodeWalletImportFormat( - privSigningKeyBase58).encode('hex') - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') - pubSigningKey = highlevelcrypto.privToPub( - privSigningKeyHex).decode('hex') - pubEncryptionKey = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex') + privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( + privSigningKeyBase58)) + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) + pubSigningKey = unhexlify(highlevelcrypto.privToPub( + privSigningKeyHex)) + pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex)) dataToEncrypt += pubSigningKey[1:] dataToEncrypt += pubEncryptionKey[1:] @@ -324,7 +325,7 @@ class singleWorker(threading.Thread, StoppableThread): privEncryptionKey = doubleHashOfAddressData[:32] pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( - dataToEncrypt, pubEncryptionKey.encode('hex')) + dataToEncrypt, hexlify(pubEncryptionKey)) # Do the POW for this pubkey message target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) @@ -339,7 +340,7 @@ class singleWorker(threading.Thread, StoppableThread): shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, doubleHashOfAddressData[32:]) - logger.info('broadcasting inv with hash: ' + inventoryHash.encode('hex')) + logger.info('broadcasting inv with hash: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -373,15 +374,15 @@ class singleWorker(threading.Thread, StoppableThread): ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue - privSigningKeyHex = shared.decodeWalletImportFormat( - privSigningKeyBase58).encode('hex') - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') + privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( + privSigningKeyBase58)) + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) 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 = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex') + pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex)) if TTL > 28 * 24 * 60 * 60: TTL = 28 * 24 * 60 * 60 @@ -437,7 +438,7 @@ class singleWorker(threading.Thread, StoppableThread): pubEncryptionKey = highlevelcrypto.pointMult(privEncryptionKey) payload += highlevelcrypto.encrypt( - dataToEncrypt, pubEncryptionKey.encode('hex')) + dataToEncrypt, hexlify(pubEncryptionKey)) target = 2 ** 64 / (shared.networkDefaultProofOfWorkNonceTrialsPerByte*(len(payload) + 8 + shared.networkDefaultPayloadLengthExtraBytes + ((TTL*(len(payload)+8+shared.networkDefaultPayloadLengthExtraBytes))/(2 ** 16)))) logger.info('(For broadcast message) Doing proof of work...') @@ -460,7 +461,7 @@ class singleWorker(threading.Thread, StoppableThread): objectType = 3 shared.inventory[inventoryHash] = ( objectType, streamNumber, payload, embeddedTime, tag) - logger.info('sending inv (within sendBroadcast function) for object: ' + inventoryHash.encode('hex')) + logger.info('sending inv (within sendBroadcast function) for object: ' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( streamNumber, 'advertiseobject', inventoryHash)) @@ -553,7 +554,7 @@ 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. - shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex'))) + shared.neededPubkeys[tag] = (toaddress, highlevelcrypto.makeCryptor(hexlify(privEncryptionKey))) for value in shared.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. @@ -675,10 +676,10 @@ class singleWorker(threading.Thread, StoppableThread): 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())))) logger.error('Error within sendMsg. Could not read the keys from the keys.dat file for our own address. %s\n' % err) continue - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') - pubEncryptionKeyBase256 = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex')[1:] + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) + pubEncryptionKeyBase256 = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex))[1:] requiredAverageProofOfWorkNonceTrialsPerByte = shared.networkDefaultProofOfWorkNonceTrialsPerByte requiredPayloadLengthExtraBytes = shared.networkDefaultPayloadLengthExtraBytes shared.UISignalQueue.put(('updateSentItemStatusByAckdata', ( @@ -701,15 +702,15 @@ class singleWorker(threading.Thread, StoppableThread): ackdata, tr.translateText("MainWindow", "Error! Could not find sender address (your address) in the keys.dat file.")))) continue - privSigningKeyHex = shared.decodeWalletImportFormat( - privSigningKeyBase58).encode('hex') - privEncryptionKeyHex = shared.decodeWalletImportFormat( - privEncryptionKeyBase58).encode('hex') + privSigningKeyHex = hexlify(shared.decodeWalletImportFormat( + privSigningKeyBase58)) + privEncryptionKeyHex = hexlify(shared.decodeWalletImportFormat( + privEncryptionKeyBase58)) - pubSigningKey = highlevelcrypto.privToPub( - privSigningKeyHex).decode('hex') - pubEncryptionKey = highlevelcrypto.privToPub( - privEncryptionKeyHex).decode('hex') + pubSigningKey = unhexlify(highlevelcrypto.privToPub( + privSigningKeyHex)) + pubEncryptionKey = unhexlify(highlevelcrypto.privToPub( + privEncryptionKeyHex)) 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. @@ -755,7 +756,7 @@ class singleWorker(threading.Thread, StoppableThread): # We have assembled the data that will be encrypted. try: - encrypted = highlevelcrypto.encrypt(payload,"04"+pubEncryptionKeyBase256.encode('hex')) + encrypted = highlevelcrypto.encrypt(payload,"04"+hexlify(pubEncryptionKeyBase256)) except: sqlExecute('''UPDATE sent SET status='badkey' WHERE ackdata=?''', ackdata) 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())))) @@ -795,7 +796,7 @@ class singleWorker(threading.Thread, StoppableThread): else: # not sending to a chan or one of my addresses shared.UISignalQueue.put(('updateSentItemStatusByAckdata', (ackdata, tr.translateText("MainWindow", "Message sent. Waiting for acknowledgement. Sent on %1").arg(l10n.formatTimestamp())))) - logger.info('Broadcasting inv for my msg(within sendmsg function):' + inventoryHash.encode('hex')) + logger.info('Broadcasting inv for my msg(within sendmsg function):' + hexlify(inventoryHash)) shared.broadcastToSendDataQueues(( toStreamNumber, 'advertiseobject', inventoryHash)) @@ -864,7 +865,7 @@ class singleWorker(threading.Thread, StoppableThread): 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 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. + shared.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 retryNumber == 0: TTL = 2.5*24*60*60 # 2.5 days. This was chosen fairly arbitrarily. @@ -878,10 +879,10 @@ class singleWorker(threading.Thread, StoppableThread): payload += encodeVarint(streamNumber) if addressVersionNumber <= 3: payload += ripe - logger.info('making request for pubkey with ripe: %s', ripe.encode('hex')) + logger.info('making request for pubkey with ripe: %s', hexlify(ripe)) else: payload += tag - logger.info('making request for v4 pubkey with tag: %s', tag.encode('hex')) + logger.info('making request for v4 pubkey with tag: %s', hexlify(tag)) # print 'trial value', trialValue statusbar = 'Doing the computations necessary to request the recipient\'s public key.' diff --git a/src/helper_generic.py b/src/helper_generic.py index a9de6e05..b8a38863 100644 --- a/src/helper_generic.py +++ b/src/helper_generic.py @@ -1,5 +1,6 @@ import socket import sys +from binascii import hexlify, unhexlify import shared @@ -8,13 +9,13 @@ def convertIntToString(n): if a[-1:] == 'L': a = a[:-1] if (len(a) % 2) == 0: - return a[2:].decode('hex') + return unhexlify(a[2:]) else: - return ('0' + a[2:]).decode('hex') + return unhexlify('0' + a[2:]) def convertStringToInt(s): - return int(s.encode('hex'), 16) + return int(hexlify(s), 16) def signal_handler(signal, frame): diff --git a/src/highlevelcrypto.py b/src/highlevelcrypto.py index 5a2ae920..c8b67e77 100644 --- a/src/highlevelcrypto.py +++ b/src/highlevelcrypto.py @@ -1,3 +1,4 @@ +from binascii import hexlify import pyelliptic from pyelliptic import arithmetic as a, OpenSSL def makeCryptor(privkey): @@ -18,7 +19,7 @@ def makePubCryptor(pubkey): def privToPub(privkey): private_key = a.changebase(privkey, 16, 256, minlen=32) public_key = pointMult(private_key) - return public_key.encode('hex') + return hexlify(public_key) # Encrypts message with hex public key def encrypt(msg,hexPubkey): return pyelliptic.ECC(curve='secp256k1').encrypt(msg,hexToPubkey(hexPubkey)) diff --git a/src/message_data_reader.py b/src/message_data_reader.py index 250e06a9..a99be336 100644 --- a/src/message_data_reader.py +++ b/src/message_data_reader.py @@ -7,6 +7,7 @@ from time import strftime, localtime import sys import shared import string +from binascii import hexlify appdata = shared.lookupAppdataFolder() @@ -31,7 +32,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 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 + 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 def readSubscriptions(): print 'Printing everything in subscriptions table:' @@ -50,7 +51,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:', transmitdata.encode('hex') + 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) def readInventory(): print 'Printing everything in inventory table:' @@ -60,7 +61,7 @@ def readInventory(): output = cur.fetchall() for row in output: hash, objecttype, streamnumber, payload, expirestime = row - 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') + print 'Hash:', hexlify(hash), objecttype, streamnumber, '\t', hexlify(payload), '\t', unicode(strftime('%a, %d %b %Y %I:%M %p',localtime(expirestime)),'utf-8') def takeInboxMessagesOutOfTrash(): diff --git a/src/shared.py b/src/shared.py index 9c4c90b7..315e5671 100644 --- a/src/shared.py +++ b/src/shared.py @@ -26,6 +26,7 @@ import datetime from os import path, environ from struct import Struct import traceback +from binascii import hexlify # Project imports. from addresses import * @@ -417,8 +418,8 @@ def reloadMyAddressHashes(): 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') + privEncryptionKey = hexlify(decodeWalletImportFormat( + config.get(addressInKeysFile, 'privencryptionkey'))) if len(privEncryptionKey) == 64:#It is 32 bytes encoded as 64 hex characters myECCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey) @@ -447,13 +448,13 @@ def reloadBroadcastSendersForWhichImWatching(): if addressVersionNumber <= 3: privEncryptionKey = hashlib.sha512(encodeVarint(addressVersionNumber)+encodeVarint(streamNumber)+hash).digest()[:32] - MyECSubscriptionCryptorObjects[hash] = highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex')) + MyECSubscriptionCryptorObjects[hash] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) else: doubleHashOfAddressData = hashlib.sha512(hashlib.sha512(encodeVarint( addressVersionNumber) + encodeVarint(streamNumber) + hash).digest()).digest() tag = doubleHashOfAddressData[32:] privEncryptionKey = doubleHashOfAddressData[:32] - MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(privEncryptionKey.encode('hex')) + MyECSubscriptionCryptorObjects[tag] = highlevelcrypto.makeCryptor(hexlify(privEncryptionKey)) def isProofOfWorkSufficient(data, nonceTrialsPerByte=0, @@ -662,7 +663,7 @@ def decryptAndCheckPubkeyPayload(data, address): readPosition += signatureLengthLength signature = decryptedData[readPosition:readPosition + signatureLength] - if highlevelcrypto.verify(signedData, signature, publicSigningKey.encode('hex')): + if highlevelcrypto.verify(signedData, signature, hexlify(publicSigningKey)): logger.info('ECDSA verify passed (within decryptAndCheckPubkeyPayload)') else: logger.info('ECDSA verify failed (within decryptAndCheckPubkeyPayload)') @@ -688,9 +689,9 @@ def decryptAndCheckPubkeyPayload(data, address): publicSigningKey in hex: %s\n\ publicEncryptionKey in hex: %s' % (addressVersion, streamNumber, - ripe.encode('hex'), - publicSigningKey.encode('hex'), - publicEncryptionKey.encode('hex') + hexlify(ripe), + hexlify(publicSigningKey), + hexlify(publicEncryptionKey) ) ) @@ -775,7 +776,7 @@ def _checkAndShareUndefinedObjectWithPeers(data): inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') inventoryLock.release() - logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -803,7 +804,7 @@ def _checkAndShareMsgWithPeers(data): inventory[inventoryHash] = ( objectType, streamNumber, data, embeddedTime,'') inventoryLock.release() - logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's enqueue it to be processed ourselves. @@ -840,7 +841,7 @@ def _checkAndShareGetpubkeyWithPeers(data): objectType, streamNumber, data, embeddedTime,'') inventoryLock.release() # This getpubkey request is valid. Forward to peers. - logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. @@ -862,7 +863,7 @@ def _checkAndSharePubkeyWithPeers(data): return if addressVersion >= 4: tag = data[readPosition:readPosition + 32] - logger.debug('tag in received pubkey is: %s' % tag.encode('hex')) + logger.debug('tag in received pubkey is: %s' % hexlify(tag)) else: tag = '' @@ -878,7 +879,7 @@ def _checkAndSharePubkeyWithPeers(data): objectType, streamNumber, data, embeddedTime, tag) inventoryLock.release() # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) @@ -918,7 +919,7 @@ def _checkAndShareBroadcastWithPeers(data): objectType, streamNumber, data, embeddedTime, tag) inventoryLock.release() # This object is valid. Forward it to peers. - logger.debug('advertising inv with hash: %s' % inventoryHash.encode('hex')) + logger.debug('advertising inv with hash: %s' % hexlify(inventoryHash)) broadcastToSendDataQueues((streamNumber, 'advertiseobject', inventoryHash)) # Now let's queue it to be processed ourselves. -- 2.45.1 From fd4329bee001f31a1d449fdd39df9c982144ac1c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 15 Apr 2016 12:12:49 +0200 Subject: [PATCH 0357/1102] Refactor localisation The language combo box is generated dynamically from the list of available translations in the translations directory. This allows the users to add their own translations without having to change the code. --- src/bitmessageqt/__init__.py | 17 ++++---------- src/bitmessageqt/languagebox.py | 40 +++++++++++++++++++++++++++++++++ src/bitmessageqt/settings.py | 32 ++------------------------ 3 files changed, 46 insertions(+), 43 deletions(-) create mode 100644 src/bitmessageqt/languagebox.py diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 6e2ae623..70a39a31 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -2349,10 +2349,10 @@ class MyForm(settingsmixin.SMainWindow): shared.config.set('bitmessagesettings', 'replybelow', str( self.settingsDialogInstance.ui.checkBoxReplyBelow.isChecked())) - 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]) + lang = str(self.settingsDialogInstance.ui.languageComboBox.itemData(self.settingsDialogInstance.ui.languageComboBox.currentIndex()).toString()) + shared.config.set('bitmessagesettings', 'userlocale', lang) + logger.debug("Setting locale to %s", lang) + change_translation(lang) if int(shared.config.get('bitmessagesettings', 'port')) != int(self.settingsDialogInstance.ui.lineEditTCPPort.text()): if not shared.safeConfigGetBoolean('bitmessagesettings', 'dontconnect'): @@ -3870,15 +3870,6 @@ class settingsDialog(QtGui.QDialog): self.ui.checkBoxReplyBelow.setChecked( shared.safeConfigGetBoolean('bitmessagesettings', 'replybelow')) - 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: - curr_index = languages.index('other') - self.ui.languageComboBox.setCurrentIndex(curr_index) - if shared.appdata == shared.lookupExeFolder(): self.ui.checkBoxPortableMode.setChecked(True) else: diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py new file mode 100644 index 00000000..77c39d53 --- /dev/null +++ b/src/bitmessageqt/languagebox.py @@ -0,0 +1,40 @@ +import glob +import os +from PyQt4 import QtCore, QtGui + +from debug import logger +from shared import codePath, config + +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 (codePath(), 'translations') + configuredLocale = "system" + try: + configuredLocale = config.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()): + logger.debug("Checking locale %s at %i", str(self.itemData(i).toString()), i) + if self.itemData(i) == configuredLocale: + logger.debug("Matching locale %s at %i", configuredLocale, i) + self.setCurrentIndex(i) + break diff --git a/src/bitmessageqt/settings.py b/src/bitmessageqt/settings.py index e6fbbc66..6b7dd9b3 100644 --- a/src/bitmessageqt/settings.py +++ b/src/bitmessageqt/settings.py @@ -8,6 +8,7 @@ # WARNING! All changes made in this file will be lost! from PyQt4 import QtCore, QtGui +from languagebox import LanguageBox try: _fromUtf8 = QtCore.QString.fromUtf8 @@ -88,36 +89,9 @@ 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 = QtGui.QComboBox(self.groupBox) + self.languageComboBox = LanguageBox(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ñol")) - 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("")) @@ -467,8 +441,6 @@ 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)) -- 2.45.1 From 70e06c33f69810ab5b152ff12cc307590a872e64 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 15 Apr 2016 12:41:51 +0200 Subject: [PATCH 0358/1102] Remove some debugging Language loading debugging not necessary. --- src/bitmessageqt/languagebox.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bitmessageqt/languagebox.py b/src/bitmessageqt/languagebox.py index 77c39d53..2a8cb865 100644 --- a/src/bitmessageqt/languagebox.py +++ b/src/bitmessageqt/languagebox.py @@ -2,7 +2,6 @@ import glob import os from PyQt4 import QtCore, QtGui -from debug import logger from shared import codePath, config class LanguageBox(QtGui.QComboBox): @@ -33,8 +32,6 @@ class LanguageBox(QtGui.QComboBox): else: self.addItem(locale.nativeLanguageName(), localeShort) for i in range(self.count()): - logger.debug("Checking locale %s at %i", str(self.itemData(i).toString()), i) if self.itemData(i) == configuredLocale: - logger.debug("Matching locale %s at %i", configuredLocale, i) self.setCurrentIndex(i) break -- 2.45.1 From 5adc4429f0566b3f93dc05fcb7a5f335252e0dba Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Fri, 15 Apr 2016 12:50:07 +0200 Subject: [PATCH 0359/1102] Translations update - synced translations from Transifex - updated source - added Slovak translation --- src/translations/bitmessage.pro | 2 + src/translations/bitmessage_ar.qm | Bin 40538 -> 39639 bytes src/translations/bitmessage_ar.ts | 2125 ++++++++---------- src/translations/bitmessage_cs.qm | Bin 56765 -> 56769 bytes src/translations/bitmessage_cs.ts | 248 +-- src/translations/bitmessage_da.qm | Bin 53492 -> 52648 bytes src/translations/bitmessage_da.ts | 500 ++--- src/translations/bitmessage_de.qm | Bin 74934 -> 81139 bytes src/translations/bitmessage_de.ts | 297 +-- src/translations/bitmessage_en.qm | Bin 23 -> 334 bytes src/translations/bitmessage_en.ts | 162 +- src/translations/bitmessage_en_pirate.qm | Bin 16943 -> 17497 bytes src/translations/bitmessage_en_pirate.ts | 1435 ++++++------ src/translations/bitmessage_eo.qm | Bin 33666 -> 74419 bytes src/translations/bitmessage_eo.ts | 2253 +++++++++---------- src/translations/bitmessage_fr.qm | Bin 40335 -> 73001 bytes src/translations/bitmessage_fr.ts | 2542 ++++++++++------------ src/translations/bitmessage_it.ts | 1936 ++++++++++++++++ src/translations/bitmessage_ja.qm | Bin 34722 -> 34663 bytes src/translations/bitmessage_ja.ts | 1547 ++++++------- src/translations/bitmessage_nb.ts | 1898 ++++++++++++++++ src/translations/bitmessage_nl.qm | Bin 8651 -> 12672 bytes src/translations/bitmessage_nl.ts | 1541 +++++++------ src/translations/bitmessage_no.qm | Bin 54889 -> 60163 bytes src/translations/bitmessage_no.ts | 2295 +++++++++---------- src/translations/bitmessage_pl.ts | 1898 ++++++++++++++++ src/translations/bitmessage_pt.ts | 1898 ++++++++++++++++ src/translations/bitmessage_ru.qm | Bin 50648 -> 50975 bytes src/translations/bitmessage_ru.ts | 1957 ++++++++--------- src/translations/bitmessage_sk.qm | Bin 0 -> 60472 bytes src/translations/bitmessage_sk.ts | 1909 ++++++++++++++++ src/translations/bitmessage_sv.ts | 1898 ++++++++++++++++ src/translations/bitmessage_zh_cn.qm | Bin 35054 -> 35229 bytes src/translations/bitmessage_zh_cn.ts | 1608 ++++++-------- 34 files changed, 19799 insertions(+), 10150 deletions(-) create mode 100644 src/translations/bitmessage_it.ts create mode 100644 src/translations/bitmessage_nb.ts create mode 100644 src/translations/bitmessage_pl.ts create mode 100644 src/translations/bitmessage_pt.ts create mode 100644 src/translations/bitmessage_sk.qm create mode 100644 src/translations/bitmessage_sk.ts create mode 100644 src/translations/bitmessage_sv.ts diff --git a/src/translations/bitmessage.pro b/src/translations/bitmessage.pro index 875388f4..b616e3cd 100644 --- a/src/translations/bitmessage.pro +++ b/src/translations/bitmessage.pro @@ -27,6 +27,7 @@ SOURCES = ../addresses.py\ ../bitmessageqt/foldertree.py\ ../bitmessageqt/help.py\ ../bitmessageqt/iconglossary.py\ + ../bitmessageqt/languagebox.py\ ../bitmessageqt/messagecompose.py\ ../bitmessageqt/messageview.py\ ../bitmessageqt/networkstatus.py\ @@ -54,6 +55,7 @@ TRANSLATIONS = \ bitmessage_ja.ts \ bitmessage_nl.ts \ bitmessage_no.ts \ + bitmessage_sk.ts \ bitmessage_ru.ts \ bitmessage_zh_cn.ts diff --git a/src/translations/bitmessage_ar.qm b/src/translations/bitmessage_ar.qm index 77ec5d7fc511ad99b10bff05a9a1d92f0190c132..e7d39f2da807314183ea117f39dfda4bfeb4015f 100644 GIT binary patch delta 2588 zcma)73s6+&75?ttz5BZRkQJnAgG9hrL=aH~m8f7eD62*VK>>MeSspG57$gXb5Tg=P zVAi*Uv8nMDAE`v5_-fQl42e{ORl#bkZA_|&IvQ-8D*ebh){e2$J3I6J_x%4o=R4my z=ik=DiVOP{Rql=|07C)00#H^1-erKa7Z|-6m^7H{FM*j~0R8=dIfH2D+7<~^jfV0J zZ7(l}vLylNyAH~>K)}cB!sK#DtCYatZIEhsKHw~*U0Z;+4?wj;9Q%(C0UJrB@RW@>c{^*8*d{M#%YcV73Jl*PbNVlP*kfNA#LI415&PYjwmQ zFg5cnU~wDXSbUi0-f>}E0b(jL8R%QYW^lhW4zu@%1G;+5RaL-&mA$aw5glajM&SoT zfZoL@+Ufu_7qG;>5h%*X`o&&A$|W=&O9VV0q4mTbDsvB)d(*Lf7&<<02SO(Z+RgU? zw_`$|Ud-H276#~jfEj8bXxi%tt`77*zeutv?2NLgjPVwG?c3|u&#n!pBdp}Za&2j7j+;bJD=Mnv{ zDJ~SBpj7J>*OhrdT!Z4)T2E%$SJbbPfR*oyhO_(lo-3M`H3RW}qIXR=@ailvu=x)R zlrE0QDFNQ>A&#+l0~LYdxTF@~wIO0{;xZDNDmLg@LPxyVxQ_3>`C^kpZ3VQO#HKDx zEEZeZR|8@X@kT5e4h<9A7t>*6srb(W(}6)TN>fq=P<&H4=F>=ENwqS@?@bOm5ETEHy>x$-<5<*bZn@XLhh_*ZD&cLjch)fhZJUGDTdWc zN%j>w^CxsewMIJN{gkE{yn9f+ByczlFCb&=+bs+eJJBhx#EyE-s6GX zo6@EgbR4i%+Otw(pcJVgodJWEN=@&w$%>~*XEq0OM8l0%dy5DvOVjR0v zpLR)~FjaMKro~FmAN^_;3;j zhr)T$L~9ziv$_1YYQA!KaT>nRv~D1J1#3FW7BbTW&A%=aJsxP?ug@UiYueu1e&qZw zjn(%1ih+H%YeVLy@&+5H&9l(a%O7hu{&_fSTc+JSx|0h1r0Z8s#z`l1*0w1?$!VP} zt(G_1O$Z&>fWT(~qa_V9h;_=Nq~crFBHJ?$){z zN?b5h7NYlXj0uaJaOf5N*uhxvTy6pWD?_#>CZY$ zWYWJ;T?2TOp<7<5HInmH>10DKYG59-o@}}%- zNZP)EL^c_+I!b`oPaEEfsN|S^ZaCjKgcs9l!`~}YI7Jr>KiS6eemP>qAL++lV;t0V zqxvj2Iwo~gP?F`wX`qDJamLEq+!)np+&pI_$K}59>zYs?d7rTAn>hw0&aZ*zWs#{yO>oS&qGdv+U_md0PMH7_qRBRM-KT@Xn~ z=Uf`r-MLe%m!H{pj!7M6e&+qj`ML&mqToD`66UmOy4C$k>o&PADt5i8&TRAf*{sv1 zWGAO)WoP8&*9B&b)78z-e_yPtE!^(w2w?fmSl1=Na}RG+Xr8mWJ+<&JX+wHlMI?q_WoOe?^rFLGr%=Us|3W delta 3585 zcmb7FeOOd=7Cv`A?hG@-j1X$+liUSGR2a}i1Q9hr!4IreL5PrH=8lZOz2m)i7?5O4 zvivGBltg)0w{?w5>4SAC@ncu5HA~WkENOM!wcKh=Ycp+qD)yZjv}|{ueRlqs-@U*4 zyXU;;ecyBL`}dbkFxhBNo%RVckTNdT7GtR-&{+lzgV1sL)2UnvMZ1 z1=o^%nz!`}Bz~FZH5st>(fnmAi0Z27=hX)Qc0J{-Uq-aXMfoo5uenHz_oWksv{4be zp6IDvpW&gQ8H0-7n6HNgM@<^rljCmqT(Zrkb;U63Yc{d15nO6X7k`~qNHAC$6i$M)Lf=( z7pSv-!Q8w68j`F`zbXS4oho)KfZivm;xB;WnDeU2wE~fGhic^~0DkwIswdr7h^FmV z?JmN8(0D$vz3{Bbzn+OID($do|@o6jX9XcZSoh}h(^xRrksH3$}QT|GDtC@O?&^fTq5%%?VJm}M3&Rq;<|m1@VwTM4<_S` zTCueQ2_M$huR@_uRBN}TAkUmr+U;NAd9}x<-LV#dt=qKi>$FI;P`iIA5{{R(-5X%C z)qUDiJ0}vU6SW`Yh zJxn)c7N|Cb=;od62EcG#Uc*YFg1_td@h+lAt97-JW};C#-Q#obAzC+Bx8eKuyhz0K2G@t?>y9J==*E+}zvY6dL34CBMgfp-cD8;p`y~)h*Dpw41RyK) z1&6kvQir~l&n03%(XaniA+)@t-#iwY&;DBfYB*l3cv*j-D;)!7n*Kx^%oVpy|F&-g z5~}rm%~Kg^kCh^YtS(t`&6@?0>KZzyxLVv>0b%P!ztUQTfJwizCo z3_#Ng4ejYS(M`WFyl%XPI3b4DTfRbjW*UyJ>cFZoeEv)w(IZ_(W?nm}PHHxW)If{7 zv_^yaG||{pW6ZTf(EJ@^?7?E}-!SIRhWi(-46ao@#s~YsMEy*VcSNo|cF%JL|Pno92`78a#w0LDXC@wTPzFva-1AYtbJ~r!7Dj^Qh^=+8#{4Uek?*NOVtw=|&IshaU^oU)l#Rw1%2z z;{NWG(BTyy!6RcrW10~!>Qrca;|rLmNuf*HngMK7X!-Rze9#VuuE^MgcI*s2bHa)N z_IRl8qfMn~x3@z7SvDP7cbe&U2&lxE$NEQaRE;_N`g%|nW`2M`@$!r2O;@p>dceH% zp~+~gOXhc4QqX>T%-sp-g2J2Tv$?B@@(Y7&^*_uP9K}R~cUvY19(+?eElJ10MBN_C zoZkY_$Q?gUJ=4@EN<(~UvfCzbvQksQPmSW7qM*ckdDqf1C3R9_ z;*_ZL2P9EWO)HfW($fi2<&pYA;QSotJQIcvnTdC+#xKf+F+$AjKJnmrBa=u2k zI&2E(bXD-2P39^@JjIHf10WE&6j=fw+%{Qumq|96AIS8-ipvmv!oOEn>5&zbHxM~i zlsK>CLZJ@PD~$PRCeGyypy8|Cyj|fGkt+q#QozOKogDeA@gG;pcoZ!0s78)deniTh ziE)gxHHK9U_JL4`|1HP_$}2g+6R6o1V8iQD%6CPQnJ(1r zDg_n?=MfxG+mCc!&ccMn^NLc!v4&G zy)4$sP6*s(vKfJs<8XE+JDVLt(98$f5^v{>%n_=1K|xEy!(zF|Epu+jB7-Brk;*0h z7aW5E*|XR6g0JTMM}u$2R=CRjZ34Fi#tgjd5nRhX{EvEOOu*+tpkw^q z<-_cAN(kwYIl0VlLzlw2J*Dsya=@p-whAQix+*IC(*ZPjaM0f{Zpl@J8G0LPpos=L zlCMD1mWt@^fkA5vVhuEWU>cz0IX}W5$cFSTnL`38SY{RP7YT(0;9!*ER1J3v%B?Vg dC>`hIcSlC7g<&iV^)pOAqv{{2HuR4*{tH^KKllIu diff --git a/src/translations/bitmessage_ar.ts b/src/translations/bitmessage_ar.ts index ce6b83f7..44a7c8a4 100644 --- a/src/translations/bitmessage_ar.ts +++ b/src/translations/bitmessage_ar.ts @@ -1,21 +1,21 @@ - + AddAddressDialog Add new entry - + إضافة مدخل جديد Label - + إسم مستعار Address - + عنوان @@ -76,7 +76,7 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: +Please type the desired email address (including @mailchuck.com) below: @@ -130,89 +130,49 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - - Bitmessage - Bitmessage + + Reply to sender + - - To - إلى + + Reply to channel + - - From - من + + Add sender to your Address Book + إضافة جهة اتصال لدفتر العناوين - - Subject - الموضوع + + Add sender to your Blacklist + - - Received - تاريخ الإستلام + + Move to Trash + حذف إلى سلة المهملات - - Inbox - البريد الوارد + + Undelete + - - Load from Address book - تحميل من دفتر العناوين + + View HTML code as formatted text + إظهار نظام تشفير HTML كنص منسق - - Message: - الرسالة: + + Save message as... + حفظ الرسالة ك - - Subject: - الموضوع: - - - - Send to one or more specific people - إرسال لشخص أو عدة أشخاص - - - - To: - إلى: - - - - From: - من: - - - - Broadcast to everyone who is subscribed to your address - إرسال لجميع المتابعين - - - - Send - إرسال - - - - Be aware that broadcasts are only encrypted with your address. Anyone who knows your address can read them. - إنتبه أن البث مشفر فقط بعنوانك، و يمكن لأي شخص يعرف عنوانك قراءة البث - - - - Status - الحالة - - - - Sent - البريد المرسل + + Mark Unread + وضع علامة غير مقروء @@ -220,234 +180,89 @@ Please type the desiged email address (including @mailchuck.com) below: جديد - - Label (not shown to anyone) - إسم مستعار خاص - غير مرئي للآخرين + + Enable + تفعيل - - Address - العنوان + + Disable + تعطيل - - Group - المجموعة + + Set avatar... + تغيير الصورة الرمزية - - Stream - مجرى + + Copy address to clipboard + نسخ العنوان إلى الحافظة - - Your Identities - هوياتك + + Special address behavior... + سلوك عنوان خاص - - 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. - هنا يمكن التسجيل لمتابعة مشاركات الآخرين، الرسائل ستظهر في البريد الوارد، و العناوين هنا تبطل العناوين في القائمة السوداء. + + Email gateway + - - Add new Subscription - إدخال إشتراك جديدة + + Delete + حذف - - Label - إسم مستعار + + Send message to this address + أرسل رسالة لهذا العنوان - - Subscriptions - الإشتراكات + + Subscribe to this 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. - دفتر العناوين مفيد لإضافة أسماء أو طوابع بريدية للأشخاص الآخرين مع عناوينهم لكي يسهل تمييزهم بسهولة في البريد الوارد، يمكنك إضافة جهات اتصال جديدة باستخدام زر إضافة أو من البريد الوارد بالضغط الأيمن على الرسالة الواردة. + + Add New Address + إضافة جهة إتصال - - Add new entry - إضافة جهة اتصال جديدة + + Copy destination address to clipboard + نسخ عنوان المرسل إليه إلى الحافظة - - Name or Label - إسم مستعار + + Force send + إرسال قصري - - Address Book - دفتر العناوين + + 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 غير مدعومه حالياً، هل باستطاعتنا حذفه الآن؟ - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - إستخدام القائمة السوداء - تسمح وصول كل الرسائل الواردة عدا العناوين المسجلة في القائمة السوداء + + 1 hour + - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - إستخدام القائمة البيضاء - تمنع وصول كل الرسائل الواردة عدا العناوين المسجلة في القائمة البيضاء + + %1 hours + - - Blacklist - القائمة السوداء + + %1 days + - - 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. - بانتظار مفتاح التشفير، سيتم طلبه مرة أخرى قريباً + + Waiting for their encryption key. Will request it again soon. + @@ -459,6 +274,16 @@ Please type the desiged email address (including @mailchuck.com) below: 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. @@ -484,15 +309,50 @@ Please type the desiged email address (including @mailchuck.com) below: 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. تم تجازو الصعوبة قصراً، ستبدأ الإرسال قريباً - - Message sent. Waiting on acknowledgement. Sent at %1 - تم إرسال الرسالة، بانتظار إشعار الإستلام، تم الإرسال في %1 + + Unknown status: %1 %2 + حالة غير معروفه: %1 %2 + + + + Not Connected + غير متصل + + + + Show Bitmessage + إظهار Bitmessage + + + + Send + إرسال + + + + Subscribe + إشتراك + + + + Channel + + + + + Quit + الخروج @@ -508,6 +368,11 @@ It is important that you back up this file. %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.) @@ -523,453 +388,39 @@ It is important that you back up this file. Would you like to open the file now? مهم جداً أن تحتفظ بنسخة إضافية من هذا الملف. هل ترغب بفتح الملف الآن؟ تأكد من إغلاق البرنامج Bitmessage قبل تعديل الملف. - - 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 - إرسال قصري + + Delete trash? + حذف سلة المهملات؟ Are you sure you want to delete all trashed messages? هل أنت متأكد من رغبتك في حذف كل الرسائل من سلة المهملات؟ - - - You must type your passphrase. If you don't have one then this is not the form for you. - يجب إدخال عبارة المرور، إن لم تكن لديك عبارة مرور، إذاً هذه ليست الطريقة المناسبة لك - - - - Delete trash? - حذف سلة المهملات؟ - - - - Open keys.dat? - فتح ملف keys.dat؟ - bad passphrase عبارة المرور غير جيدة - - Restart - إعادة تشغيل + + You must type your passphrase. If you don't have one then this is not the form for you. + يجب إدخال عبارة المرور، إن لم تكن لديك عبارة مرور، إذاً هذه ليست الطريقة المناسبة لك - - You must restart Bitmessage for the port number change to take effect. - لتفعيل تغيير رقم نقطة العبور (port) يجب عليك إعادة تشغيل برنامج Bitmessage. + + Bad address version number + - - 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. + + Your address version number must be a number: either 3 or 4. + - - Error: You cannot add the same address to your list twice. Perhaps rename the existing one if you want. - خطأ: لا يمكنك إضافة نفس العنوان مرتين إلى القائمة، يمكنك إعادة تسمية العنوان. - - - - The address you entered was invalid. Ignoring it. - العنوان الذي أدخلته غير صالح، سيتم تجاهله. - - - - 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. - تم إضافة جهة الاتصال لدفتر العناوين، يمكنك تعديل الإسم المستعار إذا أحببت. - - - - Error: You cannot add the same address to your address book twice. Try renaming the existing one if you want. - خطأ: لا يمكنك إضافة نفس العنوان إلى دفتر العناوين مرتين، يمكنك إعادة تسمية العنوان. - - - - Moved items to trash. - تم نقل المادة لسلة المهملات. - - - - No addresses selected. - لم يتم اختيار عناوين - - - - 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-'' - العنوان يجب أن يبدأ ب "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. - بعض البيانات المشفرة ضمن العنوان طويلة جداً. - - - - Address is valid. - العنوان صحيح - - - - You are using TCP port %1. (This can be changed in the settings). - أنت تستخدم نقطة عبور TCP %1 - يمكنك تغييره في قائمة الضبط. - - - - Error: Bitmessage addresses start with BM- Please check %1 - خطأ: عناوين ال Bitmessage تبدأ ب BM-، يرجى فحص %1 - - - - Error: The address %1 contains invalid characters. Please check it. - خطأ: العنوان %1 يحتوي على حروف غير صالحة، يرجى فحصه. - - - - 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 + + Your address version number must be either 3 or 4. + @@ -1037,164 +488,19 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2.تم الإنضمام للزمرة بنجاح. - - Fetched address from namecoin identity. - تم تحصيل العنوان من هوية namecoin. + + Connection lost + تم فقد الاتصال - - New Message - رسالة جديدة + + Connected + متصل - - 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 - الكل - - - - Message - الرسالة - - - - Fetch Namecoin ID - إحضار هوية namecoin - - - - Stream # - المجرى # - - - - Connections - الروابط - - - - Ctrl+Q - Ctrl+Q - - - - F1 - F1 - - - - Join / Create chan - إنضمام / تكوين زمرة - - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Blacklist - - - - - Undelete - - - - - Email gateway - - - - - 1 hour - - - - - %1 hours - - - - - %1 days - - - - - Waiting for their encryption key. Will request it again soon. - - - - - Message sent. Waiting for acknowledgement. Sent at %1 - - - - - Channel - - - - - 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. - + + Message trashed + تم حذف الرسالة @@ -1219,26 +525,146 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2.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 يدوياً لإغلاق الروابط الحالية -إن وجدت. + Number needed @@ -1269,6 +695,56 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2.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. @@ -1279,11 +755,31 @@ Il n'y a pas de difficulté requise pour ces adresses de version 2.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. @@ -1309,49 +805,89 @@ Are you sure you want to delete the channel? - + 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. - + 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. - + + You are using TCP port %1. (This can be changed in the settings). + أنت تستخدم نقطة عبور TCP %1 - يمكنك تغييره في قائمة الضبط. - - Display the %1 recent broadcasts from this address. - + + Bitmessage + Bitmessage @@ -1363,6 +899,41 @@ Are you sure you want to delete the channel? New Identity + + + Search + بحث + + + + All + الكل + + + + To + إلى + + + + From + من + + + + Subject + الموضوع + + + + Message + الرسالة + + + + Received + تاريخ الإستلام + Messages @@ -1373,55 +944,141 @@ Are you sure you want to delete the channel? Address book + + + Address + العنوان + Add Contact - - <!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> - + + Fetch Namecoin ID + إحضار هوية namecoin - + + 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 + Ctrl+Q + + + + F1 + F1 + + + Contact support + + + About + عن + + + + Regenerate deterministic addresses + إعادة إنتاج عناوين حتمية - غير عشوائية + + + + Delete all trashed messages + حذف سلة المهملات + + + + Join / Create chan + إنضمام / تكوين زمرة + All accounts @@ -1432,13 +1089,20 @@ p, li { white-space: pre-wrap; } Zoom level %1% - - - MainWindows - - Address is valid. - L'adresse est valide. + + 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. + @@ -1458,7 +1122,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> - + @@ -1482,8 +1146,8 @@ The 'Random Number' option is selected by default but deterministic ad - Address version number: 3 - رقم إصدار العنوان: 3 + Address version number: 4 + @@ -1540,34 +1204,6 @@ The 'Random Number' option is selected by default but deterministic ad (saves you some bandwidth and processing power) يوفر عليك بعض النطاق و القوة المعالجة - - - Address version number: 4 - رقم إصدار العنوان: 4 - - - - NewGroupDialog - - - Add new entry - إضافة مدخل جديد - - - - Label - الإسم المستعار - - - - Address - العنوان - - - - Group Name - إسم المجموعة - NewSubscriptionDialog @@ -1588,7 +1224,7 @@ The 'Random Number' option is selected by default but deterministic ad - CheckBox + Enter an address above. @@ -1622,6 +1258,11 @@ The 'Random Number' option is selected by default but deterministic ad aboutDialog + + + About + عن البرنامج + PyBitmessage @@ -1633,28 +1274,56 @@ The 'Random Number' option is selected by default but deterministic ad الإصدار ؟ - - About - عن البرنامج - - - - Copyright © 2013 Jonathan Warren - حقوق الحفظ © 2013 Warren Jonathan + + <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 - - <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + 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 @@ -1681,44 +1350,6 @@ The 'Random Number' option is selected by default but deterministic ad أسمح لي بتعديل ضبط الشبكة الخاص أولاً - - hashtagDialog - - - Hashtag - هاشتاق - - - - Trending Hashtags - الهاشتاقات النشطة - - - - Day - يوم - - - - Week - أسبوع - - - - Month - شهر - - - - All Time - كل الأوقات - - - - Popularity - الشعبية - - helpDialog @@ -1726,16 +1357,16 @@ The 'Random Number' option is selected by default but deterministic ad Help مساعدة - - - As Bitmessage is a collaborative project, help can be found online in the Bitmessage Wiki: - باعتبار أن برنامج Bitmessage هو مشروع تعاوني، يمكنك إيجاد المساعدة في Bitmessage Wiki: - <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: + باعتبار أن برنامج Bitmessage هو مشروع تعاوني، يمكنك إيجاد المساعدة في Bitmessage Wiki: + iconGlossaryDialog @@ -1795,7 +1426,7 @@ The 'Random Number' option is selected by default but deterministic ad Inventory lookups per second: 0 - معدل البحث ضمن المخزن لكل ثانية: 0 + @@ -1815,12 +1446,57 @@ The 'Random Number' option is selected by default but deterministic ad 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 + @@ -1848,7 +1524,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> - + @@ -1922,322 +1598,295 @@ The 'Random Number' option is selected by default but deterministic ad settingsDialog - + Settings الضبط - + Start Bitmessage on user login إبدأ برنامج Bitmessage عند نقطة ولوج المستخدم - - Start Bitmessage in the tray (don't show main window) - تشغيل البرنامج في شريط المهام - - - - Minimize 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. - - - - User Interface - واجهة المستخدم - - - - Use Identicons - استخدم Identicons - - - - Interface Language - لغة العرض - - - - Listening port - نقطة عبور للإستماع - - - - Listen for connections on port: - استماع للروابط في نقطة عبور: - - - - Proxy server / 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. - - - - 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 - الصعوبة القصوى المقبولة - - - - 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 - أنصت للروابط الوارده عن استخدام البروكسي - - - - 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 - - - - 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 - إنتهاء صلاحية إعادة الإرسال - - - + 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 - - Pirate English - en_pirate - + + User Interface + واجهة المستخدم - - Other (set in keys.dat) - other - + + 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 + + + + 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. + هنا يمكنك تحديد الكمية القصوى من العمل الذي ترغب بأدائه عندما ترسل رسالة لشخص آخر، تصفير هذه القيم يدل على قبولك بأي قيمة. + + + + 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 + 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> + + + Give up after + توقف بعد + + + + and + و + + + + days + أيام + + + + months. + شهور. + + + + Resends Expire + إنتهاء صلاحية إعادة الإرسال + diff --git a/src/translations/bitmessage_cs.qm b/src/translations/bitmessage_cs.qm index 4ae7368554f3829ec93566c69067fadfcb2273c4..34778a666167cb8ff884ab762e7b8f0b8a560fa4 100644 GIT binary patch delta 2822 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 diff --git a/src/translations/bitmessage_cs.ts b/src/translations/bitmessage_cs.ts index 0cf209cf..7f8aa393 100644 --- a/src/translations/bitmessage_cs.ts +++ b/src/translations/bitmessage_cs.ts @@ -76,7 +76,7 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: +Please type the desired email address (including @mailchuck.com) below: @@ -335,7 +335,7 @@ Please type the desiged email address (including @mailchuck.com) below: Ukázat Bitmessage - + Send Poslat @@ -350,7 +350,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Quit Ukončit @@ -623,7 +623,7 @@ Je důležité si tento soubor zazálohovat. Přejete si tento soubor nyní otev From - Od + Od @@ -805,92 +805,82 @@ Are you sure you want to delete the channel? 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. - - Display the %1 recent broadcast from this address. - Zobrazit %1 zprávu nedávno rozeslanou z této adresy. - - - - Display the %1 recent broadcasts from this address. - Zobrazit %1 zpráv nedávno rozeslaných z této adresy. - - - + 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í). @@ -910,37 +900,37 @@ Are you sure you want to delete the channel? - + Search Hledej - + All Vše - + To Komu - + From Od - + Subject Předmět - + Message Zpráva - + Received Doručeno @@ -970,12 +960,12 @@ Are you sure you want to delete the channel? Načíst Namecoin ID - + Subject: Předmět: - + From: Od: @@ -985,116 +975,107 @@ Are you sure you want to delete the channel? Komu: - - <!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 ordinary Message - + Send Message to your Subscribers - + TTL: - + X days - + Subscriptions Odběry - + Add new Subscription Přidat nový odběr - + Chans - + Add Chan - + 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 @@ -1118,6 +1099,11 @@ p, li { white-space: pre-wrap; } Add new entry Přidat novou položku + + + Display the %1 recent broadcast(s) from this address. + + NewAddressDialog @@ -1238,8 +1224,8 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi - CheckBox - CheckBox + Enter an address above. + Zadejte adresu výše. @@ -1612,72 +1598,72 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi 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. - + 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í - + Use Identicons Používat identikony - + Reply below Quote Odpověď pod citací - + Interface Language Jazyk pro rozhraní - + System Settings system Dle nastavení systému @@ -1686,231 +1672,231 @@ Možnost "Náhodné číslo" je nastavena jako výchozí, deterministi Pirate English en_pirate - Pirate English + Pirate English Other (set in keys.dat) other - Jiný (nastavený v keys.dat) + Jiný (nastavený v keys.dat) - + 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: - + 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í diff --git a/src/translations/bitmessage_da.qm b/src/translations/bitmessage_da.qm index 844be3adc37c4a037467a02eb7d39d8238e1a7f0..b32237db9cc1f67a90408a2cb0630c31e7cb38dc 100644 GIT binary patch delta 3115 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 diff --git a/src/translations/bitmessage_da.ts b/src/translations/bitmessage_da.ts index 60145cef..b471c5b5 100644 --- a/src/translations/bitmessage_da.ts +++ b/src/translations/bitmessage_da.ts @@ -76,7 +76,7 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: +Please type the desired email address (including @mailchuck.com) below: @@ -180,22 +180,22 @@ Please type the desiged email address (including @mailchuck.com) below: Ny - + Enable Aktiver - + Disable Deaktiver - + Set avatar... Sæt ikon... - + Copy address to clipboard Kopiér adresse til udklipsholder @@ -210,7 +210,7 @@ Please type the desiged email address (including @mailchuck.com) below: Email gateway - + Delete Slet @@ -239,21 +239,11 @@ Please type the desiged email address (including @mailchuck.com) below: Force send Gennemtving afsendelse - - - Add new entry - Tilføj nyt element - 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? - - - Since startup on %1 - Siden opstart - 1 hour @@ -345,7 +335,7 @@ Please type the desiged email address (including @mailchuck.com) below: Vis Bitmessage - + Send Send @@ -360,7 +350,7 @@ Please type the desiged email address (including @mailchuck.com) below: Kanal - + Quit Afslut @@ -497,46 +487,6 @@ Det er vigtigt at tage backup af denne fil. (Sørg for at lukke Bitmessage før Successfully joined chan. Du er nu medlem af kanalen - - - Objects to be synced: %1 - Objekter der skal synkroniseres: %1 - - - - Processed %1 person-to-person messages. - %1 person-til-person-beskeder behandlet. - - - - Processed %1 broadcast messages. - %1 broadcast-beskeder behandlet. - - - - Processed %1 public keys. - %1 offentlige nøgler behandlet. - - - - Down: %1/s Total: %2 - Download: %1/s Total: %2 - - - - Up: %1/s Total: %2 - Upload: %1/s Total: %2 - - - - Total Connections: %1 - Totalt antal forbindelser: %1 - - - - Inventory lookups per second: %1 - Opslag i objektdatabasen per sekund: %1 - Connection lost @@ -681,12 +631,12 @@ Det er vigtigt at tage backup af denne fil. (Sørg for at lukke Bitmessage før 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. @@ -859,92 +809,82 @@ Er du sikker på at du vil slette denne kanal? 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 - - Display the %1 recent broadcast from this address. - Vis den %1 nyeste broadcast-besked fra denne adresse. - - - - Display the %1 recent broadcasts from this address. - Vis de %1 nyeste 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). @@ -964,37 +904,37 @@ Er du sikker på at du vil slette denne kanal? Ny identitet - + Search Søg - + All Alle - + To Til - + From Fra - + Subject Emne - + Message Besked - + Received Modtaget @@ -1024,12 +964,12 @@ Er du sikker på at du vil slette denne kanal? Hent Namecoin ID - + Subject: Emne: - + From: Fra: @@ -1039,191 +979,107 @@ Er du sikker på at du vil slette denne kanal? Til: - - <!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 ordinary Message Send almindelig besked - + Send Message to your Subscribers Send besked til dine abonnenter - + TTL: TTL: - + X days X dage - + Subscriptions Abonnementer - + Add new Subscription Tilføj nyt abonnement - + Chans Kanaler - + Add Chan TIlføj kanal - - Use a Blacklist (Allow all incoming messages except those on the Blacklist) - Brug en sortliste (Tillad beskeder fra alle afsendere bortset fra dem på din sortliste) - - - - Use a Whitelist (Block all incoming messages except those on the Whitelist) - Brug en hvidliste (Bloker beskeder fra alle afsendere bortset fra dem på din hvidliste) - - - - Name or Label - Navn eller beskrivelse - - - - Blacklist - Sortliste - - - - Stream # - Flod # - - - - Connections - Forbindelser - - - - Total connections: - Totalt antal forbindelser: - - - - Since startup: - Siden opstart: - - - - Objects to be synced: - Objekter der skal synkroniseres: - - - - Processed 0 person-to-person messages. - 0 person-til-person-beskeder behandlet. - - - - Processed 0 public keys. - 0 offentlige nøgler behandlet. - - - - Processed 0 broadcasts. - 0 broadcast-beskeder behandlet. - - - - Inventory lookups per second: 0 - Opslag i objektdatabasen per sekund: 0 - - - - Down: 0 KB/s - Download: 0 KB/s - - - - Up: 0 KB/s - Upload: 0 KB/s - - - + Network Status Netværksstatus - + 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 @@ -1237,6 +1093,21 @@ p, li { white-space: pre-wrap; } 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. + + NewAddressDialog @@ -1357,8 +1228,8 @@ Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved a - CheckBox - + Enter an address above. + Vælg en adresse ovenfor. @@ -1422,6 +1293,44 @@ Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved a 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 @@ -1496,57 +1405,102 @@ Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved a Total connections: - Totalt antal forbindelser: + Since startup: - Siden opstart: + Processed 0 person-to-person messages. - 0 person-til-person-beskeder behandlet. + Processed 0 public keys. - 0 offentlige nøgler behandlet. + Processed 0 broadcasts. - 0 broadcast-beskeder behandlet. + Inventory lookups per second: 0 - Opslag i objektdatabasen per sekund: 0 + Down: 0 KB/s - Download: 0 KB/s + Up: 0 KB/s - Upload: 0 KB/s + Objects to be synced: - Objekter der skal synkroniseres: + Stream # - Flod # + Connections - Forbindelser + + + + + 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 + @@ -1648,72 +1602,72 @@ Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved a 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 @@ -1722,231 +1676,231 @@ Som standard er tilfældige tal valgt, men der er både fordele og ulemper ved a Pirate English en_pirate - Piratengelsk + Piratengelsk Other (set in keys.dat) other - Andet (indstillet i keys.dat) + Andet (indstillet i keys.dat) - + 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.qm b/src/translations/bitmessage_de.qm index 44b0b06fb601ae1d251bf45863f3dc338d68973a..d2ddfe6405bf01b61a07d6ea8d23766dae3cf285 100644 GIT binary patch delta 8572 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 delta 3228 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 diff --git a/src/translations/bitmessage_de.ts b/src/translations/bitmessage_de.ts index 802f8774..a06a9b04 100644 --- a/src/translations/bitmessage_de.ts +++ b/src/translations/bitmessage_de.ts @@ -76,9 +76,9 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: - E-Mailschnittstelle ermöglicht es mit anderen E-Mailnutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mailschnittstelle (@mailchuck.com) verfügbar. -Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: +Please type the desired email address (including @mailchuck.com) below: + E-Mail-Schnittstelle ermöglicht es, mit anderen E-Mail-Nutzern zu kommunizieren. Zur Zeit ist nur die Mailchuck-E-Mail-Schnittstelle verfügbar (@mailchuck.com). +Bitte füllen Sie die gewünschte E-Mail-Address (inkl. @mailchuck.com) unten: @@ -125,7 +125,52 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: # 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 +# The 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 sonst 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, erhaltne Sie +# die Zalungen direkt. Um es wieder auszuschalten, ändern Sie die +# "feeamount"-Variable auf 0. Erfordert Abonnement. @@ -336,7 +381,7 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Bitmessage anzeigen - + Send Senden @@ -351,7 +396,7 @@ Bitte schreiben Sie die gewünschte E-Mailaddresse (inkl. @mailchuck.com) unten: Chan - + Quit Schließen @@ -811,92 +856,82 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? 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. Dies ist eine Chan-Adresse. Sie können sie nicht als Pseudo-Mailingliste verwenden. - + 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. - + Some data encoded in the address is malformed. Einige in der Adresse kodierten Daten sind ungültig. - + Enter an address above. Eine Addresse oben ausfüllen. - + 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. - - Display the %1 recent broadcast from this address. - Die letzte %1 Rundrufe von dieser Addresse anzeigen. - - - - Display the %1 recent broadcasts from this address. - Die letzten %1 Rundrufe von dieser Addresse anzeigen. - - - + 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). @@ -916,37 +951,37 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neue Identität - + Search Suchen - + All Alle - + To An - + From Von - + Subject Betreff - + Message Nachricht - + Received Erhalten @@ -976,12 +1011,12 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Hole Namecoin ID - + Subject: Betreff: - + From: Von: @@ -991,116 +1026,107 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? An: - - <!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 ordinary Message Ordentliche Nachricht senden - + Send Message to your Subscribers Rundruf an Ihre Abonnenten senden - + TTL: Ablauf: - + X days X Tage - + Subscriptions Abonnements - + Add new Subscription Neues Abonnement anlegen - + Chans Chans - + Add Chan Chan hinzufügen - + Network Status Netzwerkstatus - + 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ütung 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 @@ -1124,6 +1150,11 @@ p, li { white-space: pre-wrap; } Add new entry Neuen Eintrag erstellen + + + Display the %1 recent broadcast(s) from this address. + Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. + NewAddressDialog @@ -1244,8 +1275,8 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei - CheckBox - + Enter an address above. + Bitte geben Sie oben eine Adresse ein. @@ -1618,72 +1649,72 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei 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 Systemtray minimieren - + Close to tray Schliessen ins Infobereich - + 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 Bitcoinadresse) - + Reply below Quote Antworte unter zitierter Nachricht - + Interface Language Sprachauswahl - + System Settings system Vom System übernehmen @@ -1692,231 +1723,231 @@ Die Zufallszahlen-Option ist standard, jedoch haben deterministische Adressen ei Pirate English en_pirate - Piraten-Englisch + Piraten-Englisch Other (set in keys.dat) other - Andere (in keys.dat einstellen) + Andere (in keys.dat einstellen) - + User Interface Benutzerinterface - + Listening 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 - + 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. - + 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. - + 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) Hardwaregrafikkartenbeschleunigung (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 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 - + <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 Ablauf herunterlädt, zum Beisplel 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 Viederersandversuche 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> - + Give up after Gib auf nach - + and und - + days Tagen - + months. Monaten. - + Resends Expire Neusendungsablauf diff --git a/src/translations/bitmessage_en.qm b/src/translations/bitmessage_en.qm index 9dad8dffceb9623e88f8b96d9cd0caf25574c6fa..d925dd6023249a2d001c2c96bec2fb85bd813e0f 100644 GIT binary patch literal 334 qcmcE7ks@*G{hX<16=n7(EZlonpMinVh+#UzC?F{WI)JK~7#RUrb_zrQ literal 23 fcmcE7ks@*G{hX<16=n7(EZlpygMop8iIEWihQJ9+ diff --git a/src/translations/bitmessage_en.ts b/src/translations/bitmessage_en.ts index cd552a9d..67adf5b4 100644 --- a/src/translations/bitmessage_en.ts +++ b/src/translations/bitmessage_en.ts @@ -801,82 +801,82 @@ Are you sure you want to delete the channel? - + 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). @@ -1096,7 +1096,7 @@ Are you sure you want to delete the channel? - + Display the %1 recent broadcast(s) from this address. @@ -1593,305 +1593,293 @@ 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. - + 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 diff --git a/src/translations/bitmessage_en_pirate.qm b/src/translations/bitmessage_en_pirate.qm index 18432860923466bd214912537edf9b6344b66411..69e6bde80093b2b1fb33eac0eba92e595a373db1 100644 GIT binary patch delta 1146 zcmb7Cc}P@o5dPkty8B#r)$-o;D6jHNO+nL0Nu;)t(C*xA7k#$4ZmVdKZm5-rh4Ruo zN}^jO41^Bq53wMTE+`8BD>|SED@6a0%w~IPQVBIY_-5ue^Ud}8>zUC8rrFC;1|S{? z{szgXIDp9#Q2PY({A?hj8=CBKz|)4+FX{mA<;bhLOF1V6^f4m8u>^=Up@2I?*oIxQ zMj)jXhf6zw=+|hk(gHy`CV~wGG@qG-!jC}UMJBO^-W>_yOyTzPKtKf3b&Uv8GDI({ z?-7wk^j=~Ie7eMJla%}q#O_C*0lp#PWNQr&#f#JRK|pGrB>iR<5W`8<>3gWaW=ZAr zIzX8(O&$3{gRPg=9WeuOgVOfYNI-O4+Br_VVQ*!H2fE>aE>~93OoihnWH;p$7;s7U zyw`&o7?$TZR|8A??`p#xHMka zL5-eG71jFr$qN_-Ccw1kL!pSnf!y@3B&x4l<8XvMEo7$oA5XjRT6 zH4<@M_3%t8pq)}Zj-`zNvp6K6_lSUj%T%NKTEJ_QfZ?2b(y$g-k>);iqMqv2ar9$7 z5)(lP-|Lso-xt;MJ$`GHij4-Yw16u$Su6QzzewI9RuA-xJrn~;s>d2NmG3?uK z;q2wkfCc8jcU@G7BbKI`#A#=1e--8ruVUV#p4Xhp(w`PJ{XgQsibcW`7x6pYbjo?5 zE6mEaIpsIp{hPheOkQaGyUyEuy&|AA7_AlMS)9RQEm9PlEoFiVmEBxk&XpF~1)Fz- m`)kx|O(yydnC)|3gHFru@%QFif<3kPb)^LtMFVvtVwfNKXX}0d delta 776 zcmX|X`)8*INmb1)sNg^>Y#3+Q!Hc(j`ZJJikiZ7KIUnh(%W7e~}d-6_qtYD0^iQhs$%g=Y4@sv1XGM-7mXi(S=6 zNZlwGcL3QgG`jkLw0r1j&;W727#)`YD2o_F#R9Oli7__Qxz7NmV)r#5_BeCt76GzV zg4w3WK>C8<1M3A;KZM*_5&iEMhMkxJ)JKJ8cQcUc6z1A^z@le!$F@;@0c*7l0uh63 z{ckHE8)1h#88R9WSth^IfV`;nm;=b{74=wB0D)7~x9Eir$q&R8o-5=qL0s2G1~R9` zV-hNi{Ud%kq@;t*=CQLTUW_xXb?!9d8@E7Vgb6eL_f8-Xzdk2YEH-18a&MW@JPobM>QP4YDV5D*iP?;Yr+sP8K9 zh%V5I6-5Cuq&uycx@-Y7Gm7a9N(2b1DnT)4Yas&zL0wl6W_qdt^ig3;=i2C=@@jfe zH-yxnMLz7bc>j2u$v-7%^S>1&`V-mkI0dYzg@=|CdXz|4@Zy!vTI+G@OZ+?=Ir>7V z3>BJ@?@tcN(B*)K@qd{*-){Ffyk7p0!{e=XyLeaKfl7xbhd26fi`1j@@@EmF20lqE KX(y(DVg3TzCd5eq diff --git a/src/translations/bitmessage_en_pirate.ts b/src/translations/bitmessage_en_pirate.ts index 988b6d15..c0a9e9bf 100644 --- a/src/translations/bitmessage_en_pirate.ts +++ b/src/translations/bitmessage_en_pirate.ts @@ -1,21 +1,21 @@ - + AddAddressDialog Add new entry - Add yee new entry + Add yee new entry Label - Label + Label Address - Address + Address @@ -76,7 +76,7 @@ Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: +Please type the desired email address (including @mailchuck.com) below: @@ -130,8 +130,13 @@ Please type the desiged email address (including @mailchuck.com) below: MainWindow - - One of your addresses, %1, is an old version 1 address. Version 1 addresses are no longer supported. May we delete it now? + + Reply to sender + + + + + Reply to channel @@ -139,11 +144,21 @@ Please type the desiged email address (including @mailchuck.com) below: Add sender to your Address Book + + + Add sender to your Blacklist + + Move to Trash + + + Undelete + + View HTML code as formatted text @@ -165,17 +180,22 @@ Please type the desiged email address (including @mailchuck.com) below: - + Enable - + Disable - + + Set avatar... + + + + Copy address to clipboard @@ -184,6 +204,16 @@ Please type the desiged email address (including @mailchuck.com) below: Special address behavior... + + + Email gateway + + + + + Delete + + Send message to this address @@ -199,11 +229,6 @@ Please type the desiged email address (including @mailchuck.com) below: Add New Address - - - Delete - - Copy destination address to clipboard @@ -215,9 +240,24 @@ Please type the desiged email address (including @mailchuck.com) below: - - Add new entry - Add yee new entry + + 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 + @@ -295,7 +335,7 @@ Please type the desiged email address (including @mailchuck.com) below: - + Send @@ -305,7 +345,12 @@ Please type the desiged email address (including @mailchuck.com) below: - + + Channel + + + + Quit @@ -358,6 +403,21 @@ It is important that you back up this file. Would you like to open the file now? 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 @@ -438,6 +498,29 @@ It is important that you back up this file. Would you like to open the file now? 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 @@ -468,6 +551,11 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -503,6 +591,11 @@ It is important that you back up this file. Would you like to open the file now? 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. @@ -529,12 +622,17 @@ It is important that you back up this file. Would you like to open the file now? - + + Sending email gateway registration request + + + + Address is valid. - + The address you entered was invalid. Ignoring it. @@ -543,6 +641,11 @@ It is important that you back up this file. Would you like to open the file now? 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 @@ -558,6 +661,36 @@ It is important that you back up this file. Would you like to open the file now? 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 @@ -608,11 +741,26 @@ It is important that you back up this file. Would you like to open the file now? 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... @@ -628,394 +776,6 @@ It is important that you back up this file. Would you like to open the file now? 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 - - - - - Fetch Namecoin ID - - - - - Subject: - - - - - To: - - - - - From: - - - - - Address - Address - - - - Add new Subscription - - - - - Label - Label - - - - Subscriptions - - - - - Network Status - - - - - File - - - - - Settings - Settings - - - - Help - Help - - - - Import keys - - - - - Manage keys - - - - - Ctrl+Q - Ctrrl+Q - - - - F1 - - - - - About - - - - - Regenerate deterministic addresses - - - - - Delete all trashed messages - - - - - 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. - - - - - 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. - - - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Blacklist - - - - - Undelete - - - - - Email gateway - - - - - 1 hour - - - - - %1 hours - - - - - %1 days - - - - - Channel - - - - - 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: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - - - - - Message queued. - - - - - Sending email gateway registration request - - - - - Error: You cannot add the same address to your subscriptions twice. Perhaps rename the existing one if you want. - - - - - Number needed - - - - - Your maximum download and upload rate must be numbers. Ignoring what you typed. - - - - - Sending email gateway unregistration request - - - - - Sending email gateway status request - - - - - 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. - - - - - Undeleted item. - - 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. @@ -1031,10 +791,100 @@ 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 @@ -1045,6 +895,41 @@ Are you sure you want to delete the channel? New Identity + + + Search + + + + + All + + + + + To + + + + + From + + + + + Subject + + + + + Message + + + + + Received + + Messages @@ -1055,55 +940,141 @@ Are you sure you want to delete the channel? Address book + + + Address + Address + Add Contact - - <!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> + + 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 + 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 @@ -1114,6 +1085,21 @@ p, li { white-space: pre-wrap; } 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. + + NewAddressDialog @@ -1140,9 +1126,9 @@ T' 'Random Number' option be selected by default but deterministi Use yee random number generator to make an arrddress - - Use a passpharase to make addresses - Use yee passpharase to make arrddresses + + Use a passphrase to make addresses + @@ -1156,8 +1142,8 @@ T' 'Random Number' option be selected by default but deterministi - Address version number: 3 - Arrddress version number: 3 + Address version number: 4 + @@ -1214,16 +1200,6 @@ 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 @@ -1244,7 +1220,7 @@ T' 'Random Number' option be selected by default but deterministi - CheckBox + Enter an address above. @@ -1278,6 +1254,11 @@ T' 'Random Number' option be selected by default but deterministi aboutDialog + + + About + + PyBitmessage @@ -1289,8 +1270,8 @@ T' 'Random Number' option be selected by default but deterministi Version ? - - About + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> @@ -1303,9 +1284,42 @@ T' 'Random Number' option be selected by default but deterministi This is Beta software. + + + blacklist - - <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + + 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 @@ -1341,19 +1355,14 @@ T' 'Random Number' option be selected by default but deterministi - <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> + <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: Bitmessage be project of many, a pirates help can be found online in the Bitmessage Wiki: - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - iconGlossaryDialog @@ -1368,9 +1377,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 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. + + 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. + @@ -1382,11 +1391,6 @@ 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. - - - 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. - - networkstatus @@ -1445,6 +1449,51 @@ T' 'Random Number' option be selected by default but deterministi 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 @@ -1512,14 +1561,9 @@ T' 'Random Number' option be selected by default but deterministi Number of arrddresses to make based on yee passphrase: - - Address version Number: - Arrddress version Number: - - - - 3 - 3 + + Address version number: + @@ -1546,316 +1590,299 @@ 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 - - Pirate English - en_pirate - + + User Interface + User Interface - - Other (set in keys.dat) - other - + + Listening port + Listenin' port - - <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> - + + Listen for connections on port: + Listen for connections on yee port: - - Give up after - - - - - and - - - - - days - - - - - months. - - - - - Resends Expire - - - - - Tray - - - - - Close to tray - - - - - Reply below Quote - - - - + UPnP: - + Bandwidth limit - + Maximum download 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 + + + + + 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. + + + + + 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 + + diff --git a/src/translations/bitmessage_eo.qm b/src/translations/bitmessage_eo.qm index 8c48a1ef6db99c24bedca1da0f65c8dd53a4d029..174c0bc11f705fa15d4e57942b5d1778215783bb 100644 GIT binary patch literal 74419 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 z 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 G^?w7S1Si1& delta 2815 zcmZWqX;f5K68`S%e!ab3XcQL|X%$dG5R51)5)oXn5siWiq9};X(v2W0ptNy|OH|;B zZ48Hy3^5urIQnAT_c$`BsL_z%j7cYY5>1RjW7K#wPBr|=ncGy@bvzK(3h|RVU^$?6CXc3t z8@;dp3G{duA-+w(kd+v_{c}p9sohRq18Y?)0nUeYyN>K8Ov)|+7ByhXvg34ad%LyX zM)JmNU}-m`*l2(0QA|G=14uzgRc)j=5y*c@_p_Fw_=7OOR|9A1E+?QJj^*~9z~X(_ zv8)G>VnpMqG{EN$Zl0^Bif`e``3FGMU8b#l4449#zb{o3Si%O*{fXGfW5djJE^ID~ zO&vn#>@2aF_Ko>$!)yvPVGpbDX#xhPuw!)!V1OTcPUIr;?@snghy&OLK~+V8U#k#8 z-9$}at1#UCCJ=B|$Xjm*3?agbyOdBDv#>e;0TA;@*p*6tOQNvLQ4e?r3SX@_2P|n4 ze%aoc64oj7Z;Mp%e1+lK0eVkXSgK=y5i=Cw*Y^YZ+ls-CGGfpftB9S`0*oG|s7YH( zJ^e&+R8Q0|DOWVQ=smz+(WK4{~xCStHwxpylAoL=S1Px^ldc%4!1 zTb)9po1>JgI|9)f<>$qLfcc5C+50Ss>|=3A>kgv4SsdC(T1dSs4qHf64*Zvx;J!gr z4;ItPNSFi8i5V${KFQ}S8E56;=RSMQ$#>fAwE%1D|)wxPvgzhtY@mZ1vNl&A63?$RPn+pRZ%&KtT;hc z_n#|3zXsLEmXqYys1A7;o4ikT<700U;S1HRWWrxEKBGQ6d>wlt9= zth2h*-v|V)SFfAc6)0J&-t8Ls2P5WsY&GBO~G=@htjk~GEp|>;_olXkG zzSZ1(hpgXd&5K)$fDTKv9e;R(v=FQ9_R;SI=+FjTB;bI_+99d)Y5cy|7A6uvPqTLC zmyy&0m$o+g6)xS`?%Yc1*=vCkv)0qNbdj{hM5Xz(q*Gi2LMo)7$0w;ppGtjCq><|D zq{Im{*AwI0ZO&b3@~b@*xLn#)vKpBEg;aj(CgCrTc3zJIa{rL3wS%bgep16q8!)m$ zayESL33OZf>K&rWaY(|_o2$1(tS%djm;W;crqmr zenCHdMGj3vls@D4IW#5l`facK(%9ANkFi1$mF%zwuJ_P+-~>W77ZQ$fsLN?kx54uBOQhGmcv`8`S7$+ zW?nxif;qT*&J(i}}m=5I!|Nif@Uxo7Z48p`^D3 z8%8*pyk}D9%I}O^8WY4U+%YkLPZ^WO9`XHShVoxZyK{?G#f@Y2l^ea~)8l*?d-nf3 z8t%8egFJJ>2$A0yZ{~Wd7YpTwCMEq(QGETtp8U}`@5;wYo|I(ddnXv>lB58EZ%eLb zy?8{5A3Z0fl=0IuO4vj`eC7}z3ss&$b=#?K8?uO;Fj(XbGaDEWPBrrM)J0-1j7J{d zJ^zu^9oDwOa$w{8GV)}5WS17x+l&$R&1d^tACNhac};xrM*GEmk&F2~4z8A$D%L=fkVt z)bYse5ps@ekDhh07NF3RBSOiaOV7Xh(&gCiFK7hzDKGsw zS73hp=btYa(veL7cG7DeGUX%pXDX}RZ6}%2+T$r|6F_^GIc>Lc$meyD66jF(SFa!1 zDzF~~*Ljh7u_9Nq$Q&-6nx(sz>ezc-gGqcIZF*=dpfDbVwx#Zhkl1y#21yjP(B-3N z8QovepT_e|QhB~hNw$LY#hI4T_N-i6;X+rs#Jaea>)F9WZUgHi97^+IrOXxL&B8U% fVJboAyHYx{5SQ46Emx8&(G_H2!RqydB{2411k6YX diff --git a/src/translations/bitmessage_eo.ts b/src/translations/bitmessage_eo.ts index 62ffb858..aaf8e974 100644 --- a/src/translations/bitmessage_eo.ts +++ b/src/translations/bitmessage_eo.ts @@ -1,21 +1,21 @@ - + AddAddressDialog Add new entry - Aldoni novan elementon + Aldoni novan elementon Label - Etikedo + Etikedo Address - Adreso + Adreso @@ -23,37 +23,37 @@ Email gateway - + Retpoŝta kluzo Register on email gateway - + Registri je retpoŝta kluzo Account status at email gateway - + Stato de retpoŝta 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): @@ -61,23 +61,24 @@ Registration failed: - + Registrado malsukcesis: The requested email address is not available, please try a new one. Fill out the new desired email address (including @mailchuck.com) below: - + La dezirata retpoŝtadreso ne estas disponebla, bonvolu provi kun alia. Entajpu novan deziratan adreson (kune kun @mailchuck.com) sube: Email gateway registration - + Registrado je retpoŝta kluzo Email gateway allows you to communicate with email users. Currently, only the Mailchuck email gateway (@mailchuck.com) is available. -Please type the desiged email address (including @mailchuck.com) below: - +Please type the desired email address (including @mailchuck.com) below: + Retpoŝta kluzo ebligas al vi komunikadi kun retpoŝtaj uzantoj. Nuntempe, nur la retpoŝta kluzo de Mailchuck (@mailchuck.com) estas disponebla. +Bonvolu entajpi deziratan retpoŝtadreson (kune kun @mailchuck.com) sube: @@ -124,31 +125,77 @@ Please type the desiged email address (including @mailchuck.com) below: # 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. Bezonas 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. Bezonas abonon. +# +# attachments: no +# Oni ignoros kunsendaĵojn. +# +# archive: yes +# Viaj alvenontaj retmesaĝoj estos arĥivitaj en la servilo. Uzu tion, se vi +# bezonas helpon kun senerarigado aŭ vi bezonas ekstere-liveritan 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 (defaŭlte 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 re-malaktivigi ĝin, agordu "feeamount" al 0. Bezonas abonon. + MainWindow - - 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 sender + Respondi al sendinto - - Reply - Respondi + + Reply to channel + Respondi al kanalo 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 + Malforviŝi + View HTML code as formatted text @@ -159,23 +206,33 @@ Please type the desiged email address (including @mailchuck.com) below: Save message as... Konservi mesaĝon kiel... + + + Mark Unread + Marki kiel nelegita + New Nova - + Enable Ŝalti - + Disable Malŝalti - + + Set avatar... + Agordi avataron... + + + Copy address to clipboard Kopii adreson al tondejo @@ -184,6 +241,16 @@ Please type the desiged email address (including @mailchuck.com) below: Special address behavior... Speciala sinteno de adreso... + + + Email gateway + Retpoŝta kluzo + + + + Delete + Forviŝi + Send message to this address @@ -199,11 +266,6 @@ Please type the desiged email address (including @mailchuck.com) below: Add New Address Aldoni novan adreson - - - Delete - Forviŝi - Copy destination address to clipboard @@ -215,14 +277,29 @@ Please type the desiged email address (including @mailchuck.com) below: Devigi sendadon - - Add new entry - Aldoni novan elementon + + 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 forviŝi ĝin? + + + + 1 hour + 1 horo + + + + %1 hours + %1 horoj + + + + %1 days + %1 tagoj Waiting for their encryption key. Will request it again soon. - Atendante al ilia ĉifroŝlosilo. Baldaŭ petos ĝin denove. + Atendante ilian ĉifroŝlosilon. Baldaŭ petos ĝin denove. @@ -239,6 +316,11 @@ Please type the desiged email address (including @mailchuck.com) below: Message sent. Waiting for acknowledgement. Sent at %1 Mesaĝo sendita. Atendante konfirmon. Sendita je %1 + + + Message sent. Sent at %1 + Mesaĝo sendita. Sendita je %1 + Need to do work to send message. Work is queued. @@ -272,18 +354,13 @@ Please type the desiged email address (including @mailchuck.com) below: Forced difficulty override. Send should start soon. - Devigita superado de limito de malfacilaĵo. Sendado devus baldaŭ komenci. + 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 @@ -295,7 +372,7 @@ Please type the desiged email address (including @mailchuck.com) below: Montri Bitmesaĝon - + Send Sendi @@ -305,12 +382,12 @@ Please type the desiged email address (including @mailchuck.com) below: Aboni - - Address Book - Adresaro + + Channel + Kanalo - + Quit Eliri @@ -331,7 +408,7 @@ Estas grava ke vi faru savkopion de tiu dosiero. Open keys.dat? - Ĉu malfermi keys.dat? + Ĉu malfermi keys.dat? @@ -355,7 +432,7 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier Are you sure you want to delete all trashed messages? - Ĉu vi certas ke vi volas forviŝi ĉiujn mesaĝojn el la rubojo? + Ĉu vi certe volas forviŝi ĉiujn mesaĝojn el la rubujo? @@ -368,527 +445,19 @@ Estas grava ke vi faru savkopion de tiu dosiero. Ĉu vi volas malfermi la dosier 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. + + Bad address version number + Malkorekta numero de adresversio - - Processed %1 broadcast messages. - Pritraktis %1 elsendojn. + + Your address version number must be a number: either 3 or 4. + Via numero de adresversio devas esti: aŭ 3 aŭ 4. - - 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. - - - - 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. - - - - 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. - Bitmessage wird den Proxy-Server ab jetzt verwenden, möglicherweise möchten Sie Bitmessage neu starten um bestehende Verbindungen zu schließen. - - - - 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. - Movis elementojn al rubujo. - - - - 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 - Sendita - - - - Label (not shown to anyone) - Etikdeo (ne montrita al iu ajn) - - - - Address - Adreso - - - - Stream - Fluo - - - - Your Identities - Via identigoj - - - - 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". - - - - Add new Subscription - Aldoni novan Abonon - - - - Label - Etikedo - - - - Subscriptions - Abonoj - - - - 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. - - - - Name or Label - Nomo aŭ Etikedo - - - - 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 + + Your address version number must be either 3 or 4. + Via numero de adresversio devas esti: aŭ 3 aŭ 4. @@ -898,12 +467,12 @@ p, li { white-space: pre-wrap; } You didn't enter a chan name. - Vi ne enmetis nonon de kanalo. + Vi ne enmetis nomon de kanalo. Address already present - Adreso jam ĉi tie + Adreso jam ĉi tie @@ -928,7 +497,7 @@ p, li { white-space: pre-wrap; } 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. + Kvankam tiu Bitmesaĝa adreso povus esti ĝusta, ĝia versionumero estas tro nova por pritrakti ĝin. Eble vi devas ĝisdatigi vian Bitmesaĝon. @@ -938,7 +507,7 @@ p, li { white-space: pre-wrap; } That Bitmessage address is not valid. - Tiu Bitmesaĝa adreso ne estas ĝusta. + Tiu Bitmesaĝa adreso ne estas ĝusta. @@ -948,222 +517,27 @@ p, li { white-space: pre-wrap; } 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. + Kvankam la Bitmesaĝa adreso kiun vi enigis estas ĝusta, ĝi ne kongruas kun la kanalonomo. Successfully joined chan. - Sukcese aniĝis al kanalo. + 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. + + Connection lost + Perdis konekton - - 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. + + Connected + Konektita - - Search - Serĉi - - - - All - Ĉio - - - - Message - Mesaĝo - - - - Join / Create chan - Aniĝi / Krei kanalon - - - - Encryption key was requested earlier. - Verschlüsselungscode wurde bereits angefragt. - - - - Sending a request for the recipient's encryption key. - Sende eine Anfrage für den Verschlüsselungscode des Empfängers. - - - - Doing work necessary to request encryption key. - 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 für den Verschlüsselungscode versendet (wird automatisch periodisch neu verschickt). - - - - Sending public key request. Waiting for reply. Requested at %1 - Anfrag für den Verschlüsselungscode gesendet. Warte auf Antwort. Angefragt am %1 - - - - Mark Unread - Marki nelegita - - - - Fetched address from namecoin identity. - Venigis adreson de Namecoin identigo. - - - - Testing... - Testante... - - - - Fetch Namecoin ID - Venigu Namecoin ID - - - - Ctrl+Q - Stir+Q - - - - F1 - F1 - - - - 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. - - - - - 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. - - - - - Reply to sender - - - - - Reply to channel - - - - - Add sender to your Blacklist - - - - - Undelete - - - - - Email gateway - - - - - 1 hour - - - - - %1 hours - - - - - %1 days - - - - - Channel - + + Message trashed + Movis mesaĝon al rubujo @@ -1171,175 +545,605 @@ p, li { white-space: pre-wrap; } 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 pro %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 + Eraro: Bitmesaĝaj 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 adresversio %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 address %1 is too short. There might be something wrong with the software of your acquaintance. + Eraro: Kelkaj datumoj koditaj 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 koditaj en la adreso %1 estas tro longaj. Povus esti ke io en la programo de via konato malfunkcias. Error: Some data encoded in the address %1 is malformed. There might be something wrong with the software of your acquaintance. - + Eraro: Kelkaj datumoj koditaj en la adreso %1 estas misformitaj. 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'. + + + + 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. + Priaboranta adreson %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. + Priaboranta adreson %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 ero(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 + De Sending email gateway registration request - + Sendanta peton pri registrado je retpoŝta kluzo + + + + 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 jaman 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 jaman 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 vian prokurilon (proxy) ekde nun sed eble vi volas permane restartigi Bitmesaĝon nun por ke ĝi fermu eblajn jamajn 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 - + Sendanta peton pri malregistrado de retpoŝta kluzo Sending email gateway status request - + Sendanta peton pri stato de retpoŝta kluzo + + + + 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 etikedon laŭvole. 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. - + Malforviŝis 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 forviŝos 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 forviŝi 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 forviŝos 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 forviŝi la kanalon? - + + Do you really want to remove this avatar? + Ĉu vi certe volas forviŝi tiun avataron? + + + + You have already set an avatar for this address. Do you really want to overwrite it? + Vi jam agordis avataron por tiu 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... + Testante... + + + + This is a chan address. You cannot use it as a pseudo-mailing list. + Tio estas kanaladreso. Vi ne povas ĝin uzi kiel kvazaŭ-dissendolisto. + + + + 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. + La numero de adresversio estas pli alta ol tiun, 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. + 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. + + + Some data encoded in the address is malformed. - + Kelkaj datumoj koditaj en la adreso estas misformitaj. + + + + Enter an address above. + Enmetu adreson supre. + + + + Address is an old type. We cannot display its past broadcasts. + Malnova speco de adreso. Ne povas montri ĝiajn antaŭajn elsendojn. + + + + There are no recent broadcasts from this address to display. + Neniaj lastatempaj elsendoj de tiu adreso por montri. + + + + 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 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 - + Adresaro + + + + Address + Adreso Add Contact - + Aldoni kontakton - - <!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> - + + Fetch Namecoin ID + Venigu Namecoin ID + + + + Subject: + Temo: + + + + From: + De: + + + + To: + Al: + + + + Send ordinary Message + Sendi ordinaran mesaĝon - Send ordinary Message - - - - Send Message to your Subscribers - + Sendi mesaĝon al viaj abonantoj - + TTL: - + Vivdaŭro: - + X days - + X tagoj + + + + Subscriptions + Abonoj + + + + Add new Subscription + Aldoni novan abonon + + + + Chans + Kanaloj + + + + Add Chan + Aldoni kanalon + + + + Network Status + Reta Stato + + + + File + Dosiero + + + + Settings + Agordoj + + + + Help + Helpo + + + + Import keys + Enporti ŝlosilojn - Chans - + Manage keys + Administri ŝlosilojn - - Add Chan - + + Ctrl+Q + Stir+Q - + + F1 + F1 + + + Contact support - + Peti pri helpo + + + + About + Pri + + + + Regenerate deterministic addresses + Regeneri determinisman 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 la %1 lasta(j)n elsendo(j)n de tiu adreso. @@ -1347,98 +1151,99 @@ p, li { white-space: pre-wrap; } 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 adresojn, kiom vi volas. Ververe kreado kaj forlasado de adresoj estas konsilinda. Vi povas krei adresojn uzante hazardajn nombrojn aŭ pasfrazon. Se vi uzos pasfrazon, la adreso estas nomita kiel 'determinisma' adreso. +La 'hazardnombra' adreso estas elektita defaŭlte, sed determinismaj 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 savkopion de keys.dat dosiero 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 nombro 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 fari la adreso(j)n 1 aŭ 2 signoj pli mallongaj Make deterministic addresses - - - - - In addition to your passphrase, you must remember these numbers: - - - - - Passphrase - Pasfrazo - - - - Number of addresses to make based on your passphrase: - Kvanto de farotaj adresoj bazante sur via pasfrazo: - - - - 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) - + Fari determinisman 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 + + + + Number of addresses to make based on your passphrase: + Kvanto de farotaj adresoj bazante sur via pasfrazo: + + + + Stream number: 1 + Fluo numero: 1 + + + + Retype passphrase + Reenmeti pasfrazon + + + + 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 tiun estas la unuan de ĉiuj adresojn vi kreos) + + + + Use the same stream as an existing address + Uzi saman fluon kiel jama adreso + + + + (saves you some bandwidth and processing power) + (konservas iomete rettrafikon kaj komputopovon) @@ -1446,22 +1251,22 @@ The 'Random Number' option is selected by default but deterministic ad Add new entry - Aldoni novan elementon + Aldoni novan elementon Label - Etikedo + Etikedo Address - Adreso + Adreso - CheckBox - + Enter an address above. + Enmetu adreson supre. @@ -1469,27 +1274,27 @@ The 'Random Number' option is selected by default but deterministic ad 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 la kvazaŭ-dissendlisto: @@ -1507,12 +1312,12 @@ The 'Random Number' option is selected by default but deterministic ad version ? - Veriso ? + versio ? - - - Copyright © 2013 Jonathan Warren - Kopirajto © 2013 Jonathan Warren + + + <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> + <html><head/><body><p>Aŭtorrajto © 2012-2014 Jonathan Warren<br/>Aŭtorrajto © 2013-2014 La Programistoj de Bitmesaĝo</p></body></html> @@ -1524,10 +1329,43 @@ The 'Random Number' option is selected by default but deterministic ad This is Beta software. Tio estas beta-eldono. + + + blacklist - - <html><head/><body><p>Copyright © 2012-2014 Jonathan Warren<br/>Copyright © 2013-2014 The Bitmessage Developers</p></body></html> - + + 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) + + + + 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) + + + + Add new entry + Aldoni novan elementon + + + + Name or Label + Nomo aŭ etikedo + + + + Address + Adreso + + + + Blacklist + Nigra Listo + + + + Whitelist + Blanka Listo @@ -1540,12 +1378,12 @@ The 'Random Number' option is selected by default but deterministic ad Bitmessage won't connect to anyone until you let it. - Bitmesaĝo ne konektos antaŭ vi permesas al ĝi. + Bitmesaĝo ne konektos antaŭ vi permesos al ĝi. Connect now - Kenekti nun + Konekti nun @@ -1562,19 +1400,14 @@ The 'Random Number' option is selected by default but deterministic ad - <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> + <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: Ĉar Bitmesaĝo estas kunlabora projekto, vi povas trovi helpon enrete ĉe la vikio de Bitmesaĝo: - - - <a href="https://bitmessage.org/wiki/PyBitmessage_Help">https://bitmessage.org/wiki/PyBitmessage_Help</a> - - iconGlossaryDialog @@ -1591,12 +1424,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. - 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. + Vi konektis almenaŭ al unu samtavolano 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). + Ĉu vi estas uzanta TCP pordon ?. (Tio estas ŝanĝebla en la agordoj). @@ -1609,57 +1442,102 @@ The 'Random Number' option is selected by default but deterministic ad 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 Down: 0 KB/s - + Elŝuto: 0 KB/s Up: 0 KB/s - + Alŝuto: 0 KB/s Objects to be synced: - + Samtempigotaj eroj: Stream # - Fluo # + Fluo # Connections - Konetkoj + Konetkoj + + + + Since startup on %1 + Ekde lanĉo de la programo je %1 + + + + Objects to be synced: %1 + Eroj por samtempigi: %1 + + + + 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. + + + + Down: %1/s Total: %2 + Elŝuto: %1/s Entute: %2 + + + + Up: %1/s Total: %2 + Alŝuto: %1/s Entute: %2 + + + + Total Connections: %1 + Ĉiuj konektoj: %1 + + + + Inventory lookups per second: %1 + Petoj pri inventaro en sekundo: %1 @@ -1684,6 +1562,11 @@ The 'Random Number' option is selected by default but deterministic ad Create a chan Krei kanalon + + + <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> + Chan name: @@ -1692,18 +1575,13 @@ 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>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> + <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 hom-legebla vorto aŭ frazo (la nomo de la kanalo). Por sendi mesaĝon al ĉiu en la kanalo, sendu normalan inter-personan 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: - - - <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 @@ -1715,7 +1593,7 @@ The 'Random Number' option is selected by default but deterministic ad Regenerate existing addresses - Regeneri ekzistantajn Adresojn + Regeneri ekzistantajn adresojn @@ -1728,14 +1606,9 @@ The 'Random Number' option is selected by default but deterministic ad Kvanto de farotaj adresoj bazante sur via pasfrazo: - - Address version Number: - Adresa versio numero: - - - - 3 - 3 + + Address version number: + Numero de adresversio: @@ -1750,333 +1623,323 @@ 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 - Elspezi kelkajn minutojn per aldona tempo de komputila kalkulado por fari adreso(j)n 1 aŭ 2 simbolojn pli mallonge + Pasigi kelkajn minutojn aldone kompute por krei la adreso(j)n 1 aŭ 2 signoj pli mallongaj 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 markobutono samkiel vi faris kiam vi generis vian adreson la unuan fojon. + Vi devas marki (aŭ ne marki) tiun markobutono samkiel vi faris kiam vi generis vian adreson unuafoje. 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 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: - + Se vi antaŭe kreis determinismajn adresojn sed perdis ilin akcidente (ekz. en diska paneo), vi povas regeneri ilin ĉi tie. Se vi uzis la generilo de hazardnombroj por krei vian adreson tiu formularo ne taŭgos por vi. 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 Pirate English en_pirate - + Pirate English Other (set in keys.dat) other - + Alia (agordi en keys.dat) - - <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> - + + User Interface + Fasado - - Give up after - + + Listening port + Aŭskultanta pordo (port) - - and - + + Listen for connections on port: + Aŭskulti pri konektoj ĉe pordo: - - days - - - - - months. - - - - - Resends Expire - - - - - Tray - - - - - Close to tray - - - - - Reply below Quote - - - - + UPnP: - + UPnP: + + + + Bandwidth limit + Rettrafika limo + + + + Maximum download rate (kB/s): [0: unlimited] + Maksimuma rapido de elŝuto (kB/s): [0: senlima] + + + + Maximum upload rate (kB/s): [0: unlimited] + Maksimuma rapido de alŝuto (kB/s): [0: senlima] + + + + Proxy server / Tor + Prokurila (proxy) servilo / Tor + + + + Type: + Speco: + + + + Server hostname: + Servilo gastiga nomo (hostname): - Bandwidth limit - + Port: + Pordo (port): + + + + Authentication + Aŭtentigo - Maximum download rate (kB/s): [0: unlimited] - + Username: + Uzantnomo: + + + + Pass: + Pasvorto: + + + + Listen for incoming connections when using proxy + Aŭskulti pri alvenaj konektoj kiam dum uzado de prokurilo + + + + 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 kiu 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 defaŭlte estas 1. Vi povas pligrandigi tiun valoron por novaj adresoj kiuj 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) + Aparatara GPU-a plirapidigo (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;">testo. </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: - Maximum upload rate (kB/s): [0: unlimited] - + Password: + Pasvorto: - - Hardware GPU acceleration (OpenCL) - + + Test + Testo + + + + 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>Defaŭlte 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 eblas ŝanĝi kiam Bitmesaĝo devos rezigni je sendado.</p><p>Lasu tiujn kampojn malplenaj por defaŭlta sinteno.</p></body></html> + + + + Give up after + Rezigni post + + + + and + kaj + + + + days + tagoj + + + + months. + monatoj. + + + + Resends Expire + Resenda fortempiĝo diff --git a/src/translations/bitmessage_fr.qm b/src/translations/bitmessage_fr.qm index 7d7adbd0ff6d06b36a7d953f74bb9e5539a193e1..55e86be8392c1c12ff1049c860fa55f355f77954 100644 GIT binary patch literal 73001 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%0D!23lF#@K1KOTkBZ$x$m z>#9&9tW3C0k!9(|Mtb6d1^pEL;fYj4fzX`fbM!pO%D9?S?eb_kBom!zZ8}nB=Gwds zl@7dG_OfLqFuK;XPZS;~Q8}uPCAmlbY-ay77QM}5$VcD3WuQkhQnj%e|VC$4)RPNlIC$Y0~yJ=fJ5O4;!~CK;f%HARXSSU_iS6NbrLuEL>q4-R5DpShoceR_QlLhyBcE zx3B~bD*(|(O2S=l8kWeek6nr30ssEN!sX zn!YSuBi9yZqh9kL%^%|Ih$fXbQVq&!>hzjt%$O*>QfW@B1V|zY4Mq#XQc6l^ONA@S z87Y_s!lT{R2vsmP;#h=b5Yw*9`O?ln7sSz0GTCScb9pF?`rH473r&JPSDGkK_ym>4pnq$nby+T z&y_vau1rpW0|OVibN3L4?m!3~)s1_u^d*AT3P#%58zB}2hKaA4u?&>QphmD*2$&3g zyXLTV5|nZCFELUl+!1X;p;4Jw0th^@LR8U460_|1icY2IDY|<1r^k17M$Sfebwa1m zE6A9sVcJlZPH?s{vD#9jL^DCtdADWp^_heWYeJjarlC_qg+SJj;_>mJI}$d?YEpvYjAI@LmJ6Xs({8cL{5Cb{dlS#Z zkq&c`Z78WaA~w;%Br1xdNebER&jk$IpD}7zSM-GW4anh*Wag7cW!ke%t-h^TqMfTm zW0C)fAsC-*vMkp*zp3P(b5cCu%{gR(jt*O;UrZgEv0{c7#1vflHe)K?+Lbr7=@O)h zXNQzQI`8$}GbD=HAouotXg&G(`+nKH{ zeJFhA#a)xZJ%SSKV}NF5cnFZN5DO#&6jxXf!slyK;2sBXklDDLE6!J`j(Km)e5KBi zWT}95ZEun|bU|!@~sq%3Z zb60{NKs^tlI-b$IM1G2Y#DdBX8~%LQ$0){}Jr^MpXy$CWjHpQQI$wh*pXyIgnC13O z-tM%BB!zkOr1pEXSVAB563!LMQ*camoV63L6TBqoAUJTuD$Hh?nxnHamO%=6kJss- zbe5YhOSmi~3m~<);n>_9Bw|^N9Ng(N=WOGM64{K}QDsV1=sp(UXYO;86HO8{`ipg* zNe1%=X9XcQsX#LUf5Ik`6uebg@bdj3{r*vZ39e5H)~*5Jx?eC*XNiq4u6Ia5M2vkl zr_MN~9ri4#MhnBPJ>iNpo4LU7S-x=`cMI!*O}Wl0&3%vpvhD z!G=m3cew#DHv+k|&r?*`paJZBkXcM9e0`t|_Ij2xkW+tX2xVc2cD6 zz9Sp{b!mi+n^l%Evh?PHAIy2nA*%RK@3Z90Mec z@-d#~=-yqb4q2zJhYk76_04rUBwe!2e;Ak;omknHQK8kXe^}4c zvNHrX84PO7)Ko+Dv3g_E6W8m1BO}VSoce4@PG`q4jn?(jy@Ex$#t5_G~5b zf@qv^A&&QSQA=`q^Wy!}k)sR8*r+Hmx&*=u5lr%2mH7P#wJCF{u zga>xwdZ(sw+fZLum#Nt^Ci@7N1hd`bp=~Ib3SBF!MJhOx^vQ&426P`aP<$WlHS98z zqBx}SU>}?V^ZxL_@b~y8;2x!EXE|73%!qzNLR#e)#B|(`8m~g$S_>zC3-Fq$+_~1A z+7!Q~)mz8LcqpsdIID^{`=`mL$*d$6*cz?N+a$(`ZVOxE!-H)IefT61ih;>ODOJN5 zy-Bau*c283N%6hN61xtuVw$MRCtbuP5t5|)G=atY4i=b>t*D%lr!!dmS#kwHuh8><0(e=Fj-}Hr zQbL?=Svj!&sWb(HG=zGX8AhePf)%%)dJAQs%CiPM-?E-#Iu z-8Q9PDdAezNkzKbeCn5iE^M}7KmFuKPwb?02dg>Dr76>8u-Z!GmN#3bs)wuVvU>YA z9m(9Xe#ST)~I~XlyEpFM`%z7uv&k@8PQ}EE+Z3^rt<;JNg|AuSS@BDASjJM zEMRfiYkkII?`N(moQF_^O@j>fq2VB40BZoI&({nae#ydHHE@xTiy=}Il$g?tO~3-| zu-jDiVk&2MjaBiR1wYO8iDH=hi)QQBIA$H14`!)(=3*R7c(ZYAen6@WI4?Yn2U9kgIva6twQ)#vaB^fK4dl6v zQjXuy6q-?*X;4Wn-P@#jD~bo8QoWwS8?^K%P7EhwWX9$iFKaAiTWJhr^`MU<`vX#L zr(9zMHOCtKVJNg{du8a|pVZ7yuF0N;s9HyjjLom^fMMS;mO_z*0CDFh@`G`U?_3(x z$sCnNe{!V;sOcCX@BVj?c#5&^5WhotW=%t5mj4VqRU}o64ziL=w3ZrF7YX$yvh~cY zEY$5%+sy7xpq=5*$VW5~p|f~gJZn7I-KYa^v?eIDBb$6QVT(eQ?QKk)N(6rq*rPdz z02)Ue9`rm$);9c>ISy)v%33%CYF)FWbG2LLF@5mIK`og%=|I7x*`6pSUax=GN-${h z6lsfXlJ%u)x2@~6pc@m6(C3Rtig8L48TKR%5&%_| z9Z|-Uw(+rg{qW?3+Q!8!O-15r!yupoq7l@%G(SnW)~A?x{OnMz?*P<*f_8(xp2R{R zJj;c{)GShf@obNLHcb-E+Q;nk4+Bsek}phdPS=Ji!`>n-*zJo?Z4!YXqDxn{qHwCt zc)nS*g{ee%kFptL>%o~VCTTMe;c>p!YnAKyaVeCAUiqyugJ}NV)S3^Egp8%>?pIyIBT9tadL-d z$07?X*qLR>(+^17(j}mWl&GOX&S6KHchN~t6h%v4Zum|zWwDy^IK2I+Xyl2htXPng zXFah4-GO4vL{niV-%Zx%^ryy5R9`ysW4uZW&k9DL&LZkBI{9hR36|Rg8B3tk(l={# z)7WMgH}&b%_4VmDOq{H?UOQvLlhM_^OfZ|Kp1b>$GOs%&2MG(}XxaYFtdv53^P~)3 z%`hkHI;q$LOiK(RN>5X1&_D>Q8a-GX36X$IVvdFsB99>84m16lnkCyrhZC_k_f2RM zD|T%1l`E_(#7uButQ9M+)K+5fn%T*F{+YuCyRu$B0k`Q3YnwDXCl(puR#M2Bb!Kh+ zc%%eUH_i^WL+OUJpzgg&JOqZ1=^xfoaOiEEe7jjNkXeM|+GjJ|#g3l*p7#q!G_a79XLi%05yl8d`wnGW;>a6ctMwQi+A8cXb_A;= z@L_ndKmhF*<^bBhQ3-91vxR_+k_{$%APKf<*rV*+Cv3;-dSP+4daE7r>q`Pv$HVy> z<Ghk`WusIrOFcc2)j z4#n~@xKPYVX|b!+%4 z2MY$1lWqlHJf9r4$ZTuFbxDz2C;iL)IF<&XRUcaW*u<9Y8mH;Orthwy=S9@y$oRM! zZY&4#3gpS!xI9Ls-KhZW(0L~FZ;H`kcy!J?Pf6Sz@PdbK;SkdZEFKs#mJLU;HTH>7 zoc8V{#6h;_6_H^vC7x!2H2@*=EfEXK-s0GCUaGvgCeO&0VLX((+sK;~uf;gyJ)syn zik&qY(XP+>*T&GcB1E!9(oo^VOpWc@g*dPkmC{-KDZ3`aS3Ei;e;%GeLlS{~z>!4! zwd2&Tit$GTLx=?-o~Wt?^7c4sR8kSgCcqKUSv3@Y4|`zv59?w5A&VN~QpNYP-czXB z>S`1VlcbW?9*4!*M;7T3y{COnX*+0hazuw@^MDl}Vup*38uP*7rPcl*zA{axz6V!= zWwKV)qenB%Q)@g2)_eo0kNqfS<>iOEoxH?S*vKjpHHCQF66c=5L&2ilbMkt~Ej

g|+C>hQ8nJj~?3{U}VBQSY2rc<{b^Y-{~M>671J!11Eja zw>$xOI|nW;>wu6v49+Js=AMPe#tT5_RgLy*4Ltwx23!I$Vxxu-h{4G4STL`%7_;yc zp=)Zi?`FeibvT&MR*auc=i{5hx7gJP^f`tJ(ax0ddH5?=lTAaQssQjbV!nAkpi*PO zHVSBnC1UbyfblXG?WFIlK4H=6(ZI&LSR82r8`%PhdQd=#ax>LQ?pV4rU z5ZH5{i8=4+{XWcWn+~kyGuFNh4=gNX9eW-J8&b`>$rixNf0=#I3oz9ZW*<%86_l{v zaTMT$UCg;j0g&d-2Ke`-`wYxrET;?lD_D>pMgDO(3x*De%VA+(=z`|2SfmqWp4pzQ znq&i%ma~jQ1bwIVY|DOvaPnhzGM@u7eqz7%+5;$_HrnB#?5gYlY+lAb?jVQLcd%~? zcc4p^LO4Z^b6+atna_cWN`|_DYgYY1G>#u?DVJirwuVGt_M+sslkf!nVpE;&lUHUoF|g>S5)dIgS9JB z{LM!L?=ExvVh6CcE}Xnp0Go1})7~rudW_-pE2w1eeYvKEPl5Clu0xh91-_iKaNG{o zLC;ycQ#&8s&)MESL;)sq4l>4qdyoU?> zLeP($#l_f=7PNoFZ7wSU?i}Yfe+dA#)^gbaD=6Sx?u2}S0#qn$46D>2A9}!sbfT1xkO;|dt@*jL z2_dt+{DS|e=FcAUOW)rGj@R%>eW95-R$I|IQLkZy2SD2MekPqB1#M_sGxm^d*oZeF?SS3(E$-?1r&#d>7;-rRcP=y%IuCRVVfJ>dsVe^cx$kUJyh!)9s;A@s#04}SD5*$ zQmZMD5gSy-jN93OkB7<>Q2+$#RoikYgCVa}c`?h0e4^^twbWJ!YP8)xG}`+7M*FQ? zb<~T#&pV?!=a3B+#8eNIbn*TY)uX!v@iAxBbHg1HxI)#3&ZmL0K((Xt4Vdp+wd0#Q z60T21wYTdydeBPkcRC%goS|MY*anE1u3o);0#NO)Uf-QqUumOGJF5e3c2=MA9RSwU zOnvI4D4%m2s?i+i+E-nfhb;Oy* z^eAy_!eyYmwRk9(IA@H=60h600qZeQy#60S*nPHG_LSN%yHvb&&p;4XiRJ5Q5pgdO z{~7y**lefK7@er^w`im&Vm<0KO-ICmStn|mhL!@Ho91WsjI=&k(#IB_gg6Bd$9^MBG{P55Jqur}a_We#dhoIeepq23zPb8>jsLQ~-S znH27xrfB?E5|T*Gaft+ITc+l0DP?4CuQ?x2ZJM)7b7LiuZkD8Z;$KZl*-=xwi2@t? zMq(ohh$AZ{F(#A}Nsu($O<iNSWW3v`Yt5=1-(nrbyyIiPYuYX`uTT$yON$ z+`23|jp|G*RHo$WOV9mYN^VVw)e2cM3|kG<%=lqhZ>?lFK>_Y>FOB}T2W;#MY04tv zig~rPCN_cWLMio3B?W#>GTnA3o$!^iL}PCfoI}!1=@D>dll1F zUHXe6-*ra1x7h&Z*iov8siSuKCRGm2pa6GDHD+DG_!TR?kPl`UfRWrU1>9N)MmV;88O{MoBd}g z@aF+-`4v)5v90!5N-))UnD*m63PfS4{S?-pNWLSUwT@Aa=>PFM5=9y;KEN%~{$vq|X;`jd0(fD^I$bIr*f zaMs_7G|)cqR$twZ`aL6A|2dgvhF>jBq8Tom&T!0-c0-$AbWsDFiW!k9o?b5=$+oxGOiD}=wb @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 @@ -203,52 +203,52 @@ Please type the desired email address (including @mailchuck.com) below: MainWindow - + Reply to sender Dem Absender antworten - + Reply to channel Antworten in den Chan - + 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 @@ -273,12 +273,12 @@ Please type the desired email address (including @mailchuck.com) below: Adresse in die Zwischenablage kopieren - + Special address behavior... Spezielles Verhalten der Adresse... - + Email gateway E-Mail Schnittstelle @@ -288,37 +288,37 @@ Please type the desired email address (including @mailchuck.com) below: 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 - + 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. @@ -328,17 +328,17 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 @@ -348,77 +348,77 @@ Please type the desired email address (including @mailchuck.com) below: - + 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. @@ -427,17 +427,17 @@ It is important that you back up this file. 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.) @@ -447,37 +447,37 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di (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. @@ -547,22 +547,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -570,17 +570,17 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -625,57 +625,57 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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 @@ -700,47 +700,47 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -775,22 +775,22 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di 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. @@ -800,42 +800,42 @@ Es ist empfehlenswert, vorher ein Backup dieser Datei anzulegen. Möchten Sie di - + 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? @@ -844,7 +844,7 @@ Are you sure you want to delete the subscription? 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? @@ -853,32 +853,32 @@ Are you sure you want to delete the channel? 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... @@ -943,192 +943,192 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? - + 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 @@ -1148,67 +1148,67 @@ Sind Sie sicher, dass Sie das Chan löschen möchten? Neuen Eintrag erstellen - + Display the %1 recent broadcast(s) from this address. - Die letzten %1 Rundruf(e) von dieser Addresse anzeigen. + - + 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. - + 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 - + Shutting down PyBitmessage... %1% PyBitmessage wird beendet... %1% - + Sent Gesendet @@ -1311,7 +1311,7 @@ Receiver's required difficulty: %1 and %2 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. @@ -1321,7 +1321,7 @@ Receiver's required difficulty: %1 and %2 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... @@ -1346,37 +1346,37 @@ Receiver's required difficulty: %1 and %2 UPnP Port-Mapping entfernt - + Mark all messages as read Alle Nachrichten als gelesen markieren - + Are you sure you would like to mark all messages read? Sind Sie sicher, dass Sie alle Nachrichten als gelesen markieren möchten? - + Doing work necessary to send broadcast. Führe Arbeit aus, die notwendig ist zum Senden des Rundspruches. - + 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 - + Wait until these tasks finish? Warten bis diese Aufgaben erledigt sind? @@ -1441,12 +1441,12 @@ Receiver's required difficulty: %1 and %2 Ihre Grafikkarte hat inkorrekt berechnet, OpenCL wird deaktiviert. Bitte benachrichtigen Sie die Entwickler. - + Set notification sound... Benachrichtigungsklang einstellen ... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1460,120 +1460,155 @@ Willkommen zu einfachem und sicherem Bitmessage * diskutieren Sie mit anderen Leuten in Chans - + not recommended for chans für Chans nicht empfohlen - + Quiet Mode stiller Modus - + Problems connecting? Try enabling UPnP in the Network Settings Verbindungsprobleme? Versuchen Sie UPnP in den Netzwerkeinstellungen einzuschalten - + 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 @@ -1764,7 +1799,7 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. @@ -1972,27 +2007,27 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi - + 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 @@ -2007,32 +2042,32 @@ Die Zufallszahlen-Option ist standardmässig gewählt, jedoch haben deterministi 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. -- 2.45.1 From 4ba5702cc22fa8b52e3b7dba3f9df44b1f28b197 Mon Sep 17 00:00:00 2001 From: PyBitmessage Translations Date: Mon, 12 Feb 2018 22:31:54 +0100 Subject: [PATCH 1094/1102] Auto-updated language ru from transifex --- src/translations/bitmessage_ru.qm | Bin 91386 -> 92911 bytes src/translations/bitmessage_ru.ts | 446 ++++++++++++++++-------------- 2 files changed, 243 insertions(+), 203 deletions(-) diff --git a/src/translations/bitmessage_ru.qm b/src/translations/bitmessage_ru.qm index c831d389433262f7920f31b7e6fd20c4e0ba7586..53d58f012d8e96cf2653679d120850ea71268188 100644 GIT binary patch delta 4794 zcmZWr30zcV_kP})duLx1#5M7%p^$)xB8vhdDuRevZltL!LyX9b4j`fCXfBx>C>l!U z7Ww6ZrDU2GmD%TxnrWd~=2})-pJ-}o-!p^N_xt~U{Frm^eb0N&^PcmZ^Pc;M z29(x8-dY7QxD4{{S0SE_f@YJNj&?#jqCdp*{?K~#jwV3g{{uQd0n3IuATa_>``-dC z_e9g}%OHHaqZQ(Sn_*~OvIO{7J^bG+1$K5u$5W4hu_Mq)7Y8>s$D>PY8d%p8UEYiU z?!SxR!)+n@InnLk{6768!k4ZAc5FrDnc2V(rRde-1~6_3`d7^XoKGO>wf#WHqm8n` ziR2%i1)^R@N|%>`=nxEk&A^D1V91225V4c+%!?l~>dQRR4O}0M5ep_jBo$z!oeD{p zFlr}}_lUuB1u=|31;%I=P`-e1+HF988IzKkwj)KD;$H=5s!_a_026*h$%atinG2Y< zk#@TTVp=WJwWJ=?9hDG$Qt`_04UE+HSoxwq@MmkRx4V6S`MIdt&D{3Bj;)Is+PlM0 z9ZQ8jp1{s88G*P_IB8u3+^$Ex>l83I2j|-maEFDsl(+}bzk)lTGa~CZ2>rSSAa^H@qszl() zJ1Y4@0;rT#ru=KbiF#F+_-~o(i>i=M81mvds*npF*+&&t%pAWrTh;CE%MkK6s$Lgn z0h89Nl4ep)cB*pw+=du9Ni{KKC;il`^5;8%o_Q+wOHLp(z^z(vrYS_bIjTh-g=NE4 ziznRxJ_u5+9e)|p* zkV|E1X?g^NwYA!`NQM{|s5YP60R#%1>QxWM0xOQG*NmM@!0pw0O#2}QTu>jb;Jb5;x=w3j{f8JD zAMTc`kIzp7(%x2Is!S#)OzP_+dGhi{>KiZ40BYN*@9rj>-G?M=+a(a@Ba(F-t0J+L z)O>R~aK|9U?qWkqSRo~*F~{HkAq_l6GG;VLnZC<;z{`^Doly3X%Tk_^k!;v36;6`j z7Mi6}@k8eP+$w3-?bE>aX43qg%^XSmLq>jxrQN+Pn2hd*FkjKFVCK7gGl~Hp8swVxzR&j97BgIugNQ;gMcrd zmMd=+Ky=pOJP@Z`fvG&M_nfvZb3 zUvBnc8To0>k6;c5xHUI4G`wM~)~AdSoSLDHH1On>Fl|gmXJFnS?cn-4_K_ai5oIs2 zWvjKeZgzIS6Ixs5a31JO?d-MjK%ZB&?s=)L*m#a>mqdIEq<*O_YtCxWBx=j95Wv7X z?TS-t*iu8Zm3iBE^NrK4T~FkFS7Wce^k~6-#1#j}|K6gjA)N@sz?4~RK!~z^l)O|QA zfd{#z`*3d@Bl3~%@Z0;@KWcSH-2Om7s_yJO2dm4Ss5`rgA4ZMWT|PgS2RWeo<^CGr z#|GV>)ZT`IZf`a?{wrhcDN{g_{tKt-iP|gF~5mBEg?4s73=d?6KL{weL)%lWZu)yy7vge^tFCbGX1(E!}aA&B;I1sFaM=G zFkp(l(i57BoBGx7$8g{{r+;JiA>h~u{r2@FU(P)JvGCRqZLjH%J!D9qxT-&XiRJj( zLH!qBr2+41^=FoHaOsn%|6$kzk~+^|a7RNl>uE4fCi{i2!FTWsmaEy|Ypdh^ukK{% zATE=|TMeCNGZpvEh7qrBWvE&ivMU+NC-V)qpHoS?1Ve5%9S%NZm~eprFa7A1qSJ1} zj4`~7VxkR|*XZ!*bi=l|`)tjd3^gMk5zunO2gU{-sLb$59S_v>bHisdS*|O$7*5QK zCwuKD4d0Ks0vtYI_@#o#V%{-|!P`ihL^z+1*J%?#ksUSssr0UWi~8RJIr`|wg@yl*Su_pZjYlm!It=anMh zoH1>Wn+V@(VI2DBCW!vmjak!38lUOLg;Qr!wlJ1`e3r;-jg_Yo*)S}|)%qT6JXyw# z#_xdlcN(`mFdm#~2lo8Oc<>^Duia$)YE>FU&=F&O$qk6qEylA0R}f&e@n;{F z=e>80KP&7f(Y;Jz?h#{w zB*|oZZ4Gd$rzx+xFAZEXO-g=)z`L3X&-DV@FE^E>vsG{HXBrgPIyaa22GYIudITX@y1 zySkINVH0zkiR9S1uI4ARKI2q<#oTEX?K@mB}nIgbPhg8|nZ?>@bgedle(F(42RNfc76WJKp2>15M3N_eh>F z$UHT%ly|~M=IPVpSibknEB?c~B0Jf<=Ic7(_!;w=!=b<(oE(!)qM9W0#OB< z@8$O440y_dPnf$7_bs}X%%x?crP;&)4k#xr9s8z{WG2f~el(Q7z!IGHI!PF38F+`+ zaZr(E>QOoxRAZSZwgC%bETuQ8cO%BK>b*@YzfwzOCCm6&gJs?5DAxaUyJfw?&}c_l zj;@Xd9$vK6btPMYMj24uD1RK)C~r5j)TeRey3*V$MPNV6&7n_nKq<03^0z>=PqcOo zXw8UKSi>Df5b^h{5eNM_c2`+@wc#A#|HwM%eMYRXk9A0uXa4`}xb?YrYatM49bY+z z*X*y>><0{eS-RCxN~`R#bJi;VdPd-;b@Q=D5MAb5 zwyWw|f@)OvsM96hhYH+VHY zKe~L@?Ub73=4(;ynn?aqk`yH+NPYR+S4!1+!lB{6oH)^zQ9gNvU(K`uf!dlOX@UCA zE~%Z=M~b6nB!34=y`(TG-lr(3n-s&h7{13=gmn>q#z-kl>Q41UDYC+xF4_!Iqy(<^ z@Oty;hW_oVTYs0!=~A3oSw$|FEjvcZau!X@RvgYkWuh}9TgkT-6lA<$Q*vC+d?njn zkXJs-=~q)cQW62pcz}U4`L}xnpxfVu^ef=QL5FB5c>RR-)Q3Sky{>OiV9sS0o>45Pv-`W9cx0&k2MP$%BM>G|KC4^yq|)? zZ7y4=^4N1xfi2tfS#f1JvdKP2QGTY)r8MqX)?kVxJeQJ@o$Vq=Z3P}x2Y>7ZN{-W& zuN2!SPE;~&iZh37R%pzFk6S`3)`g3XyMnrkn`)KtFJF4n&+TDVZ*O3{mB_FR=9fgu z?%pKFF`qG>cLXwQjkIVC>R&rO`Sv6rh`z zr+T>>CY3K4Zz%s`u)#e!of*$BVp6kmZCQCrAX|f{6?or*8iUJHRVH{;yy^8&B-@_t z)ueQEE(}tNJ&EuvkSjLN!~e;Wl4Eyycw^7Eg=$%xt^T4xMRmCF+tsqWxY+H#nN2dX delta 3587 zcmZ8kd0dTY8@`_NzVBJz^PZ_RhNfgGTZL#^C`+Y?<1?w0ET!WssgOaIUi%U$LQ0b@ zdxb*DHe+A2WGjP42)`y{vc!b%rvJV_`rYR}&v~Ecey;nvuKVuQZQO$)~foLDF;OpS8+X0dO;44Q1 zgxFJHn&A*u^1zb)5H@@SvT7jY_yF>XM*1)UNb`q~p9khw0ikp` z*wEQf?&j!#MyP^)!9pUS@jXI`42HC|9PloHnQsG7V+peZYrxD~pcTA;dIMS~tpaui z!e(0^<(q`~2mHJDcsdYq$$IRS89oeLD% z!}ZQWpf(=8Th;?()$q+*1jMh0-}*B^`zy_{!H7Z60|B><7`k3d2sB{W#93gj#rS#V zF+z7ub9~`};FO7A{SPA~hSmqzW8@((8R+GKutX2KaTUUqDHQi$tf~<3or~! z$SbANxjG_0m5_el69t~M{^4I7x+T+%y*l8AVI}aU6qQpefJN1KU`3g>orD_iGC;Ew z@6HkeTYhAk&2IqDRm^;o1g5>o+O+0@sXS}j?Fd*;C)P=95BxcWIgfh@{2Roa6Y0Gj z0_&Ab3Hq*K9%h9=$_Lgz+!ffI&5ZIL+MrJ~8y8BM*KK8ykboIJEV}6>nED}$>vRH8 zTe5g}LLg0M%SSr_XOr2w15|=`f3l4Q1m)0<>}VbbtUSSv_awq99yUk+VeGQ#0;Jz! zjoazqC~Njb;SF?nrx1=&0$H*`7UODxYo&^=eIEh|;R?s!2=eKl6^_+kW0|7+j0HgP zCq<9O1z`M9MepkQz+@|h-@LE!g(AA&TdHNTVv^$_V0EA(Zdp9=Q>;Rsn*cc3DN^p3 zf!UZ8E5EH@Q>0F=2THdoHjR4%*sqWkJHqLOh;xdo<0!*rGZlB@IuOfi6nE#ICbC2* zs-y_8?*bIh_(b4E0>{sB0n`7>i7N##V=Sk?Q3P}z&KVX{>0bQ9SrpX}5{{g0ju){% zjBD?`+VOp;L*h=8!Np8>- z9>|a3qMHc%VKrQmQ#D}S#ARJ81}?qgvYN&K>-@OfF^ehTja->{h7xYiUCN~Agdeza zl?iavHpll;%;f54CIiQ_xW-aqv+T_qtXF}F`MhB) zslhXx|9(#>k@E%bSwe=>`yTIYq#9RO@%~qdj1lpCq{Ujg;aT3a&xw4ZBOj|HBpa6V z(DXht5Kw)KRNy3xNhT7d z&l93TsMbqc2oqd>r&?VV5^@Rhz6N2Qb2*rUN?1701m@F5ShnAfxM3-zdVD=7LfGKm z8Mx6+$ZkjkYrk9AxQq^7aZxB-E|5W;7Y+u|!KTYX*?;NxYwrpdugN5js4qhK3etO@ zjlxU6VPq_qgm)Z46z?Xy_c0^6D3xXtX+u9*Ipk#+k!G?oa67TStx6d;A)b0cg)-qb z^#zA4~~68ucQOE+*6sS6H-a{Rjyh>KyRk3p{(QGWCcdj##KnkwJ7*qiW%%zCeGbS~8>+*g$jDDwl`A5Th#nds2na zP9>*5rA!75RIRJX1%~fbWycl*VU?;)Tj&PfdezpXMMSW{^;!#4Il$R#+p#Ca)O@Y|Lc&>YtkVWB&nFFKXrrzI#HaVO+POmxI>{>eT@+fVg*GICmI&E>tXL1cm zdqnq!E~M4|R!$fCZin{tJksO_JMHx)#ITqE?VsUK$rk%-|H@28SJvwv9UEFmjF5Di zBom4Eu1?F{0OqgPX`f63vmT+-&-Wz+oHLGVTFNdu_y5?@lqBoCMxFqIG`hYPt$=ru z&Nw)QI_jHmk+r?AGnP?0d8>89zwD;#IO@jFrt+JO)~%SekkV?@rJt;#G~IOB72ae4 zk}gNni)iscw?p>`INVLQ_Y)0E$_m|uc`-oQB;AF_l%>3>y{PlVeI@oTlUSNSe0AJqFZ;1{MJ;}j1BJLt#m$|3~I^|9|Lp)&*Y@dxSqb1U=-atJVGn|_wJ zoJI^;uAeiLCwL=+DC57GT- zoGX&lKN!grmr5-r*^$%(r1k@hz=b7J7fX6Sj+Y#a8_7z%B>#8RQ0;z^W?iBE101C# ztPog!P)d_u(GUM>C1oAlP2x(Eva?B~S1P20$??&VV znxkDobA0aF92**>N+S(THE+K~*1<=5HM|3j7^Tu@8wt#|gQ1&UYeFj1;2i%8&8>Y5 zvdaY<8c=Huy{)K~TR$=c944p|%M8Qv2-?$w3}O3E0AH*PRShQ&S1a&FI#1aPbv=ty^*J zz)mW=k$fB8i}&EW^RDzafFA-|*wOz|wtQc{AFcTFz4?HQKT3LLCb%)Jql-^W;^avY zNw(9XO}2JDY^R#Wo8qV0MovwLh#DV}IIUA+XWI!=6XIw+CNX1Pk#(`b*hy3TA%the z?xCmTj8T=7iWOB&UK|~o$y%}d%sul#D|U?a$=uh9S!d2_&7{oWADNjz!o>f5*}BBW UibYtKjO)q%=1TPL>~W9(0fyBrLI3~& diff --git a/src/translations/bitmessage_ru.ts b/src/translations/bitmessage_ru.ts index 38e1112f..ffb2eac9 100644 --- a/src/translations/bitmessage_ru.ts +++ b/src/translations/bitmessage_ru.ts @@ -60,27 +60,27 @@ @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-шлюзе @@ -197,52 +197,52 @@ Please type the desired email address (including @mailchuck.com) below: 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 Новый адрес @@ -267,12 +267,12 @@ Please type the desired email address (including @mailchuck.com) below: Скопировать адрес в буфер обмена - + Special address behavior... Особое поведение адресов... - + Email gateway Email-шлюз @@ -282,37 +282,37 @@ Please type the desired email address (including @mailchuck.com) below: Удалить - + 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. Ожидаем ключ шифрования от Вашего собеседника. Запрос будет повторен через некоторое время. @@ -322,17 +322,17 @@ Please type the desired email address (including @mailchuck.com) below: - + Queued. В очереди. - + Message sent. Waiting for acknowledgement. Sent at %1 Сообщение отправлено. Ожидаем подтверждения. Отправлено в %1 - + Message sent. Sent at %1 Сообщение отправлено в %1 @@ -342,78 +342,78 @@ Please type the desired email address (including @mailchuck.com) below: - + 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 Подписки - + 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. @@ -422,19 +422,19 @@ 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.) @@ -444,37 +444,37 @@ It is important that you back up this file. Would you like to open the file now? (пожалуйста, закройте 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. @@ -544,22 +544,22 @@ It is important that you back up this file. Would you like to open the file now? - + 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 @@ -570,17 +570,17 @@ It is important that you back up this file. Would you like to open the file now? сообщение. Часто разумным вариантом будет установка 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, пожалуйста, подождите пока процесс регистрации не завершится, прежде чем попытаться отправить сообщение заново. @@ -625,57 +625,57 @@ It is important that you back up this file. Would you like to open the file now? - + 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 Новое сообщение @@ -700,47 +700,47 @@ It is important that you back up this file. Would you like to open the file now? Вы ввели неправильный адрес. Это адрес проигнорирован. - + 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 ждет перед первой попыткой переотправки сообщения, поэтому ваши сообщения никогда не будут переотправлены. @@ -775,22 +775,22 @@ It is important that you back up this file. Would you like to open the file now? Вы действительно должны ввести секретную фразу. - + 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. Ошибка: адрес, с которого Вы пытаетесь отправить, выключен. Вам нужно будет включить этот адрес во вкладке "Ваши адреса". @@ -800,42 +800,42 @@ It is important that you back up this file. Would you like to open the file now? - + 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? @@ -844,7 +844,7 @@ 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? @@ -853,32 +853,32 @@ 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... Проверяем... @@ -943,192 +943,192 @@ Are you sure you want to delete the channel? - + 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 Все аккаунты @@ -1148,67 +1148,67 @@ Are you sure you want to delete the channel? Добавить новую запись - + 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 часа%n часов%n час(а/ов) - + %n day(s) %n день%n дня%n дней%n дней - + Shutting down PyBitmessage... %1% Завершение PyBitmessage... %1% - + Sent Отправлено @@ -1312,7 +1312,7 @@ Receiver's required difficulty: %1 and %2 Проблема: вы пытаетесь отправить сообщение самому себе или в чан, но ваш ключ шифрования не найден в файле ключей keys.dat. Невозможно зашифровать сообщение. %1 - + Doing work necessary to send message. Выполнение работы, требуемой для отправки сообщения. @@ -1322,7 +1322,7 @@ Receiver's required difficulty: %1 and %2 Отправлено. Ожидаем подтверждения. Отправлено в %1 - + Doing work necessary to request encryption key. Выполнение работы, требуемой для запроса ключа шифрования. @@ -1347,37 +1347,37 @@ Receiver's required difficulty: %1 and %2 Распределение портов 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 объекта в ожидании доказательства работы%n объектов в ожидании доказательства работы%n объектов в ожидании доказательства работы - + %n object(s) waiting to be distributed %n объект ожидает раздачи%n объекта ожидают раздачи%n объектов ожидают раздачи%n объектов ожидают раздачи - + Wait until these tasks finish? Подождать завершения этих задач? @@ -1442,12 +1442,12 @@ Receiver's required difficulty: %1 and %2 Ваша видеокарта вычислила неправильно, отключаем OpenCL. Пожалуйста, сообщите разработчикам. - + Set notification sound... Установить звук уведомления... - + Welcome to easy and secure Bitmessage * send messages to other people @@ -1461,115 +1461,155 @@ Receiver's required difficulty: %1 and %2 * участвуйте в обсуждениях в чанах - + 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? Вы пытаетесь отправить email вместо 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 + Ошибка: %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. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?Bitmessage не синхронизирован с сетью, незагруженных объектов: %n. Выход сейчас может привести к задержкам доставки. Подождать завершения синхронизации?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? У вас уже есть звук уведомления для этого адресата. Вы уверены, что хотите перезаписать звук уведомления? - + + Error occurred: could not load message from disk. + Произошла ошибка: не удалось загрузить сообщение с диска. + + + + Display the %n recent broadcast(s) from this address. + + + + Go online Подключиться к сети - + Go offline Отключиться от сети + + + Clear + Очистить + + + + inbox + входящие + + + + new + новые + + + + sent + отправленные + + + + trash + + MessageView @@ -1759,7 +1799,7 @@ The 'Random Number' option is selected by default but deterministic ad Имя псевдо-рассылки: - + This is a chan address. You cannot use it as a pseudo-mailing list. Это адрес чана. Вы не можете его использовать как адрес рассылки. @@ -1782,12 +1822,12 @@ The 'Random Number' option is selected by default but deterministic ad - + <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. Это бета версия программы. @@ -1797,7 +1837,7 @@ The 'Random Number' option is selected by default but deterministic ad - + <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> @@ -1967,27 +2007,27 @@ The 'Random Number' option is selected by default but deterministic ad - + 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 @@ -2002,34 +2042,34 @@ The 'Random Number' option is selected by default but deterministic ad Загрузка: 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 сообщений. + Обработано %n сообщение.Обработано %n сообщения.Обработано %n сообщений.Обработано %n сообщений. - + Processed %n broadcast message(s). - Обработана %n рассылка.Обработано %n рассылок.Обработано %n рассылок.Обработано %n рассылок. + Обработана %n рассылка.Обработано %n рассылки.Обработано %n рассылок.Обработано %n рассылок. - + Processed %n public key(s). - Обработан %n открытый ключ.Обработано %n открытых ключей.Обработано %n открытых ключей.Обработано %n открытых ключей. + Обработан %n открытый ключ.Обработано %n открытых ключа.Обработано %n открытых ключей.Обработано %n открытых ключей. @@ -2239,12 +2279,12 @@ The 'Random Number' option is selected by default but deterministic ad 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. - + Если Вы ранее создали детерминистические адреса, но случайно потеряли их, Вы можете их восстановить здесь. Если же Вы использовали генератор случайных чисел чтобы создать Ваши адреса, то Вы не сможете их здесь восстановить. -- 2.45.1 From 8b932ade2d26d0ee3b5d4b69b4ea096bc588b4fa Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 13 Feb 2018 00:50:47 +0200 Subject: [PATCH 1095/1102] No "getinfo" in modern namecoind - try "getnetworkinfo" --- src/namecoin.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/namecoin.py b/src/namecoin.py index 2cfa5a1d..1124bbeb 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -129,12 +129,14 @@ class namecoinConnection (object): # 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": - res = self.callRPC ("getinfo", []) - vers = res["version"] - + try: + vers = self.callRPC("getinfo", [])["version"] + except RPCError: + vers = self.callRPC("getnetworkinfo", [])["version"] + v3 = vers % 100 vers = vers / 100 v2 = vers % 100 -- 2.45.1 From 3ad94cb4aa0366019295d6a32cc498fc0a18dbe9 Mon Sep 17 00:00:00 2001 From: Dmitri Bogomolov <4glitch@gmail.com> Date: Tue, 13 Feb 2018 11:53:43 +0200 Subject: [PATCH 1096/1102] Translate namecoin failure message --- src/namecoin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/namecoin.py b/src/namecoin.py index 1124bbeb..9b3c3c3e 100644 --- a/src/namecoin.py +++ b/src/namecoin.py @@ -162,7 +162,11 @@ class namecoinConnection (object): except Exception: logger.info("Namecoin connection test failure") - return ('failed', "The connection to namecoin failed.") + return ( + 'failed', + tr._translate( + "MainWindow", "The connection to namecoin failed.") + ) # Helper routine that actually performs an JSON RPC call. def callRPC (self, method, params): -- 2.45.1 From f9a648d720848a8027ba2cb684da35681417973f Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 13 Feb 2018 13:24:37 +0100 Subject: [PATCH 1097/1102] Message decoding exception handler fix - was unfinished and caused the object processor thread to crash --- src/class_objectProcessor.py | 10 ++++++++-- src/helper_msgcoding.py | 26 +++++++++++++++++--------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/class_objectProcessor.py b/src/class_objectProcessor.py index 6387f6a7..181ce30e 100644 --- a/src/class_objectProcessor.py +++ b/src/class_objectProcessor.py @@ -509,7 +509,10 @@ class objectProcessor(threading.Thread): if toLabel == '': toLabel = toAddress - decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + try: + decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + except helper_msgcoding.MsgDecodeException: + return subject = decodedMessage.subject body = decodedMessage.body @@ -761,7 +764,10 @@ class objectProcessor(threading.Thread): sendersAddressVersion, sendersStream, calculatedRipe) logger.debug('fromAddress: ' + fromAddress) - decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + try: + decodedMessage = helper_msgcoding.MsgDecode(messageEncodingType, message) + except helper_msgcoding.MsgDecodeException: + return subject = decodedMessage.subject body = decodedMessage.body diff --git a/src/helper_msgcoding.py b/src/helper_msgcoding.py index aae35d27..f8bc95a6 100644 --- a/src/helper_msgcoding.py +++ b/src/helper_msgcoding.py @@ -21,7 +21,15 @@ BITMESSAGE_ENCODING_SIMPLE = 2 BITMESSAGE_ENCODING_EXTENDED = 3 -class DecompressionSizeException(Exception): +class MsgEncodeException(Exception): + pass + + +class MsgDecodeException(Exception): + pass + + +class DecompressionSizeException(MsgDecodeException): def __init__(self, size): self.size = size @@ -38,7 +46,7 @@ class MsgEncode(object): elif self.encoding == BITMESSAGE_ENCODING_TRIVIAL: self.encodeTrivial(message) else: - raise ValueError("Unknown encoding %i" % (encoding)) + raise MsgEncodeException("Unknown encoding %i" % (encoding)) def encodeExtended(self, message): try: @@ -46,10 +54,10 @@ class MsgEncode(object): self.data = zlib.compress(msgpack.dumps(msgObj.encode(message)), 9) except zlib.error: logger.error("Error compressing message") - raise + raise MsgEncodeException("Error compressing message") except msgpack.exceptions.PackException: logger.error("Error msgpacking message") - raise + raise MsgEncodeException("Error msgpacking message") self.length = len(self.data) def encodeSimple(self, message): @@ -85,7 +93,7 @@ class MsgDecode(object): data = dc.unconsumed_tail except zlib.error: logger.error("Error decompressing message") - raise + raise MsgDecodeException("Error decompressing message") else: raise DecompressionSizeException(len(tmp)) @@ -94,21 +102,21 @@ class MsgDecode(object): except (msgpack.exceptions.UnpackException, msgpack.exceptions.ExtraData): logger.error("Error msgunpacking message") - raise + raise MsgDecodeException("Error msgunpacking message") try: msgType = tmp[""] except KeyError: logger.error("Message type missing") - raise + raise MsgDecodeException("Message type missing") msgObj = messagetypes.constructObject(tmp) if msgObj is None: - raise ValueError("Malformed message") + raise MsgDecodeException("Malformed message") try: msgObj.process() except: - raise ValueError("Malformed message") + raise MsgDecodeException("Malformed message") if msgType == "message": self.subject = msgObj.subject self.body = msgObj.body -- 2.45.1 From 96ea36cfd245f7dc10209b01278b5fa2970f360c Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 13 Feb 2018 16:11:53 +0100 Subject: [PATCH 1098/1102] UPnP client port randomize --- src/upnp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/upnp.py b/src/upnp.py index ff657619..ad72560c 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -187,7 +187,7 @@ class uPnPThread(threading.Thread, StoppableThread): self.localIP = self.getLocalIP() self.routers = [] self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.sock.bind((self.localIP, 10000)) + self.sock.bind((self.localIP, 0)) self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 2) self.sock.settimeout(5) self.sendSleep = 60 -- 2.45.1 From 3a8016d31f517775d226aa8b902480f4a3a148a9 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 13 Feb 2018 16:39:35 +0100 Subject: [PATCH 1099/1102] Fix message encoding bug - prevent loading invalid message types --- src/messagetypes/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index c3911dfd..d9291013 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -12,9 +12,10 @@ class MsgBase(object): def constructObject(data): try: - classBase = eval(data[""] + "." + data[""].title()) - except NameError: - logger.error("Don't know how to handle message type: \"%s\"", data[""]) + 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() -- 2.45.1 From 4cd36ececc5ec467526a9d084ea8818125dbedd1 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Tue, 13 Feb 2018 17:16:20 +0100 Subject: [PATCH 1100/1102] Bump version --- src/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.py b/src/version.py index 694f71e4..a3837aa5 100644 --- a/src/version.py +++ b/src/version.py @@ -1,2 +1,2 @@ softwareName = 'PyBitmessage' -softwareVersion = '0.6.2' +softwareVersion = '0.6.3' -- 2.45.1 From c050ef0814b920cb92f66a632046d084b31292e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=A0urda?= Date: Tue, 13 Feb 2018 23:33:12 +0100 Subject: [PATCH 1101/1102] Messagetype attack mitigation - temporarily restrict messagetypes - use a new "Contact support" address --- src/bitmessageqt/support.py | 4 +++- src/messagetypes/__init__.py | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bitmessageqt/support.py b/src/bitmessageqt/support.py index cea5ddc8..25c6113d 100644 --- a/src/bitmessageqt/support.py +++ b/src/bitmessageqt/support.py @@ -21,7 +21,8 @@ import state from version import softwareVersion # this is BM support address going to Peter Surda -SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' +OLD_SUPPORT_ADDRESS = 'BM-2cTkCtMYkrSPwFTpgcBrMrf5d8oZwvMZWK' +SUPPORT_ADDRESS = 'BM-2cUdgkDDAahwPAU6oD2A7DnjqZz3hgY832' SUPPORT_LABEL = 'PyBitmessage support' SUPPORT_MY_LABEL = 'My new address' SUPPORT_SUBJECT = 'Support request' @@ -53,6 +54,7 @@ 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) diff --git a/src/messagetypes/__init__.py b/src/messagetypes/__init__.py index d9291013..1a5223df 100644 --- a/src/messagetypes/__init__.py +++ b/src/messagetypes/__init__.py @@ -11,6 +11,9 @@ class MsgBase(object): def constructObject(data): + whitelist = ["message"] + if data[""] not in whitelist: + return None try: m = import_module("messagetypes." + data[""]) classBase = getattr(m, data[""].title()) -- 2.45.1 From 634a49cd6d8fc2f52504586be4c4766340641b25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20=C5=A0urda?= Date: Wed, 14 Feb 2018 00:23:47 +0100 Subject: [PATCH 1102/1102] Bump version --- src/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.py b/src/version.py index a3837aa5..076b8c56 100644 --- a/src/version.py +++ b/src/version.py @@ -1,2 +1,2 @@ softwareName = 'PyBitmessage' -softwareVersion = '0.6.3' +softwareVersion = '0.6.3.2' -- 2.45.1