- Implemented sync over TLS.
- Obsoleted the Socket code, replacing it with TLSClient, TLSServer.
- Added task server details to the 'diagnostics' command output.
- 'rc.debug.tls' controls the GnuTLS log level.
- Removed redundant cmake diagnostics.
This commit is contained in:
Paul Beckingham 2013-05-12 01:05:58 -04:00
parent f15c9a1b7e
commit 1e9fb8eebc
13 changed files with 173 additions and 195 deletions

View file

@ -56,7 +56,6 @@ set (PACKAGE_STRING "${PACKAGE} ${VERSION}")
message ("-- Looking for GnuTLS") message ("-- Looking for GnuTLS")
find_package (GnuTLS) find_package (GnuTLS)
if (GNUTLS_FOUND) if (GNUTLS_FOUND)
message ("-- Found GnuTLS: ${GNUTLS_LIBRARIES}")
set (HAVE_LIBGNUTLS true) set (HAVE_LIBGNUTLS true)
set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${GNUTLS_INCLUDE_DIR}) set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${GNUTLS_INCLUDE_DIR})
set (TASK_LIBRARIES ${TASK_LIBRARIES} ${GNUTLS_LIBRARIES}) set (TASK_LIBRARIES ${TASK_LIBRARIES} ${GNUTLS_LIBRARIES})
@ -79,7 +78,6 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
message ("-- Looking for GNU Readline") message ("-- Looking for GNU Readline")
find_package (Readline) find_package (Readline)
if (READLINE_FOUND) if (READLINE_FOUND)
message ("-- Found GNU Readline: ${READLINE_LIBRARIES}")
set (HAVE_READLINE true) set (HAVE_READLINE true)
set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${READLINE_INCLUDE_DIR}) set (TASK_INCLUDE_DIRS ${TASK_INCLUDE_DIRS} ${READLINE_INCLUDE_DIR})
set (TASK_LIBRARIES ${TASK_LIBRARIES} ${READLINE_LIBRARIES}) set (TASK_LIBRARIES ${TASK_LIBRARIES} ${READLINE_LIBRARIES})

View file

@ -22,6 +22,8 @@ Features
+ Merged three l10n utility scripts into one tools, scripts/utils/l10n, which + Merged three l10n utility scripts into one tools, scripts/utils/l10n, which
will help the translation effort. will help the translation effort.
+ The 'due' urgency component now uses seconds, not days, in the calculation. + The 'due' urgency component now uses seconds, not days, in the calculation.
+ The 'debug.tls' configuration variable takes an integer which corresponds to
the GnuTLS log level. For debugging.
Bugs Bugs
+ #1196 Now builds on Hurd (thanks to Jakub Wilk). + #1196 Now builds on Hurd (thanks to Jakub Wilk).

View file

@ -26,6 +26,7 @@ set (task_SRCS A3.cpp A3.h
Task.cpp Task.h Task.cpp Task.h
Taskmod.cpp Taskmod.h Taskmod.cpp Taskmod.h
Timer.cpp Timer.h Timer.cpp Timer.h
TLSClient.cpp TLSClient.h
Transport.cpp Transport.h Transport.cpp Transport.h
TransportCurl.cpp TransportCurl.h TransportCurl.cpp TransportCurl.h
TransportRSYNC.cpp TransportRSYNC.h TransportRSYNC.cpp TransportRSYNC.h
@ -41,7 +42,6 @@ set (task_SRCS A3.cpp A3.h
legacy.cpp legacy.cpp
recur.cpp recur.cpp
rules.cpp rules.cpp
Socket.cpp Socket.h
sort.cpp sort.cpp
text.cpp text.h text.cpp text.h
utf8.cpp utf8.h utf8.cpp utf8.h

View file

@ -290,6 +290,7 @@ std::string Config::_defaults =
"list.all.tags=no # Include old tag names in 'tags' command\n" "list.all.tags=no # Include old tag names in 'tags' command\n"
"print.empty.columns=no # Print columns which have no data for any task\n" "print.empty.columns=no # Print columns which have no data for any task\n"
"debug=no # Display diagnostics\n" "debug=no # Display diagnostics\n"
"debug.tls=0 # GnuTLS log level\n"
"extensions=off # Extension system master switch\n" "extensions=off # Extension system master switch\n"
"fontunderline=yes # Uses underlines rather than -------\n" "fontunderline=yes # Uses underlines rather than -------\n"
"shell.prompt=task> # Prompt used by the shell command\n" "shell.prompt=task> # Prompt used by the shell command\n"

View file

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager. // taskwarrior - a command line task list manager.
// //
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez. // Copyright 2006 - 2013, Paul Beckingham, Federico Hernandez.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -25,45 +25,92 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#ifdef HAVE_LIBGNUTLS
#include <iostream> #include <iostream>
#include <stdarg.h> #include <TLSClient.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/types.h>
#include <netdb.h> #include <netdb.h>
#include <unistd.h>
#include <string.h> #define MAX_BUF 1024
#include <Socket.h>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Socket::Socket () : static void gnutls_log_function (int level, const char* message)
_socket (0), {
_limit (0), // Unlimited std::cout << "c: " << level << " " << message;
_debug (false) }
////////////////////////////////////////////////////////////////////////////////
TLSClient::TLSClient ()
: _ca ("")
, _socket (0)
, _debug (false)
{ {
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Socket::Socket (int s) : TLSClient::~TLSClient ()
_socket (s),
_limit (0), // Unlimited
_debug (false)
{ {
gnutls_deinit (_session);
gnutls_certificate_free_credentials (_credentials);
gnutls_global_deinit ();
if (_socket)
{
shutdown (_socket, SHUT_RDWR);
close (_socket);
}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Socket::~Socket () void TLSClient::limit (int max)
{ {
close (); _limit = max;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// For clients. // Calling this method results in all subsequent socket traffic being sent to
void Socket::connect (const std::string& host, const std::string& port) // std::cout, labelled with >>> for outgoing, <<< for incoming.
void TLSClient::debug (int level)
{
_debug = true;
gnutls_global_set_log_function (gnutls_log_function);
gnutls_global_set_log_level (level);
}
////////////////////////////////////////////////////////////////////////////////
void TLSClient::init (const std::string& ca)
{
_ca = ca;
gnutls_global_init ();
gnutls_certificate_allocate_credentials (&_credentials);
gnutls_certificate_set_x509_trust_file (_credentials, _ca.c_str (), GNUTLS_X509_FMT_PEM);
gnutls_init (&_session, GNUTLS_CLIENT);
// Use default priorities.
const char *err;
int ret = gnutls_priority_set_direct (_session, "NORMAL", &err);
if (ret < 0)
{
if (ret == GNUTLS_E_INVALID_REQUEST)
std::cout << "c: ERROR Priority error at: " << err << "\n";
exit (1);
}
// Apply the x509 credentials to the current session.
gnutls_credentials_set (_session, GNUTLS_CRD_CERTIFICATE, _credentials);
}
////////////////////////////////////////////////////////////////////////////////
void TLSClient::connect (const std::string& host, const std::string& port)
{ {
// use IPv4 or IPv6, does not matter. // use IPv4 or IPv6, does not matter.
struct addrinfo hints; struct addrinfo hints;
@ -95,10 +142,7 @@ void Socket::connect (const std::string& host, const std::string& port)
throw "ERROR: " + std::string (::strerror (errno)); throw "ERROR: " + std::string (::strerror (errno));
if (::connect (_socket, p->ai_addr, p->ai_addrlen) == -1) if (::connect (_socket, p->ai_addr, p->ai_addrlen) == -1)
{
close ();
continue; continue;
}
break; break;
} }
@ -107,80 +151,31 @@ void Socket::connect (const std::string& host, const std::string& port)
if (p == NULL) if (p == NULL)
throw "ERROR: Could not connect to " + host + " " + port; throw "ERROR: Could not connect to " + host + " " + port;
}
//////////////////////////////////////////////////////////////////////////////// gnutls_transport_set_ptr (_session, (gnutls_transport_ptr_t) _socket);
void Socket::close ()
{
if (_socket)
::close (_socket);
_socket = 0;
}
//////////////////////////////////////////////////////////////////////////////// // Perform the TLS handshake
// For servers. int ret = gnutls_handshake (_session);
void Socket::bind (const std::string& port)
{
// use IPv4 or IPv6, does not matter.
struct addrinfo hints;
memset (&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
struct addrinfo* res; if (ret < 0)
if (::getaddrinfo (NULL, port.c_str (), &hints, &res) != 0)
throw "ERROR: " + std::string (::gai_strerror (errno));
if ((_socket = ::socket (res->ai_family,
res->ai_socktype,
res->ai_protocol)) == -1)
throw "ERROR: Can not bind to port " + port;
// When a socket is closed, it remains unavailable for a while (netstat -an).
// Setting SO_REUSEADDR allows this program to assume control of a closed, but
// unavailable socket.
int on = 1;
if (::setsockopt (_socket,
SOL_SOCKET,
SO_REUSEADDR,
(const void*) &on,
sizeof (on)) == -1)
throw "ERROR: " + std::string (::strerror (errno));
if (::bind (_socket, res->ai_addr, res->ai_addrlen) == -1)
throw "ERROR: " + std::string (::strerror (errno));
}
////////////////////////////////////////////////////////////////////////////////
void Socket::listen (int queue /*= 5*/)
{
if (::listen (_socket, queue) < 0)
throw "ERROR: " + std::string (::strerror (errno));
}
////////////////////////////////////////////////////////////////////////////////
int Socket::accept ()
{
struct sockaddr_storage client;
socklen_t length = sizeof client;
int connection;
do
{ {
memset (&client, 0, length); std::cout << "c: ERROR Handshake failed\n";
connection = ::accept (_socket, (struct sockaddr*) &client, &length); gnutls_perror (ret);
}
else
{
std::cout << "c: INFO Handshake was completed\n";
} }
while (errno == EINTR);
if (connection < 0)
throw "ERROR: " + std::string (::strerror (errno));
return connection;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Socket::write (const std::string& data) void TLSClient::bye ()
{
gnutls_bye (_session, GNUTLS_SHUT_RDWR);
}
////////////////////////////////////////////////////////////////////////////////
void TLSClient::send (const std::string& data)
{ {
std::string packet = "XXXX" + data; std::string packet = "XXXX" + data;
@ -199,9 +194,10 @@ void Socket::write (const std::string& data)
int status; int status;
do do
{ {
status = ::send (_socket, packet.c_str () + total, remaining, 0); status = gnutls_record_send (_session, packet.c_str () + total, remaining);
} }
while (errno == EINTR); while (errno == GNUTLS_E_INTERRUPTED ||
errno == GNUTLS_E_AGAIN);
if (status == -1) if (status == -1)
break; break;
@ -211,25 +207,28 @@ void Socket::write (const std::string& data)
} }
if (_debug) if (_debug)
std::cout << ">>> " std::cout << "c: INFO Sending 'XXXX"
<< data.c_str () << data.c_str ()
<< " (" << total << " bytes)" << "' (" << total << " bytes)"
<< std::endl; << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Socket::read (std::string& data) void TLSClient::recv (std::string& data)
{ {
data = ""; // No appending of data. data = ""; // No appending of data.
int received = 0; int received = 0;
// Get the encoded length. // Get the encoded length.
unsigned char header[4]; unsigned char header[4] = {0};
do do
{ {
received = ::recv (_socket, header, sizeof (header), 0); received = gnutls_record_recv (_session, header, 4);
} }
while (errno == EINTR); while (received > 0 &&
(errno == GNUTLS_E_INTERRUPTED ||
errno == GNUTLS_E_AGAIN));
int total = received; int total = received;
// Decode the length. // Decode the length.
@ -237,11 +236,12 @@ void Socket::read (std::string& data)
(header[1]<<16) | (header[1]<<16) |
(header[2]<<8) | (header[2]<<8) |
header[3]; header[3];
std::cout << "c: INFO expecting " << expected << " bytes.\n";
// TODO This would be a good place to assert 'expected < _limit'. // TODO This would be a good place to assert 'expected < _limit'.
// Arbitrary buffer size. // Arbitrary buffer size.
char buffer[8192]; char buffer[MAX_BUF];
// Keep reading until no more data. Concatenate chunks of data if a) the // Keep reading until no more data. Concatenate chunks of data if a) the
// read was interrupted by a signal, and b) if there is more data than // read was interrupted by a signal, and b) if there is more data than
@ -250,17 +250,22 @@ void Socket::read (std::string& data)
{ {
do do
{ {
received = ::recv (_socket, buffer, sizeof (buffer) - 1, 0); received = gnutls_record_recv (_session, buffer, MAX_BUF - 1);
} }
while (errno == EINTR); while (received > 0 &&
(errno == GNUTLS_E_INTERRUPTED ||
errno == GNUTLS_E_AGAIN));
// Other end closed the connection. // Other end closed the connection.
if (received == 0) if (received == 0)
{
std::cout << "c: INFO Peer has closed the TLS connection\n";
break; break;
}
// Something happened. // Something happened.
if (received < 0) if (received < 0)
throw "ERROR: " + std::string (::strerror (errno)); throw "ERROR: " + std::string (gnutls_strerror (received));
buffer [received] = '\0'; buffer [received] = '\0';
data += buffer; data += buffer;
@ -273,35 +278,11 @@ void Socket::read (std::string& data)
while (received > 0 && total < (int) expected); while (received > 0 && total < (int) expected);
if (_debug) if (_debug)
std::cout << "<<< " std::cout << "c: INFO Receiving 'XXXX"
<< data.c_str () << data.c_str ()
<< " (" << total << " bytes)" << "' (" << total << " bytes)"
<< std::endl; << std::endl;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Socket::limit (int max) #endif
{
_limit = max;
}
////////////////////////////////////////////////////////////////////////////////
// Calling this method results in all subsequent socket traffic being sent to
// std::cout, labelled with >>> for outgoing, <<< for incoming.
void Socket::debug ()
{
_debug = true;
}
////////////////////////////////////////////////////////////////////////////////
// get sockaddr, IPv4 or IPv6:
void* Socket::get_in_addr (struct sockaddr* sa)
{
if (sa->sa_family == AF_INET)
return &(((struct sockaddr_in*) sa)->sin_addr);
return &(((struct sockaddr_in6*) sa)->sin6_addr);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -1,7 +1,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager. // taskwarrior - a command line task list manager.
// //
// Copyright 2006-2013, Paul Beckingham, Federico Hernandez. // Copyright 2006 - 2013, Paul Beckingham, Federico Hernandez.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -24,49 +24,39 @@
// http://www.opensource.org/licenses/mit-license.php // http://www.opensource.org/licenses/mit-license.php
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_TLSCLIENT
#define INCLUDED_TLSCLIENT
#ifndef INCLUDED_SOCKET #ifdef HAVE_LIBGNUTLS
#define INCLUDED_SOCKET
#include <string> #include <string>
#include <sys/select.h> #include <gnutls/gnutls.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
class Socket class TLSClient
{ {
public: public:
Socket (); TLSClient ();
Socket (int); ~TLSClient ();
~Socket ();
// Client
void connect (const std::string&, const std::string&);
// Server
void bind (const std::string&);
void listen (int queue = 5);
int accept ();
void read (std::string&);
void write (const std::string&);
void close ();
void limit (int); void limit (int);
void debug (); void debug (int);
void init (const std::string&);
void connect (const std::string&, const std::string&);
void bye ();
void send (const std::string&);
void recv (std::string&);
private: private:
void* get_in_addr (struct sockaddr*); std::string _ca;
gnutls_certificate_credentials_t _credentials;
private: gnutls_session_t _session;
int _socket; int _socket;
int _limit; int _limit;
bool _debug; bool _debug;
}; };
#endif
#endif #endif
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -213,14 +213,6 @@ int CmdDiagnostics::execute (std::string& output)
<< location.mode () << location.mode ()
<< "\n"; << "\n";
out << " Server: "
<< context.config.get ("taskd.server")
<< "\n";
out << " Cert: "
<< context.config.get ("taskd.certificate")
<< "\n";
out << " Locking: " out << " Locking: "
<< (context.config.getBoolean ("locking") << (context.config.getBoolean ("locking")
? STRING_CMD_DIAG_ENABLED ? STRING_CMD_DIAG_ENABLED
@ -236,7 +228,25 @@ int CmdDiagnostics::execute (std::string& output)
else if ((peditor = getenv ("EDITOR")) != NULL) else if ((peditor = getenv ("EDITOR")) != NULL)
out << " $EDITOR: " << peditor << "\n"; out << " $EDITOR: " << peditor << "\n";
out << "\n"; out << " Server: "
<< context.config.get ("taskd.server")
<< "\n";
out << " Cert: "
<< context.config.get ("taskd.certificate")
<< "\n";
// Get credentials, but mask out the key.
std::string credentials = context.config.get ("taskd.credentials");
std::string::size_type last_slash = credentials.rfind ('/');
if (last_slash != std::string::npos)
credentials = credentials.substr (0, last_slash)
+ "/"
+ std::string (credentials.length () - last_slash - 1, '*');
out << " Creds: "
<< credentials
<< "\n\n";
// External commands. // External commands.
out << bold.colorize (STRING_CMD_DIAG_EXTERNAL) out << bold.colorize (STRING_CMD_DIAG_EXTERNAL)

View file

@ -25,15 +25,12 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <cmake.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <inttypes.h> #include <inttypes.h>
#include <Context.h> #include <Context.h>
#include <cmake.h>
#include <Socket.h> // TODO Socket is obsolete.
/*
#include <TLSClient.h> #include <TLSClient.h>
*/
#include <Color.h> #include <Color.h>
#include <text.h> #include <text.h>
#include <i18n.h> #include <i18n.h>
@ -77,6 +74,10 @@ int CmdSync::execute (std::string& output)
if (credentials.size () != 3) if (credentials.size () != 3)
throw std::string (STRING_CMD_SYNC_BAD_CRED); throw std::string (STRING_CMD_SYNC_BAD_CRED);
std::string certificate = context.config.get ("taskd.certificate");
if (certificate == "")
throw std::string (STRING_CMD_SYNC_BAD_CERT);
// Read backlog.data. // Read backlog.data.
std::string payload = ""; std::string payload = "";
File backlog (context.config.get ("data.location") + "/backlog.data"); File backlog (context.config.get ("data.location") + "/backlog.data");
@ -110,7 +111,7 @@ int CmdSync::execute (std::string& output)
<< "\n"; << "\n";
Msg response; Msg response;
if (send (connection, request, response)) if (send (connection, certificate, request, response))
{ {
std::string code = response.get ("code"); std::string code = response.get ("code");
if (code == "200") if (code == "200")
@ -259,6 +260,7 @@ int CmdSync::execute (std::string& output)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool CmdSync::send ( bool CmdSync::send (
const std::string& to, const std::string& to,
const std::string& certificate,
const Msg& request, const Msg& request,
Msg& response) Msg& response)
{ {
@ -270,23 +272,14 @@ bool CmdSync::send (
std::string server = to.substr (0, colon); std::string server = to.substr (0, colon);
std::string port = to.substr (colon + 1); std::string port = to.substr (colon + 1);
File cert (certificate);
try try
{ {
// TODO Socket is obsolete.
Socket s;
s.connect (server, port);
s.write (request.serialize () + "\n");
std::string incoming;
s.read (incoming);
s.close ();
/*
// A very basic TLS client, with X.509 authentication. // A very basic TLS client, with X.509 authentication.
TLSClient client; TLSClient client;
client.debug (); // TODO if (context.config.get ("debug")) client.debug (context.config.getInteger ("debug.tls"));
client.limit (1024); // TODO ??? client.init (cert);
client.init ("pki/client.cert.pem"); // TODO ???
client.connect (server, port); client.connect (server, port);
client.send (request.serialize () + "\n"); client.send (request.serialize () + "\n");
@ -294,7 +287,6 @@ bool CmdSync::send (
std::string incoming; std::string incoming;
client.recv (incoming); client.recv (incoming);
client.bye (); client.bye ();
*/
response.parse (incoming); response.parse (incoming);
return true; return true;

View file

@ -39,7 +39,7 @@ public:
int execute (std::string&); int execute (std::string&);
private: private:
bool send (const std::string&, const Msg&, Msg&); bool send (const std::string&, const std::string&, const Msg&, Msg&);
}; };
#endif #endif

View file

@ -404,6 +404,7 @@
#define STRING_CMD_SYNC_USAGE "Synchronizes data with the Task Server" #define STRING_CMD_SYNC_USAGE "Synchronizes data with the Task Server"
#define STRING_CMD_SYNC_NO_SERVER "Task Server is not configured." #define STRING_CMD_SYNC_NO_SERVER "Task Server is not configured."
#define STRING_CMD_SYNC_BAD_CRED "Task Server credentials malformed." #define STRING_CMD_SYNC_BAD_CRED "Task Server credentials malformed."
#define STRING_CMD_SYNC_BAD_CERT "Task Server certificate missing."
#define STRING_CMD_SYNC_ADD " add {1} '{2}'" #define STRING_CMD_SYNC_ADD " add {1} '{2}'"
#define STRING_CMD_SYNC_MOD "modify {1} '{2}'" #define STRING_CMD_SYNC_MOD "modify {1} '{2}'"
#define STRING_CMD_SYNC_PROGRESS "Syncing with {1}" #define STRING_CMD_SYNC_PROGRESS "Syncing with {1}"

View file

@ -415,6 +415,7 @@
#define STRING_CMD_SYNC_USAGE "Sincroniza datos con el Servidor Task" #define STRING_CMD_SYNC_USAGE "Sincroniza datos con el Servidor Task"
#define STRING_CMD_SYNC_NO_SERVER "El Servidor Task no está configurado." #define STRING_CMD_SYNC_NO_SERVER "El Servidor Task no está configurado."
#define STRING_CMD_SYNC_BAD_CRED "Credenciales del Servidor Task incorrectas." #define STRING_CMD_SYNC_BAD_CRED "Credenciales del Servidor Task incorrectas."
#define STRING_CMD_SYNC_BAD_CERT "Task Server certificate missing."
#define STRING_CMD_SYNC_ADD " añade {1} '{2}'" #define STRING_CMD_SYNC_ADD " añade {1} '{2}'"
#define STRING_CMD_SYNC_MOD "modifica {1} '{2}'" #define STRING_CMD_SYNC_MOD "modifica {1} '{2}'"
#define STRING_CMD_SYNC_PROGRESS "Sincronizando con {1}" #define STRING_CMD_SYNC_PROGRESS "Sincronizando con {1}"

View file

@ -404,6 +404,7 @@
#define STRING_CMD_SYNC_USAGE "Synchronizes data with the Task Server" #define STRING_CMD_SYNC_USAGE "Synchronizes data with the Task Server"
#define STRING_CMD_SYNC_NO_SERVER "Task Server is not configured." #define STRING_CMD_SYNC_NO_SERVER "Task Server is not configured."
#define STRING_CMD_SYNC_BAD_CRED "Task Server credentials malformed." #define STRING_CMD_SYNC_BAD_CRED "Task Server credentials malformed."
#define STRING_CMD_SYNC_BAD_CERT "Task Server certificate missing."
#define STRING_CMD_SYNC_ADD " add {1} '{2}'" #define STRING_CMD_SYNC_ADD " add {1} '{2}'"
#define STRING_CMD_SYNC_MOD "modify {1} '{2}'" #define STRING_CMD_SYNC_MOD "modify {1} '{2}'"
#define STRING_CMD_SYNC_PROGRESS "Syncing with {1}" #define STRING_CMD_SYNC_PROGRESS "Syncing with {1}"

View file

@ -405,6 +405,7 @@
#define STRING_CMD_SYNC_USAGE "Sincronizza i dati con il Task Server" #define STRING_CMD_SYNC_USAGE "Sincronizza i dati con il Task Server"
#define STRING_CMD_SYNC_NO_SERVER "Task Server non configurato." #define STRING_CMD_SYNC_NO_SERVER "Task Server non configurato."
#define STRING_CMD_SYNC_BAD_CRED "Credenziali del Task Server malformate." #define STRING_CMD_SYNC_BAD_CRED "Credenziali del Task Server malformate."
#define STRING_CMD_SYNC_BAD_CERT "Task Server certificate missing."
#define STRING_CMD_SYNC_ADD " aggiunto {1} '{2}'" #define STRING_CMD_SYNC_ADD " aggiunto {1} '{2}'"
#define STRING_CMD_SYNC_MOD "modificato {1} '{2}'" #define STRING_CMD_SYNC_MOD "modificato {1} '{2}'"
#define STRING_CMD_SYNC_PROGRESS "Sincronizzazione con {1}" #define STRING_CMD_SYNC_PROGRESS "Sincronizzazione con {1}"