mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-07 18:46:49 +02:00
Compare commits
112 Commits
v1.8.0
...
v1.8.1-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
458f336405 | ||
|
|
3f3f27d4d3 | ||
|
|
7c9cffa5ae | ||
|
|
996223197c | ||
|
|
b8e7555977 | ||
|
|
ed80a712ab | ||
|
|
2866e56c51 | ||
|
|
2074bdbb19 | ||
|
|
d212ac7d16 | ||
|
|
d2bae21b14 | ||
|
|
4283ab3b44 | ||
|
|
c579069071 | ||
|
|
88488c695c | ||
|
|
21594e9aa9 | ||
|
|
9ffacd4ecd | ||
|
|
9d5f5ea3bc | ||
|
|
2dbd27af76 | ||
|
|
0634a4d0c6 | ||
|
|
fa80a006b8 | ||
|
|
9d88ef5432 | ||
|
|
7b99877c68 | ||
|
|
ec81cdefb0 | ||
|
|
454d5b575c | ||
|
|
785b59e6d1 | ||
|
|
9d8fc4aa4d | ||
|
|
57ac1d9ea2 | ||
|
|
d9ea6936ab | ||
|
|
c917251e9e | ||
|
|
c805c5d6e9 | ||
|
|
adcf40afc3 | ||
|
|
d986011067 | ||
|
|
5a83636f81 | ||
|
|
d475628c70 | ||
|
|
4a890eae38 | ||
|
|
760e11bc5d | ||
|
|
96ebf2b519 | ||
|
|
4a6f4919d7 | ||
|
|
b98040c7d5 | ||
|
|
1240a8163d | ||
|
|
e15b9b5358 | ||
|
|
1617c9d482 | ||
|
|
16600fe86a | ||
|
|
50ba73860c | ||
|
|
750cdc1910 | ||
|
|
f4e2c84111 | ||
|
|
4f27750711 | ||
|
|
71d9f23068 | ||
|
|
9f7aed7602 | ||
|
|
7f2213416a | ||
|
|
9b9f0bdd4d | ||
|
|
ee0aec514f | ||
|
|
c2fd7d6ebd | ||
|
|
4a893c5267 | ||
|
|
2473183f19 | ||
|
|
7d7142d7d8 | ||
|
|
cb57cda87a | ||
|
|
f2fa812b0b | ||
|
|
ef89582d7e | ||
|
|
ae74a21305 | ||
|
|
32af63764c | ||
|
|
61ff90409d | ||
|
|
ba0c3256fa | ||
|
|
b6fe5d2cff | ||
|
|
9123fac545 | ||
|
|
c6bc388001 | ||
|
|
ea985a85af | ||
|
|
2578832002 | ||
|
|
cfada67aa6 | ||
|
|
5483682281 | ||
|
|
2a8c23aac3 | ||
|
|
88bc96fc4c | ||
|
|
588129d852 | ||
|
|
0889991c38 | ||
|
|
5c87a35fe4 | ||
|
|
418185af9a | ||
|
|
4b56cc6e08 | ||
|
|
3cef771868 | ||
|
|
59b20de7cd | ||
|
|
e0ae34f01b | ||
|
|
a9a24c96fc | ||
|
|
a202203325 | ||
|
|
83c3d76966 | ||
|
|
99734f8d72 | ||
|
|
570a0bb586 | ||
|
|
450a815d61 | ||
|
|
dafc2d2b73 | ||
|
|
0bd2edd33a | ||
|
|
807267cfdb | ||
|
|
48c9222578 | ||
|
|
b5ea56df73 | ||
|
|
2fdf6dd8f2 | ||
|
|
5b8c9eb16f | ||
|
|
9c05150c12 | ||
|
|
c7eb85ef78 | ||
|
|
4df455f2e0 | ||
|
|
653a00d63d | ||
|
|
3c9acdf724 | ||
|
|
e81d1ab9b8 | ||
|
|
ad5620efb5 | ||
|
|
f455c71338 | ||
|
|
033f2cd231 | ||
|
|
c9eccd729d | ||
|
|
b1100cd9e5 | ||
|
|
8f728ddfb2 | ||
|
|
4ef0ce112c | ||
|
|
57c14a0eba | ||
|
|
89f831e7d4 | ||
|
|
917b8409ae | ||
|
|
86fd39e3a9 | ||
|
|
04db332051 | ||
|
|
06a2f58c51 | ||
|
|
b87d55758b |
@@ -1,10 +1,10 @@
|
||||
set( MIRALL_VERSION_MAJOR 1 )
|
||||
set( MIRALL_VERSION_MINOR 8 )
|
||||
set( MIRALL_VERSION_PATCH 0 )
|
||||
set( MIRALL_VERSION_PATCH 1 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "beta1") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
19
admin/win/docker/build.sh
Executable file
19
admin/win/docker/build.sh
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $(basename $0) directory_relative_to_home [uid]"
|
||||
exit
|
||||
fi
|
||||
|
||||
useradd user -u ${2:-1000}
|
||||
su - user << EOF
|
||||
cd /home/user/$1
|
||||
rm -rf build-win32
|
||||
mkdir build-win32
|
||||
cd build-win32
|
||||
../admin/win/download_runtimes.sh
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE=../admin/win/Toolchain-mingw32-openSUSE.cmake -DWITH_CRASHREPORTER=ON
|
||||
make -j4
|
||||
make package
|
||||
ctest .
|
||||
EOF
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#VS2013
|
||||
base_url=http://download.microsoft.com/download/2/E/6/2E61CFA4-993B-4DD4-91DA-3737CD5CD6E3
|
||||
tmp_path=/tmp/.vcredist
|
||||
tmp_path=${1:-/tmp/.vcredist}
|
||||
|
||||
mkdir -p $tmp_path
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ StrCpy $PageReinstall_SAME_Field_3 "Desinstal.lar ${APPLICATION_NAME}"
|
||||
StrCpy $UNINSTALLER_APPDATA_TITLE "Desinstal.lar ${APPLICATION_NAME}"
|
||||
StrCpy $PageReinstall_SAME_MUI_HEADER_TEXT_SUBTITLE "Escolliu l'opció de manteniment per executar-ho."
|
||||
StrCpy $SEC_APPLICATION_DETAILS "Instal·lant ${APPLICATION_NAME} essencial."
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integració per Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Instal·lant integració per Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_SECTION "Accés directe del programa al menú d'inici"
|
||||
StrCpy $OPTION_SECTION_SC_START_MENU_DetailPrint "Afegint la drecera per ${APPLICATION_NAME} al menú d'inici."
|
||||
StrCpy $OPTION_SECTION_SC_DESKTOP_SECTION "Drecera a l'escriptori"
|
||||
@@ -42,5 +44,3 @@ StrCpy $INIT_INSTALLER_RUNNING "L'instal·lador ja s'està executant."
|
||||
StrCpy $UAC_UNINSTALLER_REQUIRE_ADMIN "Aquest desinstal·lador requereix accés d'administrador, intenteu-ho de nou."
|
||||
StrCpy $INIT_UNINSTALLER_RUNNING "El desinstal·lador ja s'està executant."
|
||||
StrCpy $SectionGroup_Shortcuts "Dreceres"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_SECTION "Integration for Windows Explorer"
|
||||
StrCpy $OPTION_SECTION_SC_SHELL_EXT_DetailPrint "Installing Integration for Windows Explorer"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Auto-generated - do not modify
|
||||
StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Afficher les notes de version"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Le(s) processus en cours d’exécution ${APPLICATION_EXECUTABLE} doit (doivent) être stoppé(s) afin de poursuivre.$\nVoulez-vous que le programme d’installation s’en charge pour vous ?"
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Les processus ${APPLICATION_EXECUTABLE} en cours d’exécution doivent être stoppés avant de poursuivre.$\nVoulez-vous que le programme d’installation s’en charge pour vous ?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Fermeture des processus ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Le processus à stopper n'a pas été trouvé !"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Une ancienne version de ${APPLICATION_NAME} est installée sur votre système. Il est recommandé de désinstaller cette version avant de continuer. Sélectionnez l'opération que vous voulez exécuter et cliquez sur Suivant pour continuer."
|
||||
|
||||
2
binary
2
binary
Submodule binary updated: 01d73965dc...1fb9ddfa9a
@@ -576,7 +576,8 @@ int csync_commit(CSYNC *ctx) {
|
||||
_csync_clean_ctx(ctx);
|
||||
|
||||
ctx->remote.read_from_db = 0;
|
||||
ctx->read_from_db_disabled = 0;
|
||||
ctx->read_remote_from_db = true;
|
||||
ctx->db_is_empty = false;
|
||||
|
||||
|
||||
/* Create new trees */
|
||||
@@ -773,10 +774,3 @@ int csync_set_module_property(CSYNC* ctx, const char* key, void* value)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int csync_set_read_from_db(CSYNC* ctx, int enabled)
|
||||
{
|
||||
ctx->read_from_db_disabled = !enabled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -550,11 +550,6 @@ void csync_resume(CSYNC *ctx);
|
||||
*/
|
||||
int csync_abort_requested(CSYNC *ctx);
|
||||
|
||||
/**
|
||||
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
|
||||
*/
|
||||
int csync_set_read_from_db(CSYNC* ctx, int enabled);
|
||||
|
||||
char *csync_normalize_etag(const char *);
|
||||
time_t oc_httpdate_parse( const char *date );
|
||||
|
||||
|
||||
@@ -151,7 +151,17 @@ struct csync_s {
|
||||
int status;
|
||||
volatile int abort;
|
||||
void *rename_info;
|
||||
int read_from_db_disabled;
|
||||
|
||||
/**
|
||||
* Specify if it is allowed to read the remote tree from the DB (default to enabled)
|
||||
*/
|
||||
bool read_remote_from_db;
|
||||
|
||||
/**
|
||||
* If true, the DB is considered empty and all reads are skipped. (default is false)
|
||||
* This is useful during the initial local discovery as it speeds it up significantly.
|
||||
*/
|
||||
bool db_is_empty;
|
||||
|
||||
struct csync_owncloud_ctx_s *owncloud_context;
|
||||
|
||||
|
||||
@@ -156,8 +156,8 @@ static int _csync_merge_algorithm_visitor(void *obj, void *data) {
|
||||
}
|
||||
|
||||
if( tmp ) {
|
||||
if( tmp->path ) {
|
||||
len = strlen( tmp->path );
|
||||
len = strlen( tmp->path );
|
||||
if( len > 0 ) {
|
||||
h = c_jhash64((uint8_t *) tmp->path, len, 0);
|
||||
/* First, check that the file is NOT in our tree (another file with the same name was added) */
|
||||
node = c_rbtree_find(ctx->current == REMOTE_REPLICA ? ctx->remote.tree : ctx->local.tree, &h);
|
||||
|
||||
@@ -298,7 +298,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_hash(CSYNC *ctx,
|
||||
csync_file_stat_t *st = NULL;
|
||||
int rc;
|
||||
|
||||
if( !ctx ) {
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_file_id(CSYNC *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !ctx ) {
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ csync_file_stat_t *csync_statedb_get_stat_by_inode(CSYNC *ctx,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( !ctx ) {
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -448,7 +448,7 @@ int csync_statedb_get_below_path( CSYNC *ctx, const char *path ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( !ctx ) {
|
||||
if( !ctx || ctx->db_is_empty ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -306,7 +306,7 @@ static int _csync_detect_update(CSYNC *ctx, const char *file,
|
||||
|| !c_streq(fs->remotePerm, tmp->remotePerm)))
|
||||
|| (ctx->current == LOCAL_REPLICA && fs->inode != tmp->inode);
|
||||
if (type == CSYNC_FTW_TYPE_DIR && ctx->current == REMOTE_REPLICA
|
||||
&& !metadata_differ && !ctx->read_from_db_disabled) {
|
||||
&& !metadata_differ && ctx->read_remote_from_db) {
|
||||
/* If both etag and file id are equal for a directory, read all contents from
|
||||
* the database.
|
||||
* The metadata comparison ensure that we fetch all the file id or permission when
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "c_lib.h"
|
||||
#include "csync.h"
|
||||
#include "csync_log.h"
|
||||
|
||||
csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||
csync_vio_file_stat_t *file_stat = (csync_vio_file_stat_t *) c_malloc(sizeof(csync_vio_file_stat_t));
|
||||
@@ -30,7 +31,9 @@ csync_vio_file_stat_t *csync_vio_file_stat_new(void) {
|
||||
csync_vio_file_stat_t* csync_vio_file_stat_copy(csync_vio_file_stat_t *file_stat) {
|
||||
csync_vio_file_stat_t *file_stat_cpy = csync_vio_file_stat_new();
|
||||
memcpy(file_stat_cpy, file_stat, sizeof(csync_vio_file_stat_t));
|
||||
file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
|
||||
if (file_stat_cpy->fields & CSYNC_VIO_FILE_STAT_FIELDS_ETAG) {
|
||||
file_stat_cpy->etag = c_strdup(file_stat_cpy->etag);
|
||||
}
|
||||
if (file_stat_cpy->directDownloadCookies) {
|
||||
file_stat_cpy->directDownloadCookies = c_strdup(file_stat_cpy->directDownloadCookies);
|
||||
}
|
||||
@@ -68,6 +71,7 @@ void csync_vio_file_stat_set_file_id( csync_vio_file_stat_t *dst, const char* sr
|
||||
void csync_vio_set_file_id( char* dst, const char *src ) {
|
||||
if( src && dst ) {
|
||||
if( strlen(src) > FILE_ID_BUF_SIZE ) {
|
||||
CSYNC_LOG(CSYNC_LOG_PRIORITY_ERROR, "Ignoring file_id because it is too long: %s", src);
|
||||
strcpy(dst, "");
|
||||
} else {
|
||||
strcpy(dst, src);
|
||||
|
||||
@@ -18,6 +18,9 @@ and then use their package managers to install the desktop sync client. Linux
|
||||
users will also update their sync clients via package manager, and the client
|
||||
will display a notification when an update is available.
|
||||
|
||||
Linux users must also have a password manager enabled, such as GNOME Keyring or
|
||||
KWallet, so that the sync client can login automatically.
|
||||
|
||||
Improvements and New Features
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class SocketConnect(GObject.GObject):
|
||||
print("Sending failed.")
|
||||
self.reconnect()
|
||||
else:
|
||||
print "Cannot send, not connected!"
|
||||
print("Cannot send, not connected!")
|
||||
|
||||
def addListener(self, listener):
|
||||
self._listeners.append(listener)
|
||||
@@ -85,7 +85,7 @@ class SocketConnect(GObject.GObject):
|
||||
self.connected = True
|
||||
print("Setting connected to %r" % self.connected )
|
||||
self._watch_id = GObject.io_add_watch(self._sock, GObject.IO_IN, self._handle_notify)
|
||||
print "Socket watch id: "+str(self._watch_id)
|
||||
print("Socket watch id: "+str(self._watch_id))
|
||||
return False # don't run again
|
||||
except Exception as e:
|
||||
print("Could not connect to unix socket." + str(e))
|
||||
@@ -175,7 +175,7 @@ class MenuExtension(GObject.GObject, Nautilus.MenuProvider):
|
||||
|
||||
def menu_share(self, menu, file):
|
||||
filename = get_local_path(file.get_uri())
|
||||
print "Share file "+filename
|
||||
print("Share file "+filename)
|
||||
socketConnect.sendCommand("SHARE:"+filename+"\n")
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
@@ -101,8 +100,8 @@
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OCCONTEXTMENU_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -132,6 +131,7 @@
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>..\$(Configuration)\$(Platform);</AdditionalLibraryDirectories>
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -145,6 +146,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\OCUtil;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -136,6 +137,7 @@
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PreprocessorDefinitions>NDEBUG;_USING_V110_SDK71_;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
@@ -194,6 +194,9 @@ void parseOptions( const QStringList& app_args, CmdOptions *options )
|
||||
if (options->target_url.startsWith("http"))
|
||||
options->target_url.replace(0, 4, "owncloud");
|
||||
options->source_dir = args.takeLast();
|
||||
if (!options->source_dir.endsWith('/')) {
|
||||
options->source_dir.append('/');
|
||||
}
|
||||
if( !QFile::exists( options->source_dir )) {
|
||||
std::cerr << "Source dir '" << qPrintable(options->source_dir) << "' does not exist." << std::endl;
|
||||
exit(1);
|
||||
@@ -442,7 +445,9 @@ restart_sync:
|
||||
if (!f.open(QFile::ReadOnly)) {
|
||||
qCritical() << "Could not open file containing the list of unsynced folders: " << options.unsyncedfolders;
|
||||
} else {
|
||||
selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n');
|
||||
// filter out empty lines and comments
|
||||
selectiveSyncList = QString::fromUtf8(f.readAll()).split('\n').filter(QRegExp("\\S+")).filter(QRegExp("^[^#]"));
|
||||
|
||||
for (int i = 0; i < selectiveSyncList.count(); ++i) {
|
||||
if (!selectiveSyncList.at(i).endsWith(QLatin1Char('/'))) {
|
||||
selectiveSyncList[i].append(QLatin1Char('/'));
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
#include "account.h"
|
||||
#include "simplesslerrorhandler.h"
|
||||
|
||||
bool SimpleSslErrorHandler::handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, OCC::AccountPtr account)
|
||||
bool SimpleSslErrorHandler::handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr account)
|
||||
{
|
||||
(void) account;
|
||||
(void) conf;
|
||||
|
||||
if (!certs) {
|
||||
qDebug() << "Certs parameter required but is NULL!";
|
||||
|
||||
@@ -20,7 +20,7 @@ class QSslCertificate;
|
||||
|
||||
class SimpleSslErrorHandler : public OCC::AbstractSslErrorHandler {
|
||||
public:
|
||||
bool handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, OCC::AccountPtr) Q_DECL_OVERRIDE;
|
||||
bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, OCC::AccountPtr) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // SIMPLESSLERRORHANDLER_H
|
||||
|
||||
@@ -154,10 +154,19 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
||||
qt_add_translation(client_I18N ${TRANSLATIONS})
|
||||
|
||||
IF( WIN32 )
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/version.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||
@ONLY)
|
||||
set(client_version ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||
ENDIF()
|
||||
|
||||
set( final_src
|
||||
${MIRALL_RC_SRC}
|
||||
${client_SRCS}
|
||||
${client_UI_SRCS}
|
||||
${client_version}
|
||||
${guiMoc}
|
||||
${client_I18N}
|
||||
${3rdparty_SRC}
|
||||
|
||||
@@ -43,7 +43,9 @@ void AccountStateManager::setAccountState(AccountState *accountState)
|
||||
emit accountStateRemoved(_accountState);
|
||||
}
|
||||
_accountState = accountState;
|
||||
emit accountStateAdded(accountState);
|
||||
if (accountState) {
|
||||
emit accountStateAdded(accountState);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountStateManager::slotAccountAdded(AccountPtr account)
|
||||
@@ -54,13 +56,15 @@ void AccountStateManager::slotAccountAdded(AccountPtr account)
|
||||
AccountState::AccountState(AccountPtr account)
|
||||
: QObject(account.data())
|
||||
, _account(account)
|
||||
, _quotaInfo(new QuotaInfo(this))
|
||||
, _quotaInfo(0)
|
||||
, _state(AccountState::Disconnected)
|
||||
, _connectionStatus(ConnectionValidator::Undefined)
|
||||
, _waitingForNewCredentials(false)
|
||||
{
|
||||
qRegisterMetaType<AccountState*>("AccountState*");
|
||||
|
||||
_quotaInfo = new QuotaInfo(this); // Need to be initialized when 'this' is fully initialized
|
||||
|
||||
connect(account.data(), SIGNAL(invalidCredentials()),
|
||||
SLOT(slotInvalidCredentials()));
|
||||
connect(account.data(), SIGNAL(credentialsFetched(AbstractCredentials*)),
|
||||
@@ -179,6 +183,15 @@ void AccountState::checkConnectivity()
|
||||
conValidator->checkAuthentication();
|
||||
} else {
|
||||
// Check the server and then the auth.
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// There seems to be a bug in Qt on Windows where QNAM sometimes stops
|
||||
// working correctly after the computer woke up from sleep. See #2895 #2899
|
||||
// and #2973.
|
||||
// As an attempted workaround, reset the QNAM regularly if the account is
|
||||
// disconnected.
|
||||
account()->resetNetworkAccessManager();
|
||||
#endif
|
||||
conValidator->checkServerAndAuth();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,8 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
// qDebug() << "* OCC shutdown";
|
||||
// Remove the account from the account manager so it can be deleted.
|
||||
AccountManager::instance()->setAccount(AccountPtr());
|
||||
}
|
||||
|
||||
void Application::slotLogin()
|
||||
@@ -403,7 +404,10 @@ void Application::parseOptions(const QStringList &options)
|
||||
} else if (option == QLatin1String("--confdir")) {
|
||||
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
|
||||
QString confDir = it.next();
|
||||
ConfigFile::setConfDir( confDir );
|
||||
if (!ConfigFile::setConfDir( confDir )) {
|
||||
std::cerr << "Invalid path passed to --confdir" << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
} else {
|
||||
showHelp();
|
||||
}
|
||||
|
||||
@@ -873,6 +873,13 @@ void FolderMan::setDirtyProxy(bool value)
|
||||
foreach( Folder *f, _folderMap.values() ) {
|
||||
if(f) {
|
||||
f->setProxyDirty(value);
|
||||
|
||||
if (f->accountState() && f->accountState()->account()
|
||||
&& f->accountState()->account()->networkAccessManager()) {
|
||||
// Need to do this have us not use the old determined system proxy
|
||||
f->accountState()->account()->networkAccessManager()->setProxy(
|
||||
QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,6 +246,12 @@ FolderWizardRemotePath::FolderWizardRemotePath(AccountPtr account)
|
||||
_lscolTimer.setInterval(500);
|
||||
_lscolTimer.setSingleShot(true);
|
||||
connect(&_lscolTimer, SIGNAL(timeout()), SLOT(slotLsColFolderEntry()));
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
_ui.folderTreeWidget->header()->setSectionResizeMode(0,QHeaderView::ResizeToContents);
|
||||
// Make sure that there will be a scrollbar when the contents is too wide
|
||||
_ui.folderTreeWidget->header()->setStretchLastSection(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotAddRemoteFolder()
|
||||
@@ -291,6 +297,8 @@ void FolderWizardRemotePath::slotCreateRemoteFolderFinished(QNetworkReply::Netwo
|
||||
qDebug() << "** webdav mkdir request finished";
|
||||
showWarn(tr("Folder was successfully created on %1.").arg(Theme::instance()->appNameGUI()));
|
||||
slotRefreshFolders();
|
||||
_ui.folderEntry->setText(static_cast<MkColJob *>(sender())->path());
|
||||
slotLsColFolderEntry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,9 @@ void OwncloudSetupWizard::slotDetermineAuthType(const QString &urlString)
|
||||
}
|
||||
AccountPtr account = _ocWizard->account();
|
||||
account->setUrl(url);
|
||||
// Reset the proxy which might had been determined previously in ConnectionValidator::checkServerAndAuth()
|
||||
// when there was a previous account.
|
||||
account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
// Set fake credentials beforfe we check what credential it actually is.
|
||||
account->setCredentials(CredentialsFactory::create("dummy"));
|
||||
CheckServerJob *job = new CheckServerJob(_ocWizard->account(), this);
|
||||
@@ -214,11 +217,53 @@ void OwncloudSetupWizard::testOwnCloudConnect()
|
||||
auto *job = new PropfindJob(account, "/", this);
|
||||
job->setIgnoreCredentialFailure(true);
|
||||
job->setProperties(QList<QByteArray>() << "getlastmodified");
|
||||
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
||||
connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotConnectionCheck(QNetworkReply*)));
|
||||
connect(job, SIGNAL(result(QVariantMap)), _ocWizard, SLOT(successfulStep()));
|
||||
connect(job, SIGNAL(finishedWithError()), this, SLOT(slotAuthError()));
|
||||
connect(job, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotAuthNetworkError(QNetworkReply*)));
|
||||
job->start();
|
||||
}
|
||||
|
||||
void OwncloudSetupWizard::slotAuthError()
|
||||
{
|
||||
QString errorMsg;
|
||||
|
||||
PropfindJob* job = qobject_cast<PropfindJob*>(sender());
|
||||
if (!job) {
|
||||
qWarning() << "Can't check for authed redirects. This slot should be invoked from PropfindJob!";
|
||||
return;
|
||||
}
|
||||
|
||||
// If there were redirects on the *authed* requests, also store
|
||||
// the updated server URL, similar to redirects on status.php.
|
||||
QUrl redirectUrl = job->reply()->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
|
||||
if (!redirectUrl.isEmpty()) {
|
||||
qDebug() << "authed request was redirected to" << redirectUrl.toString();
|
||||
|
||||
// strip the expected path
|
||||
QString path = redirectUrl.path();
|
||||
static QString expectedPath = "/" + _ocWizard->account()->davPath();
|
||||
if (path.endsWith(expectedPath)) {
|
||||
path.chop(expectedPath.size());
|
||||
redirectUrl.setPath(path);
|
||||
|
||||
qDebug() << "setting account url to" << redirectUrl.toString();
|
||||
_ocWizard->account()->setUrl(redirectUrl);
|
||||
testOwnCloudConnect();
|
||||
return;
|
||||
} else {
|
||||
errorMsg = tr("The authenticated request to the server was redirected to "
|
||||
"'%1'. The URL is bad, the server is misconfigured.")
|
||||
.arg(redirectUrl.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (errorMsg.isEmpty()) {
|
||||
errorMsg = tr("There was an invalid response to an authenticated webdav request");
|
||||
}
|
||||
_ocWizard->displayError(errorMsg, false);
|
||||
_ocWizard->show();
|
||||
}
|
||||
|
||||
bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
||||
{
|
||||
if(reply->url().scheme() != QLatin1String("https")) {
|
||||
@@ -242,7 +287,7 @@ bool OwncloudSetupWizard::checkDowngradeAdvised(QNetworkReply* reply)
|
||||
return true;
|
||||
}
|
||||
|
||||
void OwncloudSetupWizard::slotConnectionCheck(QNetworkReply* reply)
|
||||
void OwncloudSetupWizard::slotAuthNetworkError(QNetworkReply* reply)
|
||||
{
|
||||
QString msg = reply->errorString();
|
||||
switch (reply->error()) {
|
||||
@@ -291,7 +336,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
|
||||
}
|
||||
if (nextStep) {
|
||||
EntityExistsJob *job = new EntityExistsJob(_ocWizard->account(), _ocWizard->account()->davPath() + remoteFolder, this);
|
||||
connect(job, SIGNAL(exists(QNetworkReply*)), SLOT(slotAuthCheckReply(QNetworkReply*)));
|
||||
connect(job, SIGNAL(exists(QNetworkReply*)), SLOT(slotRemoteFolderExists(QNetworkReply*)));
|
||||
job->start();
|
||||
} else {
|
||||
finalizeSetup( false );
|
||||
@@ -299,7 +344,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString& localFo
|
||||
}
|
||||
|
||||
// ### TODO move into EntityExistsJob once we decide if/how to return gui strings from jobs
|
||||
void OwncloudSetupWizard::slotAuthCheckReply(QNetworkReply *reply)
|
||||
void OwncloudSetupWizard::slotRemoteFolderExists(QNetworkReply *reply)
|
||||
{
|
||||
bool ok = true;
|
||||
QString error;
|
||||
@@ -519,8 +564,10 @@ bool DetermineAuthTypeJob::finished()
|
||||
} else if (redirection.toString().endsWith(account()->davPath())) {
|
||||
// do a new run
|
||||
_redirects++;
|
||||
resetTimeout();
|
||||
setReply(getRequest(redirection));
|
||||
setupConnections(reply());
|
||||
return false; // don't discard
|
||||
} else {
|
||||
QRegExp shibbolethyWords("SAML|wayf");
|
||||
|
||||
|
||||
@@ -62,10 +62,11 @@ private slots:
|
||||
void slotNoOwnCloudFoundAuthTimeout(const QUrl&url);
|
||||
|
||||
void slotConnectToOCUrl(const QString&);
|
||||
void slotConnectionCheck(QNetworkReply*);
|
||||
void slotAuthNetworkError(QNetworkReply*);
|
||||
void slotAuthError();
|
||||
|
||||
void slotCreateLocalAndRemoteFolders(const QString&, const QString&);
|
||||
void slotAuthCheckReply(QNetworkReply*);
|
||||
void slotRemoteFolderExists(QNetworkReply*);
|
||||
void slotCreateRemoteFolderFinished(QNetworkReply::NetworkError);
|
||||
void slotAssistantFinished( int );
|
||||
void slotSkipFolderConfiguration();
|
||||
|
||||
@@ -73,16 +73,10 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
||||
_copyBtn->setToolTip( tr("Copy the activity list to the clipboard."));
|
||||
_copyBtn->setEnabled(false);
|
||||
connect(_copyBtn, SIGNAL(clicked()), SLOT(copyToClipboard()));
|
||||
|
||||
ConfigFile cfg;
|
||||
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
|
||||
}
|
||||
|
||||
ProtocolWidget::~ProtocolWidget()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.saveGeometryHeader(_ui->_treeWidget->header() );
|
||||
|
||||
delete _ui;
|
||||
}
|
||||
|
||||
@@ -137,6 +131,20 @@ void ProtocolWidget::slotRetrySync()
|
||||
folderMan->slotScheduleAllFolders();
|
||||
}
|
||||
|
||||
void ProtocolWidget::showEvent(QShowEvent *ev)
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.restoreGeometryHeader(_ui->_treeWidget->header());
|
||||
QWidget::showEvent(ev);
|
||||
}
|
||||
|
||||
void ProtocolWidget::hideEvent(QHideEvent *ev)
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.saveGeometryHeader(_ui->_treeWidget->header() );
|
||||
QWidget::hideEvent(ev);
|
||||
}
|
||||
|
||||
void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
||||
{
|
||||
int itemCnt = _ui->_treeWidget->topLevelItemCount();
|
||||
@@ -159,16 +167,11 @@ void ProtocolWidget::cleanIgnoreItems(const QString& folder)
|
||||
|
||||
QString ProtocolWidget::timeString(QDateTime dt, QLocale::FormatType format) const
|
||||
{
|
||||
QLocale loc = QLocale::system();
|
||||
QString timeStr;
|
||||
|
||||
if( format == QLocale::NarrowFormat ) {
|
||||
timeStr = loc.toString(dt, QLocale::NarrowFormat);
|
||||
} else {
|
||||
timeStr = loc.toString(dt, format);
|
||||
}
|
||||
|
||||
return timeStr;
|
||||
const QLocale loc = QLocale::system();
|
||||
QString dtFormat = loc.dateTimeFormat(format);
|
||||
static const QRegExp re("(HH|H|hh|h):mm(?!:s)");
|
||||
dtFormat.replace(re, "\\1:mm:ss");
|
||||
return loc.toString(dt, dtFormat);
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotOpenFile( QTreeWidgetItem *item, int )
|
||||
|
||||
@@ -39,8 +39,6 @@ public:
|
||||
explicit ProtocolWidget(QWidget *parent = 0);
|
||||
~ProtocolWidget();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void slotProgressInfo( const QString& folder, const Progress::Info& progress );
|
||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||
@@ -49,6 +47,10 @@ protected slots:
|
||||
void copyToClipboard();
|
||||
void slotRetrySync();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *);
|
||||
void hideEvent(QHideEvent *);
|
||||
|
||||
signals:
|
||||
void guiLog(const QString&, const QString&);
|
||||
|
||||
|
||||
@@ -26,10 +26,33 @@
|
||||
#include <QDebug>
|
||||
#include <QSettings>
|
||||
#include <QScopedValueRollback>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QLabel>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
|
||||
class SelectiveSyncTreeViewItem : public QTreeWidgetItem {
|
||||
public:
|
||||
SelectiveSyncTreeViewItem(int type = QTreeWidgetItem::Type)
|
||||
: QTreeWidgetItem(type) { }
|
||||
SelectiveSyncTreeViewItem(const QStringList &strings, int type = QTreeWidgetItem::Type)
|
||||
: QTreeWidgetItem(strings, type) { }
|
||||
SelectiveSyncTreeViewItem(QTreeWidget *view, int type = QTreeWidgetItem::Type)
|
||||
: QTreeWidgetItem(view, type) { }
|
||||
SelectiveSyncTreeViewItem(QTreeWidgetItem *parent, int type = QTreeWidgetItem::Type)
|
||||
: QTreeWidgetItem(parent, type) { }
|
||||
|
||||
private:
|
||||
bool operator<(const QTreeWidgetItem &other)const {
|
||||
int column = treeWidget()->sortColumn();
|
||||
if (column == 1) {
|
||||
return data(1, Qt::UserRole).toLongLong() < other.data(1, Qt::UserRole).toLongLong();
|
||||
}
|
||||
return QTreeWidgetItem::operator <(other);
|
||||
}
|
||||
};
|
||||
|
||||
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||
{
|
||||
@@ -101,9 +124,9 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
||||
parent->setToolTip(0, path);
|
||||
parent->setData(0, Qt::UserRole, path);
|
||||
} else {
|
||||
QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
|
||||
SelectiveSyncTreeViewItem *item = static_cast<SelectiveSyncTreeViewItem*>(findFirstChild(parent, pathTrail.first()));
|
||||
if (!item) {
|
||||
item = new QTreeWidgetItem(parent);
|
||||
item = new SelectiveSyncTreeViewItem(parent);
|
||||
if (parent->checkState(0) == Qt::Checked
|
||||
|| parent->checkState(0) == Qt::PartiallyChecked) {
|
||||
item->setCheckState(0, Qt::Checked);
|
||||
@@ -138,7 +161,7 @@ void SelectiveSyncTreeView::slotUpdateDirectories(const QStringList&list)
|
||||
QScopedValueRollback<bool> isInserting(_inserting);
|
||||
_inserting = true;
|
||||
|
||||
QTreeWidgetItem *root = topLevelItem(0);
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||
|
||||
if (!root && list.size() <= 1) {
|
||||
_loading->setText(tr("No subfolders currently on the server."));
|
||||
@@ -149,7 +172,7 @@ void SelectiveSyncTreeView::slotUpdateDirectories(const QStringList&list)
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
root = new QTreeWidgetItem(this);
|
||||
root = new SelectiveSyncTreeViewItem(this);
|
||||
root->setText(0, _rootName);
|
||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||
root->setData(0, Qt::UserRole, QString());
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "folder.h"
|
||||
#include "theme.h"
|
||||
#include "syncresult.h"
|
||||
#include "configfile.h"
|
||||
|
||||
#include "QProgressIndicator.h"
|
||||
#include <QBuffer>
|
||||
@@ -44,6 +45,8 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
_resharingAllowed(resharingAllowed)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setObjectName("SharingDialog"); // required as group for saveGeometry call
|
||||
|
||||
_ui->setupUi(this);
|
||||
_ui->pushButton_copy->setIcon(QIcon::fromTheme("edit-copy"));
|
||||
_ui->pushButton_copy->setEnabled(false);
|
||||
@@ -84,24 +87,31 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
QIcon icon = icon_provider.icon(f_info);
|
||||
_ui->label_icon->setPixmap(icon.pixmap(40,40));
|
||||
|
||||
QString name;
|
||||
if( f_info.isDir() ) {
|
||||
name = tr("Share Directory");
|
||||
} else {
|
||||
name = tr("Share File");
|
||||
}
|
||||
_ui->groupBox->setTitle(name);
|
||||
|
||||
QString lPath(_localPath);
|
||||
if( lPath.length() > 50) {
|
||||
lPath = QLatin1String("...")+lPath.right(50);
|
||||
}
|
||||
_ui->label_name->setText(tr("Local path: %1").arg(lPath));
|
||||
QFileInfo lPath(_localPath);
|
||||
QString fileName = lPath.fileName();
|
||||
_ui->label_name->setText(tr("%1").arg(fileName));
|
||||
QFont f( _ui->label_name->font());
|
||||
f.setPointSize( f.pointSize() * 1.4 );
|
||||
_ui->label_name->setFont( f );
|
||||
|
||||
_ui->label_sharePath->setWordWrap(true);
|
||||
_ui->label_sharePath->setText(tr("%1 path: %2").arg(Theme::instance()->appNameGUI()).arg(_sharePath));
|
||||
QString ocDir(_sharePath);
|
||||
ocDir.truncate(ocDir.length()-fileName.length());
|
||||
|
||||
if( ocDir == QLatin1String("/")) {
|
||||
_ui->label_sharePath->setText(QString());
|
||||
} else {
|
||||
if( ocDir.startsWith(QLatin1Char('/')) ) {
|
||||
ocDir = ocDir.mid(1, -1);
|
||||
}
|
||||
if( ocDir.endsWith(QLatin1Char('/')) ) {
|
||||
ocDir.chop(1);
|
||||
}
|
||||
_ui->label_sharePath->setText(tr("Folder: %2").arg(ocDir));
|
||||
}
|
||||
|
||||
this->setWindowTitle(tr("%1 Sharing").arg(Theme::instance()->appNameGUI()));
|
||||
_ui->label_password->setText(tr("Set p&assword"));
|
||||
_ui->checkBox_password->setText(tr("P&assword protect"));
|
||||
// check if the file is already inside of a synced folder
|
||||
if( sharePath.isEmpty() ) {
|
||||
// The file is not yet in an ownCloud synced folder. We could automatically
|
||||
@@ -128,6 +138,12 @@ ShareDialog::ShareDialog(AccountPtr account, const QString &sharePath, const QSt
|
||||
_ui->errorLabel->hide();
|
||||
}
|
||||
|
||||
void ShareDialog::done( int r ) {
|
||||
ConfigFile cfg;
|
||||
cfg.saveGeometry(this);
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
void ShareDialog::setExpireDate(const QDate &date)
|
||||
{
|
||||
if( _public_share_id == 0 ) {
|
||||
@@ -331,19 +347,40 @@ void ShareDialog::slotSharesFetched(const QString &reply)
|
||||
}
|
||||
}
|
||||
|
||||
void ShareDialog::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QDialog::resizeEvent(e);
|
||||
redrawElidedUrl();
|
||||
}
|
||||
|
||||
void ShareDialog::redrawElidedUrl()
|
||||
{
|
||||
QString u;
|
||||
|
||||
if( !_shareUrl.isEmpty() ) {
|
||||
QFontMetrics fm( _ui->_labelShareLink->font() );
|
||||
int linkLengthPixel = _ui->_labelShareLink->width();
|
||||
|
||||
const QUrl realUrl(_shareUrl);
|
||||
QString elidedUrl = fm.elidedText(_shareUrl, Qt::ElideRight, linkLengthPixel);
|
||||
|
||||
u = QString("<a href=\"%1\">%2</a>").arg(realUrl.toString(QUrl::None)).arg(elidedUrl);
|
||||
}
|
||||
_ui->_labelShareLink->setText(u);
|
||||
}
|
||||
|
||||
void ShareDialog::setShareLink( const QString& url )
|
||||
{
|
||||
// FIXME: shorten the url for output.
|
||||
const QUrl realUrl(url);
|
||||
if( realUrl.isValid() ) {
|
||||
const QString u = QString("<a href=\"%1\">%2</a>").arg(realUrl.toString(QUrl::None)).arg(url);
|
||||
_ui->_labelShareLink->setText(u);
|
||||
_shareUrl = url;
|
||||
_ui->pushButton_copy->setEnabled(true);
|
||||
} else {
|
||||
_shareUrl.clear();
|
||||
_ui->_labelShareLink->setText(QString::null);
|
||||
}
|
||||
redrawElidedUrl();
|
||||
|
||||
}
|
||||
|
||||
@@ -407,7 +444,7 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
|
||||
// there needs to be a password
|
||||
_ui->checkBox_password->setChecked(true);
|
||||
_ui->checkBox_password->setVisible(false);
|
||||
_ui->label_password->setText(tr("Public shå requires a password:"));
|
||||
_ui->checkBox_password->setText(tr("Public shå requires a password:"));
|
||||
_ui->lineEdit_password->setFocus();
|
||||
_ui->widget_shareLink->show();
|
||||
|
||||
@@ -421,13 +458,7 @@ void ShareDialog::slotCreateShareFetched(const QString &reply)
|
||||
bool success;
|
||||
QVariantMap json = QtJson::parse(reply, success).toMap();
|
||||
_public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong();
|
||||
QString url = json.value("ocs").toMap().values("data")[0].toMap().value("url").toString();
|
||||
|
||||
setShareLink(url);
|
||||
|
||||
setShareCheckBoxTitle(true);
|
||||
|
||||
_ui->widget_shareLink->show();
|
||||
getShares();
|
||||
}
|
||||
|
||||
void ShareDialog::slotCheckBoxPasswordClicked()
|
||||
@@ -487,8 +518,8 @@ int ShareDialog::checkJsonReturnCode(const QString &reply, QString &message)
|
||||
|
||||
void ShareDialog::setShareCheckBoxTitle(bool haveShares)
|
||||
{
|
||||
const QString noSharesTitle(tr("Check to &share by public link"));
|
||||
const QString haveSharesTitle(tr("&Shared by public link (uncheck to delete share)"));
|
||||
const QString noSharesTitle(tr("&Share link"));
|
||||
const QString haveSharesTitle(tr("&Share link"));
|
||||
|
||||
if( haveShares ) {
|
||||
_ui->checkBox_shareLink->setText( haveSharesTitle );
|
||||
|
||||
@@ -76,11 +76,15 @@ private slots:
|
||||
void slotPasswordChanged(const QString& newText);
|
||||
void slotPushButtonCopyLinkPressed();
|
||||
void slotThumbnailFetched(const int &statusCode, const QByteArray &reply);
|
||||
|
||||
void done( int r );
|
||||
private:
|
||||
void setShareCheckBoxTitle(bool haveShares);
|
||||
void displayError(int code);
|
||||
void displayError(const QString& errMsg);
|
||||
void setShareLink( const QString& url );
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
void redrawElidedUrl();
|
||||
|
||||
Ui::ShareDialog *_ui;
|
||||
AccountPtr _account;
|
||||
|
||||
@@ -6,23 +6,71 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>403</width>
|
||||
<height>296</height>
|
||||
<width>372</width>
|
||||
<height>241</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Share NewDocument.odt</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="errorLabel">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_icon">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_name">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>share label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="2">
|
||||
<widget class="QProgressIndicator" name="pi_share" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_sharePath">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ownCloud Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_shareLink">
|
||||
<property name="topMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_shareLink">
|
||||
<property name="text">
|
||||
@@ -34,8 +82,14 @@
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QWidget" name="widget_shareLink" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
@@ -68,7 +122,7 @@
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_copy">
|
||||
<property name="text">
|
||||
<string>Copy &Link</string>
|
||||
<string>Copy &link</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -79,30 +133,36 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_password">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>Set password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_password">
|
||||
<property name="text">
|
||||
<string>Set p&assword</string>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>checkBox_password</cstring>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_14">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit_password">
|
||||
<property name="echoMode">
|
||||
@@ -112,15 +172,24 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_setPassword">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set &Password</string>
|
||||
<string>Set &password </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox_expire">
|
||||
<property name="text">
|
||||
@@ -140,80 +209,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Share Info</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QLabel" name="label_icon">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label_name">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>share label</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" rowspan="2">
|
||||
<widget class="QProgressIndicator" name="pi_share" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="label_sharePath">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>ownCloud Path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -227,7 +222,37 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="errorLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>errorLabel</zorder>
|
||||
<zorder>widget_shareLink</zorder>
|
||||
<zorder>buttonBox</zorder>
|
||||
<zorder>checkBox_password</zorder>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) by Dominik Schmidt <dev@dominik-schmidt.de>
|
||||
* Copyright (C) by Klaas Freitag <freitag@owncloud.com>
|
||||
* Copyright (C) by Roeland Jago Douma <roeland@famdouma.nl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +25,7 @@
|
||||
#include "syncfileitem.h"
|
||||
#include "filesystem.h"
|
||||
#include "version.h"
|
||||
#include "accountstate.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QUrl>
|
||||
@@ -136,7 +138,9 @@ SocketApi::~SocketApi()
|
||||
{
|
||||
DEBUG << "dtor";
|
||||
_localServer.close();
|
||||
qDeleteAll(_listeners);
|
||||
// All remaining sockets will be destroyed with _localServer, their parent
|
||||
Q_ASSERT(_listeners.isEmpty() || _listeners.first()->parent() == &_localServer);
|
||||
_listeners.clear();
|
||||
slotClearExcludesList();
|
||||
}
|
||||
|
||||
@@ -163,7 +167,7 @@ void SocketApi::slotReadExcludes()
|
||||
|
||||
void SocketApi::slotNewConnection()
|
||||
{
|
||||
SocketType* socket = _localServer.nextPendingConnection();
|
||||
QLocalSocket* socket = _localServer.nextPendingConnection();
|
||||
|
||||
if( ! socket ) {
|
||||
return;
|
||||
@@ -195,7 +199,7 @@ void SocketApi::onLostConnection()
|
||||
{
|
||||
DEBUG << "Lost connection " << sender();
|
||||
|
||||
SocketType* socket = qobject_cast<SocketType*>(sender());
|
||||
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
|
||||
_listeners.removeAll(socket);
|
||||
socket->deleteLater();
|
||||
}
|
||||
@@ -203,7 +207,7 @@ void SocketApi::onLostConnection()
|
||||
|
||||
void SocketApi::slotReadSocket()
|
||||
{
|
||||
SocketType* socket = qobject_cast<SocketType*>(sender());
|
||||
QLocalSocket* socket = qobject_cast<QLocalSocket*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
|
||||
while(socket->canReadLine()) {
|
||||
@@ -211,12 +215,12 @@ void SocketApi::slotReadSocket()
|
||||
QString command = line.split(":").first();
|
||||
QString function = QString(QLatin1String("command_")).append(command);
|
||||
|
||||
QString functionWithArguments = function + QLatin1String("(QString,SocketType*)");
|
||||
QString functionWithArguments = function + QLatin1String("(QString,QLocalSocket*)");
|
||||
int indexOfMethod = this->metaObject()->indexOfMethod(functionWithArguments.toAscii());
|
||||
|
||||
QString argument = line.remove(0, command.length()+1).trimmed();
|
||||
if(indexOfMethod != -1) {
|
||||
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(SocketType*, socket));
|
||||
QMetaObject::invokeMethod(this, function.toAscii(), Q_ARG(QString, argument), Q_ARG(QLocalSocket*, socket));
|
||||
} else {
|
||||
DEBUG << "The command is not supported by this version of the client:" << command << "with argument:" << argument;
|
||||
}
|
||||
@@ -228,7 +232,7 @@ void SocketApi::slotRegisterPath( const QString& alias )
|
||||
Folder *f = FolderMan::instance()->folder(alias);
|
||||
if (f) {
|
||||
QString message = buildRegisterPathMessage(f->path());
|
||||
foreach(SocketType *socket, _listeners) {
|
||||
foreach(QLocalSocket *socket, _listeners) {
|
||||
sendMessage(socket, message);
|
||||
}
|
||||
}
|
||||
@@ -333,7 +337,7 @@ void SocketApi::slotSyncItemDiscovered(const QString &folder, const SyncFileItem
|
||||
|
||||
|
||||
|
||||
void SocketApi::sendMessage(SocketType *socket, const QString& message, bool doWait)
|
||||
void SocketApi::sendMessage(QLocalSocket *socket, const QString& message, bool doWait)
|
||||
{
|
||||
DEBUG << "Sending message: " << message;
|
||||
QString localMessage = message;
|
||||
@@ -368,12 +372,12 @@ void SocketApi::broadcastMessage( const QString& verb, const QString& path, cons
|
||||
|
||||
// sendMessage already has a debug output
|
||||
//DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << msg;
|
||||
foreach(SocketType *socket, _listeners) {
|
||||
foreach(QLocalSocket *socket, _listeners) {
|
||||
sendMessage(socket, msg, doWait);
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketType* socket)
|
||||
void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket)
|
||||
{
|
||||
// This command is the same as RETRIEVE_FILE_STATUS
|
||||
|
||||
@@ -381,7 +385,7 @@ void SocketApi::command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketTy
|
||||
command_RETRIEVE_FILE_STATUS(argument, socket);
|
||||
}
|
||||
|
||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType* socket)
|
||||
void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QLocalSocket* socket)
|
||||
{
|
||||
if( !socket ) {
|
||||
qDebug() << "No valid socket object.";
|
||||
@@ -409,7 +413,7 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType
|
||||
sendMessage(socket, message);
|
||||
}
|
||||
|
||||
void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
||||
void SocketApi::command_SHARE(const QString& localFile, QLocalSocket* socket)
|
||||
{
|
||||
if (!socket) {
|
||||
qDebug() << Q_FUNC_INFO << "No valid socket object.";
|
||||
@@ -423,6 +427,10 @@ void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
||||
const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(localFile);
|
||||
// files that are not within a sync folder are not synced.
|
||||
sendMessage(socket, message);
|
||||
} else if (!shareFolder->accountState()->isConnected()) {
|
||||
const QString message = QLatin1String("SHARE:NOTCONNECTED:")+QDir::toNativeSeparators(localFile);
|
||||
// if the folder isn't connected, don't open the share dialog
|
||||
sendMessage(socket, message);
|
||||
} else {
|
||||
const QString folderForPath = shareFolder->path();
|
||||
const QString remotePath = shareFolder->remotePath() + localFile.right(localFile.count()-folderForPath.count()+1);
|
||||
@@ -443,12 +451,12 @@ void SocketApi::command_SHARE(const QString& localFile, SocketType* socket)
|
||||
}
|
||||
}
|
||||
|
||||
void SocketApi::command_VERSION(const QString&, SocketType* socket)
|
||||
void SocketApi::command_VERSION(const QString&, QLocalSocket* socket)
|
||||
{
|
||||
sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION));
|
||||
}
|
||||
|
||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, SocketType* socket)
|
||||
void SocketApi::command_SHARE_MENU_TITLE(const QString &, QLocalSocket* socket)
|
||||
{
|
||||
sendMessage(socket, QLatin1String("SHARE_MENU_TITLE:") + tr("Share with %1", "parameter is ownCloud").arg(Theme::instance()->appNameGUI()));
|
||||
}
|
||||
|
||||
@@ -37,8 +37,6 @@ class QStringList;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
typedef QLocalSocket SocketType;
|
||||
|
||||
class SyncFileStatus;
|
||||
class Folder;
|
||||
|
||||
@@ -72,24 +70,20 @@ private:
|
||||
SyncJournalFileRecord dbFileRecord_capi( Folder *folder, QString fileName );
|
||||
SqlQuery *getSqlQuery( Folder *folder );
|
||||
|
||||
void sendMessage(SocketType* socket, const QString& message, bool doWait = false);
|
||||
void sendMessage(QLocalSocket* socket, const QString& message, bool doWait = false);
|
||||
void broadcastMessage(const QString& verb, const QString &path, const QString &status = QString::null, bool doWait = false);
|
||||
|
||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketType* socket);
|
||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType* socket);
|
||||
Q_INVOKABLE void command_SHARE(const QString& localFile, SocketType* socket);
|
||||
Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, QLocalSocket* socket);
|
||||
Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, QLocalSocket* socket);
|
||||
Q_INVOKABLE void command_SHARE(const QString& localFile, QLocalSocket* socket);
|
||||
|
||||
Q_INVOKABLE void command_VERSION(const QString& argument, SocketType* socket);
|
||||
Q_INVOKABLE void command_VERSION(const QString& argument, QLocalSocket* socket);
|
||||
|
||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, SocketType* socket);
|
||||
Q_INVOKABLE void command_SHARE_MENU_TITLE(const QString& argument, QLocalSocket* socket);
|
||||
QString buildRegisterPathMessage(const QString& path);
|
||||
|
||||
#ifdef SOCKETAPI_TCP
|
||||
QTcpServer _localServer;
|
||||
#else
|
||||
QLocalServer _localServer;
|
||||
#endif
|
||||
QList<SocketType*> _listeners;
|
||||
QList<QLocalSocket*> _listeners;
|
||||
c_strlist_t *_excludes;
|
||||
QHash<Folder*, SqlQuery*> _dbQueries;
|
||||
QHash<Folder*, SqlDatabase*> _openDbs;
|
||||
|
||||
@@ -31,6 +31,10 @@ SslButton::SslButton(QWidget *parent) :
|
||||
{
|
||||
setPopupMode(QToolButton::InstantPopup);
|
||||
setAutoRaise(true);
|
||||
|
||||
setMenu(new QMenu(this));
|
||||
QObject::connect(menu(), SIGNAL(aboutToShow()),
|
||||
this, SLOT(slotUpdateMenu()));
|
||||
}
|
||||
|
||||
QString SslButton::protoToString(QSsl::SslProtocol proto)
|
||||
@@ -178,19 +182,39 @@ void SslButton::updateAccountState(AccountState *accountState)
|
||||
} else {
|
||||
setVisible(true);
|
||||
}
|
||||
AccountPtr account = accountState->account();
|
||||
if(QMenu *oldMenu = menu()) {
|
||||
oldMenu->hide(); // Need to be hidden because the QToolButton would be left in invalid state if the menu is deleted while it is visible
|
||||
setMenu(0);
|
||||
oldMenu->deleteLater(); // setMenu do not delete the previous menu.
|
||||
}
|
||||
_accountState = accountState;
|
||||
|
||||
AccountPtr account = _accountState->account();
|
||||
if (account->url().scheme() == QLatin1String("https")) {
|
||||
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-https.png"))));
|
||||
QPixmap pm(Theme::hidpiFileName(":/client/resources/lock-https.png"));
|
||||
setIcon(QIcon(pm));
|
||||
QSslCipher cipher = account->sslConfiguration().sessionCipher();
|
||||
setToolTip(tr("This connection is encrypted using %1 bit %2.\n").arg(cipher.usedBits()).arg(cipher.name()));
|
||||
QMenu *menu = new QMenu(this);
|
||||
} else {
|
||||
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png"))));
|
||||
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void SslButton::slotUpdateMenu() {
|
||||
menu()->clear();
|
||||
|
||||
if (!_accountState) {
|
||||
return;
|
||||
}
|
||||
|
||||
AccountPtr account = _accountState->account();
|
||||
|
||||
if (account->url().scheme() == QLatin1String("https")) {
|
||||
|
||||
QList<QSslCertificate> chain = account->sslConfiguration().peerCertificateChain();
|
||||
menu->addAction(tr("Certificate information:"))->setEnabled(false);
|
||||
|
||||
if (chain.isEmpty()) {
|
||||
qWarning() << "empty certificate chain";
|
||||
return;
|
||||
}
|
||||
|
||||
menu()->addAction(tr("Certificate information:"))->setEnabled(false);
|
||||
|
||||
QList<QSslCertificate> tmpChain;
|
||||
foreach(QSslCertificate cert, chain) {
|
||||
@@ -213,13 +237,9 @@ void SslButton::updateAccountState(AccountState *accountState)
|
||||
it.toBack();
|
||||
int i = 0;
|
||||
while (it.hasPrevious()) {
|
||||
menu->addMenu(buildCertMenu(menu, it.previous(), account->approvedCerts(), i));
|
||||
menu()->addMenu(buildCertMenu(menu(), it.previous(), account->approvedCerts(), i));
|
||||
i++;
|
||||
}
|
||||
setMenu(menu);
|
||||
} else {
|
||||
setIcon(QIcon(QPixmap(Theme::hidpiFileName(":/client/resources/lock-http.png"))));
|
||||
setToolTip(tr("This connection is NOT secure as it is not encrypted.\n"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,6 @@ class QSslConfiguration;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class Account;
|
||||
class AccountState;
|
||||
|
||||
class SslButton : public QToolButton
|
||||
@@ -35,9 +34,13 @@ public:
|
||||
QString protoToString(QSsl::SslProtocol proto);
|
||||
void updateAccountState(AccountState *accountState);
|
||||
|
||||
public slots:
|
||||
void slotUpdateMenu();
|
||||
|
||||
private:
|
||||
QMenu* buildCertMenu(QMenu *parent, const QSslCertificate& cert,
|
||||
const QList<QSslCertificate>& userApproved, int pos);
|
||||
QPointer<AccountState> _accountState;
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -34,8 +34,9 @@ namespace Utility {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SslDialogErrorHandler::handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, AccountPtr account)
|
||||
bool SslDialogErrorHandler::handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, AccountPtr account)
|
||||
{
|
||||
(void) conf;
|
||||
if (!certs) {
|
||||
qDebug() << "Certs parameter required but is NULL!";
|
||||
return false;
|
||||
|
||||
@@ -33,7 +33,7 @@ class SslErrorDialog;
|
||||
|
||||
class SslDialogErrorHandler : public AbstractSslErrorHandler {
|
||||
public:
|
||||
bool handleErrors(QList<QSslError> errors, QList<QSslCertificate> *certs, AccountPtr) Q_DECL_OVERRIDE;
|
||||
bool handleErrors(QList<QSslError> errors, const QSslConfiguration &conf, QList<QSslCertificate> *certs, AccountPtr) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
class SslErrorDialog : public QDialog
|
||||
|
||||
@@ -52,9 +52,10 @@ bool OCUpdater::performUpdate()
|
||||
QSettings settings(cfg.configFile(), QSettings::IniFormat);
|
||||
QString updateFile = settings.value(updateAvailableC).toString();
|
||||
if (!updateFile.isEmpty() && QFile(updateFile).exists()) {
|
||||
if (QMessageBox::information(0, tr("New Update Ready"),
|
||||
tr("A new update is about to be installed. The updater may ask\n"
|
||||
"for additional privileges during the process."), QMessageBox::Ok)) {
|
||||
const QString name = Theme::instance()->appNameGUI();
|
||||
if (QMessageBox::information(0, tr("New %1 Update Ready").arg(name),
|
||||
tr("A new update for %1 is about to be installed. The updater may ask\n"
|
||||
"for additional privileges during the process.").arg(name), QMessageBox::Ok)) {
|
||||
slotStartInstaller();
|
||||
return true;
|
||||
}
|
||||
|
||||
25
src/gui/version.rc.in
Normal file
25
src/gui/version.rc.in
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "winresrc.h"
|
||||
|
||||
#define VER_FILEVERSION @MIRALL_VERSION_MAJOR@,@MIRALL_VERSION_MINOR@,@MIRALL_VERSION_PATCH@,@MIRALL_VERSION_BUILD@
|
||||
#define VER_FILEVERSION_STR "@MIRALL_VERSION_MAJOR@.@MIRALL_VERSION_MINOR@.@MIRALL_VERSION_PATCH@.@MIRALL_VERSION_BUILD@\0"
|
||||
|
||||
#define VER_PRODUCTVERSION @MIRALL_VERSION_MAJOR@,@MIRALL_VERSION_MINOR@,@MIRALL_VERSION_PATCH@,@MIRALL_VERSION_BUILD@
|
||||
#define VER_PRODUCTVERSION_STR "@MIRALL_VERSION_MAJOR@.@MIRALL_VERSION_MINOR@.@MIRALL_VERSION_PATCH@.@MIRALL_VERSION_BUILD@\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
PRODUCTVERSION VER_PRODUCTVERSION
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "FileVersion", VER_FILEVERSION_STR
|
||||
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x809, 1200
|
||||
END
|
||||
END
|
||||
@@ -64,7 +64,6 @@ set(libsync_SRCS
|
||||
creds/dummycredentials.cpp
|
||||
creds/abstractcredentials.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
creds/http/httpconfigfile.cpp
|
||||
creds/credentialscommon.cpp
|
||||
../3rdparty/qjson/json.cpp
|
||||
../3rdparty/certificates/p12topem.cpp
|
||||
|
||||
@@ -63,7 +63,9 @@ void AccountManager::setAccount(AccountPtr account)
|
||||
emit accountRemoved(_account);
|
||||
}
|
||||
_account = account;
|
||||
emit accountAdded(account);
|
||||
if (account) {
|
||||
emit accountAdded(account);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -129,6 +131,15 @@ void Account::save()
|
||||
if (!certs.isEmpty()) {
|
||||
settings->setValue( QLatin1String(caCertsKeyC), certs );
|
||||
}
|
||||
|
||||
// Save cookies.
|
||||
if (_am) {
|
||||
CookieJar* jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
||||
if (jar) {
|
||||
qDebug() << "Saving cookies.";
|
||||
jar->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AccountPtr Account::restore()
|
||||
@@ -271,6 +282,21 @@ void Account::clearCookieJar()
|
||||
_am->setCookieJar(new CookieJar);
|
||||
}
|
||||
|
||||
void Account::resetNetworkAccessManager()
|
||||
{
|
||||
if (!_credentials || !_am) {
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "Resetting QNAM";
|
||||
QNetworkCookieJar* jar = _am->cookieJar();
|
||||
_am->deleteLater();
|
||||
_am = _credentials->getQNAM();
|
||||
_am->setCookieJar(jar); // takes ownership of the old cookie jar
|
||||
connect(_am, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
|
||||
SLOT(slotHandleErrors(QNetworkReply*,QList<QSslError>)));
|
||||
}
|
||||
|
||||
QNetworkAccessManager *Account::networkAccessManager()
|
||||
{
|
||||
return _am;
|
||||
@@ -460,7 +486,7 @@ void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
|
||||
return;
|
||||
}
|
||||
|
||||
if (_sslErrorHandler->handleErrors(errors, &approvedCerts, sharedFromThis())) {
|
||||
if (_sslErrorHandler->handleErrors(errors, reply->sslConfiguration(), &approvedCerts, sharedFromThis())) {
|
||||
QSslSocket::addDefaultCaCertificates(approvedCerts);
|
||||
addApprovedCerts(approvedCerts);
|
||||
// all ssl certs are known and accepted. We can ignore the problems right away.
|
||||
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
class AbstractSslErrorHandler {
|
||||
public:
|
||||
virtual ~AbstractSslErrorHandler() {}
|
||||
virtual bool handleErrors(QList<QSslError>, QList<QSslCertificate>*, AccountPtr) = 0;
|
||||
virtual bool handleErrors(QList<QSslError>, const QSslConfiguration &conf, QList<QSslCertificate>*, AccountPtr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -156,6 +156,7 @@ public:
|
||||
|
||||
void clearCookieJar();
|
||||
|
||||
void resetNetworkAccessManager();
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
||||
/// Called by network jobs on credential errors.
|
||||
@@ -185,7 +186,6 @@ private:
|
||||
QNetworkAccessManager *_am;
|
||||
AbstractCredentials* _credentials;
|
||||
bool _treatSslErrorsAsFailure;
|
||||
int _state;
|
||||
static QString _configFileName;
|
||||
QByteArray _pemCertificate;
|
||||
QString _pemPrivateKey;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "configfile.h"
|
||||
#include <QUrl>
|
||||
#include <QThreadPool>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -23,7 +24,7 @@ ClientProxy::ClientProxy(QObject *parent) :
|
||||
{
|
||||
}
|
||||
|
||||
QNetworkProxy ClientProxy::proxyFromConfig(const ConfigFile& cfg)
|
||||
static QNetworkProxy proxyFromConfig(const ConfigFile& cfg)
|
||||
{
|
||||
QNetworkProxy proxy;
|
||||
|
||||
@@ -39,6 +40,22 @@ QNetworkProxy ClientProxy::proxyFromConfig(const ConfigFile& cfg)
|
||||
return proxy;
|
||||
}
|
||||
|
||||
bool ClientProxy::isUsingSystemDefault() {
|
||||
OCC::ConfigFile cfg;
|
||||
|
||||
// if there is no config file, default to system proxy.
|
||||
if( cfg.exists() ) {
|
||||
return cfg.proxyType() == QNetworkProxy::DefaultProxy;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString printQNetworkProxy(const QNetworkProxy &proxy)
|
||||
{
|
||||
return QString("%1://%2:%3").arg(proxy.type()).arg(proxy.hostName()).arg(proxy.port());
|
||||
}
|
||||
|
||||
void ClientProxy::setupQtProxyFromConfig()
|
||||
{
|
||||
OCC::ConfigFile cfg;
|
||||
@@ -53,19 +70,23 @@ void ClientProxy::setupQtProxyFromConfig()
|
||||
|
||||
switch(proxyType) {
|
||||
case QNetworkProxy::NoProxy:
|
||||
qDebug() << "Set proxy configuration to use NO proxy";
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
|
||||
break;
|
||||
case QNetworkProxy::DefaultProxy:
|
||||
qDebug() << "Set proxy configuration to use system configuration";
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(true);
|
||||
break;
|
||||
case QNetworkProxy::Socks5Proxy:
|
||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||
qDebug() << "Set proxy configuration to SOCKS5" << printQNetworkProxy(proxy);
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||
QNetworkProxy::setApplicationProxy(proxy);
|
||||
break;
|
||||
case QNetworkProxy::HttpProxy:
|
||||
proxy.setType(QNetworkProxy::HttpProxy);
|
||||
qDebug() << "Set proxy configuration to HTTP" << printQNetworkProxy(proxy);
|
||||
QNetworkProxyFactory::setUseSystemConfiguration(false);
|
||||
QNetworkProxy::setApplicationProxy(proxy);
|
||||
break;
|
||||
@@ -96,6 +117,7 @@ const char* ClientProxy::proxyTypeToCStr(QNetworkProxy::ProxyType type)
|
||||
|
||||
void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
|
||||
{
|
||||
#ifdef USE_NEON
|
||||
/* Store proxy */
|
||||
QList<QNetworkProxy> proxies = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(url));
|
||||
// We set at least one in Application
|
||||
@@ -118,7 +140,38 @@ void ClientProxy::setCSyncProxy( const QUrl& url, CSYNC *csync_ctx )
|
||||
csync_set_module_property( csync_ctx, "proxy_port", &proxy_port );
|
||||
csync_set_module_property( csync_ctx, "proxy_user", proxy.user().toUtf8().data());
|
||||
csync_set_module_property( csync_ctx, "proxy_pwd", proxy.password().toUtf8().data());
|
||||
#else
|
||||
Q_UNUSED(url);
|
||||
Q_UNUSED(csync_ctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClientProxy::lookupSystemProxyAsync(const QUrl &url, QObject *dst, const char *slot)
|
||||
{
|
||||
SystemProxyRunnable *runnable = new SystemProxyRunnable(url);
|
||||
QObject::connect(runnable, SIGNAL(systemProxyLookedUp(QNetworkProxy)), dst, slot);
|
||||
QThreadPool::globalInstance()->start(runnable); // takes ownership and deletes
|
||||
}
|
||||
|
||||
SystemProxyRunnable::SystemProxyRunnable(const QUrl &url) : QObject(), QRunnable(), _url(url)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SystemProxyRunnable::run()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Starting system proxy lookup";
|
||||
QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(_url));
|
||||
|
||||
if (proxies.isEmpty()) {
|
||||
emit systemProxyLookedUp(QNetworkProxy(QNetworkProxy::NoProxy));
|
||||
} else {
|
||||
emit systemProxyLookedUp(proxies.first());
|
||||
// FIXME Would we really ever return more?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkProxy>
|
||||
#include <QRunnable>
|
||||
#include <QUrl>
|
||||
|
||||
#include <csync.h>
|
||||
#include "utility.h"
|
||||
@@ -30,17 +32,31 @@ class OWNCLOUDSYNC_EXPORT ClientProxy : public QObject
|
||||
public:
|
||||
explicit ClientProxy(QObject *parent = 0);
|
||||
|
||||
signals:
|
||||
static bool isUsingSystemDefault();
|
||||
static void lookupSystemProxyAsync(const QUrl &url, QObject *dst, const char *slot);
|
||||
|
||||
public slots:
|
||||
void setCSyncProxy( const QUrl& url, CSYNC *csync_ctx );
|
||||
void setupQtProxyFromConfig();
|
||||
|
||||
private:
|
||||
QNetworkProxy proxyFromConfig(const ConfigFile& cfg);
|
||||
const char* proxyTypeToCStr(QNetworkProxy::ProxyType type);
|
||||
};
|
||||
|
||||
class SystemProxyRunnable : public QObject, public QRunnable {
|
||||
Q_OBJECT
|
||||
public:
|
||||
SystemProxyRunnable(const QUrl &url);
|
||||
void run();
|
||||
signals:
|
||||
void systemProxyLookedUp(const QNetworkProxy &url);
|
||||
private:
|
||||
QUrl _url;
|
||||
};
|
||||
|
||||
QString printQNetworkProxy(const QNetworkProxy &proxy);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // CLIENTPROXY_H
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
static const char caCertsKeyC[] = "CaCertificates";
|
||||
//static const char caCertsKeyC[] = "CaCertificates"; only used from account.cpp
|
||||
static const char remotePollIntervalC[] = "remotePollInterval";
|
||||
static const char forceSyncIntervalC[] = "forceSyncInterval";
|
||||
static const char monoIconsC[] = "monoIcons";
|
||||
@@ -85,10 +85,10 @@ ConfigFile::ConfigFile()
|
||||
// qDebug() << Q_FUNC_INFO << "Loading config: " << config << " (URL is " << settings.value("url").toString() << ")";
|
||||
}
|
||||
|
||||
void ConfigFile::setConfDir(const QString &value)
|
||||
bool ConfigFile::setConfDir(const QString &value)
|
||||
{
|
||||
QString dirPath = value;
|
||||
if( dirPath.isEmpty() ) return;
|
||||
if( dirPath.isEmpty() ) return false;
|
||||
|
||||
QFileInfo fi(dirPath);
|
||||
if ( !fi.exists() && !fi.isAbsolute() ) {
|
||||
@@ -101,7 +101,9 @@ void ConfigFile::setConfDir(const QString &value)
|
||||
dirPath = fi.absoluteFilePath();
|
||||
qDebug() << "** Using custom config dir " << dirPath;
|
||||
_confDir=dirPath;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfigFile::optionalDesktopNotifications() const
|
||||
@@ -145,7 +147,7 @@ void ConfigFile::saveGeometryHeader(QHeaderView *header)
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
if(!header) return;
|
||||
Q_ASSERT(!header->objectName().isNull());
|
||||
Q_ASSERT(!header->objectName().isEmpty());
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
@@ -162,7 +164,7 @@ void ConfigFile::restoreGeometryHeader(QHeaderView *header)
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
header->restoreState(getValue(geometryC, header->objectName()).toByteArray());
|
||||
header->restoreState(settings.value(geometryC).toByteArray());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -315,20 +317,6 @@ bool ConfigFile::dataExists(const QString& group, const QString& key) const
|
||||
return settings.contains(key);
|
||||
}
|
||||
|
||||
QByteArray ConfigFile::caCerts( )
|
||||
{
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
return settings.value( QLatin1String(caCertsKeyC) ).toByteArray();
|
||||
}
|
||||
|
||||
void ConfigFile::setCaCerts( const QByteArray & certs )
|
||||
{
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
|
||||
settings.setValue( QLatin1String(caCertsKeyC), certs );
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
int ConfigFile::remotePollInterval( const QString& connection ) const
|
||||
{
|
||||
QString con( connection );
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
void setUploadLimit(int kbytes);
|
||||
void setDownloadLimit(int kbytes);
|
||||
|
||||
static void setConfDir(const QString &value);
|
||||
static bool setConfDir(const QString &value);
|
||||
|
||||
bool optionalDesktopNotifications() const;
|
||||
void setOptionalDesktopNotifications(bool show);
|
||||
|
||||
@@ -13,11 +13,13 @@
|
||||
|
||||
#include <QtCore>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkProxyFactory>
|
||||
|
||||
#include "connectionvalidator.h"
|
||||
#include "theme.h"
|
||||
#include "account.h"
|
||||
#include "networkjobs.h"
|
||||
#include "clientproxy.h"
|
||||
#include <creds/abstractcredentials.h>
|
||||
|
||||
namespace OCC {
|
||||
@@ -61,8 +63,38 @@ void ConnectionValidator::checkServerAndAuth()
|
||||
reportResult( NotConfigured );
|
||||
return;
|
||||
}
|
||||
qDebug() << "Checking server and authentication";
|
||||
|
||||
_isCheckingServerAndAuth = true;
|
||||
|
||||
// Lookup system proxy in a thread https://github.com/owncloud/client/issues/2993
|
||||
if (ClientProxy::isUsingSystemDefault()) {
|
||||
qDebug() << "Trying to look up system proxy";
|
||||
ClientProxy::lookupSystemProxyAsync(_account->url(),
|
||||
this, SLOT(systemProxyLookupDone(QNetworkProxy)));
|
||||
} else {
|
||||
// We want to reset the QNAM proxy so that the global proxy settings are used (via ClientProxy settings)
|
||||
_account->networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::DefaultProxy));
|
||||
// use a queued invocation so we're as asynchronous as with the other code path
|
||||
QMetaObject::invokeMethod(this, "slotCheckServerAndAuth", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionValidator::systemProxyLookupDone(const QNetworkProxy &proxy) {
|
||||
if (!_account) {
|
||||
qDebug() << "Bailing out, Account had been deleted";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << Q_FUNC_INFO << "Setting QNAM proxy to be system proxy" << printQNetworkProxy(proxy);
|
||||
_account->networkAccessManager()->setProxy(proxy);
|
||||
|
||||
slotCheckServerAndAuth();
|
||||
}
|
||||
|
||||
// The actual check
|
||||
void ConnectionValidator::slotCheckServerAndAuth()
|
||||
{
|
||||
CheckServerJob *checkJob = new CheckServerJob(_account, this);
|
||||
checkJob->setIgnoreCredentialFailure(true);
|
||||
connect(checkJob, SIGNAL(instanceFound(QUrl,QVariantMap)), SLOT(slotStatusFound(QUrl,QVariantMap)));
|
||||
@@ -98,12 +130,16 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
|
||||
// Fetch them now! Once fetched, a new connectivity check will be
|
||||
// initiated anyway.
|
||||
creds->fetch();
|
||||
|
||||
// no result is reported
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
// status.php could not be loaded (network or server issue!).
|
||||
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << reply->error() << reply->errorString();
|
||||
if( reply && ! _account->credentials()->stillValid(reply)) {
|
||||
_errors.append(tr("Authentication error: Either username or password are wrong."));
|
||||
} else {
|
||||
|
||||
@@ -36,6 +36,8 @@ namespace OCC {
|
||||
|
||||
|
||||
*---> checkServerAndAuth (check status.php)
|
||||
Will asynchronously check for system proxy (if using system proxy)
|
||||
And then invoke slotCheckServerAndAuth
|
||||
CheckServerJob
|
||||
|
|
||||
+-> slotNoStatusFound --> X
|
||||
@@ -85,6 +87,7 @@ public:
|
||||
public slots:
|
||||
/// Checks the server and the authentication.
|
||||
void checkServerAndAuth();
|
||||
void systemProxyLookupDone(const QNetworkProxy &proxy);
|
||||
|
||||
/// Checks authentication only.
|
||||
void checkAuthentication();
|
||||
@@ -93,6 +96,8 @@ signals:
|
||||
void connectionResult( ConnectionValidator::Status status, QStringList errors );
|
||||
|
||||
protected slots:
|
||||
void slotCheckServerAndAuth();
|
||||
|
||||
void slotStatusFound(const QUrl&url, const QVariantMap &info);
|
||||
void slotNoStatusFound(QNetworkReply *reply);
|
||||
void slotJobTimeout(const QUrl& url);
|
||||
|
||||
@@ -71,7 +71,6 @@ CookieJar::CookieJar(QObject *parent) :
|
||||
|
||||
CookieJar::~CookieJar()
|
||||
{
|
||||
save();
|
||||
}
|
||||
|
||||
bool CookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url)
|
||||
@@ -103,7 +102,7 @@ void CookieJar::save()
|
||||
qDebug() << storagePath();
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream stream(&file);
|
||||
stream << allCookies();
|
||||
stream << removeExpired(allCookies());
|
||||
file.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,11 @@ public:
|
||||
using QNetworkCookieJar::setAllCookies;
|
||||
using QNetworkCookieJar::allCookies;
|
||||
|
||||
void save();
|
||||
|
||||
signals:
|
||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
private:
|
||||
void save();
|
||||
void restore();
|
||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||
QString storagePath() const;
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "creds/http/httpconfigfile.h"
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const char userC[] = "user";
|
||||
const char passwdC[] = "passwd";
|
||||
const char oldPasswdC[] = "password";
|
||||
|
||||
} // ns
|
||||
|
||||
QString HttpConfigFile::user() const
|
||||
{
|
||||
return retrieveData(QString(), QLatin1String(userC)).toString();
|
||||
}
|
||||
|
||||
void HttpConfigFile::setUser(const QString& user)
|
||||
{
|
||||
storeData(QString(), QLatin1String(userC), QVariant(user));
|
||||
}
|
||||
|
||||
QString HttpConfigFile::password() const
|
||||
{
|
||||
const QVariant passwd(retrieveData(QString(), QLatin1String(passwdC)));
|
||||
|
||||
if (passwd.isValid()) {
|
||||
return QString::fromUtf8(QByteArray::fromBase64(passwd.toByteArray()));
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void HttpConfigFile::setPassword(const QString& password)
|
||||
{
|
||||
QByteArray pwdba = password.toUtf8();
|
||||
storeData( QString(), QLatin1String(passwdC), QVariant(pwdba.toBase64()) );
|
||||
removeOldPassword();
|
||||
}
|
||||
|
||||
bool HttpConfigFile::passwordExists() const
|
||||
{
|
||||
return dataExists(QString(), QLatin1String(passwdC));
|
||||
}
|
||||
|
||||
void HttpConfigFile::removePassword()
|
||||
{
|
||||
removeOldPassword();
|
||||
removeData(QString(), QLatin1String(passwdC));
|
||||
}
|
||||
|
||||
void HttpConfigFile::fixupOldPassword()
|
||||
{
|
||||
const QString old(QString::fromLatin1(oldPasswdC));
|
||||
|
||||
if (dataExists(QString(), old)) {
|
||||
setPassword(retrieveData(QString(), old).toString());
|
||||
}
|
||||
}
|
||||
|
||||
void HttpConfigFile::removeOldPassword()
|
||||
{
|
||||
removeData(QString(), QLatin1String(oldPasswdC));
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Krzesimir Nowak <krzesimir@endocode.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#ifndef MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
||||
#define MIRALL_CREDS_HTTP_CONFIG_FILE_H
|
||||
|
||||
#include "configfile.h"
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
class HttpConfigFile : public ConfigFile
|
||||
{
|
||||
public:
|
||||
QString user() const;
|
||||
void setUser(const QString& user);
|
||||
|
||||
QString password() const;
|
||||
void setPassword(const QString& password);
|
||||
bool passwordExists() const;
|
||||
void removePassword();
|
||||
void fixupOldPassword();
|
||||
QString certificatePath() const;
|
||||
void setCertificatePath(const QString& cPath);
|
||||
QString certificatePasswd() const;
|
||||
void setCertificatePasswd(const QString& cPasswd);
|
||||
|
||||
private:
|
||||
void removeOldPassword();
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#endif
|
||||
@@ -313,6 +313,9 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *job)
|
||||
|
||||
void HttpCredentials::invalidateToken()
|
||||
{
|
||||
if (! _password.isEmpty()) {
|
||||
_previousPassword = _password;
|
||||
}
|
||||
_password = QString();
|
||||
_ready = false;
|
||||
|
||||
@@ -333,6 +336,14 @@ void HttpCredentials::invalidateToken()
|
||||
job->setKey(kck);
|
||||
job->start();
|
||||
|
||||
// Also ensure the password is deleted from the deprecated place
|
||||
// otherwise we'd possibly read and use it again and again.
|
||||
DeletePasswordJob *job2 = new DeletePasswordJob(Theme::instance()->appName());
|
||||
// no job2->setSettings() call here, to make it use the deprecated location.
|
||||
job2->setInsecureFallback(true);
|
||||
job2->setKey(kck);
|
||||
job2->start();
|
||||
|
||||
_account->clearCookieJar();
|
||||
}
|
||||
|
||||
@@ -387,7 +398,7 @@ QString HttpCredentialsGui::queryPassword(bool *ok)
|
||||
QString str = QInputDialog::getText(0, tr("Enter Password"),
|
||||
tr("Please enter %1 password for user '%2':")
|
||||
.arg(Theme::instance()->appNameGUI(), _user),
|
||||
QLineEdit::Password, QString(), ok);
|
||||
QLineEdit::Password, _previousPassword, ok);
|
||||
return str;
|
||||
} else {
|
||||
return QString();
|
||||
|
||||
@@ -64,6 +64,7 @@ private Q_SLOTS:
|
||||
protected:
|
||||
QString _user;
|
||||
QString _password;
|
||||
QString _previousPassword;
|
||||
|
||||
private:
|
||||
QString _certificatePath;
|
||||
|
||||
@@ -268,8 +268,11 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap
|
||||
}
|
||||
|
||||
|
||||
csync_vio_file_stat_t *file_stat = propertyMapToFileStat(map);
|
||||
FileStatPointer file_stat(propertyMapToFileStat(map));
|
||||
file_stat->name = strdup(file.toUtf8());
|
||||
if (!file_stat->etag || strlen(file_stat->etag) == 0) {
|
||||
qDebug() << "WARNING: etag of" << file_stat->name << "is" << file_stat->etag << " This must not happen.";
|
||||
}
|
||||
//qDebug() << "!!!!" << file_stat << file_stat->name << file_stat->file_id << map.count();
|
||||
_results.append(file_stat);
|
||||
}
|
||||
@@ -282,6 +285,13 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file,QMap
|
||||
|
||||
void DiscoverySingleDirectoryJob::lsJobFinishedWithoutErrorSlot()
|
||||
{
|
||||
if (!_ignoredFirst) {
|
||||
// This is a sanity check, if we haven't _ignoredFirst then it means we never received any directoryListingIteratedSlot
|
||||
// which means somehow the server XML was bogus
|
||||
emit finishedWithError(ERRNO_WRONG_CONTENT, QLatin1String("Server error: PROPFIND reply is not XML formatted!"));
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
emit etagConcatenation(_etagConcatenation);
|
||||
emit finishedWithResult(_results);
|
||||
deleteLater();
|
||||
@@ -293,7 +303,7 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r)
|
||||
int httpCode = r->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
QString httpReason = r->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||
QString msg = r->errorString();
|
||||
int errnoCode = 0;
|
||||
int errnoCode = EIO; // Something went wrong
|
||||
qDebug() << Q_FUNC_INFO << r->errorString() << httpCode << r->error();
|
||||
if (httpCode != 0 && httpCode != 207) {
|
||||
errnoCode = get_errno_from_http_errcode(httpCode, httpReason);
|
||||
@@ -302,6 +312,8 @@ void DiscoverySingleDirectoryJob::lsJobFinishedWithErrorSlot(QNetworkReply *r)
|
||||
} else if (!contentType.contains("application/xml; charset=utf-8")) {
|
||||
msg = QLatin1String("Server error: PROPFIND reply is not XML formatted!");
|
||||
errnoCode = ERRNO_WRONG_CONTENT;
|
||||
} else {
|
||||
// Default keep at EIO, see above
|
||||
}
|
||||
|
||||
emit finishedWithError(errnoCode, msg);
|
||||
@@ -316,15 +328,6 @@ void DiscoveryMainThread::setupHooks(DiscoveryJob *discoveryJob, const QString &
|
||||
connect(discoveryJob, SIGNAL(doOpendirSignal(QString,DiscoveryDirectoryResult*)),
|
||||
this, SLOT(doOpendirSlot(QString,DiscoveryDirectoryResult*)),
|
||||
Qt::QueuedConnection);
|
||||
connect(discoveryJob, SIGNAL(doClosedirSignal(QString)),
|
||||
this, SLOT(doClosedirSlot(QString)),
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void DiscoveryMainThread::doClosedirSlot(QString path)
|
||||
{
|
||||
//qDebug() << Q_FUNC_INFO << "Invalidating" << path;
|
||||
deleteCacheEntry(path);
|
||||
}
|
||||
|
||||
// Coming from owncloud_opendir -> DiscoveryJob::vio_opendir_hook -> doOpendirSignal
|
||||
@@ -349,8 +352,8 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul
|
||||
|
||||
// Schedule the DiscoverySingleDirectoryJob
|
||||
_singleDirJob = new DiscoverySingleDirectoryJob(_account, fullPath, this);
|
||||
QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t *>)),
|
||||
this, SLOT(singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>)));
|
||||
QObject::connect(_singleDirJob, SIGNAL(finishedWithResult(const QList<FileStatPointer> &)),
|
||||
this, SLOT(singleDirectoryJobResultSlot(const QList<FileStatPointer> &)));
|
||||
QObject::connect(_singleDirJob, SIGNAL(finishedWithError(int,QString)),
|
||||
this, SLOT(singleDirectoryJobFinishedWithErrorSlot(int,QString)));
|
||||
QObject::connect(_singleDirJob, SIGNAL(firstDirectoryPermissions(QString)),
|
||||
@@ -361,7 +364,7 @@ void DiscoveryMainThread::doOpendirSlot(QString subPath, DiscoveryDirectoryResul
|
||||
}
|
||||
|
||||
|
||||
void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t *> result)
|
||||
void DiscoveryMainThread::singleDirectoryJobResultSlot(const QList<FileStatPointer> & result)
|
||||
{
|
||||
if (!_currentDiscoveryDirectoryResult) {
|
||||
return; // possibly aborted
|
||||
@@ -369,11 +372,9 @@ void DiscoveryMainThread::singleDirectoryJobResultSlot(QLinkedList<csync_vio_fil
|
||||
qDebug() << Q_FUNC_INFO << "Have" << result.count() << "results for " << _currentDiscoveryDirectoryResult->path;
|
||||
|
||||
|
||||
_directoryContents.insert(_currentDiscoveryDirectoryResult->path, result);
|
||||
|
||||
_currentDiscoveryDirectoryResult->list = result;
|
||||
_currentDiscoveryDirectoryResult->code = 0;
|
||||
_currentDiscoveryDirectoryResult->iterator = _currentDiscoveryDirectoryResult->list.begin();
|
||||
_currentDiscoveryDirectoryResult->listIndex = 0;
|
||||
_currentDiscoveryDirectoryResult = 0; // the sync thread owns it now
|
||||
|
||||
_discoveryJob->_vioMutex.lock();
|
||||
@@ -411,7 +412,7 @@ void DiscoveryMainThread::abort() {
|
||||
if (_singleDirJob) {
|
||||
_singleDirJob->disconnect(SIGNAL(finishedWithError(int,QString)), this);
|
||||
_singleDirJob->disconnect(SIGNAL(firstDirectoryPermissions(QString)), this);
|
||||
_singleDirJob->disconnect(SIGNAL(finishedWithResult(QLinkedList<csync_vio_file_stat_t*>)), this);
|
||||
_singleDirJob->disconnect(SIGNAL(finishedWithResult(const QList<FileStatPointer> &)), this);
|
||||
_singleDirJob->abort();
|
||||
}
|
||||
if (_currentDiscoveryDirectoryResult) {
|
||||
@@ -466,9 +467,8 @@ csync_vio_file_stat_t* DiscoveryJob::remote_vio_readdir_hook (csync_vio_handle_t
|
||||
DiscoveryJob *discoveryJob = static_cast<DiscoveryJob*>(userdata);
|
||||
if (discoveryJob) {
|
||||
DiscoveryDirectoryResult *directoryResult = static_cast<DiscoveryDirectoryResult*>(dhandle);
|
||||
if (directoryResult->iterator != directoryResult->list.end()) {
|
||||
csync_vio_file_stat_t *file_stat = *(directoryResult->iterator);
|
||||
directoryResult->iterator++;
|
||||
if (directoryResult->listIndex < directoryResult->list.size()) {
|
||||
csync_vio_file_stat_t *file_stat = directoryResult->list.at(directoryResult->listIndex++).data();
|
||||
// Make a copy, csync_update will delete the copy
|
||||
return csync_vio_file_stat_copy(file_stat);
|
||||
}
|
||||
@@ -484,7 +484,6 @@ void DiscoveryJob::remote_vio_closedir_hook (csync_vio_handle_t *dhandle, void
|
||||
QString path = directoryResult->path;
|
||||
qDebug() << Q_FUNC_INFO << discoveryJob << path;
|
||||
delete directoryResult; // just deletes the struct and the iterator, the data itself is owned by the SyncEngine/DiscoveryMainThread
|
||||
emit discoveryJob->doClosedirSignal(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,36 @@ class Account;
|
||||
* if the files are new, or changed.
|
||||
*/
|
||||
|
||||
class FileStatPointer {
|
||||
public:
|
||||
FileStatPointer(csync_vio_file_stat_t *stat)
|
||||
: _stat(stat)
|
||||
{ }
|
||||
FileStatPointer(const FileStatPointer &other)
|
||||
: _stat(csync_vio_file_stat_copy(other._stat))
|
||||
{ }
|
||||
~FileStatPointer() {
|
||||
csync_vio_file_stat_destroy(_stat);
|
||||
}
|
||||
FileStatPointer &operator=(const FileStatPointer &other) {
|
||||
csync_vio_file_stat_destroy(_stat);
|
||||
_stat = csync_vio_file_stat_copy(other._stat);
|
||||
return *this;
|
||||
}
|
||||
inline csync_vio_file_stat_t *data() const { return _stat; }
|
||||
inline csync_vio_file_stat_t *operator->() const { return _stat; }
|
||||
|
||||
private:
|
||||
csync_vio_file_stat_t *_stat;
|
||||
};
|
||||
|
||||
struct DiscoveryDirectoryResult {
|
||||
QString path;
|
||||
QString msg;
|
||||
int code;
|
||||
QLinkedList<csync_vio_file_stat_t*>::iterator iterator;
|
||||
QLinkedList<csync_vio_file_stat_t *> list;
|
||||
QList<FileStatPointer> list;
|
||||
int listIndex;
|
||||
DiscoveryDirectoryResult() : code(EIO), listIndex(0) { }
|
||||
};
|
||||
|
||||
// Run in the main thread, reporting to the DiscoveryJobMainThread object
|
||||
@@ -53,14 +77,14 @@ public:
|
||||
signals:
|
||||
void firstDirectoryPermissions(const QString &);
|
||||
void etagConcatenation(const QString &);
|
||||
void finishedWithResult(QLinkedList<csync_vio_file_stat_t*>);
|
||||
void finishedWithResult(const QList<FileStatPointer> &);
|
||||
void finishedWithError(int csyncErrnoCode, QString msg);
|
||||
private slots:
|
||||
void directoryListingIteratedSlot(QString,QMap<QString,QString>);
|
||||
void lsJobFinishedWithoutErrorSlot();
|
||||
void lsJobFinishedWithErrorSlot(QNetworkReply*);
|
||||
private:
|
||||
QLinkedList<csync_vio_file_stat_t*> _results;
|
||||
QList<FileStatPointer> _results;
|
||||
QString _subPath;
|
||||
QString _etagConcatenation;
|
||||
AccountPtr _account;
|
||||
@@ -73,11 +97,6 @@ class DiscoveryJob;
|
||||
class DiscoveryMainThread : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
// For non-recursive and recursive
|
||||
// If it is not in this map it needs to be requested
|
||||
QMap<QString, QLinkedList<csync_vio_file_stat_t*> > _directoryContents;
|
||||
|
||||
|
||||
QPointer<DiscoveryJob> _discoveryJob;
|
||||
QPointer<DiscoverySingleDirectoryJob> _singleDirJob;
|
||||
QString _pathPrefix;
|
||||
@@ -87,22 +106,6 @@ class DiscoveryMainThread : public QObject {
|
||||
public:
|
||||
DiscoveryMainThread(AccountPtr account) : QObject(), _account(account), _currentDiscoveryDirectoryResult(0) {
|
||||
|
||||
}
|
||||
void deleteCacheEntry(QString path) {
|
||||
//qDebug() << path << _directoryContents.value(path).count();
|
||||
foreach (csync_vio_file_stat_t* stat, _directoryContents.value(path)) {
|
||||
csync_vio_file_stat_destroy(stat);
|
||||
}
|
||||
_directoryContents.remove(path);
|
||||
}
|
||||
|
||||
~DiscoveryMainThread() {
|
||||
// Delete the _contents_ of the list-map explicitly:
|
||||
foreach (const QLinkedList<csync_vio_file_stat_t*> & list, _directoryContents) {
|
||||
foreach (csync_vio_file_stat_t* stat, list) {
|
||||
csync_vio_file_stat_destroy(stat);
|
||||
}
|
||||
}
|
||||
}
|
||||
void abort();
|
||||
|
||||
@@ -110,10 +113,9 @@ public:
|
||||
public slots:
|
||||
// From DiscoveryJob:
|
||||
void doOpendirSlot(QString url, DiscoveryDirectoryResult* );
|
||||
void doClosedirSlot(QString path);
|
||||
|
||||
// From Job:
|
||||
void singleDirectoryJobResultSlot(QLinkedList<csync_vio_file_stat_t*>);
|
||||
void singleDirectoryJobResultSlot(const QList<FileStatPointer> &);
|
||||
void singleDirectoryJobFinishedWithErrorSlot(int csyncErrnoCode, QString msg);
|
||||
void singleDirectoryJobFirstDirectoryPermissionsSlot(QString);
|
||||
signals:
|
||||
@@ -175,8 +177,6 @@ signals:
|
||||
|
||||
// After the discovery job has been woken up again (_vioWaitCondition)
|
||||
void doOpendirSignal(QString url, DiscoveryDirectoryResult*);
|
||||
// to tell the main thread to invalidate its directory data
|
||||
void doClosedirSignal(QString path);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -68,11 +68,12 @@ AbstractNetworkJob::AbstractNetworkJob(AccountPtr account, const QString &path,
|
||||
|
||||
void AbstractNetworkJob::setReply(QNetworkReply *reply)
|
||||
{
|
||||
if (_reply) {
|
||||
_reply->deleteLater();
|
||||
}
|
||||
reply->setProperty("doNotHandleAuth", true);
|
||||
if (reply)
|
||||
reply->setProperty("doNotHandleAuth", true);
|
||||
|
||||
QNetworkReply *old = _reply;
|
||||
_reply = reply;
|
||||
delete old;
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::setTimeout(qint64 msec)
|
||||
@@ -213,9 +214,7 @@ QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
|
||||
AbstractNetworkJob::~AbstractNetworkJob()
|
||||
{
|
||||
if (_reply) {
|
||||
_reply->deleteLater();
|
||||
}
|
||||
setReply(0);
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::start()
|
||||
@@ -224,7 +223,10 @@ void AbstractNetworkJob::start()
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
qDebug() << "!!!" << metaObject()->className() << "created for" << account()->url() << "querying" << path();
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
||||
qDebug() << "!!!" << metaObject()->className() << "created for" << displayUrl << "+" << path();
|
||||
}
|
||||
|
||||
void AbstractNetworkJob::slotTimeout()
|
||||
@@ -318,6 +320,131 @@ bool MkColJob::finished()
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
// supposed to read <D:collection> when pointing to <D:resourcetype><D:collection></D:resourcetype>..
|
||||
static QString readContentsAsString(QXmlStreamReader &reader) {
|
||||
QString result;
|
||||
int level = 0;
|
||||
do {
|
||||
QXmlStreamReader::TokenType type = reader.readNext();
|
||||
if (type == QXmlStreamReader::StartElement) {
|
||||
level++;
|
||||
result += "<" + reader.name().toString() + ">";
|
||||
} else if (type == QXmlStreamReader::Characters) {
|
||||
result += reader.text();
|
||||
} else if (type == QXmlStreamReader::EndElement) {
|
||||
level--;
|
||||
if (level < 0) {
|
||||
break;
|
||||
}
|
||||
result += "</" + reader.name().toString() + ">";
|
||||
}
|
||||
|
||||
} while (!reader.atEnd());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
LsColXMLParser::LsColXMLParser()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool LsColXMLParser::parse( const QByteArray& xml, QHash<QString, qint64> *sizes)
|
||||
{
|
||||
// Parse DAV response
|
||||
QXmlStreamReader reader(xml);
|
||||
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||
|
||||
QStringList folders;
|
||||
QString currentHref;
|
||||
QMap<QString, QString> currentTmpProperties;
|
||||
QMap<QString, QString> currentHttp200Properties;
|
||||
bool currentPropsHaveHttp200 = false;
|
||||
bool insidePropstat = false;
|
||||
bool insideProp = false;
|
||||
bool insideMultiStatus = false;
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
QXmlStreamReader::TokenType type = reader.readNext();
|
||||
QString name = reader.name().toString();
|
||||
// Start elements with DAV:
|
||||
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||
if (name == QLatin1String("href")) {
|
||||
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
|
||||
} else if (name == QLatin1String("response")) {
|
||||
} else if (name == QLatin1String("propstat")) {
|
||||
insidePropstat = true;
|
||||
} else if (name == QLatin1String("status") && insidePropstat) {
|
||||
QString httpStatus = reader.readElementText();
|
||||
if (httpStatus.startsWith("HTTP/1.1 200")) {
|
||||
currentPropsHaveHttp200 = true;
|
||||
} else {
|
||||
currentPropsHaveHttp200 = false;
|
||||
}
|
||||
} else if (name == QLatin1String("prop")) {
|
||||
insideProp = true;
|
||||
continue;
|
||||
} else if (name == QLatin1String("multistatus")) {
|
||||
insideMultiStatus = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) {
|
||||
// All those elements are properties
|
||||
QString propertyContent = readContentsAsString(reader);
|
||||
if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) {
|
||||
folders.append(currentHref);
|
||||
} else if (name == QLatin1String("quota-used-bytes")) {
|
||||
bool ok = false;
|
||||
auto s = propertyContent.toLongLong(&ok);
|
||||
if (ok && sizes) {
|
||||
sizes->insert(currentHref, s);
|
||||
}
|
||||
}
|
||||
currentTmpProperties.insert(reader.name().toString(), propertyContent);
|
||||
}
|
||||
|
||||
// End elements with DAV:
|
||||
if (type == QXmlStreamReader::EndElement) {
|
||||
if (reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||
if (reader.name() == "response") {
|
||||
if (currentHref.endsWith('/')) {
|
||||
currentHref.chop(1);
|
||||
}
|
||||
emit directoryListingIterated(currentHref, currentHttp200Properties);
|
||||
currentHref.clear();
|
||||
currentHttp200Properties.clear();
|
||||
} else if (reader.name() == "propstat") {
|
||||
insidePropstat = false;
|
||||
if (currentPropsHaveHttp200) {
|
||||
currentHttp200Properties = QMap<QString,QString>(currentTmpProperties);
|
||||
}
|
||||
currentTmpProperties.clear();
|
||||
currentPropsHaveHttp200 = false;
|
||||
} else if (reader.name() == "prop") {
|
||||
insideProp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.hasError()) {
|
||||
// XML Parser error? Whatever had been emitted before will come as directoryListingIterated
|
||||
qDebug() << "ERROR" << reader.errorString() << xml;
|
||||
return false;
|
||||
} else if (!insideMultiStatus) {
|
||||
qDebug() << "ERROR no WebDAV response?" << xml;
|
||||
return false;
|
||||
} else {
|
||||
emit directoryListingSubfolders(folders);
|
||||
emit finishedWithoutError();
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*********************************************************************************************/
|
||||
|
||||
LsColJob::LsColJob(AccountPtr account, const QString &path, QObject *parent)
|
||||
@@ -375,117 +502,36 @@ void LsColJob::start()
|
||||
AbstractNetworkJob::start();
|
||||
}
|
||||
|
||||
// supposed to read <D:collection> when pointing to <D:resourcetype><D:collection></D:resourcetype>..
|
||||
static QString readContentsAsString(QXmlStreamReader &reader) {
|
||||
QString result;
|
||||
int level = 0;
|
||||
do {
|
||||
QXmlStreamReader::TokenType type = reader.readNext();
|
||||
if (type == QXmlStreamReader::StartElement) {
|
||||
level++;
|
||||
result += "<" + reader.name().toString() + ">";
|
||||
} else if (type == QXmlStreamReader::Characters) {
|
||||
result += reader.text();
|
||||
} else if (type == QXmlStreamReader::EndElement) {
|
||||
level--;
|
||||
if (level < 0) {
|
||||
break;
|
||||
}
|
||||
result += "</" + reader.name().toString() + ">";
|
||||
}
|
||||
|
||||
} while (!reader.atEnd());
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: Instead of doing all in this slot, we should iteratively parse in readyRead(). This
|
||||
// would allow us to be more asynchronous in processing while data is coming from the network,
|
||||
// not in all in one big blobb at the end.
|
||||
bool LsColJob::finished()
|
||||
{
|
||||
QString contentType = reply()->header(QNetworkRequest::ContentTypeHeader).toString();
|
||||
int httpCode = reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
if (httpCode == 207 && contentType.contains("application/xml; charset=utf-8")) {
|
||||
// Parse DAV response
|
||||
QByteArray xml = reply()->readAll();
|
||||
QXmlStreamReader reader(xml);
|
||||
reader.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration("d", "DAV:"));
|
||||
LsColXMLParser parser;
|
||||
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||
this, SIGNAL(directoryListingSubfolders(const QStringList&)) );
|
||||
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||
connect( &parser, SIGNAL(finishedWithError(QNetworkReply *)),
|
||||
this, SIGNAL(finishedWithError(QNetworkReply *)) );
|
||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||
this, SIGNAL(finishedWithoutError()) );
|
||||
|
||||
QStringList folders;
|
||||
QString currentHref;
|
||||
QMap<QString, QString> currentTmpProperties;
|
||||
QMap<QString, QString> currentHttp200Properties;
|
||||
bool currentPropsHaveHttp200 = false;
|
||||
bool insidePropstat = false;
|
||||
bool insideProp = false;
|
||||
|
||||
while (!reader.atEnd()) {
|
||||
QXmlStreamReader::TokenType type = reader.readNext();
|
||||
QString name = reader.name().toString();
|
||||
// Start elements with DAV:
|
||||
if (type == QXmlStreamReader::StartElement && reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||
if (name == QLatin1String("href")) {
|
||||
currentHref = QUrl::fromPercentEncoding(reader.readElementText().toUtf8());
|
||||
} else if (name == QLatin1String("response")) {
|
||||
} else if (name == QLatin1String("propstat")) {
|
||||
insidePropstat = true;
|
||||
} else if (name == QLatin1String("status") && insidePropstat) {
|
||||
QString httpStatus = reader.readElementText();
|
||||
if (httpStatus.startsWith("HTTP/1.1 200")) {
|
||||
currentPropsHaveHttp200 = true;
|
||||
} else {
|
||||
currentPropsHaveHttp200 = false;
|
||||
}
|
||||
} else if (name == QLatin1String("prop")) {
|
||||
insideProp = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == QXmlStreamReader::StartElement && insidePropstat && insideProp) {
|
||||
// All those elements are properties
|
||||
QString propertyContent = readContentsAsString(reader);
|
||||
if (name == QLatin1String("resourcetype") && propertyContent.contains("collection")) {
|
||||
folders.append(currentHref);
|
||||
} else if (name == QLatin1String("quota-used-bytes")) {
|
||||
bool ok = false;
|
||||
auto s = propertyContent.toLongLong(&ok);
|
||||
if (ok) {
|
||||
_sizes[currentHref] = s;
|
||||
}
|
||||
}
|
||||
currentTmpProperties.insert(reader.name().toString(), propertyContent);
|
||||
}
|
||||
|
||||
// End elements with DAV:
|
||||
if (type == QXmlStreamReader::EndElement) {
|
||||
if (reader.namespaceUri() == QLatin1String("DAV:")) {
|
||||
if (reader.name() == "response") {
|
||||
if (currentHref.endsWith('/')) {
|
||||
currentHref.chop(1);
|
||||
}
|
||||
emit directoryListingIterated(currentHref, currentHttp200Properties);
|
||||
currentHref.clear();
|
||||
currentHttp200Properties.clear();
|
||||
} else if (reader.name() == "propstat") {
|
||||
insidePropstat = false;
|
||||
if (currentPropsHaveHttp200) {
|
||||
currentHttp200Properties = QMap<QString,QString>(currentTmpProperties);
|
||||
}
|
||||
currentTmpProperties.clear();
|
||||
currentPropsHaveHttp200 = false;
|
||||
} else if (reader.name() == "prop") {
|
||||
insideProp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !parser.parse( reply()->readAll(), &_sizes ) ) {
|
||||
// XML parse error
|
||||
emit finishedWithError(reply());
|
||||
}
|
||||
emit directoryListingSubfolders(folders);
|
||||
emit finishedWithoutError();
|
||||
} else if (httpCode == 207) {
|
||||
// wrong content type
|
||||
emit finishedWithError(reply());
|
||||
} else {
|
||||
// wrong HTTP code
|
||||
// wrong HTTP code or any other network error
|
||||
emit finishedWithError(reply());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -648,8 +694,9 @@ bool PropfindJob::finished()
|
||||
if (type == QXmlStreamReader::StartElement) {
|
||||
if (!curElement.isEmpty() && curElement.top() == QLatin1String("prop")) {
|
||||
items.insert(reader.name().toString(), reader.readElementText());
|
||||
} else {
|
||||
curElement.push(reader.name().toString());
|
||||
}
|
||||
curElement.push(reader.name().toString());
|
||||
}
|
||||
if (type == QXmlStreamReader::EndElement) {
|
||||
if(curElement.top() == reader.name()) {
|
||||
|
||||
@@ -94,6 +94,9 @@ protected:
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is recieved
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
// GET requests that don't set up any HTTP body or other flags.
|
||||
bool _followRedirects;
|
||||
|
||||
private slots:
|
||||
@@ -129,6 +132,21 @@ private slots:
|
||||
/**
|
||||
* @brief The LsColJob class
|
||||
*/
|
||||
class OWNCLOUDSYNC_EXPORT LsColXMLParser : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LsColXMLParser();
|
||||
|
||||
bool parse(const QByteArray &xml, QHash<QString, qint64> *sizes);
|
||||
|
||||
signals:
|
||||
void directoryListingSubfolders(const QStringList &items);
|
||||
void directoryListingIterated(const QString &name, const QMap<QString,QString> &properties);
|
||||
void finishedWithError(QNetworkReply *reply);
|
||||
void finishedWithoutError();
|
||||
|
||||
};
|
||||
|
||||
class OWNCLOUDSYNC_EXPORT LsColJob : public AbstractNetworkJob {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#endif
|
||||
#include "configfile.h"
|
||||
#include "utility.h"
|
||||
#include "account.h"
|
||||
#include <json.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -40,9 +41,13 @@
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QTimerEvent>
|
||||
#include <QDebug>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
OwncloudPropagator::~OwncloudPropagator()
|
||||
{}
|
||||
|
||||
/* The maximum number of active job in parallel */
|
||||
int OwncloudPropagator::maximumActiveJob()
|
||||
{
|
||||
@@ -631,6 +636,9 @@ void PropagateDirectory::finalize()
|
||||
emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
|
||||
}
|
||||
|
||||
CleanupPollsJob::~CleanupPollsJob()
|
||||
{}
|
||||
|
||||
void CleanupPollsJob::start()
|
||||
{
|
||||
if (_pollInfos.empty()) {
|
||||
|
||||
@@ -270,6 +270,8 @@ public:
|
||||
, _account(account)
|
||||
{ }
|
||||
|
||||
~OwncloudPropagator();
|
||||
|
||||
void start(const SyncFileItemVector &_syncedItems);
|
||||
|
||||
QAtomicInt _downloadLimit;
|
||||
@@ -359,6 +361,8 @@ public:
|
||||
SyncJournalDb *journal, const QString &localPath, QObject* parent = 0)
|
||||
: QObject(parent), _pollInfos(pollInfos), _account(account), _journal(journal), _localPath(localPath) {}
|
||||
|
||||
~CleanupPollsJob();
|
||||
|
||||
void start();
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <QNetworkReply>
|
||||
#include <QDebug>
|
||||
#include "syncfileitem.h"
|
||||
|
||||
namespace OCC {
|
||||
@@ -33,9 +34,14 @@ inline QByteArray parseEtag(const char *header) {
|
||||
|
||||
inline QByteArray getEtagFromReply(QNetworkReply *reply)
|
||||
{
|
||||
QByteArray ret = parseEtag(reply->rawHeader("OC-ETag"));
|
||||
QByteArray ocEtag = parseEtag(reply->rawHeader("OC-ETag"));
|
||||
QByteArray etag = parseEtag(reply->rawHeader("ETag"));
|
||||
QByteArray ret = ocEtag;
|
||||
if (ret.isEmpty()) {
|
||||
ret = parseEtag(reply->rawHeader("ETag"));
|
||||
ret = etag;
|
||||
}
|
||||
if (ocEtag.length() > 0 && ocEtag != etag) {
|
||||
qDebug() << "Quite peculiar, we have an etag != OC-Etag [no problem!]" << etag << ocEtag;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <cmath>
|
||||
|
||||
namespace OCC {
|
||||
@@ -368,6 +369,7 @@ void PropagateDownloadFileQNAM::start()
|
||||
_job->start();
|
||||
}
|
||||
|
||||
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
|
||||
void PropagateDownloadFileQNAM::slotGetFinished()
|
||||
{
|
||||
_propagator->_activeJobs--;
|
||||
@@ -407,7 +409,18 @@ void PropagateDownloadFileQNAM::slotGetFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
// This gives a custom QNAM (by the user of libowncloudsync) to abort() a QNetworkReply in its metaDataChanged() slot and
|
||||
// set a custom error string to make this a soft error. In contrast to the default hard error this won't bring down
|
||||
// the whole sync and allows for a custom error message.
|
||||
QNetworkReply *reply = job->reply();
|
||||
if (err == QNetworkReply::OperationCanceledError && reply->property(owncloudCustomSoftErrorStringC).isValid()) {
|
||||
job->setErrorString(reply->property(owncloudCustomSoftErrorStringC).toString());
|
||||
job->setErrorStatus(SyncFileItem::SoftError);
|
||||
}
|
||||
|
||||
SyncFileItem::Status status = job->errorStatus();
|
||||
|
||||
|
||||
if (status == SyncFileItem::NoStatus) {
|
||||
status = classifyError(err, _item._httpErrorCode);
|
||||
}
|
||||
@@ -506,10 +519,14 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
||||
_tmpFile.setPermissions(existingFile.permissions());
|
||||
}
|
||||
|
||||
FileSystem::setFileHidden(_tmpFile.fileName(), false);
|
||||
FileSystem::setModTime(_tmpFile.fileName(), _item._modtime);
|
||||
// We need to fetch the time again because some file system such as FAT have a less than a second
|
||||
// Accuracy, and we really need the time from the file system. (#3103)
|
||||
_item._modtime = FileSystem::getModTime(_tmpFile.fileName());
|
||||
|
||||
QString error;
|
||||
_propagator->addTouchedFile(fn);
|
||||
FileSystem::setFileHidden(_tmpFile.fileName(), false);
|
||||
if (!FileSystem::renameReplace(_tmpFile.fileName(), fn, &error)) {
|
||||
qDebug() << Q_FUNC_INFO << QString("Rename failed: %1 => %2").arg(_tmpFile.fileName()).arg(fn);
|
||||
// If we moved away the original file due to a conflict but can't
|
||||
@@ -530,7 +547,6 @@ void PropagateDownloadFileQNAM::downloadFinished()
|
||||
|
||||
// Maybe we downloaded a newer version of the file than we thought we would...
|
||||
// Get up to date information for the journal.
|
||||
FileSystem::setModTime(fn, _item._modtime);
|
||||
_item._size = FileSystem::getSize(fn);
|
||||
|
||||
_propagator->_journal->setFileRecord(SyncJournalFileRecord(_item, fn));
|
||||
|
||||
@@ -78,8 +78,10 @@ public:
|
||||
qint64 currentDownloadPosition();
|
||||
|
||||
QString errorString() const;
|
||||
void setErrorString(const QString& s) { _errorString = s; }
|
||||
|
||||
SyncFileItem::Status errorStatus() { return _errorStatus; }
|
||||
void setErrorStatus(const SyncFileItem::Status & s) { _errorStatus = s; }
|
||||
|
||||
virtual void slotTimeout() Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -85,9 +85,10 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
<< (_job->reply()->error() == QNetworkReply::NoError ? QLatin1String("") : _job->reply()->errorString());
|
||||
|
||||
QNetworkReply::NetworkError err = _job->reply()->error();
|
||||
_item._httpErrorCode = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
const int httpStatus = _job->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
_item._httpErrorCode = httpStatus;
|
||||
|
||||
if (err != QNetworkReply::NoError) {
|
||||
if (err != QNetworkReply::NoError && err != QNetworkReply::ContentNotFoundError) {
|
||||
|
||||
if( checkForProblemsWithShared(_item._httpErrorCode,
|
||||
tr("The file has been removed from a read only share. It was restored.")) ) {
|
||||
@@ -102,7 +103,11 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
_item._requestDuration = _job->duration();
|
||||
_item._responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
if (_item._httpErrorCode != 204 ) {
|
||||
// A 404 reply is also considered a success here: We want to make sure
|
||||
// a file is gone from the server. It not being there in the first place
|
||||
// is ok. This will happen for files that are in the DB but not on
|
||||
// the server or the local file system.
|
||||
if (httpStatus != 204 && httpStatus != 404) {
|
||||
// Normaly we expect "204 No Content"
|
||||
// If it is not the case, it might be because of a proxy or gateway intercepting the request, so we must
|
||||
// throw an error.
|
||||
|
||||
@@ -64,6 +64,12 @@ static qint64 chunkSize() {
|
||||
return chunkSize;
|
||||
}
|
||||
|
||||
PUTFileJob::~PUTFileJob()
|
||||
{
|
||||
// Make sure that we destroy the QNetworkReply before our _device of which it keeps an internal pointer.
|
||||
setReply(0);
|
||||
}
|
||||
|
||||
void PUTFileJob::start() {
|
||||
QNetworkRequest req;
|
||||
for(QMap<QByteArray, QByteArray>::const_iterator it = _headers.begin(); it != _headers.end(); ++it) {
|
||||
@@ -518,8 +524,8 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
// But if the upload is ongoing, because not all chunks were uploaded
|
||||
// yet, the upload can be stopped and an error can be displayed, because
|
||||
// the server hasn't registered the new file yet.
|
||||
bool finished = job->reply()->hasRawHeader("ETag")
|
||||
|| job->reply()->hasRawHeader("OC-ETag");
|
||||
QByteArray etag = getEtagFromReply(job->reply());
|
||||
bool finished = etag.length() > 0;
|
||||
|
||||
// Check if the file still exists
|
||||
const QString fullFilePath(_propagator->getFilePath(_item._file));
|
||||
@@ -589,7 +595,6 @@ void PropagateUploadFileQNAM::slotPutFinished()
|
||||
_item._fileId = fid;
|
||||
}
|
||||
|
||||
QByteArray etag = getEtagFromReply(job->reply());
|
||||
_item._etag = etag;
|
||||
|
||||
_item._responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
explicit PUTFileJob(AccountPtr account, const QString& path, QIODevice *device,
|
||||
const QMap<QByteArray, QByteArray> &headers, int chunk, QObject* parent = 0)
|
||||
: AbstractNetworkJob(account, path, parent), _device(device), _headers(headers), _chunk(chunk) {}
|
||||
~PUTFileJob();
|
||||
|
||||
int _chunk;
|
||||
|
||||
|
||||
@@ -384,6 +384,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
case CSYNC_STATUS_STORAGE_UNAVAILABLE:
|
||||
item._errorString = QLatin1String("Directory temporarily not available on server.");
|
||||
item._status = SyncFileItem::SoftError;
|
||||
_temporarilyUnavailablePaths.insert(item._file);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT("Non handled error-status");
|
||||
@@ -484,9 +485,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
}
|
||||
|
||||
item._direction = dir;
|
||||
// check for blacklisting of this item.
|
||||
// if the item is on blacklist, the instruction was set to IGNORE
|
||||
checkErrorBlacklisting( &item );
|
||||
if (instruction != CSYNC_INSTRUCTION_NONE) {
|
||||
// check for blacklisting of this item.
|
||||
// if the item is on blacklist, the instruction was set to ERROR
|
||||
checkErrorBlacklisting( &item );
|
||||
}
|
||||
|
||||
if (!item._isDirectory) {
|
||||
_progressInfo._totalFileCount++;
|
||||
@@ -605,11 +608,15 @@ void SyncEngine::startSync()
|
||||
if (fileRecordCount >= 1 && isUpdateFrom_1_5) {
|
||||
qDebug() << "detected update from 1.5" << fileRecordCount << isUpdateFrom_1_5;
|
||||
// Disable the read from DB to be sure to re-read all the fileid and etags.
|
||||
csync_set_read_from_db(_csync_ctx, false);
|
||||
_csync_ctx->read_remote_from_db = false;
|
||||
} else {
|
||||
csync_set_read_from_db(_csync_ctx, true);
|
||||
_csync_ctx->read_remote_from_db = true;
|
||||
}
|
||||
|
||||
// This tells csync to never read from the DB if it is empty
|
||||
// thereby speeding up the initial discovery significantly.
|
||||
_csync_ctx->db_is_empty = (fileRecordCount == 0);
|
||||
|
||||
bool usingSelectiveSync = (!_selectiveSyncBlackList.isEmpty());
|
||||
qDebug() << (usingSelectiveSync ? "====Using Selective Sync" : "====NOT Using Selective Sync");
|
||||
if (fileRecordCount >= 0 && fileRecordCount < 50 && !usingSelectiveSync) {
|
||||
@@ -690,7 +697,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
return;
|
||||
}
|
||||
|
||||
_stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
|
||||
qDebug() << "<<#### Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Reconcile Finished"));
|
||||
|
||||
_progressInfo = Progress::Info();
|
||||
|
||||
@@ -698,6 +705,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
_hasRemoveFile = false;
|
||||
bool walkOk = true;
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
|
||||
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
|
||||
qDebug() << "Error in local treewalk.";
|
||||
@@ -791,6 +799,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
emit(started());
|
||||
|
||||
_propagator->start(_syncedItems);
|
||||
|
||||
qDebug() << "<<#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Post-Reconcile Finished"));
|
||||
}
|
||||
|
||||
void SyncEngine::slotCleanPollsJobAborted(const QString &error)
|
||||
@@ -859,7 +869,7 @@ void SyncEngine::slotFinished()
|
||||
_anotherSyncNeeded = _anotherSyncNeeded || _propagator->_anotherSyncNeeded;
|
||||
|
||||
// emit the treewalk results.
|
||||
if( ! _journal->postSyncCleanup( _seenFiles ) ) {
|
||||
if( ! _journal->postSyncCleanup( _seenFiles, _temporarilyUnavailablePaths ) ) {
|
||||
qDebug() << "Cleaning of synced ";
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,21 @@ private:
|
||||
QPointer<DiscoveryMainThread> _discoveryMainThread;
|
||||
QSharedPointer <OwncloudPropagator> _propagator;
|
||||
QString _lastDeleted; // if the last item was a path and it has been deleted
|
||||
|
||||
// After a sync, only the syncdb entries whose filenames appear in this
|
||||
// set will be kept. See _temporarilyUnavailablePaths.
|
||||
QSet<QString> _seenFiles;
|
||||
|
||||
// Some paths might be temporarily unavailable on the server, for
|
||||
// example due to 503 Storage not available. Deleting information
|
||||
// about the files from the database in these cases would lead to
|
||||
// incorrect synchronization.
|
||||
// Therefore all syncdb entries whose filename starts with one of
|
||||
// the paths in this set will be kept.
|
||||
// The specific case that fails otherwise is deleting a local file
|
||||
// while the remote says storage not available.
|
||||
QSet<QString> _temporarilyUnavailablePaths;
|
||||
|
||||
QThread _thread;
|
||||
|
||||
Progress::Info _progressInfo;
|
||||
|
||||
@@ -698,7 +698,8 @@ SyncJournalFileRecord SyncJournalDb::getFileRecord( const QString& filename )
|
||||
return rec;
|
||||
}
|
||||
|
||||
bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
||||
bool SyncJournalDb::postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
||||
const QSet<QString>& prefixesToKeep)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
@@ -719,8 +720,16 @@ bool SyncJournalDb::postSyncCleanup(const QSet<QString> &items )
|
||||
|
||||
while(query.next()) {
|
||||
const QString file = query.stringValue(1);
|
||||
bool contained = items.contains(file);
|
||||
if( !contained ) {
|
||||
bool keep = filepathsToKeep.contains(file);
|
||||
if( !keep ) {
|
||||
foreach( const QString & prefix, prefixesToKeep ) {
|
||||
if( file.startsWith(prefix) ) {
|
||||
keep = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( !keep ) {
|
||||
superfluousItems.append(query.stringValue(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,8 @@ public:
|
||||
*/
|
||||
void avoidReadFromDbOnNextSync(const QString& fileName);
|
||||
|
||||
bool postSyncCleanup( const QSet<QString>& items );
|
||||
bool postSyncCleanup(const QSet<QString>& filepathsToKeep,
|
||||
const QSet<QString>& prefixesToKeep);
|
||||
|
||||
/* Because sqlite transactions is really slow, we encapsulate everything in big transactions
|
||||
* Commit will actually commit the transaction and create a new one.
|
||||
|
||||
@@ -122,11 +122,14 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
|
||||
flavor = QLatin1String("colored");
|
||||
}
|
||||
|
||||
QIcon icon;
|
||||
if( QIcon::hasThemeIcon( name )) {
|
||||
// use from theme
|
||||
icon = QIcon::fromTheme( name );
|
||||
} else {
|
||||
return QIcon::fromTheme( name );
|
||||
}
|
||||
|
||||
QString key = name + "," + flavor;
|
||||
QIcon & cached = _iconCache[key];
|
||||
if (cached.isNull()) {
|
||||
QList<int> sizes;
|
||||
sizes <<16 << 22 << 32 << 48 << 64 << 128 << 256;
|
||||
foreach (int size, sizes) {
|
||||
@@ -140,19 +143,20 @@ QIcon Theme::themeIcon( const QString& name, bool sysTray ) const
|
||||
p.setPen(QColor("#dfdbd2"));
|
||||
p.drawPixmap(px.rect(), mask, mask.rect());
|
||||
}
|
||||
icon.addPixmap(px);
|
||||
cached.addPixmap(px);
|
||||
}
|
||||
}
|
||||
if (icon.isNull()) {
|
||||
if (cached.isNull()) {
|
||||
foreach (int size, sizes) {
|
||||
QString pixmapName = QString::fromLatin1(":/client/resources/%1-%2.png").arg(name).arg(size);
|
||||
if (QFile::exists(pixmapName)) {
|
||||
icon.addFile(pixmapName);
|
||||
cached.addFile(pixmapName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return icon;
|
||||
|
||||
return cached;
|
||||
}
|
||||
|
||||
QString Theme::hidpiFileName(const QString &fileName, QPaintDevice *dev)
|
||||
|
||||
@@ -196,7 +196,9 @@ public:
|
||||
virtual bool wizardSelectiveSyncDefaultNothing() const;
|
||||
|
||||
protected:
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
QIcon themeIcon(const QString& name, bool sysTray = false) const;
|
||||
#endif
|
||||
Theme();
|
||||
|
||||
signals:
|
||||
@@ -208,7 +210,9 @@ private:
|
||||
|
||||
static Theme* _instance;
|
||||
bool _mono;
|
||||
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
mutable QHash<QString, QIcon> _iconCache;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -32,5 +32,5 @@ owncloud_add_test(SyncJournalDB "")
|
||||
owncloud_add_test(SyncFileItem "")
|
||||
owncloud_add_test(ConcatUrl "")
|
||||
|
||||
|
||||
owncloud_add_test(XmlParse "")
|
||||
|
||||
|
||||
245
test/testxmlparse.h
Normal file
245
test/testxmlparse.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
* */
|
||||
|
||||
#ifndef MIRALL_TESTXMLPARSE_H
|
||||
#define MIRALL_TESTXMLPARSE_H
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
#include "networkjobs.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
class TestXmlParse : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
bool _success;
|
||||
QStringList _subdirs;
|
||||
QStringList _items;
|
||||
|
||||
public slots:
|
||||
void slotDirectoryListingSubFolders(const QStringList& list)
|
||||
{
|
||||
qDebug() << "subfolders: " << list;
|
||||
_subdirs.append(list);
|
||||
}
|
||||
|
||||
void slotDirectoryListingIterated(const QString& item, const QMap<QString,QString>& )
|
||||
{
|
||||
qDebug() << " item: " << item;
|
||||
_items.append(item);
|
||||
}
|
||||
|
||||
void slotFinishedSuccessfully()
|
||||
{
|
||||
_success = true;
|
||||
}
|
||||
|
||||
private slots:
|
||||
void init() {
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
_success = false;
|
||||
_subdirs.clear();
|
||||
_items.clear();
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
}
|
||||
|
||||
|
||||
void testParser1() {
|
||||
const QByteArray testXml = "<?xml version='1.0' encoding='utf-8'?>"
|
||||
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||
"<d:response>"
|
||||
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||
"<oc:size>121780</oc:size>"
|
||||
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||
"<d:resourcetype>"
|
||||
"<d:collection/>"
|
||||
"</d:resourcetype>"
|
||||
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||
"</d:propstat>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<d:getcontentlength/>"
|
||||
"<oc:downloadURL/>"
|
||||
"<oc:dDC/>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||
"</d:propstat>"
|
||||
"</d:response>"
|
||||
"<d:response>"
|
||||
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||
"<oc:permissions>RDNVW</oc:permissions>"
|
||||
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||
"<d:resourcetype/>"
|
||||
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||
"</d:propstat>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:downloadURL/>"
|
||||
"<oc:dDC/>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||
"</d:propstat>"
|
||||
"</d:response>"
|
||||
"</d:multistatus>";
|
||||
|
||||
|
||||
LsColXMLParser parser;
|
||||
|
||||
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||
this, SLOT(slotFinishedSuccessfully()) );
|
||||
|
||||
QHash <QString, qint64> sizes;
|
||||
QVERIFY(parser.parse( testXml, &sizes ));
|
||||
|
||||
QVERIFY(_success);
|
||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||
|
||||
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder/quitte.pdf"));
|
||||
QVERIFY(_items.contains("/oc/remote.php/webdav/sharefolder"));
|
||||
QVERIFY(_items.size() == 2 );
|
||||
|
||||
QVERIFY(_subdirs.contains("/oc/remote.php/webdav/sharefolder/"));
|
||||
QVERIFY(_subdirs.size() == 1);
|
||||
}
|
||||
|
||||
void testParserBrokenXml() {
|
||||
const QByteArray testXml = "X<?xml version='1.0' encoding='utf-8'?>"
|
||||
"<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\">"
|
||||
"<d:response>"
|
||||
"<d:href>/oc/remote.php/webdav/sharefolder/</d:href>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:id>00004213ocobzus5kn6s</oc:id>"
|
||||
"<oc:permissions>RDNVCK</oc:permissions>"
|
||||
"<oc:size>121780</oc:size>"
|
||||
"<d:getetag>\"5527beb0400b0\"</d:getetag>"
|
||||
"<d:resourcetype>"
|
||||
"<d:collection/>"
|
||||
"</d:resourcetype>"
|
||||
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||
"</d:propstat>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<d:getcontentlength/>"
|
||||
"<oc:downloadURL/>"
|
||||
"<oc:dDC/>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||
"</d:propstat>"
|
||||
"</d:response>"
|
||||
"<d:response>"
|
||||
"<d:href>/oc/remote.php/webdav/sharefolder/quitte.pdf</d:href>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:id>00004215ocobzus5kn6s</oc:id>"
|
||||
"<oc:permissions>RDNVW</oc:permissions>"
|
||||
"<d:getetag>\"2fa2f0d9ed49ea0c3e409d49e652dea0\"</d:getetag>"
|
||||
"<d:resourcetype/>"
|
||||
"<d:getlastmodified>Fri, 06 Feb 2015 13:49:55 GMT</d:getlastmodified>"
|
||||
"<d:getcontentlength>121780</d:getcontentlength>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 200 OK</d:status>"
|
||||
"</d:propstat>"
|
||||
"<d:propstat>"
|
||||
"<d:prop>"
|
||||
"<oc:downloadURL/>"
|
||||
"<oc:dDC/>"
|
||||
"</d:prop>"
|
||||
"<d:status>HTTP/1.1 404 Not Found</d:status>"
|
||||
"</d:propstat>"
|
||||
"</d:response>"
|
||||
"</d:multistatus>";
|
||||
|
||||
|
||||
LsColXMLParser parser;
|
||||
|
||||
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||
this, SLOT(slotFinishedSuccessfully()) );
|
||||
|
||||
QHash <QString, qint64> sizes;
|
||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||
|
||||
QVERIFY(!_success);
|
||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||
|
||||
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||
|
||||
QVERIFY(_subdirs.size() == 0);
|
||||
}
|
||||
|
||||
void testParserEmptyXmlNoDav() {
|
||||
const QByteArray testXml = "<html><body>I am under construction</body></html>";
|
||||
|
||||
LsColXMLParser parser;
|
||||
|
||||
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||
this, SLOT(slotFinishedSuccessfully()) );
|
||||
|
||||
QHash <QString, qint64> sizes;
|
||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||
|
||||
QVERIFY(!_success);
|
||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||
|
||||
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||
QVERIFY(_subdirs.size() == 0);
|
||||
}
|
||||
|
||||
void testParserEmptyXml() {
|
||||
const QByteArray testXml = "";
|
||||
|
||||
LsColXMLParser parser;
|
||||
|
||||
connect( &parser, SIGNAL(directoryListingSubfolders(const QStringList&)),
|
||||
this, SLOT(slotDirectoryListingSubFolders(const QStringList&)) );
|
||||
connect( &parser, SIGNAL(directoryListingIterated(const QString&, const QMap<QString,QString>&)),
|
||||
this, SLOT(slotDirectoryListingIterated(const QString&, const QMap<QString,QString>&)) );
|
||||
connect( &parser, SIGNAL(finishedWithoutError()),
|
||||
this, SLOT(slotFinishedSuccessfully()) );
|
||||
|
||||
QHash <QString, qint64> sizes;
|
||||
QVERIFY(false == parser.parse( testXml, &sizes )); // verify false
|
||||
|
||||
QVERIFY(!_success);
|
||||
QVERIFY(sizes.size() == 0 ); // No quota info in the XML
|
||||
|
||||
QVERIFY(_items.size() == 0 ); // FIXME: We should change the parser to not emit during parsing but at the end
|
||||
QVERIFY(_subdirs.size() == 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,6 +22,7 @@ trans.pt_BR = client_pt_BR.ts
|
||||
trans.ru = client_ru.ts
|
||||
trans.sl = client_sl.ts
|
||||
trans.sv = client_sv.ts
|
||||
trans.sr = client_sr.ts
|
||||
trans.tr = client_tr.ts
|
||||
trans.uk = client_uk.ts
|
||||
trans.zh_TW = client_zh_TW.ts
|
||||
|
||||
@@ -235,12 +235,12 @@ Total time left %5</source>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="17"/>
|
||||
<source>SSL client certificate authentication</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Επικύρωση πιστοποιητικού χρήστη SSL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="23"/>
|
||||
<source>This server probably requires a SSL client certificate.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διακομιστής πιθανόν απαιτεί πιστοποιητικό χρήστη SSL </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="35"/>
|
||||
@@ -250,7 +250,7 @@ Total time left %5</source>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="51"/>
|
||||
<source>Browse...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Περιήγηση...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="60"/>
|
||||
@@ -669,7 +669,7 @@ Are you sure you want to perform this operation?</source>
|
||||
<message>
|
||||
<location filename="../src/gui/folderwizard.cpp" line="444"/>
|
||||
<source>Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Επιλέξτε Τι θα Συγχρονιστεί: Μπορείτε προαιρετικά να καταργήστε την επιλογή υποφακέλων που δεν επιθυμείτε να συγχρονίσετε.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -734,7 +734,7 @@ Are you sure you want to perform this operation?</source>
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="47"/>
|
||||
<source>Show crash reporter</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Εμφάνιση αναφοράς κατάρρευσης</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="57"/>
|
||||
@@ -1203,7 +1203,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="193"/>
|
||||
<source>Timeout while trying to connect to %1 at %2.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Λήξη χρονικού ορίου κατά τη σύνδεση σε %1 σε %2.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="204"/>
|
||||
@@ -1213,7 +1213,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="253"/>
|
||||
<source>Access forbidden by server. To verify that you have proper access, <a href="%1">click here</a> to access the service with your browser.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Απαγόρευση πρόσβασης από τον διακομιστή. Για να επιβεβαιώσετε ότι έχετε δικαιώματα πρόσβασης, <a href="%1">πατήστε εδώ</a> για να προσπελάσετε την υπηρεσία με το πρόγραμμα πλοήγησής σας.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="275"/>
|
||||
@@ -1362,7 +1362,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="121"/>
|
||||
<source>Invalid JSON reply from the poll URL</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Λανθασμένη απάντηση JSON από την ιστοσελίδα poll</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1421,7 +1421,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="104"/>
|
||||
<source>Continue blacklisting: </source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Συνέχεια μαύρη λίστα:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="200"/>
|
||||
@@ -1478,7 +1478,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="103"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 204, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διακομιστής επέστρεψε εσφαλμένο κωδικό HTTP. Αναμενόταν 204, ελήφθη "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1486,7 +1486,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemkdir.cpp" line="67"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διακομιστής επέστρεψε εσφαλμένο κωδικό HTTP. Αναμενόταν 201, ελήφθη "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1509,7 +1509,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="127"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διακομιστής επέστρεψε εσφαλμένο κωδικό HTTP. Αναμενόταν 201, ελήφθη "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1552,7 +1552,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="468"/>
|
||||
<source>Poll URL missing</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Η διεύθυνση poll URL λείπει</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="493"/>
|
||||
@@ -1646,13 +1646,19 @@ It is not advisable to use it.</source>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="265"/>
|
||||
<source>%n files are ignored because of previous errors.
|
||||
</source>
|
||||
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation>
|
||||
<translation><numerusform>%n αρχεία αγνοήθηκαν λόγω προηγούμενων σφαλμάτων.
|
||||
|
||||
</numerusform><numerusform>%n αρχεία αγνοήθηκαν λόγω προηγούμενων σφαλμάτων.
|
||||
|
||||
</numerusform></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="266"/>
|
||||
<source>%n files are partially downloaded.
|
||||
</source>
|
||||
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform></translation>
|
||||
<translation><numerusform>%n αρχεία λήφθηκαν μερικώς.
|
||||
</numerusform><numerusform>%n αρχεία λήφθηκαν μερικώς.
|
||||
</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="267"/>
|
||||
@@ -1670,12 +1676,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="318"/>
|
||||
<source>Choose What to Sync: Select remote subfolders you wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Επιλέξτε Τι θα Συγχρονιστεί: Επιλέξτε τους απομακρυσμένους υποφακέλους που επιθυμείτε να συγχρονίσετε.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="319"/>
|
||||
<source>Choose What to Sync: Deselect remote subfolders you do not wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Επιλέξτε Τι θα Συγχρονιστεί: Επιλέξτε τους απομακρυσμένους υποφακέλους που δεν επιθυμείτε να συγχρονίσετε.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="325"/>
|
||||
@@ -1778,7 +1784,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="53"/>
|
||||
<source>share label</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Διαμοιρασμός ετικέτας</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="75"/>
|
||||
@@ -1804,7 +1810,7 @@ It is not advisable to use it.</source>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="67"/>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="461"/>
|
||||
<source>%1 path: %2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 διαδρομή: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="68"/>
|
||||
@@ -1824,7 +1830,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="351"/>
|
||||
<source>OCS API error code: %1</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>OCS API κωδικός λάθους: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="374"/>
|
||||
@@ -1839,12 +1845,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="393"/>
|
||||
<source>Sharing of external directories is not yet working.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο διαμοιρασμός εξωτερικών καταλόγων δεν λειτουργεί ακόμα.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="408"/>
|
||||
<source>A sync file with the same name exists. The file can not be registered to sync.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ήδη υπάρχει αρχείο συγχρονισμού με το ίδιο όνομα. Το αρχείο δεν μπορεί να καταχωρηθεί προς συγχρονισμό.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="420"/>
|
||||
@@ -1854,7 +1860,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="422"/>
|
||||
<source>Unable to register in sync space.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Αδυναμία καταχώρησης στο χώρο συγχρονισμού.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="453"/>
|
||||
@@ -1864,7 +1870,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="463"/>
|
||||
<source>Sync of registered file was not successful yet.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ο συγχρονισμός του καταχωρημένου αρχείου δεν πέτυχε ακόμη.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2123,7 +2129,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="99"/>
|
||||
<source>CSync failed to load the journal file. The journal file is corrupted.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Το CSync απέτυχε να φορτώσει ο αρχείο καταλόγου. Το αρχείο καταλόγου έχει καταστραφεί.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="102"/>
|
||||
@@ -2346,7 +2352,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="237"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><p>Πνευματικά δικαιώματα ownCloud, Ανώνυμη Εταιρία</p></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="238"/>
|
||||
@@ -2454,7 +2460,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="435"/>
|
||||
<source>Crash now</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Κατάρρευση τώρα</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="446"/>
|
||||
@@ -2502,7 +2508,7 @@ It is not advisable to use it.</source>
|
||||
<message utf8="true">
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="48"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><p>Έκδοση %2. Για περισσότερες πληροφορίες επισκεφθείτε <a href="%3">%4</a></p><p><small>Των Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz και άλλων.</small></p><p>Πνευματικά δικαιώματα ownCloud, Inc.</p><p>Αδειοδότηση υπό την GNU General Public License (GPL) Έκδοση 2.0<br/>το ownCloud και το λογότυπο ownCloud είναι σήματα κατατεθέντα της ownCloud, Inc. στις Η.Π.Α., σε άλλες χώρες ή και στα δύο</p></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2561,7 +2567,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="224"/>
|
||||
<source>S&ync everything from server</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Σ&υγχρονισμός όλων από τον διακομιστή</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="306"/>
|
||||
@@ -2579,7 +2585,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="43"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address specified. How do you wish to proceed?</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p>Αποτυχία σύνδεσης στην ασφαλή διεύθυνση διακομιστή που ορίστηκε. Πώς θέλετε να συνεχίσετε;</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="55"/>
|
||||
@@ -2589,17 +2595,17 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="62"/>
|
||||
<source>Retry unencrypted over HTTP (insecure)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Επανάληψη χωρίς κρυπτογράφηση μέσω HTTP (ανασφαλής)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="69"/>
|
||||
<source>Configure client-side TLS certificate</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Διαμόρφωση πιστοποιητικού TLS του δέκτη</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.cpp" line="18"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address <em>%1</em>. How do you wish to proceed?</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p> Αποτυχία σύνδεσης με ασφαλή διεύθυνση του διακομιστή <em>%1</em>. Πώς θέλετε να συνεχίσετε;</p></body></html></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -695,7 +695,7 @@ Voulez-vous réellement effectuer cette opération ?</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="156"/>
|
||||
<source>Server returned wrong content-range</source>
|
||||
<translation>Le serveur a retourné une gamme de contenu erronnée</translation>
|
||||
<translation>Le serveur a retourné une gamme de contenu erronée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagatedownload.cpp" line="257"/>
|
||||
@@ -757,12 +757,12 @@ Voulez-vous réellement effectuer cette opération ?</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/creds/httpcredentials.cpp" line="400"/>
|
||||
<source>Enter Password</source>
|
||||
<translation>Entrez le mot de passe</translation>
|
||||
<translation>Saisissez le mot de passe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/creds/httpcredentials.cpp" line="401"/>
|
||||
<source>Please enter %1 password for user '%2':</source>
|
||||
<translation>Veuillez entrer le mot de passe %1 pour l'utilisateur '%2' :</translation>
|
||||
<translation>Veuillez saisir le mot de passe %1 pour l'utilisateur '%2' :</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -770,7 +770,7 @@ Voulez-vous réellement effectuer cette opération ?</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.ui" line="14"/>
|
||||
<source>Ignored Files Editor</source>
|
||||
<translation>Éditeur de modification des fichiers ignorés</translation>
|
||||
<translation>Éditeur de la liste des fichiers ignorés</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.ui" line="53"/>
|
||||
@@ -789,7 +789,7 @@ Voulez-vous réellement effectuer cette opération ?</translation>
|
||||
Checked items will also be deleted if they prevent a directory from being removed. This is useful for meta data.</source>
|
||||
<translation>Les fichiers ou dossiers correspondants à un motif ne seront pas synchronisés.
|
||||
|
||||
Les items cochés seront également supprimés s'ils empêchent la suppression d'un dossier. Cela est utile pour les meta-données.</translation>
|
||||
Les motifs cochés seront également supprimés s'ils empêchent la suppression d'un dossier. Cela est utile pour les meta-données.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.cpp" line="97"/>
|
||||
@@ -809,22 +809,22 @@ Les items cochés seront également supprimés s'ils empêchent la suppress
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.cpp" line="106"/>
|
||||
<source>Add a new ignore pattern:</source>
|
||||
<translation>Ajouter un nouveau modèle à ignorer :</translation>
|
||||
<translation>Ajoutez un nouveau motif à ignorer :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.cpp" line="128"/>
|
||||
<source>Edit Ignore Pattern</source>
|
||||
<translation>Éditer le modèle</translation>
|
||||
<translation>Modifier le motif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.cpp" line="129"/>
|
||||
<source>Edit ignore pattern:</source>
|
||||
<translation>Éditer le modèle :</translation>
|
||||
<translation>Éditer le motif :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/ignorelisteditor.cpp" line="140"/>
|
||||
<source>This entry is provided by the system at '%1' and cannot be modified in this view.</source>
|
||||
<translation>Cette entrée est fournie par le système à '%1' et ne peut être modifiée dans cette vue.</translation>
|
||||
<translation>Cette entrée est fournie par le système dans '%1' et ne peut être modifiée dans cette vue.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -916,7 +916,7 @@ Les items cochés seront également supprimés s'ils empêchent la suppress
|
||||
<message>
|
||||
<location filename="../src/gui/updater/ocupdater.cpp" line="275"/>
|
||||
<source>Skip this version</source>
|
||||
<translation>Ignorer cette version.</translation>
|
||||
<translation>Ignorer cette version</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/updater/ocupdater.cpp" line="276"/>
|
||||
@@ -1007,7 +1007,7 @@ Les items cochés seront également supprimés s'ils empêchent la suppress
|
||||
<message>
|
||||
<location filename="../src/gui/networksettings.cpp" line="34"/>
|
||||
<source>Hostname of proxy server</source>
|
||||
<translation>Nom d'hôte ou serveur mandataire</translation>
|
||||
<translation>Nom d'hôte du serveur mandataire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/networksettings.cpp" line="35"/>
|
||||
@@ -1384,7 +1384,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagator_legacy.cpp" line="516"/>
|
||||
<source>Server returned wrong content-range</source>
|
||||
<translation>Le serveur a retourné une gamme de contenu erronnée</translation>
|
||||
<translation>Le serveur a retourné une gamme de contenu erronée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagator_legacy.cpp" line="567"/>
|
||||
@@ -1420,12 +1420,12 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="104"/>
|
||||
<source>Continue blacklisting: </source>
|
||||
<translation>Poursuivre la liste noire :</translation>
|
||||
<translation>Poursuivre la mise sur liste noire :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="200"/>
|
||||
<source>A file or directory was removed from a read only share, but restoring failed: %1</source>
|
||||
<translation>Un fichier ou un dossier a été supprimé du partage en lecture seule, mais la restauration à échoué : %1</translation>
|
||||
<translation>Un fichier ou un dossier a été supprimé d'un partage en lecture seule, mais la restauration a échoué : %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1477,7 +1477,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="103"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 204, but recieved "%1 %2".</source>
|
||||
<translation>Le code HTTP retourné par le serveur est invalide. La valeur attendue est 204 mais la valeur reçue est "%1 %2".</translation>
|
||||
<translation>Le code HTTP retourné par le serveur n'est pas valide. La valeur attendue est 204 mais la valeur reçue est "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1485,7 +1485,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemkdir.cpp" line="67"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation>Le code HTTP retourné par le serveur est invalide. La valeur attendue est 201 mais la valeur reçue est "%1 %2".</translation>
|
||||
<translation>Le code HTTP retourné par le serveur n'est pas valide. La valeur attendue est 201 mais la valeur reçue est "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1498,7 +1498,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="75"/>
|
||||
<source>This folder must not be renamed. Please name it back to Shared.</source>
|
||||
<translation>Ce dossier ne doit pas être renommé. Veuillez le nommer Partagé uniquement.</translation>
|
||||
<translation>Ce dossier ne doit pas être renommé. Veuillez le renommer en Shared.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="111"/>
|
||||
@@ -1508,7 +1508,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="127"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation>Le code HTTP retourné par le serveur est invalide. La valeur attendue est 201 mais la valeur reçue est "%1 %2".</translation>
|
||||
<translation>Le code HTTP retourné par le serveur n'est pas valide. La valeur attendue est 201 mais la valeur reçue est "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2123,7 +2123,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="95"/>
|
||||
<source>CSync failed to load or create the journal file. Make sure you have read and write permissions in the local sync directory.</source>
|
||||
<translation>CSync n’a pu charger ou créer le fichier de journalisation. Veuillez vérifier que vous possédez les droits en lecture/écriture dans le répertoire de synchronisation local.</translation>
|
||||
<translation>CSync n’a pu charger ou créer le fichier de journalisation. Veuillez vérifier que vous possédez les droits en lecture et écriture dans le répertoire de synchronisation local.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="99"/>
|
||||
@@ -2158,17 +2158,17 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="117"/>
|
||||
<source>CSync processing step reconcile failed.</source>
|
||||
<translation>Erreur CSync lors de l'opération d'harmonisation</translation>
|
||||
<translation>Erreur CSync lors de l'opération de réconciliation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="120"/>
|
||||
<source>CSync could not authenticate at the proxy.</source>
|
||||
<translation>CSync ne peut s'authentifier auprès du proxy.</translation>
|
||||
<translation>CSync n'a pu s'authentifier auprès du proxy.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="123"/>
|
||||
<source>CSync failed to lookup proxy or server.</source>
|
||||
<translation>CSync n'a pu trouver un proxy ou serveur auquel se connecter.</translation>
|
||||
<translation>CSync n'a pu trouver le proxy ou serveur auquel se connecter.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="126"/>
|
||||
@@ -2183,7 +2183,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="132"/>
|
||||
<source>A network connection timeout happened.</source>
|
||||
<translation>Le délai d'attente pour la connexion réseau a été dépassé.</translation>
|
||||
<translation>Le délai d'attente de la connexion réseau a été dépassé.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="135"/>
|
||||
@@ -2198,7 +2198,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="141"/>
|
||||
<source>CSync failed to access </source>
|
||||
<translation>Echec de CSync pour accéder</translation>
|
||||
<translation>CSync n'a pu accéder à</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="144"/>
|
||||
@@ -2279,7 +2279,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="895"/>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="902"/>
|
||||
<source>Ignored because of the "choose what to sync" blacklist</source>
|
||||
<translation>Ignoré à cause de la liste noire du contenu à synchroniser.</translation>
|
||||
<translation>Ignoré à cause de la liste noire "Choisir le contenu à synchroniser".</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="920"/>
|
||||
@@ -2389,7 +2389,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="295"/>
|
||||
<source>None.</source>
|
||||
<translation>Aucun.</translation>
|
||||
<translation>Aucune</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="299"/>
|
||||
@@ -2404,7 +2404,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="326"/>
|
||||
<source>Managed Folders:</source>
|
||||
<translation>Répertoires suivis :</translation>
|
||||
<translation>Répertoires configurés :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="335"/>
|
||||
@@ -2464,7 +2464,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="446"/>
|
||||
<source>Quota n/a</source>
|
||||
<translation>Quota n/a</translation>
|
||||
<translation>Quota non disponible ou non applicable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="453"/>
|
||||
@@ -2474,7 +2474,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="465"/>
|
||||
<source>No items synced recently</source>
|
||||
<translation>Aucun item synchronisé récemment</translation>
|
||||
<translation>Aucun élément synchronisé récemment</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="477"/>
|
||||
@@ -2484,12 +2484,12 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="482"/>
|
||||
<source>Syncing %1 of %2 (%3 left)</source>
|
||||
<translation>Synchronisation %1 de %2 (%3 restant)</translation>
|
||||
<translation>Synchronisation de %1 sur %2 (%3 restant)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="487"/>
|
||||
<source>Syncing %1 (%2 left)</source>
|
||||
<translation>Synchronisation %1 (%2 restant)</translation>
|
||||
<translation>Synchronisation de %1 (%2 restant)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="507"/>
|
||||
@@ -2566,7 +2566,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="224"/>
|
||||
<source>S&ync everything from server</source>
|
||||
<translation>Synchroniser tout le contenu depuis le serveur</translation>
|
||||
<translation>S&ynchroniser tout le contenu depuis le serveur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="306"/>
|
||||
@@ -2584,17 +2584,17 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="43"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address specified. How do you wish to proceed?</p></body></html></source>
|
||||
<translation><html><head/><body><p>Impossible de se connecter au serveur via l'adresse sécurisée indiquée. Comment voulez-vous procéder ?</p></body></html></translation>
|
||||
<translation><html><head/><body><p>Impossible de se connecter au serveur via l'adresse sécurisée indiquée. Que souhaitez-vous faire ?</p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="55"/>
|
||||
<source>Select a different URL</source>
|
||||
<translation>Sélectionner un URL différent</translation>
|
||||
<translation>Sélectionner une URL différente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="62"/>
|
||||
<source>Retry unencrypted over HTTP (insecure)</source>
|
||||
<translation>Réessayer en clair sur HTTP (non sécurisé)</translation>
|
||||
<translation>Essayer en clair sur HTTP (non sécurisé)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="69"/>
|
||||
@@ -2604,7 +2604,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.cpp" line="18"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address <em>%1</em>. How do you wish to proceed?</p></body></html></source>
|
||||
<translation><html><head/><body><p>Impossible de se connecter à l'adresse sécurisée du serveur <em>%1</em>. Comment voulez-vous procéder ?</p></body></html></translation>
|
||||
<translation><html><head/><body><p>Impossible de se connecter à l'adresse sécurisée <em>%1</em>. Que souhaitez-vous faire ?</p></body></html></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2696,7 +2696,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetuppage.ui" line="120"/>
|
||||
<source>&Do not store password on local machine</source>
|
||||
<translation>&Ne pas mémoriser le mot de passe sur la machine locale</translation>
|
||||
<translation>Ne &pas mémoriser le mot de passe sur la machine locale</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetuppage.ui" line="140"/>
|
||||
@@ -2786,7 +2786,7 @@ Il est déconseillé de l'utiliser.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/main.cpp" line="46"/>
|
||||
<source>%1 requires on a working system tray. If you are running XFCE, please follow <a href="http://docs.xfce.org/xfce/xfce4-panel/systray">these instructions</a>. Otherwise, please install a system tray application such as 'trayer' and try again.</source>
|
||||
<translation>%1 nécessite la présence d'une zone de notification système (system tray). Si vous utilisez XFCE, veuillez suivre <a href="http://docs.xfce.org/xfce/xfce4-panel/systray">ces instructions</a>. Sinon, installez une application mettant en place une zone de notification, telle que 'trayer', et essayez à nouveau.</translation>
|
||||
<translation>%1 nécessite la présence d'une zone de notification système. Si vous utilisez XFCE, veuillez suivre <a href="http://docs.xfce.org/xfce/xfce4-panel/systray">ces instructions</a>. Sinon, installez une application mettant en place une zone de notification, telle que 'trayer', et essayez à nouveau.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -2265,7 +2265,7 @@ Recomendámoslle que non o use.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="567"/>
|
||||
<source>Unable to initialize a sync journal.</source>
|
||||
<translation>Non é posíbel iniciar un rexistro de sincronización.</translation>
|
||||
<translation>Non é posíbel preparar un rexistro de sincronización.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="648"/>
|
||||
|
||||
@@ -1210,7 +1210,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="253"/>
|
||||
<source>Access forbidden by server. To verify that you have proper access, <a href="%1">click here</a> to access the service with your browser.</source>
|
||||
<translation>サーバからアクセスが拒否されました。適切なアクセス権の検証には、<a href="%1">ここをクリック</a>してブラウザからサービスにアクセスしてください。</translation>
|
||||
<translation>サーバーによってアクセスが拒否されています。適切なアクセス権があるか検証するには、<a href="%1">ここをクリック</a>してブラウザーでサービスにアクセスしてください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="275"/>
|
||||
@@ -1828,12 +1828,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="374"/>
|
||||
<source>There is no sync folder configured.</source>
|
||||
<translation>同期フォルダが設定されていません。</translation>
|
||||
<translation>同期フォルダーが設定されていません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="386"/>
|
||||
<source>Can not find an folder to upload to.</source>
|
||||
<translation>アップロード先のフォルダが見つけられません。</translation>
|
||||
<translation>アップロード先のフォルダーが見つかりません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="393"/>
|
||||
@@ -1926,7 +1926,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sslbutton.cpp" line="101"/>
|
||||
<source>Subject Alternative Names:</source>
|
||||
<translation>Subject Alternative Names(サブジェクトの別名):</translation>
|
||||
<translation>サブジェクトの別名:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sslbutton.cpp" line="103"/>
|
||||
@@ -1971,7 +1971,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sslbutton.cpp" line="115"/>
|
||||
<source>Expires on:</source>
|
||||
<translation>期限切れ期日:</translation>
|
||||
<translation>有効期限:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sslbutton.cpp" line="118"/>
|
||||
@@ -2237,7 +2237,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="340"/>
|
||||
<source>Symbolic links are not supported in syncing.</source>
|
||||
<translation>同期機能は、シンボリックリンクをサポートしていません。</translation>
|
||||
<translation>同期機能はシンボリックリンクをサポートしていません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="343"/>
|
||||
|
||||
@@ -226,7 +226,7 @@ Skupaj še %5</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/accountsettings.cpp" line="820"/>
|
||||
<source>No %1 connection configured.</source>
|
||||
<translation>Ni nastavljenih %1 povezav.</translation>
|
||||
<translation>Ni nastavljene povezave %1.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -234,7 +234,7 @@ Skupaj še %5</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="17"/>
|
||||
<source>SSL client certificate authentication</source>
|
||||
<translation>SSL overjanje potrdila odjemalca</translation>
|
||||
<translation>Overitev odjemalca s potrdilom SSL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="23"/>
|
||||
@@ -329,7 +329,7 @@ Skupaj še %5</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="41"/>
|
||||
<source>Connection timed out</source>
|
||||
<translation>Povezava je potekla</translation>
|
||||
<translation>Povezava je časovno potekla</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2473,7 +2473,7 @@ Uporaba ni priporočljiva.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="477"/>
|
||||
<source>Discovering '%1'</source>
|
||||
<translation>Poteka preučevanje %1</translation>
|
||||
<translation>Poteka preučevanje '%1'</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="482"/>
|
||||
|
||||
4
translations/client_sr.ts
Normal file
4
translations/client_sr.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.0" language="en_US">
|
||||
</TS>
|
||||
@@ -668,7 +668,7 @@ Detta kan bero på att konfigurationen för mappen ändrats, eller att alla file
|
||||
<message>
|
||||
<location filename="../src/gui/folderwizard.cpp" line="444"/>
|
||||
<source>Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Välj Vad du vill Synka: Du har även möjlighet att avmarkera mappar på servern som du ej vill synkronisera.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -733,7 +733,7 @@ Detta kan bero på att konfigurationen för mappen ändrats, eller att alla file
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="47"/>
|
||||
<source>Show crash reporter</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Visa kraschrapporteringsverktyg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="57"/>
|
||||
@@ -1420,7 +1420,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="104"/>
|
||||
<source>Continue blacklisting: </source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Fortsätt svartlista:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="200"/>
|
||||
@@ -1477,7 +1477,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="103"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 204, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Fel HTTP-kod returnerades av servern. Förväntade 204, men tog emot "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -733,7 +733,7 @@ Are you sure you want to perform this operation?</source>
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="47"/>
|
||||
<source>Show crash reporter</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Показати звіти про помилки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/generalsettings.ui" line="57"/>
|
||||
@@ -1202,7 +1202,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="193"/>
|
||||
<source>Timeout while trying to connect to %1 at %2.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Перевищено час очікування з'єднання до %1 на %2.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="204"/>
|
||||
@@ -1212,7 +1212,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="253"/>
|
||||
<source>Access forbidden by server. To verify that you have proper access, <a href="%1">click here</a> to access the service with your browser.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Доступ заборонений сервером. Щоб довести, що у Вас є права доступу, <a href="%1">клікніть тут</a> для входу через Ваш браузер.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudsetupwizard.cpp" line="275"/>
|
||||
@@ -1361,7 +1361,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="121"/>
|
||||
<source>Invalid JSON reply from the poll URL</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Неправильна JSON відповідь на сформований URL</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1420,7 +1420,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="104"/>
|
||||
<source>Continue blacklisting: </source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Продовжити занесення до чорного списку:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/owncloudpropagator.cpp" line="200"/>
|
||||
@@ -1477,7 +1477,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="103"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 204, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Сервер відповів неправильним HTTP кодом. Очікувався 204, але отриманий "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1485,7 +1485,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemkdir.cpp" line="67"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Сервер відповів неправильним HTTP кодом. Очікувався 201, але отриманий "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1508,7 +1508,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="127"/>
|
||||
<source>Wrong HTTP code returned by server. Expected 201, but recieved "%1 %2".</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Сервер відповів неправильним HTTP кодом. Очікувався 201, але отриманий "%1 %2".</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1551,7 +1551,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="468"/>
|
||||
<source>Poll URL missing</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Не вистачає сформованого URL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="493"/>
|
||||
@@ -1645,13 +1645,19 @@ It is not advisable to use it.</source>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="265"/>
|
||||
<source>%n files are ignored because of previous errors.
|
||||
</source>
|
||||
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
|
||||
<translation><numerusform>%n файл пропущено через попередні помилки.
|
||||
</numerusform><numerusform>%n файлів пропущено через попередні помилки.
|
||||
</numerusform><numerusform>%n файлів пропущено через попередні помилки.
|
||||
</numerusform></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="266"/>
|
||||
<source>%n files are partially downloaded.
|
||||
</source>
|
||||
<translation type="unfinished"><numerusform></numerusform><numerusform></numerusform><numerusform></numerusform></translation>
|
||||
<translation><numerusform>%n файлів частково завантажений.
|
||||
</numerusform><numerusform>%n файлів частково завантажені.
|
||||
</numerusform><numerusform>%n файлів частково завантажено.
|
||||
</numerusform></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/protocolwidget.cpp" line="267"/>
|
||||
@@ -1669,12 +1675,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="318"/>
|
||||
<source>Choose What to Sync: Select remote subfolders you wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Виберіть Що Синхронізувати: Виберіть папки на віддаленому сервері, які Ви хотіли б синхронізувати.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="319"/>
|
||||
<source>Choose What to Sync: Deselect remote subfolders you do not wish to synchronize.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Виберіть Що Синхронізувати: Зніміть вибір папок на віддаленому сервері, які Ви не хочете синхронізувати.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/selectivesyncdialog.cpp" line="325"/>
|
||||
@@ -1761,12 +1767,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="14"/>
|
||||
<source>Share NewDocument.odt</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Поділитися NewDocument.odt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="26"/>
|
||||
<source>Share Info</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Поділитися Інформацією</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="34"/>
|
||||
@@ -1777,12 +1783,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="53"/>
|
||||
<source>share label</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>поділитися міткою</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="75"/>
|
||||
<source>OwnCloud Path:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Шлях до OwnCloud:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="89"/>
|
||||
@@ -1803,12 +1809,12 @@ It is not advisable to use it.</source>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="67"/>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="461"/>
|
||||
<source>%1 path: %2</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 шлях: %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="68"/>
|
||||
<source>%1 Sharing</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ви поділилися %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="141"/>
|
||||
@@ -1823,27 +1829,27 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="351"/>
|
||||
<source>OCS API error code: %1</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>OCS API код помилки: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="374"/>
|
||||
<source>There is no sync folder configured.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Немає папок налаштованих для синхронізації.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="386"/>
|
||||
<source>Can not find an folder to upload to.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Неможливо знайти папку для завантаження в неї.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="393"/>
|
||||
<source>Sharing of external directories is not yet working.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Функція відкриття доступу до зовнішніх папок поки не працює.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="408"/>
|
||||
<source>A sync file with the same name exists. The file can not be registered to sync.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Існує файл з ім'ям як у синхронізованого. Файл не може бути прийнятий до синхронізації.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="420"/>
|
||||
@@ -1853,17 +1859,17 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="422"/>
|
||||
<source>Unable to register in sync space.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Неможливо зареєструватися в синхронізованому просторі.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="453"/>
|
||||
<source>The file can not be synced.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Файл не може бути синхронізований.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="463"/>
|
||||
<source>Sync of registered file was not successful yet.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Синхронізація зареєстрованого файлу поки не була успішною.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1908,7 +1914,7 @@ It is not advisable to use it.</source>
|
||||
<location filename="../src/gui/socketapi.cpp" line="431"/>
|
||||
<source>Share with %1</source>
|
||||
<comment>parameter is ownCloud</comment>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Поділитися з %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2122,7 +2128,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="99"/>
|
||||
<source>CSync failed to load the journal file. The journal file is corrupted.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>CSync не вдалося завантажити файл журналу. Файл журналу пошкоджений.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="102"/>
|
||||
@@ -2217,12 +2223,12 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="156"/>
|
||||
<source>The mounted directory is temporarily not available on the server</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Приєднана тека тимчасово недоступна на сервері</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="159"/>
|
||||
<source>An error opening a directory happened</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Сталася помилка при відкритті теки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/syncengine.cpp" line="162"/>
|
||||
@@ -2345,7 +2351,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="237"/>
|
||||
<source><p>Copyright ownCloud, Incorporated</p></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><p> Права належать ownCloud, Incorporated </p></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/theme.cpp" line="238"/>
|
||||
@@ -2453,7 +2459,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="435"/>
|
||||
<source>Crash now</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Критична помилка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/owncloudgui.cpp" line="446"/>
|
||||
@@ -2501,7 +2507,7 @@ It is not advisable to use it.</source>
|
||||
<message utf8="true">
|
||||
<location filename="../src/libsync/owncloudtheme.cpp" line="48"/>
|
||||
<source><p>Version %2. For more information visit <a href="%3">%4</a></p><p><small>By Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz and others.</small></p><p>Copyright ownCloud, Inc.</p><p>Licensed under the GNU General Public License (GPL) Version 2.0<br/>ownCloud and the ownCloud Logo are registered trademarks of ownCloud, Inc. in the United States, other countries, or both.</p></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><p>Версія %2. Для більш детальної інформації відвідайте <a href="%3">%4</a></p> <p><small> Klaas Freitag, Daniel Molkentin, Jan-Christoph Borchardt, Olivier Goffart, Markus Götz та інші.</ small></p> <p> Права належать ownCloud, Inc. </p> <p> Під ліцензією GNU General Public License (GPL) Version 2.0 <br/> ownCloud і логотип ownCloud є зареєстрованими товарними знаками ownCloud, Inc. в США та інших країнах. </p></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2560,7 +2566,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="224"/>
|
||||
<source>S&ync everything from server</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Синхронізувати все з сервером</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.ui" line="306"/>
|
||||
@@ -2578,7 +2584,7 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="43"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address specified. How do you wish to proceed?</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p> Не вдалося підключитися до безпечного серверу за наданною адресою. Як Ви хочете продовжити? </p></body></html></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="55"/>
|
||||
@@ -2588,17 +2594,17 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="62"/>
|
||||
<source>Retry unencrypted over HTTP (insecure)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Спробувати без шифрування через HTTP (небезпечно)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.ui" line="69"/>
|
||||
<source>Configure client-side TLS certificate</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Налаштувати TLS сертифікат клієнта</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/wizard/owncloudconnectionmethoddialog.cpp" line="18"/>
|
||||
<source><html><head/><body><p>Failed to connect to the secure server address <em>%1</em>. How do you wish to proceed?</p></body></html></source>
|
||||
<translation type="unfinished"/>
|
||||
<translation><html><head/><body><p>Не вдалося підключитися до безпечного серверу за адресою <em>%1</em>. Як Ви хочете продовжити?</p></body></html></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2747,22 +2753,22 @@ It is not advisable to use it.</source>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="113"/>
|
||||
<source>%L1 TiB</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%L1 Тіб</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="116"/>
|
||||
<source>%L1 GiB</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%L1 ГіБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="119"/>
|
||||
<source>%L1 MiB</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%L1 МіБ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="122"/>
|
||||
<source>%L1 KiB</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%L1 КіБ </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/utility.cpp" line="125"/>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user