mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-04 12:11:33 +02:00
Compare commits
129 Commits
v1.8.0rc1
...
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 | ||
|
|
38ef525d5e | ||
|
|
367b1fcc33 | ||
|
|
f5c930968e | ||
|
|
5264a8c7f6 | ||
|
|
6c4b7f1479 | ||
|
|
c42c9f0002 | ||
|
|
95f299f865 | ||
|
|
09749e2c7f | ||
|
|
dc33784a76 | ||
|
|
961df1fc44 | ||
|
|
e93c1ccb73 | ||
|
|
286ad0c478 | ||
|
|
e30970ff90 | ||
|
|
14e0e4a072 | ||
|
|
60da0a15e6 | ||
|
|
0f84510e6f | ||
|
|
1dd3488973 |
@@ -1,6 +1,6 @@
|
||||
ChangeLog
|
||||
=========
|
||||
version 1.8.0 (release 2015-02-xx)
|
||||
version 1.8.0 (release 2015-03-xx)
|
||||
* Mac OS: HIDPI support
|
||||
* Support Sharing from desktop: Added a share dialog that can be
|
||||
opened by context menu in the file managers (Win, Mac, Nautilus)
|
||||
@@ -12,7 +12,7 @@ version 1.8.0 (release 2015-02-xx)
|
||||
* Added ability to build on Windows utilizing MingGW
|
||||
* SQLite database fixes if running on FAT filesystems
|
||||
* Improved detection of changing files to upload from local
|
||||
* Preparations for the muli-account feature
|
||||
* Preparations for the multi-account feature
|
||||
* Fixed experience for Window manager without system tray
|
||||
* Build with Qt 5.4
|
||||
* Dropped libneon dependency if Qt 5.4 is available
|
||||
@@ -24,8 +24,7 @@ version 1.8.0 (release 2015-02-xx)
|
||||
* Prepared direct download
|
||||
* Added Crashreporter feature to be switched on on demand
|
||||
* A huge amount of bug fixes in all areas of the client.
|
||||
|
||||
* more than 7000 commits since 1.7.0
|
||||
* almost 700 commits since 1.7.1
|
||||
|
||||
version 1.7.1 (release 2014-12-18)
|
||||
* Documentation fixes and updates
|
||||
|
||||
@@ -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 "rc1") #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 )
|
||||
|
||||
@@ -6,3 +6,4 @@ killall @APPLICATION_EXECUTABLE@
|
||||
# Unload the Finder plugin. see issue #2105
|
||||
killall Finder
|
||||
|
||||
exit 0
|
||||
|
||||
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,11 +151,12 @@ CSYNC_EXCLUDE_TYPE csync_excluded(CSYNC *ctx, const char *path, int filetype) {
|
||||
return match;
|
||||
}
|
||||
|
||||
// See http://support.microsoft.com/kb/74496
|
||||
static const char *win_reserved_words[] = {"CON","PRN","AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4",
|
||||
"LPT1", "LPT2", "LPT3", "CLOCK$" };
|
||||
|
||||
// See http://support.microsoft.com/kb/74496 and
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||
// Additionally, we ignore '$Recycle.Bin', see https://github.com/owncloud/client/issues/2955
|
||||
static const char* win_reserved_words[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5",
|
||||
"COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4",
|
||||
"LPT5", "LPT6", "LPT7", "LPT8", "LPT9", "CLOCK$", "$Recycle.Bin" };
|
||||
|
||||
bool csync_is_windows_reserved_word(const char* filename) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -151,9 +151,9 @@ ownCloud Client provides the ability to add custom patterns.
|
||||
|
||||
By default, the ownCloud Client ignores the following files:
|
||||
|
||||
- Files matched by one of the patterns defined in :ref:`ignoredFilesEditor-label`.
|
||||
- Files containing characters that do not work on certain file systems (`\, /, :, ?, *, ", >, <, |`).
|
||||
* Files starting in ``.csync_journal.db*``, as these files are reserved for journalling.
|
||||
* Files matched by one of the patterns defined in the Ignored Files Editor
|
||||
* Files containing characters that do not work on certain file systems ``(`\, /, :, ?, *, ", >, <, |`)``.
|
||||
* Files starting in ``.csync_journal.db``, as these files are reserved for journalling.
|
||||
|
||||
If a pattern selected using a checkbox in the `ignoredFilesEditor-label` (or if
|
||||
a line in the exclude file starts with the character `]` directly followed by
|
||||
@@ -212,62 +212,61 @@ In the communication between client and server a couple of custom WebDAV propert
|
||||
were introduced. They are either needed for sync functionality or help have a positive
|
||||
effect on synchronization performance.
|
||||
|
||||
This chapter describes additional xml elemeents which the server returns in response
|
||||
to a successful PROPFIND request on a file or directory. The elemnts are returned in
|
||||
This chapter describes additional xml elements which the server returns in response
|
||||
to a successful PROPFIND request on a file or directory. The elements are returned in
|
||||
the namespace oc.
|
||||
|
||||
###Server Side Permissions
|
||||
Server Side Permissions
|
||||
------------------------
|
||||
|
||||
The XML element <oc:permissions> represents the permission- and sharing state of the
|
||||
The XML element ``<oc:permissions>`` represents the permission- and sharing state of the
|
||||
item. It is a list of characters, and each of the chars has a meaning as outlined
|
||||
in the table below:
|
||||
|
||||
+------+-------------+-------------------------------------------+
|
||||
| Code | Resource | Description |
|
||||
|======+=============+===========================================|
|
||||
| S | File or Folder | is shared |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| R | File or Folder | can share (includes reshare) |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| M | File or Folder | is mounted (like on DropBox, Samba, etc.) |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| W | File | can write file |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| C | Folder |can create file in folder |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| D | File or Folder |can delete file or folder |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+---+----------------+-------------------------------------------|
|
||||
| V | File or Folder | can move file or folder |
|
||||
+---+----------------+-------------------------------------------|
|
||||
+----+----------------+-------------------------------------------+
|
||||
|Code| Resource | Description |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| S | File or Folder | is shared |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| R | File or Folder | can share (includes reshare) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| M | File or Folder | is mounted (like on DropBox, Samba, etc.) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| W | File | can write file |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| C | Folder |can create file in folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| K | Folder | can create folder (mkdir) |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| D | File or Folder |can delete file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| N | File or Folder | can rename file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
| V | File or Folder | can move file or folder |
|
||||
+----+----------------+-------------------------------------------+
|
||||
|
||||
|
||||
Example:
|
||||
```
|
||||
<oc:permissions>RDNVCK</oc:permissions>
|
||||
```
|
||||
|
||||
###File- or Directory Size
|
||||
<oc:permissions>RDNVCK</oc:permissions>
|
||||
|
||||
The XML element <oc:size> represents the file- or directory size in bytes. For
|
||||
File- or Directory Size
|
||||
-----------------------
|
||||
|
||||
The XML element ``<oc:size>`` represents the file- or directory size in bytes. For
|
||||
directories, the size of the whole file tree underneath the directory is accumulated.
|
||||
|
||||
Example:
|
||||
```
|
||||
<oc:size>2429176697</oc:size>
|
||||
```
|
||||
|
||||
###FileID
|
||||
<oc:size>2429176697</oc:size>
|
||||
|
||||
FileID
|
||||
------
|
||||
|
||||
The XML element <oc:id> represents the so called file ID. It is a non volatile string id
|
||||
The XML element ``<oc:id>`` represents the so called file ID. It is a non volatile string id
|
||||
that stays constant as long as the file exists. It is not changed if the file changes or
|
||||
is renamed or moved.
|
||||
|
||||
|
||||
Example:
|
||||
```
|
||||
<oc:id>00000020oc5cfy6qqizm</oc:id>
|
||||
```
|
||||
|
||||
<oc:id>00000020oc5cfy6qqizm</oc:id>
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ IFACEMETHODIMP OCContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT
|
||||
|
||||
assert(!info.shareMenuTitle.empty());
|
||||
MENUITEMINFO mii = { sizeof(mii) };
|
||||
mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE;
|
||||
mii.wID = idCmdFirst + IDM_SHARE;
|
||||
mii.fType = MFT_STRING;
|
||||
mii.dwTypeData = &info.shareMenuTitle[0];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(WITH_CRASHREPORTER)
|
||||
#include <libcrashreporter-handler/Handler.h>
|
||||
#endif
|
||||
|
||||
#include <QTranslator>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
@@ -106,6 +110,11 @@ Application::Application(int &argc, char **argv) :
|
||||
if (isRunning())
|
||||
return;
|
||||
|
||||
#if defined(WITH_CRASHREPORTER)
|
||||
if (ConfigFile().crashReporter())
|
||||
_crashHandler.reset(new CrashReporter::Handler( QDir::tempPath(), true, CRASHREPORTER_EXECUTABLE ));
|
||||
#endif
|
||||
|
||||
setupLogging();
|
||||
setupTranslations();
|
||||
|
||||
@@ -171,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()
|
||||
@@ -394,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();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ class QMessageBox;
|
||||
class QSystemTrayIcon;
|
||||
class QSocket;
|
||||
|
||||
namespace CrashReporter {
|
||||
class Handler;
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
class Theme;
|
||||
class Folder;
|
||||
@@ -109,6 +113,9 @@ private:
|
||||
|
||||
QTimer _checkConnectionTimer;
|
||||
|
||||
#if defined(WITH_CRASHREPORTER)
|
||||
QScopedPointer<CrashReporter::Handler> _crashHandler;
|
||||
#endif
|
||||
QScopedPointer<FolderMan> _folderManager;
|
||||
|
||||
friend class ownCloudGui; // for _startupNetworkError
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,10 +239,19 @@ FolderWizardRemotePath::FolderWizardRemotePath(AccountPtr account)
|
||||
|
||||
connect(_ui.addFolderButton, SIGNAL(clicked()), SLOT(slotAddRemoteFolder()));
|
||||
connect(_ui.refreshButton, SIGNAL(clicked()), SLOT(slotRefreshFolders()));
|
||||
connect(_ui.folderTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
|
||||
connect(_ui.folderTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
|
||||
connect(_ui.folderTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(_ui.folderTreeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), SLOT(slotCurrentItemChanged(QTreeWidgetItem*)));
|
||||
connect(_ui.folderEntry, SIGNAL(textEdited(QString)), SLOT(slotFolderEntryEdited(QString)));
|
||||
|
||||
_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()
|
||||
@@ -288,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,27 +326,58 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
|
||||
|
||||
void FolderWizardRemotePath::recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path)
|
||||
{
|
||||
QFileIconProvider prov;
|
||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||
if (pathTrail.size() == 0) {
|
||||
if (path.endsWith('/')) {
|
||||
path.chop(1);
|
||||
}
|
||||
parent->setToolTip(0, path);
|
||||
parent->setData(0, Qt::UserRole, path);
|
||||
} else {
|
||||
QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
|
||||
if (!item) {
|
||||
item = new QTreeWidgetItem(parent);
|
||||
item->setIcon(0, folderIcon);
|
||||
item->setText(0, pathTrail.first());
|
||||
item->setData(0, Qt::UserRole, pathTrail.first());
|
||||
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
|
||||
}
|
||||
if (pathTrail.isEmpty())
|
||||
return;
|
||||
|
||||
pathTrail.removeFirst();
|
||||
recursiveInsert(item, pathTrail, path);
|
||||
const QString parentPath = parent->data(0, Qt::UserRole).toString();
|
||||
const QString folderName = pathTrail.first();
|
||||
QString folderPath;
|
||||
if (parentPath == QLatin1String("/")) {
|
||||
folderPath = folderName;
|
||||
} else {
|
||||
folderPath = parentPath + "/" + folderName;
|
||||
}
|
||||
QTreeWidgetItem *item = findFirstChild(parent, folderName);
|
||||
if (!item) {
|
||||
item = new QTreeWidgetItem(parent);
|
||||
QFileIconProvider prov;
|
||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||
item->setIcon(0, folderIcon);
|
||||
item->setText(0, folderName);
|
||||
item->setData(0, Qt::UserRole, folderPath);
|
||||
item->setToolTip(0, folderPath);
|
||||
item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
|
||||
}
|
||||
|
||||
pathTrail.removeFirst();
|
||||
recursiveInsert(item, pathTrail, path);
|
||||
}
|
||||
|
||||
bool FolderWizardRemotePath::selectByPath(QString path)
|
||||
{
|
||||
if (path.startsWith(QLatin1Char('/'))) {
|
||||
path = path.mid(1);
|
||||
}
|
||||
if (path.endsWith(QLatin1Char('/'))) {
|
||||
path.chop(1);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *it = _ui.folderTreeWidget->topLevelItem(0);
|
||||
if (!path.isEmpty()) {
|
||||
const QStringList pathTrail = path.split(QLatin1Char('/'));
|
||||
foreach (const QString& path, pathTrail) {
|
||||
if (!it) {
|
||||
return false;
|
||||
}
|
||||
it = findFirstChild(it, path);
|
||||
}
|
||||
}
|
||||
if (!it) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_ui.folderTreeWidget->setCurrentItem(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotUpdateDirectories(const QStringList &list)
|
||||
@@ -367,6 +409,7 @@ void FolderWizardRemotePath::slotRefreshFolders()
|
||||
SLOT(slotUpdateDirectories(QStringList)));
|
||||
job->start();
|
||||
_ui.folderTreeWidget->clear();
|
||||
_ui.folderEntry->clear();
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotItemExpanded(QTreeWidgetItem *item)
|
||||
@@ -379,6 +422,49 @@ void FolderWizardRemotePath::slotItemExpanded(QTreeWidgetItem *item)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotCurrentItemChanged(QTreeWidgetItem *item)
|
||||
{
|
||||
if (item) {
|
||||
QString dir = item->data(0, Qt::UserRole).toString();
|
||||
if (!dir.startsWith(QLatin1Char('/'))) {
|
||||
dir.prepend(QLatin1Char('/'));
|
||||
}
|
||||
_ui.folderEntry->setText(dir);
|
||||
}
|
||||
|
||||
emit completeChanged();
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotFolderEntryEdited(const QString& text)
|
||||
{
|
||||
if (selectByPath(text)) {
|
||||
_lscolTimer.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
_ui.folderTreeWidget->setCurrentItem(0);
|
||||
_lscolTimer.start(); // avoid sending a request on each keystroke
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotLsColFolderEntry()
|
||||
{
|
||||
QString path = _ui.folderEntry->text();
|
||||
if (path.startsWith(QLatin1Char('/')))
|
||||
path = path.mid(1);
|
||||
|
||||
LsColJob *job = new LsColJob(_account, path, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype");
|
||||
connect(job, SIGNAL(directoryListingSubfolders(QStringList)),
|
||||
SLOT(slotTypedPathFound(QStringList)));
|
||||
job->start();
|
||||
}
|
||||
|
||||
void FolderWizardRemotePath::slotTypedPathFound(const QStringList& subpaths)
|
||||
{
|
||||
slotUpdateDirectories(subpaths);
|
||||
selectByPath(_ui.folderEntry->text());
|
||||
}
|
||||
|
||||
FolderWizardRemotePath::~FolderWizardRemotePath()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,11 +86,17 @@ protected slots:
|
||||
void slotUpdateDirectories(const QStringList&);
|
||||
void slotRefreshFolders();
|
||||
void slotItemExpanded(QTreeWidgetItem*);
|
||||
void slotCurrentItemChanged(QTreeWidgetItem*);
|
||||
void slotFolderEntryEdited(const QString& text);
|
||||
void slotLsColFolderEntry();
|
||||
void slotTypedPathFound(const QStringList& subpaths);
|
||||
private:
|
||||
void recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path);
|
||||
bool selectByPath(QString path);
|
||||
Ui_FolderWizardTargetPage _ui;
|
||||
bool _warnWasVisible;
|
||||
AccountPtr _account;
|
||||
QTimer _lscolTimer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="3" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="folderEntry"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QFrame" name="warnFrame">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
@@ -179,7 +182,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
@@ -28,13 +28,6 @@
|
||||
|
||||
#include "updater/updater.h"
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#ifdef WITH_CRASHREPORTER
|
||||
#include "configfile.h"
|
||||
#include <libcrashreporter-handler/Handler.h>
|
||||
#endif
|
||||
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
@@ -59,12 +52,6 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
OCC::Application app(argc, argv);
|
||||
|
||||
|
||||
#ifdef WITH_CRASHREPORTER
|
||||
if (ConfigFile().crashReporter())
|
||||
new CrashReporter::Handler( QDir::tempPath(), true, CRASHREPORTER_EXECUTABLE );
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
@@ -185,8 +189,9 @@ void SocketApi::slotNewConnection()
|
||||
broadcastMessage(QLatin1String("ICON_PATH"), iconPath );
|
||||
#endif
|
||||
|
||||
foreach( QString alias, FolderMan::instance()->map().keys() ) {
|
||||
slotRegisterPath(alias);
|
||||
foreach( Folder *f, FolderMan::instance()->map() ) {
|
||||
QString message = buildRegisterPathMessage(f->path());
|
||||
sendMessage(socket, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,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();
|
||||
}
|
||||
@@ -202,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()) {
|
||||
@@ -210,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;
|
||||
}
|
||||
@@ -226,7 +231,10 @@ void SocketApi::slotRegisterPath( const QString& alias )
|
||||
{
|
||||
Folder *f = FolderMan::instance()->folder(alias);
|
||||
if (f) {
|
||||
broadcastMessage(QLatin1String("REGISTER_PATH"), f->path() );
|
||||
QString message = buildRegisterPathMessage(f->path());
|
||||
foreach(QLocalSocket *socket, _listeners) {
|
||||
sendMessage(socket, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,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;
|
||||
@@ -364,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
|
||||
|
||||
@@ -377,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.";
|
||||
@@ -405,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.";
|
||||
@@ -419,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);
|
||||
@@ -439,16 +451,24 @@ 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()));
|
||||
}
|
||||
|
||||
QString SocketApi::buildRegisterPathMessage(const QString& path)
|
||||
{
|
||||
QFileInfo fi(path);
|
||||
QString message = QLatin1String("REGISTER_PATH:");
|
||||
message.append(QDir::toNativeSeparators(fi.absoluteFilePath()));
|
||||
return message;
|
||||
}
|
||||
|
||||
SqlQuery* SocketApi::getSqlQuery( Folder *folder )
|
||||
{
|
||||
if( !folder ) {
|
||||
|
||||
@@ -37,8 +37,6 @@ class QStringList;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
typedef QLocalSocket SocketType;
|
||||
|
||||
class SyncFileStatus;
|
||||
class Folder;
|
||||
|
||||
@@ -72,23 +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);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -204,12 +204,12 @@ bool FileSystem::renameReplace(const QString& originFileName, const QString& des
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileSystem::openFileSharedRead(QFile* file, QString* error)
|
||||
bool FileSystem::openAndSeekFileSharedRead(QFile* file, QString* errorOrNull, qint64 seek)
|
||||
{
|
||||
bool ok = false;
|
||||
if (error) {
|
||||
error->clear();
|
||||
}
|
||||
QString errorDummy;
|
||||
// avoid many if (errorOrNull) later.
|
||||
QString& error = errorOrNull ? *errorOrNull : errorDummy;
|
||||
error.clear();
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//
|
||||
@@ -236,9 +236,7 @@ bool FileSystem::openFileSharedRead(QFile* file, QString* error)
|
||||
|
||||
// Bail out on error.
|
||||
if (fileHandle == INVALID_HANDLE_VALUE) {
|
||||
if (error) {
|
||||
*error = qt_error_string();
|
||||
}
|
||||
error = qt_error_string();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -247,19 +245,34 @@ bool FileSystem::openFileSharedRead(QFile* file, QString* error)
|
||||
// the fd the handle will be closed too.
|
||||
int fd = _open_osfhandle((intptr_t)fileHandle, _O_RDONLY);
|
||||
if (fd == -1) {
|
||||
if (error) {
|
||||
*error = "could not make fd from handle";
|
||||
}
|
||||
error = "could not make fd from handle";
|
||||
return false;
|
||||
}
|
||||
ok = file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle);
|
||||
#else
|
||||
ok = file->open(QFile::ReadOnly);
|
||||
#endif
|
||||
if (! ok && error) {
|
||||
*error = file->errorString();
|
||||
if (!file->open(fd, QIODevice::ReadOnly, QFile::AutoCloseHandle)) {
|
||||
error = file->errorString();
|
||||
return false;
|
||||
}
|
||||
return ok;
|
||||
|
||||
// Seek to the right spot
|
||||
LARGE_INTEGER *li = reinterpret_cast<LARGE_INTEGER*>(&seek);
|
||||
DWORD newFilePointer = SetFilePointer(fileHandle, li->LowPart, &li->HighPart, FILE_BEGIN);
|
||||
if (newFilePointer == 0xFFFFFFFF && GetLastError() != NO_ERROR) {
|
||||
error = qt_error_string();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (!file->open(QFile::ReadOnly)) {
|
||||
error = file->errorString();
|
||||
return false;
|
||||
}
|
||||
if (!file->seek(seek)) {
|
||||
error = file->errorString();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
|
||||
@@ -75,13 +75,13 @@ bool renameReplace(const QString &originFileName, const QString &destinationFile
|
||||
QString *errorString);
|
||||
|
||||
/**
|
||||
* Replacement for QFile::open(ReadOnly) that sets a more permissive sharing mode
|
||||
* on Windows.
|
||||
* Replacement for QFile::open(ReadOnly) followed by a seek().
|
||||
* This version sets a more permissive sharing mode on Windows.
|
||||
*
|
||||
* Warning: The resuting file may have an empty fileName and be unsuitable for use
|
||||
* with QFileInfo!
|
||||
* with QFileInfo! Calling seek() on the QFile with >32bit signed values will fail!
|
||||
*/
|
||||
bool openFileSharedRead(QFile* file, QString* error);
|
||||
bool openAndSeekFileSharedRead(QFile* file, QString* error, qint64 seek);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
/**
|
||||
|
||||
@@ -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) {
|
||||
@@ -232,17 +238,13 @@ bool UploadDevice::prepareAndOpen(const QString& fileName, qint64 start, qint64
|
||||
|
||||
QFile file(fileName);
|
||||
QString openError;
|
||||
if (!FileSystem::openFileSharedRead(&file, &openError)) {
|
||||
if (!FileSystem::openAndSeekFileSharedRead(&file, &openError, start)) {
|
||||
setErrorString(openError);
|
||||
return false;
|
||||
}
|
||||
|
||||
size = qMin(FileSystem::getSize(fileName), size);
|
||||
size = qBound(0ll, size, FileSystem::getSize(fileName) - start);
|
||||
_data.resize(size);
|
||||
if (!file.seek(start)) {
|
||||
setErrorString(file.errorString());
|
||||
return false;
|
||||
}
|
||||
auto read = file.read(_data.data(), size);
|
||||
if (read != size) {
|
||||
setErrorString(file.errorString());
|
||||
@@ -406,6 +408,7 @@ void PropagateUploadFileQNAM::startNextChunk()
|
||||
return;
|
||||
}
|
||||
|
||||
// job takes ownership of device via a QScopedPointer. Job deletes itself when finishing
|
||||
PUTFileJob* job = new PUTFileJob(_propagator->account(), _propagator->_remoteFolder + path, device, headers, _currentChunk);
|
||||
_jobs.append(job);
|
||||
connect(job, SIGNAL(finishedSignal()), this, SLOT(slotPutFinished()));
|
||||
@@ -521,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));
|
||||
@@ -592,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;
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
|
||||
#include <csync.h>
|
||||
|
||||
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG) && (__GNUC__ * 100 + __GNUC_MINOR__ < 408)
|
||||
// openSuse 12.3 didn't like enum bitfields.
|
||||
#define BITFIELD(size)
|
||||
#else
|
||||
#define BITFIELD(size) :size
|
||||
#endif
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class SyncFileItem {
|
||||
@@ -114,19 +121,19 @@ public:
|
||||
// Variables usefull for everybody
|
||||
QString _file;
|
||||
QString _renameTarget;
|
||||
Type _type:3;
|
||||
Direction _direction:2;
|
||||
bool _isDirectory:1;
|
||||
Type _type BITFIELD(3);
|
||||
Direction _direction BITFIELD(2);
|
||||
bool _isDirectory BITFIELD(1);
|
||||
|
||||
/// Whether there's an entry in the blacklist table.
|
||||
/// Note: that entry may have retries left, so this can be true
|
||||
/// without the status being FileIgnored.
|
||||
bool _hasBlacklistEntry:1;
|
||||
bool _hasBlacklistEntry BITFIELD(1);
|
||||
|
||||
// Variables usefull to report to the user
|
||||
Status _status:4;
|
||||
bool _isRestoration:1; // The original operation was forbidden, and this is a restoration
|
||||
bool _should_update_etag:1;
|
||||
Status _status BITFIELD(4);
|
||||
bool _isRestoration BITFIELD(1); // The original operation was forbidden, and this is a restoration
|
||||
bool _should_update_etag BITFIELD(1);
|
||||
quint16 _httpErrorCode;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
QByteArray _responseTimeStamp;
|
||||
@@ -155,8 +162,8 @@ public:
|
||||
time_t _other_modtime;
|
||||
QByteArray _other_etag;
|
||||
QByteArray _other_fileId;
|
||||
enum csync_instructions_e _instruction:16;
|
||||
enum csync_instructions_e _other_instruction:16;
|
||||
enum csync_instructions_e _instruction BITFIELD(16);
|
||||
enum csync_instructions_e _other_instruction BITFIELD(16);
|
||||
} log;
|
||||
};
|
||||
|
||||
|
||||
@@ -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,12 +1784,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"/>
|
||||
@@ -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>
|
||||
@@ -1909,7 +1915,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>
|
||||
@@ -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"/>
|
||||
@@ -2218,7 +2224,7 @@ 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"/>
|
||||
@@ -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>
|
||||
@@ -244,27 +244,27 @@ Total tid kvar %5</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="35"/>
|
||||
<source>Certificate :</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Certifikat :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="51"/>
|
||||
<source>Browse...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Bläddra...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.ui" line="60"/>
|
||||
<source>Certificate password :</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Certifikatlösenord :</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.cpp" line="23"/>
|
||||
<source>Select a certificate</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Välj ett certifikat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/addcertificatedialog.cpp" line="23"/>
|
||||
<source>Certificate files (*.p12 *.pfx)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Certifikatfiler (*.p12 *.pfx)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -329,7 +329,7 @@ Total tid kvar %5</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotedelete.cpp" line="41"/>
|
||||
<source>Connection timed out</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tidsgräns för anslutningen överskreds</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -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"/>
|
||||
@@ -898,7 +898,7 @@ Valda objekt kommer också att raderas om dom hindrar en mapp från att tas bort
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateremotemove.cpp" line="45"/>
|
||||
<source>Connection timed out</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tidsgräns för anslutningen överskreds</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1131,7 +1131,7 @@ efter ytterligare privilegier under processen.</translation>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.cpp" line="297"/>
|
||||
<location filename="../src/gui/wizard/owncloudadvancedsetuppage.cpp" line="318"/>
|
||||
<source>(%1)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>(%1)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -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>
|
||||
@@ -1535,7 +1535,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="156"/>
|
||||
<source>File Removed</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Filen Raderad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libsync/propagateupload.cpp" line="171"/>
|
||||
@@ -1792,12 +1792,12 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="127"/>
|
||||
<source>Set password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ange lösenord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.ui" line="149"/>
|
||||
<source>Set expiry date</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Sätt utgångsdatum</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="67"/>
|
||||
@@ -1813,7 +1813,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="141"/>
|
||||
<source>Password Protected</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Lösenordsskyddad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="299"/>
|
||||
@@ -1858,7 +1858,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="453"/>
|
||||
<source>The file can not be synced.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Filen kan inte synkas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gui/sharedialog.cpp" line="463"/>
|
||||
@@ -1908,7 +1908,7 @@ Det är inte lämpligt använda den.</translation>
|
||||
<location filename="../src/gui/socketapi.cpp" line="431"/>
|
||||
<source>Share with %1</source>
|
||||
<comment>parameter is ownCloud</comment>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dela med %1</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