Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55c477b193 | ||
|
|
7513f76be7 | ||
|
|
78c6aa5236 | ||
|
|
1f48a7c95e | ||
|
|
16ab99e7cf | ||
|
|
bd0547fb73 | ||
|
|
03fa91dc22 | ||
|
|
e2b8494a9c | ||
|
|
d69f55c265 | ||
|
|
f8638a3f4e | ||
|
|
f18e3a05c3 | ||
|
|
6425a62e1a | ||
|
|
5021376daf | ||
|
|
8c38c9ce03 | ||
|
|
f86a32d0a1 | ||
|
|
2ebb63767e | ||
|
|
c755ab3b4e | ||
|
|
07e9d34865 | ||
|
|
645be8fcc5 | ||
|
|
0f24c17516 | ||
|
|
c675dbfaa7 | ||
|
|
dd367b0e94 | ||
|
|
1a80fd6284 | ||
|
|
ec4d7807d9 | ||
|
|
972ffcc0c6 | ||
|
|
3a442f1b3d | ||
|
|
eab6d9f249 | ||
|
|
3dc9b90992 | ||
|
|
798bed54e2 | ||
|
|
2b455fe587 | ||
|
|
ad7dc8f45e | ||
|
|
ed9121175a | ||
|
|
6514fbb8f1 | ||
|
|
9a295c5944 | ||
|
|
1bb74c7522 | ||
|
|
56e4929ca7 | ||
|
|
401e2f51cd | ||
|
|
799e8c21af | ||
|
|
070705acfa | ||
|
|
95e19379f6 | ||
|
|
f017fef4b2 | ||
|
|
a914fd4151 | ||
|
|
c0c506f910 | ||
|
|
b42882b564 | ||
|
|
ae293ec3ce | ||
|
|
e662f10389 | ||
|
|
c7a519ca12 | ||
|
|
22ab0b3c75 | ||
|
|
b77129e2e7 | ||
|
|
4585293d99 | ||
|
|
9d277c3f15 | ||
|
|
4461122697 | ||
|
|
b96e531f66 | ||
|
|
6c3e66142f | ||
|
|
16fcb46c4b | ||
|
|
f252e0e2c2 | ||
|
|
09d87b2d23 | ||
|
|
9e20190fad | ||
|
|
981748754a | ||
|
|
8d8ef5fd67 | ||
|
|
666c979eea | ||
|
|
1d59c616ac | ||
|
|
a7f7950d91 | ||
|
|
5d616600df | ||
|
|
a077512e34 | ||
|
|
23c8648169 | ||
|
|
9fad7e6f9c | ||
|
|
0fb3db0608 | ||
|
|
a7651e56c5 | ||
|
|
481a9bf1de | ||
|
|
f48f27c812 | ||
|
|
86d94ab8fe | ||
|
|
aba41a06b4 | ||
|
|
ed7a136e0f | ||
|
|
d99f020f82 | ||
|
|
244d1388eb | ||
|
|
dfcbbba514 | ||
|
|
7bee193413 | ||
|
|
4ef79e219c | ||
|
|
736d7589b1 | ||
|
|
4d8cca10f6 | ||
|
|
c8dd5535b3 | ||
|
|
42f620e562 | ||
|
|
3662846900 | ||
|
|
b9f6b90740 | ||
|
|
b69ef6d7a5 | ||
|
|
3ab86776e2 | ||
|
|
7fa0daea43 | ||
|
|
55dbae6bee | ||
|
|
d48befd151 | ||
|
|
f5f8f112cd | ||
|
|
08bc6aff3f | ||
|
|
8290cf2859 | ||
|
|
8f03432a55 | ||
|
|
9649ae345f | ||
|
|
e9c03d3cf7 | ||
|
|
031e117cba | ||
|
|
dabad1d0cf | ||
|
|
c1b6388260 | ||
|
|
bc6b849d66 | ||
|
|
51f1521dba | ||
|
|
516606baff | ||
|
|
a782424a30 | ||
|
|
f53d7b73db | ||
|
|
8766b7c6b3 | ||
|
|
8a907737de | ||
|
|
1a6f2825b6 |
No files matched your search
@@ -10,6 +10,7 @@
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
ActiveSync/ActiveSync.SOGo
|
||||
API/API.SOGo
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
Documentation/*.html
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = fr: French, pt_BR: BrazilianPortuguese, ru: Russian, sk: Slovak, es_AR: SpanishArgentina, fi: Finnish, id_ID: Indonesian, lt: Lithuanian, tr_TR: TurkishTurkey, zh_TW: ChineseTaiwan, ar: Arabic, cs: Czech, nn_NO: NorwegianNynorsk, sl_SI: Slovenian, uk: Ukrainian, zh_CN: ChineseChina, sv: Swedish, bg_BG: Bulgarian, cy: Welsh, is: Icelandic, sr: Serbian, lv: Latvian, pl: Polish, ro_RO: Romanian, bs_BA: Bosnian,ca: Catalan, he: Hebrew, kk: Kazakh, pt: Portuguese, es_ES: SpanishSpain, eu: Basque, hu: Hungarian, ja: Japanese, mk_MK: Macedonian, nb_NO: NorwegianBokmal, nl: Dutch, sr@latin: SerbianLatin, da_DK: Danish, de: German, hr_HR: Croatian, it: Italian, sr_ME@latin: Montenegrin, gl_ES: Galician
|
||||
lang_map = fr: French, pt_BR: BrazilianPortuguese, ru: Russian, sk: Slovak, es_AR: SpanishArgentina, fi: Finnish, id_ID: Indonesian, lt: Lithuanian, tr_TR: TurkishTurkey, zh_TW: ChineseTaiwan, ar: Arabic, cs: Czech, nn_NO: NorwegianNynorsk, sl_SI: Slovenian, uk: Ukrainian, zh_CN: ChineseChina, sv: Swedish, bg_BG: Bulgarian, cy: Welsh, is: Icelandic, sr: Serbian, lv: Latvian, pl: Polish, ro_RO: Romanian, bs_BA: Bosnian,ca: Catalan, he: Hebrew, kk: Kazakh, pt: Portuguese, es_ES: SpanishSpain, eu: Basque, hu: Hungarian, ja: Japanese, mk_MK: Macedonian, nb_NO: NorwegianBokmal, nl: Dutch, sr@latin: SerbianLatin, da_DK: Danish, de: German, hr_HR: Croatian, it: Italian, sr_ME@latin: Montenegrin, gl_ES: Galician, ko: Korean, th: Thai
|
||||
|
||||
[o:alinto:p:sogo:r:soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
|
||||
# GNUstep makefile
|
||||
|
||||
include common.make
|
||||
|
||||
BUNDLE_NAME = API
|
||||
|
||||
API_PRINCIPAL_CLASS = SOGoAPIProduct
|
||||
|
||||
API_OBJC_FILES = \
|
||||
SOGoAPIProduct.m \
|
||||
SOGoAPI.m \
|
||||
SOGoAPIVersion.m \
|
||||
SOGoAPIUserFolder.m \
|
||||
SOGoAPIDispatcher.m
|
||||
|
||||
API_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
API_LANGUAGES = $(SOGO_LANGUAGES)
|
||||
|
||||
API_LOCALIZED_RESOURCE_FILES = Localizable.strings
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
||||
@@ -0,0 +1,16 @@
|
||||
# compile settings
|
||||
|
||||
ADDITIONAL_CPPFLAGS += \
|
||||
-DSOGO_MAJOR_VERSION=$(MAJOR_VERSION) \
|
||||
-DSOGO_MINOR_VERSION=$(MINOR_VERSION) \
|
||||
-DSOGO_PATCH_VERSION=$(SUBMINOR_VERSION) \
|
||||
-DSOGO_LIBDIR="@\"$(SOGO_LIBDIR)\""
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-D_GNU_SOURCE -I../SOPE/ -I../SoObjects/
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/sogo -lSOGo \
|
||||
-L../SOPE/GDLContentStore/$(GNUSTEP_OBJ_DIR)/ -lGDLContentStore \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ -lNGCards \
|
||||
-lEOControl -lNGStreams -lNGMime -lNGExtensions -lNGObjWeb -lWEExtensions
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPI : NSObject
|
||||
- (NSArray *) methodAllowed;
|
||||
- (BOOL) needAuth;
|
||||
- (NSArray *) paramNeeded;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
|
||||
@implementation SOGoAPI
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSArray *) methodAllowed
|
||||
{
|
||||
NSArray *result;
|
||||
|
||||
result = [NSArray arrayWithObjects:@"GET",nil];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSArray *) paramNeeded
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
@"API not defined", @"error",
|
||||
nil];
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPI */
|
||||
Whitespace-only changes.
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSException;
|
||||
@class NSMutableDictionary;
|
||||
@class NSURL;
|
||||
@class NSNumber;
|
||||
|
||||
static volatile BOOL apiShouldTerminate = NO;
|
||||
|
||||
@interface SOGoAPIDispatcher : NSObject
|
||||
{
|
||||
|
||||
id context;
|
||||
BOOL debugOn;
|
||||
}
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoAPIDispatcher.h"
|
||||
|
||||
#import <Foundation/NSAutoreleasePool.h>
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WOCoreApplication.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGExtensions/NSString+Encoding.h>
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserManager.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/WORequest+SOGo.h>
|
||||
#import <SOGo/WOResponse+SOGo.h>
|
||||
#import <SOGo/NSArray+Utilities.h>
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/SOGoOpenIdSession.h>
|
||||
|
||||
|
||||
void handle_api_terminate(int signum)
|
||||
{
|
||||
NSLog(@"Forcing termination of API loop.");
|
||||
apiShouldTerminate = YES;
|
||||
[[WOCoreApplication application] terminateAfterTimeInterval: 1];
|
||||
}
|
||||
|
||||
@implementation SOGoAPIDispatcher
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] apiDebugEnabled];
|
||||
apiShouldTerminate = NO;
|
||||
|
||||
signal(SIGTERM, handle_api_terminate);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) _sendAPIErrorResponse: (WOResponse* ) response
|
||||
withMessage: (NSString *) message
|
||||
withStatus: (unsigned int) status
|
||||
{
|
||||
NSDictionary *msg;
|
||||
msg = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
message, @"error",
|
||||
nil];
|
||||
[response setStatus: status];
|
||||
[response setContent: [msg jsonRepresentation]];
|
||||
}
|
||||
|
||||
- (NSString *) _getActionFromUri: (NSString *) _uri
|
||||
{
|
||||
/*
|
||||
_uri always start with /SOGo/SOGoAPI
|
||||
full _uri example /SOGo/SOGoAPI/Action/subaction1?param1¶m2
|
||||
*/
|
||||
|
||||
NSString *uriWithoutParams, *action, *prefix;
|
||||
NSArray *uriSplits;
|
||||
|
||||
prefix = @"/SOGo/SOGoAPI";
|
||||
action = @"";
|
||||
|
||||
uriWithoutParams = [_uri urlWithoutParameters];
|
||||
if(![uriWithoutParams hasPrefix: prefix])
|
||||
{
|
||||
[self errorWithFormat: @"Uri for API request does not start with /SOGo/SOGoAPI: %@", uriWithoutParams];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:[prefix length]];
|
||||
}
|
||||
|
||||
//remove first and last '/'' if needed
|
||||
if([uriWithoutParams hasPrefix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringFromIndex:1];
|
||||
}
|
||||
if([uriWithoutParams hasSuffix: @"/"])
|
||||
{
|
||||
uriWithoutParams = [uriWithoutParams substringToIndex:([uriWithoutParams length] -1)];
|
||||
}
|
||||
if([uriWithoutParams length] == 0)
|
||||
{
|
||||
[self warnWithFormat: @"Uri for API request has no action, make Version instead: %@", uriWithoutParams];
|
||||
return @"SOGoAPIVersion";
|
||||
}
|
||||
else
|
||||
{
|
||||
uriSplits = [uriWithoutParams componentsSeparatedByString: @"/"];
|
||||
action = [@"SOGoAPI" stringByAppendingString: [uriSplits objectAtIndex: 0]];
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"API request, action made is %@", action];
|
||||
}
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authBasicCheck: (NSString *) auth
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSRange rng;
|
||||
NSString *decodeCred, *domain, *login, *pwd;
|
||||
SOGoUserManager *lm;
|
||||
SOGoPasswordPolicyError perr;
|
||||
int expire, grace;
|
||||
BOOL rc;
|
||||
|
||||
user = nil;
|
||||
|
||||
decodeCred = [[auth substringFromIndex:5] stringByTrimmingLeadWhiteSpaces];
|
||||
decodeCred = [decodeCred stringByDecodingBase64];
|
||||
|
||||
rng = [decodeCred rangeOfString:@":"];
|
||||
login = [decodeCred substringToIndex:rng.location];
|
||||
pwd = [decodeCred substringFromIndex:(rng.location + rng.length)];
|
||||
|
||||
domain = nil;
|
||||
perr = PolicyNoError;
|
||||
rc = ([[SOGoUserManager sharedUserManager]
|
||||
checkLogin: [login stringByReplacingString: @"%40"
|
||||
withString: @"@"]
|
||||
password: pwd
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
expire: &expire
|
||||
grace: &grace
|
||||
additionalInfo: nil]
|
||||
&& perr == PolicyNoError);
|
||||
|
||||
if(rc)
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
- (NSDictionary *) _authOpenId: (NSString *) auth withDomain: (NSString *) domain
|
||||
{
|
||||
NSDictionary *user;
|
||||
NSString *token, *login;
|
||||
SOGoOpenIdSession *openIdSession;
|
||||
SOGoUserManager *lm;
|
||||
|
||||
user = nil;
|
||||
token = [[auth substringFromIndex:6] stringByTrimmingLeadWhiteSpaces];
|
||||
|
||||
openIdSession = [SOGoOpenIdSession OpenIdSession: domain];
|
||||
if(![openIdSession sessionIsOk])
|
||||
{
|
||||
[self errorWithFormat: @"API - OpenId server not found or has unexpected behavior, contact your admin."];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[openIdSession setAccessToken: token];
|
||||
login = [openIdSession login: @""];
|
||||
|
||||
if(login && ![login isEqualToString: @"anonymous"])
|
||||
{
|
||||
//Fecth user info
|
||||
lm = [SOGoUserManager sharedUserManager];
|
||||
user = [lm contactInfosForUserWithUIDorEmail: login];
|
||||
}
|
||||
else
|
||||
user = nil;
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
- (NSException *) dispatchRequest: (WORequest*) theRequest
|
||||
inResponse: (WOResponse*) theResponse
|
||||
context: (id) theContext
|
||||
{
|
||||
NSAutoreleasePool *pool;
|
||||
id activeUser;
|
||||
NSString *method, *action, *error;
|
||||
NSDictionary *form;
|
||||
NSArray *paramNeeded;
|
||||
NSMutableDictionary *paramInjected, *ret;
|
||||
NSBundle *bundle;
|
||||
id classAction;
|
||||
Class clazz;
|
||||
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
ASSIGN(context, theContext);
|
||||
|
||||
//Get the api action, check it
|
||||
action = [self _getActionFromUri: [theRequest uri]];
|
||||
if(!action)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No actions found for request to API: %@", [theRequest uri]];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//Get the class for this action, check it
|
||||
bundle = [NSBundle bundleForClass: NSClassFromString(@"SOGoAPIProduct")];
|
||||
clazz = [bundle classNamed: action];
|
||||
if(!clazz)
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No backend API found for action: %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//try to instantiate the class
|
||||
NS_DURING
|
||||
{
|
||||
classAction = [[clazz alloc] init];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Can't alloc and init class: %@", classAction];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
//Check method
|
||||
method = [theRequest method];
|
||||
if(![[classAction methodAllowed] containsObject: method])
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Method %@ not allowed for action %@", method, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
paramInjected = [NSMutableDictionary dictionary];
|
||||
//Check parameters
|
||||
if((paramNeeded = [classAction paramNeeded]) && [paramNeeded count] >= 1)
|
||||
{
|
||||
NSDictionary* formAndQuery = [theRequest formValues];
|
||||
for(NSString *param in paramNeeded)
|
||||
{
|
||||
id value;
|
||||
if((value = [formAndQuery objectForKey: param]))
|
||||
{
|
||||
NSString* trueValue;
|
||||
if ([value isKindOfClass: [NSArray class]])
|
||||
trueValue = [value lastObject];
|
||||
else
|
||||
trueValue = value;
|
||||
[paramInjected setObject: trueValue forKey: param];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Missing param %@ for action %@", param, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 400];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if([classAction needAuth])
|
||||
{
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"Check auth for action %@", action];
|
||||
//check auth
|
||||
NSString *auth = [theRequest headerForKey: @"authorization"];
|
||||
if(auth)
|
||||
{
|
||||
NSDictionary* user;
|
||||
if([[auth lowercaseString] hasPrefix: @"basic"])
|
||||
{
|
||||
//basic auth
|
||||
user = [self _authBasicCheck: auth];
|
||||
}
|
||||
else if([[auth lowercaseString] hasPrefix: @"bearer"])
|
||||
{
|
||||
//openid auth, we may need to know the user-domain to know which openid server to fetch
|
||||
NSString *domain = [theRequest headerForKey: @"user-domain"];
|
||||
user = [self _authOpenId: auth withDomain: domain];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Authorization method incorrect: %@ for action %@", auth, action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
|
||||
//add current user in paramInjected
|
||||
if(user){
|
||||
if(debugOn)
|
||||
[self logWithFormat: @"User authenticated %@", user];
|
||||
[paramInjected setObject: user forKey: @"user"];
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"User wrong login or not found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = [NSString stringWithFormat: @"No authorization header found for action %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 401];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
//Execute action
|
||||
NS_DURING
|
||||
{
|
||||
ret = [classAction action: context withParam: paramInjected];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
error = [NSString stringWithFormat: @"Internal error during: %@", action];
|
||||
[self errorWithFormat: error];
|
||||
[self _sendAPIErrorResponse: theResponse withMessage: error withStatus: 500];
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
return nil;
|
||||
}
|
||||
NS_ENDHANDLER;
|
||||
|
||||
|
||||
//Make the response
|
||||
[theResponse setContent: [ret jsonRepresentation]];
|
||||
|
||||
RELEASE(context);
|
||||
RELEASE(pool);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@interface SOGoAPIProduct : NSObject
|
||||
@end
|
||||
|
||||
@implementation SOGoAPIProduct
|
||||
@end /* SOGoAPIProduct */
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIUserFolder : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIUserFolder.h>
|
||||
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
#import <GDLContentStore/GCSFolder.h>
|
||||
|
||||
@implementation SOGoAPIUserFolder
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
|
||||
|
||||
{
|
||||
"calendar":[
|
||||
{
|
||||
"name":"DidyShared",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/12509-67F67D00-1-3105AF40"
|
||||
},
|
||||
{
|
||||
"name":"LocalDidy",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/1BC38-67B60000-1-6E4B6880"
|
||||
},
|
||||
{
|
||||
"name":"Personal Calendar",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/personal"
|
||||
}
|
||||
],
|
||||
"username":"sogo-tests1@example.org",
|
||||
"contact":[
|
||||
{
|
||||
"name":"Personal Address Book",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Contacts/personal"
|
||||
}
|
||||
]
|
||||
}
|
||||
**/
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
NSArray *folders;
|
||||
NSMutableArray *cardavLinks, *caldavLinks;
|
||||
NSString *serverUrl, *basePath, *c_uid, *url;
|
||||
GCSFolderManager *fm;
|
||||
GCSFolder *folder;
|
||||
|
||||
int max, i;
|
||||
|
||||
//Should be a user
|
||||
c_uid = [[[param objectForKey: @"user"] objectForKey: @"emails"] objectAtIndex: 0];
|
||||
|
||||
//fetch folders
|
||||
fm = [GCSFolderManager defaultFolderManager];
|
||||
basePath = [NSString stringWithFormat: @"/Users/%@", c_uid];
|
||||
folders = [fm listSubFoldersAndNamesAtPath: basePath recursive: YES];
|
||||
|
||||
//Generate dav link
|
||||
max = [folders count];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
|
||||
cardavLinks = [NSMutableArray array];
|
||||
caldavLinks = [NSMutableArray array];
|
||||
serverUrl = [[ctx serverURL] absoluteString];
|
||||
for (i = 0; i < max; i++)
|
||||
{
|
||||
NSMutableDictionary *folderRet;
|
||||
folderRet = [NSMutableDictionary dictionary];
|
||||
folder = [folders objectAtIndex: i];
|
||||
url = [NSString stringWithFormat: @"%@/SOGo/dav/%@/%@", serverUrl, c_uid, [folder objectForKey: @"path"]];
|
||||
[folderRet setObject: url forKey: @"url"];
|
||||
[folderRet setObject: [folder objectForKey: @"name"] forKey: @"name"];
|
||||
if([url rangeOfString:@"/Calendar/"].location == NSNotFound)
|
||||
{
|
||||
//Contacts
|
||||
[cardavLinks addObject: folderRet];
|
||||
}
|
||||
else
|
||||
{
|
||||
//Calendar
|
||||
[caldavLinks addObject: folderRet];
|
||||
}
|
||||
}
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
c_uid, @"username",
|
||||
cardavLinks, @"contact",
|
||||
caldavLinks, @"calendar",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of SOPE.
|
||||
|
||||
SOPE is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
SOPE 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with SOPE; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <SOGoAPI.h>
|
||||
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoAPIVersion : SOGoAPI
|
||||
- (NSArray *) methodAllowed;
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param;
|
||||
@end
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright (C) todo...
|
||||
*/
|
||||
|
||||
#import <SOGoAPIVersion.h>
|
||||
|
||||
|
||||
@implementation SOGoAPIVersion
|
||||
|
||||
- (id) init
|
||||
{
|
||||
[super init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (BOOL) needAuth
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *) action: (WOContext*) ctx withParam: (NSDictionary *) param
|
||||
{
|
||||
NSDictionary* result;
|
||||
|
||||
result = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:SOGO_MAJOR_VERSION], @"major",
|
||||
[NSNumber numberWithInt:SOGO_MINOR_VERSION], @"minor",
|
||||
[NSNumber numberWithInt:SOGO_PATCH_VERSION], @"patch",
|
||||
nil];
|
||||
|
||||
[result autorelease];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@end /* SOGoAPIVersion */
|
||||
@@ -0,0 +1,34 @@
|
||||
include ../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../Version
|
||||
|
||||
NEEDS_GUI=no
|
||||
BUNDLE_EXTENSION = .SOGo
|
||||
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
|
||||
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
|
||||
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
|
||||
|
||||
# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-I.. \
|
||||
-I../.. \
|
||||
-I../../SOPE
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib \
|
||||
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
-lSOGo \
|
||||
-lGDLContentStore \
|
||||
-lGDLAccess \
|
||||
-lNGObjWeb \
|
||||
-lNGCards -lNGMime -lNGLdap \
|
||||
-lNGStreams -lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC -lSBJson
|
||||
|
||||
ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
requires = ( MAIN, Appointments, Contacts, Mailer );
|
||||
|
||||
publicResources = ();
|
||||
|
||||
factories = {};
|
||||
|
||||
classes = {
|
||||
SOGoAPI = {
|
||||
protectedBy = "<public>";
|
||||
defaultRoles = {
|
||||
"View" = ( "Authenticated", "PublicUser" );
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
categories = {
|
||||
SOGoAPI = {
|
||||
slots = {
|
||||
};
|
||||
methods = {
|
||||
Version = {
|
||||
protectedBy = "View";
|
||||
pageName = "SOGoAPI";
|
||||
actionName = "sogoVersion";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -370,7 +370,9 @@ void handle_eas_terminate(int signum)
|
||||
NSMutableString *s;
|
||||
NSData *d;
|
||||
|
||||
int type;
|
||||
int type, status;
|
||||
|
||||
status = 1;
|
||||
|
||||
parentId = [[(id)[theDocumentElement getElementsByTagName: @"ParentId"] lastObject] textValue];
|
||||
displayName = [[(id)[theDocumentElement getElementsByTagName: @"DisplayName"] lastObject] textValue];
|
||||
@@ -413,7 +415,12 @@ void handle_eas_terminate(int signum)
|
||||
// FIXME
|
||||
// handle exists (status == 2)
|
||||
// handle right synckey
|
||||
if ([newFolder create])
|
||||
if([newFolder exists])
|
||||
{
|
||||
nameInContainer = [newFolder nameInContainer];
|
||||
status = 2;
|
||||
}
|
||||
else if ([newFolder create])
|
||||
{
|
||||
SOGoMailAccount *accountFolder;
|
||||
NSDictionary *imapGUIDs;
|
||||
@@ -528,7 +535,7 @@ void handle_eas_terminate(int signum)
|
||||
[s appendString: @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"];
|
||||
[s appendString: @"<!DOCTYPE ActiveSync PUBLIC \"-//MICROSOFT//DTD ActiveSync//EN\" \"http://www.microsoft.com/\">"];
|
||||
[s appendString: @"<FolderCreate xmlns=\"FolderHierarchy:\">"];
|
||||
[s appendFormat: @"<Status>%d</Status>", 1];
|
||||
[s appendFormat: @"<Status>%d</Status>", status];
|
||||
[s appendFormat: @"<SyncKey>%@</SyncKey>", syncKey];
|
||||
[s appendFormat: @"<ServerId>%@</ServerId>", [nameInContainer stringByEscapingURL]];
|
||||
[s appendString: @"</FolderCreate>"];
|
||||
|
||||
@@ -1627,7 +1627,7 @@ struct GlobalObjectId {
|
||||
|
||||
[map setObject: dateReceived forKey: @"date"];
|
||||
|
||||
messageId = [NSString generateMessageID];
|
||||
messageId = [NSString generateMessageID: [identity objectForKey: @"email"]];
|
||||
[map setObject: messageId forKey: @"message-id"];
|
||||
|
||||
attachmentKeys = [self fetchFileAttachmentKeys];
|
||||
|
||||
+112
@@ -2,6 +2,118 @@
|
||||
|
||||
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.4](https://github.com/Alinto/sogo/compare/SOGo-5.12.3...SOGo-5.13.0) (2025-10-06)
|
||||
|
||||
|
||||
### Enhancements
|
||||
|
||||
* **mail:** Add a setting to show the attachments above the mail body ([5d61660](https://github.com/Alinto/sogo/commit/5d616600dfa6258e4eebcb5c065e393ebfae8f3a))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **calendar:** fetch our own iana timezone instead of trusting VTIMEZONE ([244d138](https://github.com/Alinto/sogo/commit/244d1388eb00c060c5302e5bfd997fd397820bc0))
|
||||
* **curl:** properly close curl connection ([42f620e](https://github.com/Alinto/sogo/commit/42f620e56201e17391532507c02ae370f117c574))
|
||||
* **eas:** use proper imap mech for EAS request when using openid ([a7f7950](https://github.com/Alinto/sogo/commit/a7f7950d91c83acd75c0b0d55dec74ab85d38d6c))
|
||||
* **ldap:** don't try to fetch for a nobody user ([4d8cca1](https://github.com/Alinto/sogo/commit/4d8cca10f63aff9499b71d61d59d6f81570eb659))
|
||||
* **label:** ensure the translation kept is not null ([0fb3db0](https://github.com/Alinto/sogo/commit/0fb3db060871a14e2abd8c6963ccd812cbacf200))
|
||||
* **label:** missing trad ([23c8648](https://github.com/Alinto/sogo/commit/23c8648169b4893aaafa2e369259d94d56c76831))
|
||||
* **ldap:** fetch the correct user source when creating an event with an attendee ([736d758](https://github.com/Alinto/sogo/commit/736d7589b16be4ebcf9fc6931a79187888c3b444))
|
||||
* **login:** Only remember the login if the auth was successful ([9e20190](https://github.com/Alinto/sogo/commit/9e20190fad1a437f7e1307f0adcfe19a8d45184c))
|
||||
* **log:** remove the ics from the log line ([86d94ab](https://github.com/Alinto/sogo/commit/86d94ab8fefaf3aa5ba99e13c28a0b24036d94ff))
|
||||
* **mailer:** correctly show interline for p element ([666c979](https://github.com/Alinto/sogo/commit/666c979eeae6d51a6bc09684ebbab57ed9ce4b91))
|
||||
* **mailer:** don't add mailto: to string starting with @ ([9817487](https://github.com/Alinto/sogo/commit/981748754a4857bab66a6fb94cdc5da4265ce003))
|
||||
* **mail:** preoperly generates the message-id header value ([7bee193](https://github.com/Alinto/sogo/commit/7bee193413935ca03e4936a15791fbbb534493ec))
|
||||
* **openid:** correcly type userTokenInterval ([4ef79e2](https://github.com/Alinto/sogo/commit/4ef79e219c289697eec0c2d100c8af1a5d0889b6))
|
||||
* **password:** Correctly check the secret question answer when hitting enter instead of the button next ([ed7a136](https://github.com/Alinto/sogo/commit/ed7a136e0f2c5ecd35033aef6d0561d9fcf2ccdc))
|
||||
* **task:** fix reminder for tasks ([a7651e5](https://github.com/Alinto/sogo/commit/a7651e56c53a4dc33892d86f404a132a2b8af83a))
|
||||
* **ui:** add css class for login page ([a077512](https://github.com/Alinto/sogo/commit/a077512e34bf42933457b92613b348ff2e06642a))
|
||||
* **calendar:** don't allocate and copy all children for each time we call _filterComponent: ([481a9bf](https://github.com/Alinto/sogo/commit/481a9bf1de1da8e07b5ed4c1786aac89d19ca6c3))
|
||||
* **core:** store translations in a globally static NSMutableDictionary ([f48f27c](https://github.com/Alinto/sogo/commit/f48f27c812466ce806ab60b43ebe5a2bfc97ed0a))
|
||||
|
||||
### Localization
|
||||
|
||||
* **ar:** Update Arabic translations ([6c3e661](https://github.com/Alinto/sogo/commit/6c3e66142f50c68ee9b1435e5d6961573e7445d4))
|
||||
* **bg_BG:** Update Bulgarian translations ([4585293](https://github.com/Alinto/sogo/commit/4585293d999152e6c7b54f00f73f925051a4ed64))
|
||||
* **bs_BA:** Update Bosnian translations ([4461122](https://github.com/Alinto/sogo/commit/446112269705ae1565a21d3e39e4665c172fc3d4))
|
||||
* **ca:** Update Catalan translations ([b77129e](https://github.com/Alinto/sogo/commit/b77129e2e7608f163eeeb1c4ed7e35fb5558c3cb))
|
||||
* **cs:** Update Czech translations ([f252e0e](https://github.com/Alinto/sogo/commit/f252e0e2c271118cceb2979a828f5220350ba57f))
|
||||
* **cy:** Update Welsh translations ([6425a62](https://github.com/Alinto/sogo/commit/6425a62e1ab8900dc83df5ca165eb92718856886))
|
||||
* **da_DK:** Update Danish translations ([ae293ec](https://github.com/Alinto/sogo/commit/ae293ec3ce7488530199e82bd7bde50b2d506a43))
|
||||
* **de:** Update German translations ([95e1937](https://github.com/Alinto/sogo/commit/95e19379f6fa698f54a09d7b7bcb4cfe16b4c358))
|
||||
* **es_AR:** Update SpanishArgentina translations ([07e9d34](https://github.com/Alinto/sogo/commit/07e9d34865e57fa64f8db1b7ed4a5a67a0c1f234))
|
||||
* **es_ES:** Update SpanishSpain translations ([c755ab3](https://github.com/Alinto/sogo/commit/c755ab3b4ea5ecad2c98d396d6bca6d873d0f1de))
|
||||
* **eu:** Update Basque translations ([b96e531](https://github.com/Alinto/sogo/commit/b96e531f662a41802bd83e54e4a8055987d36164))
|
||||
* **fi:** Update Finnish translations ([c0c506f](https://github.com/Alinto/sogo/commit/c0c506f9103b12ed5a39b340c4bccac500a2f6a8))
|
||||
* **fr:** Update French translations ([a914fd4](https://github.com/Alinto/sogo/commit/a914fd4151e5565d4f168819c2664dc460587dec))
|
||||
* **gl:** Update Galician translations ([f017fef](https://github.com/Alinto/sogo/commit/f017fef4b2a86f210f36bd5e62afe37c7bba3a18))
|
||||
* **he:** Update Hebrew translations ([070705a](https://github.com/Alinto/sogo/commit/070705acfaa65ad435c1d2fa659e4b1f333b59a8))
|
||||
* **hr_HR:** Update Croatian translations ([e662f10](https://github.com/Alinto/sogo/commit/e662f10389795e281abd283775f0d168a519e25d))
|
||||
* **hu:** Update Hungarian translations ([799e8c2](https://github.com/Alinto/sogo/commit/799e8c21af79b2a8beb082a9d56a238aee30ae4a))
|
||||
* **id_ID:** Update Indonesian translations ([56e4929](https://github.com/Alinto/sogo/commit/56e4929ca78c105dde470a6d26749b1328fad47f))
|
||||
* **is:** Update Icelandic translations ([401e2f5](https://github.com/Alinto/sogo/commit/401e2f51cd3a69afa72fb76ffeb8fc91a5779cca))
|
||||
* **it:** Update Italian translations ([1bb74c7](https://github.com/Alinto/sogo/commit/1bb74c75227f858d680035a5eccd7c5ef954f869))
|
||||
* **ja:** Update Japanese translations ([9a295c5](https://github.com/Alinto/sogo/commit/9a295c5944886df95b941f716fc5e6b4c62525b7))
|
||||
* **kk:** Update Kazakh translations ([6514fbb](https://github.com/Alinto/sogo/commit/6514fbb8f1c2745dd44be49c72da88937fcf107f))
|
||||
* **ko:** Update Korean translations ([ed91211](https://github.com/Alinto/sogo/commit/ed9121175aa6164a73987a247cebe47e53676529))
|
||||
* **lt:** Update Lithuanian translations ([2b455fe](https://github.com/Alinto/sogo/commit/2b455fe587f96700c4398538b995680251660ac1))
|
||||
* **lv:** Update Latvian translations ([ad7dc8f](https://github.com/Alinto/sogo/commit/ad7dc8f45ee316c4d39ebf5fa71207947b4be2f8))
|
||||
* **mk_MK:** Update Macedonian translations ([798bed5](https://github.com/Alinto/sogo/commit/798bed54e2eb0f76f26dc6c6c423285c565b9888))
|
||||
* **nb_NO:** Update NorwegianBokmal translations ([eab6d9f](https://github.com/Alinto/sogo/commit/eab6d9f2492eccc2397c3ad49ab284223cb8771c))
|
||||
* **nl:** Update Dutch translations ([b42882b](https://github.com/Alinto/sogo/commit/b42882b564ad9aa1b510b00d06da21688d959785))
|
||||
* **nn_NO:** Update NorwegianNynorsk translations ([3a442f1](https://github.com/Alinto/sogo/commit/3a442f1b3d38350a5544f0fb62718f45b70c37ad))
|
||||
* **pl:** Update Polish translations ([16fcb46](https://github.com/Alinto/sogo/commit/16fcb46c4be26497d12be712c5bacf0f0056a5b3))
|
||||
* **pt_BR:** Update BrazilianPortuguese translations ([9d277c3](https://github.com/Alinto/sogo/commit/9d277c3f157e21183648609e5bee429559e87a63))
|
||||
* **pt:** Update Portuguese translations ([972ffcc](https://github.com/Alinto/sogo/commit/972ffcc0c6f4f67da5557da28b6c5af87d632b96))
|
||||
* **ro_RO:** Update Romanian translations ([ec4d780](https://github.com/Alinto/sogo/commit/ec4d7807d994836218c6ba9c5979283623a520d4))
|
||||
* **ru:** Update Russian translations ([1a80fd6](https://github.com/Alinto/sogo/commit/1a80fd6284750cc9997e6cbbafcdf86765032405))
|
||||
* **sk:** Update Slovak translations ([0f24c17](https://github.com/Alinto/sogo/commit/0f24c175163e2a000d6cace4d9302cae384f3b49))
|
||||
* **sl_SI:** Update Slovenian translations ([645be8f](https://github.com/Alinto/sogo/commit/645be8fcc53cd2729dad9906e66a8f630cffaf52))
|
||||
* **sr_ME@latin:** Update Montenegrin translations ([3dc9b90](https://github.com/Alinto/sogo/commit/3dc9b9099223940ec4a4f660d499ac450398d6cc))
|
||||
* **sr@latin:** Update SerbianLatin translations ([c675dbf](https://github.com/Alinto/sogo/commit/c675dbfaa70755abf4300462f538dfa878c7c969))
|
||||
* **sr:** Update Serbian translations ([dd367b0](https://github.com/Alinto/sogo/commit/dd367b0e94b74dccfc862d9ca07906cc16234965))
|
||||
* **sv:** Update Swedish translations ([2ebb637](https://github.com/Alinto/sogo/commit/2ebb63767e53c39bc982d9959dabacfdce8b9b19))
|
||||
* **th:** Update Thai translations ([f86a32d](https://github.com/Alinto/sogo/commit/f86a32d0a148b8465a01f098855dc58470c1a689))
|
||||
* **tr_TR:** Update TurkishTurkey translations ([8c38c9c](https://github.com/Alinto/sogo/commit/8c38c9ce038e902d4b79f2093448ffec2c1f1d55))
|
||||
* **uk:** Update Ukrainian translations ([5021376](https://github.com/Alinto/sogo/commit/5021376daf92c95a69afa2a2d99cf559f858d478))
|
||||
* **zh_CN:** Update ChineseChina translations ([22ab0b3](https://github.com/Alinto/sogo/commit/22ab0b3c751f7c20c234c1824552aaa4c661f983))
|
||||
* **zh_TW:** Update ChineseTaiwan translations ([c7a519c](https://github.com/Alinto/sogo/commit/c7a519ca124121e259a00473e6163cbd93e16aa4))
|
||||
|
||||
### [5.12.3](https://github.com/Alinto/sogo/compare/SOGo-5.12.2...SOGo-5.12.3) (2025-07-12)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **calendar:** fix recurrent event last date ([3ab8677](https://github.com/Alinto/sogo/commit/3ab86776e2ea826e043e3a0519097538853d82e3)), closes [#8766b7](https://bugs.sogo.nu/view.php?id=8766b7)
|
||||
* **view:** automatically refresh view only if a number is set. ([55dbae6](https://github.com/Alinto/sogo/commit/55dbae6bee9bdd1aa00333320ba076617cbfb0fc))
|
||||
|
||||
## [5.12.2](https://github.com/Alinto/sogo/compare/SOGo-5.12.1...SOGo-5.12.2) (2025-06-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **api:** add endpoint for caldav/cardav url ([51f1521](https://github.com/Alinto/sogo/commit/51f1521dba2d0ca8bdbadffadb16db26b975f668))
|
||||
* **openid:** swicth to libcurl for http request ([a782424](https://github.com/Alinto/sogo/commit/a782424a30cfe8e9c6f2769a45bcdd3498679237))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **api:** add handler for internal error ([dabad1d](https://github.com/Alinto/sogo/commit/dabad1d0cf46263d78558d79d2af9fff528a9a89))
|
||||
* **calendar:** properly evalute last occurance freebusy ([8766b7c](https://github.com/Alinto/sogo/commit/8766b7c6b32aedf37d7f8f350e461931b253a4fb))
|
||||
* **openid:** add state in connection flow ([085fc4a](https://github.com/Alinto/sogo/commit/085fc4a9eb7d1e2a0f7b48baa1f09a8ba0d515e1))
|
||||
* **openid:** allow expires_in param to be null ([9954c36](https://github.com/Alinto/sogo/commit/9954c3607bfda55424f5ac532a1075407235f345))
|
||||
* **openid:** make end_session_endpoint optional ([c5fb348](https://github.com/Alinto/sogo/commit/c5fb3482e22f1bfc935213e8ed7208becd9bd1f4))
|
||||
* **password:** put correct regex for special char ([e36d0d2](https://github.com/Alinto/sogo/commit/e36d0d219baed8c7d57af0069fadb8d1bf7df072))
|
||||
* **session:** allow password/token to be longer than userkey ([516606b](https://github.com/Alinto/sogo/commit/516606baff5674c25da1e76f532ca2a9d7818ec0))
|
||||
* **sieve:** add requirements for notify when doing a filter ([f53d7b7](https://github.com/Alinto/sogo/commit/f53d7b73db3d87a17a253bf98ee09a80052b3fd8))
|
||||
* **view:** don't hide the option mailcomposer in small screen ([8a90773](https://github.com/Alinto/sogo/commit/8a907737de336f873047ecdc7d5c8ac07ae9e45b))
|
||||
|
||||
|
||||
### Localization
|
||||
|
||||
* **nl:** Update Dutch translations ([031e117](https://github.com/Alinto/sogo/commit/031e117cbacf9d41caff43be19e639dee81b84dc))
|
||||
* **pt:** Update Portuguese translations ([9649ae3](https://github.com/Alinto/sogo/commit/9649ae345f334d390860b0db70db8c3b621f513e))
|
||||
* **tr_TR:** Update TurkishTurkey translations ([e9c03d3](https://github.com/Alinto/sogo/commit/e9c03d3cf7e668866ac757f72d87cdc4709c9d33))
|
||||
|
||||
## [5.12.1](https://github.com/Alinto/sogo/compare/SOGo-5.12.0...SOGo-5.12.1) (2025-04-30)
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
Installation and Configuration Guide
|
||||
====================================
|
||||
= Installation and Configuration Guide
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
@@ -10,8 +9,8 @@ Installation and Configuration Guide
|
||||
////
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
== About this Guide
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
the SOGo solution. It also covers the installation and configuration of
|
||||
@@ -23,8 +22,8 @@ The instructions are based on version {release_version} of SOGo.
|
||||
The latest version of this guide is available
|
||||
at https://www.sogo.nu/support.html#/documentation.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
== Introduction
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
@@ -48,8 +47,8 @@ device, or Outlook 2013/2016
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found at https://sogo.nu/
|
||||
|
||||
Architecture and Compatibility
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Architecture and Compatibility
|
||||
|
||||
image::images/architecture.png[System Architecture, 400, 964]
|
||||
|
||||
@@ -61,11 +60,11 @@ protocol are also supported.
|
||||
To install and configure the Outlook CalDav Synchronizer, please refer
|
||||
to the _Outlook Connector Configuration Guide_.
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
|
||||
Assumptions
|
||||
~~~~~~~~~~~
|
||||
== System Requirements
|
||||
|
||||
|
||||
=== Assumptions
|
||||
|
||||
SOGo reuses many components in an infrastructure. Thus, it requires the
|
||||
following:
|
||||
@@ -104,8 +103,8 @@ components, together with version numbers:
|
||||
|
||||
More recent versions of the software mentioned above can also be used.
|
||||
|
||||
Minimum Hardware Requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Minimum Hardware Requirements
|
||||
|
||||
The following table provides hardware recommendations for the server,
|
||||
desktops and mobile devices:
|
||||
@@ -157,8 +156,8 @@ Linux
|
||||
Microsoft ActiveSync.
|
||||
|=======================================================================
|
||||
|
||||
Operating System Requirements
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Operating System Requirements
|
||||
|
||||
The following operating systems are currently supported by SOGo:
|
||||
|
||||
@@ -182,16 +181,19 @@ directly to the SOGo website at https://sogo.nu/faq/installation.html.
|
||||
Note that once the SOGo packages are installed under Debian and Ubuntu,
|
||||
this guide can be followed in order to fully configure SOGo.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
== Installation
|
||||
|
||||
This section will guide you through the installation of SOGo together
|
||||
with its dependencies. The steps described here apply to an RPM-based
|
||||
installation for a Red Hat or CentOS 7 distribution. Most of these steps
|
||||
should apply to all supported operating systems.
|
||||
|
||||
Software Downloads
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Software Downloads
|
||||
|
||||
**In order to access the community build, go to https://www.sogo.nu/download.html[SOGo website]
|
||||
and select "Development (nightly builds)" at the bottom of the page.**
|
||||
|
||||
[NOTE]
|
||||
In order to access the production builds, you need a proper support contract
|
||||
@@ -252,8 +254,8 @@ sed -i '/enabled=1/a exclude=gnustep* ytnef*' /etc/yum.repos.d/epel.repo
|
||||
|
||||
For more information on EPEL, visit http://fedoraproject.org/wiki/EPEL/.
|
||||
|
||||
Software Installation
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Software Installation
|
||||
|
||||
Once the yum configuration file has been created, you are now ready to
|
||||
install SOGo and its dependencies. To do so, proceed with the following
|
||||
@@ -273,8 +275,8 @@ for Oracle. The installation command will thus look like this:
|
||||
Once completed, SOGo will be fully installed on your server. You are now
|
||||
ready to configure it.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
== Configuration
|
||||
|
||||
In this section, you'll learn how to configure SOGo to use your existing
|
||||
LDAP, SMTP and database servers. As previously mentioned, we assume that
|
||||
@@ -282,8 +284,8 @@ those components run on the same server on which SOGo is being
|
||||
installed. If this is not the case, please adjust the configuration
|
||||
parameters to reflect those changes.
|
||||
|
||||
GNUstep Environment Overview
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== GNUstep Environment Overview
|
||||
|
||||
SOGo makes use of the GNUstep environment. GNUstep is a free software
|
||||
implementation of the OpenStep specification which provides many
|
||||
@@ -316,8 +318,8 @@ wrapped within curly brackets `{ [configuration] }`. If SOGo refuses to
|
||||
start due to syntax errors in its configuration file, `plparse` is helpful
|
||||
for finding these, as it indicates the line containing the problem.
|
||||
|
||||
Preferences Hierarchy
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Preferences Hierarchy
|
||||
|
||||
SOGo supports domain names segregation, meaning that you can separate
|
||||
multiple groups of users within one installation of SOGo. A user
|
||||
@@ -347,8 +349,8 @@ following abbreviations in the tables of this document:
|
||||
Remember that the hierarchy paradigm allow the default value of a
|
||||
parameter to be defined at a parent level.
|
||||
|
||||
General Preferences
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== General Preferences
|
||||
|
||||
The following table describes the general parameters that can be set:
|
||||
|
||||
@@ -876,8 +878,8 @@ Obiously, if your users can connect without specifying a domain, let this parame
|
||||
|
||||
[[Secret-for-sensitive-data]]
|
||||
|
||||
Secret for sensitive data
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Secret for sensitive data
|
||||
|
||||
_Since 5.10_
|
||||
|
||||
@@ -971,8 +973,7 @@ sogo-tool user-preferences unset default <user> AuxiliaryMailAccounts
|
||||
user being the full mail address or just the username if domainless. After that, the user will have to set its auxiliary accounts again.
|
||||
|
||||
|
||||
Authentication using LDAP
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== Authentication using LDAP
|
||||
|
||||
SOGo can use a LDAP server to authenticate users and, if desired, to
|
||||
provide global address books. SOGo can also use an SQL backend for this
|
||||
@@ -1382,8 +1383,8 @@ Defaults to `NO` when unset.
|
||||
|
||||
|=======================================================================
|
||||
|
||||
LDAP Attributes Indexing
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== LDAP Attributes Indexing
|
||||
|
||||
To ensure proper performance of the SOGo application, the following LDAP
|
||||
attributes must be fully indexed:
|
||||
@@ -1399,8 +1400,8 @@ attributes must be fully indexed:
|
||||
Please refer to the documentation of the software you use in order to
|
||||
index those attributes.
|
||||
|
||||
LDAP Attributes Mapping
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== LDAP Attributes Mapping
|
||||
|
||||
Some LDAP attributes are mapped to contacts attributes in the SOGo UI.
|
||||
The table below list most of them. It is possible to override these by
|
||||
@@ -1460,8 +1461,8 @@ mapping = {
|
||||
|Photo |photo
|
||||
|===
|
||||
|
||||
Authenticating using C.A.S.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Authenticating using C.A.S.
|
||||
|
||||
SOGo natively supports C.A.S. authentication. For activating C.A.S.
|
||||
authentication you need first to make sure that the
|
||||
@@ -1564,8 +1565,8 @@ expected by pam_cas, otherwise it will fail to authenticate incoming
|
||||
connection properly.
|
||||
|
||||
|
||||
Authenticating using OPENID
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[[openid-section]]
|
||||
=== Authenticating using OPENID
|
||||
|
||||
SOGo natively supports OPENID authentication. For activating OpenId authentication you need first to make sure that
|
||||
_SOGoAuthenticationType_ is set to `openid`,
|
||||
@@ -1638,8 +1639,8 @@ the session will stays in the table and be useless. That's why a new sogo-tool c
|
||||
You can put it in a cron to do that periodicly. +
|
||||
See _<<sogo-tool-clean-openid-sessions,sogo-tool clean-openid-sessions>>_.
|
||||
|
||||
Authenticating using SAML2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Authenticating using SAML2
|
||||
|
||||
SOGo natively supports SAML2 authentication. Please refer to the documentation of your identity
|
||||
provider and the SAML2 configuration keys that are listed above for proper setup. Once a SOGo
|
||||
@@ -1672,8 +1673,7 @@ _NGImap4AuthMechanism_ is configured to use the `SAML` mechanism. If you
|
||||
make use of the CrudeSAML PAM plugin, this value may be left empty.
|
||||
|
||||
|
||||
Database Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== Database Configuration
|
||||
|
||||
SOGo requires a relational database system in order to store
|
||||
appointments, tasks and contacts information. It also uses the database
|
||||
@@ -1920,10 +1920,9 @@ calendar.
|
||||
|
||||
Ensure the computer used for the test has emoji fonts installed.
|
||||
|
||||
[[Authentication-using-SQL]]
|
||||
|
||||
Authentication using SQL
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[[Authentication-using-SQL]]
|
||||
=== Authentication using SQL
|
||||
|
||||
SOGo can use a SQL-based database server for authentication. The
|
||||
configuration is very similar to LDAP-based authentication.
|
||||
@@ -2160,8 +2159,8 @@ or username@domain.tld
|
||||
Note that groups are currently not supported for SQL-based
|
||||
authentication sources.
|
||||
|
||||
SMTP Server Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SMTP Server Configuration
|
||||
|
||||
SOGo makes use of a SMTP server to send emails from the Web interface,
|
||||
iMIP/iTIP messages and various notifications.
|
||||
@@ -2220,8 +2219,8 @@ Possible values are:
|
||||
Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
|
||||
IMAP Server Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== IMAP Server Configuration
|
||||
|
||||
SOGo requires an IMAP server in order to let users consult their email
|
||||
messages, manage their folders and more.
|
||||
@@ -2389,8 +2388,8 @@ permissions for the individual user.
|
||||
The default prefix is `$`.
|
||||
|=======================================================================
|
||||
|
||||
Web Interface Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Web Interface Configuration
|
||||
|
||||
The following additional parameters only affect the Web interface
|
||||
behaviour of SOGo.
|
||||
@@ -2897,8 +2896,8 @@ SOGoMailJunkSettings = {
|
||||
sent by SOGo. Defaults to `NO` when unset.
|
||||
|=======================================================================
|
||||
|
||||
SOGo Configuration Summary
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SOGo Configuration Summary
|
||||
|
||||
The complete SOGo configuration file `/etc/sogo/sogo.conf` should look
|
||||
like this:
|
||||
@@ -2946,10 +2945,9 @@ like this:
|
||||
}
|
||||
----
|
||||
|
||||
[[multi-domains-configuration]]
|
||||
|
||||
Multi-domains Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
[[multi-domains-configuration]]
|
||||
=== Multi-domains Configuration
|
||||
|
||||
If you want your installation to isolate two groups of users, you must
|
||||
define a distinct authentication source for each _domain_. Your domain keys
|
||||
@@ -3045,8 +3043,8 @@ Defaults to an empty array, which means domains are isolated from each
|
||||
other.
|
||||
|=======================================================================
|
||||
|
||||
Apache Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apache Configuration
|
||||
|
||||
The SOGo configuration for Apache is located in
|
||||
`/etc/httpd/conf.d/SOGo.conf`.
|
||||
@@ -3075,8 +3073,8 @@ The default configuration will use `mod_proxy` and `mod_headers` to
|
||||
relay requests to the `sogod` parent process. This is suitable for small
|
||||
to medium deployments.
|
||||
|
||||
Starting Services
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Starting Services
|
||||
|
||||
Once SOGo if fully installed and configured, start the services using
|
||||
the following command:
|
||||
@@ -3092,8 +3090,8 @@ modules and configuration files were added:
|
||||
Finally, you should also make sure that the `memcached` service is
|
||||
started and that it is also automatically started at boot time.
|
||||
|
||||
_Cronjob_ — EMail reminders
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Cronjob_ — EMail reminders
|
||||
|
||||
SOGo allows you to set email-based reminders for events and tasks. To
|
||||
enable this, you must enable the `SOGoEnableEMailAlarms` preference and
|
||||
@@ -3120,8 +3118,8 @@ SOGoSMTPMasterUserUsername = "foo";
|
||||
SOGoSMTPMasterUserPassword = "bar";
|
||||
```
|
||||
|
||||
_Cronjob_ — Vacation messages activation and expiration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Cronjob_ — Vacation messages activation and expiration
|
||||
|
||||
When vacation messages are enabled (see the parameter
|
||||
_SOGoVacationEnabled_), users can set an activation or expiration date
|
||||
@@ -3142,8 +3140,8 @@ The _cronjob_ should look like this:
|
||||
0 0 * * * sogo /usr/sbin/sogo-tool update-autoreply -p /etc/sogo/sieve.creds
|
||||
----
|
||||
|
||||
_Password_ — Force user password change at login
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== _Password_ — Force user password change at login
|
||||
|
||||
The following commands force user to change his password at login :
|
||||
|
||||
@@ -3157,11 +3155,11 @@ Disable :
|
||||
/usr/sbin/sogo-tool user-preferences unset settings [USER] ForceResetPassword
|
||||
----
|
||||
|
||||
Managing User Accounts
|
||||
----------------------
|
||||
|
||||
Creating the SOGo Administrative Account
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
== Managing User Accounts
|
||||
|
||||
|
||||
=== Creating the SOGo Administrative Account
|
||||
|
||||
First, create the SOGo administrative account in your LDAP server. The
|
||||
following LDIF file (`sogo.ldif`) can be used as an example:
|
||||
@@ -3188,8 +3186,8 @@ administrative account using the following command:
|
||||
|
||||
ldappasswd -h 127.0.0.1 -x -w qwerty -D cn=Manager,dc=acme,dc=com uid=sogo,ou=users,dc=acme,dc=com -s qwerty
|
||||
|
||||
Creating a User Account
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Creating a User Account
|
||||
|
||||
SOGo uses LDAP directories to authenticate users. Use the following LDIF
|
||||
file (`jdoe.ldif`) as an example to create a SOGo user account:
|
||||
@@ -3222,8 +3220,8 @@ easier. These GUI utilities can make use of templates to create and
|
||||
pre-configure typical user accounts or any standardized LDAP record,
|
||||
along with the correct object classes, fields and default values.
|
||||
|
||||
Microsoft Enterprise ActiveSync
|
||||
-------------------------------
|
||||
|
||||
=== Microsoft Enterprise ActiveSync
|
||||
|
||||
SOGo supports the Microsoft ActiveSync protocol.
|
||||
|
||||
@@ -3359,8 +3357,8 @@ and send an email to iplicreq@microsoft.com
|
||||
Alinto provides this software for free, but is not responsible for
|
||||
anything related to its usage.
|
||||
|
||||
Microsoft Enterprise ActiveSync Tuning
|
||||
--------------------------------------
|
||||
|
||||
== Microsoft Enterprise ActiveSync Tuning
|
||||
|
||||
First of all, it is important to know that most EAS devices will keep
|
||||
HTTP connections open to SOGo (and thus, Apache) for a long time. This
|
||||
@@ -3435,8 +3433,8 @@ SOGoMaximumSyncInterval = 3540;
|
||||
SOGoInternalSyncInterval = 60;
|
||||
----
|
||||
|
||||
S/MIME Support in SOGo
|
||||
----------------------
|
||||
|
||||
== S/MIME Support in SOGo
|
||||
|
||||
SOGo supports S/MIME email signing and encryption. When receiving
|
||||
S/MIME signed emails, SOGo automatically extracts the PKCS (Public-Key
|
||||
@@ -3454,11 +3452,10 @@ please have a look at Actalis:
|
||||
https://www.actalis.it/products/certificates-for-secure-electronic-mail.aspx
|
||||
|
||||
|
||||
Using SOGo
|
||||
----------
|
||||
== Using SOGo
|
||||
|
||||
SOGo Web Interface
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== SOGo Web Interface
|
||||
|
||||
To acces the SOGo Web Interface, point your Web browser, which is
|
||||
running from the same server where SOGo was installed, to the following
|
||||
@@ -3467,8 +3464,8 @@ URL: http://127.0.0.1/SOGo.
|
||||
Log in using the "jdoe" user and the "qwerty" password. The underlying
|
||||
database tables will automatically be created by SOGo.
|
||||
|
||||
Mozilla Thunderbird and Lightning
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Mozilla Thunderbird and Lightning
|
||||
|
||||
Alternatively, you can access SOGo with a GroupDAV and a CalDAV client.
|
||||
A typical well-integrated setup is to use Mozilla Thunderbird and
|
||||
@@ -3510,8 +3507,8 @@ To access your personal calendar:
|
||||
`http://127.0.0.1/SOGo/dav/jdoe/Calendar/personal/`
|
||||
* Click on Continue.
|
||||
|
||||
Apple Calendar (macOS, iOS, iPadOS)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apple Calendar (macOS, iOS, iPadOS)
|
||||
|
||||
Apple Calendar on macOS, iOS, and iPadOS can also be used
|
||||
as a client application for SOGo.
|
||||
@@ -3529,8 +3526,8 @@ You have to add the profile to your device :
|
||||
* Go to Settings / Profiles / Click on + / Continue
|
||||
* Type your SOGo account password and click on install
|
||||
|
||||
Apple AddressBook
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Apple AddressBook
|
||||
|
||||
Since Mac OS X 10.6 (Snow Leopard), Apple AddressBook can be configured
|
||||
to use SOGo.
|
||||
@@ -3578,8 +3575,8 @@ You have to add the profile to your device :
|
||||
* Go to Settings / Profiles / Click on + / Continue
|
||||
* Type your SOGo account password and click on install
|
||||
|
||||
Microsoft ActiveSync
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== Microsoft ActiveSync
|
||||
|
||||
You can synchronize contacts, emails, events and tasks from SOGo with
|
||||
any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
|
||||
@@ -3588,8 +3585,9 @@ any mobile devices that support Microsoft ActiveSync. Microsoft Outlook
|
||||
The Microsoft ActiveSync server URL is generally something
|
||||
like: `http://127.0.0.1/Microsoft-Server-ActiveSync`.
|
||||
|
||||
Using sogo-tool
|
||||
---------------
|
||||
|
||||
== Using sogo-tool
|
||||
|
||||
The command _sogo-tool_ allows to do some operations on database and sieve filter. It is included with
|
||||
the sogo package on Debian/Ubuntu but must be installed manually on RHEl/CentOS:
|
||||
|
||||
@@ -3598,8 +3596,8 @@ the sogo package on Debian/Ubuntu but must be installed manually on RHEl/CentOS:
|
||||
*_WARNING_: Use sogo-tool with full awareness of what you are doing. This is an admin tool that can cause loss of data
|
||||
or completely make the webmail unusable by a user.*
|
||||
|
||||
sogo-tool backup/restore
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool backup/restore
|
||||
|
||||
The backup tool saves the information of a user into a file. The information saved are its preferences, its events and its contacts.
|
||||
|
||||
@@ -3680,8 +3678,8 @@ sogo-tool restore -F "Contacts/personal" tmp/backup user1
|
||||
sogo-tool restore -F "Calendar/60C8-65323D80-7-4D9F7D80" tmp/backup user1
|
||||
----
|
||||
|
||||
sogo-tool checkup
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool checkup
|
||||
|
||||
Check the events and contacts data's integrity of a user
|
||||
|
||||
@@ -3712,8 +3710,8 @@ sogo-tool checkup -d user1
|
||||
|
||||
[[sogo-tool-clean-openid-sessions]]
|
||||
|
||||
sogo-tool clean-openid-sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool clean-openid-sessions
|
||||
|
||||
Obviously only usefull if you have set SOGo with openId authentication.
|
||||
Will clean all expired openId sessions from the database.
|
||||
@@ -3725,8 +3723,8 @@ Example:
|
||||
sogo-tool clean-openid-sessions
|
||||
----
|
||||
|
||||
sogo-tool cleanup
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool cleanup
|
||||
|
||||
Will purge all user's deleted events and contacts which the deletion is older than a number of days.
|
||||
|
||||
@@ -3750,8 +3748,7 @@ Purged 5 records from folder /Users/user2/Calendar/personal
|
||||
----
|
||||
|
||||
|
||||
sogo-tool create-folder
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool create-folder
|
||||
|
||||
Create a folder (Calendar or Address Book) for a user.
|
||||
|
||||
@@ -3768,8 +3765,7 @@ sogo-tool create-folder user2 Calendar Pro_Calendar
|
||||
----
|
||||
|
||||
|
||||
sogo-tool dump-defaults
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool dump-defaults
|
||||
|
||||
Output all current defaults value of GNUstep and SOGo (sogo.conf)
|
||||
|
||||
@@ -3786,8 +3782,8 @@ sogo-tool dump-defaults all
|
||||
sogo-tool dump-defaults -f /tmp/foo/conf.xml
|
||||
----
|
||||
|
||||
sogo-tool expire-sessions
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool expire-sessions
|
||||
|
||||
Expires user sessions from database without activity for specified number of minutes. When a user log in to sogo for
|
||||
the first time, sogo will create a entry in database's table OCSSessionsFolderURL with the user's information. Sogo will
|
||||
@@ -3806,8 +3802,8 @@ sogo-tool expire-sessions 160 #Will remove session which last activity is ol
|
||||
sogo-tool expire-sessions 0 #Will remove session which last activity is older than 0 minutes.
|
||||
----
|
||||
|
||||
sogo-tool manage-acl
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool manage-acl
|
||||
|
||||
Manage access-control list (ACL) of a user for folders (Calendar and Address Book).
|
||||
|
||||
@@ -3878,8 +3874,8 @@ Example:
|
||||
sogo-tool manage-acl unsubscribe sogo-tests1 Contacts/5E1D-653FC400-1-1A330C40 sogo-tests2
|
||||
----
|
||||
|
||||
sogo-tool manage-eas
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool manage-eas
|
||||
|
||||
Manage EAS folders
|
||||
|
||||
@@ -3909,8 +3905,8 @@ sogo-tool manage-eas mergevcard janedow androidc316986417 YES
|
||||
sogo-tool manage-eas mergevevent janedow androidc316986417 YES
|
||||
----
|
||||
|
||||
sogo-tool remove
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool remove
|
||||
|
||||
Remove all folders (Calendar and Address Book) and Preference settings of a user. The personal Calendar and Address Book
|
||||
will stay but be emptied of all entries. The Preferences will go back to defaults values as for a new user.
|
||||
@@ -3934,8 +3930,8 @@ Deleting /Users/user2/Contacts/B087-65363400-7-374DA380
|
||||
Deleting /Users/user2/Contacts/personal
|
||||
----
|
||||
|
||||
sogo-tool remove-doubles
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool remove-doubles
|
||||
|
||||
remove duplicate contacts from the specified user addressbook
|
||||
|
||||
@@ -3960,8 +3956,8 @@ sogo-tool remove-doubles user1 personal
|
||||
sogo-tool remove-doubles user2 489-65376E80-1-2D2BA000
|
||||
----
|
||||
|
||||
sogo-tool rename-user
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool rename-user
|
||||
|
||||
Update records pertaining to a user after a change of user id. Will change all folders path, subscriptions from others users,
|
||||
all mention of user id in database.
|
||||
@@ -3979,8 +3975,8 @@ Example:
|
||||
sogo-tool rename-user old_username new_username
|
||||
----
|
||||
|
||||
sogo-tool truncate-calendar
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
=== sogo-tool truncate-calendar
|
||||
|
||||
Remove old calendar entries from the specified user calendar.
|
||||
|
||||
@@ -4010,8 +4006,7 @@ Removing 1 records...
|
||||
Removed 1 records.
|
||||
----
|
||||
|
||||
sogo-tool update-autoreply
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool update-autoreply
|
||||
|
||||
_This command is only useful if your sieve server doesn't have the capabilities *date* or *relational*_
|
||||
In that case this command will check vacation's setting of all the users. If vacation is enabled/disabled,
|
||||
@@ -4031,8 +4026,7 @@ Example:
|
||||
[[sogo-tool-update-secret]]
|
||||
|
||||
|
||||
sogo-tool update-secret
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool update-secret
|
||||
|
||||
_New in 5.10_
|
||||
|
||||
@@ -4058,8 +4052,7 @@ If your data are already encrypted with 'oldSecret' but you want to decrypt them
|
||||
sogo-tool update-secret -o oldSecret
|
||||
----
|
||||
|
||||
sogo-tool user-preferences
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=== sogo-tool user-preferences
|
||||
|
||||
Get, set or unset user defaults / settings in the database.
|
||||
|
||||
@@ -4118,9 +4111,153 @@ sogo-tool user-preferences set defaults user1 Forward -f /path/filename -p cred
|
||||
----
|
||||
|
||||
|
||||
== API REST
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
Starting from 5.12.2, an API with two endpoints is available.
|
||||
All response will be on json format. In case of errors, the message will be:
|
||||
```json
|
||||
{"error" : "message"}
|
||||
```
|
||||
with an explicit message
|
||||
|
||||
=== API server url
|
||||
|
||||
_<scheme>_://_<domain>_/SOGo/SOGoAPI/_<action>_
|
||||
|
||||
• *scheme* : https or http
|
||||
• *domain* : domain or ip:port of SOGo's server
|
||||
• *action* : name of the action. No action does the Version action described below.
|
||||
|
||||
=== Authentication
|
||||
|
||||
Somes actions needs to be authenticated. There is two ways to do so:
|
||||
|
||||
* *Basic auth*
|
||||
|
||||
Add a header *Auhtorization* with value:
|
||||
|
||||
'Basic <credentials>'
|
||||
|
||||
*credentials* is the sitrng '<uid>:<password>' base64 encoded.
|
||||
|
||||
* *OpenID*
|
||||
|
||||
**Only works if you configure sogo to use openid. See <<openid-section, the related section>>**
|
||||
|
||||
Add a header *Auhtorization* with value:
|
||||
|
||||
'Bearer <access_token>'
|
||||
|
||||
*acces_token* is from the https://connect2id.com/products/server/docs/api/token#url[openid protocol]. It has to be fetch with the scope `openid`.
|
||||
|
||||
=== Action - Version
|
||||
|
||||
* *URL*: <scheme>://<domain>/SOGo/SOGoAPI/Version
|
||||
* *Authentication needed*: NO
|
||||
* *HTTP method allowed*: GET
|
||||
* *Description*: Return the current version of sogo
|
||||
* *Answer structure*:
|
||||
```json
|
||||
{
|
||||
"major":5,
|
||||
"patch":1,
|
||||
"minor":12
|
||||
}
|
||||
```
|
||||
|
||||
=== Action - UserFolder
|
||||
|
||||
* *URL*: <scheme>://<domain>/SOGo/SOGoAPI/UserFolder
|
||||
* *Authentication needed*: YES
|
||||
* *HTTP method allowed*: GET
|
||||
* *Description*: Return the caldav and cardav links of the authenticated user, plus their names.
|
||||
* *Answer structure*:
|
||||
```json
|
||||
{
|
||||
"calendar":[
|
||||
{
|
||||
"name":"DidyShared",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/12509-67F67D00-1-3105AF40"
|
||||
},
|
||||
{
|
||||
"name":"LocalDidy",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/1BC38-67B60000-1-6E4B6880"
|
||||
},
|
||||
{
|
||||
"name":"Personal Calendar",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Calendar/personal"
|
||||
}
|
||||
],
|
||||
"username":"sogo-tests1@example.org",
|
||||
"contact":[
|
||||
{
|
||||
"name":"Personal Address Book",
|
||||
"url":"http://127.0.0.1/SOGo/dav/sogo-tests1@example.org/Contacts/personal"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
* *Note*:
|
||||
|
||||
The Answer has 3 primary keys:
|
||||
|
||||
** *username*: uid of the user.
|
||||
** *calendar*: array of calendar's folder info.
|
||||
** *contact*: array of calendar's folder info.
|
||||
|
||||
A folder info is a dict with:
|
||||
|
||||
** *name*: Name of the folder.
|
||||
** *url*: Dav link of the folder.
|
||||
|
||||
=== Errors and messages
|
||||
|
||||
Complete http response is `{“error:” : <message>}`.
|
||||
*<action>* is the one used for the request: `<scheme>://<domain>/SOGo/SOGoAPI/<action>`
|
||||
|
||||
[%header,cols="1,3,3"]
|
||||
|===
|
||||
|Status |Message |Description
|
||||
|
||||
|400
|
||||
|No backend API found for action: <action>
|
||||
|The requested action doesn't exist
|
||||
|
||||
|500
|
||||
|Can't alloc and init class: <classAction>
|
||||
|The requested action exist but failed to be instantiated. <classAction> is the class's name
|
||||
|
||||
|400
|
||||
|Method <method> not allowed for action <action>
|
||||
|Http method not allowed. <methos> is the one used (GET, PUT, POST...)
|
||||
|
||||
|400
|
||||
|Missing param <param> for action <action>
|
||||
|Required param for action not found. <param> is the name of the missing parameter.
|
||||
|
||||
|401
|
||||
|No authorization header found for <action>
|
||||
|No Authorization header found
|
||||
|
||||
|401
|
||||
|Authorization method incorrect: <auth> for action <action>
|
||||
|Value of Authorization's header doesn't start with Basic or Bearer. <auth> is the full value.
|
||||
|
||||
|401
|
||||
|User wrong login or not found for action <action>
|
||||
|Fail to authenticate the user. Various causes possible: wrong login, wrong password, expired token...
|
||||
|
||||
|500
|
||||
|Internal error during: <action>
|
||||
|Internal error during the action
|
||||
|===
|
||||
|
||||
|
||||
To have more logs you can add `SOGoAPIDebugEnabled = YES;` to your sogo.conf.
|
||||
|
||||
|
||||
|
||||
== Upgrading
|
||||
|
||||
This section describes what needs to be done when upgrading to the
|
||||
current version of SOGo from the previous release.
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
|
||||
////
|
||||
|
||||
Additional Information
|
||||
----------------------
|
||||
|
||||
== Additional Information
|
||||
|
||||
For more information, please consult the online FAQs (Frequently Asked
|
||||
Questions) :
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
////
|
||||
|
||||
Commercial Support and Contact Information
|
||||
------------------------------------------
|
||||
== Commercial Support and Contact Information
|
||||
|
||||
For any questions or comments, do not hesitate to contact us by writing
|
||||
an email to contact@sogo.nu.
|
||||
|
||||
@@ -9,6 +9,7 @@ SUBPROJECTS = \
|
||||
SoObjects \
|
||||
Main \
|
||||
UI \
|
||||
API \
|
||||
Tools \
|
||||
Tests/Unit \
|
||||
|
||||
|
||||
+8
-2
@@ -417,7 +417,7 @@ static BOOL debugLeaks;
|
||||
{
|
||||
id obj;
|
||||
WORequest *request;
|
||||
BOOL isDAVRequest;
|
||||
BOOL isDAVRequest, isAPIRequest;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
/* put locale info into the context in case it's not there */
|
||||
@@ -425,8 +425,14 @@ static BOOL debugLeaks;
|
||||
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
request = [_ctx request];
|
||||
isAPIRequest = [[request requestHandlerKey] isEqualToString:@"SOGoAPI"];
|
||||
isDAVRequest = [[request requestHandlerKey] isEqualToString:@"dav"];
|
||||
if (isDAVRequest || [sd isWebAccessEnabled])
|
||||
if(isAPIRequest && ![_key isEqualToString:@"SOGo"] && ![_key isEqualToString:@"SOGoAPI"])
|
||||
{
|
||||
//The request will be handle by the API Dispatcher
|
||||
obj = nil;
|
||||
}
|
||||
else if (isDAVRequest || [sd isWebAccessEnabled])
|
||||
{
|
||||
if (isDAVRequest)
|
||||
{
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path;
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_flag;
|
||||
- (NSArray *)listSubFoldersAndNamesAtPath:(NSString *)_path recursive:(BOOL)_recursive;
|
||||
|
||||
- (NSDictionary *) recordAtPath: (NSString *) _path;
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path;
|
||||
|
||||
@@ -598,6 +598,27 @@ static BOOL _singleStoreMode = NO;
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString *)generateSQLPathAndNameFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT c_path, c_foldername FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
if (debugSQLGen) [self logWithFormat:@"PathFetch-SQL: %@", sql];
|
||||
return sql;
|
||||
}
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (BOOL)_isStandardizedPath:(NSString *)_path {
|
||||
@@ -806,6 +827,72 @@ static BOOL _singleStoreMode = NO;
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSArray *)listSubFoldersAndNamesAtPath:(NSString *)_path recursive:(BOOL)_recursive{
|
||||
NSMutableArray *result;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathAndNameFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return emptyArray;
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
fname = [fname stringByAppendingString:@"/"]; /* add slash */
|
||||
for (i = 0; i < count; i++) {
|
||||
NSDictionary *record, *folderInfo;
|
||||
NSString *sname, *spath, *foldername;
|
||||
|
||||
record = [records objectAtIndex:i];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
if (![sname hasPrefix:fname]) /* does not match at all ... */
|
||||
continue;
|
||||
|
||||
/* strip prefix and following slash */
|
||||
sname = [sname substringFromIndex:[fname length]];
|
||||
spath = [self pathPartFromInternalName:sname];
|
||||
|
||||
if (_recursive) {
|
||||
if ([spath length] > 0){
|
||||
foldername = [record objectForKey: @"c_foldername"];
|
||||
folderInfo = [NSDictionary dictionaryWithObjectsAndKeys: spath, @"path", foldername, @"name", nil];
|
||||
[result addObject:folderInfo];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* direct children only, so exclude everything with a slash */
|
||||
if ([sname rangeOfString:@"/"].length == 0 && [spath length] > 0)
|
||||
{
|
||||
foldername = [record objectForKey: @"c_foldername"];
|
||||
folderInfo = [NSDictionary dictionaryWithObjectsAndKeys: spath, @"path", foldername, @"name", nil];
|
||||
[result addObject:folderInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSDictionary *) recordAtPath: (NSString *) _path
|
||||
{
|
||||
NSMutableString *sql;
|
||||
|
||||
@@ -303,8 +303,8 @@ static NSString *openIdFolderURLString = nil;
|
||||
newRecord = [NSDictionary dictionaryWithObjectsAndKeys: _user_session, @"c_user_session",
|
||||
_old_session, @"c_old_session",
|
||||
[NSNumber numberWithInt:now], @"c_session_started",
|
||||
_refresh_token, @"c_refresh_token",
|
||||
[NSNumber numberWithInt:nowExpire] , @"c_access_token_expires_in",
|
||||
_refresh_token, @"c_refresh_token",
|
||||
[NSNumber numberWithInt:nowRefreshExpire] , @"c_refresh_token_expires_in",
|
||||
nil];
|
||||
record = [self recordForSession: _user_session useOldSession: NO];
|
||||
|
||||
@@ -214,10 +214,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_user_session TEXT NOT NULL,"
|
||||
@" c_old_session TEXT NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_refresh_token TEXT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
@@ -274,7 +274,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR(4096) NOT NULL,"
|
||||
@" c_value TEXT NOT NULL,"
|
||||
@" c_creationdate INT4 NOT NULL,"
|
||||
@" c_lastseen INT4 NOT NULL)");
|
||||
|
||||
@@ -375,10 +375,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR(4096) NULL,"
|
||||
@" c_user_session TEXT NOT NULL,"
|
||||
@" c_old_session TEXT NULL,"
|
||||
@" c_session_started INT4 NOT NULL,"
|
||||
@" c_refresh_token VARCHAR(4096) NULL,"
|
||||
@" c_refresh_token TEXT NULL,"
|
||||
@" c_access_token_expires_in INT4 NULL,"
|
||||
@" c_refresh_token_expires_in INT4 NULL)");
|
||||
|
||||
@@ -435,7 +435,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR(4096) NOT NULL,"
|
||||
@" c_value TEXT NOT NULL,"
|
||||
@" c_creationdate INT NOT NULL,"
|
||||
@" c_lastseen INT NOT NULL)");
|
||||
|
||||
@@ -536,10 +536,10 @@
|
||||
{
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_user_session VARCHAR2(4096) NOT NULL,"
|
||||
@" c_old_session VARCHAR2(4096) NULL,"
|
||||
@" c_user_session VARCHAR2(8192) NOT NULL,"
|
||||
@" c_old_session VARCHAR2(8192) NULL,"
|
||||
@" c_session_started INTEGER NOT NULL,"
|
||||
@" c_refresh_token VARCHAR2(4096) NULL,"
|
||||
@" c_refresh_token VARCHAR2(8192) NULL,"
|
||||
@" c_access_token_expires_in INTEGER NULL,"
|
||||
@" c_refresh_token_expires_in INTEGER NULL)");
|
||||
|
||||
@@ -595,7 +595,7 @@
|
||||
static NSString *sqlFolderFormat
|
||||
= (@"CREATE TABLE %@ ("
|
||||
@" c_id VARCHAR2(255) PRIMARY KEY,"
|
||||
@" c_value VARCHAR2(4096) NOT NULL,"
|
||||
@" c_value VARCHAR2(8192) NOT NULL,"
|
||||
@" c_creationdate INTEGER NOT NULL,"
|
||||
@" c_lastseen INTEGER NOT NULL)");
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
iCalByDayMask *dayMask;
|
||||
long i, count, repeatCount;
|
||||
unsigned interval;
|
||||
@@ -63,6 +63,7 @@
|
||||
//[self logWithFormat: @"Recurrence rule is %@", rrule];
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
startDate = [_r startDate];
|
||||
endDate = [_r endDate];
|
||||
dayMask = nil;
|
||||
@@ -84,34 +85,41 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
NSCalendarDate *until, *lastDate;
|
||||
NSCalendarDate *until, *lastStartDate, *lastEndDate;
|
||||
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
if (until)
|
||||
{
|
||||
lastDate = until;
|
||||
lastStartDate = until;
|
||||
lastEndDate = until;
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatCount = [rrule repeatCount];
|
||||
if (dayMask == nil)
|
||||
{
|
||||
// If there's no day mask, we can compute the date of the last
|
||||
// occurrence of the recurrent rule.
|
||||
lastDate = [firStart dateByAddingYears: 0 months: 0
|
||||
lastStartDate = [firStart dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1))];
|
||||
lastEndDate = [firEnd dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1))];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil && lastEndDate != nil)
|
||||
{
|
||||
if ([lastDate compare: startDate] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: startDate] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
|
||||
if ([lastDate compare: endDate] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: endDate] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
endDate = lastDate;
|
||||
endDate = lastStartDate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,8 +86,13 @@
|
||||
tzId = [self value: 0 ofAttribute: @"tzid"];
|
||||
if ([tzId length])
|
||||
{
|
||||
calendar = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
|
||||
timeZone = [calendar timeZoneWithId: tzId];
|
||||
//Hack, get timezone inf from sogo and not from the event VTIMEZONE as it can be incorrect/incomplete
|
||||
timeZone = [iCalTimeZone timeZoneForName: tzId];
|
||||
if(!timeZone)
|
||||
{
|
||||
calendar = (iCalCalendar *) [self searchParentOfClass: [iCalCalendar class]];
|
||||
timeZone = [calendar timeZoneWithId: tzId];
|
||||
}
|
||||
//if (!timeZone)
|
||||
//[self logWithFormat: @"timezone '%@' not found in calendar", tzId];
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
// TODO: check whether this is OK for multiday-events!
|
||||
NSMutableArray *ranges;
|
||||
NSTimeZone *timeZone;
|
||||
NSCalendarDate *eventStartDate, *rStart, *rEnd, *until, *referenceDate;
|
||||
NSCalendarDate *eventStartDate, *eventEndDate, *rStart, *rEnd, *untilStart, *untilEnd, *referenceDate;
|
||||
int eventDayOfMonth;
|
||||
unsigned monthIdxInRange, numberOfMonthsInRange, interval, repeatCount;
|
||||
int diff, count;
|
||||
@@ -199,12 +199,14 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
iCalByDayMask *byDayMask;
|
||||
|
||||
eventStartDate = [firstRange startDate];
|
||||
eventEndDate = [firstRange endDate];
|
||||
eventDayOfMonth = [eventStartDate dayOfMonth];
|
||||
timeZone = [eventStartDate timeZone];
|
||||
rStart = [_r startDate];
|
||||
rEnd = [_r endDate];
|
||||
interval = [rrule repeatInterval];
|
||||
until = nil;
|
||||
untilStart = nil;
|
||||
untilEnd = nil;
|
||||
repeatCount = [rrule repeatCount];
|
||||
byMonth = [rrule byMonth];
|
||||
byMonthDay = [rrule byMonthDay];
|
||||
@@ -218,24 +220,28 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
{
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
until = [eventStartDate dateByAddingYears: 0
|
||||
untilStart = [eventStartDate dateByAddingYears: 0
|
||||
months: (interval * (repeatCount - 1))
|
||||
days: 0];
|
||||
untilEnd = [eventEndDate dateByAddingYears: 0
|
||||
months: (interval * (repeatCount - 1))
|
||||
days: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
until = [rrule untilDate];
|
||||
untilStart = [rrule untilDate];
|
||||
untilEnd = [rrule untilDate];
|
||||
}
|
||||
}
|
||||
|
||||
if (until != nil)
|
||||
if (untilStart != nil && untilEnd != nil)
|
||||
{
|
||||
if ([until compare: rStart] == NSOrderedAscending)
|
||||
if ([untilEnd compare: rStart] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([until compare: rEnd] == NSOrderedAscending)
|
||||
if ([untilStart compare: rEnd] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
rEnd = until;
|
||||
rEnd = untilStart;
|
||||
}
|
||||
|
||||
if (byMonth && [byMonth count] > 0)
|
||||
@@ -441,7 +447,7 @@ static inline unsigned iCalDoWForNSDoW (int dow)
|
||||
|
||||
start = [cursor dateByAddingYears: 0 months: 0 days: (dom - 1)];
|
||||
doCont = [self _addInstanceWithStartDate: start
|
||||
limitDate: until
|
||||
limitDate: untilStart
|
||||
limitRange: _r
|
||||
toArray: ranges];
|
||||
//NSLog(@"*** MONTHLY [%i/%i] adding %@%@ (count = %i)", dom, numDaysInMonth, start, (doCont?@"":@" .. NOT!"), count);
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
- (NSArray *) recurrenceRangesWithinCalendarDateRange: (NGCalendarDateRange *) _r
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSCalendarDate *firStart, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
NSCalendarDate *firStart, *firEnd, *startDate, *endDate, *currentStartDate, *currentEndDate;
|
||||
long i, repeatCount, count;
|
||||
unsigned interval;
|
||||
iCalByDayMask *dayMask;
|
||||
@@ -73,6 +73,7 @@
|
||||
//[self logWithFormat: @"Recurrence rule is %@", rrule];
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
startDate = [_r startDate];
|
||||
endDate = [_r endDate];
|
||||
dayMask = nil;
|
||||
@@ -95,31 +96,40 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
NSCalendarDate *until, *lastDate;
|
||||
NSCalendarDate *until, *lastStartDate, *lastEndDate;
|
||||
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
if (until)
|
||||
lastDate = until;
|
||||
{
|
||||
lastStartDate = until;
|
||||
lastEndDate = until;
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatCount = [rrule repeatCount];
|
||||
if (dayMask == nil)
|
||||
{
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
lastDate = [firStart dateByAddingYears: 0 months: 0
|
||||
lastStartDate = [firStart dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1) * 7)];
|
||||
lastEndDate = [firEnd dateByAddingYears: 0 months: 0
|
||||
days: (interval
|
||||
* (repeatCount - 1) * 7)];
|
||||
}
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil && lastEndDate != nil)
|
||||
{
|
||||
if ([lastDate compare: startDate] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: startDate] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([lastDate compare: endDate] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: endDate] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
endDate = [lastDate addTimeInterval: [firstRange duration]];
|
||||
endDate = [lastStartDate addTimeInterval: [firstRange duration]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,13 +44,14 @@
|
||||
{
|
||||
NSMutableArray *ranges;
|
||||
NSArray *byMonth;
|
||||
NSCalendarDate *firStart, *lastDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
|
||||
NSCalendarDate *firStart, *firEnd, *lastStartDate, *lastEndDate, *rStart, *rEnd, *until, *referenceDate, *rTemp;
|
||||
NSInteger *hoursOfOffset;
|
||||
iCalMonthlyRecurrenceCalculator *monthlyCalc;
|
||||
unsigned j, yearIdxInRange, numberOfYearsInRange, count, interval, monthDiff;
|
||||
int diff, repeatCount, currentMonth, origNbDaysInMonth;
|
||||
|
||||
firStart = [firstRange startDate];
|
||||
firEnd = [firstRange endDate];
|
||||
rStart = [_r startDate];
|
||||
rEnd = [_r endDate];
|
||||
interval = [rrule repeatInterval];
|
||||
@@ -71,33 +72,40 @@
|
||||
// If rule is bound, check the bounds
|
||||
if (![rrule isInfinite])
|
||||
{
|
||||
lastDate = nil;
|
||||
lastStartDate = nil;
|
||||
lastEndDate = nil;
|
||||
until = [rrule untilDate];
|
||||
repeatCount = [rrule repeatCount];
|
||||
|
||||
if (until)
|
||||
{
|
||||
lastDate = until;
|
||||
lastStartDate = until;
|
||||
lastEndDate = until;
|
||||
}
|
||||
if (repeatCount > 0)
|
||||
{
|
||||
if (lastDate == nil && ![rrule hasByMask])
|
||||
if (lastStartDate == nil && ![rrule hasByMask])
|
||||
{
|
||||
// When there's no BYxxx mask, we can find the date of the last
|
||||
// occurrence.
|
||||
lastDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
|
||||
lastStartDate = [firStart dateByAddingYears: (interval * (repeatCount - 1))
|
||||
months: 0
|
||||
days: 0];
|
||||
lastEndDate = [firEnd dateByAddingYears: (interval * (repeatCount - 1))
|
||||
months: 0
|
||||
days: 0];
|
||||
}
|
||||
referenceDate = firStart;
|
||||
}
|
||||
|
||||
if (lastDate != nil)
|
||||
if (lastStartDate != nil)
|
||||
{
|
||||
if ([lastDate compare: rStart] == NSOrderedAscending)
|
||||
if ([lastEndDate compare: rStart] == NSOrderedAscending)
|
||||
// Range starts after last occurrence
|
||||
return nil;
|
||||
if ([lastDate compare: rEnd] == NSOrderedAscending)
|
||||
if ([lastStartDate compare: rEnd] == NSOrderedAscending)
|
||||
// Range ends after last occurence; adjust end date
|
||||
rEnd = [lastDate addTimeInterval: [firstRange duration]];
|
||||
rEnd = [lastStartDate addTimeInterval: [firstRange duration]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ CREATE TABLE sogo_quick_contact (
|
||||
|
||||
CREATE TABLE sogo_sessions_folder (
|
||||
c_id varchar(255) NOT NULL,
|
||||
c_value varchar(4096) NOT NULL,
|
||||
c_value text NOT NULL,
|
||||
c_creationdate int(11) NOT NULL,
|
||||
c_lastseen int(11) NOT NULL,
|
||||
PRIMARY KEY (c_id)
|
||||
@@ -166,10 +166,10 @@ CREATE TABLE sogo_admin (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE sogo_opend_id (
|
||||
c_user_session varchar(4096) NOT NULL,
|
||||
c_old_session varchar(4096) DEFAULT '',
|
||||
c_user_session text NOT NULL,
|
||||
c_old_session text DEFAULT '',
|
||||
c_session_started int(11) NOT NULL,
|
||||
c_refresh_token varchar(4096) DEFAULT '',
|
||||
c_refresh_token text DEFAULT '',
|
||||
c_access_token_expires_in int(11) DEFAULT '',
|
||||
c_refresh_token_expires_in int(11) DEFAULT NULL,
|
||||
PRIMARY KEY (c_user_session)
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
"Inviting the following persons is prohibited:" = "다음 사람들을 초대하는 것은 금지되어 있습니다:";
|
||||
"Personal Calendar" = "개인 캘린더";
|
||||
vevent_class0 = "(공개 이벤트)";
|
||||
vevent_class1 = "(비공개 이벤트)";
|
||||
vevent_class2 = "(기밀 이벤트)";
|
||||
|
||||
vtodo_class0 = "(공개 할 일)";
|
||||
vtodo_class1 = "(비공개 할 일)";
|
||||
vtodo_class2 = "(기밀 할 일)";
|
||||
|
||||
/* Receipts */
|
||||
"The event \"%{Summary}\" was created" = "이벤트 \"%{Summary}\"가 생성되었습니다";
|
||||
"The event \"%{Summary}\" was deleted" = "이벤트 \"%{Summary}\"가 삭제되었습니다";
|
||||
"The event \"%{Summary}\" was updated" = "이벤트 \"%{Summary}\"가 업데이트되었습니다";
|
||||
"The task \"%{Summary}\" was created" = "할 일 \"%{Summary}\"이 생성되었습니다";
|
||||
"The task \"%{Summary}\" was deleted" = "할 일 \"%{Summary}\"이 삭제되었습니다";
|
||||
"The task \"%{Summary}\" was updated" = "할 일 \"%{Summary}\"이 업데이트되었습니다";
|
||||
"The following attendees(s) were notified" = "다음 참석자에게 알림이 전송되었습니다";
|
||||
"The following attendees(s) were added" = "다음 참석자가 추가되었습니다";
|
||||
"The following attendees(s) were removed" = "다음 참석자가 제거되었습니다";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "캘린더";
|
||||
"startDate_label" = "시작";
|
||||
"endDate_label" = "종료";
|
||||
"time_label" = "시간";
|
||||
"to_label" = "까지";
|
||||
"due_label" = "마감일";
|
||||
"location_label" = "장소";
|
||||
"summary_label" = "요약";
|
||||
"comment_label" = "설명";
|
||||
"organizer_label" = "주최자";
|
||||
"attendee_label" = "참석자";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "이벤트 초대: \"%{Summary}\"";
|
||||
"(sent by %{SentBy}) " = "(%{SentBy}님이 보냄) ";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}님이 %{Summary}에 초대했습니다.\n\n시작: %{StartDate}\n종료: %{EndDate}\n설명: %{Description}";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}님이 %{Summary}에 초대했습니다.\n\n시작: %{StartDate} %{StartTime}\n종료: %{EndDate} %{EndTime}\n설명: %{Description}";
|
||||
|
||||
/* Deletion */
|
||||
"Event Cancelled: \"%{Summary}\"" = "이벤트 취소됨: \"%{Summary}\"";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}님이 이 이벤트를 취소했습니다: %{Summary}.\n\n시작: %{StartDate}\n종료: %{EndDate}\n설명: %{Description}";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}님이 이 이벤트를 취소했습니다: %{Summary}.\n\n시작: %{StartDate} %{StartTime}\n종료: %{EndDate} %{EndTime}\n설명: %{Description}";
|
||||
|
||||
/* Update */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
= "%{OldStartDate}에 예정된 약속 \"%{Summary}\"이 변경되었습니다";
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||
= "%{OldStartDate} %{OldStartTime}에 예정된 약속 \"%{Summary}\"이 변경되었습니다";
|
||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||
= "모임 \"%{Summary}\"에서 다음 매개변수가 변경되었습니다:";
|
||||
"Please accept or decline those changes."
|
||||
= "이 변경 사항을 수락하거나 거절하십시오.";
|
||||
|
||||
/* Reply */
|
||||
"Accepted invitation: \"%{Summary}\"" = "초대 수락: \"%{Summary}\"";
|
||||
"Declined invitation: \"%{Summary}\"" = "초대 거절: \"%{Summary}\"";
|
||||
"Delegated invitation: \"%{Summary}\"" = "초대 위임: \"%{Summary}\"";
|
||||
"Not yet decided on invitation: \"%{Summary}\"" = "초대에 대해 아직 결정하지 않음: \"%{Summary}\"";
|
||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||
= "%{Attendee} %{SentByText}님이 귀하의 이벤트 초대를 수락했습니다.";
|
||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||
= "%{Attendee} %{SentByText}님이 귀하의 이벤트 초대를 거절했습니다.";
|
||||
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||
= "%{Attendee} %{SentByText}님이 %{Delegate}에게 초대를 위임했습니다.";
|
||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||
= "%{Attendee} %{SentByText}님이 귀하의 이벤트 초대에 대해 아직 결정하지 않았습니다.";
|
||||
|
||||
/* Reminder */
|
||||
"Reminder: \"%{Summary}\" - %{StartDate}" = "알림: \"%{Summary}\" - %{StartDate}";
|
||||
|
||||
/* Resources */
|
||||
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "리소스에 접근할 수 없습니다: \"%{Cn} %{SystemEmail}\"";
|
||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "리소스 \"%{Cn} %{SystemEmail}\"에 대한 최대 동시 예약 수(%{NumberOfSimultaneousBookings})에 도달했습니다. 충돌하는 이벤트는 \"%{EventTitle}\"이며, %{StartDate}에 시작합니다.";
|
||||
|
||||
/* Participation role */
|
||||
"Your participation is required to this event" = "이 이벤트에 귀하의 참여가 필수입니다";
|
||||
"Your participation is optional to this event" = "이 이벤트에 귀하의 참여는 선택 사항입니다";
|
||||
"Your participation is not required to this event" = "이 이벤트에 귀하의 참여는 필요하지 않습니다";
|
||||
@@ -1133,8 +1133,8 @@ firstInstanceCalendarDateRange: (NGCalendarDateRange *) fir
|
||||
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId inArray: ma];
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex == -1) {
|
||||
[self warnWithFormat:
|
||||
@"missing exception record for recurrence-id %@ (uid %@), ma = %@, dr = %@, rir = %@",
|
||||
recurrenceId, [component uid], ma, dateRange, recurrenceIdRange];
|
||||
@"missing exception record for recurrence-id %@ (uid %@), dr = %@, rir = %@",
|
||||
recurrenceId, [component uid], dateRange, recurrenceIdRange];
|
||||
}
|
||||
if ([dateRange doesIntersectWithDateRange: recurrenceIdRange] && recordIndex != -1)
|
||||
{
|
||||
|
||||
@@ -65,6 +65,9 @@
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
#import "SOGoCalendarComponent.h"
|
||||
|
||||
|
||||
static NSArray *allowed_tags = nil;
|
||||
|
||||
@implementation SOGoCalendarComponent
|
||||
|
||||
+ (SOGoWebDAVAclManager *) webdavAclManager
|
||||
@@ -210,7 +213,6 @@
|
||||
SOGoUser *calendarOwner;
|
||||
NSEnumerator *children;
|
||||
CardElement *element;
|
||||
NSArray *tags;
|
||||
|
||||
int classification;
|
||||
|
||||
@@ -231,22 +233,25 @@
|
||||
summary = [self labelForKey: [NSString stringWithFormat: @"%@_class%d",
|
||||
type, classification]
|
||||
inContext: context];
|
||||
|
||||
tags = [NSArray arrayWithObjects: @"DTSTAMP", @"DTSTART", @"DTEND", @"DUE", @"EXDATE", @"EXRULE", @"RRULE", @"RECURRENCE-ID", nil];
|
||||
if(!allowed_tags)
|
||||
allowed_tags = [[NSArray arrayWithObjects: @"DTSTAMP", @"DTSTART", @"DTEND", @"DUE", @"EXDATE", @"EXRULE", @"RRULE", @"RECURRENCE-ID", nil] retain];
|
||||
uid = [[component uid] asCryptedPassUsingScheme: @"ssha256"
|
||||
withSalt: [[settings userPublicSalt] dataUsingEncoding: NSASCIIStringEncoding]
|
||||
andEncoding: encHex
|
||||
keyPath: nil];
|
||||
|
||||
children = [[[[component children] copy] autorelease] objectEnumerator];
|
||||
|
||||
children = [[component children] objectEnumerator];
|
||||
NSMutableArray *to_remove = [NSMutableArray arrayWithCapacity: 8];
|
||||
|
||||
while ((element = [children nextObject]))
|
||||
{
|
||||
tag = [element tag];
|
||||
if (![tags containsObject: [tag uppercaseString]])
|
||||
[component removeChild: element];
|
||||
if (![allowed_tags containsObject: [tag uppercaseString]])
|
||||
[to_remove addObject: element];
|
||||
}
|
||||
|
||||
[component removeChildren: to_remove];
|
||||
|
||||
[component setSummary: summary];
|
||||
[component setUid: uid];
|
||||
}
|
||||
@@ -885,7 +890,7 @@
|
||||
mailDate = [[NSCalendarDate date] rfc822DateString];
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: subject forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: senderEmail] forKey: @"message-id"];
|
||||
if ([msgType length] > 0)
|
||||
[headerMap setObject: msgType forKey: @"x-sogo-message-type"];
|
||||
msg = [NGMimeMessage messageWithHeader: headerMap];
|
||||
@@ -974,7 +979,7 @@
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: [[p getSubject] asQPSubjectString: @"UTF-8"]
|
||||
forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: [[attendee mailAddress] pureEMailAddress]] forKey: @"message-id"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
|
||||
if (textOnly)
|
||||
@@ -1163,7 +1168,7 @@
|
||||
mailDate = [[NSCalendarDate date] rfc822DateString];
|
||||
[headerMap setObject: mailDate forKey: @"date"];
|
||||
[headerMap setObject: [page getSubject] forKey: @"subject"];
|
||||
[headerMap setObject: [NSString generateMessageID] forKey: @"message-id"];
|
||||
[headerMap setObject: [NSString generateMessageID: senderEmail] forKey: @"message-id"];
|
||||
[headerMap setObject: @"1.0" forKey: @"MIME-Version"];
|
||||
[headerMap setObject: @"text/html; charset=utf-8"
|
||||
forKey: @"content-type"];
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
"Inviting the following persons is prohibited:" = " ไม่เชิญบุคคลต่อไปนี้:";
|
||||
"Personal Calendar" = "ปฏิทินส่วนตัว";
|
||||
vevent_class0 = "(กิจกรรมสาธารณะ)";
|
||||
vevent_class1 = "(กิจกรรมส่วนตัว)";
|
||||
vevent_class2 = "(กิจกรรมลับ)";
|
||||
|
||||
vtodo_class0 = "(งานสาธารณะ)";
|
||||
vtodo_class1 = "(งานส่วนตัว)";
|
||||
vtodo_class2 = "(งานลับ)";
|
||||
|
||||
/* Receipts */
|
||||
"The event \"%{Summary}\" was created" = "กิจกรรม \"%{Summary}\" ถุกสร้างขึ้น";
|
||||
"The event \"%{Summary}\" was deleted" = "กิจกรรม \"%{Summary}\" ถูกลบ";
|
||||
"The event \"%{Summary}\" was updated" = "กิจกรรม \"%{Summary}\" ถูกอัพเดต";
|
||||
"The task \"%{Summary}\" was created" = "งาน \"%{Summary}\" ถูกสร้างขี้น";
|
||||
"The task \"%{Summary}\" was deleted" = "งาน \"%{Summary}\" ถูกลบ";
|
||||
"The task \"%{Summary}\" was updated" = "งาน \"%{Summary}\" ถูกอัพเดต";
|
||||
"The following attendees(s) were notified" = "แจ้งผู้เข้าร่วมดังต่อไปนี้";
|
||||
"The following attendees(s) were added" = "ผู้เข้าร่วมต่อไปนี้ถูกเพิ่มเข้ามา";
|
||||
"The following attendees(s) were removed" = "ผู้เข้าร่วมต่อไปนี้ถูกลบออก";
|
||||
|
||||
/* IMIP messages */
|
||||
"calendar_label" = "ปฏิทิน";
|
||||
"startDate_label" = "เริ่ม";
|
||||
"endDate_label" = "สิ้นสุด";
|
||||
"time_label" = "เวลา";
|
||||
"to_label" = "ถึง";
|
||||
"due_label" = "วันครบกำหนด";
|
||||
"location_label" = "สถานที่";
|
||||
"summary_label" = "สรุป";
|
||||
"comment_label" = "ความคิดเห็น";
|
||||
"organizer_label" = "ผู้จัดงาน";
|
||||
"attendee_label" = "ผู้เข้าร่วม";
|
||||
|
||||
/* Invitation */
|
||||
"Event Invitation: \"%{Summary}\"" = "คำเชิญร่วมกิจกรรม : \"%{Summary}\"";
|
||||
"(sent by %{SentBy}) " = "(ส่งโดย %{SentBy}) ";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}" = "%{Organizer} %{SentByText}ได้ทําการเชิญคุณไป %{Summary}.\n\nเริ่ม: %{StartDate}\nสิ้นสุด: %{EndDate}\nคำอธิบาย: %{Description}";
|
||||
"%{Organizer} %{SentByText}has invited you to %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}" = "%{Organizer} %{SentByText}ได้ทําการเชิญคุณไป %{Summary}.\n\nเริ่ม: %{StartDate} เวลา %{StartTime}\nสิ้นสุด: %{EndDate} เวลา %{EndTime}\nคำอธิบาย: %{Description}";
|
||||
|
||||
/* Deletion */
|
||||
"Event Cancelled: \"%{Summary}\"" = "กิจกรรมถูกยกเลิกแล้ว: \"%{Summary}\"";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate}\nEnd: %{EndDate}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}:ได้ยกเลิกกิจกรรม %{Summary}.\n\nเริ่ม: %{StartDate}\nสิ้นสุด: %{EndDate}\nคำอธิบาย: %{Description}";
|
||||
"%{Organizer} %{SentByText}has cancelled this event: %{Summary}.\n\nStart: %{StartDate} at %{StartTime}\nEnd: %{EndDate} at %{EndTime}\nDescription: %{Description}"
|
||||
= "%{Organizer} %{SentByText}hasได้ยกเลิกกิจกรรม: %{Summary}.\n\nเริ่ม: %{StartDate} เวลา %{StartTime}\nสิ้นสุด: %{EndDate} เวลา %{EndTime}\nคำอธิบาย: %{Description}";
|
||||
|
||||
/* Update */
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} has changed"
|
||||
= "นัดหมาย \"%{Summary}\" สำหรับวันที่ %{OldStartDate} มีการเปลี่ยนแปลง";
|
||||
"The appointment \"%{Summary}\" for the %{OldStartDate} at %{OldStartTime} has changed"
|
||||
= "นัดหมาย \"%{Summary}\" สำหรับวันที่ %{OldStartDate} เวลา %{OldStartTime} มีการเปลี่ยนแปลง";
|
||||
"The following parameters have changed in the \"%{Summary}\" meeting:"
|
||||
= "มีการเปลี่ยนแปลงใน \"%{Summary}\" :";
|
||||
"Please accept or decline those changes."
|
||||
= "กรุณาตอบรับหรือปฏิเสธการเปลี่ยนแปลงเหล่านั้น";
|
||||
|
||||
/* Reply */
|
||||
"Accepted invitation: \"%{Summary}\"" = "ตอบรับคำเชิญ: \"%{Summary}\"";
|
||||
"Declined invitation: \"%{Summary}\"" = "ปฏิเสธคำเชิญ: \"%{Summary}\"";
|
||||
"Delegated invitation: \"%{Summary}\"" = "ลบคำเชิญ: \"%{Summary}\"";
|
||||
"Not yet decided on invitation: \"%{Summary}\"" = "ยังไม่ตัดสินใจเกี่ยวกับคำเชิญ: \"%{Summary}\"";
|
||||
"%{Attendee} %{SentByText}has accepted your event invitation."
|
||||
= "%{Attendee} %{SentByText} ได้ตอบรับคำเชิญกิจกรรมของคุณแล้ว";
|
||||
"%{Attendee} %{SentByText}has declined your event invitation."
|
||||
= "%{Attendee} %{SentByText} ได้ตอบปฏิเสธคำเชิญกิจกรรมของคุณแล้ว";
|
||||
"%{Attendee} %{SentByText}has delegated the invitation to %{Delegate}."
|
||||
= "%{Attendee} %{SentByText}ได้มอบหมายการเชิญให้ %{Delegate}.";
|
||||
"%{Attendee} %{SentByText}has not yet decided upon your event invitation."
|
||||
= "%{Attendee} %{SentByText}ยังไม่ได้ตัดสินใจเกี่ยวกับคำเชิญงานของคุณ";
|
||||
|
||||
/* Reminder */
|
||||
"Reminder: \"%{Summary}\" - %{StartDate}" = "สิ่งเตือนความจำ: \"%{Summary}\" - %{StartDate}";
|
||||
|
||||
/* Resources */
|
||||
"Cannot access resource: \"%{Cn} %{SystemEmail}\"" = "ไม่สามารถเข้าถึงทรัพยากรได้: \"%{Cn} %{SystemEmail}\"";
|
||||
"Maximum number of simultaneous bookings (%{NumberOfSimultaneousBookings}) reached for resource \"%{Cn} %{SystemEmail}\". The conflicting event is \"%{EventTitle}\", and starts on %{StartDate}." = "จำนวนการจองสูงสุดพร้อมกัน (%{NumberOfSimultaneousBookings}) ขอใช้ทรัพยากร \"%{Cn} %{SystemEmail}\". งานที่ขัดแย้งกัน \"%{EventTitle}\", and starts on %{StartDate}.";
|
||||
|
||||
/* Participation role */
|
||||
"Your participation is required to this event" = "การเข้าร่วมของคุณจำเป็นสำหรับกิจกรรมนี้";
|
||||
"Your participation is optional to this event" = " การเข้าร่วมกิจกรรมนี้ไม่จำเป็น";
|
||||
"Your participation is not required to this event" = " การเข้าร่วมของคุณไม่จำเป็นสำหรับกิจกรรมนี้";
|
||||
@@ -107,6 +107,7 @@
|
||||
BOOL isAllDayStartDate, isAllDayDueDate;
|
||||
NSCalendarDate *startDate, *dueDate, *completedDate;
|
||||
NSInteger percent;
|
||||
NSString *owner;
|
||||
SOGoUserDefaults *ud;
|
||||
iCalDateTime *todoStartDate, *todoDueDate;
|
||||
iCalTimeZone *tz;
|
||||
@@ -230,6 +231,15 @@
|
||||
}
|
||||
else
|
||||
[self setPercentComplete: @""];
|
||||
|
||||
//To make an ics conforme with outlook live (bouh), valarm must be the last element of vevent
|
||||
//Try to set it here
|
||||
o = [data objectForKey: @"alarm"];
|
||||
if ([o isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
owner = [data objectForKey: @"owner"];
|
||||
[self _setAlarm: o forOwner: owner];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) quickRecordFromContent: (NSString *) theContent
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
"Personal Address Book" = "개인 주소록";
|
||||
"Collected Address Book" = "받은/보낸 주소록";
|
||||
@@ -0,0 +1,2 @@
|
||||
"Personal Address Book" = "สมุดที่อยู่ส่วนตัว";
|
||||
"Collected Address Book" = "สมุดที่อยู่ที่เก็บรวบรวม";
|
||||
@@ -94,6 +94,8 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailJapaneseReply.wo \
|
||||
SOGoMailKazakhForward.wo \
|
||||
SOGoMailKazakhReply.wo \
|
||||
SOGoMailKoreanForward.wo \
|
||||
SOGoMailKoreanReply.wo \
|
||||
SOGoMailLatvianForward.wo \
|
||||
SOGoMailLatvianReply.wo \
|
||||
SOGoMailLithuanianForward.wo \
|
||||
@@ -128,6 +130,8 @@ Mailer_RESOURCE_FILES += \
|
||||
SOGoMailSpanishArgentinaReply.wo \
|
||||
SOGoMailSwedishForward.wo \
|
||||
SOGoMailSwedishReply.wo \
|
||||
SOGoMailThaiForward.wo \
|
||||
SOGoMailThaiReply.wo \
|
||||
SOGoMailTurkishTurkeyForward.wo \
|
||||
SOGoMailTurkishTurkeyReply.wo \
|
||||
SOGoMailUkrainianForward.wo \
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
"OtherUsersFolderName" = "다른 사용자";
|
||||
"SharedFoldersName" = "공유 폴더";
|
||||
|
||||
"Report: Marked messages as junk" = "보고서: 스팸으로 표시된 메시지";
|
||||
"Report: Marked messages as not junk" = "보고서: 스팸이 아닌 것으로 표시된 메시지";
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
@interface NSString (SOGoExtension)
|
||||
|
||||
+ (NSString *) generateMessageID;
|
||||
+ (NSString *) generateMessageID: (NSString *) mailOrDomain;
|
||||
- (NSString *) htmlToText;
|
||||
- (NSString *) htmlByExtractingImages: (NSMutableArray *) theImages;
|
||||
- (NSString *) stringByConvertingCRLNToHTML;
|
||||
|
||||
@@ -560,15 +560,27 @@
|
||||
|
||||
@implementation NSString (SOGoExtension)
|
||||
|
||||
+ (NSString *) generateMessageID
|
||||
+ (NSString *) generateMessageID: (NSString *) mailOrDomain
|
||||
{
|
||||
NSMutableString *messageID;
|
||||
NSString *pGUID;
|
||||
NSString *_domain;
|
||||
NSRange r;
|
||||
|
||||
messageID = [NSMutableString string];
|
||||
[messageID appendFormat: @"<%@", [SOGoObject globallyUniqueObjectId]];
|
||||
pGUID = [[NSProcessInfo processInfo] globallyUniqueString];
|
||||
[messageID appendFormat: @"@%u>", (unsigned int)[pGUID hash]];
|
||||
[messageID appendFormat: @"<%@", [SOGoObject mailUniqueMessageId]];
|
||||
if(mailOrDomain)
|
||||
{
|
||||
r = [mailOrDomain rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
//Its the full email not a domain
|
||||
_domain = [mailOrDomain substringFromIndex: (r.location + r.length)];
|
||||
}
|
||||
else
|
||||
_domain = mailOrDomain;
|
||||
[messageID appendFormat: @"@%@>", _domain];
|
||||
}
|
||||
|
||||
|
||||
return [messageID lowercaseString];
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ static NSString *userAgent = nil;
|
||||
messageID = [headers objectForKey: @"message-id"];
|
||||
if (!messageID)
|
||||
{
|
||||
messageID = [NSString generateMessageID];
|
||||
messageID = [NSString generateMessageID: [[newHeaders objectForKey: @"from"] pureEMailAddress]];
|
||||
[headers setObject: messageID forKey: @"message-id"];
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,10 @@
|
||||
else
|
||||
imapAuthMech = nil;
|
||||
|
||||
//If ActiveSync, force the plain mech
|
||||
if([[[[self context] request] requestHandlerKey] isEqualToString:@"Microsoft-Server-ActiveSync"])
|
||||
imapAuthMech = @"plain";
|
||||
|
||||
return [NGImap4ConnectionManager defaultConnectionManager: imapAuthMech];
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,9 @@
|
||||
@interface SOGoMailKazakhForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailKoreanForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailLatvianForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@@ -163,6 +166,9 @@
|
||||
@interface SOGoMailSwedishForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailThaiForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
@interface SOGoMailTurkishTurkeyForward : SOGoMailForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -366,6 +366,9 @@
|
||||
@implementation SOGoMailKazakhForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailKoreanForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailLatvianForward
|
||||
@end
|
||||
|
||||
@@ -417,6 +420,9 @@
|
||||
@implementation SOGoMailSwedishForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailThaiForward
|
||||
@end
|
||||
|
||||
@implementation SOGoMailTurkishTurkeyForward
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<#newLine/><#newLine
|
||||
/><#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop
|
||||
>-------- 원본 메시지 --------<#newLine
|
||||
/>제목: <#subject/><#newLine
|
||||
/>날짜: <#date/><#newLine
|
||||
/>보낸 사람: <#from/><#newLine
|
||||
/><#hasReplyTo>회신: <#replyTo/><#newLine/></#hasReplyTo>
|
||||
<#hasOrganization>조직: <#organization/><#newLine/></#hasOrganization>
|
||||
받는 사람: <#to/>
|
||||
<#hasCc>참조: <#cc/><#newLine/></#hasCc>
|
||||
<#hasNewsGroups>뉴스그룹: <#newsgroups/><#newLine/></#hasNewsGroups>
|
||||
<#hasReferences>참조: <#references/><#newLine/></#hasReferences>
|
||||
<#newLine/><#newLine
|
||||
/><#messageBody
|
||||
/><#signaturePlacementOnBottom><#newLine/><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,88 @@
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<#replyPlacementOnTop><#newLine/><#newLine/></#replyPlacementOnTop>
|
||||
<#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop>
|
||||
<#outlookMode>
|
||||
-------- 원본 메시지 --------
|
||||
제목: <#subject/><#newLine/>
|
||||
날짜: <#date/><#newLine/>
|
||||
보낸 사람: <#from/><#newLine/>
|
||||
<#hasReplyTo>회신: <#replyTo/><#newLine/></#hasReplyTo>
|
||||
<#hasOrganization>조직: <#organization/><#newLine/></#hasOrganization>
|
||||
받는 사람: <#to/><#newLine/>
|
||||
<#hasCc>참조: <#cc/><#newLine/></#hasCc>
|
||||
<#hasNewsGroups>뉴스그룹: <#newsgroups/><#newLine/></#hasNewsGroups>
|
||||
<#hasReferences>참조: <#references/><#newLine/></#hasReferences>
|
||||
</#outlookMode>
|
||||
<#standardMode>
|
||||
<#date/>에 <#from/>(이)가 작성했습니다:
|
||||
</#standardMode>
|
||||
<#newLine/><#newLine/><#messageBody/>
|
||||
<#replyPlacementOnBottom><#newLine/><#newLine/></#replyPlacementOnBottom>
|
||||
<#signaturePlacementOnBottom><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,106 @@
|
||||
outlookMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
}
|
||||
|
||||
standardMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
replyPlacementOnTop: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
}
|
||||
|
||||
replyPlacementOnBottom: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -108,6 +108,9 @@
|
||||
@interface SOGoMailJapaneseReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailKoreanReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailKazakhReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@@ -162,6 +165,9 @@
|
||||
@interface SOGoMailSwedishReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailThaiReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
@interface SOGoMailTurkishTurkeyReply : SOGoMailReply
|
||||
@end
|
||||
|
||||
|
||||
@@ -167,6 +167,9 @@
|
||||
@implementation SOGoMailKazakhReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailKoreanReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailLatvianReply
|
||||
@end
|
||||
|
||||
@@ -218,6 +221,9 @@
|
||||
@implementation SOGoMailSwedishReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailThaiReply
|
||||
@end
|
||||
|
||||
@implementation SOGoMailTurkishTurkeyReply
|
||||
@end
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<#newLine/><#newLine
|
||||
/><#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop
|
||||
>-------- ข้อความต้นทาง --------<#newLine
|
||||
/>หัวข้อ: <#subject/><#newLine
|
||||
/>วันที่: <#date/><#newLine
|
||||
/>จาก: <#from/><#newLine
|
||||
/><#hasReplyTo>ตอบกลับ: <#replyTo/><#newLine/></#hasReplyTo
|
||||
><#hasOrganization>องค์กร: <#organization/><#newLine/></#hasOrganization
|
||||
>ถึง: <#to/><#newLine
|
||||
/><#hasCc>สำเนา: <#cc/><#newLine/></#hasCc
|
||||
><#hasNewsGroups>กลุ่มข่าว: <#newsgroups/><#newLine/></#hasNewsGroups
|
||||
><#hasReferences>การอ้างถึง: <#references/><#newLine/></#hasReferences
|
||||
><#newLine/><#newLine
|
||||
/><#messageBody
|
||||
/><#signaturePlacementOnBottom><#newLine/><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,88 @@
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<#replyPlacementOnTop><#newLine/><#newLine/></#replyPlacementOnTop
|
||||
><#signaturePlacementOnTop><#signature/><#newLine/><#newLine/></#signaturePlacementOnTop
|
||||
><#outlookMode
|
||||
>-------- ข้อความต้นทาง --------<#newLine
|
||||
/>หัวข้อ: <#subject/><#newLine
|
||||
/>วันที่: <#date/><#newLine
|
||||
/>จาก: <#from/><#newLine
|
||||
/><#hasReplyTo>ตอบกลับ: <#replyTo/><#newLine/></#hasReplyTo
|
||||
><#hasOrganization>องค์กร: <#organization/><#newLine/></#hasOrganization
|
||||
>ถึง: <#to/><#newLine
|
||||
/><#hasCc>สำเนา: <#cc/><#newLine/></#hasCc
|
||||
><#hasNewsGroups>กลุ่มข่าว: <#newsgroups/><#newLine/></#hasNewsGroups
|
||||
><#hasReferences>การอ้างถึง: <#references/><#newLine/></#hasReferences
|
||||
></#outlookMode
|
||||
><#standardMode>บน <#date/>, <#from/> ขียน:</#standardMode
|
||||
><#newLine/><#newLine/><#messageBody
|
||||
/><#replyPlacementOnBottom><#newLine/><#newLine/></#replyPlacementOnBottom
|
||||
><#signaturePlacementOnBottom><#newLine/><#signature/></#signaturePlacementOnBottom>
|
||||
@@ -0,0 +1,106 @@
|
||||
outlookMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
}
|
||||
|
||||
standardMode: WOConditional {
|
||||
condition = outlookMode;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
subject: WOString {
|
||||
value = subject;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
date: WOString {
|
||||
value = date;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
from: WOString {
|
||||
value = from;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
newLine: WOString {
|
||||
value = newLine;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReplyTo: WOConditional {
|
||||
condition = hasReplyTo;
|
||||
}
|
||||
|
||||
replyTo: WOString {
|
||||
value = replyTo;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasOrganization: WOConditional {
|
||||
condition = hasOrganization;
|
||||
}
|
||||
|
||||
organization: WOString {
|
||||
value = organization;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
to: WOString {
|
||||
value = to;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasCc: WOConditional {
|
||||
condition = hasCc;
|
||||
}
|
||||
|
||||
cc: WOString {
|
||||
value = cc;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasNewsGroups: WOConditional {
|
||||
condition = hasNewsGroups;
|
||||
}
|
||||
|
||||
newsgroups: WOString {
|
||||
value = newsgroups;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
hasReferences: WOConditional {
|
||||
condition = hasReferences;
|
||||
}
|
||||
|
||||
references: WOString {
|
||||
value = references;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
messageBody: WOString {
|
||||
value = messageBody;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
signature: WOString {
|
||||
value = signature;
|
||||
escapeHTML = NO;
|
||||
}
|
||||
|
||||
replyPlacementOnTop: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
}
|
||||
|
||||
replyPlacementOnBottom: WOConditional {
|
||||
condition = replyPlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
|
||||
signaturePlacementOnTop: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
}
|
||||
|
||||
signaturePlacementOnBottom: WOConditional {
|
||||
condition = signaturePlacementOnTop;
|
||||
negate = YES;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
"OtherUsersFolderName" = "ผู้ใช้งานอื่นๆ";
|
||||
"SharedFoldersName" = "โฟลเดอร์ที่แชร์";
|
||||
|
||||
"Report: Marked messages as junk" = "รายงาน: ทำเครื่องหมายข้อความเป็นขยะ";
|
||||
"Report: Marked messages as not junk" = "รายงาน: ทำเครื่องหมายข้อความว่าไม่ใช่ขยะ";
|
||||
@@ -231,7 +231,7 @@ endif
|
||||
ADDITIONAL_TOOL_LIBS += -Lobj -lSOGo$(LIBRARY_NAME_SUFFIX)
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../../SOPE/
|
||||
ADDITIONAL_LIB_DIRS += -L../../SOPE/GDLContentStore/obj/
|
||||
ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef
|
||||
ADDITIONAL_LDFLAGS += -lmemcached -lzip -lytnef -lcurl
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
ifneq ($(FHS_INSTALL_ROOT),)
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
@class NSArray;
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
@class NSNull;
|
||||
|
||||
@interface NSObject (SOGoObjectUtilities)
|
||||
|
||||
|
||||
@@ -33,6 +33,9 @@
|
||||
|
||||
#import "NSObject+Utilities.h"
|
||||
|
||||
static NSMutableDictionary *translationCache = nil;
|
||||
|
||||
|
||||
@implementation NSObject (SOGoObjectUtilities)
|
||||
|
||||
- (NSString *) jsonRepresentation
|
||||
@@ -101,19 +104,28 @@
|
||||
if (!bundle)
|
||||
bundle = [NSBundle mainBundle];
|
||||
languages = [[self _languagesForLabelsInContext: context] objectEnumerator];
|
||||
|
||||
if(!translationCache)
|
||||
translationCache = [NSMutableDictionary new];
|
||||
|
||||
while (!label && (language = [languages nextObject]))
|
||||
{
|
||||
paths = [bundle pathsForResourcesOfType: @"strings"
|
||||
inDirectory: [NSString stringWithFormat: @"%@.lproj",
|
||||
language]
|
||||
if (![translationCache objectForKey: language] || [[translationCache objectForKey: language] objectForKey: key] != [NSNull null]) {
|
||||
paths = [bundle pathsForResourcesOfType: @"strings"
|
||||
inDirectory: [NSString stringWithFormat: @"%@.lproj",
|
||||
language]
|
||||
forLocalization: language];
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
strings = [NSDictionary
|
||||
dictionaryFromStringsFile: [paths objectAtIndex: 0]];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
if ([paths count] > 0)
|
||||
{
|
||||
strings = [NSDictionary
|
||||
dictionaryFromStringsFile: [paths objectAtIndex: 0]];
|
||||
[translationCache setObject: strings forKey: language];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
} else {
|
||||
strings = [translationCache objectForKey: language];
|
||||
label = [strings objectForKey: key];
|
||||
}
|
||||
}
|
||||
if (!label)
|
||||
label = key;
|
||||
|
||||
@@ -184,6 +184,9 @@ static int cssEscapingCount;
|
||||
{
|
||||
rangePtr->location += offset;
|
||||
urlText = [selfCopy substringFromRange: *rangePtr];
|
||||
//If we try to detect mail, check if the first char is @, meaning this is not an email
|
||||
if([prefix isEqualToString: @"mailto:"] && [urlText characterAtIndex: 0] == '@')
|
||||
continue;
|
||||
newUrlText = [NSString stringWithFormat: @"<a rel=\"noopener\" href=\"%@%@\">%@</a>",
|
||||
([urlText hasPrefix: prefix]? @"" : prefix),
|
||||
urlText, urlText];
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
- (BOOL) checkLogin: (NSString *) _login
|
||||
password: (NSString *) _pwd
|
||||
{
|
||||
NSString *domain;
|
||||
NSString *domain, *trueLogin;
|
||||
SOGoSystemDefaults *sd;
|
||||
SOGoCASSession *session;
|
||||
SOGoPasswordPolicyError perr;
|
||||
@@ -58,9 +58,10 @@
|
||||
|
||||
domain = nil;
|
||||
perr = PolicyNoError;
|
||||
trueLogin = [_login stringByReplacingString: @"%40"
|
||||
withString: @"@"];
|
||||
rc = ([[SOGoUserManager sharedUserManager]
|
||||
checkLogin: [_login stringByReplacingString: @"%40"
|
||||
withString: @"@"]
|
||||
checkLogin: trueLogin
|
||||
password: _pwd
|
||||
domain: &domain
|
||||
perr: &perr
|
||||
|
||||
@@ -66,6 +66,7 @@
|
||||
"Italian",
|
||||
"Japanese",
|
||||
"Kazakh",
|
||||
"Korean",
|
||||
"Latvian",
|
||||
"Lithuanian",
|
||||
"Macedonian",
|
||||
@@ -84,6 +85,7 @@
|
||||
"SpanishArgentina",
|
||||
"SpanishSpain",
|
||||
"Swedish",
|
||||
"Thai",
|
||||
"TurkishTurkey",
|
||||
"Ukrainian",
|
||||
"Welsh"
|
||||
@@ -127,6 +129,7 @@
|
||||
SOGoMailDisplayFullEmail = NO;
|
||||
SOGoMailDisplayRemoteInlineImages = "never";
|
||||
SOGoMailCertificateEnabled = YES;
|
||||
SOGoMailDisplayAttachmentAbove = NO;
|
||||
|
||||
SOGoMailAutoMarkAsReadDelay = "0";
|
||||
SOGoMailAutoSave = "5";
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
@class NSException;
|
||||
@class NSTimeZone;
|
||||
@class NSURL;
|
||||
@class NSUUID;
|
||||
|
||||
@class WOContext;
|
||||
@class WORequest;
|
||||
@@ -74,6 +75,9 @@
|
||||
+ (NSString *) globallyUniqueObjectId;
|
||||
- (NSString *) globallyUniqueObjectId;
|
||||
|
||||
+ (NSString *) mailUniqueMessageId;
|
||||
- (NSString *) mailUniqueMessageId;
|
||||
|
||||
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container;
|
||||
|
||||
- (id) initWithName: (NSString *) _name inContainer:(id)_container;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#import <unistd.h>
|
||||
|
||||
|
||||
#import <NGObjWeb/SoClass.h>
|
||||
#import <NGObjWeb/SoObject+SoDAV.h>
|
||||
#import <NGObjWeb/WOApplication.h>
|
||||
@@ -111,11 +110,28 @@
|
||||
pid, (int) f, sequence++, (int) rndm];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) globallyUniqueObjectId
|
||||
{
|
||||
return [[self class] globallyUniqueObjectId];
|
||||
}
|
||||
|
||||
+ (NSString *) mailUniqueMessageId
|
||||
{
|
||||
/*
|
||||
843F8180-4E33-7B0B-6F1B-9847CAD3E6EB
|
||||
*/
|
||||
return [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
|
||||
- (NSString *) mailUniqueMessageId
|
||||
{
|
||||
/*
|
||||
843F8180-4E33-7B0B-6F1B-9847CAD3E6EB
|
||||
*/
|
||||
return [[self class] mailUniqueMessageId];
|
||||
}
|
||||
|
||||
/* containment */
|
||||
|
||||
+ (id) objectWithName: (NSString *)_name inContainer:(id)_container
|
||||
|
||||
@@ -33,6 +33,25 @@
|
||||
@class NSURL;
|
||||
@class NSJSONSerialization;
|
||||
|
||||
size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer);
|
||||
|
||||
@interface SimpleOpenIdResponse: NSObject
|
||||
{
|
||||
unsigned int status;
|
||||
NSString *content;
|
||||
NSString *headers;
|
||||
}
|
||||
|
||||
- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status;
|
||||
|
||||
- (void)setStatus:(unsigned int)_status;
|
||||
- (unsigned int)status;
|
||||
- (void)setContent:(NSString *)_data;
|
||||
- (NSString *)contentString;
|
||||
- (void)setHearders:(NSString *)_data;
|
||||
- (NSString *)headers;
|
||||
|
||||
@end
|
||||
|
||||
@interface SOGoOpenIdSession : SOGoObject
|
||||
{
|
||||
@@ -80,12 +99,12 @@
|
||||
- (void) initialize;
|
||||
- (void) initializeWithConfig: (NSDictionary *) _config;
|
||||
- (BOOL) sessionIsOK;
|
||||
- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
method: (NSString *) method
|
||||
headers: (NSDictionary *) headers
|
||||
body: (NSData *) body;
|
||||
- (NSMutableDictionary *) fecthConfiguration: (NSString *) _domain;
|
||||
- (void) setAccessToken;
|
||||
- (void) setAccessToken: (NSString* ) token;
|
||||
- (NSString *) getRefreshToken;
|
||||
- (NSString *) getToken;
|
||||
- (NSString *) getCurrentToken;
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
|
||||
#import <curl/curl.h>
|
||||
|
||||
#import <NGObjWeb/WOHTTPConnection.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
#import <NGObjWeb/WOResponse.h>
|
||||
@@ -27,12 +30,12 @@
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
|
||||
|
||||
#import <GDLContentStore/GCSOpenIdFolder.h>
|
||||
#import <GDLContentStore/GCSFolderManager.h>
|
||||
|
||||
#import "NSDictionary+Utilities.h"
|
||||
#import "NSString+Utilities.h"
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
#import <SOGo/NSString+Crypto.h>
|
||||
#import "SOGoCache.h"
|
||||
#import "SOGoSystemDefaults.h"
|
||||
|
||||
@@ -40,6 +43,87 @@
|
||||
|
||||
static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
|
||||
|
||||
size_t curl_body_function(void *ptr, size_t size, size_t nmemb, void *buffer)
|
||||
{
|
||||
size_t total;
|
||||
|
||||
total = size * nmemb;
|
||||
[(NSMutableData *)buffer appendBytes: ptr length: total];
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
@implementation SimpleOpenIdResponse
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithResponse: (NSString *)_data andHeaders: (NSString *)_headers andStatus:(unsigned int )_status{
|
||||
if ((self = [self init])) {
|
||||
[self setStatus: _status];
|
||||
[self setContent: _data];
|
||||
[self setHeaders: _headers];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setStatus:(unsigned int)_status
|
||||
{
|
||||
self->status = _status;
|
||||
}
|
||||
|
||||
- (unsigned int)status
|
||||
{
|
||||
if(self->status)
|
||||
return self->status;
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)setContent:(NSString *)_data
|
||||
{
|
||||
self->content = _data;
|
||||
}
|
||||
|
||||
- (NSString *)contentString
|
||||
{
|
||||
if(self->content)
|
||||
return self->content;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setHeaders:(NSString *)_data
|
||||
{
|
||||
self->headers = _data;
|
||||
}
|
||||
|
||||
- (NSString *)headers
|
||||
{
|
||||
if(self->headers)
|
||||
return self->headers;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)description {
|
||||
NSString *co, *hd;
|
||||
unsigned int st;
|
||||
st = 0;
|
||||
co = @"nil";
|
||||
hd = @"nil";
|
||||
if(self->status)
|
||||
st = self->status;
|
||||
if(self->headers)
|
||||
hd = self->headers;
|
||||
if(self->content)
|
||||
co = self->content;
|
||||
return [NSString stringWithFormat: @"<SimpleOpenIdResponse> <status: %d>, <headers: %@>, <content: %@>", st, hd, co];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation SOGoOpenIdSession
|
||||
|
||||
/// Check if all required parameters to set up a OpenIdSession are in sogo.conf
|
||||
@@ -54,13 +138,20 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
return NO;
|
||||
}
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
|
||||
if(![[sd authenticationType] isEqualToString: @"openid"])
|
||||
{
|
||||
[self errorWithFormat: @"Sogo SOGoAuthenticationType is not openid"];
|
||||
return NO;
|
||||
}
|
||||
|
||||
return ([sd openIdConfigUrl] && [sd openIdScope] && [sd openIdClient] && [sd openIdClientSecret]);
|
||||
}
|
||||
|
||||
- (void) initializeWithConfig: (NSDictionary *) _config
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
id refreshTokenBool, domainInfo;
|
||||
id refreshTokenBool, domainInfo, intForKey;
|
||||
|
||||
if([_config objectForKey: @"SOGoOpenIdConfigUrl"] &&
|
||||
[_config objectForKey: @"SOGoOpenIdScope"] &&
|
||||
@@ -83,8 +174,12 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
if (domainInfo && [domainInfo respondsToSelector: @selector (boolValue)])
|
||||
sendDomainInfo = [domainInfo boolValue];
|
||||
|
||||
|
||||
userTokenInterval = [_config objectForKey: @"SOGoOpenIdTokenCheckInterval"];
|
||||
intForKey = [_config objectForKey: @"SOGoOpenIdTokenCheckInterval"];
|
||||
if (intForKey && [intForKey respondsToSelector: @selector (intValue)])
|
||||
userTokenInterval = [intForKey intValue];
|
||||
else
|
||||
userTokenInterval = 0;
|
||||
|
||||
[self _loadSessionFromCache: forDomain];
|
||||
|
||||
if(cacheUpdateNeeded)
|
||||
@@ -120,7 +215,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"Missing parameters from sogo.conf"];
|
||||
[self errorWithFormat: @"LoginTypebyDOmain - Openid not found or missing parameters for domain", _domain];
|
||||
}
|
||||
}
|
||||
else if ([[self class] checkUserConfig])
|
||||
@@ -149,66 +244,150 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (WOResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
- (SimpleOpenIdResponse *) _performOpenIdRequest: (NSString *) endpoint
|
||||
method: (NSString *) method
|
||||
headers: (NSDictionary *) headers
|
||||
body: (NSData *) body
|
||||
{
|
||||
NSURL *url;
|
||||
NSMutableData *buffer, *buffHeaders;
|
||||
SimpleOpenIdResponse *response;
|
||||
|
||||
CURL *curl;
|
||||
struct curl_slist *headerlist=NULL;
|
||||
NSUInteger status;
|
||||
WORequest *request;
|
||||
WOResponse *response;
|
||||
WOHTTPConnection *httpConnection;
|
||||
|
||||
|
||||
url = [NSURL URLWithString: endpoint];
|
||||
if (url)
|
||||
{
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
{
|
||||
NSLog(@"OpenId perform request: %@ %@", method, endpoint);
|
||||
NSLog(@"OpenId perform request, headers %@", headers);
|
||||
// if(body)
|
||||
// NSLog(@"OpenId perform request: content %@", [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding]);
|
||||
}
|
||||
|
||||
httpConnection = [[WOHTTPConnection alloc] initWithURL: url];
|
||||
[httpConnection autorelease];
|
||||
NSString *content, *headerResp;
|
||||
CURLcode rc;
|
||||
char error[CURL_ERROR_SIZE];
|
||||
|
||||
request = [[WORequest alloc] initWithMethod: method
|
||||
uri: [endpoint hostlessURL]
|
||||
httpVersion: @"HTTP/1.1"
|
||||
headers: headers content: body
|
||||
userInfo: nil];
|
||||
[request autorelease];
|
||||
[httpConnection sendRequest: request];
|
||||
response = [httpConnection readResponse];
|
||||
status = [response status];
|
||||
if(status >= 200 && status <500 && status != 404)
|
||||
return response;
|
||||
else if (status == 404)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
url = [NSURL URLWithString: endpoint];
|
||||
if(!url)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID can't handle endpoint (not a url): '%@'", endpoint];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
{
|
||||
NSLog(@"OpenId perform request: %@ %@", method, endpoint);
|
||||
NSLog(@"OpenId perform request, headers %@", headers);
|
||||
}
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, body raw %@", body);
|
||||
|
||||
curl_global_init(CURL_GLOBAL_SSL);
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (curl)
|
||||
{
|
||||
error[0] = 0;
|
||||
curl_easy_setopt(curl, CURLOPT_URL, [endpoint UTF8String]);
|
||||
|
||||
//add form
|
||||
if(body)
|
||||
{
|
||||
//Trick because sometimes NSData bytes don't add the \0 at the end and junk character may be added
|
||||
const char *myBodyTmp = (const char*)[body bytes];
|
||||
char myBody[[body length]+1];
|
||||
strncpy(myBody, myBodyTmp, [body length]);
|
||||
myBody[[body length]]='\0';
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, myBodyTmp %s", myBodyTmp);
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request, myBody %s", myBody);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, myBody);
|
||||
}
|
||||
|
||||
//add headers
|
||||
if(headers)
|
||||
{
|
||||
NSEnumerator *enumerator = [headers keyEnumerator];
|
||||
NSString *key, *header;
|
||||
while((key = [enumerator nextObject]))
|
||||
{
|
||||
header = [NSString stringWithFormat: @"%@: %@", key, [headers objectForKey: key]];
|
||||
headerlist = curl_slist_append(headerlist, [header UTF8String]);
|
||||
}
|
||||
}
|
||||
if(headerlist != NULL)
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
|
||||
buffer = [NSMutableData data];
|
||||
buffHeaders = [NSMutableData data];
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_body_function);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, buffer);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curl_body_function);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, buffHeaders);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error);
|
||||
|
||||
// Perform SOAP request
|
||||
rc = curl_easy_perform(curl);
|
||||
if (rc == CURLE_OK)
|
||||
{
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||
|
||||
response = [SimpleOpenIdResponse alloc];
|
||||
headerResp = [[NSString alloc] initWithData: buffHeaders
|
||||
encoding: NSUTF8StringEncoding];
|
||||
|
||||
response = [response initWithResponse: nil andHeaders: headerResp andStatus: status];
|
||||
|
||||
if(status >= 200 && status <500 && status != 404)
|
||||
{
|
||||
content = [[NSString alloc] initWithData: buffer
|
||||
encoding: NSUTF8StringEncoding];
|
||||
if (!content)
|
||||
content = [[NSString alloc] initWithData: buffer
|
||||
encoding: NSISOLatin1StringEncoding];
|
||||
[response setContent: content];
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId perform request: response is: %@", response);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
return [response autorelease];
|
||||
}
|
||||
else if (status == 404)
|
||||
{
|
||||
[self errorWithFormat: @"OpenID endpoint not found (404): %@", endpoint];
|
||||
curl_easy_cleanup(curl);
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID server internal error during %@: %@", endpoint, response];
|
||||
curl_easy_cleanup(curl);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"CURL error while accessing %@ (%d): %@", endpoint, rc,
|
||||
[NSString stringWithCString: strlen(error) ? error : curl_easy_strerror(rc)]];
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
else
|
||||
{
|
||||
[self errorWithFormat: @"OpenID error when setting curl request for: %@", endpoint];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) fecthConfiguration: (NSString*) _domain
|
||||
{
|
||||
NSString *content;
|
||||
WOResponse * response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse * response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *config, *headers;
|
||||
@@ -498,7 +677,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) fetchToken: (NSString * ) code redirect: (NSString *) oldLocation
|
||||
{
|
||||
NSString *location, *form, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *headers;
|
||||
@@ -523,7 +703,10 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
self->forDomain, @"sogo-user-domain", nil];
|
||||
else
|
||||
headers = [NSDictionary dictionaryWithObject: @"application/x-www-form-urlencoded" forKey: @"content-type"];
|
||||
|
||||
|
||||
if(SOGoOpenIDDebugEnabled)
|
||||
NSLog(@"OpenId fetch token, form %@", form);
|
||||
|
||||
response = [self _performOpenIdRequest: location
|
||||
method: @"POST"
|
||||
headers: headers
|
||||
@@ -566,7 +749,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) refreshToken: (NSString * ) userRefreshToken
|
||||
{
|
||||
NSString *location, *form, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *headers;
|
||||
@@ -639,7 +823,8 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
- (NSMutableDictionary *) fetchUserInfo
|
||||
{
|
||||
NSString *location, *auth, *content;
|
||||
WOResponse *response;
|
||||
SimpleOpenIdResponse *response;
|
||||
// WOResponse *response;
|
||||
NSUInteger status;
|
||||
NSMutableDictionary *result;
|
||||
NSDictionary *profile, *headers;
|
||||
@@ -695,7 +880,7 @@ static BOOL SOGoOpenIDDebugEnabled = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"Error during fetching the token (status %d), response: %@", status, response];
|
||||
[self logWithFormat: @"Error fetching userInfo (status %d), response: %@", status, response];
|
||||
[result setObject: @"http-error" forKey: @"error"];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,28 +122,28 @@ static NSString *productDirectoryName = @"SOGo";
|
||||
|
||||
pathes = [[self productSearchPathes] objectEnumerator];
|
||||
while ((lpath = [pathes nextObject]))
|
||||
{
|
||||
productNames = [[fm directoryContentsAtPath: lpath] objectEnumerator];
|
||||
while ((productName = [productNames nextObject]))
|
||||
{
|
||||
productNames = [[fm directoryContentsAtPath: lpath] objectEnumerator];
|
||||
while ((productName = [productNames nextObject]))
|
||||
{
|
||||
if ([[productName pathExtension] isEqualToString: @"SOGo"])
|
||||
{
|
||||
bpath = [lpath stringByAppendingPathComponent: productName];
|
||||
[registry registerProductAtPath: bpath];
|
||||
[loadedProducts addObject: productName];
|
||||
}
|
||||
}
|
||||
if ([loadedProducts count])
|
||||
if ([[productName pathExtension] isEqualToString: @"SOGo"])
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
[self logWithFormat: @"SOGo products loaded from '%@':", lpath];
|
||||
[self logWithFormat: @" %@",
|
||||
[loadedProducts componentsJoinedByString: @", "]];
|
||||
}
|
||||
[loadedProducts removeAllObjects];
|
||||
bpath = [lpath stringByAppendingPathComponent: productName];
|
||||
[registry registerProductAtPath: bpath];
|
||||
[loadedProducts addObject: productName];
|
||||
}
|
||||
}
|
||||
if ([loadedProducts count])
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
[self logWithFormat: @"SOGo products loaded from '%@':", lpath];
|
||||
[self logWithFormat: @" %@",
|
||||
[loadedProducts componentsJoinedByString: @", "]];
|
||||
}
|
||||
[loadedProducts removeAllObjects];
|
||||
}
|
||||
}
|
||||
|
||||
if (![registry loadAllProducts] && verbose)
|
||||
[self warnWithFormat: @"could not load all products !"];
|
||||
|
||||
@@ -162,11 +162,23 @@
|
||||
|
||||
// Get the key length and its bytes
|
||||
data = [theKey dataByDecodingBase64];
|
||||
key = (char *)[data bytes];
|
||||
klen = [data length];
|
||||
|
||||
|
||||
//value longer than the key, concatenate the key with itself until long enough
|
||||
if (klen < [theValue length])
|
||||
[self errorWithFormat: @"Value to be secured is too big (%i > %i) -- secured value will be corrupted", [theValue length], klen, [theKey length]];
|
||||
{
|
||||
NSMutableData *concatenatedData = [NSMutableData data];
|
||||
int j;
|
||||
int nbDuplication = [theValue length]/klen;
|
||||
for(j=0; j <= nbDuplication; j++)
|
||||
[concatenatedData appendData:data];
|
||||
|
||||
data = [NSData dataWithData: concatenatedData];
|
||||
klen = [data length];
|
||||
}
|
||||
|
||||
key = (char *)[data bytes];
|
||||
|
||||
// Get the key - padding it with 0 with key length
|
||||
pass = (char *) calloc(klen, sizeof(char));
|
||||
@@ -201,7 +213,6 @@
|
||||
|
||||
// Get the key length and its bytes
|
||||
dataKey = [theKey dataByDecodingBase64];
|
||||
key = (char *)[dataKey bytes];
|
||||
klen = [dataKey length];
|
||||
|
||||
// Get the secured value length and its bytes
|
||||
@@ -209,6 +220,20 @@
|
||||
value = (char *)[dataValue bytes];
|
||||
vlen = [dataValue length];
|
||||
|
||||
//If the key is shorer than the value, duplicate it with itself.
|
||||
if(klen < vlen)
|
||||
{
|
||||
NSMutableData *concatenatedData = [NSMutableData data];
|
||||
int j;
|
||||
int nbDuplication = [dataValue length]/klen;
|
||||
for(j=0; j <= nbDuplication; j++)
|
||||
[concatenatedData appendData:dataKey];
|
||||
|
||||
dataKey = [NSData dataWithData: concatenatedData];
|
||||
klen = [dataKey length];
|
||||
}
|
||||
key = (char *)[dataKey bytes];
|
||||
|
||||
// Target buffer
|
||||
buf = (char *) calloc(klen, sizeof(char));
|
||||
|
||||
|
||||
@@ -496,6 +496,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSString *) _extractSieveAction: (NSDictionary *) action
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSString *sieveAction, *method, *requirement, *argument, *flag, *mailbox;
|
||||
@@ -548,7 +549,9 @@ static NSString *sieveScriptName = @"sogo";
|
||||
{
|
||||
argument = [NSString stringWithFormat: @"mailto:%@", argument];
|
||||
sieveAction = [NSString stringWithFormat: @"%@ %@",
|
||||
method, [argument asSieveQuotedString]];
|
||||
method, [argument asSieveQuotedString]];
|
||||
[req addObjectUniquely: @"enotify"];
|
||||
[req addObjectUniquely: @"variables"];
|
||||
}
|
||||
else if ([method isEqualToString: @"reject"])
|
||||
sieveAction = [NSString stringWithFormat: @"%@ %@",
|
||||
@@ -575,6 +578,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSArray *) _extractSieveActions: (NSArray *) actions
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSMutableArray *sieveActions;
|
||||
@@ -586,6 +590,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
for (count = 0; !scriptError && count < max; count++)
|
||||
{
|
||||
sieveAction = [self _extractSieveAction: [actions objectAtIndex: count]
|
||||
withReq: req
|
||||
delimiter: delimiter];
|
||||
if (!scriptError)
|
||||
[sieveActions addObject: sieveAction];
|
||||
@@ -595,6 +600,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
}
|
||||
|
||||
- (NSString *) _convertScriptToSieve: (NSDictionary *) newScript
|
||||
withReq: (NSMutableDictionary *) req
|
||||
delimiter: (NSString *) delimiter
|
||||
{
|
||||
NSMutableString *sieveText;
|
||||
@@ -624,6 +630,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
scriptError = [NSString stringWithFormat: @"Bad test: %@", match];
|
||||
}
|
||||
sieveActions = [self _extractSieveActions: [newScript objectForKey: @"actions"]
|
||||
withReq: req
|
||||
delimiter: delimiter];
|
||||
if ([sieveActions count])
|
||||
[sieveText appendFormat: @" %@;\r\n",
|
||||
@@ -660,6 +667,7 @@ static NSString *sieveScriptName = @"sogo";
|
||||
if ([[currentScript objectForKey: @"active"] boolValue])
|
||||
{
|
||||
sieveText = [self _convertScriptToSieve: currentScript
|
||||
withReq: newRequirements
|
||||
delimiter: delimiter];
|
||||
[sieveScript appendString: sieveText];
|
||||
}
|
||||
@@ -782,10 +790,10 @@ static NSString *sieveScriptName = @"sogo";
|
||||
imapAuthMech = nil;
|
||||
if([sd doesLoginTypeByDomain])
|
||||
{
|
||||
r = [theUsername rangeOfString: @"@"];
|
||||
r = [authname rangeOfString: @"@"];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
userDomain = [theUsername substringFromIndex: r.location+1];
|
||||
userDomain = [authname substringFromIndex: r.location+1];
|
||||
imapAuthMech = [sd getImapAuthMechForDomain: userDomain];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ static const NSString *kDisableSharingCalendar = @"Calendar";
|
||||
- (BOOL) uixDebugEnabled;
|
||||
- (BOOL) easDebugEnabled;
|
||||
- (BOOL) openIdDebugEnabled;
|
||||
- (BOOL) apiDebugEnabled;
|
||||
- (BOOL) tnefDecoderDebugEnabled;
|
||||
- (BOOL) xsrfValidationEnabled;
|
||||
|
||||
|
||||
@@ -654,6 +654,11 @@ _injectConfigurationFromFile (NSMutableDictionary *defaultsDict,
|
||||
return [self boolForKey: @"SOGoOpenIDDebugEnabled"];
|
||||
}
|
||||
|
||||
- (BOOL) apiDebugEnabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoAPIDebugEnabled"];
|
||||
}
|
||||
|
||||
- (BOOL) tnefDecoderDebugEnabled
|
||||
{
|
||||
return [self boolForKey: @"SOGoTnefDecoderDebugEnabled"];
|
||||
|
||||
+83
-76
@@ -145,92 +145,91 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
realUID = nil;
|
||||
domain = nil;
|
||||
|
||||
if ([newLogin isEqualToString: @"anonymous"]
|
||||
|| [newLogin isEqualToString: @"freebusy"])
|
||||
if ([newLogin isEqualToString: @"anonymous"] || [newLogin isEqualToString: @"freebusy"])
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
r = [newLogin rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
// The domain is probably appended to the username;
|
||||
// make sure it is defined as a domain in the configuration.
|
||||
domain = [newLogin substringFromIndex: (r.location + r.length)];
|
||||
if ([[SOGoUserManager sharedUserManager] isDomainDefined: domain] &&
|
||||
![sd enableDomainBasedUID])
|
||||
newLogin = [newLogin substringToIndex: r.location];
|
||||
r = [newLogin rangeOfString: @"@" options: NSBackwardsSearch];
|
||||
if (r.location != NSNotFound)
|
||||
{
|
||||
// The domain is probably appended to the username;
|
||||
// make sure it is defined as a domain in the configuration.
|
||||
domain = [newLogin substringFromIndex: (r.location + r.length)];
|
||||
if ([[SOGoUserManager sharedUserManager] isDomainDefined: domain] &&
|
||||
![sd enableDomainBasedUID])
|
||||
newLogin = [newLogin substringToIndex: r.location];
|
||||
|
||||
if (domain != nil && ![sd enableDomainBasedUID])
|
||||
// Login domains are enabled (SOGoLoginDomains) but not
|
||||
// domain-based UID (SOGoEnableDomainBasedUID).
|
||||
// Drop the domain from the login name.
|
||||
domain = nil;
|
||||
}
|
||||
}
|
||||
|
||||
newLogin = [newLogin stringByReplacingString: @"%40"
|
||||
withString: @"@"];
|
||||
if (b)
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
contactInfos = [um contactInfosForUserWithUIDorEmail: newLogin
|
||||
inDomain: domain];
|
||||
realUID = [contactInfos objectForKey: @"c_uid"];
|
||||
if (domain == nil && [sd enableDomainBasedUID])
|
||||
domain = [contactInfos objectForKey: @"c_domain"];
|
||||
}
|
||||
|
||||
if ([realUID length] && [domain length])
|
||||
{
|
||||
// When the user is associated to a domain, the [SOGoUser login]
|
||||
// method returns the combination login@domain while
|
||||
// [SOGoUser loginInDomain] only returns the login.
|
||||
r = [realUID rangeOfString: domain options: NSBackwardsSearch|NSCaseInsensitiveSearch];
|
||||
|
||||
// Do NOT strip @domain.com if SOGoEnableDomainBasedUID is enabled since
|
||||
// the real login most likely is the email address.
|
||||
if (r.location != NSNotFound && ![sd enableDomainBasedUID])
|
||||
uid = [realUID substringToIndex: r.location-1];
|
||||
// If we don't have the domain in the UID but SOGoEnableDomainBasedUID is
|
||||
// enabled, let's add it internally so so it becomes unique across
|
||||
// all potential domains.
|
||||
else if (r.location == NSNotFound && [sd enableDomainBasedUID])
|
||||
{
|
||||
uid = [NSString stringWithString: realUID];
|
||||
realUID = [NSString stringWithFormat: @"%@@%@", realUID, domain];
|
||||
}
|
||||
// We found the domain and SOGoEnableDomainBasedUID is enabled,
|
||||
// we keep realUID.. This would happen for example if the user
|
||||
// authenticates with foo@bar.com and the UIDFieldName is also foo@bar.com
|
||||
else if ([sd enableDomainBasedUID])
|
||||
uid = [NSString stringWithString: realUID];
|
||||
}
|
||||
if (domain != nil && ![sd enableDomainBasedUID])
|
||||
// Login domains are enabled (SOGoLoginDomains) but not
|
||||
// domain-based UID (SOGoEnableDomainBasedUID).
|
||||
// Drop the domain from the login name.
|
||||
domain = nil;
|
||||
}
|
||||
}
|
||||
|
||||
newLogin = [newLogin stringByReplacingString: @"%40"
|
||||
withString: @"@"];
|
||||
if (b)
|
||||
realUID = newLogin;
|
||||
else
|
||||
{
|
||||
um = [SOGoUserManager sharedUserManager];
|
||||
contactInfos = [um contactInfosForUserWithUIDorEmail: newLogin
|
||||
inDomain: domain];
|
||||
realUID = [contactInfos objectForKey: @"c_uid"];
|
||||
if (domain == nil && [sd enableDomainBasedUID])
|
||||
domain = [contactInfos objectForKey: @"c_domain"];
|
||||
}
|
||||
|
||||
if ([realUID length] && [domain length])
|
||||
{
|
||||
// When the user is associated to a domain, the [SOGoUser login]
|
||||
// method returns the combination login@domain while
|
||||
// [SOGoUser loginInDomain] only returns the login.
|
||||
r = [realUID rangeOfString: domain options: NSBackwardsSearch|NSCaseInsensitiveSearch];
|
||||
|
||||
// Do NOT strip @domain.com if SOGoEnableDomainBasedUID is enabled since
|
||||
// the real login most likely is the email address.
|
||||
if (r.location != NSNotFound && ![sd enableDomainBasedUID])
|
||||
uid = [realUID substringToIndex: r.location-1];
|
||||
// If we don't have the domain in the UID but SOGoEnableDomainBasedUID is
|
||||
// enabled, let's add it internally so so it becomes unique across
|
||||
// all potential domains.
|
||||
else if (r.location == NSNotFound && [sd enableDomainBasedUID])
|
||||
{
|
||||
uid = [NSString stringWithString: realUID];
|
||||
realUID = [NSString stringWithFormat: @"%@@%@", realUID, domain];
|
||||
}
|
||||
// We found the domain and SOGoEnableDomainBasedUID is enabled,
|
||||
// we keep realUID.. This would happen for example if the user
|
||||
// authenticates with foo@bar.com and the UIDFieldName is also foo@bar.com
|
||||
else if ([sd enableDomainBasedUID])
|
||||
uid = [NSString stringWithString: realUID];
|
||||
}
|
||||
}
|
||||
|
||||
if ([realUID length])
|
||||
{
|
||||
if ((self = [super initWithLogin: realUID roles: newRoles]))
|
||||
{
|
||||
if ((self = [super initWithLogin: realUID roles: newRoles]))
|
||||
{
|
||||
allEmails = nil;
|
||||
currentPassword = nil;
|
||||
cn = nil;
|
||||
ASSIGN (loginInDomain, (uid ? uid : realUID));
|
||||
_defaults = nil;
|
||||
_domainDefaults = nil;
|
||||
_settings = nil;
|
||||
mailAccounts = nil;
|
||||
}
|
||||
allEmails = nil;
|
||||
currentPassword = nil;
|
||||
cn = nil;
|
||||
ASSIGN (loginInDomain, (uid ? uid : realUID));
|
||||
_defaults = nil;
|
||||
_domainDefaults = nil;
|
||||
_settings = nil;
|
||||
mailAccounts = nil;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
{
|
||||
[self release];
|
||||
self = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -265,6 +264,14 @@ static const NSString *kEncryptedUserNamePrefix = @"uenc";
|
||||
|
||||
- (NSString *) loginInDomain
|
||||
{
|
||||
SOGoSystemDefaults *sd;
|
||||
NSString *_domain, *realLoginInDomain;
|
||||
NSRange r;
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
if ([sd enableDomainBasedUID] || [[sd loginDomains] count] > 0)
|
||||
{
|
||||
return self->login;
|
||||
}
|
||||
return loginInDomain;
|
||||
}
|
||||
|
||||
|
||||
@@ -156,12 +156,14 @@ extern NSString *SOGoPasswordRecoverySecondaryEmail;
|
||||
- (void) setMailComposeFontSize: (int) newValue;
|
||||
- (int) mailComposeFontSize;
|
||||
|
||||
- (void) setMailDisplayFullEmail: (BOOL *) newValue;
|
||||
- (BOOL *) mailDisplayFullEmail;
|
||||
- (void) setMailDisplayFullEmail: (BOOL) newValue;
|
||||
- (BOOL) mailDisplayFullEmail;
|
||||
|
||||
- (void) setMailDisplayRemoteInlineImages: (NSString *) newValue;
|
||||
- (NSString *) mailDisplayRemoteInlineImages;
|
||||
|
||||
- (void) setMailDisplayAttachmentAbove: (BOOL) newValue;
|
||||
- (BOOL) mailDisplayAttachmentAbove;
|
||||
|
||||
- (void) setMailAutoMarkAsReadDelay: (int) newValue;
|
||||
- (int) mailAutoMarkAsReadDelay;
|
||||
|
||||
@@ -634,12 +634,12 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
return [self integerForKey: @"SOGoMailComposeFontSize"];
|
||||
}
|
||||
|
||||
- (void) setMailDisplayFullEmail: (BOOL *) newValue
|
||||
- (void) setMailDisplayFullEmail: (BOOL) newValue
|
||||
{
|
||||
[self setBool: newValue forKey: @"SOGoMailDisplayFullEmail"];
|
||||
}
|
||||
|
||||
- (BOOL *) mailDisplayFullEmail;
|
||||
- (BOOL) mailDisplayFullEmail;
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailDisplayFullEmail"];
|
||||
}
|
||||
@@ -654,6 +654,16 @@ NSString *SOGoPasswordRecoverySecondaryEmail = @"SecondaryEmail";
|
||||
return [self stringForKey: @"SOGoMailDisplayRemoteInlineImages"];
|
||||
}
|
||||
|
||||
- (void) setMailDisplayAttachmentAbove: (BOOL) newValue
|
||||
{
|
||||
[self setBool: newValue forKey: @"SOGoMailDisplayAttachmentAbove"];
|
||||
}
|
||||
|
||||
- (BOOL) mailDisplayAttachmentAbove;
|
||||
{
|
||||
return [self boolForKey: @"SOGoMailDisplayAttachmentAbove"];
|
||||
}
|
||||
|
||||
- (void) setMailAutoMarkAsReadDelay: (int) newValue
|
||||
{
|
||||
[self setInteger: newValue forKey: @"SOGoMailAutoMarkAsReadDelay"];
|
||||
|
||||
@@ -172,6 +172,9 @@
|
||||
EOAdaptorContext *ac;
|
||||
EOAdaptorChannel *fc;
|
||||
NSString *profileURL, *sql, *sqlFromUserID, *sqlToUserID;
|
||||
NSString *old_c_default, *old_c_settings, *new_c_default, *new_c_settings;
|
||||
NSArray *attrs;
|
||||
NSDictionary *row;
|
||||
NSException *sqlError;
|
||||
SOGoSystemDefaults *sd;
|
||||
|
||||
@@ -188,9 +191,22 @@
|
||||
|
||||
[ac beginTransaction];
|
||||
|
||||
sql = [NSString stringWithFormat: @"UPDATE %@ SET c_uid = '%@'"
|
||||
sql = [NSString stringWithFormat: @"SELECT c_defaults, c_settings FROM %@"
|
||||
@" WHERE c_uid = '%@'",
|
||||
[profileLocation gcsTableName], sqlToUserID, sqlFromUserID];
|
||||
[profileLocation gcsTableName], sqlFromUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
attrs = [fc describeResults: NO];
|
||||
while ((row = [fc fetchAttributes: attrs withZone: NULL]))
|
||||
{
|
||||
old_c_default = [row objectForKey: @"c_defaults"];
|
||||
old_c_settings = [row objectForKey: @"c_settings"];
|
||||
new_c_default = [old_c_default stringByReplacingOccurrencesOfString:fromUserID withString:toUserID];
|
||||
new_c_settings = [old_c_settings stringByReplacingOccurrencesOfString:fromUserID withString:toUserID];
|
||||
}
|
||||
|
||||
sql = [NSString stringWithFormat: @"UPDATE %@ SET c_uid = '%@', c_defaults = '%@', "
|
||||
@"c_settings = '%@' WHERE c_uid = '%@'",
|
||||
[profileLocation gcsTableName], sqlToUserID, new_c_default, new_c_settings, sqlFromUserID];
|
||||
sqlError = [fc evaluateExpressionX: sql];
|
||||
if (sqlError)
|
||||
{
|
||||
@@ -568,6 +584,7 @@
|
||||
[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" = "Geen middelen";
|
||||
"Any Authenticated User" = "Elke geauthenticeerde gebruiker";
|
||||
"Public Access" = "Publieke toegang";
|
||||
"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" = "Opslaan";
|
||||
"Clear" = "Leeg maken";
|
||||
"Message of the day" = "Bericht van de dag";
|
||||
"Message of the day has been saved" = "Bericht van de dag is opgeslagen";
|
||||
@@ -0,0 +1,31 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Help" = "도움말";
|
||||
"Close" = "닫기";
|
||||
"Modules" = "모듈";
|
||||
/* Modules short names */
|
||||
"ACLs" = "ACL";
|
||||
/* Modules titles */
|
||||
"ACLs_title" = "사용자 폴더 ACL 관리";
|
||||
/* Modules descriptions */
|
||||
"ACLs_description" = "<p>접근 제어 목록(ACL) 관리 모듈은 각 사용자의 캘린더 및 주소록의 ACL을 변경할 수 있도록 합니다.</p><p>사용자 폴더의 ACL을 수정하려면 창 상단의 검색 필드에 사용자 이름을 입력하고 원하는 폴더를 두 번 클릭하십시오.</p>";
|
||||
"Name or Email" = "이름 또는 이메일";
|
||||
"ACLs saved" = "ACL 저장됨";
|
||||
/* Rights module: initial search message */
|
||||
"Start a search to edit the rights" = "권한을 편집하려면 검색을 시작하십시오";
|
||||
/* Rights module: Empty search result */
|
||||
"No matching user" = "일치하는 사용자 없음";
|
||||
/* Rights module: no selection */
|
||||
"No resource selected" = "선택된 리소스 없음";
|
||||
"Add User" = "사용자 추가";
|
||||
"Subscribe User" = "사용자 구독";
|
||||
"Rights" = "권한";
|
||||
"Search Users" = "사용자 검색";
|
||||
"users found" = "사용자 발견";
|
||||
"No resource" = "리소스 없음";
|
||||
"Any Authenticated User" = "모든 인증된 사용자";
|
||||
"Public Access" = "공개 접근";
|
||||
"Save" = "저장";
|
||||
"Clear" = "지우기";
|
||||
"Message of the day" = "오늘의 메시지";
|
||||
"Message of the day has been saved" = "오늘의 메시지가 저장되었습니다";
|
||||
@@ -0,0 +1,31 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Help" = "ช่วยเหลือ";
|
||||
"Close" = "ปิด";
|
||||
"Modules" = "โมดูล";
|
||||
/* Modules short names */
|
||||
"ACLs" = "ACLs";
|
||||
/* Modules titles */
|
||||
"ACLs_title" = "Users folders ACLs management";
|
||||
/* Modules descriptions */
|
||||
"ACLs_description" = "<p>โมดูลการจัดการรายการควบคุมการเข้าถึงช่วยให้สามารถเปลี่ยนแปลง ACLs ของปฏิทินและสมุดที่อยู่ของผู้ใช้แต่ละคนได้</p><p>ในการแก้ไข ACLs ของโฟลเดอร์ของผู้ใช้ ให้พิมพ์ชื่อผู้ใช้ในช่องค้นหาที่ด้านบนของหน้าต่างและดับเบิลคลิกที่โฟลเดอร์ที่ต้องการ</p>";
|
||||
"Name or Email" = "ชื่อหรืออีเมล์";
|
||||
"ACLs saved" = "ACLs บันทึกแล้ว";
|
||||
/* Rights module: initial search message */
|
||||
"Start a search to edit the rights" = "เริ่มการค้นหาเพื่อแก้ไขสิทธิ์";
|
||||
/* Rights module: Empty search result */
|
||||
"No matching user" = "ไม่พบผู้ใช้ที่ตรงกัน";
|
||||
/* Rights module: no selection */
|
||||
"No resource selected" = "ไม่ได้เลือกทรัพยากร";
|
||||
"Add User" = "เพิ่มผู้ใช้";
|
||||
"Subscribe User" = "สมัครสมาชิกผู้ใช้";
|
||||
"Rights" = "สิทธิ์";
|
||||
"Search Users" = "ค้นหาผู้ใช้";
|
||||
"users found" = "ผู้ใช้พบ";
|
||||
"No resource" = "ไม่มีทรัพยากร";
|
||||
"Any Authenticated User" = "ผู้ใช้ที่ได้รับการยืนยันตัวตนใด ๆ";
|
||||
"Public Access" = "การเข้าถึงสาธารณะ";
|
||||
"Save" = "บันทึก";
|
||||
"Clear" = "ชัดเจน";
|
||||
"Message of the day" = "ข้อความของวันนี้";
|
||||
"Message of the day has been saved" = "ข้อความของวันนี้ถูกบันทึกแล้ว";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Sekundární e-mail";
|
||||
|
||||
/* 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" = "Minimum je %{0} malých znaků";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimum je %{0} velkých písmen";
|
||||
"POLICY_MIN_DIGIT" = "Minimum je %{0} číslic";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimum je %{0} speciálních znaků";
|
||||
"POLICY_MIN_LENGTH" = "Minimální délka je %{0} znaků";
|
||||
@@ -45,7 +45,7 @@
|
||||
"Reduce" = "Verminderen";
|
||||
|
||||
/* tooltip */
|
||||
"Refresh" = "Refresh";
|
||||
"Refresh" = "Vernieuwen";
|
||||
|
||||
/* generic.js */
|
||||
"Unable to subscribe to that folder!"
|
||||
@@ -109,7 +109,7 @@
|
||||
"Personal" = "Persoonlijk";
|
||||
"To Do" = "Te doen";
|
||||
"Later" = "Later";
|
||||
"Forwarded" = "Forwarded";
|
||||
"Forwarded" = "Doorgestuurd";
|
||||
"Return Receipt Sent" = "Ontvangstbewijs verzonden";
|
||||
"a2_Sunday" = "Zo";
|
||||
"a2_Monday" = "Ma";
|
||||
@@ -122,7 +122,7 @@
|
||||
"Add User" = "Gebruiker toevoegen";
|
||||
"Loading" = "Laden";
|
||||
"No such user." = "Geen dergelijke gebruiker";
|
||||
"You cannot (un)subscribe to a folder that you own!" = "Kan niet aan- of afmelden van eigen map!";
|
||||
"You cannot (un)subscribe to a folder that you own!" = "U kunt zich niet (af)melden voor een map waarvan u de eigenaar bent!";
|
||||
|
||||
/* SMIME Certificate field */
|
||||
"S/MIME Certificate" = "S/MIME Certificaat";
|
||||
@@ -227,16 +227,16 @@
|
||||
"Move forward" = "Ga vooruit";
|
||||
|
||||
/* Password Recovery */
|
||||
"passwordRecovery_Disabled" = "Disabled";
|
||||
"passwordRecovery_SecretQuestion" = "Secret question";
|
||||
"passwordRecovery_SecretQuestion1" = "What is the name of your first pet ?";
|
||||
"passwordRecovery_SecretQuestion2" = "What was your first car ?";
|
||||
"passwordRecovery_SecretQuestion3" = "What is your favorite movie ?";
|
||||
"passwordRecovery_SecondaryEmail" = "Secondary E-mail";
|
||||
"passwordRecovery_Disabled" = "Uitgezet";
|
||||
"passwordRecovery_SecretQuestion" = "Geheime vraag";
|
||||
"passwordRecovery_SecretQuestion1" = "Hoe heet je eerste huisdier?";
|
||||
"passwordRecovery_SecretQuestion2" = "Wat was je eerste auto?";
|
||||
"passwordRecovery_SecretQuestion3" = "Wat is je favoriete film?";
|
||||
"passwordRecovery_SecondaryEmail" = "Secundair e-mailadres";
|
||||
|
||||
/* 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" = "Minimaal %{0} kleine letter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Minimaal %{0} hoofdletter";
|
||||
"POLICY_MIN_DIGIT" = "Minimaal %{0} cijfer";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Minimaal %{0} speciale symbolen";
|
||||
"POLICY_MIN_LENGTH" = "Minimale lengte van %{0} tekens";
|
||||
@@ -0,0 +1,242 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
/* toolbars */
|
||||
"Save" = "저장";
|
||||
"Close" = "닫기";
|
||||
"Edit User Rights" = "사용자 권한 편집";
|
||||
"Home" = "홈";
|
||||
"Calendar" = "캘린더";
|
||||
"Address Book" = "주소록";
|
||||
"Mail" = "메일";
|
||||
"Preferences" = "환경설정";
|
||||
"Administration" = "관리";
|
||||
"Disconnect" = "연결 끊기";
|
||||
"Toggle Menu" = "메뉴 전환";
|
||||
"Right Administration" = "권한 관리";
|
||||
"Log Console (dev.)" = "로그 콘솔 (개발)";
|
||||
"User" = "사용자";
|
||||
"Vacation message is enabled" = "부재중 메시지 활성화됨";
|
||||
"Help" = "도움말";
|
||||
"noJavascriptError" = "SOGo를 실행하려면 Javascript가 필요합니다. 브라우저 환경설정에서 이 옵션이 사용 가능하고 활성화되어 있는지 확인하세요.";
|
||||
"noJavascriptRetry" = "다시 시도";
|
||||
"Owner" = "소유자";
|
||||
"Publish the Free/Busy information" = "약속 가능/불가능 정보 게시";
|
||||
"Add..." = "추가...";
|
||||
"Remove" = "제거";
|
||||
"Subscribe User" = "사용자 구독";
|
||||
"Any Authenticated User" = "모든 인증된 사용자";
|
||||
"Public Access" = "공개 접근";
|
||||
"Any user not listed above" = "위에 나열되지 않은 모든 사용자";
|
||||
"Anybody accessing this resource from the public area" = "공개 영역에서 이 리소스에 접근하는 모든 사람";
|
||||
"Sorry, the user rights can not be configured for that object." = "죄송합니다, 해당 개체에 대한 사용자 권한은 설정할 수 없습니다.";
|
||||
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
||||
= "이 시스템에 계정이 있는 모든 사용자가 귀하의 사서함 \"%{0}\"에 접근할 수 있습니다. 그들 모두를 신뢰하십니까?";
|
||||
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
||||
= "이 시스템에 계정이 있는 모든 사용자가 귀하의 캘린더 \"%{0}\"에 접근할 수 있습니다. 그들 모두를 신뢰하십니까?";
|
||||
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "이 시스템에 계정이 없더라도 인터넷상의 누구나 귀하의 캘린더 \"%{0}\"에 접근할 수 있습니다. 이 정보는 공개 인터넷에 적합합니까?";
|
||||
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
|
||||
= "이 시스템에 계정이 있는 모든 사용자가 귀하의 주소록 \"%{0}\"에 접근할 수 있습니다. 그들 모두를 신뢰하십니까?";
|
||||
"Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "이 시스템에 계정이 없더라도 인터넷상의 누구나 귀하의 주소록 \"%{0}\"에 접근할 수 있습니다. 이 정보는 공개 인터넷에 적합합니까?";
|
||||
"Give Access" = "접근 권한 부여";
|
||||
"Keep Private" = "비공개 유지";
|
||||
"Expand" = "확장";
|
||||
"Reduce" = "축소";
|
||||
|
||||
/* tooltip */
|
||||
"Refresh" = "새로고침";
|
||||
|
||||
/* generic.js */
|
||||
"Unable to subscribe to that folder!"
|
||||
= "해당 폴더를 구독할 수 없습니다!";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "소유하고 있는 폴더는 구독할 수 없습니다!";
|
||||
"Unable to unsubscribe from that folder!"
|
||||
= "해당 폴더 구독을 취소할 수 없습니다!";
|
||||
"You cannot unsubscribe from a folder that you own!"
|
||||
= "소유하고 있는 폴더는 구독을 취소할 수 없습니다!";
|
||||
"Unable to rename that folder!" = "해당 폴더 이름을 바꿀 수 없습니다!";
|
||||
"You have already subscribed to that folder!"
|
||||
= "이미 해당 폴더를 구독했습니다!";
|
||||
"The user rights cannot be edited for this object!"
|
||||
= "이 개체에 대한 사용자 권한은 편집할 수 없습니다!";
|
||||
"A folder by that name already exists." = "해당 이름의 폴더가 이미 존재합니다.";
|
||||
"You cannot create a list in a shared address book."
|
||||
= "공유 주소록에서는 목록을 생성할 수 없습니다.";
|
||||
"Warning" = "경고";
|
||||
"Can't contact server" = "서버와 통신하는 중 오류가 발생했습니다. 나중에 다시 시도해 주세요.";
|
||||
"You are not allowed to access this module or this system. Please contact your system administrator."
|
||||
= "이 모듈 또는 이 시스템에 접근할 수 없습니다. 시스템 관리자에게 문의하십시오.";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "이 작업을 수행하는 데 필요한 권한이 없습니다.";
|
||||
"noEmailForDelegation" = "초대를 위임할 주소를 지정해야 합니다.";
|
||||
"delegate is organizer" = "위임자가 주최자입니다. 다른 위임자를 지정하십시오.";
|
||||
"delegate is a participant" = "위임자가 이미 참가자입니다.";
|
||||
"delegate is a group" = "지정된 주소는 그룹에 해당합니다. 개별 사용자에게만 위임할 수 있습니다.";
|
||||
|
||||
/* common buttons */
|
||||
"OK" = "확인";
|
||||
"Cancel" = "취소";
|
||||
"Yes" = "예";
|
||||
"No" = "아니요";
|
||||
|
||||
/* generic messages */
|
||||
"Error" = "오류";
|
||||
"Success" = "성공";
|
||||
|
||||
/* confirmation dialog box */
|
||||
"Confirmation" = "확인";
|
||||
|
||||
/* alarms */
|
||||
"Reminder" = "알림";
|
||||
"Start" = "시작";
|
||||
"Due Date" = "마감일";
|
||||
"Location" = "장소";
|
||||
"Snooze" = "다시 알림";
|
||||
"Snooze for " = "다시 알림 ";
|
||||
"5 minutes" = "5분";
|
||||
"10 minutes" = "10분";
|
||||
"15 minutes" = "15분";
|
||||
"30 minutes" = "30분";
|
||||
"45 minutes" = "45분";
|
||||
"1 hour" = "1시간";
|
||||
"1 day" = "1일";
|
||||
|
||||
/* mail labels */
|
||||
"Important" = "중요";
|
||||
"Work" = "업무";
|
||||
"Personal" = "개인";
|
||||
"To Do" = "할 일";
|
||||
"Later" = "나중에";
|
||||
"Forwarded" = "전달됨";
|
||||
"Return Receipt Sent" = "읽음 확인 전송됨";
|
||||
"a2_Sunday" = "일";
|
||||
"a2_Monday" = "월";
|
||||
"a2_Tuesday" = "화";
|
||||
"a2_Wednesday" = "수";
|
||||
"a2_Thursday" = "목";
|
||||
"a2_Friday" = "금";
|
||||
"a2_Saturday" = "토";
|
||||
"Access Rights" = "접근 권한";
|
||||
"Add User" = "사용자 추가";
|
||||
"Loading" = "로딩 중";
|
||||
"No such user." = "해당 사용자가 없습니다.";
|
||||
"You cannot (un)subscribe to a folder that you own!" = "소유하고 있는 폴더는 (구독/구독 취소)할 수 없습니다!";
|
||||
|
||||
/* SMIME Certificate field */
|
||||
"S/MIME Certificate" = "S/MIME 인증서";
|
||||
"Subject Name" = "주체 이름";
|
||||
"Issuer" = "발급자";
|
||||
"streetAddress" = "거리 주소";
|
||||
"stateOrProvinceName" = "주 또는 시/도";
|
||||
"localityName" = "지역";
|
||||
"countryName" = "국가";
|
||||
"organizationName" = "기관명";
|
||||
"organizationalUnitName" = "조직 단위";
|
||||
"commonName" = "일반 이름";
|
||||
"surname" = "성";
|
||||
"givenName" = "이름";
|
||||
"emailAddress" = "이메일 주소";
|
||||
|
||||
|
||||
/* Authentication username */
|
||||
"Username" = "사용자명";
|
||||
|
||||
/* Authentication password */
|
||||
"Password" = "비밀번호";
|
||||
|
||||
/* Authentication failed */
|
||||
"Wrong username or password." = "잘못된 사용자명 또는 비밀번호입니다.";
|
||||
|
||||
/* Error message displayed bellow search field when the search string has less than the required number of characters */
|
||||
"Enter at least %{minimumSearchLength} characters" = "최소 %{minimumSearchLength}자를 입력하세요";
|
||||
|
||||
/* Error message displayed when a file upload exceeds WOMaxUploadSize */
|
||||
"File size upload limit reached" = "파일 크기 업로드 제한에 도달했습니다";
|
||||
|
||||
/* Generic server error */
|
||||
"An error occured, please try again." = "An error occured, please try again.";
|
||||
|
||||
/* Open datepicker */
|
||||
"Open Calendar" = "캘린더 열기";
|
||||
|
||||
/* Toggle visibility (ex: mail account in left navigation menu) */
|
||||
"Toggle visibility" = "가시성 전환";
|
||||
|
||||
"Keyboard Shortcuts" = "키보드 단축키";
|
||||
|
||||
/* Aria label for avatar button to select and unselect an item */
|
||||
"Toggle item" = "항목 전환";
|
||||
|
||||
/* Toggle multiple items at the same time (hotkeys cheatsheet) */
|
||||
"Toggle range of items" = "항목 범위 전환";
|
||||
|
||||
/* Question mark shows list of hotkeys */
|
||||
"Show or hide this help" = "이 도움말 표시 또는 숨기기";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "스페이스";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "삭제";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "시프트 + 스페이스";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
|
||||
/* Down arrow key */
|
||||
"key_down" = "↓";
|
||||
|
||||
/* Left arrow key */
|
||||
"key_left" = "←";
|
||||
|
||||
/* Right arrow key */
|
||||
"key_right" = "→";
|
||||
|
||||
/* Shift and up arrow combo keys */
|
||||
"key_shift+up" = "시프트 + ↑";
|
||||
|
||||
/* Shift and down arrow combo keys */
|
||||
"key_shift+down" = "시프트 + ↓";
|
||||
|
||||
/* Backspace key */
|
||||
"key_backspace" = "⌫";
|
||||
|
||||
/* Hotkey to start a search */
|
||||
"hotkey_search" = "s";
|
||||
|
||||
/* Hotkey description to select next list item */
|
||||
"View next item" = "다음 항목 보기";
|
||||
|
||||
/* Hotkey description to select previous list item */
|
||||
"View previous item" = "이전 항목 보기";
|
||||
|
||||
/* Hotkey description to add next list item to selection */
|
||||
"Add next item to selection" = "선택 항목에 다음 항목 추가";
|
||||
|
||||
/* Hotkey description to add previous list item to selection */
|
||||
"Add previous item to selection" = "선택 항목에 이전 항목 추가";
|
||||
|
||||
/* Hotkey description to move backward in current view */
|
||||
"Move backward" = "뒤로 이동";
|
||||
|
||||
/* Hotkey description to move forward in current view */
|
||||
"Move forward" = "앞으로 이동";
|
||||
|
||||
/* Password Recovery */
|
||||
"passwordRecovery_Disabled" = "비활성화됨";
|
||||
"passwordRecovery_SecretQuestion" = "비밀 질문";
|
||||
"passwordRecovery_SecretQuestion1" = "첫 번째 반려동물의 이름은 무엇인가요?";
|
||||
"passwordRecovery_SecretQuestion2" = "첫 번째 자동차는 무엇이었나요?";
|
||||
"passwordRecovery_SecretQuestion3" = "가장 좋아하는 영화는 무엇인가요?";
|
||||
"passwordRecovery_SecondaryEmail" = "보조 이메일";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "최소 %{0}개의 소문자";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "최소 %{0}개의 대문자";
|
||||
"POLICY_MIN_DIGIT" = "최소 %{0}개의 숫자";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "최소 %{0}개의 특수 기호";
|
||||
"POLICY_MIN_LENGTH" = "최소 길이 %{0}자";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "Dodatkowy e-mail";
|
||||
|
||||
/* 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" = "Co najmniej %{0} małych liter";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "Co najmniej %{0} dużych liter";
|
||||
"POLICY_MIN_DIGIT" = "Co najmniej %{0} cyfr";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "Co najmniej %{0} znaków specjalnych";
|
||||
"POLICY_MIN_LENGTH" = "Długość co najmniej %{0} znaków";
|
||||
@@ -0,0 +1,242 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
/* toolbars */
|
||||
"Save" = "บันทึก";
|
||||
"Close" = "ปิด";
|
||||
"Edit User Rights" = "แก้ไขสิทธิผู้ใช้";
|
||||
"Home" = "บ้าน";
|
||||
"Calendar" = "ปฏิทิน";
|
||||
"Address Book" = "สมุดที่อยู่";
|
||||
"Mail" = "จดหมาย";
|
||||
"Preferences" = "การตั้งค่าที่ต้องการ";
|
||||
"Administration" = "การบริหาร";
|
||||
"Disconnect" = "ตัดการเชื่อมต่อ";
|
||||
"Toggle Menu" = "เปิด/ปิดเมนู";
|
||||
"Right Administration" = "การบริหารจัดการสิทธิ์";
|
||||
"Log Console (dev.)" = "คอนโซลบันทึก (dev.)";
|
||||
"User" = "ผู้ใช้";
|
||||
"Vacation message is enabled" = "ข้อความการพักผ่อนถูกเปิดใช้งาน";
|
||||
"Help" = "ช่วยเหลือ";
|
||||
"noJavascriptError" = "SOGo ต้องการ Javascript เพื่อให้ทำงาน โปรดตรวจสอบและเปิดใช้งานตัวเลือกนี้ภายในการตั้งค่าเบราว์เซอร์ของคุณ";
|
||||
"noJavascriptRetry" = "ลองใหม่";
|
||||
"Owner" = "เจ้าของ";
|
||||
"Publish the Free/Busy information" = "เผยแพร่ข้อมูลว่างเสรี/ไม่ว่างเสรี";
|
||||
"Add..." = "เพิ่ม...";
|
||||
"Remove" = "ลบ";
|
||||
"Subscribe User" = "สมัครสมาชิกผู้ใช้";
|
||||
"Any Authenticated User" = "ผู้ใช้ที่ได้รับการยืนยันตัวตนใด ๆ";
|
||||
"Public Access" = "การเข้าถึงสาธารณะ";
|
||||
"Any user not listed above" = "ผู้ใช้ที่ไม่ได้ระบุไว้ในรายชื่อด้านบน";
|
||||
"Anybody accessing this resource from the public area" = "ใครก็ตามที่เข้าถึงทรัพยากรนี้จากพื้นที่สาธารณะ";
|
||||
"Sorry, the user rights can not be configured for that object." = "ขอโทษครับ ไม่สามารถกำหนดสิทธิ์ผู้ใช้สำหรับวัตถุดังกล่าวได้";
|
||||
"Any user with an account on this system will be able to access your mailbox \"%{0}\". Are you certain you trust them all?"
|
||||
= "ใครก็ตามที่มีบัญชีบนระบบนี้จะสามารถเข้าถึงกล่องจดหมายของคุณ \"%{0}\" ได้ คุณแน่ใจหรือว่าคุณไว้ใจพวกเขาทั้งหมด?";
|
||||
"Any user with an account on this system will be able to access your calendar \"%{0}\". Are you certain you trust them all?"
|
||||
= "ใครก็ตามที่มีบัญชีบนระบบนี้จะสามารถเข้าถึงปฏิทินของคุณ \"%{0}\" ได้ คุณแน่ใจหรือว่าคุณไว้ใจพวกเขาทั้งหมด?";
|
||||
"Potentially anyone on the Internet will be able to access your calendar \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "ใครก็ตามบนอินเทอร์เน็ตอาจสามารถเข้าถึงปฏิทินของคุณ \"%{0}\" ได้ แม้ว่าพวกเขาจะไม่มีบัญชีในระบบนี้เลย ข้อมูลนี้เหมาะสำหรับอินเทอร์เน็ตสาธารณะหรือไม่?";
|
||||
"Any user with an account on this system will be able to access your address book \"%{0}\". Are you certain you trust them all?"
|
||||
= "ใครก็ตามที่มีบัญชีบนระบบนี้จะสามารถเข้าถึงสมุดที่อยู่ของคุณ \"%{0}\" ได้ คุณแน่ใจหรือว่าคุณไว้ใจพวกเขาทั้งหมด?";
|
||||
"Potentially anyone on the Internet will be able to access your address book \"%{0}\", even if they do not have an account on this system. Is this information suitable for the public Internet?"
|
||||
= "ใครก็ตามบนอินเทอร์เน็ตอาจสามารถเข้าถึงสมุดที่อยู่ของคุณ \"%{0}\" ได้ แม้ว่าพวกเขาจะไม่มีบัญชีในระบบนี้เลย ข้อมูลนี้เหมาะสำหรับอินเทอร์เน็ตสาธารณะหรือไม่?";
|
||||
"Give Access" = "ให้สิทธิ์เข้าถึง";
|
||||
"Keep Private" = "เก็บเป็นความลับ";
|
||||
"Expand" = "ขยาย";
|
||||
"Reduce" = "ลดลง";
|
||||
|
||||
/* tooltip */
|
||||
"Refresh" = "รีเฟรช";
|
||||
|
||||
/* generic.js */
|
||||
"Unable to subscribe to that folder!"
|
||||
= "ไม่สามารถสมัครสมาชิกในโฟลเดอร์นั้นได้!";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "คุณไม่สามารถสมัครสมาชิกในโฟลเดอร์ที่คุณเป็นเจ้าของ!";
|
||||
"Unable to unsubscribe from that folder!"
|
||||
= "ไม่สามารถยกเลิกการสมัครสมาชิกจากโฟลเดอร์นั้นได้!";
|
||||
"You cannot unsubscribe from a folder that you own!"
|
||||
= "คุณไม่สามารถยกเลิกการสมัครสมาชิกในโฟลเดอร์ที่คุณเป็นเจ้าของ!";
|
||||
"Unable to rename that folder!" = "ไม่สามารถเปลี่ยนชื่อโฟลเดอร์นั้นได้!";
|
||||
"You have already subscribed to that folder!"
|
||||
= "คุณได้สมัครสมาชิกในโฟลเดอร์นั้นแล้ว!";
|
||||
"The user rights cannot be edited for this object!"
|
||||
= "ไม่สามารถแก้ไขสิทธิ์ของผู้ใช้สำหรับวัตถุนี้ได้!";
|
||||
"A folder by that name already exists." = "มีโฟลเดอร์ด้วยชื่อนั้นอยู่แล้ว";
|
||||
"You cannot create a list in a shared address book."
|
||||
= "คุณไม่สามารถสร้างรายการในสมุดที่อยู่ร่วมกันได้";
|
||||
"Warning" = "คำเตือน";
|
||||
"Can't contact server" = "เกิดข้อผิดพลาดขึ้นในขณะที่ติดต่อกับเซิร์ฟเวอร์ โปรดลองอีกครั้งในภายหลัง";
|
||||
"You are not allowed to access this module or this system. Please contact your system administrator."
|
||||
= "คุณไม่ได้รับอนุญาตให้เข้าถึงโมดูลหรือระบบนี้ โปรดติดต่อผู้ดูแลระบบของคุณ";
|
||||
"You don't have the required privileges to perform the operation."
|
||||
= "คุณไม่มีสิทธิ์ที่จำเป็นในการดำเนินการ";
|
||||
"noEmailForDelegation" = "คุณต้องระบุที่อยู่ที่คุณต้องการมอบหมายให้กับคำเชิญของคุณ";
|
||||
"delegate is organizer" = "ผู้แทนเป็นผู้จัดงาน โปรดระบุผู้แทนอื่น";
|
||||
"delegate is a participant" = "ผู้แทนถูกเข้าร่วมอยู่แล้ว.";
|
||||
"delegate is a group" = "ที่อยู่ที่ระบุตรงกับกลุ่ม คุณสามารถมอบหมายให้กับบุคคลที่เป็นเอกลักษณ์เท่านั้น";
|
||||
|
||||
/* common buttons */
|
||||
"OK" = "ตกลง";
|
||||
"Cancel" = "ยกเลิก";
|
||||
"Yes" = "ใช่";
|
||||
"No" = "ไม่";
|
||||
|
||||
/* generic messages */
|
||||
"Error" = "ข้อผิดพลาด";
|
||||
"Success" = "สำเร็จ";
|
||||
|
||||
/* confirmation dialog box */
|
||||
"Confirmation" = "ยืนยัน";
|
||||
|
||||
/* alarms */
|
||||
"Reminder" = "เตือนความจำ";
|
||||
"Start" = "เริ่ม";
|
||||
"Due Date" = "วันครบกำหนด";
|
||||
"Location" = "สถานที่";
|
||||
"Snooze" = "หลับตา";
|
||||
"Snooze for " = "Snooze for";
|
||||
"5 minutes" = "5 นาที";
|
||||
"10 minutes" = "10 นาที";
|
||||
"15 minutes" = "15 นาที";
|
||||
"30 minutes" = "30 นาที";
|
||||
"45 minutes" = "45 นาที";
|
||||
"1 hour" = "1 ชั่วโมง";
|
||||
"1 day" = "1 วัน";
|
||||
|
||||
/* mail labels */
|
||||
"Important" = "สำคัญ";
|
||||
"Work" = "งาน";
|
||||
"Personal" = "ส่วนตัว";
|
||||
"To Do" = "ทำ";
|
||||
"Later" = "หลังจากนั้น";
|
||||
"Forwarded" = "ส่งต่อ";
|
||||
"Return Receipt Sent" = "ใบตอบรับการส่งได้รับแล้ว";
|
||||
"a2_Sunday" = "อา";
|
||||
"a2_Monday" = "จ";
|
||||
"a2_Tuesday" = "อ";
|
||||
"a2_Wednesday" = "พ";
|
||||
"a2_Thursday" = "พฤ";
|
||||
"a2_Friday" = "ศ";
|
||||
"a2_Saturday" = "ส";
|
||||
"Access Rights" = "สิทธิ์การเข้าถึง";
|
||||
"Add User" = "เพิ่มผู้ใช้";
|
||||
"Loading" = "โหลด";
|
||||
"No such user." = "ไม่มีผู้ใช้งานดังกล่าว";
|
||||
"You cannot (un)subscribe to a folder that you own!" = "คุณไม่สามารถสมัครสมาชิกในโฟลเดอร์ที่คุณเป็นเจ้าของ!";
|
||||
|
||||
/* SMIME Certificate field */
|
||||
"S/MIME Certificate" = "ใบรับรอง S/MIME";
|
||||
"Subject Name" = "ชื่อเรื่อง";
|
||||
"Issuer" = "ผู้ออก";
|
||||
"streetAddress" = "ถนน";
|
||||
"stateOrProvinceName" = "รัฐหรือจังหวัด";
|
||||
"localityName" = "สถานที่";
|
||||
"countryName" = "ประเทศ";
|
||||
"organizationName" = "องค์กร";
|
||||
"organizationalUnitName" = "หน่วยงานองค์กร";
|
||||
"commonName" = "ชื่อทั่วไป";
|
||||
"surname" = "นามสกุล";
|
||||
"givenName" = "ชื่อจริง";
|
||||
"emailAddress" = "ที่อยู่อีเมล์";
|
||||
|
||||
|
||||
/* Authentication username */
|
||||
"Username" = "ชื่อผู้ใช้";
|
||||
|
||||
/* Authentication password */
|
||||
"Password" = "รหัสผ่าน";
|
||||
|
||||
/* Authentication failed */
|
||||
"Wrong username or password." = "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง.";
|
||||
|
||||
/* Error message displayed bellow search field when the search string has less than the required number of characters */
|
||||
"Enter at least %{minimumSearchLength} characters" = "ป้อนอย่างน้อย %{minimumSearchLength} ตัวอักษร";
|
||||
|
||||
/* Error message displayed when a file upload exceeds WOMaxUploadSize */
|
||||
"File size upload limit reached" = "ขนาดไฟล์ที่อัปโหลดเกินขีดจำกัด";
|
||||
|
||||
/* Generic server error */
|
||||
"An error occured, please try again." = "เกิดข้อผิดพลาด โปรดลองอีกครั้ง";
|
||||
|
||||
/* Open datepicker */
|
||||
"Open Calendar" = "เปิดปฏิทิน";
|
||||
|
||||
/* Toggle visibility (ex: mail account in left navigation menu) */
|
||||
"Toggle visibility" = "เปลี่ยนการมองเห็น";
|
||||
|
||||
"Keyboard Shortcuts" = "แป้นพิมพ์ลัด";
|
||||
|
||||
/* Aria label for avatar button to select and unselect an item */
|
||||
"Toggle item" = "เปิด-ปิดรายการ";
|
||||
|
||||
/* Toggle multiple items at the same time (hotkeys cheatsheet) */
|
||||
"Toggle range of items" = "เปลี่ยนสถานะของรายการ";
|
||||
|
||||
/* Question mark shows list of hotkeys */
|
||||
"Show or hide this help" = "แสดงหรือซ่อนความช่วยเหลือนี้";
|
||||
|
||||
/* Space key */
|
||||
"key_space" = "พื้นที่";
|
||||
|
||||
/* Delete key */
|
||||
"key_delete" = "ลบ";
|
||||
|
||||
/* Shift and space key */
|
||||
"key_shift+space" = "shift + space";
|
||||
|
||||
/* Up arrow key */
|
||||
"key_up" = "↑";
|
||||
|
||||
/* Down arrow key */
|
||||
"key_down" = "↓";
|
||||
|
||||
/* Left arrow key */
|
||||
"key_left" = "←";
|
||||
|
||||
/* Right arrow key */
|
||||
"key_right" = "→";
|
||||
|
||||
/* Shift and up arrow combo keys */
|
||||
"key_shift+up" = "shift + ↑";
|
||||
|
||||
/* Shift and down arrow combo keys */
|
||||
"key_shift+down" = "shift + ↓";
|
||||
|
||||
/* Backspace key */
|
||||
"key_backspace" = "⌫";
|
||||
|
||||
/* Hotkey to start a search */
|
||||
"hotkey_search" = "s";
|
||||
|
||||
/* Hotkey description to select next list item */
|
||||
"View next item" = "ดูรายการถัดไป";
|
||||
|
||||
/* Hotkey description to select previous list item */
|
||||
"View previous item" = "ดูรายการก่อนหน้า";
|
||||
|
||||
/* Hotkey description to add next list item to selection */
|
||||
"Add next item to selection" = "เพิ่มรายการถัดไปในการเลือก";
|
||||
|
||||
/* Hotkey description to add previous list item to selection */
|
||||
"Add previous item to selection" = "เพิ่มรายการก่อนหน้านี้ในการเลือก";
|
||||
|
||||
/* Hotkey description to move backward in current view */
|
||||
"Move backward" = "ย้ายถอยหลัง";
|
||||
|
||||
/* Hotkey description to move forward in current view */
|
||||
"Move forward" = "เคลื่อนไปข้างหน้า";
|
||||
|
||||
/* Password Recovery */
|
||||
"passwordRecovery_Disabled" = "ปิดการใช้งาน";
|
||||
"passwordRecovery_SecretQuestion" = "คำถามลับ";
|
||||
"passwordRecovery_SecretQuestion1" = "ชื่อสัตว์เลี้ยงครั้งแรกของคุณคืออะไร?";
|
||||
"passwordRecovery_SecretQuestion2" = "คุณมีรถคันแรกของคุณอยู่ที่ไหน?";
|
||||
"passwordRecovery_SecretQuestion3" = "หนังเรื่องไหนเป็นหนังที่คุณชื่นชอบ?";
|
||||
"passwordRecovery_SecondaryEmail" = "อีเมลสำรอง";
|
||||
|
||||
/* Password */
|
||||
"POLICY_MIN_LOWERCASE_LETTER" = "อักษรตัวพิมพ์เล็กขั้นต่ำ %{0} ตัว";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "อักษรตัวตัวพิมพ์ใหญ่ขั้นต่ำ %{0} ตัว";
|
||||
"POLICY_MIN_DIGIT" = "ตัวเลขขั้นต่ำ %{0} หลัก";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "สัญลักษณ์พิเศษขั้นต่ำ %{0} ตัว";
|
||||
"POLICY_MIN_LENGTH" = "ความยาวขั้นต่ำ %{0} ตัว";
|
||||
@@ -235,8 +235,8 @@
|
||||
"passwordRecovery_SecondaryEmail" = "İkincil e-posta";
|
||||
|
||||
/* 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" = "En az %{0} küçük harf";
|
||||
"POLICY_MIN_UPPERCASE_LETTER" = "En az %{0} büyük harf";
|
||||
"POLICY_MIN_DIGIT" = "En az %{0} rakam";
|
||||
"POLICY_MIN_SPECIAL_SYMBOLS" = "En az %{0} özel simge";
|
||||
"POLICY_MIN_LENGTH" = "En az %{0} karakter uzunluğunda";
|
||||
@@ -193,7 +193,7 @@
|
||||
"Work" = "Werk";
|
||||
"Mobile" = "Mobiel";
|
||||
"Pager" = "Pieper";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuration profile";
|
||||
"Download iOS - MacOS configuration profile" = "Download iOS - MacOS configuratieprofiel";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "Collega, Concurrent, Klant, Vriend, Familie, Zakenpartner, Leverancier, Pers, VIP";
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Contact" = "연락처";
|
||||
"Address" = "주소";
|
||||
"Photos" = "사진";
|
||||
"Other" = "기타";
|
||||
"Address Books" = "주소록";
|
||||
"Addressbook" = "주소록";
|
||||
"Addresses" = "주소";
|
||||
"Update" = "업데이트";
|
||||
"Cancel" = "취소";
|
||||
"Common" = "공통";
|
||||
"Contact editor" = "연락처 편집기";
|
||||
"Contact viewer" = "연락처 뷰어";
|
||||
"Email" = "이메일";
|
||||
"Screen Name" = "스크린 이름";
|
||||
"Extended" = "확장";
|
||||
"Fax" = "팩스";
|
||||
"Firstname" = "이름";
|
||||
"Home" = "집";
|
||||
"HomePhone" = "집 전화";
|
||||
"Lastname" = "성";
|
||||
"Location" = "위치";
|
||||
"Add a category" = "카테고리 추가";
|
||||
"MobilePhone" = "휴대폰";
|
||||
"Name" = "이름";
|
||||
"OfficePhone" = "회사 전화";
|
||||
"Organization" = "기관";
|
||||
"Work Phone" = "직장 전화";
|
||||
"Cell" = "휴대폰";
|
||||
"Pager" = "호출기";
|
||||
"Pref" = "기본";
|
||||
"Phone" = "전화";
|
||||
"Phones" = "전화번호";
|
||||
"Postal" = "우편";
|
||||
"Save" = "저장";
|
||||
"Internet" = "인터넷";
|
||||
"Unit" = "단위";
|
||||
"delete" = "삭제";
|
||||
"edit" = "편집";
|
||||
"invalidemailwarn" = "지정된 이메일이 유효하지 않습니다";
|
||||
"new" = "새로 만들기";
|
||||
"Preferred Phone" = "기본 전화번호";
|
||||
"Move To" = "이동";
|
||||
"Copy To" = "복사";
|
||||
"Add to" = "추가";
|
||||
"To" = "받는 사람";
|
||||
"Carbon Copy (Cc)" = "참조 (Cc)";
|
||||
"Blind Carbon Copy (Bcc)" = "숨은 참조 (Bcc)";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"name" = "이름";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"c_cn" = "이름";
|
||||
|
||||
/* Search scope: secondary email field */
|
||||
"mozillanickname" = "보조 이메일";
|
||||
|
||||
/* Search scope: screen name field */
|
||||
"nsaimid" = "스크린 이름";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"mail" = "메일";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"c_mail" = "메일";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"telephonenumber" = "전화";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"homephone" = "전화";
|
||||
|
||||
/* Search scope: mobile field */
|
||||
"mobile" = "모바일";
|
||||
|
||||
/* Search scope: fax field */
|
||||
"facsimiletelephonenumber" = "팩스";
|
||||
|
||||
/* Search scope: pager field */
|
||||
"pager" = "호출기";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"c_categories" = "카테고리";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"vcardcategories" = "카테고리";
|
||||
|
||||
/* Search scope: title field */
|
||||
"title" = "직함";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"c_o" = "기관";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"o" = "기관";
|
||||
|
||||
/* Search scope: department field */
|
||||
"ou" = "부서";
|
||||
|
||||
/* Search scope: city field */
|
||||
"l" = "도시";
|
||||
|
||||
/* Search scope: country field */
|
||||
"c" = "국가";
|
||||
|
||||
/* Search scope: home address field */
|
||||
"mozillahomestreet" = "집 주소";
|
||||
|
||||
/* Search scope: state/province field */
|
||||
"st" = "주/도";
|
||||
|
||||
/* Search scope: home state/province field */
|
||||
"mozillahomestate" = "집 주/도";
|
||||
|
||||
/* Search scope: zip/postal code field */
|
||||
"postalCode" = "우편/우편번호";
|
||||
|
||||
/* Search scope: home zip/postal code field */
|
||||
"mozillahomepostalcode" = "우편/우편번호";
|
||||
|
||||
/* Search scope: home country field */
|
||||
"mozillahomecountryname" = "집 국가";
|
||||
|
||||
/* Search scope: home web page field */
|
||||
"mozillahomeurl" = "홈페이지";
|
||||
|
||||
/* Search scope: work web page field */
|
||||
"mozillaworkurl" = "웹 페이지";
|
||||
|
||||
/* Search scope: note field */
|
||||
"description" = "메모";
|
||||
|
||||
/* Subheader of empty addressbook */
|
||||
"No contact" = "연락처 없음";
|
||||
|
||||
/* Subheader of system addressbook */
|
||||
"Start a search to browse this address book" = "이 주소록을 탐색하려면 검색을 시작하십시오";
|
||||
|
||||
/* Number of contacts in addressbook; string is prefixed by number */
|
||||
"contacts" = "연락처";
|
||||
|
||||
/* No contact matching search criteria */
|
||||
"No matching contact" = "일치하는 연락처 없음";
|
||||
|
||||
/* Number of contacts matching search criteria; string is prefixed by number */
|
||||
"matching contacts" = "일치하는 연락처";
|
||||
|
||||
/* Number of selected contacts in list */
|
||||
"selected" = "선택됨";
|
||||
|
||||
/* Empty right pane */
|
||||
"No contact selected" = "선택된 연락처 없음";
|
||||
|
||||
/* Tooltips */
|
||||
"Create a new address book card" = "새 주소록 카드 만들기";
|
||||
"Create a new list" = "새 목록 만들기";
|
||||
"Edit the selected card" = "선택한 카드 편집";
|
||||
"Send a mail message" = "메일 메시지 보내기";
|
||||
"Delete selected card or address book" = "선택한 카드 또는 주소록 삭제";
|
||||
"Reload all contacts" = "모든 연락처 새로고침";
|
||||
"htmlMailFormat_UNKNOWN" = "알 수 없음";
|
||||
"htmlMailFormat_FALSE" = "일반 텍스트";
|
||||
"htmlMailFormat_TRUE" = "HTML";
|
||||
"Name or Email" = "이름 또는 이메일";
|
||||
"Category" = "카테고리";
|
||||
"Personal Addressbook" = "개인 주소록";
|
||||
"Search in Addressbook" = "주소록 검색";
|
||||
"New Card" = "새 카드";
|
||||
"New List" = "새 목록";
|
||||
"Edit" = "편집";
|
||||
"Properties" = "속성";
|
||||
"Sharing..." = "공유...";
|
||||
"Write" = "쓰기";
|
||||
"Delete" = "삭제";
|
||||
"Instant Message" = "인스턴트 메시지";
|
||||
"Add..." = "추가...";
|
||||
"Remove" = "제거";
|
||||
"Please wait..." = "기다려 주십시오...";
|
||||
"No possible subscription" = "구독할 수 없음";
|
||||
"Preferred" = "기본";
|
||||
"Display" = "표시";
|
||||
"Display Name" = "표시 이름";
|
||||
"Additional Email" = "추가 이메일";
|
||||
"Phone Number" = "전화번호";
|
||||
"Prefers to receive messages formatted as" = "선호하는 메시지 형식";
|
||||
"Categories" = "카테고리";
|
||||
"First" = "이름";
|
||||
"Last" = "성";
|
||||
"Nickname" = "별명";
|
||||
"Telephone" = "전화";
|
||||
"Work" = "직장";
|
||||
"Mobile" = "휴대폰";
|
||||
"Pager" = "호출기";
|
||||
"Download iOS - MacOS configuration profile" = "iOS - MacOS 구성 프로필 다운로드";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "동료, 경쟁사, 고객, 친구, 가족, 비즈니스 파트너, 공급업체, 언론, VIP";
|
||||
"New category" = "새 카테고리";
|
||||
|
||||
/* adresses */
|
||||
"Title" = "직함";
|
||||
"Service" = "서비스";
|
||||
"Company" = "회사";
|
||||
"Department" = "부서";
|
||||
"City" = "도시";
|
||||
"State_Province" = "주/도";
|
||||
"ZIP_Postal Code" = "우편/우편번호";
|
||||
"Country" = "국가";
|
||||
"Web Page" = "웹 페이지";
|
||||
"Other Infos" = "기타 정보";
|
||||
"Note" = "메모";
|
||||
"Timezone" = "시간대";
|
||||
"Birthday" = "생일";
|
||||
"Birthday (yyyy-mm-dd)" = "생일 (yyyy-mm-dd)";
|
||||
"Freebusy URL" = "약속 가능/불가능 URL";
|
||||
"Add as..." = "다음으로 추가...";
|
||||
"Recipient" = "받는 사람";
|
||||
"Carbon Copy" = "참조";
|
||||
"Blind Carbon Copy" = "숨은 참조";
|
||||
"New Addressbook..." = "새 주소록...";
|
||||
"Subscribe to an Addressbook..." = "주소록 구독...";
|
||||
"Remove the selected Addressbook" = "선택한 주소록 제거";
|
||||
"Subscribe to a shared contact" = "공유 주소록 구독";
|
||||
"Search User" = "사용자 검색";
|
||||
"Name of the Address Book" = "주소록 이름";
|
||||
"Are you sure you want to delete the selected address book?"
|
||||
= "선택한 주소록을 삭제하시겠습니까?";
|
||||
"Are you sure you want to delete the addressbook \"%{0}\"?"
|
||||
= "주소록 \"%{0}\"을 삭제하시겠습니까?";
|
||||
"You cannot remove nor unsubscribe from a public addressbook."
|
||||
= "공개 주소록은 제거하거나 구독 취소할 수 없습니다.";
|
||||
"You cannot remove nor unsubscribe from your personal addressbook."
|
||||
= "개인 주소록은 제거하거나 구독 취소할 수 없습니다.";
|
||||
"Are you sure you want to delete the selected contacts?"
|
||||
= "선택한 연락처를 삭제하시겠습니까?";
|
||||
"Are you sure you want to delete the card of %{0}?" = "%{0}의 카드를 삭제하시겠습니까?";
|
||||
"You cannot delete the card of \"%{0}\"."
|
||||
= "\"%{0}\"의 카드를 삭제할 수 없습니다.";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "소유하고 있는 폴더는 구독할 수 없습니다.";
|
||||
"Unable to subscribe to that folder!"
|
||||
= "해당 폴더를 구독할 수 없습니다.";
|
||||
|
||||
/* security */
|
||||
"Security" = "보안";
|
||||
"Uninstall" = "제거";
|
||||
"Error reading the card certificate." = "카드 인증서 읽기 오류.";
|
||||
"No certificate associated to card." = "카드와 연결된 인증서가 없습니다.";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "접근 권한 대상";
|
||||
"For user" = "사용자";
|
||||
"Any Authenticated User" = "모든 인증된 사용자";
|
||||
"Public Access" = "공개 접근";
|
||||
"This person can add cards to this addressbook."
|
||||
= "이 사람은 이 주소록에 카드를 추가할 수 있습니다.";
|
||||
"This person can edit the cards of this addressbook."
|
||||
= "이 사람은 이 주소록의 카드를 편집할 수 있습니다.";
|
||||
"This person can list the content of this addressbook."
|
||||
= "이 사람은 이 주소록의 내용을 나열할 수 있습니다.";
|
||||
"This person can read the cards of this addressbook."
|
||||
= "이 사람은 이 주소록의 카드를 읽을 수 있습니다.";
|
||||
"This person can erase cards from this addressbook."
|
||||
= "이 사람은 이 주소록에서 카드를 지울 수 있습니다.";
|
||||
"The selected contact has no email address."
|
||||
= "선택한 연락처에 이메일 주소가 없습니다.";
|
||||
"Please select a contact." = "연락처를 선택하십시오.";
|
||||
|
||||
/* Messages for move and copy */
|
||||
"%{0} card(s) copied" = "%{0}개 카드 복사됨";
|
||||
"%{0} card(s) moved" = "%{0}개 카드 이동됨";
|
||||
"SoAccessDeniedException" = "이 주소록에 쓸 수 없습니다.";
|
||||
"Forbidden" = "금지됨";
|
||||
"Invalid Contact" = "선택한 연락처가 더 이상 존재하지 않습니다.";
|
||||
"Unknown Destination Folder" = "선택한 대상 주소록이 더 이상 존재하지 않습니다.";
|
||||
|
||||
/* Lists */
|
||||
"List details" = "목록 세부 정보";
|
||||
"List name" = "목록 이름";
|
||||
"List nickname" = "목록 별명";
|
||||
"List description" = "목록 설명";
|
||||
"Members" = "회원";
|
||||
"Contacts" = "연락처";
|
||||
"Add" = "추가";
|
||||
"Lists can't be moved or copied." = "목록은 이동하거나 복사할 수 없습니다.";
|
||||
"Export" = "내보내기";
|
||||
"Export Address Book..." = "주소록 내보내기...";
|
||||
"View Raw Source" = "원본 내용 보기";
|
||||
|
||||
/* Import */
|
||||
"Import Cards" = "카드 가져오기";
|
||||
"Select a vCard or LDIF file." = "vCard 또는 LDIF 파일을 선택하십시오.";
|
||||
"Upload" = "업로드";
|
||||
"Uploading" = "업로드 중";
|
||||
"Done" = "완료";
|
||||
"An error occured while importing contacts." = "연락처 가져오기 중 오류가 발생했습니다.";
|
||||
"No card was imported." = "가져온 카드가 없습니다.";
|
||||
"A total of %{0} cards were imported in the addressbook." = "총 %{0}개의 카드가 주소록으로 가져와졌습니다.";
|
||||
"Reload" = "새로고침";
|
||||
|
||||
/* Properties window */
|
||||
"Address Book Name" = "주소록 이름";
|
||||
"Links to this Address Book" = "이 주소록 링크";
|
||||
"Authenticated User Access" = "인증된 사용자 접근";
|
||||
"CardDAV URL" = "CardDAV URL";
|
||||
"Options" = "옵션";
|
||||
"Rename" = "이름 변경";
|
||||
"Subscriptions" = "구독";
|
||||
"Global Addressbooks" = "전역 주소록";
|
||||
"Search" = "검색";
|
||||
"Sort" = "정렬";
|
||||
"Descending Order" = "내림차순";
|
||||
"Back" = "뒤로";
|
||||
"Select All" = "모두 선택";
|
||||
"Copy contacts" = "연락처 복사";
|
||||
"More messages options" = "더 많은 메시지 옵션";
|
||||
"New Contact" = "새 연락처";
|
||||
"Close" = "닫기";
|
||||
"More contact options" = "더 많은 연락처 옵션";
|
||||
"Organization Unit" = "조직 단위";
|
||||
"Add Organizational Unit" = "조직 단위 추가";
|
||||
"Type" = "유형";
|
||||
"Email Address" = "이메일 주소";
|
||||
"New Email Address" = "새 이메일 주소";
|
||||
"New Phone Number" = "새 전화번호";
|
||||
"URL" = "URL";
|
||||
"New URL" = "새 URL";
|
||||
"street" = "거리";
|
||||
"street (continued)" = "거리 (계속)";
|
||||
"Postoffice" = "우체국";
|
||||
"Region" = "지역";
|
||||
"Postal Code" = "우편번호";
|
||||
"New Address" = "새 주소";
|
||||
"Reset" = "재설정";
|
||||
"Description" = "설명";
|
||||
"Add Member" = "멤버 추가";
|
||||
"Subscribe" = "구독";
|
||||
"Add Birthday" = "생일 추가";
|
||||
"Import" = "가져오기";
|
||||
"More options" = "더 많은 옵션";
|
||||
"Role" = "역할";
|
||||
"Add Screen Name" = "스크린 이름 추가";
|
||||
"Custom 1" = "사용자 지정 1";
|
||||
"Custom 2" = "사용자 지정 2";
|
||||
"Custom 3" = "사용자 지정 3";
|
||||
"Custom 4" = "사용자 지정 4";
|
||||
"Custom Value" = "사용자 지정 값";
|
||||
"New Custom Value" = "새 사용자 지정 값";
|
||||
"Synchronization" = "동기화";
|
||||
"Synchronize" = "동기화";
|
||||
"Sucessfully subscribed to address book" = "주소록 구독 성공";
|
||||
"A similar card already exists. Would you like to save it anyway?" = "유사한 카드가 이미 존재합니다. 그래도 저장하시겠습니까?";
|
||||
|
||||
/* Aria label for scope of search on contacts */
|
||||
"Search scope" = "검색 범위";
|
||||
|
||||
/* Aria label for avatar button to select and unselect a card */
|
||||
"Toggle item" = "항목 전환";
|
||||
|
||||
/* Hotkey to create a new card */
|
||||
"key_create_card" = "c";
|
||||
|
||||
/* Hotkey to create a new list */
|
||||
"key_create_list" = "l";
|
||||
@@ -0,0 +1,366 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
"Contact" = "ผู้ติดต่อ";
|
||||
"Address" = "ที่อยู่";
|
||||
"Photos" = "รูปภาพ";
|
||||
"Other" = "อื่นๆ";
|
||||
"Address Books" = "สมุดรายชื่อ";
|
||||
"Addressbook" = "สมุดที่อยู่";
|
||||
"Addresses" = "ที่อยู่";
|
||||
"Update" = "อัปเดต";
|
||||
"Cancel" = "ยกเลิก";
|
||||
"Common" = "ทั่วไป";
|
||||
"Contact editor" = "ติดต่อบรรณาธิการ";
|
||||
"Contact viewer" = "ผู้ดูแลรายชื่อติดต่อ";
|
||||
"Email" = "อีเมล";
|
||||
"Screen Name" = "ชื่อหน้าจอ";
|
||||
"Extended" = "ขยายออก";
|
||||
"Fax" = "แฟกซ์";
|
||||
"Firstname" = "ชื่อจริง";
|
||||
"Home" = "บ้าน";
|
||||
"HomePhone" = "โทรศัพท์บ้าน";
|
||||
"Lastname" = "นามสกุล";
|
||||
"Location" = "สถานที่";
|
||||
"Add a category" = "เพิ่มหมวดหมู่";
|
||||
"MobilePhone" = "โทรศัพท์มือถือ";
|
||||
"Name" = "ชื่อ";
|
||||
"OfficePhone" = "โทรศัพท์ในสำนักงาน";
|
||||
"Organization" = "องค์กร";
|
||||
"Work Phone" = "โทรศัพท์ที่ใช้ในการทำงาน";
|
||||
"Cell" = "เซลล์";
|
||||
"Pager" = "เพจเจอร์";
|
||||
"Pref" = "การตั้งค่า";
|
||||
"Phone" = "โทรศัพท์";
|
||||
"Phones" = "โทรศัพท์";
|
||||
"Postal" = "ไปรษณีย์";
|
||||
"Save" = "บันทึก";
|
||||
"Internet" = "อินเทอร์เน็ต";
|
||||
"Unit" = "หน่วย";
|
||||
"delete" = "ลบ";
|
||||
"edit" = "แก้ไข";
|
||||
"invalidemailwarn" = "ระบุอีเมลที่ระบุไม่ถูกต้อง";
|
||||
"new" = "ใหม่";
|
||||
"Preferred Phone" = "โทรศัพท์ที่ต้องการ";
|
||||
"Move To" = "ย้ายไป";
|
||||
"Copy To" = "คัดลอกไปยัง";
|
||||
"Add to" = "เพิ่มเข้าไป";
|
||||
"To" = "ถึง";
|
||||
"Carbon Copy (Cc)" = "คัดลอกคาร์บอน (Cc)";
|
||||
"Blind Carbon Copy (Bcc)" = "สำเนาบนซองที่มองไม่เห็น (Bcc)";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"name" = "ชื่อ";
|
||||
|
||||
/* Search scope: name fields */
|
||||
"c_cn" = "ชื่อ";
|
||||
|
||||
/* Search scope: secondary email field */
|
||||
"mozillanickname" = "อีเมลสำรอง";
|
||||
|
||||
/* Search scope: screen name field */
|
||||
"nsaimid" = "ชื่อหน้าจอ";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"mail" = "อีเมล";
|
||||
|
||||
/* Search scope: mail fields */
|
||||
"c_mail" = "อีเมล";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"telephonenumber" = "โทรศัพท์";
|
||||
|
||||
/* Search scope: telephone field */
|
||||
"homephone" = "โทรศัพท์";
|
||||
|
||||
/* Search scope: mobile field */
|
||||
"mobile" = "มือถือ";
|
||||
|
||||
/* Search scope: fax field */
|
||||
"facsimiletelephonenumber" = "แฟกซ์";
|
||||
|
||||
/* Search scope: pager field */
|
||||
"pager" = "เพจเจอร์";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"c_categories" = "หมวดหมู่";
|
||||
|
||||
/* Search scope: categories field */
|
||||
"vcardcategories" = "หมวดหมู่";
|
||||
|
||||
/* Search scope: title field */
|
||||
"title" = "หัวข้อ";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"c_o" = "องค์กร";
|
||||
|
||||
/* Search scope: organization field */
|
||||
"o" = "องค์กร";
|
||||
|
||||
/* Search scope: department field */
|
||||
"ou" = "แผนก";
|
||||
|
||||
/* Search scope: city field */
|
||||
"l" = "เมือง";
|
||||
|
||||
/* Search scope: country field */
|
||||
"c" = "ประเทศ";
|
||||
|
||||
/* Search scope: home address field */
|
||||
"mozillahomestreet" = "ที่อยู่บ้าน";
|
||||
|
||||
/* Search scope: state/province field */
|
||||
"st" = "รัฐ/จังหวัด";
|
||||
|
||||
/* Search scope: home state/province field */
|
||||
"mozillahomestate" = "รัฐ/จังหวัดบ้าน";
|
||||
|
||||
/* Search scope: zip/postal code field */
|
||||
"postalCode" = "รหัสไปรษณีย์";
|
||||
|
||||
/* Search scope: home zip/postal code field */
|
||||
"mozillahomepostalcode" = "รหัสไปรษณีย์";
|
||||
|
||||
/* Search scope: home country field */
|
||||
"mozillahomecountryname" = "ประเทศบ้าน";
|
||||
|
||||
/* Search scope: home web page field */
|
||||
"mozillahomeurl" = "หน้าหลัก";
|
||||
|
||||
/* Search scope: work web page field */
|
||||
"mozillaworkurl" = "หน้าเว็บ";
|
||||
|
||||
/* Search scope: note field */
|
||||
"description" = "หมายเหตุ";
|
||||
|
||||
/* Subheader of empty addressbook */
|
||||
"No contact" = "ไม่มีการติดต่อ";
|
||||
|
||||
/* Subheader of system addressbook */
|
||||
"Start a search to browse this address book" = "เริ่มการค้นหาเพื่อเรียกดูสมุดที่อยู่นี้";
|
||||
|
||||
/* Number of contacts in addressbook; string is prefixed by number */
|
||||
"contacts" = "ผู้ติดต่อ";
|
||||
|
||||
/* No contact matching search criteria */
|
||||
"No matching contact" = "ไม่พบผู้ติดต่อที่ตรงกัน";
|
||||
|
||||
/* Number of contacts matching search criteria; string is prefixed by number */
|
||||
"matching contacts" = "การจับคู่ผู้ติดต่อ";
|
||||
|
||||
/* Number of selected contacts in list */
|
||||
"selected" = "เลือก";
|
||||
|
||||
/* Empty right pane */
|
||||
"No contact selected" = "ไม่มีการเลือกติดต่อ";
|
||||
|
||||
/* Tooltips */
|
||||
"Create a new address book card" = "สร้างบัตรสมุดที่อยู่ใหม่";
|
||||
"Create a new list" = "สร้างรายการใหม่";
|
||||
"Edit the selected card" = "แก้ไขการ์ดที่เลือก";
|
||||
"Send a mail message" = "ส่งข้อความอีเมล์";
|
||||
"Delete selected card or address book" = "ลบบัตรหรือสมุดที่อยู่ที่เลือก";
|
||||
"Reload all contacts" = "โหลดข้อมูลทั้งหมดใหม่";
|
||||
"htmlMailFormat_UNKNOWN" = "ไม่ทราบ";
|
||||
"htmlMailFormat_FALSE" = "ข้อความธรรมดา";
|
||||
"htmlMailFormat_TRUE" = "HTML";
|
||||
"Name or Email" = "ชื่อหรืออีเมล์";
|
||||
"Category" = "หมวดหมู่";
|
||||
"Personal Addressbook" = "สมุดที่อยู่ส่วนตัว";
|
||||
"Search in Addressbook" = "ค้นหาในสมุดที่อยู่";
|
||||
"New Card" = "บัตรใหม่";
|
||||
"New List" = "รายการใหม่";
|
||||
"Edit" = "แก้ไข";
|
||||
"Properties" = "คุณสมบัติ";
|
||||
"Sharing..." = "แชร์...";
|
||||
"Write" = "เขียน";
|
||||
"Delete" = "ลบ";
|
||||
"Instant Message" = "ข้อความสารบัญ: ข้อความทันที";
|
||||
"Add..." = "เพิ่ม...";
|
||||
"Remove" = "ลบ";
|
||||
"Please wait..." = "กรุณารอสักครู่...";
|
||||
"No possible subscription" = "ไม่มีการสมัครสมาชิกเป็นไปได้";
|
||||
"Preferred" = "ต้องการ";
|
||||
"Display" = "แสดงผล";
|
||||
"Display Name" = "ชื่อที่แสดง";
|
||||
"Additional Email" = "อีเมลเพิ่มเติม";
|
||||
"Phone Number" = "หมายเลขโทรศัพท์";
|
||||
"Prefers to receive messages formatted as" = "ต้องการรับข้อความที่จัดรูปแบบเป็น";
|
||||
"Categories" = "หมวดหมู่";
|
||||
"First" = "แรก";
|
||||
"Last" = "สุดท้าย";
|
||||
"Nickname" = "ชื่อเล่น";
|
||||
"Telephone" = "โทรศัพท์";
|
||||
"Work" = "งาน";
|
||||
"Mobile" = "มือถือ";
|
||||
"Pager" = "เพจเจอร์";
|
||||
"Download iOS - MacOS configuration profile" = "ดาวน์โหลดโปรไฟล์การกำหนดค่า iOS - MacOS";
|
||||
|
||||
/* categories */
|
||||
"contacts_category_labels" = "เพื่อนร่วมงาน, คู่แข่ง, ลูกค้า, เพื่อน, ครอบครัว, พันธมิตรทางธุรกิจ, ผู้ให้บริการ, สื่อ, บุคคลสำคัญ";
|
||||
"New category" = "หมวดหมู่ใหม่";
|
||||
|
||||
/* adresses */
|
||||
"Title" = "หัวข้อ";
|
||||
"Service" = "บริการ";
|
||||
"Company" = "บริษัท";
|
||||
"Department" = "แผนก";
|
||||
"City" = "เมือง";
|
||||
"State_Province" = "รัฐ/จังหวัด";
|
||||
"ZIP_Postal Code" = "รหัสไปรษณีย์";
|
||||
"Country" = "ประเทศ";
|
||||
"Web Page" = "หน้าเว็บ";
|
||||
"Other Infos" = "อื่น ๆ ข้อมูล";
|
||||
"Note" = "หมายเหตุ";
|
||||
"Timezone" = "เขตเวลา";
|
||||
"Birthday" = "วันเกิด";
|
||||
"Birthday (yyyy-mm-dd)" = "วันเกิด (yyyy-mm-dd)";
|
||||
"Freebusy URL" = "URL ที่สามารถใช้งานได้ฟรี";
|
||||
"Add as..." = "เพิ่มเป็น...";
|
||||
"Recipient" = "ผู้รับ";
|
||||
"Carbon Copy" = "สำเนาคาร์บอน";
|
||||
"Blind Carbon Copy" = "สำเนาบนซองอีเมล";
|
||||
"New Addressbook..." = "สมุดที่อยู่ใหม่...";
|
||||
"Subscribe to an Addressbook..." = "รับข้อมูลอัปเดตจากสมุดรายชื่อ...";
|
||||
"Remove the selected Addressbook" = "ลบสมุดรายชื่อที่เลือก";
|
||||
"Subscribe to a shared contact" = "สมัครสมาชิกสมุดรายชื่อที่ใช้ร่วมกัน";
|
||||
"Search User" = "ค้นหาผู้ใช้";
|
||||
"Name of the Address Book" = "ชื่อสมุดที่อยู่";
|
||||
"Are you sure you want to delete the selected address book?"
|
||||
= "คุณแน่ใจหรือว่าต้องการลบสมุดที่อยู่ที่เลือกไว้?";
|
||||
"Are you sure you want to delete the addressbook \"%{0}\"?"
|
||||
= "คุณแน่ใจหรือไม่ว่าต้องการลบสมุดที่อยู่ \"%{0}\"?";
|
||||
"You cannot remove nor unsubscribe from a public addressbook."
|
||||
= "คุณไม่สามารถลบหรือยกเลิกการสมัครสมาชิกจากสมุดที่อยู่สาธารณะได้";
|
||||
"You cannot remove nor unsubscribe from your personal addressbook."
|
||||
= "คุณไม่สามารถลบหรือยกเลิกการสมัครสมาชิกจากสมุดที่อยู่ส่วนตัวของคุณได้";
|
||||
"Are you sure you want to delete the selected contacts?"
|
||||
= "คุณแน่ใจหรือว่าต้องการลบรายชื่อที่เลือกไว้?";
|
||||
"Are you sure you want to delete the card of %{0}?" = "คุณแน่ใจหรือไม่ว่าต้องการลบบัตรของ %{0}?";
|
||||
"You cannot delete the card of \"%{0}\"."
|
||||
= "คุณไม่สามารถลบบัตรของ \"%{0}\" ได้";
|
||||
"You cannot subscribe to a folder that you own!"
|
||||
= "คุณไม่สามารถสมัครสมาชิกในโฟลเดอร์ที่คุณเป็นเจ้าของ!";
|
||||
"Unable to subscribe to that folder!"
|
||||
= "ไม่สามารถสมัครสมาชิกในโฟลเดอร์นั้นได้.";
|
||||
|
||||
/* security */
|
||||
"Security" = "ความปลอดภัย";
|
||||
"Uninstall" = "ถอนการติดตั้ง";
|
||||
"Error reading the card certificate." = "ข้อผิดพลาดในการอ่านใบรับรองของบัตร";
|
||||
"No certificate associated to card." = "ไม่มีใบรับรองที่เกี่ยวข้องกับบัตร";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "สิทธิ์การเข้าถึง";
|
||||
"For user" = "สำหรับผู้ใช้";
|
||||
"Any Authenticated User" = "ผู้ใช้ที่ได้รับการยืนยันตัวตนใด ๆ";
|
||||
"Public Access" = "การเข้าถึงสาธารณะ";
|
||||
"This person can add cards to this addressbook."
|
||||
= "บุคคลนี้สามารถเพิ่มบัตรเข้าสู่สมุดที่อยู่นี้ได้";
|
||||
"This person can edit the cards of this addressbook."
|
||||
= "บุคคลนี้สามารถแก้ไขบัตรของสมุดที่อยู่นี้ได้";
|
||||
"This person can list the content of this addressbook."
|
||||
= "บุคคลนี้สามารถรายการเนื้อหาของสมุดที่อยู่นี้ได้";
|
||||
"This person can read the cards of this addressbook."
|
||||
= "บุคคลนี้สามารถอ่านบัตรของสมุดที่อยู่นี้ได้.";
|
||||
"This person can erase cards from this addressbook."
|
||||
= "บุคคลนี้สามารถลบบัตรออกจากสมุดที่อยู่นี้ได้.";
|
||||
"The selected contact has no email address."
|
||||
= "ผู้ติดต่อที่เลือกไม่มีที่อยู่อีเมล์";
|
||||
"Please select a contact." = "โปรดเลือกติดต่อ";
|
||||
|
||||
/* Messages for move and copy */
|
||||
"%{0} card(s) copied" = "มีการคัดลอกบัตร %{0} ใบ";
|
||||
"%{0} card(s) moved" = "มีการย้ายบัตร %{0} ใบ";
|
||||
"SoAccessDeniedException" = "คุณไม่สามารถเขียนไปยังสมุดที่อยู่นี้ได้";
|
||||
"Forbidden" = "เข้าถึงไม่ได้";
|
||||
"Invalid Contact" = "คุณติดต่อที่เลือกไม่มีอยู่แล้ว";
|
||||
"Unknown Destination Folder" = "ที่อยู่สมุดที่เลือกไว้ไม่มีอยู่แล้ว";
|
||||
|
||||
/* Lists */
|
||||
"List details" = "รายละเอียดรายการ";
|
||||
"List name" = "ชื่อรายการ";
|
||||
"List nickname" = "รายชื่อเล่น";
|
||||
"List description" = "รายละเอียดของรายการ";
|
||||
"Members" = "สมาชิก";
|
||||
"Contacts" = "ผู้ติดต่อ";
|
||||
"Add" = "เพิ่ม";
|
||||
"Lists can't be moved or copied." = "รายการไม่สามารถย้ายหรือคัดลอกได้";
|
||||
"Export" = "ส่งออก";
|
||||
"Export Address Book..." = "ส่งออกสมุดที่อยู่...";
|
||||
"View Raw Source" = "ดูแหล่งที่มาแบบเรียลไทม์";
|
||||
|
||||
/* Import */
|
||||
"Import Cards" = "นำเข้าการ์ด";
|
||||
"Select a vCard or LDIF file." = "เลือกไฟล์ vCard หรือ LDIF";
|
||||
"Upload" = "อัปโหลด";
|
||||
"Uploading" = "กำลังอัปโหลด";
|
||||
"Done" = "เสร็จแล้ว";
|
||||
"An error occured while importing contacts." = "เกิดข้อผิดพลาดขณะนำเข้ารายชื่อผู้ติดต่อ";
|
||||
"No card was imported." = "ไม่มีการนำเข้าบัตร";
|
||||
"A total of %{0} cards were imported in the addressbook." = "จำนวนทั้งหมด %{0} บัตรถูกนำเข้าในสมุดที่อยู่";
|
||||
"Reload" = "รีโหลด";
|
||||
|
||||
/* Properties window */
|
||||
"Address Book Name" = "ชื่อสมุดที่อยู่";
|
||||
"Links to this Address Book" = "ลิงค์ไปยังสมุดที่อยู่นี้";
|
||||
"Authenticated User Access" = "การเข้าถึงผู้ใช้ที่ได้รับการรับรองแล้ว";
|
||||
"CardDAV URL" = "CardDAV URL";
|
||||
"Options" = "ตัวเลือก";
|
||||
"Rename" = "เปลี่ยนชื่อ";
|
||||
"Subscriptions" = "การสมัครสมาชิก";
|
||||
"Global Addressbooks" = "สมุดที่อยู่อีเมลทั่วไป";
|
||||
"Search" = "ค้นหา";
|
||||
"Sort" = "เรียงลำดับ";
|
||||
"Descending Order" = "ลำดับจากมากไปน้อย";
|
||||
"Back" = "กลับ";
|
||||
"Select All" = "เลือกทั้งหมด";
|
||||
"Copy contacts" = "คัดลอกที่ติดต่อ";
|
||||
"More messages options" = "ตัวเลือกข้อความเพิ่มเติม";
|
||||
"New Contact" = "ติดต่อใหม่";
|
||||
"Close" = "ปิด";
|
||||
"More contact options" = "ตัวเลือกการติดต่อเพิ่มเติม";
|
||||
"Organization Unit" = "หน่วยงานองค์กร";
|
||||
"Add Organizational Unit" = "เพิ่มหน่วยงานองค์กร";
|
||||
"Type" = "ประเภท";
|
||||
"Email Address" = "ที่อยู่อีเมล์";
|
||||
"New Email Address" = "ที่อยู่อีเมลใหม่";
|
||||
"New Phone Number" = "หมายเลขโทรศัพท์ใหม่";
|
||||
"URL" = "URL";
|
||||
"New URL" = "New URL";
|
||||
"street" = "ถนน";
|
||||
"street (continued)" = "ถนน (ต่อไป)";
|
||||
"Postoffice" = "ไปรษณีย์";
|
||||
"Region" = "ภูมิภาค";
|
||||
"Postal Code" = "รหัสไปรษณีย์";
|
||||
"New Address" = "ที่อยู่ใหม่";
|
||||
"Reset" = "รีเซ็ต";
|
||||
"Description" = "คำอธิบาย";
|
||||
"Add Member" = "เพิ่มสมาชิก";
|
||||
"Subscribe" = "สมัครสมาชิก";
|
||||
"Add Birthday" = "เพิ่มวันเกิด";
|
||||
"Import" = "นำเข้า";
|
||||
"More options" = "ตัวเลือกเพิ่มเติม";
|
||||
"Role" = "บทบาท";
|
||||
"Add Screen Name" = "เพิ่มชื่อหน้าจอ";
|
||||
"Custom 1" = "กำหนดเอง 1";
|
||||
"Custom 2" = "กำหนดเอง 2";
|
||||
"Custom 3" = "กำหนดเอง 3";
|
||||
"Custom 4" = "กำหนดเอง 4";
|
||||
"Custom Value" = "ค่าที่กำหนดเอง";
|
||||
"New Custom Value" = "ค่าที่กำหนดเองใหม่";
|
||||
"Synchronization" = "การประสานข้อมูล";
|
||||
"Synchronize" = "ซิงโครไนซ์";
|
||||
"Sucessfully subscribed to address book" = "สมัครสมาชิกที่สมุดที่อยู่เรียบร้อยแล้ว";
|
||||
"A similar card already exists. Would you like to save it anyway?" = "มีบัตรที่คล้ายกันอยู่แล้ว คุณต้องการบันทึกมันอยู่หรือไม่?";
|
||||
|
||||
/* Aria label for scope of search on contacts */
|
||||
"Search scope" = "ขอบเขตการค้นหา";
|
||||
|
||||
/* Aria label for avatar button to select and unselect a card */
|
||||
"Toggle item" = "เปิด-ปิดรายการ";
|
||||
|
||||
/* Hotkey to create a new card */
|
||||
"key_create_card" = "c";
|
||||
|
||||
/* Hotkey to create a new list */
|
||||
"key_create_list" = "l";
|
||||
@@ -78,6 +78,14 @@
|
||||
NSArray *cats, *newCats, *contactCategories;
|
||||
|
||||
ownerLogin = [[self clientObject] ownerInContext: context];
|
||||
//if ownerLogin == @"nobody", meaning the current folder is not the personnal source of the user (it's the global address book)
|
||||
//No need to fetch the user "nobody". Beware that if someone is really called nobody...
|
||||
if([ownerLogin isEqualToString:@"nobody"])
|
||||
{
|
||||
cats = [self _languageContactsCategories];
|
||||
return cats;
|
||||
}
|
||||
|
||||
ud = [[SOGoUser userWithLogin: ownerLogin] userDefaults];
|
||||
cats = [ud contactsCategories];
|
||||
if (!cats)
|
||||
@@ -85,16 +93,16 @@
|
||||
|
||||
contactCategories = [card categories];
|
||||
if (contactCategories)
|
||||
{
|
||||
newCats = [cats mergedArrayWithArray: [contactCategories trimmedComponents]];
|
||||
if ([newCats count] != [cats count])
|
||||
{
|
||||
cats = [newCats sortedArrayUsingSelector:
|
||||
@selector (localizedCaseInsensitiveCompare:)];
|
||||
[ud setContactsCategories: cats];
|
||||
[ud synchronize];
|
||||
}
|
||||
}
|
||||
{
|
||||
newCats = [cats mergedArrayWithArray: [contactCategories trimmedComponents]];
|
||||
if ([newCats count] != [cats count])
|
||||
{
|
||||
cats = [newCats sortedArrayUsingSelector:
|
||||
@selector (localizedCaseInsensitiveCompare:)];
|
||||
[ud setContactsCategories: cats];
|
||||
[ud synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
return cats;
|
||||
}
|
||||
|
||||
@@ -47,4 +47,4 @@ reply_info = "Dit is een antwoord op een door u verstuurde uitnodiging.";
|
||||
"OK" = "OK";
|
||||
"Comment" = "Commentaar:";
|
||||
"Description" = "Omschrijving";
|
||||
"Location" = "Location";
|
||||
"Location" = "Locatie";
|
||||
@@ -0,0 +1,50 @@
|
||||
ACCEPTED = "수락됨";
|
||||
COMPLETED = "완료됨";
|
||||
DECLINED = "거절됨";
|
||||
DELEGATED = "위임됨";
|
||||
"IN-PROCESS" = "진행 중";
|
||||
"NEEDS-ACTION" = "조치 필요";
|
||||
TENTATIVE = "미정";
|
||||
organized_by_you = "귀하가 주최함";
|
||||
you_are_an_attendee = "귀하는 참석자입니다";
|
||||
add_info_text = "iMIP '추가' 요청은 아직 SOGo에서 지원되지 않습니다.";
|
||||
publish_info_text = "보낸 사람이 첨부된 이벤트를 알려드립니다.";
|
||||
cancel_info_text = "귀하의 초대 또는 전체 이벤트가 취소되었습니다.";
|
||||
request_info_no_attendee = "참석자에게 회의를 제안합니다. 귀하는 알림으로 이 메일을 받으셨으며, 참가자로 예정되지 않았습니다.";
|
||||
Appointment = "약속";
|
||||
"Status Update" = "상태 업데이트";
|
||||
was = "였습니다";
|
||||
|
||||
Organizer = "주최자";
|
||||
Time = "시간";
|
||||
Attendees = "참석자";
|
||||
request_info = "회의에 귀하를 초대합니다.";
|
||||
"Add to calendar" = "캘린더에 추가";
|
||||
"Delete from calendar" = "캘린더에서 삭제";
|
||||
"Update status" = "상태 업데이트";
|
||||
Accept = "수락";
|
||||
Decline = "거절";
|
||||
Tentative = "미정";
|
||||
"Delegate ..." = "위임...";
|
||||
"Delegated to" = "위임 대상";
|
||||
"Update status in calendar" = "캘린더에서 상태 업데이트";
|
||||
"delegated from" = "위임됨";
|
||||
reply_info_no_attendee = "일정 이벤트에 대한 회신을 받았지만 회신 보낸 사람은 참가자가 아닙니다.";
|
||||
reply_info = "이것은 귀하가 보낸 이벤트 초대에 대한 회신입니다.";
|
||||
"to" = "받는 사람";
|
||||
"Untitled" = "제목 없음";
|
||||
"Size" = "크기";
|
||||
"Subject" = "제목";
|
||||
"From" = "보낸 사람";
|
||||
"Date" = "날짜";
|
||||
"To" = "받는 사람";
|
||||
"Issuer" = "발급자";
|
||||
/* Tooltips */
|
||||
"View Attachment" = "첨부 파일 보기";
|
||||
"Save Attachment" = "첨부 파일 저장";
|
||||
"CC" = "참조";
|
||||
"Cancel" = "취소";
|
||||
"OK" = "확인";
|
||||
"Comment" = "설명";
|
||||
"Description" = "설명";
|
||||
"Location" = "장소";
|
||||
@@ -47,4 +47,4 @@ reply_info = "To jest odpowiedź do utworzonego przez ciebie wydarzenia";
|
||||
"OK" = "OK";
|
||||
"Comment" = "Komentarz";
|
||||
"Description" = "Opis";
|
||||
"Location" = "Location";
|
||||
"Location" = "Położenie";
|
||||
@@ -0,0 +1,50 @@
|
||||
ACCEPTED = "ยอมรับ";
|
||||
COMPLETED = "เสร็จสิ้น";
|
||||
DECLINED = "ปฏิเสธ";
|
||||
DELEGATED = "มอบหมายงาน";
|
||||
"IN-PROCESS" = "ในกระบวนการ";
|
||||
"NEEDS-ACTION" = "ต้องการการดำเนินการ";
|
||||
TENTATIVE = "ไม่สามารถแปลได้";
|
||||
organized_by_you = "จัดระเบียบโดยคุณ";
|
||||
you_are_an_attendee = "คุณเป็นผู้เข้าร่วม";
|
||||
add_info_text = "iMIP 'ADD' ยังไม่ได้รับการสนับสนุนโดย SOGo.";
|
||||
publish_info_text = "ผู้ส่งข้อมูลแจ้งให้คุณทราบเกี่ยวกับเหตุการณ์ที่แนบมา";
|
||||
cancel_info_text = "คำเชิญของคุณหรืองานทั้งหมดถูกยกเลิก";
|
||||
request_info_no_attendee = "เสนอการประชุมกับผู้เข้าร่วม คุณได้รับอีเมลนี้เป็นการแจ้งเตือน คุณไม่ได";
|
||||
Appointment = "การนัดหมาย";
|
||||
"Status Update" = "สถานะการอัปเดต";
|
||||
was = "ก่อนหน้านี้";
|
||||
|
||||
Organizer = "ผู้จัดงาน";
|
||||
Time = "เวลา";
|
||||
Attendees = "ผู้เข้าร่วม";
|
||||
request_info = "เชิญคุณมาร่วมประชุม";
|
||||
"Add to calendar" = "เพิ่มลงในปฏิทิน";
|
||||
"Delete from calendar" = "ลบจากปฏิทิน";
|
||||
"Update status" = "อัปเดตสถานะ";
|
||||
Accept = "ยอมรับ";
|
||||
Decline = "ปฏิเสธ";
|
||||
Tentative = "ไม่สามารถแปลได้";
|
||||
"Delegate ..." = "มอบหมายงาน ...";
|
||||
"Delegated to" = "มอบหมายงานให้";
|
||||
"Update status in calendar" = "อัปเดตสถานะในปฏิทิน";
|
||||
"delegated from" = "มอบหมายโดย";
|
||||
reply_info_no_attendee = "คุณได้รับการตอบกลับเกี่ยวกับกิจกรรมการจัดตารางแต่ผู้ส่งการตอบกลับไม่ใช่ผู้เข้าร่วม";
|
||||
reply_info = "นี่คือการตอบกลับเชิญเข้าร่วมกิจกรรมที่คุณทำ";
|
||||
"to" = "ถึง";
|
||||
"Untitled" = "ไม่มีชื่อ";
|
||||
"Size" = "ขนาด";
|
||||
"Subject" = "หัวข้อ";
|
||||
"From" = "จาก";
|
||||
"Date" = "วันที่";
|
||||
"To" = "ถึง";
|
||||
"Issuer" = "ผู้ออก";
|
||||
/* Tooltips */
|
||||
"View Attachment" = "ดูไฟล์แนบ";
|
||||
"Save Attachment" = "บันทึกไฟล์แนบ";
|
||||
"CC" = "CC";
|
||||
"Cancel" = "ยกเลิก";
|
||||
"OK" = "ตกลง";
|
||||
"Comment" = "ความคิดเห็น";
|
||||
"Description" = "คำอธิบาย";
|
||||
"Location" = "ที่อยู่";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Odesílatel";
|
||||
"Subject or Sender" = "Předmět nebo Odesílatel";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Předmět nebo Příjemce";
|
||||
"To or Cc" = "Komu nebo Kopie";
|
||||
"Entire Message" = "Celá zpráva";
|
||||
"Date" = "Datum";
|
||||
@@ -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" = "Promazat složku";
|
||||
"Clean mailbox" = "Promazat schránku";
|
||||
"Delete permanently (do not use trash)" = "Smazat trvale (přeskočit Koš)";
|
||||
"Apply to subfolders" = "Použít na podsložky";
|
||||
"Delete e-mails older than" = "Smazat maily starší než";
|
||||
"3 months" = "3 měsíce";
|
||||
"6 months" = "6 měsíců";
|
||||
"9 months" = "9 měsíců";
|
||||
"1 year" = "1 rok";
|
||||
"Custom" = "Vlastní...";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Tǐmto navždy smažete zprávy. Chcete pokračovat?";
|
||||
"Apply" = "Použít";
|
||||
"%{0} message(s) deleted" = "%{0} zpráv smazáno";
|
||||
@@ -143,23 +143,23 @@
|
||||
"This mail is being sent from an unsecure network!" = "Deze e-mail wordt verzonden vanaf een onveilig netwerk!";
|
||||
"Address Book" = "Adresboek";
|
||||
"Search For" = "Zoek naar";
|
||||
"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";
|
||||
"Contains" = "bevat";
|
||||
"Does not contains" = "bevat niet";
|
||||
"Advanced search" = "Geavanceerd zoeken";
|
||||
"Anytime" = "Altijd";
|
||||
"Last 7 days" = "Laatste 7 dagen";
|
||||
"Last 30 days" = "Laatste 30 dagen";
|
||||
"Last 6 month" = "Laatste 6 maanden";
|
||||
"Before" = "Voor";
|
||||
"After" = "Na";
|
||||
"Between" = "Tussen";
|
||||
"and" = "en";
|
||||
"With attachments" = "Met bijlage";
|
||||
"In favorites" = "In favorieten";
|
||||
"Unseen only" = "Alleen ongelezen ";
|
||||
"Show more" = "Meer weergeven";
|
||||
"Reset" = "Reset";
|
||||
"Message size" = "Message size";
|
||||
"Message size" = "Berichtgrootte";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "alle";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Afzender";
|
||||
"Subject or Sender" = "Onderwerp of afzender";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Onderwerp of ontvanger";
|
||||
"To or Cc" = "Ontvanger (Aan of Cc)";
|
||||
"Entire Message" = "Volledig bericht";
|
||||
"Date" = "Datum";
|
||||
@@ -257,7 +257,7 @@
|
||||
"Save As..." = "Opslaan als...";
|
||||
"Print Preview" = "Afdrukvoorbeeld";
|
||||
"View Message Source" = "Bron bekijken";
|
||||
"View raw message" = "View raw message";
|
||||
"View raw message" = "Bekijk onbewerkt bericht";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "Omzetten naar afspraak";
|
||||
@@ -464,7 +464,7 @@
|
||||
"Copy messages" = "Kopieer berichten";
|
||||
"More messages options" = "Meer berichtopties";
|
||||
"Flag" = "Met vlag";
|
||||
"Unflag" = "Unflag";
|
||||
"Unflag" = "Vlag verwijderen";
|
||||
"Mark as Unread" = "Als ongelezen markeren";
|
||||
"Mark as Read" = "Markeren als gelezen";
|
||||
"Closing Window ..." = "Venster sluiten ...";
|
||||
@@ -478,7 +478,7 @@
|
||||
"Your email has been sent" = "Uw email is verzonden";
|
||||
"Folder compacted" = "Map gecomprimeerd";
|
||||
|
||||
"More Options" = "More Options";
|
||||
"More Options" = "Meer opties";
|
||||
|
||||
"New draft" = "Nieuw concept";
|
||||
"Create new draft with this template" = "Maak een nieuw concept met dit sjabloon";
|
||||
@@ -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" = "Map opschonen";
|
||||
"Clean mailbox" = "Mailbox opschonen";
|
||||
"Delete permanently (do not use trash)" = "Permanent verwijderen (niet in de prullenbak gebruiken)";
|
||||
"Apply to subfolders" = "Toepassen op submappen";
|
||||
"Delete e-mails older than" = "Verwijder e-mails die ouder zijn dan";
|
||||
"3 months" = "3 maanden";
|
||||
"6 months" = "6 maanden";
|
||||
"9 months" = "9 maanden";
|
||||
"1 year" = "1 jaar";
|
||||
"Custom" = "Aangepast";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "U staat op het punt om enkele berichten definitief te verwijderen. Weet u zeker dat u hiermee wilt doorgaan?";
|
||||
"Apply" = "Toepassen";
|
||||
"%{0} message(s) deleted" = "%{0} bericht(en) verwijderd";
|
||||
@@ -0,0 +1,532 @@
|
||||
/* this file is in UTF-8 format! */
|
||||
|
||||
/* Icon's label */
|
||||
"Create" = "생성";
|
||||
"Empty Trash" = "휴지통 비우기";
|
||||
"Empty Junk Folder" = "정크 폴더 비우기";
|
||||
"Delete" = "삭제";
|
||||
"Expunge" = "말소";
|
||||
"Forward" = "전달";
|
||||
"Get Mail" = "메일 가져오기";
|
||||
"Junk" = "정크";
|
||||
"Not junk" = "정크 아님";
|
||||
"Reply" = "답장";
|
||||
"Reply All" = "전체답장";
|
||||
"Print" = "인쇄";
|
||||
"Stop" = "중단";
|
||||
"Write" = "글쓰기";
|
||||
"Search" = "검색";
|
||||
"Send" = "보내기";
|
||||
"Contacts" = "연락처";
|
||||
"Attach" = "첨부";
|
||||
"Save" = "저장";
|
||||
"Options" = "옵션";
|
||||
"Close" = "닫기";
|
||||
"Size" = "크기";
|
||||
|
||||
/* Tooltips */
|
||||
"Send this message now" = "지금 이 메시지 보내기";
|
||||
"Select a recipient from an Address Book" = "주소록에서 받는 사람 선택";
|
||||
"Include an attachment" = "첨부 파일 포함";
|
||||
"Save this message" = "이 메시지 저장";
|
||||
"Get new messages" = "새 메시지 받기";
|
||||
"Create a new message" = "새 메시지 만들기";
|
||||
"Go to address book" = "주소록으로 이동";
|
||||
"Reply to the message" = "메시지에 답장하기";
|
||||
"Reply to sender and all recipients" = "발신자 및 모든 수신자에게 답장하기";
|
||||
"Forward selected message" = "선택한 메시지 전달";
|
||||
"Delete selected message or folder" = "선택한 메시지 또는 폴더 삭제";
|
||||
"Print this message" = "이 메시지 인쇄";
|
||||
"Stop the current transfer" = "현재 전송 중지";
|
||||
"Attachment" = "첨부 파일";
|
||||
"Unread" = "읽지 않음";
|
||||
"Flagged" = "플래그가 지정된";
|
||||
"Search multiple mailboxes" = "여러 메일함 검색";
|
||||
|
||||
/* Main Frame */
|
||||
"Home" = "홈";
|
||||
"Calendar" = "달력";
|
||||
"Addressbook" = "주소록";
|
||||
"Mail" = "메일";
|
||||
"Right Administration" = "권한 관리";
|
||||
"Help" = "도움말";
|
||||
|
||||
/* Mail account main windows */
|
||||
"Welcome to the SOGo Mailer. Use the folder tree on the left to browse your mail accounts!" = "SOGo 메일러에 오신 것을 환영합니다. 왼쪽의 폴더 트리를 사용하여 메일 계정을 찾아보세요!";
|
||||
"Read messages" = "메시지 읽기";
|
||||
|
||||
/* Tooltip for fab button */
|
||||
"Write a new message" = "새 메시지 작성";
|
||||
|
||||
/* Tooltip for fab button */
|
||||
"Write a message in new window" = "새 창에 메시지 쓰기";
|
||||
|
||||
"Share" = "공유";
|
||||
"Account" = "계정";
|
||||
"Shared Account" = "공유 계정";
|
||||
|
||||
/* A mailbox is selected, but no message (only shown on large screens) */
|
||||
"No message selected" = "선택한 메시지가 없습니다.";
|
||||
|
||||
/* No mailbox is selected (usually resulting from an IMAP connection problem) */
|
||||
"No mailbox selected" = "선택한 메일함이 없습니다.";
|
||||
|
||||
"An error occured while communicating with the mail server" = "메일 서버와 통신하는 동안 오류가 발생했습니다.";
|
||||
|
||||
/* Mailbox actions */
|
||||
|
||||
/* Compact Folder success message */
|
||||
"Folder compacted" = "폴더 압축";
|
||||
|
||||
/* Empty Junk Folder success message */
|
||||
"Junk folder emptied" = "정크 폴더 비우기";
|
||||
|
||||
/* Empty Trash success message */
|
||||
"Trash emptied" = "휴지통 비워짐";
|
||||
|
||||
/* acls */
|
||||
"Access rights to" = "다음에 대한 액세스 권한";
|
||||
"For user" = "사용자용";
|
||||
"Any Authenticated User" = "인증된 모든 사용자";
|
||||
"View this folder" = "이 폴더 보기";
|
||||
"Read mails from this folder" = "이 폴더에서 메일 읽기";
|
||||
"Mark mails read and unread" = "읽은 메일과 읽지 않은 메일 표시";
|
||||
"Modify the flags of the mails in this folder" = "이 폴더에 있는 메일의 플래그를 수정합니다.";
|
||||
"Insert, copy and move mails into this folder" = "이 폴더에 메일을 삽입, 복사 및 이동합니다.";
|
||||
"Post mails" = "메일 보내기";
|
||||
"Add subfolders to this folder" = "이 폴더에 하위 폴더 추가";
|
||||
"Remove this folder" = "이 폴더 제거";
|
||||
"Erase mails from this folder" = "이 폴더에서 메일 지우기";
|
||||
"Expunge this folder" = "이 폴더 삭제";
|
||||
"Export This Folder" = "이 폴더 내보내기";
|
||||
"Modify the acl of this folder" = "이 폴더의 acl을 수정 합니다.";
|
||||
"Saved Messages.zip" = "Messages.zip으로 저장됨";
|
||||
"Update" = "업데이트";
|
||||
"Cancel" = "취소";
|
||||
|
||||
/* Mail edition */
|
||||
"From" = "보낸사람";
|
||||
"Subject" = "제목";
|
||||
"To" = "받는사람";
|
||||
"Cc" = "참조";
|
||||
"Bcc" = "숨은참조";
|
||||
"Reply-To" = "답장 받는 사람";
|
||||
"Add address" = "주소 추가";
|
||||
"Body" = "본문";
|
||||
"Open" = "열기";
|
||||
"Select All" = "전체 선택";
|
||||
"Select Message" = "메시지 선택";
|
||||
"Attach Web Page..." = "웹 페이지 첨부...";
|
||||
"file" = "파일";
|
||||
"files" = "파일";
|
||||
"Save all" = "전체 저장";
|
||||
"to" = "받는사람";
|
||||
"cc" = "참조";
|
||||
"bcc" = "숨은참조";
|
||||
"Add a recipient" = "받는 사람 추가";
|
||||
"Edit Draft..." = "초안 편집...";
|
||||
"Load Images" = "이미지 불러오기";
|
||||
"Return Receipt" = "받은사람 회신";
|
||||
"Choose which identity to send this message from" = "이 메시지를 보낼 ID 선택";
|
||||
"The sender of this message has asked to be notified when you read this message. Do you with to notify the sender?" = "이 메시지를 읽으면 발신자에게 알림을 보내도록 요청했습니다. 발신자에게 알림을 보내시겠습니까?";
|
||||
"Return Receipt (displayed) - %@"= "받은사람 회신(표시됨) - %@";
|
||||
"This is a Return Receipt for the mail that you sent to %@.\n\nNote: This Return Receipt only acknowledges that the message was displayed on the recipient's computer. There is no guarantee that the recipient has read or understood the message contents." = "이 메일은 %@로 보낸 메일에 대한 받은사람의 회신입니다.\n\n참고: 이 받은사람 회신은 메시지가 수신자의 컴퓨터에 표시되었다는 사실만 확인합니다. 받는 사람이 메시지 내용을 읽었거나 이해했다는 보장은 없습니다.";
|
||||
"Security" = "보안";
|
||||
"Sign" = "서명";
|
||||
"Encrypt" = "암호화";
|
||||
"Priority" = "우선순위";
|
||||
"highest" = "매우 높음";
|
||||
"high" = "높음";
|
||||
"normal" = "보통";
|
||||
"low" = "낮음";
|
||||
"lowest" = "가장낮음";
|
||||
"This mail is being sent from an unsecure network!" = "안전하지 않은 네트워크에서 발송된 메일입니다.";
|
||||
"Address Book" = "주소록";
|
||||
"Search For" = "검색";
|
||||
"Contains" = "포함";
|
||||
"Does not contains" = "포함하지 않음";
|
||||
"Advanced search" = "고급 검색";
|
||||
"Anytime" = "언제든지";
|
||||
"Last 7 days" = "지난 7일";
|
||||
"Last 30 days" = "지난 30일";
|
||||
"Last 6 month" = "지난 6개월";
|
||||
"Before" = "전";
|
||||
"After" = "후";
|
||||
"Between" = "사이";
|
||||
"and" = "와";
|
||||
"With attachments" = "첨부 파일 포함";
|
||||
"In favorites" = "즐겨찾기에";
|
||||
"Unseen only" = "표시되지 않음";
|
||||
"Show more" = "더 보기";
|
||||
"Reset" = "초기화";
|
||||
"Message size" = "메시지 크기";
|
||||
|
||||
/* Popup "show" */
|
||||
"all" = "모두";
|
||||
"read" = "읽기";
|
||||
"unread" = "읽지 않음";
|
||||
"deleted" = "삭제됨";
|
||||
"flagged" = "플래그됨";
|
||||
|
||||
/* MailListView */
|
||||
"Sender" = "보낸사람";
|
||||
"Subject or Sender" = "제목 또는 보낸사람";
|
||||
"Subject or Recipient" = "제목 또는 받는 사람";
|
||||
"To or Cc" = "받는 사람 또는 참조";
|
||||
"Entire Message" = "전체 메시지";
|
||||
"Date" = "날짜";
|
||||
"View" = "보기";
|
||||
"All" = "모두";
|
||||
"No message" = "메시지 없음";
|
||||
"messages" = "메시지";
|
||||
"Yesterday" = "어제";
|
||||
"first" = "처음";
|
||||
"previous" = "이전";
|
||||
"next" = "다음";
|
||||
"last" = "마지막";
|
||||
"msgnumber_to" = "to";
|
||||
"msgnumber_of" = "of";
|
||||
"Mark Unread" = "읽지 않음으로 표시";
|
||||
"Mark Read" = "읽음으로 표시";
|
||||
"Untitled" = "제목 없음";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show unread messages only" = "읽지 않은 메시지만 표시";
|
||||
|
||||
/* Filter option in messages list */
|
||||
"Show flagged messages only" = "플래그가 지정된 메시지만 표시";
|
||||
|
||||
/* Aria label for icon of labels */
|
||||
"Filtered by label" = "라벨로 필터링";
|
||||
|
||||
/* Tree */
|
||||
"SentFolderName" = "보냄";
|
||||
"TrashFolderName" = "휴지통";
|
||||
"InboxFolderName" = "받은 편지함";
|
||||
"DraftsFolderName" = "초안";
|
||||
"JunkFolderName" = "정크";
|
||||
"TemplatesFolderName" = "템플릿";
|
||||
"SieveFolderName" = "필터";
|
||||
"Folders" = "폴더"; /* title line */
|
||||
|
||||
/* MailMoveToPopUp */
|
||||
"MoveTo" = "이동 …";
|
||||
|
||||
/* Address Popup menu */
|
||||
"Add to Address Book..." = "주소록에 추가...";
|
||||
"Successfully created card" = "카드 생성 성공";
|
||||
"Compose Mail To" = "메일 작성 대상";
|
||||
"Create Filter From Message..." = "메시지에서 필터 만들기...";
|
||||
|
||||
/* Image Popup menu */
|
||||
"Save Image" = "이미지 저장";
|
||||
"Save Attachment" = "첨부 파일 저장";
|
||||
|
||||
/* Mailbox popup menus */
|
||||
"Open in New Mail Window" = "새 메일 창에서 열기";
|
||||
"Copy Folder Location" = "폴더 위치 복사";
|
||||
"Subscribe..." = "구독하기...";
|
||||
"Mark Folder Read" = "폴더 읽음 표시";
|
||||
"New Folder..." = "새 폴더...";
|
||||
"Compact This Folder" = "이 폴더 압축";
|
||||
"Search Messages..." = "메시지 검색...";
|
||||
"Sharing..." = "공유...";
|
||||
"New Subfolder..." = "새 하위 폴더...";
|
||||
"Rename Folder..." = "폴더 이름변경";
|
||||
"Delete Folder" = "폴더 삭제";
|
||||
"Use This Folder For" = "이 폴더를 다음 용도로 사용";
|
||||
"Get Messages for Account" = "계정 메시지 받기";
|
||||
"Properties..." = "속성...";
|
||||
"Delegation..." = "위임...";
|
||||
|
||||
/* Use This Folder menu */
|
||||
"Sent Messages" = "메시지 보내기";
|
||||
"Drafts" = "초안";
|
||||
"Deleted Messages" = "삭제된 메시지";
|
||||
"Junk Messages" = "정크 메시지";
|
||||
|
||||
/* Message list popup menu */
|
||||
"Open Message In New Window" = "새 창에서 메시지 열기";
|
||||
"Reply to Sender Only" = "보낸 사람에게만 답장";
|
||||
"Reply to All" = "모두에게 답장";
|
||||
"Edit As New..." = "새로 편집...";
|
||||
"Move To" = "이동";
|
||||
"Copy To" = "복사";
|
||||
"Label" = "라벨";
|
||||
"Mark" = "표시";
|
||||
"Save As..." = "다른 이름으로 저장";
|
||||
"Print Preview" = "인쇄 미리보기";
|
||||
"View Message Source" = "메시지 소스 보기";
|
||||
"View raw message" = "원시 메시지 보기";
|
||||
|
||||
/* Message view "more" menu: create an event from message */
|
||||
"Convert To Event" = "이벤트로 변환";
|
||||
|
||||
/* Message view "more" menu: create a task from message */
|
||||
"Convert To Task" = "작업으로 변환";
|
||||
|
||||
/* Message view "more" menu: download message as an eml file */
|
||||
"Download message" = "메시지 다운로드";
|
||||
|
||||
/* Message view "more" menu: download message as a zip archive */
|
||||
"Download message (zip)" = "메시지 다운로드(zip)";
|
||||
|
||||
/* Message view "more" menu: download all attachments as a zip archive */
|
||||
"Download all attachments" = "모든 첨부파일 다운로드";
|
||||
|
||||
/* Filename prefix when downloading all attachments as a zip archive */
|
||||
"attachments" = "첨부";
|
||||
|
||||
"Print..." = "인쇄";
|
||||
"Delete Message" = "메시지 삭제";
|
||||
"Delete Selected Messages" = "선택한 메시지 삭제";
|
||||
"Mark the selected messages as junk" = "선택한 메시지를 정크 메시지로 표시";
|
||||
"Mark the selected messages as not junk" = "선택한 메시지를 정크 메일이 아닌 것으로 표시";
|
||||
|
||||
/* Text appended to the recipients list when there are too many recipients */
|
||||
"and %{0} more..." = "및 %{0} 더보기...";
|
||||
|
||||
/* Button label to hide extended list of recipients */
|
||||
"Hide" = "숨기기";
|
||||
|
||||
/* Number of selected messages in list */
|
||||
"selected" = "선택된";
|
||||
|
||||
/* Date formatting from one time to another time */
|
||||
"to_time" = "to";
|
||||
|
||||
/* Date formatting from one day to another day */
|
||||
"to_date" = "to";
|
||||
|
||||
/* Encrypted message notification */
|
||||
"This message is encrypted" = "이 메시지는 암호화되어 있습니다.";
|
||||
|
||||
/* Encrypted message but no certificate */
|
||||
"This message can't be decrypted. Please make sure you have uploaded your S/MIME certificate from the mail preferences module." = "이 메시지는 해독할 수 없습니다. 메일 환경설정 모듈에서 S/MIME 인증서를 업로드했는지 확인하세요.";
|
||||
|
||||
/* OpenSSL certificate error - unknown issuer */
|
||||
"certificate verify error" = "메시지 서명을 확인할 수 없음";
|
||||
|
||||
/* OpenSSL certificate error - digest failure */
|
||||
"digest failure" = "메시지가 수정되었습니다.";
|
||||
|
||||
/* OpenSSL reading error */
|
||||
"Error reading the certificate. Please install a new certificate." = "인증서를 읽는 동안 오류가 발생했습니다. 새 인증서를 설치하세요.";
|
||||
|
||||
/* Trying to access a non-existent certificate */
|
||||
"No certificate associated to account." = "계정에 연결된 인증서가 없습니다.";
|
||||
|
||||
/* Invalid S/MIME signature */
|
||||
"Digital signature is not valid" = "디지털 서명이 유효하지 않습니다.";
|
||||
|
||||
/* Valid S/MIME signature */
|
||||
"Message is signed" = "메시지가 서명됨";
|
||||
|
||||
/* Valid S/MIME signature but common name not found */
|
||||
"Message is signed but the certificate doesn't match the sender email address" = "메시지에 서명이 되어 있지만, 인증서가 발신자 이메일 주소와 일치하지 않습니다.";
|
||||
|
||||
/* Unknown error while validating message signature */
|
||||
"Digital signature is not valid" = "디지털 서명이 유효하지 않습니다.";
|
||||
|
||||
"This Folder" = "이 폴더";
|
||||
|
||||
/* Label popup menu */
|
||||
"None" = "없음";
|
||||
|
||||
/* Mark popup menu */
|
||||
"As Read" = "읽음으로 표시";
|
||||
"Thread As Read" = "스레드를 읽음으로 표시";
|
||||
"As Read By Date..." = "읽은 순서대로...";
|
||||
"All Read" = "모두 읽기";
|
||||
"As Junk" = "정크로 설정";
|
||||
"As Not Junk" = "정크 아님으로 설정";
|
||||
"Run Junk Mail Controls" = "정크 메일 컨트롤 실행";
|
||||
"Search messages in" = "다음에서 메시지 검색";
|
||||
"Search" = "검색";
|
||||
"Search subfolders" = "하위 폴더 검색";
|
||||
"Match any of the following" = "다음 중 하나에 해당합니다.";
|
||||
"Match all of the following" = "다음 중 모두 일치하는 것을 고르세요.";
|
||||
"contains" = "포함";
|
||||
"does not contain" = "포함하지 않음";
|
||||
"No matches found" = "일치하는 항목이 없음";
|
||||
"results found" = "검색 결과";
|
||||
"result found" = "검색 결과";
|
||||
"Please specify at least one filter" = "필터를 하나 이상 지정하세요.";
|
||||
|
||||
/* Folder operations */
|
||||
"Name" = "이름";
|
||||
"Enter the new name of your folder"
|
||||
="폴더의 새 이름을 입력합니다.";
|
||||
"Do you really want to move this folder into the trash ?"
|
||||
= "이 폴더를 정말로 휴지통으로 옮길까요?";
|
||||
"Operation failed" = "작업 실패";
|
||||
"Quota" = "할당량:";
|
||||
"quotasFormat" = "%{0}% : %{1} MB 사용됨";
|
||||
"messageQuotasFormat" = "%{1} 메세지 중 %{0}%";
|
||||
"Unable to move/delete folder." = "폴더를 이동/삭제할 수 없습니다.";
|
||||
|
||||
/* Alternative operation when folder cannot be deleted */
|
||||
"The mailbox could not be moved to the trash folder. Would you like to delete it immediately?"
|
||||
= "메일함을 휴지통으로 옮길 수 없습니다. 즉시 삭제하시겠습니까?";
|
||||
|
||||
/* Confirmation message when deleting multiple messages */
|
||||
"Are you sure you want to delete the selected messages?" = "선택한 메시지를 삭제하시겠습니까?";
|
||||
|
||||
/* Notification on the number of messages successfuly copied */
|
||||
"%{0} message(s) copied" = "%{0} 메시지 복사됨";
|
||||
|
||||
/* Notification on the number of messages successfuly movied */
|
||||
"%{0} message(s) moved" = "%{0} 메시지 이동됨";
|
||||
|
||||
"Please select a message." = "메시지를 선택해 주세요.";
|
||||
"Please select a message to print." = "인쇄할 메시지를 선택하세요.";
|
||||
"Please select only one message to print." = "인쇄할 메시지를 하나만 선택하세요.";
|
||||
"The message you have selected doesn't exist anymore." = "선택한 메시지가 더 이상 존재하지 않습니다.";
|
||||
"The folder with name \"%{0}\" could not be created."
|
||||
= "\"%{0}\" 이름의 폴더를 만들지 못했습니다.";
|
||||
"This folder could not be renamed to \"%{0}\"."
|
||||
= "이 폴더의 이름을 \"%{0}\"로 변경할 수 없습니다.";
|
||||
"The folder could not be deleted."
|
||||
= "폴더를 삭제할 수 없습니다.";
|
||||
"The trash could not be emptied."
|
||||
= "휴지통을 비울 수 없습니다.";
|
||||
"The folder functionality could not be changed."
|
||||
= "폴더 기능을 변경할 수 없습니다.폴더 기능은 변경할 수 없습니다.";
|
||||
"You need to choose a non-virtual folder!" = "가상 폴더가 아닌 폴더를 선택해야 합니다!";
|
||||
"Moving a message into its own folder is impossible!"
|
||||
= "메시지를 자체 폴더로 옮기는 것은 불가능합니다!";
|
||||
"Copying a message into its own folder is impossible!"
|
||||
= "메시지를 자체 폴더에 복사하는 것은 불가능합니다!";
|
||||
|
||||
/* Message operations */
|
||||
"The messages could not be moved to the trash folder. Would you like to delete them immediately?"
|
||||
= "메시지를 휴지통 폴더로 옮길 수 없습니다. 즉시 삭제하시겠습니까?";
|
||||
|
||||
/* Message editing */
|
||||
"Please specify a subject." = "제목을 지정해 주세요.";
|
||||
"error_missingsubject" = "메시지에 제목이 없습니다. 정말 보내시겠습니까?";
|
||||
"error_missingrecipients" = "받는 사람을 한 명 이상 지정하세요.";
|
||||
"Send Anyway" = "아무튼 보내기";
|
||||
"Error while saving the draft" = "초안 저장 중 오류 발생";
|
||||
|
||||
/* Error when emptying trash */
|
||||
"Unable to empty the trash folder." = "휴지통 폴더를 비울 수 없습니다.";
|
||||
|
||||
/* Error when emptying junk folder */
|
||||
"Unable to empty the junk folder." = "정크 폴더를 비울 수 없습니다.";
|
||||
|
||||
/* Error when uploading a file attachment */
|
||||
"Error while uploading the file \"%{0}\":" = "\"%{0}\" 파일을 업로드하는 동안 오류가 발생했습니다.";
|
||||
"There is an active file upload. Closing the window will interrupt it." = "활성 파일 업로드가 진행 중입니다. 창을 닫으면 업로드가 중단됩니다.";
|
||||
"Message is too big" = "메시지가 너무 큽니다.";
|
||||
|
||||
/* Appears while sending the message */
|
||||
"Sending" = "전송 중";
|
||||
|
||||
/* Appears when the message is successfuly sent */
|
||||
"Sent" = "전송됨";
|
||||
|
||||
"cannot send message: (smtp) all recipients discarded" = "메시지를 보낼 수 없음: 모든 수신자가 유효하지 않습니다.";
|
||||
"cannot send message (smtp) - recipients discarded" = "메시지를 보낼 수 없습니다. 다음 주소는 유효하지 않습니다.";
|
||||
"cannot send message: (smtp) error when connecting" = "메시지를 보낼 수 없음: SMTP 서버에 연결할 때 오류가 발생했습니다.";
|
||||
"cannot sign email without certificate" = "메일 계정에 연결된 인증서가 없기 때문에 메시지에 서명할 수 없습니다.";
|
||||
"cannot sign message because the certificate can't be read" = "메일 계정에 연결된 인증서를 읽을 수 없기 때문에 메시지에 서명할 수 없습니다.";
|
||||
"cannot sign message because the certificate doesn't include the specified sender address" = "보낸 사람 주소가 메일 계정에 연결된 인증서에 포함되어 있지 않으므로 메시지에 서명할 수 없습니다.";
|
||||
|
||||
/* Contacts list in mail editor */
|
||||
"Email" = "이메일";
|
||||
"More mail options" = "더 많은 메일 옵션";
|
||||
"Delegation" = "위임";
|
||||
"Add User" = "사용자 추가";
|
||||
"Add a tag" = "태그 추가";
|
||||
"reply" = "답장";
|
||||
"Edit" = "수정";
|
||||
"Yes" = "예";
|
||||
"No" = "아니오";
|
||||
"Location" = "위치";
|
||||
"Rename" = "이름 변경";
|
||||
"Compact" = "압축";
|
||||
"Export" = "내보내기";
|
||||
"Set as Drafts" = "초안으로 설정";
|
||||
"Set as Sent" = "보내기로 설정";
|
||||
"Set as Trash" = "휴지통으로 설정";
|
||||
|
||||
/* Set the folder as the one holding the Templates */
|
||||
"Set as Templates" = "템플릿으로 설정";
|
||||
|
||||
/* Set the folder as the one holding Junk mails */
|
||||
"Set as Junk" = "정크로 설정";
|
||||
|
||||
"Sort" = "정렬";
|
||||
"Order Received" = "수신된 순서";
|
||||
"Descending Order" = "내림차순";
|
||||
"Back" = "뒤로";
|
||||
"Copy messages" = "메시지 복사";
|
||||
"More messages options" = "더 많은 메시지 옵션";
|
||||
"Flag" = "플래그";
|
||||
"Unflag" = "플래그 해제";
|
||||
"Mark as Unread" = "읽지 않음으로 표시";
|
||||
"Mark as Read" = "읽음으로 표시";
|
||||
"Closing Window ..." = "윈도우 닫는 중";
|
||||
"Tried to send too many mails. Please wait." = "메일을 너무 많이 보내려고 했습니다. 잠시만 기다려주세요.";
|
||||
"View Mail" = "메일 보기";
|
||||
"This message contains external images." = "이 메시지에는 외부 이미지가 포함되어 있습니다.";
|
||||
"Expanded" = "확장";
|
||||
"Add a Criteria" = "기준 추가";
|
||||
"More search options" = "더 많은 검색 옵션";
|
||||
"Your email has been saved" = "이메일이 저장되었습니다.";
|
||||
"Your email has been sent" = "이메일이 전송되었습니다.";
|
||||
"Folder compacted" = "폴더 압축";
|
||||
|
||||
"More Options" = "더 많은 옵션";
|
||||
|
||||
"New draft" = "새 초안";
|
||||
"Create new draft with this template" = "이 템플릿으로 새 초안 만들기";
|
||||
|
||||
/* Advanced search */
|
||||
"Enter Subject" = "제목 입력";
|
||||
"Enter From" = "보낸사람 입력";
|
||||
"Enter To" = "받는사람 입력";
|
||||
"Enter Cc" = "참조 입력";
|
||||
"Enter Body" = "본문 입력";
|
||||
"match" = "일치";
|
||||
"does not match" = "일치하지 않음";
|
||||
|
||||
/* Aria label for scope of search on messages */
|
||||
"Search scope" = "검색 범위";
|
||||
|
||||
/* Subscriptions Dialog */
|
||||
"Manage Subscriptions" = "구독 관리";
|
||||
|
||||
/* Label of filter input field in subscriptions dialog */
|
||||
"Filter" = "필터";
|
||||
|
||||
/* Hotkey to write a new message */
|
||||
"hotkey_compose" = "w";
|
||||
|
||||
/* Hotkey to flag a message */
|
||||
"hotkey_flag" = "*";
|
||||
|
||||
/* Hotkey to reply to a message */
|
||||
"hotkey_reply" = "r";
|
||||
|
||||
/* Hotkey to reply to all recipients of a message */
|
||||
"hotkey_replyall" = "a";
|
||||
|
||||
/* Hotkey to forward to a message */
|
||||
"hotkey_forward" = "f";
|
||||
|
||||
/* Email deletion */
|
||||
"Clean folder" = "폴더 지우기";
|
||||
"Clean mailbox" = "메일함 정리";
|
||||
"Delete permanently (do not use trash)" = "영구 삭제(휴지통 사용 안 함)";
|
||||
"Apply to subfolders" = "하위 폴더에 적용";
|
||||
"Delete e-mails older than" = "다음보다 오래된 이메일 삭제";
|
||||
"3 months" = "3개월";
|
||||
"6 months" = "6개월";
|
||||
"9 months" = "9개월";
|
||||
"1 year" = "1년";
|
||||
"Custom" = "사용자 지정";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "일부 메시지를 영구 삭제하려고 합니다. 이 작업을 계속 진행하시겠습니까?";
|
||||
"Apply" = "적용";
|
||||
"%{0} message(s) deleted" = "%{0} 메시지 삭제됨";
|
||||
@@ -171,7 +171,7 @@
|
||||
/* MailListView */
|
||||
"Sender" = "Nadawca";
|
||||
"Subject or Sender" = "Temat lub nadawca";
|
||||
"Subject or Recipient" = "Subject or Recipient";
|
||||
"Subject or Recipient" = "Nadawca lub Odbiorca";
|
||||
"To or Cc" = "Do lub DW";
|
||||
"Entire Message" = "Cała wiadomość";
|
||||
"Date" = "Data";
|
||||
@@ -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" = "Uporządkuj folder";
|
||||
"Clean mailbox" = "Uporządkuj skrzynkę pocztową";
|
||||
"Delete permanently (do not use trash)" = "Usuń trwale (nie używaj kosza)";
|
||||
"Apply to subfolders" = "Zastosuj do podfolderów";
|
||||
"Delete e-mails older than" = "Usuń wiadomości starsze niż";
|
||||
"3 months" = "3 miesiące";
|
||||
"6 months" = "6 miesięcy";
|
||||
"9 months" = "9 miesięcy";
|
||||
"1 year" = "1 rok";
|
||||
"Custom" = "Ustaw";
|
||||
"You are about to permanently delete some messages. Are you sure you want to proceed with this action?" = "Za chwilę trwale usuniesz część wiadomości. Na pewno chcesz to zrobić?";
|
||||
"Apply" = "Wykonaj";
|
||||
"%{0} message(s) deleted" = "usunięto %{0} wiadomości";
|
||||
Loaded 100 of 243 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user