Compare commits
46
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be3630d009 | ||
|
|
6c93d6b66c | ||
|
|
aa7f82c09d | ||
|
|
c0a83f5c35 | ||
|
|
1bf1031ab2 | ||
|
|
012e6eff47 | ||
|
|
04a3e98238 | ||
|
|
3d9853e95b | ||
|
|
382118a93b | ||
|
|
3f4f949664 | ||
|
|
089b50c0de | ||
|
|
152f44b90e | ||
|
|
d089c4046f | ||
|
|
10dc173349 | ||
|
|
7ce69e3ea7 | ||
|
|
045a0b9c0a | ||
|
|
8813677ecb | ||
|
|
0d66d7503d | ||
|
|
f7fce46371 | ||
|
|
2a8f20e080 | ||
|
|
41e2b7b1ab | ||
|
|
f0c23407bf | ||
|
|
1caa25711f | ||
|
|
a156f4ce9f | ||
|
|
47133fdf3b | ||
|
|
78807d01ae | ||
|
|
aefc14b265 | ||
|
|
a99a848064 | ||
|
|
3a78a3bbb4 | ||
|
|
f11f34cdef | ||
|
|
39a35830e9 | ||
|
|
6904911ac1 | ||
|
|
fbd5bd19c6 | ||
|
|
97bbd7ed7f | ||
|
|
b5c83f5839 | ||
|
|
b978ceb020 | ||
|
|
d97472b93c | ||
|
|
d823cadda0 | ||
|
|
fd427f9196 | ||
|
|
b18f1a09f5 | ||
|
|
accc1c2302 | ||
|
|
6e590115fb | ||
|
|
c45233c11e | ||
|
|
27ad4ddbab | ||
|
|
e27b083213 | ||
|
|
be440baa23 |
No files matched your search
@@ -15,9 +15,9 @@
|
||||
* *
|
||||
* **************************************************************************/
|
||||
|
||||
/* Database configuration (mysql://, postgresql:// or oracle://) */
|
||||
WOPort = "0.0.0.0:50000";
|
||||
|
||||
/* Database configuration (mysql://, postgresql:// or oracle://) */
|
||||
|
||||
// MySQL
|
||||
SOGoProfileURL = "mysql://sogobuild:sogo123@mariadb:3306/sogo/sogo_user_profile";
|
||||
|
||||
@@ -2,6 +2,75 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [5.12.11](https://github.com/Alinto/sogo/compare/SOGo-5.12.10...SOGo-5.12.11) (2026-09-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **junk:** add junk action on mail view ([3f4f949](https://github.com/Alinto/sogo/commit/3f4f9496644953010a4a429f90eae733a50d61c4))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **core:** keep the [@import](https://github.com/import) cleanup working in stringWithoutHTMLInjection ([8813677](https://github.com/Alinto/sogo/commit/8813677ecb171e5d27cd582989c1d87b308c6df3))
|
||||
* **db:** release db channel after using them ([152f44b](https://github.com/Alinto/sogo/commit/152f44b90e08013b5c132473a2de249682d997df))
|
||||
* **db:** release db channel after using them part 2 ([089b50c](https://github.com/Alinto/sogo/commit/089b50c0defdb48e8c0bc0a13334591f3ee2dd11))
|
||||
* **junk:** extend list of junk icon available ([012e6ef](https://github.com/Alinto/sogo/commit/012e6eff471893efaac033c69ddf7838ca51b791))
|
||||
* **mail:** escape mail data placed in attributes of a compiled part ([045a0b9](https://github.com/Alinto/sogo/commit/045a0b9c0ac57aeea1b619f281acff0427cd81c7)), closes [#115](https://bugs.sogo.nu/view.php?id=115)
|
||||
* **mail:** stop interpreting iMIP card text fields as markup ([0d66d75](https://github.com/Alinto/sogo/commit/0d66d7503d8fd147842e87b9b4f1b921986ef44b))
|
||||
* **pwd:** use the proper url for reset password mail ([382118a](https://github.com/Alinto/sogo/commit/382118a93b6925de2ce7f774abc1865ebea2dbba))
|
||||
* **pwd:** use the proper url for reset password mail part2 ([04a3e98](https://github.com/Alinto/sogo/commit/04a3e9823889acaf6c247b224f5f7a0108f8f829))
|
||||
* **sanitization:** update regex for html sanitization ([10dc173](https://github.com/Alinto/sogo/commit/10dc1733496fb2f393537d864d83408e357f2215))
|
||||
* **UI:** use legitimate sorting value ([d089c40](https://github.com/Alinto/sogo/commit/d089c4046ffac8124874c504491db9d1f15ae650))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **hu:** Update Hungarian translations ([1bf1031](https://github.com/Alinto/sogo/commit/1bf1031ab2932f196f1adcc8fdfc9dea7dfb1f65))
|
||||
|
||||
## [5.12.10](https://github.com/Alinto/sogo/compare/SOGo-5.12.9...SOGo-5.12.10) (2026-08-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **sogo-tool:** add init-user command to create a user's personal folders and preferences without a login ([aefc14b](https://github.com/Alinto/sogo/commit/aefc14b265172e5ff94fa0fc1e4799f05d8e29f8))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bug:** escape angularJS only if needed to keep legitimate directive ([41e2b7b](https://github.com/Alinto/sogo/commit/41e2b7b1ab59fefe48cedf49ba82f4e03b646d23))
|
||||
* **bug:** incorrect method called ([1caa257](https://github.com/Alinto/sogo/commit/1caa25711f5891135c7ebca63f33b8758c00c8e8))
|
||||
* **calendar:** do not transmit og http status to external calendar ([3a78a3b](https://github.com/Alinto/sogo/commit/3a78a3bbb44484c95c141b0f3c0c8fabdc8bcf6a))
|
||||
* **ckeditor:** Sync resized image width/height into style and HTML attributes so Outlook and other mail clients ignoring CSS aspect-ratio render the correct dimensions. Closes [#6169](https://bugs.sogo.nu/view.php?id=6169). ([39a3583](https://github.com/Alinto/sogo/commit/39a35830e9d01a26b533515a20c1b4f527064519))
|
||||
* **dav:** properly parse MKCOL request ([78807d0](https://github.com/Alinto/sogo/commit/78807d01aee9195b95e2ed21344f260aadb2faef))
|
||||
* **event:** clean import of event ([b5c83f5](https://github.com/Alinto/sogo/commit/b5c83f58393e31151939d0d6fc227c0d0f127f33))
|
||||
* **event:** clean import of event ([b18f1a0](https://github.com/Alinto/sogo/commit/b18f1a09f59424a36f6de5aa7c30e6f27405c15d))
|
||||
* **mail:** escape angularJS directive for description ([47133fd](https://github.com/Alinto/sogo/commit/47133fdf3bc3148d374bbf413f058d714776e832))
|
||||
* **mail:** escape References/Organization/Newsgroups headers in HTML forward so message-id chevrons aren't parsed as HTML tags hiding the quoted body. Closes [#6046](https://bugs.sogo.nu/view.php?id=6046). ([f11f34c](https://github.com/Alinto/sogo/commit/f11f34cdefdd4175ae6c8b0814c2ccaecfd7c373))
|
||||
* **mail:** Some links broken in HTML rendering due to libxml2 (SOPE) only supporting HTML4 — when an anchor has no content between its opening and closing tags, store it and re-open it around the next element, closing </a> after that element's end tag. Closes [#5961](https://bugs.sogo.nu/view.php?id=5961). Closes [#6172](https://bugs.sogo.nu/view.php?id=6172). ([6904911](https://github.com/Alinto/sogo/commit/6904911ac17651de754246aff26fbb85aa8e01c7))
|
||||
* **passwordRecoveyr:** get the domain from the user mail ([a156f4c](https://github.com/Alinto/sogo/commit/a156f4ce9f0eda3ff54633d4bcb7051388d2f39b))
|
||||
* **tool:** wrong method called ([97bbd7e](https://github.com/Alinto/sogo/commit/97bbd7ed7f8173894f01b259f2f0f539ad6e95ed))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **hu:** Update Hungarian translations ([2a8f20e](https://github.com/Alinto/sogo/commit/2a8f20e080cdb39544622874a12fef807cc66612))
|
||||
|
||||
### [5.12.9](https://github.com/Alinto/sogo/compare/SOGo-5.12.8...SOGo-5.12.9) (2026-05-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **mail:** do not encode non-html element ([6e59011](https://github.com/Alinto/sogo/commit/6e590115fbce073847369495997228fba2fc3ce8))
|
||||
* **mail:** render the subject without html when searching ([be440ba](https://github.com/Alinto/sogo/commit/be440baa23fd8b6ad5d8c947f60f9105ad717214))
|
||||
* **pref:** prevent onevent cleaning to remove legitimate words ([c45233c](https://github.com/Alinto/sogo/commit/c45233c11e250a22fa1e1f3e47fee2d6e232045b))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **ca:** Update Catalan translations ([fd427f9](https://github.com/Alinto/sogo/commit/fd427f91967b99ca0d8eb42c4e5432f9ae4b49cf))
|
||||
* **es_ES:** Update SpanishSpain translations ([d823cad](https://github.com/Alinto/sogo/commit/d823cadda084e735c6dbeb2694f583bdf9fb7f9b))
|
||||
|
||||
### [5.12.8](https://github.com/Alinto/sogo/compare/SOGo-5.12.7...SOGo-5.12.8) (2026-05-11)
|
||||
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ following:
|
||||
* Database server (MariaDB, MySQL, PostgreSQL or Oracle)
|
||||
* LDAP server (OpenLDAP, Novell eDirectory, Microsoft Active Directory
|
||||
and others)
|
||||
* SMTP server (Postfix, Sendmail and others)
|
||||
* SMTP server (Postfix)
|
||||
* IMAP server (Courier, Cyrus IMAP Server, Dovecot and others)
|
||||
|
||||
If you plan to use ActiveSync, an IMAP server supporting the ACL,
|
||||
@@ -840,6 +840,16 @@ Obiously, if your users can connect without specifying a domain, let this parame
|
||||
|S |SOGoPasswordRecoveryEnabled
|
||||
|Boolean enable password recovery with secret question or secondary e-mail. Default value is `NO`.
|
||||
|
||||
|S |SOGoPasswordRecoveryBaseURLs
|
||||
| *Since 5.12.11*. List of allowed base URL for password reset link.
|
||||
|
||||
`SOGoPasswordRecoveryBaseURLs = ("https://demo.sogo.nu");`
|
||||
`SOGoPasswordRecoveryBaseURLs = ("https://platform1.sogo.nu", "https://platform2.sogo.nu);`
|
||||
|
||||
Do not end the URLs by '/'.
|
||||
|
||||
No defaults, will throw an error if empty or unset.
|
||||
|
||||
|S |SOGoPasswordRecoveryDomains
|
||||
|List of domains where password recovery is enabled, for example `(example.org, example.net)`. If empty array `()`, disabled for all domains. If not set, enabled for all domains.
|
||||
|
||||
@@ -2174,7 +2184,6 @@ The following table describes the related parameters.
|
||||
are:
|
||||
|
||||
[options="compact"]
|
||||
* `sendmail` - to use the sendmail binary
|
||||
* `smtp` - to use the SMTP protocol
|
||||
|
||||
|D |SOGoSMTPServer
|
||||
@@ -2202,10 +2211,6 @@ Current, Are supported `PLAIN` and 'xoauth2' for openid.
|
||||
|D |SOGoSMTPMasterUserPassword
|
||||
|SMTP account password for master account (`SOGoSMTPMasterUserEnabled` enabled).
|
||||
|
||||
|S |WOSendMail
|
||||
|The path of the sendmail binary.
|
||||
|
||||
Defaults to `/usr/lib/sendmail`.
|
||||
|
||||
|D |SOGoForceExternalLoginWithEmail
|
||||
|Parameter used to specify if, when logging in to the SMTP server, the
|
||||
@@ -2891,6 +2896,20 @@ SOGoMailJunkSettings = {
|
||||
};
|
||||
----
|
||||
|
||||
|D |mailJunkIcon
|
||||
|Choose the Junk icon. Values are :
|
||||
https://materialui.co/icon/thumb-down[thumb_down],
|
||||
https://materialui.co/icon/gpp-bad[gpp_bad],
|
||||
https://materialui.co/icon/local-fire-department[local_fire_department],
|
||||
https://materialui.co/icon/bug-report[bug_report],
|
||||
https://materialui.co/icon/error[error],
|
||||
https://materialui.co/icon/warning[warning],
|
||||
https://materialui.co/icon/dangerous[dangerous] and
|
||||
https://materialui.co/icon/report-gmailerrorred[report_gmailerrorred].
|
||||
|
||||
|
||||
Defaults to `thumb_down`.
|
||||
|
||||
|D |SOGoMailKeepDraftsAfterSend
|
||||
|Parameter used to keep mails in the drafts folder once they have been
|
||||
sent by SOGo. Defaults to `NO` when unset.
|
||||
@@ -3765,6 +3784,30 @@ sogo-tool create-folder user2 Calendar Pro_Calendar
|
||||
----
|
||||
|
||||
|
||||
=== sogo-tool init-user
|
||||
|
||||
Create the personal calendar and the personal address book of one or more users, and initialize
|
||||
their preferences. Those folders and preferences are otherwise only created upon the user's first
|
||||
login, which prevents any operation on them (setting ACLs or reading the user's preferences from a
|
||||
provisioning tool, for instance) beforehand.
|
||||
|
||||
The resulting preferences are the same as the ones a login through the web interface would produce.
|
||||
|
||||
init-user [-l language] user1 [user2] ...
|
||||
|
||||
* *user* is the name of the user
|
||||
* *language* is the language of the user's preferences, as it would be chosen at login. When
|
||||
omitted, the language of the domain or of the system is used. The categories and labels stored in
|
||||
the preferences are localized accordingly.
|
||||
|
||||
Example:
|
||||
----
|
||||
sogo-tool init-user user1
|
||||
sogo-tool init-user user1 user2
|
||||
sogo-tool init-user -l French user1
|
||||
----
|
||||
|
||||
|
||||
=== sogo-tool dump-defaults
|
||||
|
||||
Output all current defaults value of GNUstep and SOGo (sogo.conf)
|
||||
@@ -4265,6 +4308,9 @@ current version of SOGo from the previous release.
|
||||
[cols="100a"]
|
||||
|=======================================================================
|
||||
|
||||
h|5.12.11
|
||||
|If you enable Password Recovery, new mandatory settings `SOGoPasswordRecoveryBaseURLs`
|
||||
|
||||
h|5.11
|
||||
|Parameters `SOGoGlobalAddressBookFirstEntries` and `SOGoGlobalAddressBookFirstEntriesCount` has been removed. Please use `listRequiresDot` and `globalAddressBookFirstEntriesCount` instead. Signature are now between a div tag to avoid CKEditor changing the content - set `SOGoForceRawHtmlSignature` to `NO` to leave signature (https://bugs.sogo.nu/view.php?id=5920).
|
||||
|
||||
|
||||
@@ -32,10 +32,12 @@
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <GDLAccess/EOAdaptorContext.h>
|
||||
#import <GDLAccess/EOAdaptor.h>
|
||||
#import <NGExtensions/NGResourceLocator.h>
|
||||
|
||||
#import "GCSChannelManager.h"
|
||||
#import "EOAdaptorChannel+GCS.h"
|
||||
#import "EOQualifier+GCS.h"
|
||||
#import "GCSAlarmsFolder.h"
|
||||
#import "GCSAdminFolder.h"
|
||||
#import "GCSOpenIdFolder.h"
|
||||
@@ -383,21 +385,12 @@ static BOOL _singleStoreMode = NO;
|
||||
return [[self channelManager] canConnect:[self folderInfoLocation]];
|
||||
}
|
||||
|
||||
- (NSArray *)performSQL:(NSString *)_sql {
|
||||
EOAdaptorChannel *channel;
|
||||
- (NSArray *)performSQL:(NSString *)_sql withChannel: (EOAdaptorChannel*) channel{
|
||||
NSException *ex;
|
||||
NSMutableArray *rows;
|
||||
NSDictionary *row;
|
||||
NSArray *attrs;
|
||||
|
||||
/* acquire channel */
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel!"];
|
||||
return nil;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
|
||||
/* run SQL */
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:_sql]) != nil) {
|
||||
@@ -513,9 +506,12 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* generates a WHERE qualifier for matching the "quick" entries */
|
||||
NSMutableString *sql;
|
||||
EOAdaptorContext *adaptorContext;
|
||||
EOAdaptor *adaptor;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [_names count]) == 0) {
|
||||
@@ -523,10 +519,13 @@ static BOOL _singleStoreMode = NO;
|
||||
__PRETTY_FUNCTION__];
|
||||
return @"1 = 2";
|
||||
}
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:(count * 8)];
|
||||
|
||||
adaptorContext = [channel adaptorContext];
|
||||
adaptor = [adaptorContext adaptor];
|
||||
sql = [NSMutableString stringWithString:@""];
|
||||
for (i = 0; i < quickPathCount; i++) {
|
||||
NSString *pathColumn;
|
||||
EOQualifier *qualifier;
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, GCSPathColumnPattern, (i + 1));
|
||||
@@ -537,8 +536,11 @@ static BOOL _singleStoreMode = NO;
|
||||
if (i < count) {
|
||||
/* exact match, regular column */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendFormat:@" = '%@'", [_names objectAtIndex:i]];
|
||||
|
||||
qualifier = [[EOKeyValueQualifier alloc] initWithKey: pathColumn
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: [_names objectAtIndex:i]];
|
||||
[qualifier appendSQLToString: sql withAdaptor: adaptor];
|
||||
}
|
||||
else if (_beExact) {
|
||||
/* exact match, ensure that all additional quick-cols are NULL */
|
||||
@@ -569,9 +571,12 @@ static BOOL _singleStoreMode = NO;
|
||||
}
|
||||
|
||||
if (_beExact && (count > quickPathCount)) {
|
||||
[sql appendString:@" AND c_foldername = '"];
|
||||
[sql appendString:[_names lastObject]];
|
||||
[sql appendString:@"'"];
|
||||
EOQualifier *qualifier;
|
||||
[sql appendString:@" AND "];
|
||||
qualifier = [[EOKeyValueQualifier alloc] initWithKey: @"c_foldername"
|
||||
operatorSelector: EOQualifierOperatorEqual
|
||||
value: [_names lastObject]];
|
||||
[qualifier appendSQLToString: sql withAdaptor: adaptor];
|
||||
}
|
||||
|
||||
return sql;
|
||||
@@ -579,13 +584,15 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLPathFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs
|
||||
withChannel: channel];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
@@ -600,13 +607,15 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
- (NSString *)generateSQLPathAndNameFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
withChannel: (EOAdaptorChannel*) channel
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs
|
||||
withChannel: channel];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
@@ -726,6 +735,7 @@ static BOOL _singleStoreMode = NO;
|
||||
NSString *fname, *sname, *sql;
|
||||
NSArray *fnames, *records;
|
||||
unsigned int count;
|
||||
EOAdaptorChannel* channel;
|
||||
NSDictionary *record;
|
||||
BOOL result;
|
||||
|
||||
@@ -733,36 +743,41 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
fnames = [self internalNamesFromPath: _path];
|
||||
if (fnames)
|
||||
{
|
||||
sql = [self generateSQLPathFetchForInternalNames: fnames
|
||||
exactMatch: YES
|
||||
orDirectSubfolderMatch: NO];
|
||||
if ([sql length])
|
||||
{
|
||||
records = [self performSQL: sql];
|
||||
if (records)
|
||||
{
|
||||
count = [records count];
|
||||
if (count)
|
||||
{
|
||||
fname = [self internalNameFromPath: _path];
|
||||
if (count == 1)
|
||||
{
|
||||
record = [records objectAtIndex: 0];
|
||||
sname = [record objectForKey: GCSPathRecordName];
|
||||
result = [fname isEqualToString: sname];
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"records: %@", records];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
{
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathFetchForInternalNames: fnames
|
||||
exactMatch: YES
|
||||
orDirectSubfolderMatch: NO
|
||||
withChannel: channel];
|
||||
if ([sql length])
|
||||
{
|
||||
records = [self performSQL: sql withChannel: channel];
|
||||
if (records)
|
||||
{
|
||||
count = [records count];
|
||||
if (count)
|
||||
{
|
||||
fname = [self internalNameFromPath: _path];
|
||||
if (count == 1)
|
||||
{
|
||||
record = [records objectAtIndex: 0];
|
||||
sname = [record objectForKey: GCSPathRecordName];
|
||||
result = [fname isEqualToString: sname];
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"records: %@", records];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'", __PRETTY_FUNCTION__, sql];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
}
|
||||
else
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
|
||||
@@ -774,21 +789,29 @@ static BOOL _singleStoreMode = NO;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
EOAdaptorChannel *channel;
|
||||
unsigned i, count;
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES) withChannel: channel];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
[self releaseChannel: channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
@@ -833,27 +856,37 @@ static BOOL _singleStoreMode = NO;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
EOAdaptorChannel *channel;
|
||||
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
sql = [self generateSQLPathAndNameFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES) withChannel: channel];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
[self releaseChannel: channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
if ((count = [records count]) == 0) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
@@ -899,16 +932,23 @@ static BOOL _singleStoreMode = NO;
|
||||
NSArray *fnames, *records;
|
||||
NSString *ws;
|
||||
NSDictionary *record;
|
||||
|
||||
EOAdaptorChannel *channel;
|
||||
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* generate SQL to fetch folder attributes */
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
exactMatch:YES orDirectSubfolderMatch:NO withChannel: channel];
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT "];
|
||||
@@ -925,7 +965,7 @@ static BOOL _singleStoreMode = NO;
|
||||
|
||||
/* fetching */
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
if ((records = [self performSQL:sql withChannel: channel]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
@@ -992,44 +1032,55 @@ static BOOL _singleStoreMode = NO;
|
||||
andChannel: (EOAdaptorChannel *) channel
|
||||
atPath: (NSString *) path
|
||||
{
|
||||
NSString *baseURL, *tableName, *quickTableName, *aclTableName, *createQuery, *sql;
|
||||
NSString *baseURL, *tableName, *quickTableName, *aclTableName, *createQuery, *sql, *safeFolderName, *safePath;
|
||||
GCSSpecialQueries *specialQuery;
|
||||
EOAdaptorContext *aContext;
|
||||
EOAdaptor *adaptor;
|
||||
EOAttribute *attribute;
|
||||
NSMutableArray *paths;
|
||||
NSException *error;
|
||||
NSRange range;
|
||||
|
||||
paths = [NSMutableArray arrayWithArray: [path componentsSeparatedByString: @"/"]];
|
||||
aContext = [channel adaptorContext];
|
||||
[aContext beginTransaction];
|
||||
|
||||
//escape foldername to avoid sql injection
|
||||
adaptor = [aContext adaptor];
|
||||
|
||||
attribute = [EOAttribute new];
|
||||
[attribute autorelease];
|
||||
[attribute setExternalType: @"varchar"];
|
||||
|
||||
safeFolderName = [adaptor formatValue: folderName forAttribute: attribute];
|
||||
safePath = [adaptor formatValue: path forAttribute: attribute];
|
||||
|
||||
|
||||
paths = [NSMutableArray arrayWithArray: [safePath componentsSeparatedByString: @"/"]];
|
||||
|
||||
while ([paths count] < 5)
|
||||
[paths addObject: @"NULL"];
|
||||
|
||||
aContext = [channel adaptorContext];
|
||||
[aContext beginTransaction];
|
||||
|
||||
tableName = [self baseTableNameWithUID: [paths objectAtIndex: 2]];
|
||||
quickTableName = [tableName stringByAppendingString: @"_quick"];
|
||||
aclTableName = [tableName stringByAppendingString: @"_acl"];
|
||||
|
||||
// TBD: fix SQL injection issues.
|
||||
// We no longer call stringByDeletingLastPathComponent since, since GNUstep 1.22,
|
||||
// it'll replace // characters in the URL with /, so mysql:// becomes mysql:/
|
||||
// This is to conform with recent Apple changes.
|
||||
baseURL = [folderInfoLocation absoluteString];
|
||||
range = [baseURL rangeOfString: @"/" options: NSBackwardsSearch];
|
||||
if (range.location != NSNotFound)
|
||||
baseURL = [baseURL substringToIndex: range.location];
|
||||
|
||||
|
||||
|
||||
//Mind the quote, safeFolderName and safePath already have them as they have been escaped, c_path4 already has one at the end
|
||||
sql = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
|
||||
@" c_foldername, c_location, c_quick_location,"
|
||||
@" c_acl_location, c_folder_type)"
|
||||
@" VALUES ('%@', '%@', '%@', '%@', '%@', '%@', '%@/%@',"
|
||||
@" VALUES (%@, '%@', '%@', '%@', '%@, %@, '%@/%@',"
|
||||
@" '%@/%@', '%@/%@', '%@')",
|
||||
[self folderInfoTableName], path,
|
||||
[self folderInfoTableName], safePath,
|
||||
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
|
||||
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
|
||||
[folderName stringByReplacingString: @"'" withString: @"''"],
|
||||
safeFolderName,
|
||||
baseURL, tableName,
|
||||
baseURL, quickTableName,
|
||||
baseURL, aclTableName,
|
||||
@@ -1114,6 +1165,12 @@ static BOOL _singleStoreMode = NO;
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((folder = [self folderAtPath:_path]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolder"
|
||||
reason:@"missing folder"
|
||||
@@ -1126,15 +1183,11 @@ static BOOL _singleStoreMode = NO;
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
exactMatch:YES orDirectSubfolderMatch:NO withChannel: channel];
|
||||
|
||||
sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@",
|
||||
[self folderInfoTableName], ws];
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
|
||||
[[channel adaptorContext] beginTransaction];
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ vtodo_class2 = "(Bizalmas feladat)";
|
||||
"time_label" = "Idő";
|
||||
"to_label" = "-";
|
||||
"due_label" = "Lejárat napja:";
|
||||
"location_label" = "Hely";
|
||||
"location_label" = "Helyszín";
|
||||
"summary_label" = "Összegzés:";
|
||||
"comment_label" = "Megjegyzés:";
|
||||
"organizer_label" = "Szervező";
|
||||
|
||||
@@ -3521,6 +3521,15 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
timezone = nil;
|
||||
element = [components objectAtIndex: i];
|
||||
|
||||
//remove all attenddees, change organisator and change uid
|
||||
//If we do not clean up, any user could impersonate someone by importing a malicious .ics
|
||||
//and send notificaitons to attenddes or remove their event (as SOGo think the user has the rights to do so)
|
||||
[element removeAllAttendees];
|
||||
[element setOrganizer: nil];
|
||||
[element setUid: [self globallyUniqueObjectId]];
|
||||
|
||||
|
||||
|
||||
if ([element isKindOfClass: iCalEventK])
|
||||
{
|
||||
event = (iCalEvent *)element;
|
||||
|
||||
@@ -184,6 +184,10 @@ size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
else
|
||||
[result setObject: @"invalid-calendar-content" forKey: @"error"];
|
||||
}
|
||||
else if (status == 401)
|
||||
{
|
||||
[result setObject: @"need-auth" forKey: @"error"];
|
||||
}
|
||||
else
|
||||
[result setObject: @"http-error" forKey: @"error"];
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ static NSString *userAgent = nil;
|
||||
|
||||
- (void) setText: (NSString *) newText
|
||||
{
|
||||
ASSIGN (text, [newText stringWithoutHTMLInjection: NO]);
|
||||
ASSIGN (text, [newText stringWithoutHTMLInjection: NO stripAngular: NO]);
|
||||
}
|
||||
|
||||
- (NSString *) text
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"organization"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"organization"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"organization"]];
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"newsgroups"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"newsgroups"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"newsgroups"]];
|
||||
|
||||
@@ -222,7 +222,7 @@
|
||||
NSString *rc;
|
||||
|
||||
if (htmlComposition)
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [self _headerField: @"references"]];
|
||||
rc = [NSString stringWithFormat: @"%@<br/>", [[self _headerField: @"references"] stringByEscapingHTMLString]];
|
||||
else
|
||||
rc = [NSString stringWithFormat: @"%@\n", [self _headerField: @"references"]];
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@
|
||||
|
||||
/* XSS protection */
|
||||
- (NSString *) removeHTMLTagsExceptAnchorTags;
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode;
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode
|
||||
stripAngular: (BOOL)stripAngular;
|
||||
|
||||
#ifndef GNUSTEP_BASE_LIBRARY
|
||||
- (BOOL) boolValue;
|
||||
|
||||
@@ -936,18 +936,19 @@ static int cssEscapingCount;
|
||||
* @param stripHTMLCode Remove all HTML code from content
|
||||
* @return A safe string
|
||||
*/
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode
|
||||
- (NSString *) stringWithoutHTMLInjection: (BOOL)stripHTMLCode stripAngular: (BOOL)stripAngular
|
||||
{
|
||||
NSString *result, *text, *newResult;
|
||||
NSScanner *theScanner;
|
||||
NSError *error;
|
||||
NSUInteger numberOfMatches;
|
||||
NSRegularExpression *regex;
|
||||
NSRegularExpression *regex, *importRegex;
|
||||
|
||||
text = nil;
|
||||
error = nil;
|
||||
result = [NSString stringWithString: self];
|
||||
regex = nil;
|
||||
importRegex = nil;
|
||||
|
||||
NS_DURING
|
||||
{
|
||||
@@ -986,20 +987,28 @@ static int cssEscapingCount;
|
||||
// Remove javascript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"j[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*a[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
// loop until stable: a single pass lets nested tokens reconstruct
|
||||
// the scheme, e.g. "javajavascript:script:" -> "javascript:"
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove vbscript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"v[\\s\\u200B	

\\\\0]*b[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove livescript:
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"l[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*v[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*:"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
while ([regex numberOfMatchesInString:result options:0 range:NSMakeRange(0, [result length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@""];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
// Remove <script
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*c[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*t"
|
||||
@@ -1031,34 +1040,41 @@ static int cssEscapingCount;
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"</for*"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// // Remove onload
|
||||
// regex = [NSRegularExpression regularExpressionWithPattern:@"onload="
|
||||
// options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
// newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onl***="];
|
||||
// result = [NSString stringWithString: newResult];
|
||||
|
||||
// // Remove onmouseover
|
||||
// regex = [NSRegularExpression regularExpressionWithPattern:@"onmouseover="
|
||||
// options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
// newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onmouseo***="];
|
||||
// result = [NSString stringWithString: newResult];
|
||||
|
||||
// regex = [NSRegularExpression regularExpressionWithPattern:@"onrepeat="
|
||||
// options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
// newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"onrep***="];
|
||||
// result = [NSString stringWithString: newResult];
|
||||
|
||||
regex = [NSRegularExpression regularExpressionWithPattern: @"(on\\w+)\\s*=\\s*([\"'][^\"']*[\"']|[^\\s>]+)"
|
||||
options: NSRegularExpressionCaseInsensitive error: &error];
|
||||
newResult = [regex stringByReplacingMatchesInString: result options: 0 range: NSMakeRange(0, [result length]) withTemplate: @"on***=\"\""];
|
||||
// Remove ANY inline event handler (on...=) in one rule instead of an
|
||||
// incomplete allow list. This also covers obfuscation by whitespace
|
||||
// before the '=' ("onerror =") and handler names that were not listed
|
||||
// before (onfocus, onbegin, onanimationstart, ...). With onfocus gone,
|
||||
// a lone "autofocus" has no handler left to trigger.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"\\bon(click|error|focus|load|mouseover|animationstart)[\\s\\u200B	

\\r\\n\\t]*="
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"data-blocked="];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove @import css (in style tags)
|
||||
importRegex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e.*)([\\s\\u200B	

\\\\0]*@[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*m[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*o[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*t)(.*<[\\s\\u200B	

\\\\0]*\\/[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*>)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [importRegex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"$1@im****$3"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
|
||||
// Remove @import css (in style tags)
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(<[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e.*)([\\s\\u200B	

\\\\0]*@[\\s\\u200B	

\\\\0]*i[\\s\\u200B	

\\\\0]*m[\\s\\u200B	

\\\\0]*p[\\s\\u200B	

\\\\0]*o[\\s\\u200B	

\\\\0]*r[\\s\\u200B	

\\\\0]*t)(.*<[\\s\\u200B	

\\\\0]*\\/[\\s\\u200B	

\\\\0]*s[\\s\\u200B	

\\\\0]*t[\\s\\u200B	

\\\\0]*y[\\s\\u200B	

\\\\0]*l[\\s\\u200B	

\\\\0]*e[\\s\\u200B	

\\\\0]*>)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
|
||||
if(stripAngular) {
|
||||
// Remove {{ and }} as they are interprated by angularJS with no way of escaping.
|
||||
// Cover the literal form, the hex entity ({) AND the decimal entity
|
||||
// ({), both with optional leading zeros, since the browser decodes
|
||||
// any of them back to a brace before AngularJS parses the node.
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\{\\{)|(�*7b;�*7b;)|(�*123;�*123;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"{\\\\{"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
regex = [NSRegularExpression regularExpressionWithPattern:@"(\\}\\})|(�*7d;�*7d;)|(�*125;�*125;)"
|
||||
options: NSRegularExpressionCaseInsensitive error:&error];
|
||||
newResult = [regex stringByReplacingMatchesInString:result options:0 range:NSMakeRange(0, [result length]) withTemplate:@"}/}"];
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
|
||||
newResult = result;
|
||||
while([regex numberOfMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length])] > 0) {
|
||||
newResult = [regex stringByReplacingMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length]) withTemplate:@"$1@im****$3"];
|
||||
while([importRegex numberOfMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length])] > 0) {
|
||||
newResult = [importRegex stringByReplacingMatchesInString:newResult options:0 range:NSMakeRange(0, [newResult length]) withTemplate:@"$1@im****$3"];
|
||||
}
|
||||
result = [NSString stringWithString: newResult];
|
||||
}
|
||||
@@ -1073,14 +1089,75 @@ static int cssEscapingCount;
|
||||
}
|
||||
|
||||
- (NSString *) cleanInvalidHTMLTags {
|
||||
// Clean HTML invalid tags as reported in https://bugs.sogo.nu/view.php?id=5755
|
||||
NSString *s;
|
||||
|
||||
s = [NSString stringWithString: self];
|
||||
s = [s stringByReplacingOccurrencesOfString:@"<!-->" withString:@""];
|
||||
s = [s stringByReplacingOccurrencesOfString:@"<!--<!" withString:@"<!--"];
|
||||
// Clean HTML invalid tags as reported in https://bugs.sogo.nu/view.php?id=5755 and https://bugs.sogo.nu/view.php?id=6167
|
||||
// libxml2 (HTML4) sees a standalone empty comment (<!--> or <!--->) as an
|
||||
// unterminated comment and drops the rest of the document, so remove it.
|
||||
// Only do it outside of comments: the Outlook "downlevel-revealed" pattern
|
||||
// <!--[if !mso]><!--> ... <!--<![endif]--> ends its first comment with
|
||||
// "<!-->", and removing it would hide the content in between.
|
||||
NSString *result;
|
||||
unichar *in, *out;
|
||||
NSUInteger len, i, j, o;
|
||||
|
||||
return s;
|
||||
len = [self length];
|
||||
if (len == 0)
|
||||
return [NSString string];
|
||||
|
||||
// Work on raw buffers: linear time, bounded memory (no per-comment objects)
|
||||
in = NSZoneMalloc (NULL, len * sizeof (unichar));
|
||||
out = NSZoneMalloc (NULL, len * sizeof (unichar));
|
||||
[self getCharacters: in];
|
||||
i = o = 0;
|
||||
|
||||
while (i < len)
|
||||
{
|
||||
if (i + 3 < len
|
||||
&& in[i] == '<' && in[i+1] == '!' && in[i+2] == '-' && in[i+3] == '-')
|
||||
{
|
||||
j = i + 4;
|
||||
if (j < len && in[j] == '>')
|
||||
{
|
||||
// <!-->
|
||||
i = j + 1;
|
||||
continue;
|
||||
}
|
||||
if (j + 1 < len && in[j] == '-' && in[j+1] == '>')
|
||||
{
|
||||
// <!--->
|
||||
i = j + 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Regular comment: keep it untouched up to its end ("-->" or "--!>",
|
||||
// as libxml2 accepts both), or up to the end if unterminated
|
||||
while (j < len)
|
||||
{
|
||||
if (j + 2 < len && in[j] == '-' && in[j+1] == '-' && in[j+2] == '>')
|
||||
{
|
||||
j += 3;
|
||||
break;
|
||||
}
|
||||
if (j + 3 < len && in[j] == '-' && in[j+1] == '-'
|
||||
&& in[j+2] == '!' && in[j+3] == '>')
|
||||
{
|
||||
j += 4;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
memcpy (out + o, in + i, (j - i) * sizeof (unichar));
|
||||
o += j - i;
|
||||
i = j;
|
||||
}
|
||||
else
|
||||
out[o++] = in[i++];
|
||||
}
|
||||
|
||||
result = [NSString stringWithCharacters: out length: o];
|
||||
NSZoneFree (NULL, in);
|
||||
NSZoneFree (NULL, out);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -93,7 +93,7 @@ static const NSString *kCacheMotdKey = @"admin-motd";
|
||||
NSException *error;
|
||||
NSString *safeMotd;
|
||||
|
||||
safeMotd = [motd stringWithoutHTMLInjection: NO];
|
||||
safeMotd = [motd stringWithoutHTMLInjection: NO stripAngular: NO];
|
||||
error = [[[GCSFolderManager defaultFolderManager] adminFolder] writeMotd: safeMotd];
|
||||
if (!error) {
|
||||
[[SOGoCache sharedCache] setValue:safeMotd forKey:kCacheMotdKey];
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
SOGoLDAPContactInfoAttribute = "description";
|
||||
|
||||
SOGoMailingMechanism = "sendmail";
|
||||
SOGoMailingMechanism = "smtp";
|
||||
SOGoSMTPServer = "smtp://localhost";
|
||||
SOGoMailSpoolPath = "/var/spool/sogo";
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
- (BOOL) notifyOnExternalModifications;
|
||||
|
||||
- (NSDictionary *) mailJunkSettings;
|
||||
- (NSString *) mailJunkIcon;
|
||||
|
||||
- (BOOL) createIdentitiesDisabled;
|
||||
|
||||
|
||||
@@ -304,11 +304,10 @@
|
||||
NSString *mailingMechanism;
|
||||
|
||||
mailingMechanism = [self stringForKey: @"SOGoMailingMechanism"];
|
||||
if (!([mailingMechanism isEqualToString: @"sendmail"]
|
||||
|| [mailingMechanism isEqualToString: @"smtp"]))
|
||||
if (![mailingMechanism isEqualToString: @"smtp"])
|
||||
{
|
||||
[self logWithFormat: @"mechanism '%@' is invalid and"
|
||||
@" should be set to 'sendmail' or 'smtp' instead",
|
||||
@" should be set to 'smtp' instead",
|
||||
mailingMechanism];
|
||||
mailingMechanism = nil;
|
||||
}
|
||||
@@ -482,6 +481,29 @@
|
||||
return [self objectForKey: @"SOGoMailJunkSettings"];
|
||||
}
|
||||
|
||||
- (NSString *) mailJunkIcon
|
||||
{
|
||||
NSArray *iconsList;
|
||||
NSString *icon;
|
||||
|
||||
iconsList = [NSArray arrayWithObjects: @"thumb_down",
|
||||
@"gpp_bad",
|
||||
@"local_fire_department",
|
||||
@"bug_report",
|
||||
@"error",
|
||||
@"warning",
|
||||
@"dangerous",
|
||||
@"report_gmailerrorred",
|
||||
nil];
|
||||
icon = [self objectForKey: @"mailJunkIcon"];
|
||||
if (([icon length] && ![iconsList containsObject:icon]) || ![icon length])
|
||||
{
|
||||
icon = @"thumb_down";
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
- (BOOL) createIdentitiesDisabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoCreateIdentitiesDisabled"];
|
||||
|
||||
@@ -149,6 +149,7 @@ NSComparisonResult languageSort(id el1, id el2, void *context);
|
||||
- (BOOL) isEasUIDisabled;
|
||||
|
||||
- (BOOL)isPasswordRecoveryEnabled;
|
||||
- (NSArray *) passwordRecoveryBaseURLs;
|
||||
- (NSArray *) passwordRecoveryDomains;
|
||||
- (NSString *) JWTSecret;
|
||||
|
||||
|
||||
@@ -1082,6 +1082,11 @@ NSComparisonResult languageSort(id el1, id el2, void *context)
|
||||
return [self boolForKey: @"SOGoPasswordRecoveryEnabled"];
|
||||
}
|
||||
|
||||
- (NSArray *) passwordRecoveryBaseURLs
|
||||
{
|
||||
return [self stringArrayForKey: @"SOGoPasswordRecoveryBaseURLs"];
|
||||
}
|
||||
|
||||
- (NSArray *) passwordRecoveryDomains
|
||||
{
|
||||
static NSArray *passwordRecoveryDomains = nil;
|
||||
|
||||
@@ -152,7 +152,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
rc = NO;
|
||||
|
||||
if ([fullName length])
|
||||
[identity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"];
|
||||
[identity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"];
|
||||
if ([email length])
|
||||
[identity setObject: email forKey: @"email"];
|
||||
if ([replyTo length])
|
||||
@@ -864,7 +864,7 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
if (mailIdentity && [mailIdentity objectForKey: @"fullName"]) {
|
||||
fullName = [NSString stringWithString: [mailIdentity objectForKey: @"fullName"]];
|
||||
if (fullName) {
|
||||
[mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES] forKey: @"fullName"];
|
||||
[mailIdentity setObject: [fullName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"fullName"];
|
||||
[mailIdentities setObject: mailIdentity atIndexedSubscript: i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,23 +99,43 @@
|
||||
|
||||
- (void) test_stringWithoutHTMLInjection
|
||||
{
|
||||
testEquals([[NSString stringWithString:@"<a href=\"\">foo</a>bar"] stringWithoutHTMLInjection: YES], @" foo bar");
|
||||
testEquals([[NSString stringWithString:@"fb <foo@bar.com>"] stringWithoutHTMLInjection: YES], @"fb <foo@bar.com>");
|
||||
testEquals([[NSString stringWithString:@"Test\n<script>alert(\"foobar\");"] stringWithoutHTMLInjection: NO], @"Test\n<scr***>alert(\"foobar\");");
|
||||
testEquals([[NSString stringWithString:@"<img vbscript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img javascript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img livescript:test"] stringWithoutHTMLInjection: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"foobar <form action=\"\">bar</form>"] stringWithoutHTMLInjection: NO], @"foobar <for* action=\"\">bar</for*>");
|
||||
testEquals([[NSString stringWithString:@"foobar <iframe src=\"\">bar</iframe>"] stringWithoutHTMLInjection: NO], @"foobar <ifr*** src=\"\">bar</iframe>");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO], @"foobar <img onl***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO], @"foobar <img onmouseo***=foo bar");
|
||||
testEquals([[NSString stringWithString:@"<!DOCTYPE html><html><head><style>@import url(https://foo.bar/malicious.css);.foo{background-color: red; @import url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>"] stringWithoutHTMLInjection: NO], @"<!DOCTYPE html><html><head><style>@im**** url(https://foo.bar/malicious.css);.foo{background-color: red; @im**** url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>");
|
||||
testEquals([[NSString stringWithString:@"<a href=\"\">foo</a>bar"] stringWithoutHTMLInjection: YES stripAngular: NO], @" foo bar");
|
||||
testEquals([[NSString stringWithString:@"fb <foo@bar.com>"] stringWithoutHTMLInjection: YES stripAngular: NO], @"fb <foo@bar.com>");
|
||||
testEquals([[NSString stringWithString:@"Test\n<script>alert(\"foobar\");"] stringWithoutHTMLInjection: NO stripAngular: NO], @"Test\n<scr***>alert(\"foobar\");");
|
||||
testEquals([[NSString stringWithString:@"<img vbscript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img javascript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"<img livescript:test"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img test");
|
||||
testEquals([[NSString stringWithString:@"foobar <form action=\"\">bar</form>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <for* action=\"\">bar</for*>");
|
||||
testEquals([[NSString stringWithString:@"foobar <iframe src=\"\">bar</iframe>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <ifr*** src=\"\">bar</iframe>");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onload=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
testEquals([[NSString stringWithString:@"foobar <img onmouseover=foo bar"] stringWithoutHTMLInjection: NO stripAngular: NO], @"foobar <img data-blocked=foo bar");
|
||||
// any on...= handler is neutralised, including whitespace before '=' and names
|
||||
// that were never in the old list
|
||||
testEquals([[NSString stringWithString:@"<img src=x onerror =alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<img src=x data-blocked=alert(1)>");
|
||||
testEquals([[NSString stringWithString:@"<input autofocus onfocus=alert(1)>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<input autofocus data-blocked=alert(1)>");
|
||||
// deletion filters loop until stable, so nesting cannot rebuild the scheme
|
||||
testEquals([[NSString stringWithString:@"javajavascript:script:"] stringWithoutHTMLInjection: NO stripAngular: NO], @"");
|
||||
testEquals([[NSString stringWithString:@"<!DOCTYPE html><html><head><style>@import url(https://foo.bar/malicious.css);.foo{background-color: red; @import url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>"] stringWithoutHTMLInjection: NO stripAngular: NO], @"<!DOCTYPE html><html><head><style>@im**** url(https://foo.bar/malicious.css);.foo{background-color: red; @im**** url(https://bar.foo/malicious2.css);</style></head><body><table><tr><td>A</td><td>B</td><td>C</td></tr></table></body></html>");
|
||||
// the @import cleanup must still run when angular interpolation is stripped as well
|
||||
testEquals([[NSString stringWithString:@"<style>@import url(https://foo.bar/malicious.css);</style>"] stringWithoutHTMLInjection: NO stripAngular: YES], @"<style>@im**** url(https://foo.bar/malicious.css);</style>");
|
||||
// literal braces are rewritten so AngularJS cannot interpolate them
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
// ... and so are the decimal HTML entities the browser would decode back to braces
|
||||
testEquals([[NSString stringWithString:@"{{1337*1337}}"] stringWithoutHTMLInjection: NO stripAngular: YES], @"{\\{1337*1337}/}");
|
||||
}
|
||||
|
||||
- (void) test_stringCleanInvalidHTMLTags
|
||||
{
|
||||
testEquals([[NSString stringWithString:@"<div>Test<!--></div>"] cleanInvalidHTMLTags], @"<div>Test</div>");
|
||||
testEquals([[NSString stringWithString:@"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>"] cleanInvalidHTMLTags], @"<div><!--[if !mso]><span>Test</span><!--[endif]--></div>");
|
||||
testEquals([[NSString stringWithString:@"<div>Test<!---></div>"] cleanInvalidHTMLTags], @"<div>Test</div>");
|
||||
testEquals([[NSString stringWithString:@"<div>A<!-->B<!-- c -->C<!-->D</div>"] cleanInvalidHTMLTags], @"<div>AB<!-- c -->CD</div>");
|
||||
testEquals([[NSString stringWithString:@"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>"] cleanInvalidHTMLTags], @"<div><!--[if !mso]><span>Test</span><!--<![endif]--></div>");
|
||||
// Outlook "downlevel-revealed" conditional comment: content must stay visible
|
||||
testEquals([[NSString stringWithString:@"<a><!--[if !mso]><!--> <div><img src=\"x\"/></div> <!--<![endif]--><!--[if mso]><v:fill/><![endif]--></a>"] cleanInvalidHTMLTags], @"<a><!--[if !mso]><!--> <div><img src=\"x\"/></div> <!--<![endif]--><!--[if mso]><v:fill/><![endif]--></a>");
|
||||
// libxml2 also ends a comment with "--!>"
|
||||
testEquals([[NSString stringWithString:@"A<!-- x --!>B<!-->C"] cleanInvalidHTMLTags], @"A<!-- x --!>BC");
|
||||
// unterminated comment is left as is
|
||||
testEquals([[NSString stringWithString:@"<div>A<!-- B</div>"] cleanInvalidHTMLTags], @"<div>A<!-- B</div>");
|
||||
}
|
||||
|
||||
- (void) test_stringRemoveHTMLTagsExceptAnchorTags
|
||||
|
||||
@@ -25,6 +25,7 @@ $(SOGO_TOOL)_OBJC_FILES += \
|
||||
SOGoToolCleanupUser.m \
|
||||
SOGoToolRestore.m \
|
||||
SOGoToolCreateFolder.m \
|
||||
SOGoToolInitUser.m \
|
||||
SOGoToolUserPreferences.m \
|
||||
SOGoToolManageACL.m \
|
||||
SOGoToolManageEAS.m \
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/* SOGoToolInitUser.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2026 Alinto
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
#import <NGObjWeb/WOComponent.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <SOGo/SOGoGCSFolder.h>
|
||||
#import <SOGo/SOGoParentFolder.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
|
||||
#import "SOGoToolRestore.h"
|
||||
|
||||
|
||||
@interface NSObject (UIxJSONPreferences)
|
||||
|
||||
- (NSString *) jsonDefaults;
|
||||
|
||||
@end
|
||||
|
||||
@interface SOGoToolInitUser : SOGoToolRestore
|
||||
{
|
||||
NSArray *usersToInit;
|
||||
NSString *language;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoToolInitUser
|
||||
|
||||
+ (NSString *) command
|
||||
{
|
||||
return @"init-user";
|
||||
}
|
||||
|
||||
+ (NSString *) description
|
||||
{
|
||||
return @"create the personal folders and preferences of user(s) without requiring a login";
|
||||
}
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
usersToInit = nil;
|
||||
language = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[usersToInit release];
|
||||
[language release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) usage
|
||||
{
|
||||
fprintf (stderr, "init-user [-l language] user1 [user2] ...\n\n"
|
||||
" user the user whose personal folders must be created\n"
|
||||
" language the language of the user's preferences, as chosen\n"
|
||||
" at login (defaults to the domain or system one)\n\n"
|
||||
"Creates the personal calendar and the personal address book of the\n"
|
||||
"user(s) and initializes their preferences, as it would otherwise only\n"
|
||||
"happen upon their first login.\n\n"
|
||||
"Example: sogo-tool init-user jdoe\n"
|
||||
" sogo-tool init-user -l French jdoe jsmith\n");
|
||||
}
|
||||
|
||||
- (BOOL) parseArguments
|
||||
{
|
||||
NSArray *supportedLanguages;
|
||||
NSString *requestedLanguage;
|
||||
|
||||
if ([sanitizedArguments count] < 1)
|
||||
{
|
||||
[self usage];
|
||||
return NO;
|
||||
}
|
||||
|
||||
requestedLanguage = [[NSUserDefaults standardUserDefaults] stringForKey: @"l"];
|
||||
if ([requestedLanguage length])
|
||||
{
|
||||
supportedLanguages = [[SOGoSystemDefaults sharedSystemDefaults]
|
||||
supportedLanguages];
|
||||
if (![supportedLanguages containsObject: requestedLanguage])
|
||||
{
|
||||
fprintf (stderr, "Unsupported language: %s\n",
|
||||
[requestedLanguage UTF8String]);
|
||||
return NO;
|
||||
}
|
||||
ASSIGN (language, requestedLanguage);
|
||||
}
|
||||
|
||||
ASSIGN (usersToInit, sanitizedArguments);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* The lookup of the "personal" folder triggers its creation when it does not
|
||||
exist yet, provided the active user is the owner of the folder. */
|
||||
- (BOOL) _initFolderOfType: (NSString *) folderType
|
||||
withUserFolder: (SOGoUserFolder *) userFolder
|
||||
inContext: (WOContext *) localContext
|
||||
{
|
||||
SOGoParentFolder *parentFolder;
|
||||
id folder;
|
||||
|
||||
parentFolder = [userFolder lookupName: folderType
|
||||
inContext: localContext
|
||||
acquire: NO];
|
||||
if (![parentFolder isKindOfClass: [SOGoParentFolder class]])
|
||||
{
|
||||
NSLog (@"module '%@' is not available for user '%@'", folderType, userID);
|
||||
return NO;
|
||||
}
|
||||
[parentFolder setContext: localContext];
|
||||
|
||||
folder = [parentFolder lookupPersonalFolder: @"personal"
|
||||
ignoringRights: YES];
|
||||
if (![folder isKindOfClass: [SOGoGCSFolder class]])
|
||||
{
|
||||
NSLog (@"personal folder of module '%@' could not be created for user"
|
||||
@" '%@'", folderType, userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
NSLog (@"personal folder of module '%@' is ready for user '%@'",
|
||||
folderType, userID);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* Upon the first login, the c_defaults of the user are materialized when the
|
||||
web interface loads: -[UIxJSONPreferences jsonDefaults] resolves every
|
||||
default through the domain and system defaults, writes them into the user's
|
||||
profile and synchronizes it. We invoke that very method so that an
|
||||
initialized user is indistinguishable from a user who has logged in. */
|
||||
- (BOOL) _initDefaultsOfUser: (SOGoUser *) user
|
||||
inContext: (WOContext *) localContext
|
||||
{
|
||||
WOComponent *jsonPreferences;
|
||||
Class jsonPreferencesKlass;
|
||||
|
||||
/* The language must be set before the component is built: -jsonDefaults only
|
||||
materializes the defaults that are missing, and the labels it localizes
|
||||
(the calendar and contacts categories) are looked up in the languages of
|
||||
the context, which are those of the user. */
|
||||
if (language)
|
||||
[[user userDefaults] setLanguage: language];
|
||||
|
||||
if (![WOApplication application])
|
||||
[[WOApplication alloc] init];
|
||||
|
||||
jsonPreferencesKlass = NSClassFromString (@"UIxJSONPreferences");
|
||||
if (!jsonPreferencesKlass)
|
||||
{
|
||||
NSLog (@"class 'UIxJSONPreferences' is unavailable, defaults of user"
|
||||
@" '%@' cannot be initialized", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
jsonPreferences = [[[jsonPreferencesKlass alloc]
|
||||
initWithContext: localContext] autorelease];
|
||||
|
||||
if (![jsonPreferences jsonDefaults])
|
||||
{
|
||||
NSLog (@"defaults of user '%@' could not be initialized", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
NSLog (@"defaults of user '%@' are ready", userID);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL) _initUser
|
||||
{
|
||||
SOGoUserFolder *userFolder;
|
||||
WOContext *localContext;
|
||||
SOGoUser *user;
|
||||
BOOL rc;
|
||||
|
||||
user = [SOGoUser userWithLogin: userID];
|
||||
if (!user)
|
||||
{
|
||||
NSLog (@"user '%@' could not be instantiated", userID);
|
||||
return NO;
|
||||
}
|
||||
|
||||
localContext = [WOContext context];
|
||||
[localContext setActiveUser: user];
|
||||
|
||||
rc = [self _initDefaultsOfUser: user inContext: localContext];
|
||||
|
||||
userFolder = [SOGoUserFolder objectWithName: userID inContainer: nil];
|
||||
[userFolder setContext: localContext];
|
||||
|
||||
rc = [self _initFolderOfType: @"Calendar"
|
||||
withUserFolder: userFolder
|
||||
inContext: localContext] && rc;
|
||||
rc = [self _initFolderOfType: @"Contacts"
|
||||
withUserFolder: userFolder
|
||||
inContext: localContext] && rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) proceed
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
NSString *identifier;
|
||||
NSUInteger count, max;
|
||||
BOOL rc;
|
||||
|
||||
rc = YES;
|
||||
max = [usersToInit count];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
pool = [NSAutoreleasePool new];
|
||||
identifier = [usersToInit objectAtIndex: count];
|
||||
if ([self fetchUserID: identifier])
|
||||
{
|
||||
if (![self _initUser])
|
||||
rc = NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr, "Invalid user: %s\n", [identifier UTF8String]);
|
||||
rc = NO;
|
||||
}
|
||||
[pool release];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
- (BOOL) run
|
||||
{
|
||||
return ([self parseArguments] && [self proceed]);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -584,7 +584,6 @@
|
||||
[self _updateForeignSubscriptionsFromUser: oldUserID toUser: newUserID];
|
||||
[self _updateLocalACLsFromUser: oldUserID toUser: newUserID];
|
||||
[self _updateForeignACLsFromUser: oldUserID toUser: newUserID];
|
||||
[self _updateOldUserIDDefaultAndSettings: oldUserID toUser: newUserID];
|
||||
rc = YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"No resource" = "Nincs erőforrás";
|
||||
"Any Authenticated User" = "Bármely azonosított felhasználó";
|
||||
"Public Access" = "Nyilvános hozzáférés";
|
||||
"Save" = "Save";
|
||||
"Clear" = "Clear";
|
||||
"Message of the day" = "Message of the day";
|
||||
"Message of the day has been saved" = "Message of the day has been saved";
|
||||
"Save" = "Mentés";
|
||||
"Clear" = "Törlés";
|
||||
"Message of the day" = "A nap üzenete";
|
||||
"Message of the day has been saved" = "A nap üzenete mentésre került";
|
||||
@@ -176,13 +176,13 @@
|
||||
"Show or hide this help" = "Mutassa vagy elrejtse ezt a súgót";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "space";
|
||||
"key_space" = "szóköz";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "törlés";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "shift + space";
|
||||
"key_shift+space" = "shift + szóköz";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Másodlagos email cím";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Minimum of %{0} lowercase letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum of %{0} uppercase letter";
|
||||
"POLICY_MIN_DIGIT" = "Minimum of %{0} digit";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum of %{0} special symbols";
|
||||
"POLICY_MIN_LENGTH" = "Minimum length of %{0} characters";
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "Legalább %{0} kisbetű";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Legalább %{0} nagybetű";
|
||||
"POLICY_MIN_DIGIT" = "Legalább %{0} szám";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Legalább %{0} különleges karakter";
|
||||
"POLICY_MIN_LENGTH" = "Legalább %{0} karakter";
|
||||
@@ -488,6 +488,14 @@
|
||||
&& [user isSuperUser]);
|
||||
}
|
||||
|
||||
- (BOOL) usesCASAuthentication
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
return [[sd authenticationType] isEqualToString: @"cas"];
|
||||
}
|
||||
|
||||
- (BOOL) usesOpenIdAuthentication
|
||||
{
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
|
||||
name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
|
||||
name = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
nameInContainer = nil;
|
||||
|
||||
if ([name length] > 0)
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
"Common" = "Közös";
|
||||
"Contact editor" = "Kapcsolatszerkesztő";
|
||||
"Contact viewer" = "Kapcsolat betekintő";
|
||||
"Email" = "Email";
|
||||
"Email" = "Email cím";
|
||||
"Screen Name" = "Megjelenített név";
|
||||
"Extended" = "Kiterjesztett";
|
||||
"Fax" = "Fax";
|
||||
"Fax" = "Telefax";
|
||||
"Firstname" = "Keresztnév";
|
||||
"Home" = "Otthoni";
|
||||
"HomePhone" = "Otthoni telefon";
|
||||
@@ -61,10 +61,10 @@
|
||||
"nsaimid" = "Megjelenített név";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"mail" = "Mail";
|
||||
"mail" = "Üzenetek";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"c_mail" = "Mail";
|
||||
"c_mail" = "Üzenetek";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"telephonenumber" = "Telefon";
|
||||
@@ -76,7 +76,7 @@
|
||||
"mobile" = "Mobiltelefon";
|
||||
|
||||
/* Search scope: fax field */
|
||||
"facsimiletelephonenumber" = "Fax";
|
||||
"facsimiletelephonenumber" = "Telefax";
|
||||
|
||||
/* Search scope: pager field */
|
||||
"pager" = "Személyhívó";
|
||||
@@ -193,7 +193,7 @@
|
||||
"Work" = "Munkahely";
|
||||
"Mobile" = "Mobiltelefon";
|
||||
"Pager" = "Személyhívó";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
"Download iOS - MacOS configuration profile" = "iOS - MacOS konfigurációs profil letöltése";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "Munkatárs, Versenytárs, Felhasználó, Barát, Család, Üzleti partner, Szolgáltató, Sajtó, VIP";
|
||||
|
||||
@@ -485,7 +485,7 @@ static Class SOGoContactGCSEntryK = Nil;
|
||||
co = [self clientObject];
|
||||
card = [co vCard];
|
||||
request = [context request];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString];
|
||||
forceSave = [[params objectForKey: @"ignoreDuplicate"] boolValue];
|
||||
|
||||
[self setAttributes: params];
|
||||
|
||||
@@ -115,12 +115,18 @@
|
||||
{
|
||||
NSMutableDictionary *contactSettings;
|
||||
NSString *ascending, *sort;
|
||||
NSArray *sortValues;
|
||||
SOGoUserSettings *us;
|
||||
|
||||
sort = [[self requestData] objectForKey: @"sort"];
|
||||
ascending = [[self requestData] objectForKey: @"asc"];
|
||||
|
||||
if ([sort length])
|
||||
//Check value of sorting
|
||||
sortValues = [NSArray arrayWithObjects: @"c_cn", @"c_sn",
|
||||
@"c_givenname", @"c_mail", @"c_screenname", @"c_o", @"c_telephonenumber", nil];
|
||||
|
||||
|
||||
if ([sort length] && [sortValues containsObject:sort])
|
||||
{
|
||||
sort = [self sortKey];
|
||||
us = [[context activeUser] userSettings];
|
||||
|
||||
@@ -339,7 +339,7 @@
|
||||
[list retain];
|
||||
|
||||
request = [context request];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: YES stripAngular:NO] objectFromJSONString];
|
||||
|
||||
o = [params objectForKey: @"refs"];
|
||||
if (![o isKindOfClass: [NSArray class]])
|
||||
|
||||
@@ -44,7 +44,7 @@ reply_info = "Ez egy válasz az ön által kiküldött meghívásra.";
|
||||
"Save Attachment" = "Melléklet mentése";
|
||||
"CC" = "Másolat";
|
||||
"Cancel" = "Mégsem";
|
||||
"OK" = "OK";
|
||||
"OK" = "Rendben";
|
||||
"Comment" = "Megjegyzés:";
|
||||
"Description" = "Leírás";
|
||||
"Location" = "Location";
|
||||
"Location" = "Helyszín";
|
||||
@@ -130,6 +130,13 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
BOOL hasEmbeddedCSS;
|
||||
xmlCharEncoding contentEncoding;
|
||||
BOOL rawContent;
|
||||
// Wrap libxml2-orphaned <a> around the following block element
|
||||
// (HTML5 pattern <a><table>...</table></a> auto-closed by libxml2 HTML4 DTD).
|
||||
NSString *pendingAnchorTag;
|
||||
NSString *anchorWrapTag;
|
||||
NSUInteger anchorWrapDepth;
|
||||
NSString *lastAnchorOpenString;
|
||||
NSUInteger lastAnchorOpenEnd;
|
||||
}
|
||||
|
||||
- (NSString *) result;
|
||||
@@ -175,6 +182,9 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[result release];
|
||||
[css release];
|
||||
[ignoreTag release];
|
||||
[pendingAnchorTag release];
|
||||
[anchorWrapTag release];
|
||||
[lastAnchorOpenString release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@@ -228,6 +238,15 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
inCSSDeclaration = NO;
|
||||
hasEmbeddedCSS = NO;
|
||||
embeddedCSSLevel = 0;
|
||||
|
||||
[pendingAnchorTag release];
|
||||
[anchorWrapTag release];
|
||||
[lastAnchorOpenString release];
|
||||
pendingAnchorTag = nil;
|
||||
anchorWrapTag = nil;
|
||||
lastAnchorOpenString = nil;
|
||||
anchorWrapDepth = 0;
|
||||
lastAnchorOpenEnd = 0;
|
||||
}
|
||||
|
||||
- (void) endDocument
|
||||
@@ -494,6 +513,32 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
}
|
||||
else
|
||||
{
|
||||
// If a libxml2-orphaned <a> is waiting, re-open it around the next
|
||||
// block element (HTML5 pattern <a><table>...</table></a>).
|
||||
// Skip if the next element is itself <a> (avoids invalid nesting).
|
||||
if (pendingAnchorTag != nil)
|
||||
{
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[result appendString: pendingAnchorTag];
|
||||
[anchorWrapTag release];
|
||||
anchorWrapTag = [lowerName copy];
|
||||
anchorWrapDepth = 1;
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
}
|
||||
else if (anchorWrapTag != nil
|
||||
&& [lowerName isEqualToString: anchorWrapTag])
|
||||
{
|
||||
anchorWrapDepth++;
|
||||
}
|
||||
|
||||
resultPart = [NSMutableString string];
|
||||
[resultPart appendFormat: @"<%@", _rawName];
|
||||
|
||||
@@ -599,6 +644,13 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
[resultPart appendString: @"/"];
|
||||
[resultPart appendString: @">"];
|
||||
[result appendString: resultPart];
|
||||
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[lastAnchorOpenString release];
|
||||
lastAnchorOpenString = [resultPart copy];
|
||||
lastAnchorOpenEnd = [result length];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,8 +707,42 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Empty <a> auto-closed by libxml2 right after opening:
|
||||
// strip it from result and remember it to wrap the next block.
|
||||
if ([lowerName isEqualToString: @"a"]
|
||||
&& lastAnchorOpenString != nil
|
||||
&& [result length] == lastAnchorOpenEnd)
|
||||
{
|
||||
NSUInteger tagLen = [lastAnchorOpenString length];
|
||||
[result deleteCharactersInRange:
|
||||
NSMakeRange(lastAnchorOpenEnd - tagLen, tagLen)];
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = lastAnchorOpenString;
|
||||
lastAnchorOpenString = nil;
|
||||
lastAnchorOpenEnd = 0;
|
||||
return;
|
||||
}
|
||||
if ([lowerName isEqualToString: @"a"])
|
||||
{
|
||||
[lastAnchorOpenString release];
|
||||
lastAnchorOpenString = nil;
|
||||
lastAnchorOpenEnd = 0;
|
||||
}
|
||||
|
||||
//NSLog (@"%@", _localName);
|
||||
[result appendFormat: @"</%@>", _localName];
|
||||
|
||||
if (anchorWrapTag != nil
|
||||
&& [lowerName isEqualToString: anchorWrapTag])
|
||||
{
|
||||
anchorWrapDepth--;
|
||||
if (anchorWrapDepth == 0)
|
||||
{
|
||||
[result appendString: @"</a>"];
|
||||
[anchorWrapTag release];
|
||||
anchorWrapTag = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -673,9 +759,17 @@ static NSString *_sanitizeHtmlForDisplay(NSString *content)
|
||||
else if (inBody)
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
|
||||
s = [NSString stringWithCharacters: _chars length: _len];
|
||||
|
||||
if (pendingAnchorTag != nil
|
||||
&& [[s stringByTrimmingCharactersInSet:
|
||||
[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] > 0)
|
||||
{
|
||||
[pendingAnchorTag release];
|
||||
pendingAnchorTag = nil;
|
||||
}
|
||||
|
||||
// HACK: This is to avoid appending the useless junk in the <html> tag
|
||||
// that Outlook adds. It seems to confuse the XML parser for
|
||||
// forwarded messages as we get this in the _body_ of the email
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
- (BOOL) isEndDateOnSameDay;
|
||||
- (BOOL) hasLocation;
|
||||
- (NSString *)location;
|
||||
- (NSString *) organizerHref;
|
||||
- (NSString *) userComment;
|
||||
- (NSString *) eventDescription;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#import <NGExtensions/NSCalendarDate+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <NGImap4/NGImap4EnvelopeAddress.h>
|
||||
|
||||
@@ -374,6 +375,7 @@
|
||||
- (iCalEvent *) authorativeEvent
|
||||
{
|
||||
iCalEvent *authorativeEvent;
|
||||
NSString *comment, *cleanComment;
|
||||
|
||||
[self storedEvent];
|
||||
if (!storedEvent
|
||||
@@ -382,6 +384,14 @@
|
||||
else
|
||||
authorativeEvent = [self storedEvent];
|
||||
|
||||
//Clean authorative event
|
||||
if ((comment = [authorativeEvent comment])) {
|
||||
cleanComment = [comment stringWithoutHTMLInjection: NO stripAngular:YES];
|
||||
[authorativeEvent setComment: cleanComment];
|
||||
}
|
||||
|
||||
|
||||
|
||||
return authorativeEvent;
|
||||
}
|
||||
|
||||
@@ -408,6 +418,18 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *) organizerHref
|
||||
{
|
||||
NSString *address;
|
||||
|
||||
address = [[[self inEvent] organizer] rfc822Email];
|
||||
if (![address length])
|
||||
return nil;
|
||||
|
||||
return [[NSString stringWithFormat: @"mailto:%@", address]
|
||||
stringByEscapingHTMLAttributeValue];
|
||||
}
|
||||
|
||||
- (NSString *) organizerDisplayName
|
||||
{
|
||||
iCalPerson *organizer;
|
||||
@@ -587,7 +609,7 @@
|
||||
|
||||
//Sanitise the html content
|
||||
if([d objectForKey:@"content"]){
|
||||
[d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO] forKey: @"content"];
|
||||
[d setObject: [[d objectForKey:@"content"] stringWithoutHTMLInjection: NO stripAngular:NO] forKey: @"content"];
|
||||
}
|
||||
|
||||
return d;
|
||||
@@ -603,4 +625,14 @@
|
||||
return [[self inEvent] location];
|
||||
}
|
||||
|
||||
- (NSString *) userComment
|
||||
{
|
||||
return [[[self inEvent] userComment] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
- (NSString *) eventDescription
|
||||
{
|
||||
return [[[self authorativeEvent] comment] stringByEscapingHTMLString];
|
||||
}
|
||||
|
||||
@end /* UIxMailPartICalViewer */
|
||||
@@ -86,6 +86,7 @@
|
||||
- (NSString *)preferredPathExtension;
|
||||
- (NSString *)filename;
|
||||
- (NSString *)filenameForDisplay;
|
||||
- (NSString *)filenameForTitle;
|
||||
- (NSFormatter *)sizeFormatter;
|
||||
|
||||
/* caches */
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
|
||||
|
||||
content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO];
|
||||
content = [[[self generateResponse] contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO];
|
||||
if ([self respondsToSelector:@selector(getException)]) {
|
||||
e = [self getException];
|
||||
}
|
||||
@@ -327,10 +327,12 @@
|
||||
|
||||
- (NSString *) filenameForDisplay
|
||||
{
|
||||
NSString *s;
|
||||
NSString *s, *cleanFilename;
|
||||
|
||||
if ((s = [self filename]) != nil)
|
||||
return s;
|
||||
if ((s = [self filename]) != nil) {
|
||||
cleanFilename = [s stringWithoutHTMLInjection: NO stripAngular:YES];
|
||||
return cleanFilename;
|
||||
}
|
||||
|
||||
s = [partPath componentsJoinedByString:@"-"];
|
||||
return ([s length] > 0)
|
||||
@@ -338,6 +340,14 @@
|
||||
: (id)@"untitled";
|
||||
}
|
||||
|
||||
- (NSString *) filenameForTitle
|
||||
{
|
||||
/* the generic attribute writer escapes & but not the quote, so a quote in the
|
||||
filename would end the title attribute and start a new one */
|
||||
return [[self filenameForDisplay] stringByReplacingOccurrencesOfString: @"\""
|
||||
withString: @""];
|
||||
}
|
||||
|
||||
- (NSFormatter *) sizeFormatter
|
||||
{
|
||||
return [UIxMailSizeFormatter sharedMailSizeFormatter];
|
||||
|
||||
@@ -143,23 +143,23 @@
|
||||
"This mail is being sent from an unsecure network!" = "A levelet nem biztonságos hálózatból készül elküldeni!";
|
||||
"Address Book" = "Címjegyzék";
|
||||
"Search For" = "Keresés";
|
||||
"Contains" = "Contains";
|
||||
"Does not contains" = "Does not contains";
|
||||
"Advanced search" = "Advanced search";
|
||||
"Anytime" = "Anytime";
|
||||
"Last 7 days" = "Last 7 days";
|
||||
"Last 30 days" = "Last 30 days";
|
||||
"Last 6 month" = "Last 6 month";
|
||||
"Before" = "Before";
|
||||
"After" = "After";
|
||||
"Between" = "Between";
|
||||
"and" = "and";
|
||||
"With attachments" = "With attachments";
|
||||
"In favorites" = "In favorites";
|
||||
"Unseen only" = "Unseen only";
|
||||
"Show more" = "Show more";
|
||||
"Reset" = "Reset";
|
||||
"Message size" = "Message size";
|
||||
"Contains" = "Tartalmazza";
|
||||
"Does not contains" = "Nem tartalmazza";
|
||||
"Advanced search" = "Bővített keresés";
|
||||
"Anytime" = "Bármikor";
|
||||
"Last 7 days" = "Előző 7 nap";
|
||||
"Last 30 days" = "Előző 30 nap";
|
||||
"Last 6 month" = "Előző 6 hónap";
|
||||
"Before" = "Előtte";
|
||||
"After" = "Utána";
|
||||
"Between" = "Között";
|
||||
"and" = "és";
|
||||
"With attachments" = "Mellékletekkel";
|
||||
"In favorites" = "Kedvencek között";
|
||||
"Unseen only" = "Csak a még nem olvasott";
|
||||
"Show more" = "Továbbiak megjelenítése";
|
||||
"Reset" = "Alaphelyzet";
|
||||
"Message size" = "Üzenet mérete";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "összes";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Feladó";
|
||||
"Subject or Sender" = "Tárgy vagy feladó";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Tárgy vagy címzett";
|
||||
"To or Cc" = "Címzett vagy másolat";
|
||||
"Entire Message" = "A teljes üzenet";
|
||||
"Date" = "Dátum";
|
||||
@@ -257,7 +257,7 @@
|
||||
"Save As..." = "Mentés másként...";
|
||||
"Print Preview" = "Nyomtatási kép";
|
||||
"View Message Source" = "Üzenet forrása";
|
||||
"View raw message" = "View raw message";
|
||||
"View raw message" = "Nyers üzenet megtekintése";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "Eseménnyé alakít";
|
||||
@@ -434,7 +434,7 @@
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "Az üzenetet nem lehet aláírni, mivel a feladó címe nem található meg postafiókhoz hozzárendelt tanúsítványban.";
|
||||
|
||||
/* Contacts list in mail editor */
|
||||
"Email" = "Email";
|
||||
"Email" = "Email cím";
|
||||
"More mail options" = "További levelezési tulajdonságok";
|
||||
"Delegation" = "Jogok átadása";
|
||||
"Add User" = "Felhasználó hozzáadása";
|
||||
@@ -517,16 +517,16 @@
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "Clean folder";
|
||||
"Clean mailbox" = "Clean mailbox";
|
||||
"Delete permanently (do not use trash)" = "Delete permanently (do not use trash)";
|
||||
"Apply to subfolders" = "Apply to subfolders";
|
||||
"Delete e-mails older than" = "Delete e-mails older than";
|
||||
"3 months" = "3 months";
|
||||
"6 months" = "6 months";
|
||||
"9 months" = "9 months";
|
||||
"1 year" = "1 year";
|
||||
"Custom" = "Custom";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "You are about to permanently delete some messages. Are you sure you want to proceed with this action?";
|
||||
"Apply" = "Apply";
|
||||
"%{0} message(s) deleted" = "%{0} message(s) deleted";
|
||||
"Clean folder" = "Mappa ürítése";
|
||||
"Clean mailbox" = "Postafiók ürítése";
|
||||
"Delete permanently (do not use trash)" = "Végleges törlés (ne használjon lomtárat)";
|
||||
"Apply to subfolders" = "Alkalmazza az almappákra";
|
||||
"Delete e-mails older than" = "Emailek törlése amelyek régebbiek mint";
|
||||
"3 months" = "3 hónap";
|
||||
"6 months" = "6 hónap";
|
||||
"9 months" = "9 hónap";
|
||||
"1 year" = "1 év";
|
||||
"Custom" = "Egyéni";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Véglegesen törölni kíván néhány üzenetet. Biztosan végrehajtja a műveletet?";
|
||||
"Apply" = "Alkalmaz";
|
||||
"%{0} message(s) deleted" = "%{0} üzenet törölve";
|
||||
@@ -79,7 +79,7 @@
|
||||
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
folderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
|
||||
folderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
if ([folderName length] > 0)
|
||||
{
|
||||
encodedFolderName = [folderName stringByEncodingImap4FolderName];
|
||||
@@ -145,7 +145,7 @@
|
||||
// Retrieve new folder name from JSON payload
|
||||
request = [context request];
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
newFolderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES];
|
||||
newFolderName = [[params objectForKey: @"name"] stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
|
||||
if (!newFolderName || [newFolderName length] == 0)
|
||||
{
|
||||
|
||||
@@ -408,6 +408,7 @@
|
||||
NSString *sort, *module;
|
||||
NSMutableDictionary *moduleSettings;
|
||||
NSDictionary *urlParams, *sortingAttributes;
|
||||
NSArray *sortValues;
|
||||
SOGoUser *activeUser;
|
||||
SOGoUserSettings *us;
|
||||
BOOL asc, dry;
|
||||
@@ -424,20 +425,24 @@
|
||||
us = [activeUser userSettings];
|
||||
moduleSettings = [us objectForKey: module];
|
||||
|
||||
if ([sort length])
|
||||
{
|
||||
if ([sort isEqualToString: [self defaultSortKey]] && !asc)
|
||||
{
|
||||
if (moduleSettings && !dry)
|
||||
//Check sort value
|
||||
sortValues = [NSArray arrayWithObjects: @"SUBJECT", @"FROM",
|
||||
@"DATE", @"SIZE", @"ARRIVAL", nil];
|
||||
|
||||
if ([sort length] && [sortValues containsObject:sort])
|
||||
{
|
||||
if ([sort isEqualToString: [self defaultSortKey]] && !asc)
|
||||
{
|
||||
if (moduleSettings && !dry)
|
||||
{
|
||||
[moduleSettings removeObjectForKey: @"SortingState"];
|
||||
[us synchronize];
|
||||
}
|
||||
}
|
||||
else if (!dry)
|
||||
{
|
||||
// Save the sorting state in the user settings
|
||||
if (!moduleSettings)
|
||||
}
|
||||
else if (!dry)
|
||||
{
|
||||
// Save the sorting state in the user settings
|
||||
if (!moduleSettings)
|
||||
{
|
||||
moduleSettings = [NSMutableDictionary dictionary];
|
||||
[us setObject: moduleSettings forKey: module];
|
||||
@@ -445,17 +450,18 @@
|
||||
[moduleSettings setObject: [NSArray arrayWithObjects: [sort lowercaseString], [NSString stringWithFormat: @"%d", (asc ? 1 : 0)], nil]
|
||||
forKey: @"SortingState"];
|
||||
[us synchronize];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (moduleSettings)
|
||||
{
|
||||
NSArray *sortState = [moduleSettings objectForKey: @"SortingState"];
|
||||
if ([sortState count])
|
||||
{
|
||||
sort = [[sortState objectAtIndex: 0] uppercaseString];
|
||||
asc = [[sortState objectAtIndex: 1] boolValue];
|
||||
}
|
||||
}
|
||||
{
|
||||
NSArray *sortState = [moduleSettings objectForKey: @"SortingState"];
|
||||
if ([sortState count])
|
||||
{
|
||||
sort = [[sortState objectAtIndex: 0] uppercaseString];
|
||||
asc = [[sortState objectAtIndex: 1] boolValue];
|
||||
}
|
||||
}
|
||||
|
||||
if (![sort length])
|
||||
sort = [self defaultSortKey];
|
||||
|
||||
@@ -1178,7 +1184,7 @@
|
||||
[msg addObject: [NSNumber numberWithBool: [self isMessageFlagged]]];
|
||||
|
||||
// Subject
|
||||
[msg addObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO]];
|
||||
[msg addObject: [[[self messageSubject] stringWithoutHTMLInjection: YES stripAngular:NO] stringWithoutHTMLInjection: NO stripAngular:NO]];
|
||||
|
||||
// From
|
||||
from = [[message objectForKey: @"envelope"] from];
|
||||
|
||||
@@ -363,7 +363,7 @@ static NSString *mailETag = nil;
|
||||
if ([self formattedDate])
|
||||
[data setObject: [self formattedDate] forKey: @"date"];
|
||||
if ([self messageSubject])
|
||||
[data setObject: [[[self messageSubject] stringWithoutHTMLInjection: YES] stringWithoutHTMLInjection: NO] forKey: @"subject"];
|
||||
[data setObject: [[[self messageSubject] stringWithoutHTMLInjection: YES stripAngular:YES] stringWithoutHTMLInjection: NO stripAngular:YES] forKey: @"subject"];
|
||||
if ((addresses = [addressFormatter dictionariesForArray: [co fromEnvelopeAddresses]]))
|
||||
[data setObject: addresses forKey: @"from"];
|
||||
if ((addresses = [addressFormatter dictionariesForArray: [co toEnvelopeAddresses]]))
|
||||
|
||||
@@ -31,53 +31,53 @@
|
||||
"Download" = "Letöltés";
|
||||
"Language" = "Nyelv";
|
||||
"choose" = "Válasszon ...";
|
||||
"Arabic" = "العربية";
|
||||
"Basque" = "Euskara";
|
||||
"Bosnian" = "Bosanski";
|
||||
"Bulgarian" = "Български";
|
||||
"Catalan" = "Català";
|
||||
"ChineseChina" = "简体中文";
|
||||
"ChineseTaiwan" = "正體中文";
|
||||
"Croatian" = "Hrvatski";
|
||||
"Czech" = "Česky";
|
||||
"Danish" = "Dansk (Danmark)";
|
||||
"Dutch" = "Nederlands";
|
||||
"English" = "English";
|
||||
"Finnish" = "Suomi";
|
||||
"French" = "Français";
|
||||
"Galician" = "Galego";
|
||||
"German" = "Deutsch";
|
||||
"Greek" = "Ελληνικά";
|
||||
"Hebrew" = "עברית";
|
||||
"Arabic" = "Arab";
|
||||
"Basque" = "Baszk";
|
||||
"Bosnian" = "Bosnyák";
|
||||
"Bulgarian" = "Bolgár";
|
||||
"Catalan" = "Katalán";
|
||||
"ChineseChina" = "Kínai (egyszerűsített)";
|
||||
"ChineseTaiwan" = "Kínai (hagyományos)";
|
||||
"Croatian" = "Horvát";
|
||||
"Czech" = "Cseh";
|
||||
"Danish" = "Dán (Dánia)";
|
||||
"Dutch" = "Holland";
|
||||
"English" = "Angol";
|
||||
"Finnish" = "Finn";
|
||||
"French" = "Francia";
|
||||
"Galician" = "Galíciai";
|
||||
"German" = "Német";
|
||||
"Greek" = "Görög";
|
||||
"Hebrew" = "Héber";
|
||||
"Hungarian" = "Magyar";
|
||||
"Icelandic" = "Íslenska";
|
||||
"Indonesian" = "bahasa Indonesia";
|
||||
"Italian" = "Italiano";
|
||||
"Japanese" = "日本語";
|
||||
"Korean" = "한국어";
|
||||
"Kazakh" = "Қазақ";
|
||||
"Latvian" = "Latviešu";
|
||||
"Lithuanian" = "Lietuvių";
|
||||
"Macedonian" = "Македонски";
|
||||
"Montenegrin" = "Crnogorski";
|
||||
"NorwegianBokmal" = "Norsk bokmål";
|
||||
"NorwegianNynorsk" = "Norsk nynorsk";
|
||||
"Polish" = "Polski";
|
||||
"Portuguese" = "Português";
|
||||
"BrazilianPortuguese" = "Português brasileiro";
|
||||
"Romanian" = "Română";
|
||||
"Russian" = "Русский";
|
||||
"Serbian" = "Српски";
|
||||
"SerbianLatin" = "Srpski";
|
||||
"Slovak" = "Slovensky";
|
||||
"Slovenian" = "Slovenščina";
|
||||
"SpanishSpain" = "Español (España)";
|
||||
"SpanishArgentina" = "Español (Argentina)";
|
||||
"Swedish" = "Svenska";
|
||||
"Thai" = "ภาษา";
|
||||
"TurkishTurkey" = "Türkçe (Türkiye)";
|
||||
"Ukrainian" = "Українська";
|
||||
"Welsh" = "Cymraeg";
|
||||
"Icelandic" = "Izlandi";
|
||||
"Indonesian" = "Indonéz";
|
||||
"Italian" = "Olasz";
|
||||
"Japanese" = "Japán";
|
||||
"Korean" = "Koreai";
|
||||
"Kazakh" = "Kazah";
|
||||
"Latvian" = "Lett";
|
||||
"Lithuanian" = "Litván";
|
||||
"Macedonian" = "Macedón";
|
||||
"Montenegrin" = "Montenegrói";
|
||||
"NorwegianBokmal" = " Norvég bokmål";
|
||||
"NorwegianNynorsk" = "Norvég nynorsk";
|
||||
"Polish" = "Lengyel";
|
||||
"Portuguese" = "Portugál";
|
||||
"BrazilianPortuguese" = "Portugál (Brazília)";
|
||||
"Romanian" = "Román";
|
||||
"Russian" = "Orosz";
|
||||
"Serbian" = " Szerb (cirill írással)";
|
||||
"SerbianLatin" = "Szerb (latin írással)";
|
||||
"Slovak" = "Szlovák";
|
||||
"Slovenian" = "Szlovén";
|
||||
"SpanishSpain" = "Spanyol (Spanyolország)";
|
||||
"SpanishArgentina" = "Spanyol (Argentína)";
|
||||
"Swedish" = "Svéd";
|
||||
"Thai" = "Thai";
|
||||
"TurkishTurkey" = "Török (Törökország)";
|
||||
"Ukrainian" = "Ukrán";
|
||||
"Welsh" = "Walesi";
|
||||
|
||||
"About" = "Névjegy";
|
||||
"AboutBox" = "Az Inverse és az Alinto által fejlesztett SOGo egy teljes funkcionalitású csoportmunka kiszolgáló, melynek fő célkitűzései az egyszerűség és az igény szerinti növekedés (skálázhatóság).<br/><br/>\nA SOGo egy AJAX alapú modern webes felhasználói felületet biztosít, továbbá szabványos protokollok alkalmazásával, mint pl. CalDAV, CardDAV támogatja telepített alkalmazások használatát is. <br/><br/>\nA SOGo a <a href=\"http://gnu.org/licenses/gpl.html\">GNU GPL</a> 2. ill. magasabb verziói, továbbá egyes részei a GNU LGPL 2. verziója alatt kerül kiadásra. Ez egy ingyenes szoftver, a módosítása és újra kiadása megengedett.NINCS GARANCIA, a törvény által megengedett mértékben.<br/><br/>\nLátogassa meg <a href=\"http://www.sogo.nu/en/support/community.html\">ezt az oldalt</a> a különböző támogatási lehetőségek megismeréséhez. ";
|
||||
@@ -87,7 +87,7 @@
|
||||
"Change your Password" = "Változtassa meg jelszavát";
|
||||
"The password was changed successfully." = "A jelszó megváltoztatása sikeres.";
|
||||
"Your password has expired, please enter a new one below" = "A jelszava lejárt, kérem adjon meg egy újat";
|
||||
"Your password is too weak. Please choose a stronger password to enhance your security" = "Your password is too weak. Please choose a stronger password to enhance your security";
|
||||
"Your password is too weak. Please choose a stronger password to enhance your security" = "A megadott jelszó túl gyenge. Kérjük, válasszon erősebb jelszót a nagyobb biztonság érdekében";
|
||||
"Password must not be empty." = "A jelszó nem lehet üres.";
|
||||
"The passwords do not match. Please try again." = "Jelszavak nem egyeznek meg, kérem próbálja meg újra.";
|
||||
"Password Grace Period" = "Jelszóváltoztatás türelmi időszak";
|
||||
@@ -108,11 +108,11 @@
|
||||
"Unhandled error response" = "Nem kezelt hiba";
|
||||
"Password change is not supported." = "A jelszó megváltoztatása nem támogatott.";
|
||||
"Unhandled HTTP error code: %{0}" = "Nem kezelt HTTP hibakód: /{0}";
|
||||
"Current password" = "Current password";
|
||||
"Current password" = "Jelenlegi jelszó";
|
||||
"New password" = "Új jelszó";
|
||||
"Passwords don't match" = "Passwords don't match";
|
||||
"Passwords don't match" = "Jelszavak nem egyeznek meg";
|
||||
"Confirmation" = "Megerősítés";
|
||||
"Change" = "Change";
|
||||
"Change" = "Módosítás";
|
||||
"Cancel" = "Törlés";
|
||||
"Please wait..." = "Kérem várjon ...";
|
||||
"Close" = "Bezárás";
|
||||
|
||||
+38
-12
@@ -1091,7 +1091,7 @@ static const NSString *kJwtKey = @"jwt";
|
||||
}
|
||||
|
||||
//Check common injection
|
||||
loginClean = [login stringWithoutHTMLInjection: YES];
|
||||
loginClean = [login stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
if(![loginClean isEqualToString: login])
|
||||
{
|
||||
loginClean = @"";
|
||||
@@ -1316,7 +1316,8 @@ static const NSString *kJwtKey = @"jwt";
|
||||
*/
|
||||
- (WOResponse *) passwordRecoveryEmailAction
|
||||
{
|
||||
NSString *username, *domain, *mode, *uid, *mailDomain, *fromEmail, *toEmail, *jwtToken, *url, *mailContent;
|
||||
NSString *username, *domain, *mode, *uid, *mailDomain, *fromEmail, *toEmail, *jwtToken, *url, *mailContent, *email, *serverUrl;
|
||||
NSArray *baseUrls;
|
||||
NSDictionary *message, *info;
|
||||
WORequest *request;
|
||||
SOGoUserManager *um;
|
||||
@@ -1333,7 +1334,6 @@ static const NSString *kJwtKey = @"jwt";
|
||||
message = [[request contentAsString] objectFromJSONString];
|
||||
username = [message objectForKey: @"userName"];
|
||||
domain = [message objectForKey: @"domain"];
|
||||
mailDomain = [message objectForKey: @"mailDomain"];
|
||||
mode = [message objectForKey: @"mode"];
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
jwtToken = [request formValueForKey:@"token"];
|
||||
@@ -1345,14 +1345,6 @@ static const NSString *kJwtKey = @"jwt";
|
||||
ownerUser = [SOGoUser userWithLogin: username];
|
||||
dd = [ownerUser domainDefaults];
|
||||
|
||||
// Email recovery
|
||||
|
||||
// Create email from
|
||||
if (mailDomain) {
|
||||
fromEmail = [NSString stringWithFormat:@"noreply@%@", mailDomain];
|
||||
} else {
|
||||
fromEmail = [dd passwordRecoveryFrom];
|
||||
}
|
||||
|
||||
// Get password recovery email
|
||||
info = [um contactInfosForUserWithUIDorEmail: username];
|
||||
@@ -1361,14 +1353,48 @@ static const NSString *kJwtKey = @"jwt";
|
||||
inDomain: domain];
|
||||
toEmail = [userDefaults passwordRecoverySecondaryEmail];
|
||||
|
||||
//get fromEmail domain
|
||||
email = [info objectForKey: @"c_email"];
|
||||
// Create email from
|
||||
mailDomain = [email mailDomain];
|
||||
if (mailDomain) {
|
||||
fromEmail = [NSString stringWithFormat:@"noreply@%@", mailDomain];
|
||||
} else {
|
||||
fromEmail = [dd passwordRecoveryFrom];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (toEmail) {
|
||||
// Generate token
|
||||
jwtToken = [um generateAndSavePasswordRecoveryTokenWithUid: uid username: username domain: domain];
|
||||
|
||||
// Send mail
|
||||
mailer = [SOGoMailer mailerWithDomainDefaults: dd];
|
||||
|
||||
//Get Allowed server URL and check if it's OK
|
||||
baseUrls = [[SOGoSystemDefaults sharedSystemDefaults] passwordRecoveryBaseURLs];
|
||||
serverUrl = [[request headers] objectForKey:@"origin"];
|
||||
|
||||
if(!(baseUrls && [baseUrls count] > 0))
|
||||
{
|
||||
[self logWithFormat: @"Password recovery exception for user %@: empty or unset SOGoPasswordRecoveryBaseURLs", uid];
|
||||
response = [self responseWithStatus: 403
|
||||
andString: @"Password recovery email in error"];
|
||||
return response;
|
||||
}
|
||||
|
||||
if(![baseUrls containsObject:serverUrl])
|
||||
{
|
||||
[self logWithFormat: @"Password recovery exception for user %@: invalid request header", uid];
|
||||
response = [self responseWithStatus: 403
|
||||
andString: @"Password recovery email in error"];
|
||||
return response;
|
||||
}
|
||||
|
||||
url = [NSString stringWithFormat:@"%@%@?token=%@"
|
||||
, [[request headers] objectForKey:@"origin"]
|
||||
, serverUrl
|
||||
, [request uri]
|
||||
, jwtToken];
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
"Contacts Names" = "Nom dels Contactes";
|
||||
"Duplicate name" = "Nom duplicat";
|
||||
"Calendar categories must have unique names." = "Les categories de calendari han de tenir noms únics.";
|
||||
"Disable e-mail notifications on CalDAV" = "Disable e-mail notifications on CalDAV";
|
||||
"Disable e-mail notifications on CalDAV" = "Desactiva les notificacions per correu electrònic a CalDAV";
|
||||
|
||||
/* Default Calendar */
|
||||
"Default calendar" = "Calendari per defecte";
|
||||
@@ -207,7 +207,7 @@
|
||||
"Insert signature on forward" = "Insert signature on forward";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
"Show attachments above the message" = "Show attachments above the message";
|
||||
"Show attachments above the message" = "Mostra els adjunts a sobre del missatge";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Mida per defecte del tipus de lletra";
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
"Contacts Names" = "Kapcsolatok nevei";
|
||||
"Duplicate name" = "Név kettőzése";
|
||||
"Calendar categories must have unique names." = "Naptár kategóriáknak egyedi névvel kell rendelkezniük.";
|
||||
"Disable e-mail notifications on CalDAV" = "Disable e-mail notifications on CalDAV";
|
||||
"Disable e-mail notifications on CalDAV" = "E-mail értesítések kikapcsolása a CalDAV esetén";
|
||||
|
||||
/* Default Calendar */
|
||||
"Default calendar" = "Alapértelmezett naptár";
|
||||
@@ -205,9 +205,9 @@
|
||||
"Insert signature on new message" = "Aláírás beszúrása új levél esetén";
|
||||
"Insert signature on reply" = "Aláírás beszúrása válasz esetén";
|
||||
"Insert signature on forward" = "Aláírás beszúrása továbbítás esetén";
|
||||
"Show recipients or sender full email in mailboxes" = "Show recipients or sender full email in mailboxes";
|
||||
"Hide attachements for inline images" = "Hide attachments for inline images";
|
||||
"Show attachments above the message" = "Show attachments above the message";
|
||||
"Show recipients or sender full email in mailboxes" = "A címzettek vagy a feladó teljes e-mail-címének megjelenítése a postafiókokban";
|
||||
"Hide attachements for inline images" = "Beágyazott képek mellékleteinek elrejtése";
|
||||
"Show attachments above the message" = "Mellékletek megjelenítése az üzenet felett";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Alapértelmezett betűméret";
|
||||
@@ -233,11 +233,11 @@
|
||||
"Mail Account" = "Levelezési fiók";
|
||||
"New Mail Account" = "Új email fiók";
|
||||
"Server Name" = "Kiszolgáló neve";
|
||||
"Outgoing Server Name (SMTP)" = "Outgoing Server Name (SMTP)";
|
||||
"Smtp Auth" = "Smtp Auth";
|
||||
"Outgoing Server Name (SMTP)" = "Levéltovábbító kiszolgáló neve (SMTP)";
|
||||
"Smtp Auth" = "SMTP hitelesítés";
|
||||
"Port" = "Port";
|
||||
"Encryption" = "Titkosítás";
|
||||
"Outgoing Encryption" = "Outgoing Encryption";
|
||||
"Outgoing Encryption" = "Kimenő levél titkosítása";
|
||||
"None" = "Nincs";
|
||||
"User Name" = "Felhasználónév";
|
||||
"Full Name" = "Teljes név";
|
||||
@@ -315,45 +315,45 @@
|
||||
"Catalan" = "Català";
|
||||
"ChineseChina" = "简体中文";
|
||||
"ChineseTaiwan" = "正體中文";
|
||||
"Croatian" = "Hrvatski";
|
||||
"Croatian" = "Horvát";
|
||||
"Czech" = "Česky";
|
||||
"Danish" = "Dansk (Danmark)";
|
||||
"Dutch" = "Nederlands";
|
||||
"English" = "English";
|
||||
"Finnish" = "Suomi";
|
||||
"French" = "Français";
|
||||
"Galician" = "Galego";
|
||||
"German" = "Deutsch";
|
||||
"Hebrew" = "עברית";
|
||||
"Danish" = "Dán (Dánia)";
|
||||
"Dutch" = "Holland";
|
||||
"English" = "Angol";
|
||||
"Finnish" = "Finn";
|
||||
"French" = "Francia";
|
||||
"Galician" = "Galíciai";
|
||||
"German" = "Német";
|
||||
"Hebrew" = "Héber";
|
||||
"Hungarian" = "Magyar";
|
||||
"Icelandic" = "Íslenska";
|
||||
"Indonesian" = "bahasa Indonesia";
|
||||
"Italian" = "Italiano";
|
||||
"Japanese" = "日本語";
|
||||
"Kazakh" = "Қазақ";
|
||||
"Korean" = "한국어";
|
||||
"Latvian" = "Latviešu";
|
||||
"Lithuanian" = "Lietuvių";
|
||||
"Macedonian" = "Македонски";
|
||||
"Montenegrin" = "Crnogorski";
|
||||
"NorwegianBokmal" = "Norsk bokmål";
|
||||
"NorwegianNynorsk" = "Norsk nynorsk";
|
||||
"Polish" = "Polski";
|
||||
"Portuguese" = "Português";
|
||||
"BrazilianPortuguese" = "Português brasileiro";
|
||||
"Romanian" = "Română";
|
||||
"Russian" = "Русский";
|
||||
"Serbian" = "Српски";
|
||||
"SerbianLatin" = "Srpski";
|
||||
"Slovak" = "Slovensky";
|
||||
"Slovenian" = "Slovenščina";
|
||||
"SpanishSpain" = "Español (España)";
|
||||
"SpanishArgentina" = "Español (Argentina)";
|
||||
"Swedish" = "Svenska";
|
||||
"Thai" = "ภาษา";
|
||||
"TurkishTurkey" = "Türkçe (Türkiye)";
|
||||
"Ukrainian" = "Українська";
|
||||
"Welsh" = "Cymraeg";
|
||||
"Icelandic" = "Izlandi";
|
||||
"Indonesian" = "Indonéz";
|
||||
"Italian" = "Olasz";
|
||||
"Japanese" = "Japán";
|
||||
"Kazakh" = "Kazah";
|
||||
"Korean" = "Koreai";
|
||||
"Latvian" = "Lett";
|
||||
"Lithuanian" = "Litván";
|
||||
"Macedonian" = "Macedón";
|
||||
"Montenegrin" = "Montenegrói";
|
||||
"NorwegianBokmal" = " Norvég bokmål";
|
||||
"NorwegianNynorsk" = "Norvég nynorsk";
|
||||
"Polish" = "Lengyel";
|
||||
"Portuguese" = "Portugál";
|
||||
"BrazilianPortuguese" = "Portugál (Brazília)";
|
||||
"Romanian" = "Román";
|
||||
"Russian" = "Orosz";
|
||||
"Serbian" = " Szerb (cirill írással)";
|
||||
"SerbianLatin" = "Szerb (latin írással)";
|
||||
"Slovak" = "Szlovák";
|
||||
"Slovenian" = "Szlovén";
|
||||
"SpanishSpain" = "Spanyol (Spanyolország)";
|
||||
"SpanishArgentina" = "Spanyol (Argentína)";
|
||||
"Swedish" = "Svéd";
|
||||
"Thai" = "Thai";
|
||||
"TurkishTurkey" = "Török (Törökország)";
|
||||
"Ukrainian" = "Ukrán";
|
||||
"Welsh" = "Walesi";
|
||||
|
||||
"Refresh View" = "Nézet frissítése";
|
||||
"refreshview_manually" = "Kézi";
|
||||
@@ -435,7 +435,7 @@
|
||||
"Stop processing filter rules" = "Szűrő szabályok feldolgozásának befejezése";
|
||||
"is under" = "kisebb, mint";
|
||||
"is over" = "nagyobb, mint";
|
||||
"is" = "is";
|
||||
"is" = "-";
|
||||
"is not" = "nem";
|
||||
"contains" = "tartalmaz";
|
||||
"does not contain" = "nem tartalmaz";
|
||||
@@ -487,8 +487,8 @@
|
||||
"none" = "Nincs";
|
||||
"identicon" = "Azonosító ikon";
|
||||
"monsterid" = "Szörny";
|
||||
"wavatar" = "Wavatar";
|
||||
"retro" = "Retro";
|
||||
"wavatar" = "Wavatár";
|
||||
"retro" = "Retró";
|
||||
|
||||
/* Animation Level */
|
||||
"Animation Level" = "Animáció szintje";
|
||||
@@ -511,7 +511,7 @@
|
||||
"Let SOGo handle everything" = "A SOGo kezeljen mindent";
|
||||
|
||||
/* Password Recovery */
|
||||
"Password recovery mode" = "Password recovery mode";
|
||||
"Password recovery mode" = "Jelszó helyreállítás módszere";
|
||||
"Question" = "Kérdés";
|
||||
"Secondary e-mail" = "Másodlagos email cím";
|
||||
"Answer" = "Válasz";
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
"Contacts Names" = "Nombres de Contacto";
|
||||
"Duplicate name" = "Nombre duplicado";
|
||||
"Calendar categories must have unique names." = "Los nombres para las categorías de calendario deben ser únicos.";
|
||||
"Disable e-mail notifications on CalDAV" = "Disable e-mail notifications on CalDAV";
|
||||
"Disable e-mail notifications on CalDAV" = "Desactivar las notificaciones por correo electrónico en CalDAV";
|
||||
|
||||
/* Default Calendar */
|
||||
"Default calendar" = "Calendario por defecto";
|
||||
@@ -207,7 +207,7 @@
|
||||
"Insert signature on forward" = "Insertar firma en el mensaje reenviado";
|
||||
"Show recipients or sender full email in mailboxes" = "Mostrar los destinatarios o el remitente del correo electrónico completo en los buzones de correo";
|
||||
"Hide attachements for inline images" = "Ocultar los archivos adjuntos de las imágenes en línea";
|
||||
"Show attachments above the message" = "Show attachments above the message";
|
||||
"Show attachments above the message" = "Mostrar archivos adjuntos encima del mensaje";
|
||||
|
||||
/* Base font size for messages composed in HTML */
|
||||
"Default font size" = "Tamaño de fuente por defecto.";
|
||||
|
||||
@@ -344,6 +344,9 @@ static SoProduct *preferencesProduct = nil;
|
||||
[[defaults source] setObject: [domainDefaults calendarJitsiRoomPrefix] forKey: @"SOGoCalendarJitsiRoomPrefix"];
|
||||
}
|
||||
|
||||
//Add the Junk Icon pref
|
||||
[[defaults source] setObject: [domainDefaults mailJunkIcon] forKey: @"mailJunkIcon"];
|
||||
|
||||
//
|
||||
// Default Contacts preferences
|
||||
//
|
||||
|
||||
@@ -1750,7 +1750,7 @@ static NSArray *reminderValues = nil;
|
||||
id o, v;
|
||||
|
||||
requestStr = [[context request] contentAsString];
|
||||
requestStr = [requestStr stringWithoutHTMLInjection: NO];
|
||||
requestStr = [requestStr stringWithoutHTMLInjection: NO stripAngular:NO];
|
||||
o = [requestStr objectFromJSONString];
|
||||
results = nil;
|
||||
|
||||
|
||||
@@ -403,7 +403,7 @@ static SoProduct *commonProduct = nil;
|
||||
theme = [[context request] formValueForKey: @"theme"];
|
||||
if ([theme length])
|
||||
{
|
||||
safeTheme = [theme stringWithoutHTMLInjection: YES];
|
||||
safeTheme = [theme stringWithoutHTMLInjection: YES stripAngular:NO];
|
||||
if([safeTheme isEqualToString: theme])
|
||||
rel = [NSString stringWithFormat: @"%@?theme=%@", rel, theme];
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"A total of %{0} events were imported in the calendar." = "Összesen %{0} esemény lett importálva a naptárba.";
|
||||
"Compose E-Mail to All Attendees" = "Üzenet küldése az összes résztvevőnek";
|
||||
"Compose E-Mail to Undecided Attendees" = "Üzenet küldése az bizonytalan résztvevőnek";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
"Download iOS - MacOS configuration profile" = "iOS - MacOS konfigurációs profil letöltése";
|
||||
|
||||
/* Relative dates */
|
||||
"Yesterday" = "Tegnap";
|
||||
@@ -117,7 +117,7 @@
|
||||
"Save and Close" = "Mentés és bezárás";
|
||||
"Close" = "Bezárás";
|
||||
"Invite Attendees" = "Résztvevők meghívása";
|
||||
"Create Jitsi Meeting" = "Create Jitsi Meeting";
|
||||
"Create Jitsi Meeting" = "Jitsi megbeszélés létrehozása";
|
||||
"Attach" = "Csatolás";
|
||||
"Update" = "Mentés";
|
||||
"Cancel" = "Mégsem";
|
||||
@@ -163,7 +163,7 @@
|
||||
"End" = "Vége";
|
||||
"Due Date" = "Lejárat";
|
||||
"Name" = "Név";
|
||||
"Email" = "Email";
|
||||
"Email" = "Email cím";
|
||||
"Status" = "Állapot";
|
||||
"% complete" = "% kész";
|
||||
"Location" = "Hely";
|
||||
@@ -378,7 +378,7 @@
|
||||
"Show an Alert" = "Riasztás";
|
||||
"Send an E-mail" = "Email küldése";
|
||||
"Email Organizer" = "Email szervező";
|
||||
"Email Attendees (internal users)" = "Email Attendees (internal users)";
|
||||
"Email Attendees (internal users)" = "Email résztvevők (belső felhasználók)";
|
||||
"zoom_400" = "400%";
|
||||
"zoom_200" = "200%";
|
||||
"zoom_100" = "100%";
|
||||
@@ -509,7 +509,7 @@ validate_untilbeforeend = "Az ismétlődésnek az első előfordulás után k
|
||||
"Work days only" = "Csak munkanapok";
|
||||
"The whole day" = "Az egész nap";
|
||||
"Between" = "Között";
|
||||
"and" = "and";
|
||||
"and" = "és";
|
||||
"A time conflict exists with one or more attendees.\nWould you like to keep the current settings anyway?"
|
||||
= "Egy vagy több résztvevő között időütközés van.\nMegtartja ennek ellenére a beállításokat?";
|
||||
"Would you like to remove them and send the invitation to the remaining attendees?"
|
||||
@@ -611,7 +611,7 @@ vtodo_class2 = "(Bizalmas feladat)";
|
||||
"Select ending date" = "Válasszon befejezés dátumot";
|
||||
"Delegated to" = "Jogok átruházása az alábiaknak";
|
||||
"Keep sending me updates" = "Továbbiakban küldjön frissítéseket";
|
||||
"OK" = "OK";
|
||||
"OK" = "Rendben";
|
||||
"Confidential" = "Bizalmas";
|
||||
"Enable" = "Engedélyez";
|
||||
"Filter" = "Szűrő";
|
||||
|
||||
@@ -556,7 +556,7 @@
|
||||
|
||||
ex = nil;
|
||||
request = [context request];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO] objectFromJSONString];
|
||||
if (params == nil)
|
||||
{
|
||||
ex = [NSException exceptionWithName: @"JSONParsingException"
|
||||
|
||||
@@ -148,14 +148,26 @@
|
||||
*/
|
||||
- (WOResponse *) reloadAction
|
||||
{
|
||||
NSDictionary *results;
|
||||
NSMutableDictionary *results;
|
||||
NSString *error;
|
||||
unsigned int httpCode;
|
||||
|
||||
httpCode = 200;
|
||||
results = [[self clientObject] loadWebCalendar];
|
||||
|
||||
|
||||
if ([results objectForKey: @"status"])
|
||||
httpCode = [[results objectForKey: @"status"] intValue];
|
||||
{
|
||||
if ([results objectForKey: @"error"])
|
||||
{
|
||||
error = [results objectForKey: @"error"];
|
||||
if ([error isEqualToString: @"need-auth"])
|
||||
httpCode = 401;
|
||||
if ([error isEqualToString: @"invalid-calendar-content"] || [error isEqualToString: @"http-error"])
|
||||
httpCode = 500;
|
||||
}
|
||||
[results removeObjectForKey:@"status"];
|
||||
}
|
||||
|
||||
return [self responseWithStatus: httpCode andJSONRepresentation: results];
|
||||
}
|
||||
|
||||
@@ -786,12 +786,19 @@ static NSArray *tasksFields = nil;
|
||||
- (void) saveSortValue: (NSString *) submodule
|
||||
{
|
||||
NSString *sort, *ascending;
|
||||
NSArray *sortValues;
|
||||
SOGoUserSettings *us;
|
||||
NSMutableDictionary *calendarSettings;
|
||||
|
||||
sort = [[context request] formValueForKey: @"sort"];
|
||||
ascending = [[context request] formValueForKey: @"asc"];
|
||||
if ([sort length])
|
||||
|
||||
//Check value of sorting
|
||||
sortValues = [NSArray arrayWithObjects: @"title", @"location",
|
||||
@"calendarName", @"start", @"priority", @"category", @"status", @"end", nil];
|
||||
|
||||
|
||||
if ([sort length] && [sortValues containsObject:sort])
|
||||
{
|
||||
us = [[context activeUser] userSettings];
|
||||
calendarSettings = [us objectForKey: @"Calendar"];
|
||||
|
||||
@@ -254,6 +254,7 @@
|
||||
{
|
||||
WORequest *request;
|
||||
NSDictionary *params;
|
||||
NSArray *listValues;
|
||||
NSString *selectedList;
|
||||
|
||||
[self _setupContext];
|
||||
@@ -261,6 +262,14 @@
|
||||
params = [[request contentAsString] objectFromJSONString];
|
||||
|
||||
selectedList = [params objectForKey: @"list"];
|
||||
|
||||
//Check value
|
||||
listValues = [NSArray arrayWithObjects: @"eventsListView", @"tasksListView", nil];
|
||||
if([selectedList length] && ![listValues containsObject:selectedList])
|
||||
{
|
||||
selectedList = @"eventsListView";
|
||||
}
|
||||
|
||||
[moduleSettings setObject: selectedList
|
||||
forKey: @"SelectedList"];
|
||||
[us synchronize];
|
||||
|
||||
@@ -182,7 +182,7 @@ _intValueFromHex (NSString *hexString)
|
||||
fActiveTasks = [folder activeTasks];
|
||||
|
||||
[calendar setObject: folderName forKey: @"id"];
|
||||
[calendar setObject: [fDisplayName stringWithoutHTMLInjection: YES] forKey: @"name"];
|
||||
[calendar setObject: [fDisplayName stringWithoutHTMLInjection: YES stripAngular:NO] forKey: @"name"];
|
||||
[calendar setObject: [folder calendarColor] forKey: @"color"];
|
||||
isActive = [NSNumber numberWithBool: [folder isActive]];
|
||||
[calendar setObject: isActive forKey: @"active"];
|
||||
|
||||
@@ -335,7 +335,7 @@
|
||||
|
||||
ex = nil;
|
||||
request = [context request];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: NO] objectFromJSONString];
|
||||
params = [[[request contentAsString] stringWithoutHTMLInjection: NO stripAngular:NO] objectFromJSONString];
|
||||
if (params == nil)
|
||||
{
|
||||
ex = [NSException exceptionWithName: @"JSONParsingException"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</div>
|
||||
</md-toolbar>
|
||||
<md-whiteframe class="md-whiteframe-z1" layout="row" layout-align="space-between center">
|
||||
<pre><var:string value="flatContentAsString" /></pre>
|
||||
<pre ng-non-bindable=""><var:string value="flatContentAsString" /></pre>
|
||||
</md-whiteframe>
|
||||
</div>
|
||||
</var:if> <!-- if condition="couldParseCalendar" const:negate="1" -->
|
||||
@@ -137,7 +137,7 @@
|
||||
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email"
|
||||
<a ng-non-bindable="" var:href="organizerHref"
|
||||
><var:string value="organizerDisplayName" /></a>
|
||||
<var:string label:value="request_info" />
|
||||
</p>
|
||||
@@ -147,7 +147,7 @@
|
||||
<var:if condition="isLoggedInUserAnAttendee" const:negate="YES">
|
||||
<p>
|
||||
<var:string label:value="Organizer" />
|
||||
<a var:href="inEvent.organizer.email">
|
||||
<a ng-non-bindable="" var:href="organizerHref">
|
||||
<var:string value="organizerDisplayName" />
|
||||
</a>
|
||||
<var:string label:value="request_info_no_attendee" />
|
||||
@@ -233,14 +233,14 @@
|
||||
</var:if>
|
||||
|
||||
<!-- the user comment is used in replies -->
|
||||
<var:if condition="inEvent.userComment.isNotEmpty">
|
||||
<var:if condition="userComment.isNotEmpty">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label">
|
||||
<var:string label:value="Comment"/>
|
||||
</label>
|
||||
<div>
|
||||
<div ng-non-bindable="">
|
||||
<md-content>
|
||||
<var:string value="inEvent.userComment.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
||||
<var:string value="userComment.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,7 +251,7 @@
|
||||
<var:if condition="hasOrganizer" const:value="true">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="Organizer"/></label>
|
||||
<div>
|
||||
<div ng-non-bindable="">
|
||||
<var:string value="organizerDisplayName"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -268,7 +268,7 @@
|
||||
<var:if condition="hasLocation">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label"><var:string label:value="Location"/></label>
|
||||
<div>
|
||||
<div ng-non-bindable="">
|
||||
<var:string value="location"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -294,14 +294,14 @@
|
||||
</div>
|
||||
</md-list>
|
||||
|
||||
<var:if condition="authorativeEvent.comment.isNotEmpty">
|
||||
<var:if condition="eventDescription.isNotEmpty">
|
||||
<div class="pseudo-input-container">
|
||||
<label class="pseudo-input-label">
|
||||
<var:string label:value="Description"/>
|
||||
</label>
|
||||
<div>
|
||||
<div ng-non-bindable="">
|
||||
<md-content>
|
||||
<var:string value="authorativeEvent.comment.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
||||
<var:string value="eventDescription.stringByDetectingURLs" const:insertBR="1" const:escapeHTML="NO"/>
|
||||
</md-content>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<img var:src="pathToAttachment"
|
||||
var:title="filenameForDisplay"><!-- image --></img>
|
||||
<md-card-content>
|
||||
<p class="md-caption" var:title="filenameForDisplay">
|
||||
<p class="md-caption" var:title="filenameForTitle">
|
||||
<var:string value="filenameForDisplay" />
|
||||
</p>
|
||||
</md-card-content>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xmlns:label="OGo:label">
|
||||
<md-card>
|
||||
<md-card-content>
|
||||
<p class="md-caption sg-attachment-name" var:title="filenameForDisplay">
|
||||
<p class="md-caption sg-attachment-name" var:title="filenameForTitle">
|
||||
<var:if condition="preferredPathExtension.length"><span class="sg-label-outline"><var:string value="preferredPathExtension"/></span></var:if>
|
||||
<var:string value="filenameForDisplay"/>
|
||||
</p>
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
<md-icon>delete</md-icon>
|
||||
</md-button>
|
||||
<md-button class="sg-icon-button" ng-click="mailbox.markOrUnMarkMessagesAsJunk()">
|
||||
<md-icon ng-hide="::mailbox.service.selectedFolder.type == 'junk'">thumb_down</md-icon>
|
||||
<md-icon ng-hide="::mailbox.service.selectedFolder.type == 'junk'">{{ mailbox.junkIcon}}</md-icon>
|
||||
<md-tooltip ng-hide="::mailbox.service.selectedFolder.type == 'junk'" md-direction="bottom"><var:string label:value="Junk"/></md-tooltip>
|
||||
<md-icon ng-hide="::mailbox.service.selectedFolder.type != 'junk'">thumb_up</md-icon>
|
||||
<md-tooltip ng-hide="::mailbox.service.selectedFolder.type != 'junk'" md-direction="bottom"><var:string label:value="Not junk"/></md-tooltip>
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
<md-icon class="ng-animate-disabled" ng-switch-when="true" rsrc:md-svg-src="img/mark_email_unread.svg"><!-- mark as unread --></md-icon>
|
||||
<md-icon class="ng-animate-disabled" ng-switch-default="true" rsrc:md-svg-src="img/mark_email_read.svg"><!-- mark as read --></md-icon>
|
||||
</md-button>
|
||||
<md-button class="sg-icon-button" label:aria-label="Junk"
|
||||
ng-hide="::viewer.message.isDraft"
|
||||
ng-click="viewer.markOrUnMarkAsJunk()">
|
||||
<md-tooltip md-direction="bottom" ng-hide="::viewer.mailbox.type == 'junk'"><var:string label:value="Junk"/></md-tooltip>
|
||||
<md-tooltip md-direction="bottom" ng-show="::viewer.mailbox.type == 'junk'"><var:string label:value="Not junk"/></md-tooltip>
|
||||
<md-icon ng-hide="::viewer.mailbox.type == 'junk'">{{ viewer.junkIcon }}</md-icon>
|
||||
<md-icon ng-show="::viewer.mailbox.type == 'junk'">thumb_up</md-icon>
|
||||
</md-button>
|
||||
<md-button class="sg-icon-button"
|
||||
ng-hide="::viewer.message.isDraft"
|
||||
ng-click="viewer.reply($event)"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
@charset "UTF-8";.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.sg-hide{opacity:0}@-moz-document url-prefix(){[layout-fill]{margin:0;width:100%;min-height:100%;height:100%}}[flex-order]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="-20"]{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}[flex-order="-19"]{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}[flex-order="-18"]{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}[flex-order="-17"]{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}[flex-order="-16"]{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}[flex-order="-15"]{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}[flex-order="-14"]{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}[flex-order="-13"]{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}[flex-order="-12"]{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}[flex-order="-11"]{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}[flex-order="-10"]{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}[flex-order="-9"]{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}[flex-order="-8"]{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}[flex-order="-7"]{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}[flex-order="-6"]{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}[flex-order="-5"]{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}[flex-order="-4"]{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}[flex-order="-3"]{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}[flex-order="-2"]{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}[flex-order="-1"]{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}[flex-order="0"]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="1"]{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}[flex-order="2"]{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}[flex-order="3"]{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}[flex-order="4"]{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}[flex-order="5"]{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}[flex-order="6"]{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}[flex-order="7"]{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}[flex-order="8"]{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}[flex-order="9"]{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}[flex-order="10"]{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}[flex-order="11"]{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}[flex-order="12"]{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}[flex-order="13"]{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}[flex-order="14"]{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}[flex-order="15"]{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}[flex-order="16"]{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}[flex-order="17"]{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}[flex-order="18"]{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}[flex-order="19"]{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}[flex-order="20"]{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}[flex-offset="0"]{margin-left:0}[flex-offset="5"]{margin-left:5%}[flex-offset="10"]{margin-left:10%}[flex-offset="15"]{margin-left:15%}[flex-offset="20"]{margin-left:20%}[flex-offset="25"]{margin-left:25%}[flex-offset="30"]{margin-left:30%}[flex-offset="35"]{margin-left:35%}[flex-offset="40"]{margin-left:40%}[flex-offset="45"]{margin-left:45%}[flex-offset="50"]{margin-left:50%}[flex-offset="55"]{margin-left:55%}[flex-offset="60"]{margin-left:60%}[flex-offset="65"]{margin-left:65%}[flex-offset="70"]{margin-left:70%}[flex-offset="75"]{margin-left:75%}[flex-offset="80"]{margin-left:80%}[flex-offset="85"]{margin-left:85%}[flex-offset="90"]{margin-left:90%}[flex-offset="95"]{margin-left:95%}[flex-offset="33"]{margin-left:33.3333333333%}[flex-offset="66"]{margin-left:66.6666666667%}[layout-align="start stretch"],[layout-align]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}[layout-align="start center"],[layout-align="start end"],[layout-align="start start"],[layout-align="start stretch"],[layout-align=start]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}[layout-align="center center"],[layout-align="center end"],[layout-align="center start"],[layout-align="center stretch"],[layout-align=center]{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}[layout-align="end center"],[layout-align="end end"],[layout-align="end start"],[layout-align="end stretch"],[layout-align=end]{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}[layout-align="spacLine truncated
|
||||
@charset "UTF-8";.ng-cloak,.x-ng-cloak,[data-ng-cloak],[ng-cloak],[ng\:cloak],[x-ng-cloak]{display:none!important}.sg-hide{opacity:0}@-moz-document url-prefix(){[layout-fill]{margin:0;width:100%;min-height:100%;height:100%}}[flex-order]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="-20"]{-webkit-box-ordinal-group:-19;-webkit-order:-20;order:-20}[flex-order="-19"]{-webkit-box-ordinal-group:-18;-webkit-order:-19;order:-19}[flex-order="-18"]{-webkit-box-ordinal-group:-17;-webkit-order:-18;order:-18}[flex-order="-17"]{-webkit-box-ordinal-group:-16;-webkit-order:-17;order:-17}[flex-order="-16"]{-webkit-box-ordinal-group:-15;-webkit-order:-16;order:-16}[flex-order="-15"]{-webkit-box-ordinal-group:-14;-webkit-order:-15;order:-15}[flex-order="-14"]{-webkit-box-ordinal-group:-13;-webkit-order:-14;order:-14}[flex-order="-13"]{-webkit-box-ordinal-group:-12;-webkit-order:-13;order:-13}[flex-order="-12"]{-webkit-box-ordinal-group:-11;-webkit-order:-12;order:-12}[flex-order="-11"]{-webkit-box-ordinal-group:-10;-webkit-order:-11;order:-11}[flex-order="-10"]{-webkit-box-ordinal-group:-9;-webkit-order:-10;order:-10}[flex-order="-9"]{-webkit-box-ordinal-group:-8;-webkit-order:-9;order:-9}[flex-order="-8"]{-webkit-box-ordinal-group:-7;-webkit-order:-8;order:-8}[flex-order="-7"]{-webkit-box-ordinal-group:-6;-webkit-order:-7;order:-7}[flex-order="-6"]{-webkit-box-ordinal-group:-5;-webkit-order:-6;order:-6}[flex-order="-5"]{-webkit-box-ordinal-group:-4;-webkit-order:-5;order:-5}[flex-order="-4"]{-webkit-box-ordinal-group:-3;-webkit-order:-4;order:-4}[flex-order="-3"]{-webkit-box-ordinal-group:-2;-webkit-order:-3;order:-3}[flex-order="-2"]{-webkit-box-ordinal-group:-1;-webkit-order:-2;order:-2}[flex-order="-1"]{-webkit-box-ordinal-group:0;-webkit-order:-1;order:-1}[flex-order="0"]{-webkit-box-ordinal-group:1;-webkit-order:0;order:0}[flex-order="1"]{-webkit-box-ordinal-group:2;-webkit-order:1;order:1}[flex-order="2"]{-webkit-box-ordinal-group:3;-webkit-order:2;order:2}[flex-order="3"]{-webkit-box-ordinal-group:4;-webkit-order:3;order:3}[flex-order="4"]{-webkit-box-ordinal-group:5;-webkit-order:4;order:4}[flex-order="5"]{-webkit-box-ordinal-group:6;-webkit-order:5;order:5}[flex-order="6"]{-webkit-box-ordinal-group:7;-webkit-order:6;order:6}[flex-order="7"]{-webkit-box-ordinal-group:8;-webkit-order:7;order:7}[flex-order="8"]{-webkit-box-ordinal-group:9;-webkit-order:8;order:8}[flex-order="9"]{-webkit-box-ordinal-group:10;-webkit-order:9;order:9}[flex-order="10"]{-webkit-box-ordinal-group:11;-webkit-order:10;order:10}[flex-order="11"]{-webkit-box-ordinal-group:12;-webkit-order:11;order:11}[flex-order="12"]{-webkit-box-ordinal-group:13;-webkit-order:12;order:12}[flex-order="13"]{-webkit-box-ordinal-group:14;-webkit-order:13;order:13}[flex-order="14"]{-webkit-box-ordinal-group:15;-webkit-order:14;order:14}[flex-order="15"]{-webkit-box-ordinal-group:16;-webkit-order:15;order:15}[flex-order="16"]{-webkit-box-ordinal-group:17;-webkit-order:16;order:16}[flex-order="17"]{-webkit-box-ordinal-group:18;-webkit-order:17;order:17}[flex-order="18"]{-webkit-box-ordinal-group:19;-webkit-order:18;order:18}[flex-order="19"]{-webkit-box-ordinal-group:20;-webkit-order:19;order:19}[flex-order="20"]{-webkit-box-ordinal-group:21;-webkit-order:20;order:20}[flex-offset="0"]{margin-left:0}[flex-offset="5"]{margin-left:5%}[flex-offset="10"]{margin-left:10%}[flex-offset="15"]{margin-left:15%}[flex-offset="20"]{margin-left:20%}[flex-offset="25"]{margin-left:25%}[flex-offset="30"]{margin-left:30%}[flex-offset="35"]{margin-left:35%}[flex-offset="40"]{margin-left:40%}[flex-offset="45"]{margin-left:45%}[flex-offset="50"]{margin-left:50%}[flex-offset="55"]{margin-left:55%}[flex-offset="60"]{margin-left:60%}[flex-offset="65"]{margin-left:65%}[flex-offset="70"]{margin-left:70%}[flex-offset="75"]{margin-left:75%}[flex-offset="80"]{margin-left:80%}[flex-offset="85"]{margin-left:85%}[flex-offset="90"]{margin-left:90%}[flex-offset="95"]{margin-left:95%}[flex-offset="33"]{margin-left:33.3333333333%}[flex-offset="66"]{margin-left:66.6666666667%}[layout-align="start stretch"],[layout-align]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start;-webkit-align-content:stretch;align-content:stretch;-webkit-box-align:stretch;-webkit-align-items:stretch;align-items:stretch}[layout-align="start center"],[layout-align="start end"],[layout-align="start start"],[layout-align="start stretch"],[layout-align=start]{-webkit-box-pack:start;-webkit-justify-content:flex-start;justify-content:flex-start}[layout-align="center center"],[layout-align="center end"],[layout-align="center start"],[layout-align="center stretch"],[layout-align=center]{-webkit-box-pack:center;-webkit-justify-content:center;justify-content:center}[layout-align="end center"],[layout-align="end end"],[layout-align="end start"],[layout-align="end stretch"],[layout-align=end]{-webkit-box-pack:end;-webkit-justify-content:flex-end;justify-content:flex-end}[layout-align="spacLine truncated
|
||||
/*# sourceMappingURL=styles.css.map */
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"sources":["css/styles.css"],"names":[],"mappings":"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 truncated
|
||||
{"version":3,"sources":["css/styles.css"],"names":[],"mappings":"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 truncated
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -365,6 +365,7 @@
|
||||
|
||||
var refresh = function() {
|
||||
var html = vm.editor.getData();
|
||||
html = inlineImageDimensions(html);
|
||||
|
||||
var dom = document.createElement("DIV");
|
||||
dom.innerHTML = html;
|
||||
@@ -429,6 +430,29 @@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function inlineImageDimensions(html) {
|
||||
return html.replace(/<img\b[^>]*>/gi, function (tag) {
|
||||
var style = (tag.match(/style="([^"]*)"/i) || [])[1];
|
||||
if (!style) return tag;
|
||||
var r = style.match(/aspect-ratio\s*:\s*(\d+)\s*\/\s*(\d+)/i);
|
||||
if (!r) return tag;
|
||||
var w = (style.match(/(?:^|;)\s*width\s*:\s*(\d+)px/i) || [])[1]
|
||||
|| (tag.match(/\swidth="(\d+)"/i) || [])[1];
|
||||
if (!w) return tag;
|
||||
var h = Math.round(w * r[2] / r[1]);
|
||||
|
||||
var newStyle = style;
|
||||
if (!/(?:^|;)\s*width\s*:/i.test(newStyle)) newStyle = newStyle.replace(/;?\s*$/, '') + ';width:' + w + 'px';
|
||||
if (!/(?:^|;)\s*height\s*:/i.test(newStyle)) newStyle = newStyle.replace(/;?\s*$/, '') + ';height:' + h + 'px';
|
||||
|
||||
return tag
|
||||
.replace(/style="[^"]*"/i, 'style="' + newStyle + '"')
|
||||
.replace(/\swidth="[^"]*"/gi, '')
|
||||
.replace(/\sheight="[^"]*"/gi, '')
|
||||
.replace(/\s*\/?>$/, ' width="' + w + '" height="' + h + '">');
|
||||
});
|
||||
}
|
||||
|
||||
function cleanDirtyHTMLElements(html, threshold) {
|
||||
var regex = /(<[^>^/]+>( )*<\/[^>]+>)/gm;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
!function(){"use strict";function c(e){var t=this;"function"!=typeof e.then&&(angular.extend(this,e),_.forEach(this.identities,function(e){var t;e.fullName&&e.email?e.full=e.fullName+" <"+e.email+">":e.email?e.full="<"+e.email+">":e.full="",e.signature&&(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim())}),this.$mailboxes)&&c.$Mailbox.$unwrapCollection(this,c.$q.when({mailboxes:this.$mailboxes})).then(function(e){t.$mailboxes=e})}c.$factory=["$q","$timeout","$log","sgSettings","Resource","Preferences","Mailbox","Message",function(e,t,s,n,i,a,o,r){return angular.extend(c,{$q:e,$timeout:t,$log:s,$$resource:new i(n.activeUser("folderURL")+"Mail",n.activeUser()),$Preferences:a,$Mailbox:o,$Message:r}),c}];try{angular.module("SOGo.MailerUI")}catch(e){angular.module("SOGo.MailerUI",["SOGo.Common"])}angular.module("SOGo.MailerUI").factory("Account",c.$factory),c.$findAll=function(e){return e?c.$unwrapCollection(e):c.$accounts?c.$q.when(c.$accounts):c.$$resource.fetch("","mailAccounts").then(function(e){return c.$unwrapCollection(e)})},c.$unwrapCollection=function(e){var s=[];return angular.forEach(e,function(e,t){e.id=t,s[t]=new c(e)}),c.$accounts=s},c.refreshUnseenCount=function(e){var t,s=1===c.$Preferences.defaults.SOGoMailFetchAllUnseenCountFolders,n=c.$Preferences.defaults.SOGoRefreshViewCheck;if(s)t=[];else{if(!e)throw Error("SOGoMailFetchAllUnseenCountFolders is disabled and no folders list provided");t=e}_.forEach(c.$accounts,function(e){s?_.forEach(e.$$flattenMailboxes,function(e){t.push(e.id)}):(_.includes(t,e.id+"/folderINBOX")||t.push(e.id+"/folderINBOX"),_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(e.unseenCount)&&!_.includes(t,e.id)&&t.push(e.id)}))}),c.$$resource.post("","unseenCount",{mailboxes:t}).then(function(t){_.forEach(c.$accounts,function(e){_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(t[e.id])&&(e.unseenCount=t[e.id])})})}),n&&"manually"!=n&&(c.$refreshUnseenCount&&c.$timeout.cancel(c.$refreshUnseenCount),c.$refreshUnseenCount=c.$timeout(angular.bind(this,c.refreshUnseenCount,e),1e3*n.timeInterval()))},c.prototype.getLength=function(){return this.$expanded?this.$flattenMailboxes().length:0},c.prototype.getItemAtIndex=function(e){var t=this.$flattenMailboxes();return 0<=e&&e<t.length?t[e]:null},c.prototype.$getMailboxes=function(e){var a=this,t=e&&e.reload;return this.$mailboxes&&!t?c.$q.when(this.$mailboxes):(!t&&this.$futureMailboxesData||(this.$futureMailboxesData=c.$Mailbox.$find(this,e).then(function(e){function s(e){_.forEach(e,function(e){var t=_.find(n,["id",e.id]);t&&(e.unseenCount=t.unseenCount),e.children&&0<e.children.length&&s(e.children)})}var n=a.$flattenMailboxes({all:!0});a.$mailboxes=e,a.$expanded=!1;s(a.$mailboxes);function t(e){_.forEach(e,function(e){e.$expanded=0<=i.indexOf("/"+e.id),e.children&&0<e.children.length&&t(e.children)})}var i;if(c.$Preferences.settings.Mail.ExpandedFolders){if(angular.isString(c.$Preferences.settings.Mail.ExpandedFolders))try{i=angular.fromJson(c.$Preferences.settings.Mail.ExpandedFolders)}catch(e){c.$log.warn("Can't parse list of expanded folders. String was: "+c.$Preferences.settings.Mail.ExpandedFolders),i=[]}else i=c.$Preferences.settings.Mail.ExpandedFolders;a.$expanded=0<=i.indexOf("/"+a.id),0<i.length&&t(a.$mailboxes)}return c.$accounts&&(a.$expanded|=1==c.$accounts.length),a.$flattenMailboxes({reload:!0}),a.$mailboxes})),this.$futureMailboxesData)},c.prototype.$flattenMailboxes=function(t){function s(e){_.forEach(e,function(e){n.push(e),(t&&t.all||e.$expanded)&&e.children&&0<e.children.length&&s(e.children)})}var n=[],i=[];return!this.$$flattenMailboxes||t&&(t.reload||t.all)?(s(this.$mailboxes),t&&t.all||(this.$$flattenMailboxes=n,t&&t.saveState&&(_.forEach(c.$accounts,function(e){e.$expanded&&i.push("/"+e.id),_.reduce(e.$$flattenMailboxes,function(e,t){return t.$expanded&&e.push("/"+t.id),e},i)}),c.$$resource.post(null,"saveFoldersState",i)))):n=this.$$flattenMailboxes,n},c.prototype.$getMailboxByType=function(s){function n(e){var t=_.find(e,function(e){return e.type==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}return n(this.$mailboxes)},c.prototype.$getMailboxByPath=function(s){function n(e){var t=_.find(e,function(e){return e.path==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}var e;if(null==(e=n(this.$mailboxes)))throw Error("No mailbox found matching path "+s);return e},c.prototype.$newMailbox=function(e,t){var s=this;return c.$$resource.post(e.toString(),"createFolder",{name:t}).then(function(){s.$getMailboxes({reload:!0})})},c.prototype.getTextSignature=function(e){var t;return e.signature?(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim()):e.textSignature="",e.textSignature},c.prototype.$hasCertificate=function(){return this.security&&this.security.hasCLine truncated
|
||||
!function(){"use strict";function c(e){var t=this;"function"!=typeof e.then&&(angular.extend(this,e),_.forEach(this.identities,function(e){var t;e.fullName&&e.email?e.full=e.fullName+" <"+e.email+">":e.email?e.full="<"+e.email+">":e.full="",e.signature&&(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim())}),this.$mailboxes)&&c.$Mailbox.$unwrapCollection(this,c.$q.when({mailboxes:this.$mailboxes})).then(function(e){t.$mailboxes=e})}c.$factory=["$q","$timeout","$log","sgSettings","Resource","Preferences","Mailbox","Message",function(e,t,s,n,i,a,o,r){return angular.extend(c,{$q:e,$timeout:t,$log:s,$$resource:new i(n.activeUser("folderURL")+"Mail",n.activeUser()),$Preferences:a,$Mailbox:o,$Message:r}),c}];try{angular.module("SOGo.MailerUI")}catch(e){angular.module("SOGo.MailerUI",["SOGo.Common"])}angular.module("SOGo.MailerUI").factory("Account",c.$factory),c.$findAll=function(e){return e?c.$unwrapCollection(e):c.$accounts?c.$q.when(c.$accounts):c.$$resource.fetch("","mailAccounts").then(function(e){return c.$unwrapCollection(e)})},c.$unwrapCollection=function(e){var s=[];return angular.forEach(e,function(e,t){e.id=t,s[t]=new c(e)}),c.$accounts=s},c.refreshUnseenCount=function(e){var t,s=1===c.$Preferences.defaults.SOGoMailFetchAllUnseenCountFolders,n=c.$Preferences.defaults.SOGoRefreshViewCheck;if(s)t=[];else{if(!e)throw Error("SOGoMailFetchAllUnseenCountFolders is disabled and no folders list provided");t=e}_.forEach(c.$accounts,function(e){s?_.forEach(e.$$flattenMailboxes,function(e){t.push(e.id)}):(_.includes(t,e.id+"/folderINBOX")||t.push(e.id+"/folderINBOX"),_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(e.unseenCount)&&!_.includes(t,e.id)&&t.push(e.id)}))}),c.$$resource.post("","unseenCount",{mailboxes:t}).then(function(t){_.forEach(c.$accounts,function(e){_.forEach(e.$$flattenMailboxes,function(e){angular.isDefined(t[e.id])&&(e.unseenCount=t[e.id])})})}),n&&"manually"!=n&&(c.$refreshUnseenCount&&c.$timeout.cancel(c.$refreshUnseenCount),c.$refreshUnseenCount=c.$timeout(angular.bind(this,c.refreshUnseenCount,e),1e3*n.timeInterval()))},c.prototype.getLength=function(){return this.$expanded?this.$flattenMailboxes().length:0},c.prototype.getItemAtIndex=function(e){var t=this.$flattenMailboxes();return 0<=e&&e<t.length?t[e]:null},c.prototype.$getMailboxes=function(e){var a=this,t=e&&e.reload;return this.$mailboxes&&!t?c.$q.when(this.$mailboxes):(!t&&this.$futureMailboxesData||(this.$futureMailboxesData=c.$Mailbox.$find(this,e).then(function(e){function s(e){_.forEach(e,function(e){var t=_.find(n,["id",e.id]);t&&(e.unseenCount=t.unseenCount),e.children&&0<e.children.length&&s(e.children)})}var n=a.$flattenMailboxes({all:!0});a.$mailboxes=e,a.$expanded=!1;s(a.$mailboxes);function t(e){_.forEach(e,function(e){e.$expanded=0<=i.indexOf("/"+e.id),e.children&&0<e.children.length&&t(e.children)})}var i;if(c.$Preferences.settings.Mail.ExpandedFolders){if(angular.isString(c.$Preferences.settings.Mail.ExpandedFolders))try{i=angular.fromJson(c.$Preferences.settings.Mail.ExpandedFolders)}catch(e){c.$log.warn("Can't parse list of expanded folders. String was: "+c.$Preferences.settings.Mail.ExpandedFolders),i=[]}else i=c.$Preferences.settings.Mail.ExpandedFolders;a.$expanded=0<=i.indexOf("/"+a.id),0<i.length&&t(a.$mailboxes)}return c.$accounts&&(a.$expanded|=1==c.$accounts.length),a.$flattenMailboxes({reload:!0}),a.$mailboxes})),this.$futureMailboxesData)},c.prototype.$flattenMailboxes=function(t){function s(e){_.forEach(e,function(e){n.push(e),(t&&t.all||e.$expanded)&&e.children&&0<e.children.length&&s(e.children)})}var n=[],i=[];return!this.$$flattenMailboxes||t&&(t.reload||t.all)?(s(this.$mailboxes),t&&t.all||(this.$$flattenMailboxes=n,t&&t.saveState&&(_.forEach(c.$accounts,function(e){e.$expanded&&i.push("/"+e.id),_.reduce(e.$$flattenMailboxes,function(e,t){return t.$expanded&&e.push("/"+t.id),e},i)}),c.$$resource.post(null,"saveFoldersState",i)))):n=this.$$flattenMailboxes,n},c.prototype.$getMailboxByType=function(s){function n(e){var t=_.find(e,function(e){return e.type==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}return n(this.$mailboxes)},c.prototype.$getMailboxByPath=function(s){function n(e){var t=_.find(e,function(e){return e.path==s});return t||angular.forEach(e,function(e){!t&&e.children&&0<e.children.length&&(t=n(e.children))}),t}var e;if(null==(e=n(this.$mailboxes)))throw Error("No mailbox found matching path "+s);return e},c.prototype.$newMailbox=function(e,t){var s=this;return c.$$resource.post(e.toString(),"createFolder",{name:t}).then(function(){s.$getMailboxes({reload:!0})})},c.prototype.getTextSignature=function(e){var t;return e.signature?(t=angular.element("<div>"+e.signature+"</div>"),e.textSignature=_.map(t.contents(),"textContent").join(" ").trim()):e.textSignature="",e.textSignature},c.prototype.$hasCertificate=function(){return this.security&&this.security.hasCLine truncated
|
||||
//# sourceMappingURL=Mailer.services.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"Mailer.services.js","sources":["Mailer/Account.service.js","Mailer/Mailbox.service.js","Mailer/Message.service.js","Mailer/sgImageGallery.service.js","Mailer/VirtualMailbox.service.js","Mailer/MailboxController.js","Mailer/MailboxesController.js","Mailer/MessageController.js","Mailer/MessageEditorController.js","Mailer/sgAccountSection.directive.js","Mailer/sgIMIP.directive.js","Mailer/sgMailboxListItem.directive.js","Mailer/sgMessageListItem.directive.js","Mailer/sgMessageListItemMain.directive.js","Mailer/sgZoomableImage.directive.js"],"names":["Account","futureAccountData","_this","this","then","angular","extend","_","forEach","identities","identity","element","fullName","email","full","signature","textSignature","map","contents","join","trim","$mailboxes","$Mailbox","$unwrapCollection","$q","when","mailboxes","collection","$factory","$timeout","$log","Settings","Resource","Preferences","Mailbox","Message","$$resource","activeUser","$Preferences","$Message","module","e","factory","$findAll","data","$accounts","fetch","o","i","id","refreshUnseenCount","folders","unseenCountFolders","fetchAllUnseenCountFolders","defaults","SOGoMailFetchAllUnseenCountFolders","refreshViewCheck","SOGoRefreshViewCheck","Error","account","$$flattenMailboxes","mailbox","push","includes","isDefined","unseenCount","post","$refreshUnseenCount","cancel","bind","timeInterval","prototype","getLength","$expanded","$flattenMailboxes","length","getItemAtIndex","index","expandedMailboxes","$getMailboxes","options","reload","$futureMailboxesData","$find","_visitForUnseencount","previousMailbox","find","previousMailboxes","children","all","_visitForExpanded","expandedFolders","indexOf","settings","Mail","ExpandedFolders","isString","fromJson","warn","_visit","allMailboxes","saveState","reduce","$getMailboxByType","type","_find","$getMailboxByPath","path","$newMailbox","name","toString","getTextSignature","$hasCertificate","security","hasCertificate","$certificate","$$certificate","reject","$removeCertificate","updateQuota","percent","description","maxQuota","Math","round","usedSpace","l","formatted","maxMessages","messagesCount","$quota","$newMessage","debug","JSON","stringify","undefined","accountId","mailboxPath","message","$absolutePath","asDraft","accountDefaults","AuxiliaryMailAccounts","alwaysSign","sign","alwaysEncrypt","encrypt","editable","isNew","mailto","isObject","$parseMailto","$addDelegate","user","deferred","defer","param","uid","delegates","resolve","users","status","promise","$removeDelegate","splice","$omit","deep","defaultIdentity","value","key","copy","isReadOnly","pick","isDefault","forceDefaultIdentity","futureMailboxData","$account","init","newMailboxData","create","$unwrap","$rootScope","Acl","PRELOAD","BATCH_DELETE_LIMIT","$$Acl","$query","sort","asc","selectedFolder","$refreshTimeout","$virtualMode","$virtualPath","$searchMode","SortingState","parseInt","constant","LOOKAHEAD","SIZE","createMailboxes","level","isSentFolder","isDraftsFolder","quotas","split","component","asCSSIdentifier","isUndefined","uidsMap","headers","$isLoading","$messages","$visibleMessages","$selectedMessages","$highlightWords","$id","$acl","threaded","$collapsedThreads","threadsCollapsed","$displayName","$isEditable","isEditable","$isSpecial","$icon","$isNoInferiors","isNoInferiors","$shadowData","selectFolder","setSearchMode","searchMode","$lastVisibleIndex","max","$loadMessage","selectedMessages","updateCache","filter","selected","selectedCount","$unselectMessages","isSelectedMessage","messageId","$selectedMessage","selectedMessage","$selectedMessageIndex","hasSelectedMessage","$filter","sortingAttributes","filters","action","labels","searchBy","searchInput","word","cleanedWord","toLowerCase","match","secondFilter","$flaggedOnly","$unseenOnly","$syncToken","syncToken","unseenOnly","flaggedOnly","keys","$filteredLabels","k","f","endIndex","uids","startIndex","loaded","subject","min","loading","futureHeadersData","$unwrapHeaders","flags","isNoSelect","isWritable","getClassName","base","$rename","findParent","parent","parentMailbox","$save","_updateChildren","child","replace","pathRE","oldPath","sibling","localeCompare","RegExp","$compact","$canFolderAs","$setFolderAs","$empty","capitalize","substring","$markAsRead","isread","getLabels","$labels","filteredByLabel","$flagMessages","messages","operation","msgUIDs","forwardMessages","saveSelectedMessages","selectedUIDs","download","exportFolder","filename","open","$delete","$_deleteMessages","firstIndex","forEachRight","selectedIndex","findIndex","updateVisibleMessages","$deleteMessages","batchSize","_deleteMessages","start","end","currentUids","slice","$markOrUnMarkMessagesAsJunk","method","$copyMessages","folder","$moveMessages","$move","parentPath","finally","save","response","error","$reset","Object","assign","childrenArray","collapsedThread","msg","first","collapsed","$broadcast","$futureMailboxData","headersFields","msgObject","hasNewMessages","$topIndex","deleted","jLine truncated
|
||||
{"version":3,"file":"Mailer.services.js","sources":["Mailer/Account.service.js","Mailer/Mailbox.service.js","Mailer/Message.service.js","Mailer/sgImageGallery.service.js","Mailer/VirtualMailbox.service.js","Mailer/MailboxController.js","Mailer/MailboxesController.js","Mailer/MessageController.js","Mailer/MessageEditorController.js","Mailer/sgAccountSection.directive.js","Mailer/sgIMIP.directive.js","Mailer/sgMailboxListItem.directive.js","Mailer/sgMessageListItem.directive.js","Mailer/sgMessageListItemMain.directive.js","Mailer/sgZoomableImage.directive.js"],"names":["Account","futureAccountData","_this","this","then","angular","extend","_","forEach","identities","identity","element","fullName","email","full","signature","textSignature","map","contents","join","trim","$mailboxes","$Mailbox","$unwrapCollection","$q","when","mailboxes","collection","$factory","$timeout","$log","Settings","Resource","Preferences","Mailbox","Message","$$resource","activeUser","$Preferences","$Message","module","e","factory","$findAll","data","$accounts","fetch","o","i","id","refreshUnseenCount","folders","unseenCountFolders","fetchAllUnseenCountFolders","defaults","SOGoMailFetchAllUnseenCountFolders","refreshViewCheck","SOGoRefreshViewCheck","Error","account","$$flattenMailboxes","mailbox","push","includes","isDefined","unseenCount","post","$refreshUnseenCount","cancel","bind","timeInterval","prototype","getLength","$expanded","$flattenMailboxes","length","getItemAtIndex","index","expandedMailboxes","$getMailboxes","options","reload","$futureMailboxesData","$find","_visitForUnseencount","previousMailbox","find","previousMailboxes","children","all","_visitForExpanded","expandedFolders","indexOf","settings","Mail","ExpandedFolders","isString","fromJson","warn","_visit","allMailboxes","saveState","reduce","$getMailboxByType","type","_find","$getMailboxByPath","path","$newMailbox","name","toString","getTextSignature","$hasCertificate","security","hasCertificate","$certificate","$$certificate","reject","$removeCertificate","updateQuota","percent","description","maxQuota","Math","round","usedSpace","l","formatted","maxMessages","messagesCount","$quota","$newMessage","debug","JSON","stringify","undefined","accountId","mailboxPath","message","$absolutePath","asDraft","accountDefaults","AuxiliaryMailAccounts","alwaysSign","sign","alwaysEncrypt","encrypt","editable","isNew","mailto","isObject","$parseMailto","$addDelegate","user","deferred","defer","param","uid","delegates","resolve","users","status","promise","$removeDelegate","splice","$omit","deep","defaultIdentity","value","key","copy","isReadOnly","pick","isDefault","forceDefaultIdentity","futureMailboxData","$account","init","newMailboxData","create","$unwrap","$rootScope","Acl","PRELOAD","BATCH_DELETE_LIMIT","$$Acl","$query","sort","asc","selectedFolder","$refreshTimeout","$virtualMode","$virtualPath","$searchMode","SortingState","parseInt","constant","LOOKAHEAD","SIZE","createMailboxes","level","isSentFolder","isDraftsFolder","quotas","split","component","asCSSIdentifier","isUndefined","uidsMap","headers","$isLoading","$messages","$visibleMessages","$selectedMessages","$highlightWords","$id","$acl","threaded","$collapsedThreads","threadsCollapsed","$displayName","$isEditable","isEditable","$isSpecial","$icon","mailJunkIcon","$isNoInferiors","isNoInferiors","$shadowData","selectFolder","setSearchMode","searchMode","$lastVisibleIndex","max","$loadMessage","selectedMessages","updateCache","filter","selected","selectedCount","$unselectMessages","isSelectedMessage","messageId","$selectedMessage","selectedMessage","$selectedMessageIndex","hasSelectedMessage","$filter","sortingAttributes","filters","action","labels","searchBy","searchInput","word","cleanedWord","toLowerCase","match","secondFilter","$flaggedOnly","$unseenOnly","$syncToken","syncToken","unseenOnly","flaggedOnly","keys","$filteredLabels","k","f","endIndex","uids","startIndex","loaded","subject","min","loading","futureHeadersData","$unwrapHeaders","flags","isNoSelect","isWritable","getClassName","base","$rename","findParent","parent","parentMailbox","$save","_updateChildren","child","replace","pathRE","oldPath","sibling","localeCompare","RegExp","$compact","$canFolderAs","$setFolderAs","$empty","capitalize","substring","$markAsRead","isread","getLabels","$labels","filteredByLabel","$flagMessages","messages","operation","msgUIDs","forwardMessages","saveSelectedMessages","selectedUIDs","download","exportFolder","filename","open","$delete","$_deleteMessages","firstIndex","forEachRight","selectedIndex","findIndex","updateVisibleMessages","$deleteMessages","batchSize","_deleteMessages","start","end","currentUids","slice","$markOrUnMarkMessagesAsJunk","method","$copyMessages","folder","$moveMessages","$move","parentPath","finally","save","response","error","$reset","Object","assign","childrenArray","collapsedThread","msg","first","collapsed","$broadcast","$futureMailboxData","headersFields","msgObject","hasNewMessages","$topIndeLine truncated
|
||||
@@ -207,7 +207,7 @@
|
||||
}
|
||||
else if (this.type == 'junk') {
|
||||
this.$displayName = l('JunkFolderName');
|
||||
this.$icon = 'thumb_down';
|
||||
this.$icon = Mailbox.$Preferences.defaults.mailJunkIcon;
|
||||
}
|
||||
else if (this.type == 'templates') {
|
||||
this.$displayName = l('TemplatesFolderName');
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
this.allSelected = false;
|
||||
this.isLoadingMessage = false;
|
||||
this.nextAction = null;
|
||||
this.junkIcon = Preferences.defaults.mailJunkIcon;
|
||||
|
||||
if (!Mailbox.$virtualMode)
|
||||
this.selectedFolder.getLabels(); // fetch labels from server
|
||||
|
||||
@@ -527,13 +527,12 @@
|
||||
var dom = document.createElement("DIV");
|
||||
if(isHtml){
|
||||
dom.innerHTML = encodeEntities ? data.encodeEntities() : data;
|
||||
var markInstance = new Mark(dom);
|
||||
markInstance.mark(this.$mailbox.getHighlightWords());
|
||||
}
|
||||
else{
|
||||
dom.textContent = encodeEntities ? data.encodeEntities() : data;
|
||||
dom.textContent = data;
|
||||
}
|
||||
|
||||
var markInstance = new Mark(dom);
|
||||
markInstance.mark(this.$mailbox.getHighlightWords());
|
||||
data = dom.innerHTML;
|
||||
dom.remove();
|
||||
} else if (encodeEntities) {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
this.$showDetailedRecipients = this.$alwaysShowDetailedRecipients;
|
||||
this.showRawSource = false;
|
||||
this.mailInDeletion = -1;
|
||||
this.junkIcon = Preferences.defaults.mailJunkIcon;
|
||||
|
||||
_registerHotkeys(hotkeys);
|
||||
|
||||
@@ -319,10 +320,60 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Select either the next or previous message once the current message
|
||||
// has been removed from the mailbox (deleted or moved), then close the
|
||||
// popup if any.
|
||||
function _selectNextMessage(mailbox, state, index) {
|
||||
var nextMessage, previousMessage,
|
||||
nextIndex = index,
|
||||
$timeout = vm.service.$timeout;
|
||||
|
||||
if (angular.isDefined(state)) {
|
||||
if (index > 0) {
|
||||
nextIndex -= 1;
|
||||
nextMessage = mailbox.getItemAtIndex(nextIndex);
|
||||
}
|
||||
if (index < mailbox.getLength())
|
||||
previousMessage = mailbox.getItemAtIndex(index);
|
||||
|
||||
if (nextMessage) {
|
||||
if (nextMessage.isread && previousMessage && !previousMessage.isread) {
|
||||
nextIndex = index;
|
||||
nextMessage = previousMessage;
|
||||
}
|
||||
}
|
||||
else if (previousMessage) {
|
||||
nextIndex = index;
|
||||
nextMessage = previousMessage;
|
||||
}
|
||||
|
||||
try {
|
||||
if (nextMessage && $mdMedia(sgConstant['gt-md'])) {
|
||||
if (Mailbox.$virtualMode)
|
||||
state.go('mail.account.virtualMailbox.message', {mailboxId: encodeUriFilter(nextMessage.$mailbox.path), messageId: nextMessage.uid});
|
||||
else
|
||||
state.go('mail.account.mailbox.message', {messageId: nextMessage.uid});
|
||||
$timeout(function() {
|
||||
if (nextIndex < mailbox.$topIndex)
|
||||
mailbox.$topIndex = nextIndex;
|
||||
else if (nextIndex > mailbox.$lastVisibleIndex)
|
||||
mailbox.$topIndex = nextIndex - (mailbox.$lastVisibleIndex - mailbox.$topIndex);
|
||||
});
|
||||
}
|
||||
else {
|
||||
state.go('mail.account.mailbox').then(function() {
|
||||
delete mailbox.$selectedMessage;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error) {}
|
||||
}
|
||||
vm.closePopup();
|
||||
}
|
||||
|
||||
this.deleteMessage = function() {
|
||||
var mailbox, message, state, nextMessage, previousMessage,
|
||||
parentCtrls = $parentControllers(),
|
||||
$timeout = this.service.$timeout;
|
||||
var mailbox, message, state,
|
||||
parentCtrls = $parentControllers();
|
||||
|
||||
if (parentCtrls.messageCtrl) {
|
||||
mailbox = parentCtrls.mailboxCtrl.selectedFolder;
|
||||
@@ -340,52 +391,9 @@
|
||||
vm.mailInDeletion = message.uid;
|
||||
|
||||
function _success(index) {
|
||||
var nextIndex = index;
|
||||
// Remove message object from scope
|
||||
message = null;
|
||||
if (angular.isDefined(state)) {
|
||||
// Select either the next or previous message
|
||||
if (index > 0) {
|
||||
nextIndex -= 1;
|
||||
nextMessage = mailbox.getItemAtIndex(nextIndex);
|
||||
}
|
||||
if (index < mailbox.getLength())
|
||||
previousMessage = mailbox.getItemAtIndex(index);
|
||||
|
||||
if (nextMessage) {
|
||||
if (nextMessage.isread && previousMessage && !previousMessage.isread) {
|
||||
nextIndex = index;
|
||||
nextMessage = previousMessage;
|
||||
}
|
||||
}
|
||||
else if (previousMessage) {
|
||||
nextIndex = index;
|
||||
nextMessage = previousMessage;
|
||||
}
|
||||
|
||||
try {
|
||||
if (nextMessage && $mdMedia(sgConstant['gt-md'])) {
|
||||
if (Mailbox.$virtualMode)
|
||||
state.go('mail.account.virtualMailbox.message', {mailboxId: encodeUriFilter(nextMessage.$mailbox.path), messageId: nextMessage.uid});
|
||||
else
|
||||
state.go('mail.account.mailbox.message', {messageId: nextMessage.uid});
|
||||
$timeout(function() {
|
||||
if (nextIndex < mailbox.$topIndex)
|
||||
mailbox.$topIndex = nextIndex;
|
||||
else if (nextIndex > mailbox.$lastVisibleIndex)
|
||||
mailbox.$topIndex = nextIndex - (mailbox.$lastVisibleIndex - mailbox.$topIndex);
|
||||
});
|
||||
}
|
||||
else {
|
||||
state.go('mail.account.mailbox').then(function() {
|
||||
message = null;
|
||||
delete mailbox.$selectedMessage;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (error) {}
|
||||
}
|
||||
vm.closePopup();
|
||||
_selectNextMessage(mailbox, state, index);
|
||||
}
|
||||
|
||||
mailbox.$deleteMessages([message]).then(_success, function(response) {
|
||||
@@ -407,6 +415,39 @@
|
||||
});
|
||||
};
|
||||
|
||||
this.markOrUnMarkAsJunk = function() {
|
||||
var mailbox, message, state, account, dstFolder,
|
||||
parentCtrls = $parentControllers();
|
||||
|
||||
if (parentCtrls.messageCtrl) {
|
||||
mailbox = parentCtrls.mailboxCtrl.selectedFolder;
|
||||
message = parentCtrls.messageCtrl.message;
|
||||
state = parentCtrls.messageCtrl.$state;
|
||||
account = parentCtrls.messageCtrl.account;
|
||||
}
|
||||
else {
|
||||
mailbox = stateMailbox;
|
||||
message = stateMessage;
|
||||
state = $state;
|
||||
account = stateAccount;
|
||||
}
|
||||
if (Mailbox.$virtualMode) {
|
||||
mailbox = Mailbox.selectedFolder; // the VirtualMailbox instance
|
||||
}
|
||||
|
||||
if (mailbox.type == 'junk')
|
||||
dstFolder = '/' + account.id + '/folderINBOX';
|
||||
else
|
||||
dstFolder = '/' + account.$getMailboxByType('junk').id;
|
||||
|
||||
mailbox.$markOrUnMarkMessagesAsJunk([message]).then(function() {
|
||||
mailbox.$moveMessages([message], dstFolder).then(function(index) {
|
||||
message = null;
|
||||
_selectNextMessage(mailbox, state, index);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function _showMailEditor($event, message) {
|
||||
if (_messageDialog() === null) {
|
||||
var onCompleteDeferred = $q.defer();
|
||||
|
||||
@@ -11,10 +11,9 @@ $icon-badge-size: 2 * $baseline-grid;
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('../fonts/MaterialIcons-Regular.eot'); /* For IE6-8 */
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url('../fonts/MaterialIcons-Regular.woff2') format('woff2'),
|
||||
/* No local() sources: always use the bundled font so an outdated
|
||||
Material Icons font installed on the OS can't shadow it. */
|
||||
src: url('../fonts/MaterialIcons-Regular.woff2') format('woff2'),
|
||||
url('../fonts/MaterialIcons-Regular.woff') format('woff'),
|
||||
url('../fonts/MaterialIcons-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user