1
0
mirror of https://github.com/chylex/Nextcloud-Desktop.git synced 2026-04-05 14:34:16 +02:00

Compare commits

..

88 Commits

Author SHA1 Message Date
Daniel Molkentin
7cd2f39f82 ChangeLog 2013-06-25 10:37:40 +02:00
Jenkins for ownCloud
949dd5db35 [tx-robot] updated from transifex 2013-06-25 01:45:02 +02:00
Jenkins for ownCloud
49a5c5bb8b [tx-robot] updated from transifex 2013-06-24 23:05:09 +02:00
Jenkins for ownCloud
48aa355eea [tx-robot] updated from transifex 2013-06-24 23:01:20 +02:00
Daniel Molkentin
644b2673e0 More whitespace changes 2013-06-24 23:00:33 +02:00
Jenkins for ownCloud
8eed62e639 [tx-robot] updated from transifex 2013-06-24 22:58:54 +02:00
Daniel Molkentin
04c8449e5f String whitespace fixes 2013-06-24 22:58:00 +02:00
Jenkins for ownCloud
016868e95a [tx-robot] updated from transifex 2013-06-24 21:43:58 +02:00
Daniel Molkentin
a662c85728 Add "Reset Folder" option to status dialog
to recover from invalid databases. Features
a big fat warning.
2013-06-24 21:17:00 +02:00
Markus Goetz
12cc8bfd95 Raise setup wizard 2013-06-24 15:15:46 +02:00
Markus Goetz
11c6f20c90 Setup Dialog: Fix widget size issue (2) 2013-06-24 14:57:48 +02:00
Markus Goetz
c602ec310d Setup Dialog: Fix widget size issue
in advanced settings
2013-06-24 13:24:46 +02:00
Daniel Molkentin
b206a3b8e2 Beta4 2013-06-20 21:01:38 +02:00
Daniel Molkentin
3bff5a061b Network: Display actual error message next to code. 2013-06-20 20:02:25 +02:00
Daniel Molkentin
0bc9b6f44e Revert "Do not store the redirected URL in the config file."
This reverts commit 905f70a186.

Patch still has issues, defer until after Beta 4
2013-06-20 19:50:34 +02:00
Olivier Goffart
905f70a186 Do not store the redirected URL in the config file.
Because it may be a temporary URL.
Especially anoying in captive portal

Fix issue #368
2013-06-20 17:50:02 +02:00
Olivier Goffart
a8707b681d Report proper error when csync_init fails
Fix mirall issue #705
2013-06-19 18:17:32 +02:00
Olivier Goffart
5d8f9f5346 Silent clang warning 2013-06-19 18:16:43 +02:00
Daniel Molkentin
a441b1d562 Bump year 2013-06-19 16:07:07 +02:00
Daniel Molkentin
6e2042cd55 Doc: Expand usage page 2013-06-19 16:04:48 +02:00
Daniel Molkentin
bb8b58dc66 Doc: more fixes on troubleshooting section 2013-06-19 15:48:04 +02:00
Daniel Molkentin
9cd099056b Doc: More structure in troubleshooting.rst 2013-06-19 15:40:20 +02:00
Daniel Molkentin
0adbc032ae Doc: Expand trouble shooting section 2013-06-19 15:40:15 +02:00
Daniel Molkentin
22a679fb8c Doc: Add back --logfile, as it still exists 2013-06-19 15:40:09 +02:00
Daniel Molkentin
35a67fab0a Doc: remove now meaningless scentences 2013-06-19 15:40:06 +02:00
Daniel Molkentin
fdc8117211 doc: Fix wording 2013-06-19 15:40:02 +02:00
Daniel Molkentin
24208e6137 Remove mirall man page 2013-06-19 15:39:56 +02:00
Daniel Molkentin
46c7026726 Answer correctly if proxy auth is needed
Fixes #704
2013-06-19 12:48:36 +02:00
Daniel Molkentin
01ad3c4d81 Remove more dead code for readability 2013-06-19 11:31:09 +02:00
Daniel Molkentin
4ac98bde73 Remove dead code from StatusDialog 2013-06-18 17:38:20 +02:00
Daniel Molkentin
f42a6d6ef6 Advertise the use of Gists for long logs 2013-06-18 15:21:56 +02:00
Daniel Molkentin
9055c6ade7 Add storage backend field to issue template 2013-06-18 14:57:12 +02:00
Olivier Goffart
1356a5bbaa Fix reading the password from the config
The code was expecting pwdba to be in base64, which it was not if it
came from the "password" field
2013-06-18 14:19:37 +02:00
Olivier Goffart
3c320c2736 Credidentail dialog: it was suposed to be asynchronous 2013-06-18 14:19:37 +02:00
Olivier Goffart
969757199e Fix changing the password when the password manager is not available
Leaving the state in NoKeychainBackend would break any further attempt
to get the password because CredentialStore::canTryAgain would return
false.
2013-06-18 14:19:37 +02:00
Daniel Molkentin
60f1c65a48 Don't lose proxy settings when changing passwords 2013-06-17 14:25:11 +02:00
Daniel Molkentin
b87b0e16e6 Avoid infinite loop if authcheck fails 2013-06-17 13:35:54 +02:00
Daniel Molkentin
8ed0b1be55 Teach ownCloud theme about QVariant 2013-06-13 16:31:38 +02:00
Daniel Molkentin
91b5f1076f Theming cleanups
- remove splash screen pixmap
- remove backend icon (folderIcon())
- Move owncloud ad into owncloud theme
2013-06-13 12:56:20 +02:00
Daniel Molkentin
8ec2457965 Only change subtitle if the config file actually exists 2013-06-13 12:55:07 +02:00
Daniel Molkentin
82d79b1188 Remove folder from the scheduling queue
Not really needed, but cleaner
2013-06-12 12:42:02 +02:00
Olivier Goffart
e33601becd Fix leak 2013-06-12 12:23:12 +02:00
Olivier Goffart
334443adbb Fix crash when removing a folder
The problem is that the module_property of csync are not really tight to
a context, but are global to all the contextes.
Which means csync_owncloud may still have a pointer to the destroyed
context of the destroyed folder.
By always resetting the context pointer, we make sure there is no stale
pointers there
2013-06-12 12:23:12 +02:00
Daniel Molkentin
99579e8a2a 1.3.0beta3 2013-06-12 11:10:08 +02:00
Daniel Molkentin
89438f7ace Make SyncDisabler local to slotAddFolder
This also allows us to update the folder state as
soon as the wizard is being closed.
2013-06-12 09:27:20 +02:00
Daniel Molkentin
d323ec5dd9 FileItemDialog: more clarity in the label
- finished %n sec ago -> last finished %n sec ago
- switch to minutes after 60 seconds
2013-06-11 22:34:37 +02:00
Daniel Molkentin
bb5cf37330 Fix issues found after review
- use safer formatting
- remove unnecessary condition
2013-06-11 22:33:11 +02:00
Daniel Molkentin
4b0bdd648c Do not repeat old strings
Fixes #678, fixes #494
2013-06-11 22:14:32 +02:00
Olivier Goffart
5588fbe695 Fix clicking on the systray when the setup is not finished
We should raise the wizard
2013-06-11 21:32:44 +02:00
Olivier Goffart
12ea381205 Do not re-use the configuration wizard.
Create it on demand.
This allow yo alays keep a cleen state.
Mirall issue #668
2013-06-11 21:15:37 +02:00
Daniel Molkentin
99fbf25fb2 Keep the member variable, avoids double instanciation 2013-06-11 18:41:35 +02:00
Daniel Molkentin
b37645e14d Revert "Put FolderWizard on the stack"
This reverts commit 1ec5a1aaa2.
2013-06-11 18:33:39 +02:00
Daniel Molkentin
1ec5a1aaa2 Put FolderWizard on the stack 2013-06-11 18:19:09 +02:00
Daniel Molkentin
3eb7acde25 Folder wizard: use native separators in path lineedit 2013-06-11 18:18:38 +02:00
Daniel Molkentin
e53e39cfad Remove obsolete members from enum 2013-06-11 18:17:34 +02:00
Daniel Molkentin
1a17f40233 Remove debug 2013-06-11 18:17:22 +02:00
Daniel Molkentin
10094a997a Proxy Dialog: default to port 8080 2013-06-11 17:46:00 +02:00
Daniel Molkentin
2af38b093f Fix status delegate
- remove magic values
- remove backend icon, put status icon in the front
- elide text when > list view width
- use list view font
2013-06-11 14:46:12 +02:00
Daniel Molkentin
b03c168175 Status dialog> Do not adjust pen when using Vista Style
Light blue and white are not contrasting enough
2013-06-10 21:29:45 +02:00
Daniel Molkentin
1c6bc84d2d Wizard: Always initialize all labels 2013-06-10 21:29:45 +02:00
Olivier Goffart
541239c17b Make the message box more explicit when all files have been removed
Also clean the db if the user wish to keep the files
2013-06-10 15:58:02 +02:00
Daniel Molkentin
74b4ade15a Add missing return statement 2013-06-10 15:37:52 +02:00
Daniel Molkentin
205502fd3b Fix incorrect license attribution
Fixes #672
2013-06-10 07:42:35 +02:00
Daniel Molkentin
54e4217216 Add Missing LGPL_EXCEPTION.txt
Fixes #671
2013-06-10 07:38:35 +02:00
Olivier Goffart
d2579a7754 Warn if we detect that all fles are about to be removed. 2013-06-08 15:41:53 +02:00
Daniel Molkentin
76580840dd Fix misleading confirmation message
Fixes #459
2013-06-07 22:01:26 +02:00
Olivier Goffart
779e59156c Added --logexpire to remove the log after some hours 2013-06-07 18:58:16 +02:00
Daniel Molkentin
b0f0d0b1cd qDebug() ises local8bit, not utf-8.
Fixes #651
2013-06-07 17:28:04 +02:00
Daniel Molkentin
858dcb53bd Status dialog delegate: Use font from option 2013-06-06 22:12:18 +02:00
Daniel Molkentin
9d7db88fcb status dialog: Use contrast color for highlights
Fixes #440.
2013-06-06 22:11:36 +02:00
Daniel Molkentin
2099b7c6a0 ensureJournalGone: fix logic 2013-06-06 21:43:05 +02:00
Daniel Molkentin
4442564ad2 Clean up slotAddFolder
Ensure folder sync scheduling is off in the meanwhile.
2013-06-06 21:27:15 +02:00
Daniel Molkentin
12148b5c9b remove journal when adding a new sync on an existing folder 2013-06-06 17:59:50 +02:00
Daniel Molkentin
d7d77a49fc Show help on Windows
We have no console, so show a message box.
2013-06-06 16:00:51 +02:00
Daniel Molkentin
b70c2f5c20 torture scripts: fix description 2013-06-06 11:05:21 +02:00
Daniel Molkentin
033249423f Add torture scripts + standard layout files 2013-06-05 21:36:55 +02:00
Daniel Molkentin
0c959e8661 Windows: Log change of power state 2013-06-05 16:14:20 +02:00
Daniel Molkentin
79785241ea Docs: --logdir replaces --logfile 2013-06-05 14:57:32 +02:00
Daniel Molkentin
0090862313 wizard: show native separators on folder chooser button 2013-06-04 00:46:34 +02:00
Daniel Molkentin
a4a68c6622 Wizard: Better wording when renaming failes 2013-06-03 23:34:28 +02:00
Klaas Freitag
49b4c341ae Really unload folders before reconfiguring. 2013-06-03 17:27:06 +02:00
Olivier Goffart
7c1f91abdd Add the --logdir commandline option
To log to a different file for every sync.

This also changed a QueuedConnection to AutoConnection, that way we
directly save the log from the main thread in the file without waiting
for the event loop (so if it crashes before, the log has been writen)
2013-06-03 16:25:41 +02:00
Klaas Freitag
1f2ba7e254 Handle rename fails for backup reasons correctly. 2013-06-03 15:47:39 +02:00
Klaas Freitag
8014bcb7c4 Check for emptiness before backuping the entire dir. 2013-06-03 15:47:07 +02:00
Klaas Freitag
b1c8bf5954 Fix backup name generation. 2013-06-03 15:46:41 +02:00
Klaas Freitag
0eb6740bac Added default argument to terminateSyncProcess 2013-06-03 15:46:11 +02:00
Klaas Freitag
96531b548a Minor Cleanups. 2013-06-03 15:45:28 +02:00
Klaas Freitag
f3371360ed Check the CredentialStore state before fetching creds again. 2013-06-03 15:44:58 +02:00
75 changed files with 26241 additions and 12022 deletions

View File

@@ -1,5 +1,32 @@
ChangeLog
=========
version 1.3.0 (release 2013-06-25 ), csync 0.80.0 required
* Default proxy port to 8080
* Don't lose proxy settings when changing passwords
* Support SOCKS5 proxy (useful in combination with ssh *D)
* Propagate proxy changes to csync at runtime
* Improve proxy wizard
* Display proxy errors
* Solved problems with lock files
* Warn if for some reason all files are scheduled for removal on either side
* Avoid infinite loop if authentication fails in certain cases
* Fix reading the password from the config in certain cases
* Do not crash when configured sync target disappears
* Make --help work on windows
* Make sync feedback less ambiguous.
* Fix icon tray tooltip sometimes showing repeated content
* More use of native directory separators on Windows
* Remove journal when reusing a directory that used to have a journal before
* Visual clean up of status dialog items
* Wizard: When changing the URL or user name, allow the user to push his data
to the new location or wipe the folder and start from scratch
* Wizard: Make setting a custom folder as a sync target work again
* Fix application icon
* User-Agent now contains "Mozilla/5.0" and the Platform name (for firewall/proxy compat)
* Server side directory moves will be detected
* New setup wizard, defaulting to root syncing (only for new setups)
* Improved thread stop/termination
version 1.2.5 (release 2013-04-23 ), csync 0.70.7 required
* [Fixes] NSIS installer fixes

View File

@@ -1,6 +1,6 @@
set( VERSION_MAJOR 1 )
set( VERSION_MINOR 3 )
set( VERSION_PATCH 0 )
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX}beta2)
set( VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${VERSION_SUFFIX})
set( SOVERSION 0 )

View File

@@ -41,7 +41,7 @@ master_doc = 'index'
# General information about the project.
project = u'ownCloud Client Manual'
copyright = u'2012, The ownCloud developers'
copyright = u'2013, The ownCloud developers'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -215,8 +215,6 @@ latex_documents = [
man_pages = [
('owncloud.1', 'owncloud', u'File synchronisation desktop utility.',
[u'The ownCloud developers'], 1),
('mirall.1', 'mirall', u'File synchronisation desktop utility.',
[u'The ownCloud developers'], 1)
]
# If true, show URL addresses after external links.
@@ -250,7 +248,7 @@ texinfo_documents = [
epub_title = u'ownCloud Client Manual'
epub_author = u'The ownCloud developers'
epub_publisher = u'The ownCloud developers'
epub_copyright = u'2012, The ownCloud developers'
epub_copyright = u'2013, The ownCloud developers'
# The language of the text. It defaults to the language option
# or en if the language is not set.

View File

@@ -16,8 +16,6 @@ It contains settings in the ini file format known from Windows.
.. note:: Changes may be overwritten by using ownCloud's configuration dialog.
.. note:: The new version is less precise in this regard.
These are config settings that may be changed:
``remotePollinterval`` (default: ``30000``)
@@ -26,6 +24,3 @@ These are config settings that may be changed:
``maxLogLines`` (default: ``20000``)
Maximum count of log lines shown in the log window
``remotePollinterval``
The frequency used for polling for remote changes on the ownCloud Server.

View File

@@ -19,7 +19,7 @@ Mac OS X
Installing the ownCloud client on your Mac follows the normal app installation
pattern:
1. Download the installation file Click ownCloud-1.1.1.dmg, a window with the
1. Download the installation file Click ownCloud-x.y.z.dmg, a window with the
2. ownCloud icon opens In that window, drag the ownCloud application into the
3. Applications folder on the right hand side From Applications, choose
ownCloud

View File

@@ -1,38 +0,0 @@
mirall(1)
---------
SYNOPSIS
========
*mirall* [`OPTIONS`...]
DESCRIPTION
===========
mirall is a file synchronisation desktop utility.
It synchronizes files on your local machine with an ownCloud Server. If you
make a change to the files on one computer, it will flow across the others
using this desktop sync clients.
Normally you start the client by click on the desktop icon or start from the
application menu. After starting an ownCloud icon appears in the system tray.
Options
=======
.. include:: options.rst
Config File
===========
.. include:: conffile.rst
BUGS
====
Please report bugs at https://github.com/owncloud/core/issues.
SEE ALSO
========
`csync(1)`, `mirall(1)`

View File

@@ -3,8 +3,11 @@ ownCloud Client supports the following command line switches:
``--logwindow``
open a window to show log output at startup.
``--logfile`` `<filename>`
write log output to file.
``--logfile`` `<file>`
write log output to a single file
``--logdir`` `<dir>`
write log output to dir, one for each sync run.
``--flushlog``
flush the log file after every write.
@@ -12,4 +15,3 @@ ownCloud Client supports the following command line switches:
``--monoicons``
Use black/white pictograms for systray.

View File

@@ -9,7 +9,7 @@ SYNOPSIS
DESCRIPTION
===========
owncloud is a file synchronisation desktop utility it is based on mirall.
ownCloud is a file synchronisation desktop utility based on mirall.
It synchronizes files on your local machine with an ownCloud Server. If you
make a change to the files on one computer, it will flow across the others
using this desktop sync clients.
@@ -33,5 +33,5 @@ Please report bugs at https://github.com/owncloud/core/issues.
SEE ALSO
========
`csync(1)`, `mirall(1)`
`csync(1)`

View File

@@ -4,9 +4,12 @@ Doc Build Convenience Scripts
* ``htmlhelp.sh``: A script to install Microsoft HTML Workshop on Linux or Mac OS using Wine, along with some dependencies.
* ``htmlhelp.reg``: Registry file to override some DLLs with their native version and set the right Windows version.
Those files have been taken from the HTML Help Project (http://code.google.com/p/htmlhelp/wiki/HHW4Wine).
Those files have been taken from the `HTML Help Project`_.
License
-------
The HTML Help Project has licensed its software under LGPLv3 terms.
The HTML Help Project has licensed_ its software under LGPLv2.1 terms
.. _HTML Help Project: http://code.google.com/p/htmlhelp/wiki/HHW4Wine
.. _licensed: https://code.google.com/p/htmlhelp/source/browse/trunk/pyhtmlhelp/COPYING

View File

@@ -6,9 +6,10 @@ basic reasons: Either the server setup has a problem or the client
has a bug. When reporting bugs, it is crucial to find out what part
of the system causes the problem.
Here are a couple of useful steps to isolate the problem.
Identifying basic functionality problems
----------------------------------------
:A general ownCloud Server test:
:Perform a general ownCloud Server test:
A very first check is to verify that you can log on to ownClouds web
application. Assuming your ownCloud instance is installed at
``http://yourserver.com/owncloud``, type
@@ -18,8 +19,12 @@ Here are a couple of useful steps to isolate the problem.
see a red warning box on the page, your server setup is not correct or needs
fixes. Please verify that your server installation is working correctly.
:All desktop clients fail to connect to ownCloud:
The ownCloud syncing use the built in WebDAV server of ownCloud.
:Ensure the WebDAV API is working:
If all desktop clients fail to connect to ownCloud, but the access via the
web interface works, the problem often is a mis-configuration of the WebDAV
API.
The ownCloud client uses the built-in WebDAV access of the server content.
Verify that you can log on to ownClouds WebDAV server. Assuming your ownCloud
instance is installed at ``http://yourserver.com/owncloud``, type
``http://yourserver.com/owncloud/remote.php/webdav`` into your browsers
@@ -31,17 +36,38 @@ Here are a couple of useful steps to isolate the problem.
:Use a WebDAV command line tool to test:
A more sophisticated test is to use a WebDAV command line client and log
into the ownCloud WebDAV server, such as a little app called cadaver, available
on Linux. It can be used to further verify that the WebDAV server is running
properly, for example by performing PROPFIND calls:
into the ownCloud WebDAV server, such as a little app called cadaver,
available on Linux. It can be used to further verify that the WebDAV server is
running properly, for example by performing PROPFIND calls:
``propget .`` called within cadaver will return some properties of the current
directory and thus be a successful WebDAV connect.
Isolating other issues
----------------------
If the sync result is unreliable, please ensure that the folder synced with
ownCloud is not shared with other syncing apps.
.. note:: Syncing the same directory with ownCloud and other sync software such
as Unison, rsync, Microsoft Windows Offline Folders or cloud services
such as DropBox or Microsoft SkyDrive is not supported and should
not be attempted. In the worst case, doing so can result in data
loss.
If you are operating your own server and use the local storage backend (the
default), make sure that ownCloud has exclusive access to the directory.
.. note:: The data directory on the server is exclusive to ownCloud and must
not be modified manually.
If you are using a different backend, you can try to exclude a bug in the
backend by reverting to the local backend.
Logfiles
========
Doing effective debugging requires to provide as much as relevant logfiles as
Doing effective debugging requires to provide as much as relevant logs as
possible. The log output can help you with tracking down problem, and if you
report a bug, you're advised to include the output.
@@ -57,23 +83,27 @@ starting the client again with this parameter. Syntax:
* Mac OS X: ``/Applications/owncloud.app/Contents/MacOS/owncloud --logwindow``
* Linux: ``owncloud --logwindow``
It is also possible to directly log into a file, which is an useful option
It is also possible to directly log to a directory, which is an useful option
in case the problem only happens ocassionally. In that case it is better to
create a huge logfile than piping the whole log through the log window.
create a huge amount of data, as the log window has a limited buffer.
To create a log file, start the client with ``--logfile <filename>``.
To write logs to disk, start the client with ``--logfile <file>``, where
``<file`` is the file you want to log to, or ``--logdir <dir>``, where ``<dir>``
is an existing directory. In case of ``--logdir``, each sync run will create a
new file.
:ownCloud server Logfile:
The ownCloud server maintains an ownCloud specific logfile as well. It can and
must be enabled through the ownCloud Administration page. There you can adjust
the loglevel. It is advisable to set it to a verbose level like ``Debug`` or ``Info``.
the loglevel. It is advisable to set it to a verbose level like ``Debug`` or
``Info``.
The logfile can be viewed either in the web interface or can be found in the
filesystem in the ownCloud server data dir.
:Webserver Logfiles:
Also, please take a look at your webservers error log file to check if there
are problems. For apache on linux, the error logs usually can be found at
are problems. For Apache on Linux, the error logs usually can be found at
``/var/log/apache2``. A file called ``error_log`` shows errors like PHP code
problems. A file called ``access_log`` usually records all requests handled
by the server. Especially the access_log is a very good debugging tool as the
@@ -82,4 +112,3 @@ log line contains a lot of information of every request and it's result.
More information about the apache logging can be found at
``http://httpd.apache.org/docs/current/logs.html``.

View File

@@ -7,11 +7,42 @@ application menu. In the system tray, an ownCloud icon appears.
.. index:: start application
A left click on the tray icon open a status dialog which gives an overview on
the configured sync folders and allows to add and remove more sync folder
connections as well as pausing a sync connection.
Overview
--------
A right click on the tray icon gives other configuration options.
ownCloud is represented by an icon in the Desktop's system tray, also known
as notification area.
The clients menu is accessed with a right click (Windows, Linux) or left click
(Mac OS).
The status of the current sync can be observed in the Status dialog, available
trough the ``Open status...`` option. On Windows, a left click on the tray icon
also opens the status dialog.
.. note:: Until the intial setup has finished, the Connection Wizard will be
shown instead when left-clicking on Windows.
The dialog provides an overview on the configured sync folders and allows to add
and remove more sync folder connections as well as pausing a sync connection.
Changing your password
----------------------
Use the ``Configure`` option. It will open the Connection Wizard, which next to
reconfiguring your connection to use a different user or server also will allow
to change the password for the local account, or to switch from HTTP to HTTPS.
Setting up a proxy
------------------
By default, the configured system proxy will be picked up. This may not be
working reliable on some Linux distributions, as only the ``http_proxy``
variable gets parsed. You can configure a proxy different from your
system default by choosing ``Configure proxy...`` from the menu.
By default, ownCloud expects a HTTP proxy. If you want to specify a SOCKS5
proxy instead, tick the "Use as SOCKSv5 proxy" option.
Options
-------

View File

@@ -20,6 +20,8 @@ PHP version:
ownCloud version:
Storage backend:
### Client configuration
Client version:
@@ -31,18 +33,14 @@ Installation path of client:
### Logs
#### output of `owncloud --logwindow` or `owncloud --logfile log.txt`
```
Insert your log output here
```
Please use Gist (https://gist.github.com/) or a similar code paster for longer
logs.
#### Web server error log
```
Insert your webserver log here
```
```Template for output < 10 lines```
#### ownCloud log (data/owncloud.log)
```
Insert your ownCloud log here
```
1. Output of `owncloud --logwindow` or `owncloud --logfile log.txt`
2. Web server error log:
3. ownCloud log (data/owncloud.log):

View File

@@ -9,6 +9,7 @@
<file>resources/folder-grey.png</file>
<file>resources/task-ongoing.png</file>
<file>resources/view-refresh.png</file>
<file>resources/warning-16.png</file>
<file>resources/owncloud_logo_blue.png</file>
</qresource>
</RCC>

BIN
resources/warning-16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

22
src/3rdparty/LGPL_EXCEPTION.txt vendored Normal file
View File

@@ -0,0 +1,22 @@
Digia Qt LGPL Exception version 1.1
As an additional permission to the GNU Lesser General Public License version
2.1, the object code form of a "work that uses the Library" may incorporate
material from a header file that is part of the Library. You may distribute
such object code under terms of your choice, provided that:
(i) the header files of the Library have not been modified; and
(ii) the incorporated material is limited to numerical parameters, data
structure layouts, accessors, macros, inline functions and
templates; and
(iii) you comply with the terms of Section 6 of the GNU Lesser General
Public License version 2.1.
Moreover, you may apply this exception to a modified version of the Library,
provided that such modification does not involve copying material from the
Library into the modified Library's header files unless such material is
limited to (i) numerical parameters; (ii) data structure layouts;
(iii) accessors; and (iv) small macros, templates and inline functions of
five lines or less in length.
Furthermore, you are not required to apply this additional permission to a
modified version of the Library.

View File

@@ -34,6 +34,10 @@
#include "mirall/inotify.h"
#if defined(Q_OS_WIN)
#include <windows.h>
#endif
#include <QtCore>
#include <QtGui>
#include <QHash>
@@ -50,10 +54,26 @@ namespace Mirall {
void mirallLogCatcher(QtMsgType type, const char *msg)
{
Q_UNUSED(type)
Logger::instance()->mirallLog( QString::fromUtf8(msg) );
// qDebug() exports to local8Bit, which is not always UTF-8
Logger::instance()->mirallLog( QString::fromLocal8Bit(msg) );
}
namespace {
static const char optionsC[] =
"Options:\n"
" -h --help : show this help screen.\n"
" --logwindow : open a window to show log output.\n"
" --logfile <filename> : write log output to file <filename>.\n"
" --logdir <name> : write each sync log output in a new file\n"
" in directory <name>.\n"
" --logexpire <hours> : removes logs older than <hours> hours.\n"
" (to be used with --logdir)\n"
" --logflush : flush the log file after every write.\n"
" --monoicons : Use black/white pictograms for systray.\n"
" --confdir <dirname> : Use the given configuration directory.\n"
;
QString applicationTrPath()
{
#ifdef Q_OS_LINUX
@@ -82,11 +102,13 @@ Application::Application(int &argc, char **argv) :
_theme(Theme::instance()),
_updateDetector(0),
_logBrowser(0),
_logExpire(0),
_showLogWindow(false),
_logFlush(false),
_helpOnly(false),
_fileItemDialog(0),
_statusDialog(0)
_statusDialog(0),
_folderWizard(0)
{
setApplicationName( _theme->appNameGUI() );
setWindowIcon( _theme->applicationIcon() );
@@ -113,17 +135,13 @@ Application::Application(int &argc, char **argv) :
setQuitOnLastWindowClosed(false);
_folderWizard = new FolderWizard;
_owncloudSetupWizard = new OwncloudSetupWizard( _folderMan, _theme, this );
connect( _owncloudSetupWizard, SIGNAL(ownCloudWizardDone(int)),
this, SLOT(slotownCloudWizardDone(int)));
_statusDialog = new StatusDialog( _theme );
connect( _statusDialog, SIGNAL(addASync()), this, SLOT(slotAddFolder()) );
connect( _statusDialog, SIGNAL(removeFolderAlias( const QString&)),
SLOT(slotRemoveFolder(const QString&)));
connect( _statusDialog, SIGNAL(resetFolderAlias( const QString&)),
SLOT(slotResetFolder(const QString&)));
connect( _statusDialog, SIGNAL(enableFolderAlias(QString,bool)),
SLOT(slotEnableFolder(QString,bool)));
connect( _statusDialog, SIGNAL(infoFolderAlias(const QString&)),
@@ -190,7 +208,7 @@ void Application::slotStartFolderSetup( int result )
ownCloudInfo::instance()->checkInstallation();
} else {
_owncloudSetupWizard->startWizard();
slotConfigure();
}
} else {
qDebug() << "Setup Wizard was canceled. No reparsing of config.";
@@ -246,23 +264,28 @@ void Application::slotFetchCredentials()
{
QString trayMessage;
if( CredentialStore::instance()->canTryAgain() ) {
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
this, SLOT(slotCredentialsFetched(bool)) );
CredentialStore::instance()->fetchCredentials();
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
trayMessage = tr("Too many incorrect password attempts.");
}
if( CredentialStore::instance()->state() == CredentialStore::Ok ) {
// the credentials are still valid and ok.
slotCredentialsFetched( true );
} else {
qDebug() << "Can not try again to fetch Credentials.";
trayMessage = tr("%1 user credentials are wrong. Please check configuration.")
.arg(Theme::instance()->appNameGUI());
}
if( CredentialStore::instance()->canTryAgain() ) {
connect( CredentialStore::instance(), SIGNAL(fetchCredentialsFinished(bool)),
this, SLOT(slotCredentialsFetched(bool)) );
CredentialStore::instance()->fetchCredentials();
if( CredentialStore::instance()->state() == CredentialStore::TooManyAttempts ) {
trayMessage = tr("Too many incorrect password attempts.");
}
} else {
qDebug() << "Can not try again to fetch Credentials.";
trayMessage = tr("%1 user credentials are wrong. Please check configuration.")
.arg(Theme::instance()->appNameGUI());
}
if( !trayMessage.isEmpty() ) {
_tray->showMessage(tr("Credentials"), trayMessage);
_actionOpenStatus->setEnabled( false );
_actionAddFolder->setEnabled( false );
if( !trayMessage.isEmpty() ) {
_tray->showMessage(tr("Credentials"), trayMessage);
_actionOpenStatus->setEnabled( false );
_actionAddFolder->setEnabled( false );
}
}
}
@@ -352,8 +375,6 @@ void Application::slotAuthCheck( const QString& ,QNetworkReply *reply )
_actionAddFolder->setEnabled( true );
_actionOpenStatus->setEnabled( true );
setupContextMenu();
} else {
slotFetchCredentials();
}
}
@@ -402,6 +423,7 @@ void Application::slotownCloudWizardDone( int res )
}
_folderMan->setSyncEnabled( true );
slotStartFolderSetup( res );
_owncloudSetupWizard.reset(0);
}
void Application::setupActions()
@@ -521,7 +543,9 @@ void Application::setupLogBrowser()
_logBrowser = new LogBrowser;
qInstallMsgHandler( mirallLogCatcher );
// ## TODO: allow new log name maybe?
if (!_logFile.isEmpty()) {
if (!_logDirectory.isEmpty()) {
enterNextLogFile();
} else if (!_logFile.isEmpty()) {
qDebug() << "Logging into logfile: " << _logFile << " with flush " << _logFlush;
_logBrowser->setLogFile( _logFile, _logFlush );
}
@@ -537,6 +561,37 @@ void Application::setupLogBrowser()
}
void Application::enterNextLogFile()
{
if (_logBrowser && !_logDirectory.isEmpty()) {
QDir dir(_logDirectory);
if (!dir.exists()) {
dir.mkpath(".");
}
// Find out what is the file with the highest nymber if any
QStringList files = dir.entryList(QStringList("owncloud.log.*"),
QDir::Files);
QRegExp rx("owncloud.log.(\\d+)");
uint maxNumber = 0;
QDateTime now = QDateTime::currentDateTime();
foreach(const QString &s, files) {
if (rx.exactMatch(s)) {
maxNumber = qMax(maxNumber, rx.cap(1).toUInt());
if (_logExpire > 0) {
QFileInfo fileInfo = dir.absoluteFilePath(s);
if (fileInfo.lastModified().addSecs(60*60 * _logExpire) < now) {
dir.remove(s);
}
}
}
}
QString filename = _logDirectory + "/owncloud.log." + QString::number(maxNumber+1);
_logBrowser->setLogFile(filename , _logFlush);
}
}
QNetworkProxy proxyFromConfig(const MirallConfigFile& cfg)
{
QNetworkProxy proxy;
@@ -618,7 +673,7 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
slotFetchCredentials();
}
#if defined Q_WS_WIN || defined Q_WS_X11
if( reason == QSystemTrayIcon::Trigger && _actionOpenStatus->isEnabled() ) {
if( reason == QSystemTrayIcon::Trigger ) {
slotOpenStatus();
}
#endif
@@ -626,44 +681,58 @@ void Application::slotTrayClicked( QSystemTrayIcon::ActivationReason reason )
void Application::slotAddFolder()
{
_folderMan->setSyncEnabled(false); // do not start more syncs.
/** Helper class to ensure sync is always switched back on */
class SyncDisabler
{
public:
SyncDisabler(Application *app) : _app(app)
{
_app->_folderMan->setSyncEnabled(false);
}
~SyncDisabler() {
_app->_folderMan->setSyncEnabled(true);
_app->computeOverallSyncStatus();
_app->_folderMan->slotScheduleAllFolders();
}
private:
Application *_app;
};
Folder::Map folderMap = _folderMan->map();
if (_folderWizard) {
raiseDialog(_folderWizard);
return;
}
_folderWizard->setFolderMap( &folderMap );
// disables sync queuing while in scope
SyncDisabler disableSync(this);
_folderWizard->restart();
Folder::Map folderMap = _folderMan->map();
_folderWizard = new FolderWizard;
_folderWizard->setFolderMap( &folderMap );
if (_folderWizard->exec() == QDialog::Accepted) {
qDebug() << "* Folder wizard completed";
if (_folderWizard->exec() == QDialog::Accepted) {
qDebug() << "* Folder wizard completed";
bool goodData = true;
QString alias = _folderWizard->field(QLatin1String("alias")).toString();
QString sourceFolder = _folderWizard->field(QLatin1String("sourceFolder")).toString();
QString targetPath = _folderWizard->field(QLatin1String("OCFolderLineEdit")).toString();
QString backend = QLatin1String("owncloud");
QString alias = _folderWizard->field(QLatin1String("alias")).toString();
QString sourceFolder = _folderWizard->field(QLatin1String("sourceFolder")).toString();
QString backend = QLatin1String("owncloud");
QString targetPath;
bool onlyThisLAN = false;
targetPath = _folderWizard->field(QLatin1String("OCFolderLineEdit")).toString();
_folderMan->setSyncEnabled(true); // do start sync again.
if( goodData ) {
_folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, onlyThisLAN );
if (!FolderMan::ensureJournalGone( sourceFolder ))
return;
_folderMan->addFolderDefinition( backend, alias, sourceFolder, targetPath, false );
Folder *f = _folderMan->setupFolderFromConfigFile( alias );
if( f ) {
_statusDialog->slotAddFolder( f );
_statusDialog->buttonsSetEnabled();
setupContextMenu();
}
}
} else {
qDebug() << "* Folder wizard cancelled";
}
_folderMan->setSyncEnabled(true);
_folderMan->slotScheduleAllFolders();
} else {
qDebug() << "* Folder wizard cancelled";
}
_folderWizard->deleteLater();
_folderWizard = 0;
}
void Application::slotOpenStatus()
@@ -673,7 +742,7 @@ void Application::slotOpenStatus()
QWidget *raiseWidget = 0;
// check if there is a mirall.cfg already.
if( _owncloudSetupWizard->wizard()->isVisible() ) {
if( _owncloudSetupWizard && _owncloudSetupWizard->wizard()->isVisible() ) {
raiseWidget = _owncloudSetupWizard->wizard();
}
@@ -683,8 +752,7 @@ void Application::slotOpenStatus()
if( !cfgFile.exists() ) {
qDebug() << "No configured folders yet, start the Owncloud integration dialog.";
_folderMan->setSyncEnabled(false);
_owncloudSetupWizard->startWizard();
slotConfigure();
} else {
qDebug() << "#============# Status dialog starting #=============#";
raiseWidget = _statusDialog;
@@ -731,23 +799,36 @@ void Application::slotAbout()
void Application::slotRemoveFolder( const QString& alias )
{
int ret = QMessageBox::question( 0, tr("Confirm Folder Remove"),
tr("Do you really want to remove upload folder <i>%1</i>?").arg(alias),
tr("<p>Do you really want to stop syncing the folder <i>%1</i>?</p>"
"<p><b>Note:</b> This will not remove the files from your client.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::No ) {
return;
}
Folder *f = _folderMan->folder(alias);
if( f && _overallStatusStrings.contains( f->alias() )) {
_overallStatusStrings.remove( f->alias() );
}
_folderMan->slotRemoveFolder( alias );
_statusDialog->slotRemoveSelectedFolder( );
computeOverallSyncStatus();
setupContextMenu();
}
void Application::slotResetFolder( const QString & alias )
{
int ret = QMessageBox::question( 0, tr("Confirm Folder Reset"),
tr("<p>Do you really want to reset folder <i>%1</i> and rebuild your client database?</p>"
"<p><b>Note:</b> While no files will be removed, this can cause significant data "
"traffic and take several minutes to hours, depending on the size of the folder.</p>").arg(alias),
QMessageBox::Yes|QMessageBox::No );
if( ret == QMessageBox::No ) {
return;
}
Folder *f = _folderMan->folder(alias);
f->slotTerminateSync();
f->wipe();
_folderMan->slotScheduleAllFolders();
}
// Open the File list info dialog.
void Application::slotInfoFolder( const QString& alias )
{
@@ -794,11 +875,17 @@ void Application::slotEnableFolder(const QString& alias, const bool enable)
void Application::slotConfigure()
{
_folderMan->setSyncEnabled(false); // do not start more syncs.
if (!_owncloudSetupWizard->wizard()->isVisible())
_owncloudSetupWizard->startWizard();
else
if (_owncloudSetupWizard && !_owncloudSetupWizard->wizard()->isVisible()) {
raiseDialog(_owncloudSetupWizard->wizard());
return;
}
_owncloudSetupWizard.reset(new OwncloudSetupWizard( _folderMan, _theme, this ));;
connect( _owncloudSetupWizard.data(), SIGNAL(ownCloudWizardDone(int)),
this, SLOT(slotownCloudWizardDone(int)));
_folderMan->setSyncEnabled(false); // do not start more syncs.
_owncloudSetupWizard->startWizard();
}
void Application::slotConfigureProxy()
@@ -834,6 +921,10 @@ void Application::slotSyncStateChange( const QString& alias )
computeOverallSyncStatus();
qDebug() << "Sync state changed for folder " << alias << ": " << result.statusString();
if (result.status() == SyncResult::Success || result.status() == SyncResult::Error) {
enterNextLogFile();
}
}
void Application::parseOptions(const QStringList &options)
@@ -857,6 +948,18 @@ void Application::parseOptions(const QStringList &options)
} else {
setHelp();
}
} else if (option == QLatin1String("--logdir")) {
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
_logDirectory = it.next();
} else {
setHelp();
}
} else if (option == QLatin1String("--logexpire")) {
if (it.hasNext() && !it.peekNext().startsWith(QLatin1String("--"))) {
_logExpire = it.next().toInt();
} else {
setHelp();
}
} else if (option == QLatin1String("--logflush")) {
_logFlush = true;
} else if (option == QLatin1String("--monoicons")) {
@@ -880,11 +983,12 @@ void Application::computeOverallSyncStatus()
// display the info of the least successful sync (eg. not just display the result of the latest sync
SyncResult overallResult(SyncResult::Undefined );
QMap<QString, QString> overallStatusStrings;
QString trayMessage;
Folder::Map map = _folderMan->map();
foreach ( Folder *syncedFolder, map.values() ) {
QString folderMessage = _overallStatusStrings[syncedFolder->alias()];
QString folderMessage;
SyncResult folderResult = syncedFolder->syncResult();
SyncResult::Status syncStatus = folderResult.status();
@@ -914,9 +1018,9 @@ void Application::computeOverallSyncStatus()
break;
case SyncResult::Success:
if( overallResult.status() == SyncResult::Undefined ) {
folderMessage = tr( "Last Sync was successful." );
overallResult.setStatus( SyncResult::Success );
}
folderMessage = tr( "Last Sync was successful." );
break;
case SyncResult::Error:
overallResult.setStatus( SyncResult::Error );
@@ -938,15 +1042,13 @@ void Application::computeOverallSyncStatus()
}
qDebug() << "Folder in overallStatus Message: " << syncedFolder << " with name " << syncedFolder->alias();
QString msg = QString::fromLatin1("Folder %1: %2").arg(syncedFolder->alias()).arg(folderMessage);
if( msg != _overallStatusStrings[syncedFolder->alias()] ) {
_overallStatusStrings[syncedFolder->alias()] = msg;
}
QString msg = tr("Folder %1: %2").arg(syncedFolder->alias(), folderMessage);
overallStatusStrings[syncedFolder->alias()] = msg;
}
// create the tray blob message, check if we have an defined state
if( overallResult.status() != SyncResult::Undefined ) {
QStringList allStatusStrings = _overallStatusStrings.values();
QStringList allStatusStrings = overallStatusStrings.values();
if( ! allStatusStrings.isEmpty() )
trayMessage = allStatusStrings.join(QLatin1String("\n"));
else
@@ -959,22 +1061,48 @@ void Application::computeOverallSyncStatus()
}
}
// Helpers for displaying messages. Note that there is no console on Windows.
#ifdef Q_OS_WIN
// Format as <pre> HTML
static inline void toHtml(QString &t)
{
t.replace(QLatin1Char('&'), QLatin1String("&amp;"));
t.replace(QLatin1Char('<'), QLatin1String("&lt;"));
t.replace(QLatin1Char('>'), QLatin1String("&gt;"));
t.insert(0, QLatin1String("<html><pre>"));
t.append(QLatin1String("</pre></html>"));
}
static void displayHelpText(QString t) // No console on Windows.
{
toHtml(t);
QMessageBox::information(0, Theme::instance()->appNameGUI(), t);
}
#else
static void displayHelpText(const QString &t)
{
std::cout << qPrintable(t);
}
#endif
void Application::showHelp()
{
setHelp();
std::cout << _theme->appName().toLatin1().constData() << " version " <<
_theme->version().toLatin1().constData() << std::endl << std::endl;
std::cout << "File synchronisation desktop utility." << std::endl << std::endl;
std::cout << "Options:" << std::endl;
std::cout << " -h --help : show this help screen." << std::endl;
std::cout << " --logwindow : open a window to show log output." << std::endl;
std::cout << " --logfile <filename> : write log output to file <filename>." << std::endl;
std::cout << " --logflush : flush the log file after every write." << std::endl;
std::cout << " --monoicons : Use black/white pictograms for systray." << std::endl;
std::cout << " --confdir <dirname> : Use the given configuration directory." << std::endl;
std::cout << std::endl;
setHelp();
QString helpText;
QTextStream stream(&helpText);
stream << _theme->appName().toLatin1().constData()
<< QLatin1String(" version ")
<< _theme->version().toLatin1().constData() << endl;
stream << QLatin1String("File synchronisation desktop utility.") << endl << endl
<< QLatin1String(optionsC);
if (_theme->appName() == QLatin1String("ownCloud"))
std::cout << "For more information, see http://www.owncloud.org" << std::endl;
stream << endl << "For more information, see http://www.owncloud.org" << endl;
displayHelpText(helpText);
}
void Application::setHelp()
@@ -982,6 +1110,30 @@ void Application::setHelp()
_helpOnly = true;
}
#if defined(Q_OS_WIN)
bool Application::winEventFilter(MSG *pMsg, long *result)
{
if (pMsg->message == WM_POWERBROADCAST) {
switch(pMsg->wParam) {
case PBT_APMPOWERSTATUSCHANGE:
qDebug() << "WM_POWERBROADCAST: Power state changed";
break;
case PBT_APMSUSPEND:
qDebug() << "WM_POWERBROADCAST: Entering low power state";
break;
case PBT_APMRESUMEAUTOMATIC:
qDebug() << "WM_POWERBROADCAST: Resuming from low power state";
break;
default:
break;
}
return true;
}
return SharedTools::QtSingleApplication::winEventFilter(pMsg, result);
}
#endif
QString substLang(const QString &lang)
{
// Map the more apropriate script codes

View File

@@ -61,6 +61,7 @@ protected slots:
void slotAddFolder();
void slotOpenStatus();
void slotRemoveFolder( const QString& );
void slotResetFolder( const QString& );
void slotEnableFolder( const QString&, const bool );
void slotInfoFolder( const QString& );
void slotConfigure();
@@ -79,10 +80,16 @@ protected:
void setupContextMenu();
void setupLogBrowser();
void setupProxy();
void enterNextLogFile();
//folders have to be disabled while making config changes
void computeOverallSyncStatus();
// reimplemented
#if defined(Q_WS_WIN)
bool winEventFilter( MSG * message, long * result );
#endif
protected slots:
void slotTrayClicked( QSystemTrayIcon::ActivationReason );
void slotFolderOpenAction(const QString & );
@@ -118,7 +125,7 @@ private:
#endif
FolderWizard *_folderWizard;
OwncloudSetupWizard *_owncloudSetupWizard;
QScopedPointer<OwncloudSetupWizard> _owncloudSetupWizard;
SslErrorDialog *_sslErrorDialog;
// tray's menu
@@ -130,9 +137,10 @@ private:
Theme *_theme;
QSignalMapper *_folderOpenActionMapper;
UpdateDetector *_updateDetector;
QMap<QString, QString> _overallStatusStrings;
LogBrowser *_logBrowser;
QString _logFile;
QString _logDirectory;
int _logExpire;
bool _showLogWindow;
bool _logFlush;
bool _helpOnly;

View File

@@ -69,15 +69,12 @@ CredentialStore::CredState CredentialStore::state()
bool CredentialStore::canTryAgain()
{
bool canDoIt = false;
if( _tries > MAX_LOGIN_ATTEMPTS ) {
qDebug() << "canTryAgain: Max attempts reached.";
return false;
}
/* Since QtKeyChain is required now, it makes to only
* query once. */
/* Since QtKeyChain is required now, it makes sense to only query once. */
if( _state == NotFetched || _state == AsyncWriting ) {
return true;
} else {
@@ -126,7 +123,7 @@ void CredentialStore::fetchCredentials()
_inputDialog->setTextEchoMode( QLineEdit::Password );
connect(_inputDialog, SIGNAL(finished(int)), SLOT(slotUserDialogDone(int)));
_inputDialog->exec();
_inputDialog->open();
break;
}
case CredentialStore::Settings: {
@@ -363,9 +360,9 @@ void CredentialStore::slotKeyChainWriteFinished( QKeychain::Job *job )
qDebug() << "Error with keychain: " << pwdJob->errorString();
if( err == NoBackendAvailable || err == NotImplemented ||
pwdJob->errorString().contains(QLatin1String("Could not open wallet"))) {
_state = NoKeychainBackend;
_type = Settings;
saveCredentials();
_state = NoKeychainBackend;
} else {
_state = Error;
}

View File

@@ -58,6 +58,8 @@ CSyncThread::~CSyncThread()
}
//Convert an error code from csync to a user readable string.
// Keep that function thread safe as it can be called from the sync thread or the main thread
QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errString )
{
QString errStr;
@@ -106,8 +108,6 @@ QString CSyncThread::csyncErrorToString( CSYNC_ERROR_CODE err, const char *errSt
break;
case CSYNC_ERR_ACCESS_FAILED:
errStr = tr("<p>The target directory does not exist.</p><p>Please check the sync setup.</p>");
// this is critical. The database has to be removed.
emit wipeDb();
break;
case CSYNC_ERR_REMOTE_CREATE:
case CSYNC_ERR_REMOTE_STAT:
@@ -191,6 +191,11 @@ int CSyncThread::treewalkFile( TREE_WALK_FILE *file, bool remote )
int re = 0;
if (file->instruction != CSYNC_INSTRUCTION_IGNORE
&& file->instruction != CSYNC_INSTRUCTION_REMOVE) {
_hasFiles = true;
}
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE:
case CSYNC_INSTRUCTION_IGNORE:
@@ -245,8 +250,8 @@ int CSyncThread::treewalkError(TREE_WALK_FILE* file)
return 0;
if( file &&
file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
file->instruction == CSYNC_INSTRUCTION_ERROR ) {
(file->instruction == CSYNC_INSTRUCTION_STAT_ERROR ||
file->instruction == CSYNC_INSTRUCTION_ERROR) ) {
_mutex.lock();
_syncedItems[indx]._instruction = file->instruction;
_mutex.unlock();
@@ -310,6 +315,7 @@ void CSyncThread::startSync()
// cleans up behind us and emits finished() to ease error handling
CSyncRunScopeHelper helper(_csync_ctx, this);
csync_set_module_property(_csync_ctx, "csync_context", _csync_ctx);
csync_set_userdata(_csync_ctx, this);
// csync_set_auth_callback( _csync_ctx, getauth );
@@ -327,6 +333,7 @@ void CSyncThread::startSync()
return;
}
_hasFiles = false;
bool walkOk = true;
if( csync_walk_local_tree(_csync_ctx, &treewalkLocal, 0) < 0 ) {
qDebug() << "Error in local treewalk.";
@@ -336,6 +343,16 @@ void CSyncThread::startSync()
qDebug() << "Error in remote treewalk.";
}
if (!_hasFiles && !_syncedItems.isEmpty()) {
qDebug() << Q_FUNC_INFO << "All the files are going to be removed, asking the user";
bool cancel = true;
emit aboutToRemoveAllFiles(_syncedItems.first()._dir, &cancel);
if (cancel) {
qDebug() << Q_FUNC_INFO << "Abort sync";
return;
}
}
if (_needsUpdate)
emit(started());

View File

@@ -38,7 +38,7 @@ public:
CSyncThread(CSYNC *);
~CSyncThread();
QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
static QString csyncErrorToString( CSYNC_ERROR_CODE, const char * );
Q_INVOKABLE void startSync();
@@ -56,6 +56,8 @@ signals:
void finished();
void started();
void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel);
private:
void handleSyncError(CSYNC *ctx, const char *state);
static void progress(const char *remote_url,
@@ -79,6 +81,8 @@ private:
CSYNC *_csync_ctx;
bool _needsUpdate;
bool _hasFiles; // true if there is at least one file that is not ignored or removed
friend class CSyncRunScopeHelper;
};
}

View File

@@ -123,7 +123,10 @@ void FileItemDialog::slotSetFolderMessage()
QDateTime now = QDateTime::currentDateTime();
int secs = _lastSyncTime.secsTo(now);
_timelabel->setText(tr("%1 (finished %n sec. ago)", "", secs).arg(_folderMessage));
if (secs < 60)
_timelabel->setText(tr("%1 (last finished %n sec. ago)", "", secs).arg(_folderMessage));
else
_timelabel->setText(tr("%1 (last finished %n min. ago)", "", secs/60).arg(_folderMessage));
}
void FileItemDialog::copyToClipboard()

View File

@@ -27,6 +27,7 @@
#endif
#include <QDesktopServices>
#include <QMessageBox>
#include <QtCore>
namespace Mirall {
@@ -79,20 +80,28 @@ void FolderMan::slotReparseConfiguration()
setupKnownFolders();
}
int FolderMan::unloadAllFolders()
{
// first terminate sync jobs.
terminateCurrentSync();
int cnt = 0;
// clear the list of existing folders.
Folder::MapIterator i(_folderMap);
while (i.hasNext()) {
i.next();
delete _folderMap.take( i.key() );
cnt++;
}
return cnt;
}
int FolderMan::setupKnownFolders()
{
qDebug() << "* Setup folders from " << _folderConfigPath;
// first terminate sync jobs.
terminateCurrentSync();
// clear the list of existing folders.
Folder::MapIterator i(_folderMap);
while (i.hasNext()) {
i.next();
delete _folderMap.take( i.key() );
}
unloadAllFolders();
QDir dir( _folderConfigPath );
dir.setFilter(QDir::Files);
@@ -117,6 +126,25 @@ void FolderMan::wipeAllJournals()
}
}
bool FolderMan::ensureJournalGone(const QString &localPath)
{
// remove old .csync_journal file
QString stateDbFile = localPath+QLatin1String("/.csync_journal.db");
while (QFile::exists(stateDbFile) && !QFile::remove(stateDbFile)) {
int ret = QMessageBox::warning(0, tr("Could not reset folder state"),
tr("An old sync journal '%1' was found, "
"but could not be removed. Please make sure "
"that no application is currently using it.")
.arg(QDir::fromNativeSeparators(QDir::cleanPath(stateDbFile))),
QMessageBox::Retry|QMessageBox::Abort);
if (ret == QMessageBox::Abort) {
return false;
}
}
return true;
}
void FolderMan::terminateCurrentSync()
{
if( !_currentSyncFolder.isEmpty() ) {
@@ -235,7 +263,7 @@ Folder* FolderMan::setupFolderFromConfigFile(const QString &file) {
folder->setConfigFile(file);
} else {
qWarning() << "unknown backend" << backend;
return NULL;
return 0;
}
}
@@ -275,12 +303,18 @@ void FolderMan::slotEnableFolder( const QString& alias, bool enable )
// csync still remains in a stable state, regardless of that.
void FolderMan::terminateSyncProcess( const QString& alias )
{
Folder *f = _folderMap[alias];
if( f ) {
f->slotTerminateSync();
QString folderAlias = alias;
if( alias.isEmpty() ) {
folderAlias = _currentSyncFolder;
}
if( ! folderAlias.isEmpty() ) {
Folder *f = _folderMap[folderAlias];
if( f ) {
f->slotTerminateSync();
if(_currentSyncFolder == alias )
_currentSyncFolder = QString::null;
if(_currentSyncFolder == folderAlias )
_currentSyncFolder = QString::null;
}
}
}
@@ -437,6 +471,8 @@ void FolderMan::removeFolder( const QString& alias )
{
Folder *f = 0;
_scheduleQueue.removeAll(alias);
if( _folderMap.contains( alias )) {
qDebug() << "Removing " << alias;
f = _folderMap.take( alias );
@@ -464,7 +500,7 @@ QString FolderMan::getBackupName( const QString& fullPathName ) const
int cnt = 1;
do {
if( fi.exists() ) {
newName += fullPathName + QString( ".oC_bak_%1").arg(cnt++);
newName = fullPathName + QString( ".oC_bak_%1").arg(cnt++);
fi.setFile(newName);
}
} while( fi.exists() );
@@ -479,6 +515,13 @@ bool FolderMan::startFromScratch( const QString& localFolder )
QFileInfo fi( localFolder );
if( fi.exists() && fi.isDir() ) {
QDir file = fi.dir();
// check if there are files in the directory.
if( file.count() == 0 ) {
// directory is existing, but its empty. Use it.
qDebug() << "startFromScratch: Directory is empty!";
return true;
}
QString newName = getBackupName( fi.absoluteFilePath() );
if( file.rename( fi.absoluteFilePath(), newName )) {

View File

@@ -76,6 +76,13 @@ public:
*/
void wipeAllJournals();
/**
* Ensures that a given directory does not contain a .csync_journal.
*
* @returns false if the journal could not be removed, false otherwise.
*/
static bool ensureJournalGone(const QString &path);
/**
* Creates a new and empty local directory.
*/
@@ -102,7 +109,10 @@ public slots:
void slotReparseConfiguration();
void terminateSyncProcess( const QString& );
void terminateSyncProcess( const QString& alias = QString::null );
/* delete all folder objects */
int unloadAllFolders();
// if enabled is set to false, no new folders will start to sync.
// the current one will finish.

View File

@@ -36,7 +36,8 @@ FolderWizardSourcePage::FolderWizardSourcePage()
{
_ui.setupUi(this);
registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
_ui.localFolderLineEdit->setText( QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() ) );
QString defaultPath = QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() );
_ui.localFolderLineEdit->setText( QDir::toNativeSeparators( defaultPath ) );
registerField(QLatin1String("alias*"), _ui.aliasLineEdit);
_ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
@@ -64,7 +65,7 @@ void FolderWizardSourcePage::cleanupPage()
bool FolderWizardSourcePage::isComplete() const
{
QFileInfo selFile( _ui.localFolderLineEdit->text() );
QFileInfo selFile( QDir::fromNativeSeparators(_ui.localFolderLineEdit->text()) );
QString userInput = selFile.canonicalFilePath();
QString warnString;
@@ -94,7 +95,8 @@ bool FolderWizardSourcePage::isComplete() const
qDebug() << "Checking local path: " << folderDir << " <-> " << userInput;
if( QFileInfo( f->path() ) == userInput ) {
isOk = false;
warnString.append( tr("The local path %1 is already an upload folder.<br/>Please pick another one!").arg(userInput) );
warnString.append( tr("The local path %1 is already an upload folder.<br/>Please pick another one!")
.arg(QDir::toNativeSeparators(userInput)) );
}
if( isOk && folderDir.startsWith( userInput )) {
qDebug() << "A already configured folder is child of the current selected";
@@ -148,7 +150,7 @@ void FolderWizardSourcePage::on_localFolderChooseBtn_clicked()
tr("Select the source folder"),
QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
if (!dir.isEmpty()) {
_ui.localFolderLineEdit->setText(dir);
_ui.localFolderLineEdit->setText(QDir::toNativeSeparators(dir));
}
}

View File

@@ -98,9 +98,7 @@ public:
enum {
Page_Source,
Page_Target,
Page_Network,
Page_Owncloud
Page_Target
};
FolderWizard(QWidget *parent = 0);

View File

@@ -113,15 +113,12 @@ LogBrowser::LogBrowser(QWidget *parent) :
setModal(false);
// needs to be a queued connection as logs from other threads come in
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::QueuedConnection);
// Direct connection for log comming from this thread, and queued for the one in a different thread
connect(Logger::instance(), SIGNAL(newLog(QString)),this,SLOT(slotNewLog(QString)), Qt::AutoConnection);
}
LogBrowser::~LogBrowser()
{
if( _logstream ) {
_logFile.close();
}
}
void LogBrowser::slotNewLog( const QString& msg )
@@ -138,6 +135,9 @@ void LogBrowser::slotNewLog( const QString& msg )
void LogBrowser::setLogFile( const QString & name, bool flush )
{
if( _logstream ) {
_logFile.close();
}
_logFile.setFileName( name );
if(!_logFile.open(QIODevice::WriteOnly)) {
@@ -150,7 +150,7 @@ void LogBrowser::setLogFile( const QString & name, bool flush )
return;
}
_doFileFlush = flush;
_logstream = new QTextStream( &_logFile );
_logstream.reset(new QTextStream( &_logFile ));
}
void LogBrowser::slotFind()

View File

@@ -67,7 +67,7 @@ private:
QFile _logFile;
bool _doFileFlush;
QTextStream *_logstream;
QScopedPointer<QTextStream> _logstream;
};
} // namespace

View File

@@ -374,26 +374,23 @@ QString MirallConfigFile::ownCloudPasswd( const QString& connection ) const
settings.setIniCodec( "UTF-8" );
settings.beginGroup( con );
QString pwd;
QByteArray pwdba = settings.value(QLatin1String("passwd")).toByteArray();
if( pwdba.isEmpty() ) {
// check the password entry, cleartext from before
// read it and convert to base64, delete the cleartext entry.
QString p = settings.value(QLatin1String("password")).toString();
if( ! p.isEmpty() ) {
// its there, save base64-encoded and delete.
pwdba = p.toUtf8();
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
settings.remove( QLatin1String("password") );
settings.sync();
}
if( !pwdba.isEmpty() ) {
return QString::fromUtf8( QByteArray::fromBase64(pwdba) );
}
pwd = QString::fromUtf8( QByteArray::fromBase64(pwdba) );
return pwd;
// check the password entry, cleartext from before
// read it and convert to base64, delete the cleartext entry.
QString p = settings.value(QLatin1String("password")).toString();
if( ! p.isEmpty() ) {
// its there, save base64-encoded and delete.
pwdba = p.toUtf8();
settings.setValue( QLatin1String("passwd"), QVariant(pwdba.toBase64()) );
settings.remove( QLatin1String("password") );
settings.sync();
}
return p;
}
QString MirallConfigFile::ownCloudVersion() const
@@ -562,7 +559,7 @@ int MirallConfigFile::proxyPort() const
bool MirallConfigFile::proxyNeedsAuth() const
{
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toInt();
return getValue(QLatin1String("needsAuth"), QLatin1String("proxy")).toBool();
}
QString MirallConfigFile::proxyUser() const

View File

@@ -33,6 +33,8 @@
#include <QNetworkProxy>
#include <QNetworkAccessManager>
#include <QNetworkProxyFactory>
#include <QMessageBox>
#include <QPushButton>
namespace Mirall {
@@ -67,7 +69,6 @@ ownCloudFolder::ownCloudFolder(const QString &alias,
, _csync(0)
, _csyncError(false)
, _csyncUnavail(false)
, _wipeDb(false)
{
ServerActionNotifier *notifier = new ServerActionNotifier(this);
connect(notifier, SIGNAL(guiLog(QString,QString)), Logger::instance(), SIGNAL(guiLog(QString,QString)));
@@ -97,7 +98,9 @@ ownCloudFolder::ownCloudFolder(const QString &alias,
csync_set_auth_callback( _csync_ctx, getauth );
if( csync_init( _csync_ctx ) < 0 ) {
qDebug() << "Could not initialize csync!";
qDebug() << "Could not initialize csync!" << csync_get_error(_csync_ctx) << csync_get_error_string(_csync_ctx);
slotCSyncError(CSyncThread::csyncErrorToString(csync_get_error(_csync_ctx), csync_get_error_string(_csync_ctx)));
csync_destroy(_csync_ctx);
_csync_ctx = 0;
}
setProxy();
@@ -112,6 +115,7 @@ ownCloudFolder::~ownCloudFolder()
csync_request_abort(_csync_ctx);
_thread->wait();
}
delete _csync;
// Destroy csync here.
csync_destroy(_csync_ctx);
}
@@ -257,6 +261,13 @@ void ownCloudFolder::startSync()
void ownCloudFolder::startSync(const QStringList &pathList)
{
if (!_csync_ctx) {
qDebug() << Q_FUNC_INFO << "_csync_ctx is empty. probably because csync_init has failed.";
// the error should already be set
QMetaObject::invokeMethod(this, "slotCSyncFinished", Qt::QueuedConnection);
return;
}
if (_thread && _thread->isRunning()) {
qCritical() << "* ERROR csync is still running and new sync requested.";
return;
@@ -268,7 +279,6 @@ void ownCloudFolder::startSync(const QStringList &pathList)
_errors.clear();
_csyncError = false;
_csyncUnavail = false;
_wipeDb = false;
MirallConfigFile cfgFile;
@@ -283,6 +293,8 @@ void ownCloudFolder::startSync(const QStringList &pathList)
_csync->moveToThread(_thread);
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
connect( _csync, SIGNAL(treeWalkResult(const SyncFileItemVector&)),
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
@@ -290,6 +302,11 @@ void ownCloudFolder::startSync(const QStringList &pathList)
connect(_csync, SIGNAL(finished()), SLOT(slotCSyncFinished()), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncError(QString)), SLOT(slotCSyncError(QString)), Qt::QueuedConnection);
connect(_csync, SIGNAL(csyncUnavailable()), SLOT(slotCsyncUnavailable()), Qt::QueuedConnection);
//blocking connection so the message box happens in this thread, but block the csync thread.
connect(_csync, SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)), Qt::BlockingQueuedConnection);
_thread->start();
QMetaObject::invokeMethod(_csync, "startSync", Qt::QueuedConnection);
emit syncStarted();
@@ -323,7 +340,6 @@ void ownCloudFolder::slotCSyncFinished()
qDebug() << " ** error Strings: " << _errors;
_syncResult.setErrorStrings( _errors );
qDebug() << " * owncloud csync thread finished with error";
if( _wipeDb ) wipe();
} else if (_csyncUnavail) {
_syncResult.setStatus(SyncResult::Unavailable);
} else {
@@ -417,7 +433,6 @@ void ownCloudFolder::wipe()
if( ctmpFile.exists() ) {
ctmpFile.remove();
}
_wipeDb = false;
}
ServerActionNotifier::ServerActionNotifier(QObject *parent)
@@ -488,5 +503,30 @@ void ServerActionNotifier::slotSyncFinished(const SyncResult &result)
}
}
void ownCloudFolder::slotAboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel)
{
QString msg = direction == SyncFileItem::Down ?
tr("This sync would remove all the files in the local sync folder '%1'.\n"
"If you or your administrator have reset your account on the server, choose "
"\"Keep files\". If you want your data to be removed, choose \"Remove all files\".") :
tr("This sync would remove all the files in the sync folder '%1'.\n"
"This might be because the folder was silently reconfigured, or that all "
"the file were manually removed.\n"
"Are you sure you want to perform this operation?");
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
msg.arg(alias()));
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
QPushButton* keepBtn = msgBox.addButton(tr("Keep files"), QMessageBox::ActionRole);
if (msgBox.exec() == -1) {
*cancel = true;
return;
}
*cancel = msgBox.clickedButton() == keepBtn;
if (*cancel) {
wipe();
}
}
} // ns

View File

@@ -77,6 +77,7 @@ public:
public slots:
void startSync();
void slotTerminateSync();
void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
protected slots:
void slotLocalPathChanged( const QString& );

View File

@@ -483,7 +483,10 @@ bool ownCloudInfo::certsUntrusted()
void ownCloudInfo::slotError( QNetworkReply::NetworkError err)
{
qDebug() << "ownCloudInfo Network Error: " << err;
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
qDebug() << "ownCloudInfo Network Error"
<< err << ":" << reply->errorString();
switch (err) {
case QNetworkReply::ProxyConnectionRefusedError:

View File

@@ -130,6 +130,9 @@
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<item row="0" column="0" colspan="2">
<widget class="QRadioButton" name="radioButton">
<property name="text">
@@ -159,7 +162,7 @@
<item row="1" column="1">
<widget class="QLabel" name="label_6">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -213,7 +216,7 @@
<item row="3" column="1">
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>

View File

@@ -94,6 +94,7 @@ void OwncloudSetupWizard::startWizard()
_ocWizard->setMultipleFoldersExist(_folderMan->map().count() > 1);
_ocWizard->show();
_ocWizard->raise();
}
@@ -124,34 +125,50 @@ void OwncloudSetupWizard::slotAssistantFinished( int result )
qDebug() << "The User has changed, same as url change.";
}
// save the user credentials and afterwards clear the cred store.
cfg.acceptCustomConfig();
// Now write the resulting folder definition if folder names are set.
const QString localFolder = _ocWizard->localFolder();
if( !( localFolder.isEmpty() || _remoteFolder.isEmpty() ) ) { // both variables are set.
if( urlHasChanged ) {
_folderMan->removeAllFolderDefinitions();
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
localFolder, _remoteFolder, false );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
bool acceptCfg = true;
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
if( startFromScratch ) {
// clean the entire directory.
if( _folderMan->startFromScratch( localFolder ) ) {
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\">Successfully prepared syncing from scratch!</font>"));
} else {
_ocWizard->appendToConfigurationLog(tr("<font color=\"red\">Failed to prepare syncing from scratch!</font>"));
if( urlHasChanged ) {
_folderMan->unloadAllFolders();
bool startFromScratch = _ocWizard->field( "OCSyncFromScratch" ).toBool();
if( startFromScratch ) {
// first try to rename (backup) the current local dir.
bool renameOk = false;
while( !renameOk ) {
renameOk = _folderMan->startFromScratch(localFolder);
if( ! renameOk ) {
QMessageBox::StandardButton but;
but = QMessageBox::question( 0, tr("Folder rename failed"),
tr("Can't remove and back up the folder because the folder or a file in it is open in another program."
"Please close the folder or file and hit retry or cancel the setup."), QMessageBox::Retry | QMessageBox::Abort, QMessageBox::Retry);
if( but == QMessageBox::Abort ) {
renameOk = true;
acceptCfg = false;
}
}
}
} else {
// url is unchanged. Only the password was changed.
qDebug() << "Only password was changed, no changes to folder configuration.";
}
}
} else {
qDebug() << "WRN: Got unknown dialog result code " << result;
// save the user credentials and afterwards clear the cred store.
if( acceptCfg ) {
cfg.acceptCustomConfig();
}
// Now write the resulting folder definition if folder names are set.
if( acceptCfg && urlHasChanged ) {
_folderMan->removeAllFolderDefinitions();
_folderMan->addFolderDefinition( QLatin1String("owncloud"), Theme::instance()->appName(),
localFolder, _remoteFolder, false );
_ocWizard->appendToConfigurationLog(tr("<font color=\"green\"><b>Local sync folder %1 successfully created!</b></font>").arg(localFolder));
} else {
// url is unchanged. Only the password was changed.
if( acceptCfg ) {
qDebug() << "Only password was changed, no changes to folder configuration.";
} else {
qDebug() << "User interrupted change of configuration.";
}
}
}
// clear the custom config handle
@@ -219,10 +236,8 @@ void OwncloudSetupWizard::testOwnCloudConnect()
// If there is already a config, take its proxy config.
if( ownCloudInfo::instance()->isConfigured() ) {
MirallConfigFile prevCfg;
if( prevCfg.proxyType() != QNetworkProxy::DefaultProxy ) {
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
}
cfgFile.setProxyType( prevCfg.proxyType(), prevCfg.proxyHostName(), prevCfg.proxyPort(),
prevCfg.proxyNeedsAuth(), prevCfg.proxyUser(), prevCfg.proxyPassword() );
}
// now start ownCloudInfo to check the connection.

View File

@@ -15,12 +15,14 @@
#include "owncloudtheme.h"
#include <QString>
#include <QDebug>
#include <QVariant>
#include <QPixmap>
#include <QIcon>
#include <QStyle>
#include <QApplication>
#include <QDebug>
#include "mirall/version.h"
#include "config.h"
@@ -78,32 +80,6 @@ QString ownCloudTheme::about() const
.arg(devString);
}
QPixmap ownCloudTheme::splashScreen() const
{
return QPixmap(QLatin1String(":/mirall/resources/owncloud_splash.png"));
}
QIcon ownCloudTheme::folderIcon( const QString& backend ) const
{
QString name;
if( backend == QLatin1String("owncloud")) {
name = QLatin1String( "owncloud-framed" );
}
if( backend == QLatin1String("unison" )) {
name = QLatin1String( "folder-sync" );
}
if( backend == QLatin1String("csync" )) {
name = QLatin1String( "folder-remote" );
}
if( backend.isEmpty() || backend == QLatin1String("none") ) {
name = QLatin1String("folder-grey");
}
qDebug() << "==> load folder icon " << name;
return themeIcon( name );
}
QIcon ownCloudTheme::trayFolderIcon( const QString& ) const
{
QPixmap fallback = qApp->style()->standardPixmap(QStyle::SP_FileDialogNewFolder);
@@ -121,6 +97,18 @@ QIcon ownCloudTheme::applicationIcon( ) const
return themeIcon( QLatin1String("owncloud-icon") );
}
QVariant ownCloudTheme::customMedia(Theme::CustomMediaType type)
{
if (type == Theme::oCSetupTop) {
return QCoreApplication::translate("ownCloudTheme",
"If you don't have an ownCloud server yet, "
"see <a href=\"https://owncloud.com\">owncloud.com</a> for more info.",
"Top text in setup wizard. Keep short!");
} else {
return QVariant();
}
}
QColor ownCloudTheme::wizardHeaderBackgroundColor() const
{
return QColor("#1d2d42");

View File

@@ -34,6 +34,8 @@ public:
QIcon folderDisabledIcon() const;
QIcon applicationIcon() const;
QVariant customMedia(CustomMediaType type);
QColor wizardHeaderBackgroundColor() const;
QColor wizardHeaderTitleColor() const;

View File

@@ -130,16 +130,12 @@ void OwncloudSetupPage::setServerUrl( const QString& newUrl )
void OwncloudSetupPage::setupCustomization()
{
// set defaults for the customize labels.
// _ui.topLabel->hide();
_ui.topLabel->hide();
_ui.bottomLabel->hide();
Theme *theme = Theme::instance();
QVariant variant = theme->customMedia( Theme::oCSetupTop );
if( variant.isNull() ) {
_ui.topLabel->setOpenExternalLinks(true);
_ui.topLabel->setText("If you don't have an ownCloud server yet, see <a href=\"https://owncloud.com\">owncloud.com</a> for more info.");
} else {
if( !variant.isNull() ) {
setupCustomMedia( variant, _ui.topLabel );
}
@@ -196,6 +192,9 @@ void OwncloudSetupPage::initializePage()
_checking = false;
_multipleFoldersExist = false;
// call to init label
slotHandleUserInput();
if( _configExists ) {
_ui.lePassword->setFocus();
} else {
@@ -260,7 +259,7 @@ void OwncloudSetupPage::slotHandleUserInput()
t = tr("Change the Password for your configured account.");
} else {
// Complete new setup.
_ui.pbSelectLocalFolder->setText(locFolder);
_ui.pbSelectLocalFolder->setText(QDir::toNativeSeparators(locFolder));
if( _remoteFolder.isEmpty() || _remoteFolder == QLatin1String("/") ) {
t = tr("Your entire account will be synced to the local folder '%1'.")
@@ -404,8 +403,11 @@ void OwncloudWizard::setMultipleFoldersExist(bool exist)
void OwncloudSetupPage::setConfigExists( bool config )
{
_configExists = config;
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
if (config == true) {
setSubTitle( tr("<font color=\"%1\">Change your user credentials</font>")
.arg(Theme::instance()->wizardHeaderTitleColor().name()));
}
}
// ======================================================================

View File

@@ -54,7 +54,9 @@ Mirall::ProxyDialog::ProxyDialog( QWidget* parent )
}
hostLineEdit->setText(cfgFile.proxyHostName());
portSpinBox->setValue(cfgFile.proxyPort());
int port = cfgFile.proxyPort();
if (port == 0) port = 8080;
portSpinBox->setValue(port);
if (!cfgFile.proxyUser().isEmpty())
{
authRequiredcheckBox->setChecked(true);

View File

@@ -64,40 +64,33 @@ FolderViewDelegate::~FolderViewDelegate()
QSize FolderViewDelegate::sizeHint(const QStyleOptionViewItem & option ,
const QModelIndex & index) const
{
int w = 0;
QString p = qvariant_cast<QString>(index.data(FolderPathRole));
QFont aliasFont = QApplication::font();
QFont font = QApplication::font();
Q_UNUSED(option)
QFont aliasFont = option.font;
QFont font = option.font;
aliasFont.setPointSize( font.pointSize() +2 );
QFontMetrics fm(font);
QFontMetrics aliasFm(aliasFont);
int margin = aliasFm.height()/2;
w = 8 + fm.boundingRect( p ).width();
int aliasMargin = aliasFm.height()/2;
int margin = fm.height()/4;
// calc height
int h = margin; // margin to top
int h = aliasMargin; // margin to top
h += aliasFm.height(); // alias
h += fm.height()/2; // between alias and local path
h += margin; // between alias and local path
h += fm.height(); // local path
h += fm.height()/2; // between local and remote path
h += margin; // between local and remote path
h += fm.height(); // remote path
h += margin; // bottom margin
int minHeight = 48 + margin + margin; // icon + margins
if( h < minHeight ) h = minHeight;
h += aliasMargin; // bottom margin
// add some space to show an error condition.
if( ! qvariant_cast<QString>(index.data(FolderErrorMsg)).isEmpty() ) {
h += margin+fm.height();
h += aliasMargin*2+fm.height();
}
return QSize( w, h );
return QSize( 0, h);
}
void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
@@ -107,8 +100,8 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter->save();
QFont aliasFont = QApplication::font();
QFont subFont = QApplication::font();
QFont aliasFont = option.font;
QFont subFont = option.font;
QFont errorFont = subFont;
//font.setPixelSize(font.weight()+);
@@ -117,10 +110,11 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
QFontMetrics subFm( subFont );
QFontMetrics aliasFm( aliasFont );
int margin = aliasFm.height()/2;
QIcon folderIcon = qvariant_cast<QIcon>(index.data(FolderIconRole));
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIcon));
int aliasMargin = aliasFm.height()/2;
int margin = subFm.height()/4;
QIcon statusIcon = qvariant_cast<QIcon>(index.data(FolderStatusIconRole));
QString aliasText = qvariant_cast<QString>(index.data(FolderAliasRole));
QString pathText = qvariant_cast<QString>(index.data(FolderPathRole));
QString remotePath = qvariant_cast<QString>(index.data(FolderSecondPathRole));
@@ -130,72 +124,80 @@ void FolderViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
bool syncEnabled = index.data(FolderSyncEnabled).toBool();
// QString syncStatus = syncEnabled? tr( "Enabled" ) : tr( "Disabled" );
QSize iconsize(48, 48); // = icon.actualSize(option.decorationSize);
QRect aliasRect = option.rect;
QRect iconRect = option.rect;
QRect aliasRect = option.rect;
iconRect.setLeft( margin );
iconRect.setWidth( 48 );
iconRect.setTop( iconRect.top() + margin ); // (iconRect.height()-iconsize.height())/2);
iconRect.setLeft( aliasMargin );
iconRect.setTop( iconRect.top() + aliasMargin ); // (iconRect.height()-iconsize.height())/2);
QRect statusRect = iconRect;
statusRect.setLeft( option.rect.right() - margin - 48 );
statusRect.setRight( option.rect.right() - margin );
aliasRect.setLeft(iconRect.right()+margin);
aliasRect.setTop(aliasRect.top() + aliasFm.height()/2 );
aliasRect.setBottom(aliasRect.top()+aliasFm.height());
// local directory box
aliasRect.setTop(aliasRect.top() + aliasMargin );
aliasRect.setBottom(aliasRect.top() + aliasFm.height());
aliasRect.setRight(aliasRect.right() - aliasMargin );
// local directory box
QRect localPathRect = aliasRect;
localPathRect.setTop(aliasRect.bottom() + margin / 3);
localPathRect.setBottom(localPathRect.top()+subFm.height());
localPathRect.setTop(aliasRect.bottom() + margin );
localPathRect.setBottom(localPathRect.top() + subFm.height());
// remote directory box
QRect remotePathRect = localPathRect;
remotePathRect.setTop( localPathRect.bottom() + subFm.height()/2 );
remotePathRect.setTop( localPathRect.bottom() + margin );
remotePathRect.setBottom( remotePathRect.top() + subFm.height());
iconRect.setBottom(remotePathRect.bottom());
iconRect.setWidth(iconRect.height());
//painter->drawPixmap(QPoint(iconRect.right()/2,iconRect.top()/2),icon.pixmap(iconsize.width(),iconsize.height()));
if( syncEnabled ) {
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height()));
int nextToIcon = iconRect.right()+aliasMargin;
aliasRect.setLeft(nextToIcon);
localPathRect.setLeft(nextToIcon);
remotePathRect.setLeft(nextToIcon);
int iconSize = iconRect.width();
QPixmap pm = statusIcon.pixmap(iconSize, iconSize, syncEnabled ? QIcon::Normal : QIcon::Disabled );
painter->drawPixmap(QPoint(iconRect.left(), iconRect.top()), pm);
if ((option.state & QStyle::State_Selected)
&& (option.state & QStyle::State_Active)
// Hack: Windows Vista's light blue is not contrasting enough for white
&& !Application::style()->inherits("QWindowsVistaStyle")) {
painter->setPen(option.palette.color(QPalette::HighlightedText));
} else {
painter->drawPixmap(QPoint(iconRect.left(),iconRect.top()), folderIcon.pixmap(iconsize.width(),iconsize.height(), QIcon::Disabled ));
painter->setPen(option.palette.color(QPalette::Text));
}
painter->drawPixmap(QPoint(statusRect.left(), statusRect.top()), statusIcon.pixmap(48,48));
QString elidedAlias = aliasFm.elidedText(aliasText, Qt::ElideRight, aliasRect.width());
painter->setFont(aliasFont);
painter->drawText(aliasRect, aliasText);
painter->drawText(aliasRect, elidedAlias);
painter->setFont(subFont);
painter->drawText(localPathRect.left(),localPathRect.top()+17, pathText);
painter->drawText(remotePathRect, tr("Remote path: %1").arg(remotePath));
QString elidedPathText = subFm.elidedText(pathText, Qt::ElideMiddle, localPathRect.width());
painter->drawText(localPathRect, elidedPathText);
QString elidedRemotePathText = subFm.elidedText(tr("Remote path: %1").arg(remotePath),
Qt::ElideMiddle, remotePathRect.width());
painter->drawText(remotePathRect, elidedRemotePathText);
// paint an error overlay if there is an error string
if( !errorText.isEmpty() ) {
QRect errorRect = localPathRect;
errorRect.setLeft( iconRect.left());
errorRect.setTop( iconRect.bottom()+subFm.height()/2 );
errorRect.setHeight(subFm.height()+margin);
errorRect.setRight( statusRect.right() );
errorRect.setHeight(subFm.height()+aliasMargin);
errorRect.setRight( option.rect.right()-aliasMargin );
painter->setBrush( QColor(0xbb, 0x4d, 0x4d) );
painter->setPen( QColor(0xaa, 0xaa, 0xaa));
painter->drawRoundedRect( errorRect, 4, 4 );
QIcon warnIcon(":/mirall/resources/warning-16");
painter->drawPixmap( QPoint(errorRect.left()+2, errorRect.top()+2), warnIcon.pixmap(QSize(16,16)));
QPoint warnPos(errorRect.left()+aliasMargin/2, errorRect.top()+aliasMargin/2);
painter->drawPixmap( warnPos, warnIcon.pixmap(QSize(16,16)));
painter->setPen( Qt::white );
painter->setFont(errorFont);
QRect errorTextRect = errorRect;
errorTextRect.setLeft( errorTextRect.left()+margin/2 +16);
errorTextRect.setTop( errorTextRect.top()+margin/2 );
errorTextRect.setLeft( errorTextRect.left()+aliasMargin +16);
errorTextRect.setTop( errorTextRect.top()+aliasMargin/2 );
int linebreak = errorText.indexOf(QLatin1String("<br"));
QString eText = errorText;
@@ -235,19 +237,15 @@ StatusDialog::StatusDialog( Theme *theme, QWidget *parent) :
_folderList->setEditTriggers( QAbstractItemView::NoEditTriggers );
connect(_ButtonClose, SIGNAL(clicked()), this, SLOT(accept()));
connect(_ButtonRemove, SIGNAL(clicked()), this, SLOT(slotRemoveFolder()));
// hide these two for now...
_ButtonFetch->setVisible( false );
_ButtonPush->setVisible( false );
connect(_ButtonReset, SIGNAL(clicked()), this, SLOT(slotResetFolder()));
connect(_ButtonEnable, SIGNAL(clicked()), this, SLOT(slotEnableFolder()));
connect(_ButtonInfo, SIGNAL(clicked()), this, SLOT(slotInfoFolder()));
connect(_ButtonAdd, SIGNAL(clicked()), this, SLOT(slotAddSync()));
_ButtonRemove->setEnabled(false);
_ButtonFetch->setEnabled(false);
_ButtonPush->setEnabled(false);
_ButtonEnable->setEnabled(false);
_ButtonReset->setEnabled(false);
_ButtonInfo->setEnabled(false);
_ButtonAdd->setEnabled(true);
@@ -268,9 +266,8 @@ void StatusDialog::slotFolderActivated( const QModelIndex& indx )
bool state = indx.isValid();
_ButtonRemove->setEnabled( state );
_ButtonFetch->setEnabled( state );
_ButtonPush->setEnabled( state );
_ButtonEnable->setEnabled( state );
_ButtonReset->setEnabled( state );
_ButtonInfo->setEnabled( state );
if ( state ) {
@@ -322,7 +319,6 @@ void StatusDialog::buttonsSetEnabled()
{
bool haveFolders = _folderList->model()->rowCount() > 0;
_ButtonRemove->setEnabled(false);
if( _theme->singleSyncFolder() ) {
// only one folder synced folder allowed.
_ButtonAdd->setVisible(!haveFolders);
@@ -336,9 +332,9 @@ void StatusDialog::buttonsSetEnabled()
_ButtonEnable->setEnabled(isSelected);
_ButtonRemove->setEnabled(isSelected);
_ButtonFetch->setEnabled(isSelected);
_ButtonInfo->setEnabled(isSelected);
_ButtonPush->setEnabled(isSelected);
_ButtonReset->setEnabled(isSelected);
}
void StatusDialog::slotUpdateFolderState( Folder *folder )
@@ -369,8 +365,6 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
{
if( ! item || !f ) return;
QIcon icon = _theme->folderIcon( f->backend() );
item->setData( icon, FolderViewDelegate::FolderIconRole );
item->setData( f->nativePath(), FolderViewDelegate::FolderPathRole );
item->setData( f->secondPath(), FolderViewDelegate::FolderSecondPathRole );
item->setData( f->alias(), FolderViewDelegate::FolderAliasRole );
@@ -383,9 +377,9 @@ void StatusDialog::folderToModelItem( QStandardItem *item, Folder *f )
item->setData( _theme->statusHeaderText( status ), Qt::ToolTipRole );
if( f->syncEnabled() ) {
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIcon );
item->setData( _theme->syncStateIcon( status ), FolderViewDelegate::FolderStatusIconRole );
} else {
item->setData( _theme->folderDisabledIcon( ), FolderViewDelegate::FolderStatusIcon ); // size 48 before
item->setData( _theme->folderDisabledIcon( ), FolderViewDelegate::FolderStatusIconRole ); // size 48 before
}
item->setData( _theme->statusHeaderText( status ), FolderViewDelegate::FolderStatus );
item->setData( errors, FolderViewDelegate::FolderErrorMsg );
@@ -406,6 +400,15 @@ void StatusDialog::slotRemoveFolder()
slotCheckConnection();
}
void StatusDialog::slotResetFolder()
{
QModelIndex selected = _folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderViewDelegate::FolderAliasRole ).toString();
emit(resetFolderAlias( alias ));
}
}
void StatusDialog::slotRemoveSelectedFolder()
{
QModelIndex selected = _folderList->selectionModel()->currentIndex();
@@ -416,30 +419,6 @@ void StatusDialog::slotRemoveSelectedFolder()
slotCheckConnection();
}
void StatusDialog::slotFetchFolder()
{
QModelIndex selected = _folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderViewDelegate::FolderAliasRole ).toString();
qDebug() << "Fetch Folder alias " << alias;
if( !alias.isEmpty() ) {
emit(fetchFolderAlias( alias ));
}
}
}
void StatusDialog::slotPushFolder()
{
QModelIndex selected = _folderList->selectionModel()->currentIndex();
if( selected.isValid() ) {
QString alias = _model->data( selected, FolderViewDelegate::FolderAliasRole ).toString();
qDebug() << "Push Folder alias " << alias;
if( !alias.isEmpty() ) {
emit(pushFolderAlias( alias ));
}
}
}
void StatusDialog::slotEnableFolder()
{
QModelIndex selected = _folderList->selectionModel()->currentIndex();

View File

@@ -45,15 +45,14 @@ class FolderViewDelegate : public QStyledItemDelegate
FolderViewDelegate();
virtual ~FolderViewDelegate();
enum datarole { FolderAliasRole = Qt::UserRole + 100,
FolderPathRole = Qt::UserRole + 101,
FolderSecondPathRole = Qt::UserRole + 102,
FolderIconRole = Qt::UserRole + 103,
FolderRemotePath = Qt::UserRole + 104,
FolderStatus = Qt::UserRole + 105,
FolderErrorMsg = Qt::UserRole + 106,
FolderStatusIcon = Qt::UserRole + 107,
FolderSyncEnabled = Qt::UserRole + 108
enum datarole { FolderAliasRole = Qt::UserRole + 100,
FolderPathRole,
FolderSecondPathRole,
FolderRemotePath,
FolderStatus,
FolderErrorMsg,
FolderSyncEnabled,
FolderStatusIconRole
};
void paint( QPainter*, const QStyleOptionViewItem&, const QModelIndex& ) const;
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const;
@@ -73,8 +72,7 @@ public:
signals:
void removeFolderAlias( const QString& );
void fetchFolderAlias( const QString& );
void pushFolderAlias( const QString& );
void resetFolderAlias( const QString& );
void enableFolderAlias( const QString&, const bool );
void infoFolderAlias( const QString& );
void openFolderAlias( const QString& );
@@ -84,9 +82,8 @@ signals:
public slots:
void slotRemoveFolder();
void slotResetFolder();
void slotRemoveSelectedFolder();
void slotFetchFolder();
void slotPushFolder();
void slotFolderActivated( const QModelIndex& );
void slotOpenOC();
void slotEnableFolder();

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>544</width>
<height>308</height>
<height>313</height>
</rect>
</property>
<property name="windowTitle">
@@ -42,30 +42,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonRemove">
<property name="text">
<string>Remove...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonFetch">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Fetch...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonPush">
<property name="text">
<string>Push...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonEnable">
<property name="text">
@@ -73,13 +49,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonInfo">
<property name="text">
<string>Info...</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -88,11 +57,45 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>56</height>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="_ButtonRemove">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="_ButtonReset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="_ButtonInfo">
<property name="text">
<string>Info...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">

View File

@@ -82,7 +82,8 @@ QString Theme::version() const
QIcon Theme::trayFolderIcon( const QString& backend ) const
{
return folderIcon( backend );
Q_UNUSED(backend)
return applicationIcon();
}
/*

View File

@@ -70,11 +70,6 @@ public:
*/
virtual QString configFileName() const = 0;
/**
* get a folder icon for a given backend in a given size.
*/
virtual QIcon folderIcon( const QString& ) const = 0;
/**
* the icon that is shown in the tray context menu left of the folder name
*/
@@ -86,7 +81,6 @@ public:
virtual QIcon syncStateIcon( SyncResult::Status, bool sysTray = false ) const;
virtual QIcon folderDisabledIcon() const = 0;
virtual QPixmap splashScreen() const = 0;
virtual QIcon applicationIcon() const = 0;

48
test/scripts/README.rst Normal file
View File

@@ -0,0 +1,48 @@
Torture for Mirall
==================
This is a set of scripts comprising of two parts:
* ``torture_gen_layout.pl``: Generation of layout files (random)
* ``torture_create_files.pl``: Generation of a real file tree based on the
layout files (deterministic)
These scripts allow to produce a data set with the following criteria:
* realistic in naming
* realistic in file size
* realistic in structural size
without checking in the actual data. Instead, a layout file that gets generated
once (reference.lay) is checked in. This makes it possible to produce
standardized benchmarks for mirall. It allows allows to check for files gone
missing in action and other kinds of corruption produced during sync run.
``torture_create_files.pl`` can be fine tuned via variables in the script
header. It sources its file names from ``dict`` wordlist, file extensions and
other parameters can be added as needed. The defaults should be reasonable
in terms of size.
The ``references/`` directory contains default folder layouts.
Usage
-----
In order to create a reference layout and create a tree from it::
./torture_gen_layout.pl > reference.lay
./torture_create_files.pl reference.lay <targetdir>
TODO
----
* Based on the layout file, write a validator that checks files for existence
and size without requiring a full reference tree to be created via
``./torture_gen_layout.pl``.
* The current file naming is fairly tame (i.e. almost within ASCII range).
Extending it randomly is dangerous, we first need to filter all
characters forbidden by various OSes. Or maybe not, because we want to
see what happens? :-). Anyway, you have been warned.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
#!/usr/bin/env perl
use strict;
use File::Path qw(make_path);
use File::Basename qw(dirname);
if (scalar @ARGV < 2) {
print "Usage: $0 input.lay <offsetdir>\n";
exit;
}
my ($file, $offset_dir) = @ARGV;
open FILE, "<", $file or die $!;
while (<FILE>) {
my ($fillfile, $size) = split(/:/, $_);
$fillfile = $offset_dir . '/' . $fillfile;
my $dir = dirname $fillfile;
if (!-d $dir) { make_path $dir; }
open FILLFILE, ">", $fillfile;
print "writing $fillfile with $size bytes\n...";
print FILLFILE 0x01 x $size;
close FILLFILE;
}

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env perl
use strict;
use Data::Random::WordList;
############################################################################
# Which extensions to randomly assign
my @exts = ('txt', 'pdf', 'html', 'docx', 'xlsx', 'pptx', 'odt', 'ods', 'odp');
# Maximum depth of the target structure
my $depth = 4;
# Maximum amount of subfolders within a folder
my $max_subfolder = 10;
# Maximum amount of files within a folder
my $max_files_per_folder = 100;
# Maximum file size
my $max_file_size = 1024**2;
############################################################################
sub gen_entries($)
{
my ($count) = @_;
my $wl = new Data::Random::WordList( wordlist => '/usr/share/dict/words' );
my @rand_words = $wl->get_words($count);
foreach(@rand_words) {
$_ =~ s/\'//g;
}
$wl->close();
return @rand_words;
}
sub create_subdir($)
{
my ($depth) = @_;
$depth--;
my %dir_tree = ( );
my @dirs = gen_entries(int(rand($max_subfolders)));
my @files = gen_entries(int(rand($max_files_per_folder)));
foreach my $file(@files) {
$dir_tree{$file} = int(rand($max_file_size));
}
if ($depth > 0) {
foreach my $dir(@dirs) {
$dir_tree{$dir} = create_subdir($depth);
}
}
return \%dir_tree;
}
sub create_dir_listing(@)
{
my ($tree, $prefix) = @_;
foreach my $key(keys %$tree) {
my $entry = $tree->{$key};
#print "$entry:".scalar $entry.":".ref $entry."\n";
if (ref $entry eq "HASH") {
create_dir_listing($tree->{$key}, "$prefix/$key");
} else {
my $ext = @exts[rand @exts];
print "$prefix/$key.$ext:$entry\n";
}
}
}
srand();
my $dir = create_subdir($depth);
create_dir_listing($dir, '.');

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff