From 1796c20887c99c5dd69af87afc730445b1724cf5 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Mon, 19 Jan 2015 18:39:02 +0100 Subject: [PATCH 001/399] 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 002/399] 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 003/399] 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 004/399] 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 005/399] 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 006/399] 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 007/399] 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 008/399] 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 009/399] 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 010/399] 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 011/399] 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 012/399] 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 013/399] 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 014/399] 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 015/399] 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 016/399] 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 017/399] 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 018/399] 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:

" + "" + "" + "
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 019/399] 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 020/399] 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 021/399] 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 022/399] 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 023/399] 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 024/399] 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 025/399] 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 026/399] 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 027/399] 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 028/399] 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 029/399] 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 030/399] 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 031/399] 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 032/399] 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 033/399] 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 034/399] 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 035/399] 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 036/399] 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 037/399] 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 038/399] 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 039/399] 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 040/399] 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 041/399] 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 042/399] 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 043/399] 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 044/399] 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 045/399] 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 046/399] 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 047/399] 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 048/399] 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 049/399] 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 050/399] 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 051/399] 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 052/399] 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 053/399] 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 054/399] 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 055/399] 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 056/399] 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 057/399] 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 058/399] 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 059/399] 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 060/399] 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 061/399] 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 062/399] 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 063/399] 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 064/399] 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 065/399] 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 066/399] 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 067/399] 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 068/399] 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 069/399] 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 070/399] 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 071/399] 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 072/399] 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 073/399] 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 074/399] 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 075/399] 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 076/399] 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 077/399] 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 078/399] 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 079/399] 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 080/399] 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 081/399] 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 082/399] 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 083/399] 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 084/399] 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 085/399] 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 086/399] 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 087/399] 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 088/399] 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 089/399] 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 090/399] 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 091/399] 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 092/399] 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 093/399] 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 094/399] 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 095/399] 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 096/399] 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 097/399] 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 098/399] 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 099/399] 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 100/399] 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 101/399] 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 102/399] 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 103/399] 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 104/399] 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 105/399] 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 106/399] 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 107/399] 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 108/399] 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 109/399] 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 110/399] 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 111/399] 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 112/399] 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 113/399] 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 114/399] 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 115/399] 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 116/399] 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 117/399] 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 118/399] 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 119/399] 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 120/399] 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 121/399] 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 122/399] 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 123/399] 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 124/399] 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 125/399] 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 126/399] 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 127/399] 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 128/399] 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 129/399] 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 130/399] 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 131/399] 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 132/399] 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 133/399] 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 134/399] 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 135/399] 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 136/399] 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 137/399] 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 138/399] 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 139/399] 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 140/399] 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 141/399] 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 142/399] 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 143/399] 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 144/399] 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 145/399] 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 146/399] 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 147/399] 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 148/399] 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 149/399] 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 150/399] 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 151/399] 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 152/399] 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 153/399] 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 154/399] 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 155/399] 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 156/399] 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 157/399] 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 158/399] 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 159/399] 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 160/399] 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 161/399] 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 162/399] 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 163/399] 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 164/399] 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 165/399] 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 166/399] 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 167/399] 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 168/399] 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 169/399] 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 170/399] 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 171/399] 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 172/399] 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 173/399] 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 174/399] 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 175/399] 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 176/399] 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 177/399] 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 178/399] 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 179/399] 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 180/399] 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 181/399] 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 182/399] 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 183/399] 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 184/399] 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 185/399] 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 186/399] 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 187/399] 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 188/399] 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 189/399] 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 190/399] 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 191/399] 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 192/399] 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 193/399] 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 194/399] 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 195/399] 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 196/399] 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 197/399] 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 198/399] 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 199/399] 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 200/399] 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 201/399] 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 202/399] 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 203/399] 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 204/399] 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 205/399] 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 206/399] 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 207/399] 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 208/399] 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 209/399] 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 210/399] 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 211/399] 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 212/399] 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 213/399] 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 214/399] 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 215/399] 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 216/399] 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 217/399] 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 218/399] 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 219/399] 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 220/399] 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 221/399] 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 222/399] 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 223/399] 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 224/399] 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 225/399] 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 226/399] 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 227/399] 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 228/399] 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 229/399] 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 230/399] 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 231/399] 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 232/399] 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 233/399] 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 234/399] 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 235/399] 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 236/399] 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 237/399] (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 238/399] 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 239/399] 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 240/399] 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 241/399] 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 242/399] 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 243/399] 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 244/399] 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 245/399] 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 246/399] 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 247/399] 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 248/399] 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 249/399] 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 250/399] 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 251/399] "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 252/399] 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 253/399] 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 254/399] 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 255/399] 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 256/399] 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 257/399] 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 258/399] 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 259/399] 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 260/399] 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 261/399] 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 262/399] 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 263/399] 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 264/399] 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 265/399] 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 266/399] 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 267/399] 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 268/399] 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 269/399] 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 270/399] 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 271/399] 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 272/399] 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 273/399] 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 274/399] 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 275/399] 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 276/399] 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 277/399] 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 278/399] 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 279/399] 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 280/399] 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 281/399] 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 282/399] 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 283/399] 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 284/399] 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 285/399] 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 286/399] 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 287/399] 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 288/399] 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 289/399] 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 290/399] 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 291/399] 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 292/399] 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 293/399] 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 294/399] 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 295/399] 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 296/399] 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 297/399] 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 298/399] 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 299/399] 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 300/399] 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 301/399] 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 302/399] 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 303/399] 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 304/399] 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 305/399] 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 306/399] 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 307/399] 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 308/399] 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 309/399] 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 310/399] 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 311/399] 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 312/399] 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 313/399] 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 314/399] 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 315/399] 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 316/399] 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 317/399] 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 318/399] 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 319/399] 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 320/399] 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 321/399] 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 322/399] 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 323/399] 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 324/399] 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 325/399] 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 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 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 326/399] 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 327/399] 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 328/399] 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 329/399] 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 330/399] 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 331/399] 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 332/399] 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 333/399] 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 334/399] 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 335/399] 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 336/399] 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 337/399] 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 338/399] 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 339/399] 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 340/399] 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 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 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 341/399] 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 342/399] 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 343/399] 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 344/399] 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 345/399] "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 346/399] 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 347/399] 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 348/399] 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 349/399] 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 350/399] 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 351/399] 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 352/399] 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 353/399] 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 354/399] 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 355/399] 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 356/399] 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 357/399] 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 358/399] 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 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