diff --git a/bindings/ios/MEGASDK.xcodeproj/project.pbxproj b/bindings/ios/MEGASDK.xcodeproj/project.pbxproj index afa5223b09..78a2f0d04f 100644 --- a/bindings/ios/MEGASDK.xcodeproj/project.pbxproj +++ b/bindings/ios/MEGASDK.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ 940BF01919ED97B9007E7FA2 /* MEGAUserList.mm in Sources */ = {isa = PBXBuildFile; fileRef = 940BF00919ED97B9007E7FA2 /* MEGAUserList.mm */; }; A81790101EFACE6400110E91 /* MEGAHandleList.mm in Sources */ = {isa = PBXBuildFile; fileRef = A817900F1EFACE6400110E91 /* MEGAHandleList.mm */; }; A81790151EFADDDE00110E91 /* MEGAEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = A81790141EFADDDE00110E91 /* MEGAEvent.mm */; }; + A8827A5C1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.mm in Sources */ = {isa = PBXBuildFile; fileRef = A8827A5B1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.mm */; }; A8FD7B641E93B40E0031FC50 /* osxutils.mm in Sources */ = {isa = PBXBuildFile; fileRef = A8FD7B631E93B40E0031FC50 /* osxutils.mm */; }; /* End PBXBuildFile section */ @@ -253,6 +254,9 @@ A81790121EFAD24F00110E91 /* MEGAHandleList+init.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MEGAHandleList+init.h"; sourceTree = ""; }; A81790131EFADDDE00110E91 /* MEGAEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MEGAEvent.h; sourceTree = ""; }; A81790141EFADDDE00110E91 /* MEGAEvent.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MEGAEvent.mm; sourceTree = ""; }; + A8827A591F176BCA0097B5DE /* MEGATreeProcessorDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MEGATreeProcessorDelegate.h; sourceTree = ""; }; + A8827A5A1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DelegateMEGATreeProcessorListener.h; sourceTree = ""; }; + A8827A5B1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DelegateMEGATreeProcessorListener.mm; sourceTree = ""; }; A8EBFDD21EFAE14C00DF89DA /* MEGAEvent+init.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MEGAEvent+init.h"; sourceTree = ""; }; A8FD7B611E93B3ED0031FC50 /* osxutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osxutils.h; path = osx/osxutils.h; sourceTree = ""; }; A8FD7B631E93B40E0031FC50 /* osxutils.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = osxutils.mm; path = ../../src/osx/osxutils.mm; sourceTree = ""; }; @@ -383,6 +387,7 @@ 940BF09219EDBD62007E7FA2 /* MEGARequestDelegate.h */, 940BF09619EDBD62007E7FA2 /* MEGATransferDelegate.h */, 41AD7A7B1A1E0F1B00D66856 /* MEGALoggerDelegate.h */, + A8827A591F176BCA0097B5DE /* MEGATreeProcessorDelegate.h */, 940BF08F19EDBD62007E7FA2 /* MEGANode.h */, 940BF00119ED97B9007E7FA2 /* MEGANode.mm */, 940BF09019EDBD62007E7FA2 /* MEGANodeList.h */, @@ -524,6 +529,8 @@ 940BF09B19EDBD62007E7FA2 /* Private */ = { isa = PBXGroup; children = ( + A8827A5A1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.h */, + A8827A5B1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.mm */, 41AD7A7D1A1E10F900D66856 /* DelegateMEGALoggerListener.h */, 41AD7A7C1A1E10F900D66856 /* DelegateMEGALoggerListener.mm */, 41B2AED11A0A859C006C40FB /* DelegateMEGAGlobalListener.h */, @@ -701,6 +708,7 @@ 41AD7A7E1A1E10F900D66856 /* DelegateMEGALoggerListener.mm in Sources */, 41A990731A5D305700B2094A /* mega_utf8proc.cpp in Sources */, A81790101EFACE6400110E91 /* MEGAHandleList.mm in Sources */, + A8827A5C1F178A0D0097B5DE /* DelegateMEGATreeProcessorListener.mm in Sources */, 41B2AEDC1A0A859C006C40FB /* DelegateMEGATransferListener.mm in Sources */, 41B538CC1A0284CB00EABDC9 /* MEGAPricing.mm in Sources */, 940BEFD419ED92C2007E7FA2 /* utils.cpp in Sources */, diff --git a/bindings/ios/MEGASdk.h b/bindings/ios/MEGASdk.h index b5c1efd9d9..67b9ccbd73 100644 --- a/bindings/ios/MEGASdk.h +++ b/bindings/ios/MEGASdk.h @@ -41,6 +41,7 @@ #import "MEGATransferDelegate.h" #import "MEGAGlobalDelegate.h" #import "MEGALoggerDelegate.h" +#import "MEGATreeProcessorDelegate.h" typedef NS_ENUM (NSInteger, MEGASortOrderType) { MEGASortOrderTypeNone, @@ -77,8 +78,17 @@ typedef NS_ENUM (NSInteger, MEGAAttributeType) { }; typedef NS_ENUM(NSInteger, MEGAUserAttribute) { - MEGAUserAttributeFirstname = 1, - MEGAUserAttributeLastname = 2 + MEGAUserAttributeAvatar = 0, // public - char array + MEGAUserAttributeFirstname = 1, // public - char array + MEGAUserAttributeLastname = 2, // public - char array + MEGAUserAttributeAuthRing = 3, // private - byte array + MEGAUserAttributeLastInteraction = 4, // private - byte array + MEGAUserAttributeED25519PublicKey = 5, // public - char array + MEGAUserAttributeCU25519PublicKey = 6, // public - char array + MEGAUserAttributeKeyring = 7, // private - byte array + MEGAUserAttributeSigRsaPublicKey = 8, // public - char array + MEGAUserAttributeSigCU255PublicKey = 9, // public - char array + MEGAUserAttributeLanguage = 14 // private - byte array }; typedef NS_ENUM(NSInteger, MEGAPaymentMethod) { @@ -199,6 +209,11 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { */ @property (readonly, nonatomic) NSNumber *totalsUploadedBytes; +/** + * @brief The total number of nodes in the account + */ +@property (readonly, nonatomic) NSUInteger totalNodes; + /** * @brief The master key of the account. * @@ -2099,9 +2114,11 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Get the firstname of the user (public) * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Get the lastname of the user (public) + * MEGAUserAttributeLanguage = 14 + * Get the preferred language of the user (private, non-encrypted) * */ - (void)getUserAttributeForUser:(MEGAUser *)user type:(MEGAUserAttribute)type; @@ -2125,9 +2142,11 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Get the firstname of the user (public) * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Get the lastname of the user (public) + * MEGAUserAttributeLanguage = 14 + * Get the preferred language of the user (private, non-encrypted) * * @param delegate MEGARequestDelegate to track this request */ @@ -2149,9 +2168,11 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Get the firstname of the user (public) * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Get the lastname of the user (public) + * MEGAUserAttributeLanguage = 14 + * Get the preferred language of the user (private, non-encrypted) */ - (void)getUserAttributeType:(MEGAUserAttribute)type; @@ -2171,9 +2192,11 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Get the firstname of the user (public) * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Get the lastname of the user (public) + * MEGAUserAttributeLanguage = 14 + * Get the preferred language of the user (private, non-encrypted) * * @param delegate MEGARequestDelegate to track this request */ @@ -2193,9 +2216,9 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Set the firstname of the user * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Set the lastname of the user * * @param value New attribute value */ @@ -2214,9 +2237,9 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { * Valid values are: * * MEGAUserAttributeFirstname = 1 - * Get the firstname of the user + * Set the firstname of the user * MEGAUserAttributeLastname = 2 - * Get the lastname of the user + * Set the lastname of the user * * @param value New attribute value * @param delegate MEGARequestDelegate to track this request @@ -3607,6 +3630,18 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { */ - (MEGANodeList *)nodeListSearchForNode:(MEGANode *)node searchString:(NSString *)searchString; +/** + * @brief Process a node tree using a MEGATreeProcessorDelegate implementation + * @param node The parent node of the tree to explore + * @param recursive YES if you want to recursively process the whole node tree. + * @param delegate MEGATreeProcessorDelegate that will receive callbacks for every node in the tree + * NO if you want to process the children of the node only + * + * @return YES if all nodes were processed. NO otherwise (the operation can be + * cancelled by [MEGATreeProcessorDelegate processMEGANode:]) + */ +- (BOOL)processMEGANodeTree:(MEGANode *)node recursive:(BOOL)recursive delegate:(id)delegate; + /** * @brief Returns a MEGANode that can be downloaded with any instance of MEGASdk * @@ -3689,6 +3724,58 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { */ -(BOOL)setLanguageCode:(NSString *)languageCode; +/** + * @brief Set the preferred language of the user + * + * Valid data in the MEGARequest object received in onRequestFinish: + * - [MEGARequest text] - Return the language code + * + * If the language code is unknown for the SDK, the error code will be MEGAErrorTypeApiENoent + * + * This attribute is automatically created by the server. Apps only need + * to set the new value when the user changes the language. + * + * @param languageCode code to be set + * @param delegate MEGARequestDelegate to track this request + */ +- (void)setLanguangePreferenceCode:(NSString *)languageCode delegate:(id)delegate; + +/** + * @brief Set the preferred language of the user + * + * Valid data in the MEGARequest object received in onRequestFinish: + * - [MEGARequest text] - Return the language code + * + * If the language code is unknown for the SDK, the error code will be MEGAErrorTypeApiENoent + * + * This attribute is automatically created by the server. Apps only need + * to set the new value when the user changes the language. + * + * @param languageCode code to be set + */ +- (void)setLanguangePreferenceCode:(NSString *)languageCode; + +/** + * @brief Get the preferred language of the user + * + * Valid data in the MEGARequest object received in onRequestFinish when the error code + * is MEGAErrorTypeApiOk: + * - [MEGARequest text] - Return the language code + * + * @param delegate MEGARequestDelegate to track this request + */ +- (void)getLanguagePreferenceWithDelegate:(id)delegate; + +/** + * @brief Get the preferred language of the user + * + * Valid data in the MEGARequest object received in onRequestFinish when the error code + * is MEGAErrorTypeApiOk: + * - [MEGARequest text] - Return the language code + * + */ +- (void)getLanguagePreference; + /** * @brief Create a thumbnail for an image * @param imagePath Image path @@ -3705,6 +3792,14 @@ typedef NS_ENUM(NSUInteger, PushNotificationTokenType) { */ - (BOOL)createPreview:(NSString *)imagePath destinatioPath:(NSString *)destinationPath; +/** + * @brief Create an avatar for an image + * @param imagePath Image path + * @param destinationPath Destination path for the avatar (including the file name) + * @return YES if the avatar was successfully created, otherwise NO. + */ +- (BOOL)createAvatar:(NSString *)imagePath destinationPath:(NSString *)destinationPath; + #ifdef HAVE_LIBUV #pragma mark - HTTP Proxy Server diff --git a/bindings/ios/MEGASdk.mm b/bindings/ios/MEGASdk.mm index ed3b5a1730..424dec0fc1 100644 --- a/bindings/ios/MEGASdk.mm +++ b/bindings/ios/MEGASdk.mm @@ -36,6 +36,7 @@ #import "DelegateMEGAGlobalListener.h" #import "DelegateMEGAListener.h" #import "DelegateMEGALoggerListener.h" +#import "DelegateMEGATreeProcessorListener.h" #import "MEGAInputStream.h" #import @@ -112,6 +113,10 @@ - (NSNumber *)totalsUploadedBytes { return [[NSNumber alloc] initWithLongLong:self.megaApi->getTotalUploadedBytes()]; } +- (NSUInteger)totalNodes { + return self.megaApi->getNumNodes(); +} + - (NSString *)masterKey { const char *val = self.megaApi->exportMasterKey(); if (!val) return nil; @@ -1331,6 +1336,10 @@ - (MEGANodeList *)nodeListSearchForNode:(MEGANode *)node searchString:(NSString return [[MEGANodeList alloc] initWithNodeList:self.megaApi->search((node != nil) ? [node getCPtr] : NULL, (searchString != nil) ? [searchString UTF8String] : NULL, YES) cMemoryOwn:YES]; } +- (BOOL)processMEGANodeTree:(MEGANode *)node recursive:(BOOL)recursive delegate:(id)delegate { + return self.megaApi->processMegaTree(node ? [node getCPtr] : NULL, [self createMegaTreeProcessor:delegate], recursive); +} + - (MEGANode *)authorizeNode:(MEGANode *)node { return [[MEGANode alloc] initWithMegaNode:self.megaApi->authorizeNode((node != nil) ? [node getCPtr] : NULL) cMemoryOwn:YES]; } @@ -1371,6 +1380,22 @@ - (BOOL)setLanguageCode:(NSString *)languageCode { return self.megaApi->setLanguage(languageCode ? [languageCode UTF8String] : NULL); } +- (void)setLanguangePreferenceCode:(NSString *)languageCode delegate:(id)delegate { + self.megaApi->setLanguagePreference(languageCode ? [languageCode UTF8String] : NULL, [self createDelegateMEGARequestListener:delegate singleListener:YES]); +} + +- (void)setLanguangePreferenceCode:(NSString *)languageCode { + self.megaApi->setLanguagePreference(languageCode ? [languageCode UTF8String] : NULL); +} + +- (void)getLanguagePreferenceWithDelegate:(id)delegate { + self.megaApi->getLanguagePreference([self createDelegateMEGARequestListener:delegate singleListener:YES]); +} + +- (void)getLanguagePreference { + self.megaApi->getLanguagePreference(); +} + - (BOOL)createThumbnail:(NSString *)imagePath destinatioPath:(NSString *)destinationPath { if (imagePath == nil || destinationPath == nil) return NO; @@ -1383,6 +1408,12 @@ - (BOOL)createPreview:(NSString *)imagePath destinatioPath:(NSString *)destinati return self.megaApi->createPreview([imagePath UTF8String], [destinationPath UTF8String]); } +- (BOOL)createAvatar:(NSString *)imagePath destinationPath:(NSString *)destinationPath { + if (imagePath == nil || destinationPath == nil) return NO; + + return self.megaApi->createAvatar([imagePath UTF8String], [destinationPath UTF8String]); +} + #ifdef HAVE_LIBUV #pragma mark - HTTP Proxy Server @@ -1553,6 +1584,14 @@ - (MegaLogger *)createDelegateMegaLogger:(id)delegate { return delegateListener; } +- (MegaTreeProcessor *)createMegaTreeProcessor:(id)delegate { + if (delegate == nil) return nil; + + DelegateMEGATreeProcessorListener *delegateListener = new DelegateMEGATreeProcessorListener(delegate); + + return delegateListener; +} + - (void)freeRequestListener:(DelegateMEGARequestListener *)delegate { if (delegate == nil) return; diff --git a/bindings/ios/MEGATreeProcessorDelegate.h b/bindings/ios/MEGATreeProcessorDelegate.h new file mode 100644 index 0000000000..56b3730f9a --- /dev/null +++ b/bindings/ios/MEGATreeProcessorDelegate.h @@ -0,0 +1,43 @@ +/** + * @file MEGATreeProcessorDelegate.h + * @brief Delegate to process node trees + * + * (c) 2013-2017 by Mega Limited, Auckland, New Zealand + * + * This file is part of the MEGA SDK - Client Access Engine. + * + * Applications using the MEGA API must present a valid application key + * and comply with the the rules set forth in the Terms of Service. + * + * The MEGA SDK 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. + * + * @copyright Simplified (2-clause) BSD License. + * + * You should have received a copy of the license along with this + * program. + */ + +#import +#import "MEGANode.h" + +/** + * @brief Protocol to process node trees + * + * An implementation of this class can be used to process a node tree passing a pointer to + * [MEGASdk processMEGANodeTree:recursive:delegate:] + * + * The implementation will receive callbacks from an internal worker thread. + * + */ +@protocol MEGATreeProcessorDelegate + +/** + * @brief Function that will be called for all nodes in a node tree + * @param node MEGANode to be processed + * @return YES to continue processing nodes, NO to stop + */ +- (BOOL)processMEGANode:(MEGANode *)node; + +@end diff --git a/bindings/ios/MEGAUser.h b/bindings/ios/MEGAUser.h index 3aff7e6a49..78289bc553 100644 --- a/bindings/ios/MEGAUser.h +++ b/bindings/ios/MEGAUser.h @@ -41,7 +41,8 @@ typedef NS_ENUM(NSInteger, MEGAUserChangeType) { MEGAUserChangeTypePubKeyCu255 = 0x200, MEGAUserChangeTypePubKeyEd255 = 0x400, MEGAUserChangeTypeSigPubKeyRsa = 0x800, - MEGAUserChangeTypeSigPubKeyCu255 = 0x1600 + MEGAUserChangeTypeSigPubKeyCu255 = 0x1000, + MEGAUserChangeTypeLanguage = 0x2000 }; /** @@ -142,8 +143,11 @@ typedef NS_ENUM(NSInteger, MEGAUserChangeType) { * - MEGAUserChangeTypeSigPubKeyRsa = 0x800 * Check if the user has new or modified signature for RSA public key * - * - MEGAUserChangeTypeSigPubKeyCu255 = 0x1600 + * - MEGAUserChangeTypeSigPubKeyCu255 = 0x1000 * Check if the user has new or modified signature for Cu25519 public key + * + * - MEGAUserChangeTypeLanguage = 0x2000 + * Check if the user has modified the preferred language */ @property (readonly, nonatomic) MEGAUserChangeType changes; diff --git a/bindings/ios/Private/DelegateMEGATreeProcessorListener.h b/bindings/ios/Private/DelegateMEGATreeProcessorListener.h new file mode 100644 index 0000000000..a7c2328ab4 --- /dev/null +++ b/bindings/ios/Private/DelegateMEGATreeProcessorListener.h @@ -0,0 +1,34 @@ +/** + * @file DelegateMEGATreeProcessorListener.h + * @brief Listener to reveice nodes processed in a tree + * + * (c) 2013-2017 by Mega Limited, Auckland, New Zealand + * + * This file is part of the MEGA SDK - Client Access Engine. + * + * Applications using the MEGA API must present a valid application key + * and comply with the the rules set forth in the Terms of Service. + * + * The MEGA SDK 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. + * + * @copyright Simplified (2-clause) BSD License. + * + * You should have received a copy of the license along with this + * program. + */ + +#import +#import "megaapi.h" +#import "MEGATreeProcessorDelegate.h" + +class DelegateMEGATreeProcessorListener : public mega::MegaTreeProcessor { + +public: + DelegateMEGATreeProcessorListener(idlistener); + bool processMegaNode(mega::MegaNode *node); + +private: + idlistener; +}; diff --git a/bindings/ios/Private/DelegateMEGATreeProcessorListener.mm b/bindings/ios/Private/DelegateMEGATreeProcessorListener.mm new file mode 100644 index 0000000000..f6dbc7ec4c --- /dev/null +++ b/bindings/ios/Private/DelegateMEGATreeProcessorListener.mm @@ -0,0 +1,37 @@ +/** + * @file DelegateMEGATreeProcessorListener.mm + * @brief Listener to reveice nodes processed in a tree + * + * (c) 2013-2017 by Mega Limited, Auckland, New Zealand + * + * This file is part of the MEGA SDK - Client Access Engine. + * + * Applications using the MEGA API must present a valid application key + * and comply with the the rules set forth in the Terms of Service. + * + * The MEGA SDK 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. + * + * @copyright Simplified (2-clause) BSD License. + * + * You should have received a copy of the license along with this + * program. + */ + +#import "DelegateMEGATreeProcessorListener.h" +#import "MEGANode+init.h" + +using namespace mega; + +DelegateMEGATreeProcessorListener::DelegateMEGATreeProcessorListener(id listener) { + this->listener = listener; +} + +bool DelegateMEGATreeProcessorListener::processMegaNode(MegaNode *node) { + if (this->listener) { + return [listener processMEGANode:[[MEGANode alloc] initWithMegaNode:node cMemoryOwn:NO]]; + } + + return false;; +} diff --git a/include/mega/gfx.h b/include/mega/gfx.h index e74a877c88..d78090e45d 100644 --- a/include/mega/gfx.h +++ b/include/mega/gfx.h @@ -56,14 +56,16 @@ class MEGA_API GfxProc // FIXME: read dynamically from API server typedef enum { THUMBNAIL120X120, PREVIEW1000x1000 } meta_t; + typedef enum { AVATAR250X250 } avatar_t; // generate and save a fa to a file - bool savefa(string*, meta_t, string*); + bool savefa(string*, int, int, string*); // - w*0: largest square crop at the center (landscape) or at 1/6 of the height above center (portrait) // - w*h: resize to fit inside w*h bounding box static const int dimensions[][2]; - + static const int dimensionsavatar[][2]; + MegaClient* client; int w, h; diff --git a/include/mega/megaclient.h b/include/mega/megaclient.h index 60033ac971..88dadeeb45 100644 --- a/include/mega/megaclient.h +++ b/include/mega/megaclient.h @@ -420,6 +420,9 @@ class MEGA_API MegaClient // send chat stats void sendchatstats(const char*); + // send chat logs with user's annonymous id + void sendchatlogs(const char*, const char*); + // send a HTTP request void httprequest(const char*, int, bool = false, const char* = NULL, int = 1); @@ -1153,6 +1156,7 @@ class MEGA_API MegaClient void discarduser(handle); void discarduser(const char*); void mappcr(handle, PendingContactRequest*); + bool discardnotifieduser(User *); PendingContactRequest* findpcr(handle); diff --git a/include/mega/types.h b/include/mega/types.h index 331320a47d..56edc52341 100644 --- a/include/mega/types.h +++ b/include/mega/types.h @@ -406,8 +406,7 @@ typedef enum { ATTR_BIRTHDAY = 11, // public - char array - non-versioned ATTR_BIRTHMONTH = 12, // public - char array - non-versioned ATTR_BIRTHYEAR = 13, // public - char array - non-versioned -// USER_ATTR_AUTHRSA = 10, -// USER_ATTR_AUTHCU255 = 11 + ATTR_LANGUAGE = 14 // private, non-encrypted - char array in B64 - non-versioned } attr_t; typedef map userattr_map; diff --git a/include/mega/user.h b/include/mega/user.h index ae9f8fe5ae..2c349b455f 100644 --- a/include/mega/user.h +++ b/include/mega/user.h @@ -62,6 +62,7 @@ struct MEGA_API User : public Cachable bool country : 1; bool birthday : 1; // wraps status of birthday, birthmonth, birthyear bool email : 1; + bool language : 1; // preferred language code } changed; // user's public key diff --git a/include/megaapi.h b/include/megaapi.h index 41c828b41d..6e66256520 100644 --- a/include/megaapi.h +++ b/include/megaapi.h @@ -1098,7 +1098,8 @@ class MegaUser CHANGE_TYPE_PUBKEY_CU255 = 0x200, CHANGE_TYPE_PUBKEY_ED255 = 0x400, CHANGE_TYPE_SIG_PUBKEY_RSA = 0x800, - CHANGE_TYPE_SIG_PUBKEY_CU25 = 0x1600 + CHANGE_TYPE_SIG_PUBKEY_CU255 = 0x1000, + CHANGE_TYPE_LANGUAGE = 0x2000 }; /** @@ -1147,9 +1148,12 @@ class MegaUser * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_RSA = 0x800 * Check if the user has new or modified signature for RSA public key * - * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU255 = 0x1600 + * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU255 = 0x1000 * Check if the user has new or modified signature for Cu25519 public key * + * - MegaUser::CHANGE_TYPE_LANGUAGE = 0x2000 + * Check if the user has modified the preferred language + * * @return true if this user has an specific change */ virtual bool hasChanged(int changeType); @@ -1198,8 +1202,11 @@ class MegaUser * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_RSA = 0x800 * Check if the user has new or modified signature for RSA public key * - * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU255 = 0x1600 + * - MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU255 = 0x1000 * Check if the user has new or modified signature for Cu25519 public key + * + * - MegaUser::CHANGE_TYPE_LANGUAGE = 0x2000 + * Check if the user has modified the preferred language */ virtual int getChanges(); @@ -4495,10 +4502,9 @@ class MegaApi USER_ATTR_ED25519_PUBLIC_KEY = 5, // public - byte array USER_ATTR_CU25519_PUBLIC_KEY = 6, // public - byte array USER_ATTR_KEYRING = 7, // private - byte array - USER_ATTR_SIG_RSA_PUBLIC_KEY = 8, // public - byte array - USER_ATTR_SIG_CU255_PUBLIC_KEY = 9 // public - byte array -// USER_ATTR_AUTHRSA = 8, -// USER_ATTR_AUTHCU255 = + USER_ATTR_SIG_RSA_PUBLIC_KEY = 8, // public - byte array + USER_ATTR_SIG_CU255_PUBLIC_KEY = 9, // public - byte array + USER_ATTR_LANGUAGE = 14 // private - char array }; enum { @@ -6079,6 +6085,8 @@ class MegaApi * Get the signature of RSA public key of the user (public) * MegaApi::USER_ATTR_SIG_CU255_PUBLIC_KEY = 9 * Get the signature of Cu25519 public key of the user (public) + * MegaApi::USER_ATTR_LANGUAGE = 14 + * Get the preferred language of the user (private, non-encrypted) * * @param listener MegaRequestListener to track this request */ @@ -6124,6 +6132,8 @@ class MegaApi * Get the signature of RSA public key of the user (public) * MegaApi::USER_ATTR_SIG_CU255_PUBLIC_KEY = 9 * Get the signature of Cu25519 public key of the user (public) + * MegaApi::USER_ATTR_LANGUAGE = 14 + * Get the preferred language of the user (private, non-encrypted) * * @param listener MegaRequestListener to track this request */ @@ -6166,6 +6176,8 @@ class MegaApi * Get the signature of RSA public key of the user (public) * MegaApi::USER_ATTR_SIG_CU255_PUBLIC_KEY = 9 * Get the signature of Cu25519 public key of the user (public) + * MegaApi::USER_ATTR_LANGUAGE = 14 + * Get the preferred language of the user (private, non-encrypted) * * @param listener MegaRequestListener to track this request */ @@ -6274,13 +6286,13 @@ class MegaApi * Valid values are: * * MegaApi::USER_ATTR_FIRSTNAME = 1 - * Get the firstname of the user (public) + * Set the firstname of the user (public) * MegaApi::USER_ATTR_LASTNAME = 2 - * Get the lastname of the user (public) + * Set the lastname of the user (public) * MegaApi::USER_ATTR_ED25519_PUBLIC_KEY = 5 - * Get the public key Ed25519 of the user (public) + * Set the public key Ed25519 of the user (public) * MegaApi::USER_ATTR_CU25519_PUBLIC_KEY = 6 - * Get the public key Cu25519 of the user (public) + * Set the public key Cu25519 of the user (public) * * @param value New attribute value * @param listener MegaRequestListener to track this request @@ -9099,6 +9111,33 @@ class MegaApi */ bool setLanguage(const char* languageCode); + /** + * @brief Set the preferred language of the user + * + * Valid data in the MegaRequest object received in onRequestFinish: + * - MegaRequest::getText - Return the language code + * + * If the language code is unknown for the SDK, the error code will be MegaError::API_ENOENT + * + * This attribute is automatically created by the server. Apps only need + * to set the new value when the user changes the language. + * + * @param Language code to be set + * @param listener MegaRequestListener to track this request + */ + void setLanguagePreference(const char* languageCode, MegaRequestListener *listener = NULL); + + /** + * @brief Get the preferred language of the user + * + * Valid data in the MegaRequest object received in onRequestFinish when the error code + * is MegaError::API_OK: + * - MegaRequest::getText - Return the language code + * + * @param listener MegaRequestListener to track this request + */ + void getLanguagePreference(MegaRequestListener *listener = NULL); + /** * @brief Keep retrying when public key pinning fails * @@ -9229,6 +9268,14 @@ class MegaApi */ bool createPreview(const char *imagePath, const char *dstPath); + /** + * @brief Create an avatar from an image + * @param imagePath Image path + * @param dstPath Destination path for the avatar (including the file name) + * @return True if the avatar was successfully created, otherwise false. + */ + bool createAvatar(const char *imagePath, const char *dstPath); + /** * @brief Convert a Base64 string to Base32 * @@ -9861,6 +9908,9 @@ class MegaApi * @brief Send data related to MEGAchat to the stats server * * The associated request type with this request is MegaRequest::TYPE_CHAT_STATS + * Valid data in the MegaRequest object received on callbacks: + * - MegaRequest::getName - Returns the data provided. + * - MegaRequest::getParamType - Returns number 1 * * Valid data in the MegaRequest object received in onRequestFinish when the error code * is MegaError::API_OK: @@ -9873,6 +9923,27 @@ class MegaApi */ void sendChatStats(const char *data, MegaRequestListener *listener = NULL); + /** + * @brief Send logs related to MEGAchat to the logs server + * + * The associated request type with this request is MegaRequest::TYPE_CHAT_STATS + * Valid data in the MegaRequest object received on callbacks: + * - MegaRequest::getName - Returns the data provided. + * - MegaRequest::getSessionKey - Returns the aid provided + * - MegaRequest::getParamType - Returns number 2 + * + * Valid data in the MegaRequest object received in onRequestFinish when the error code + * is MegaError::API_OK: + * - MegaRequest::getNumber - Return the HTTP status code from the stats server + * - MegaRequest::getText - Returns the JSON response from the stats server + * - MegaRequest::getTotalBytes - Returns the number of bytes in the response + * + * @param data JSON data to send to the logs server + * @param aid User's anonymous identifier for logging + * @param listener MegaRequestListener to track this request + */ + void sendChatLogs(const char *data, const char *aid, MegaRequestListener *listener = NULL); + /** * @brief Get the list of chatrooms for this account * diff --git a/include/megaapi_impl.h b/include/megaapi_impl.h index 6536a3251f..aa64904d51 100644 --- a/include/megaapi_impl.h +++ b/include/megaapi_impl.h @@ -1633,6 +1633,9 @@ class MegaApiImpl : public MegaApp void changeApiUrl(const char *apiURL, bool disablepkp = false); bool setLanguage(const char* languageCode); + void setLanguagePreference(const char* languageCode, MegaRequestListener *listener = NULL); + void getLanguagePreference(MegaRequestListener *listener = NULL); + bool getLanguageCode(const char* languageCode, std::string* code); void retrySSLerrors(bool enable); void setPublicKeyPinning(bool enable); void pauseActionPackets(); @@ -1655,6 +1658,7 @@ class MegaApiImpl : public MegaApp bool createThumbnail(const char* imagePath, const char *dstPath); bool createPreview(const char* imagePath, const char *dstPath); + bool createAvatar(const char* imagePath, const char *dstPath); bool isOnline(); @@ -1703,6 +1707,7 @@ class MegaApiImpl : public MegaApp void getChatPresenceURL(MegaRequestListener *listener = NULL); void registerPushNotification(int deviceType, const char *token, MegaRequestListener *listener = NULL); void sendChatStats(const char *data, MegaRequestListener *listener = NULL); + void sendChatLogs(const char *data, const char *aid, MegaRequestListener *listener = NULL); MegaTextChatList *getChatList(); MegaHandleList *getAttachmentAccess(MegaHandle chatid, MegaHandle h); bool hasAccessToAttachment(MegaHandle chatid, MegaHandle h, MegaHandle uh); diff --git a/src/commands.cpp b/src/commands.cpp index 37d23cc5f2..c32a6529bc 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -2472,6 +2472,11 @@ void CommandPutUA::procresult() e = API_OK; User *u = client->ownuser(); + if (User::scope(at) == '^') // store in binary format + { + string avB64 = av; + Base64::atob(avB64, av); + } u->setattr(at, &av, NULL); u->setTag(tag ? tag : -1); client->notifyuser(u); @@ -2582,7 +2587,7 @@ void CommandGetUA::procresult() switch (scope) { - case '*': // private + case '*': // private, encrypted { // decrypt the data and build the TLV records TLVstore *tlvRecords = TLVstore::containerToTLVrecords(&value, &client->key); @@ -2620,6 +2625,13 @@ void CommandGetUA::procresult() client->app->getua_result((byte*) value.data(), value.size()); break; + case '^': // private, non-encrypted + + // store the value in cache in binary format + u->setattr(at, &value, &version); + client->app->getua_result((byte*) value.data(), value.size()); + break; + default: // legacy attributes or unknown attribute if (at != ATTR_FIRSTNAME && // protected at != ATTR_LASTNAME && // protected diff --git a/src/gfx.cpp b/src/gfx.cpp index 7d97f604c8..a0b390090a 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -28,6 +28,10 @@ const int GfxProc::dimensions[][2] = { { 1000, 1000 } // PREVIEW1000x1000: scaled version inside 1000x1000 bounding square }; +const int GfxProc::dimensionsavatar[][2] = { + { 250, 0 } // AVATAR250X250: square thumbnail, cropped from near center +}; + bool GfxProc::isgfx(string* localfilename) { char ext[8]; @@ -162,19 +166,18 @@ int GfxProc::gendimensionsputfa(FileAccess* fa, string* localfilename, handle th return numputs; } -bool GfxProc::savefa(string *localfilepath, GfxProc::meta_t type, string *localdstpath) +bool GfxProc::savefa(string *localfilepath, int width, int height, string *localdstpath) { if (!isgfx(localfilepath) // (this assumes that the width of the largest dimension is max) - || !readbitmap(NULL, localfilepath, dimensions[sizeof dimensions/sizeof dimensions[0]-1][0])) + || !readbitmap(NULL, localfilepath, width > height ? width : height)) { return false; } - int w = dimensions[type][0]; - int h = dimensions[type][1]; - if (type == (sizeof dimensions/sizeof dimensions[0] - 1) - && this->w < w && this->h < h ) + int w = width; + int h = height; + if (this->w < w && this->h < h) { LOG_debug << "Skipping upsizing of local preview"; w = this->w; diff --git a/src/gfx/GfxProcCG.mm b/src/gfx/GfxProcCG.mm index 0d54b7b245..6f67130d32 100644 --- a/src/gfx/GfxProcCG.mm +++ b/src/gfx/GfxProcCG.mm @@ -59,7 +59,7 @@ } const char* GfxProcCG::supportedformats() { - return ".jpg.png.bmp.tif.tiff.jpeg.gif.pdf.ico.cur.mov.mp4.m4v.3gp."; + return ".jpg.png.bmp.tif.tiff.jpeg.gif.pdf.ico.cur.mov.mp4.m4v.3gp.heic."; } bool GfxProcCG::readbitmap(FileAccess* fa, string* name, int size) { diff --git a/src/megaapi.cpp b/src/megaapi.cpp index 43d019aa92..ea4aebab1f 100644 --- a/src/megaapi.cpp +++ b/src/megaapi.cpp @@ -2552,6 +2552,16 @@ bool MegaApi::setLanguage(const char *languageCode) return pImpl->setLanguage(languageCode); } +void MegaApi::setLanguagePreference(const char *languageCode, MegaRequestListener *listener) +{ + pImpl->setLanguagePreference(languageCode, listener); +} + +void MegaApi::getLanguagePreference(MegaRequestListener *listener) +{ + pImpl->getLanguagePreference(listener); +} + void MegaApi::retrySSLerrors(bool enable) { pImpl->retrySSLerrors(enable); @@ -3637,6 +3647,11 @@ void MegaApi::sendChatStats(const char *data, MegaRequestListener *listener) pImpl->sendChatStats(data, listener); } +void MegaApi::sendChatLogs(const char *data, const char *aid, MegaRequestListener *listener) +{ + pImpl->sendChatLogs(data, aid, listener); +} + MegaTextChatList* MegaApi::getChatList() { return pImpl->getChatList(); @@ -3738,6 +3753,11 @@ bool MegaApi::createPreview(const char *imagePath, const char *dstPath) return pImpl->createPreview(imagePath, dstPath); } +bool MegaApi::createAvatar(const char *imagePath, const char *dstPath) +{ + return pImpl->createAvatar(imagePath, dstPath); +} + MegaHashSignature::MegaHashSignature(const char *base64Key) { pImpl = new MegaHashSignatureImpl(base64Key); diff --git a/src/megaapi_impl.cpp b/src/megaapi_impl.cpp index 93d68ef227..5abcde35d8 100644 --- a/src/megaapi_impl.cpp +++ b/src/megaapi_impl.cpp @@ -1169,7 +1169,11 @@ MegaUserPrivate::MegaUserPrivate(User *user) : MegaUser() } if(user->changed.sigCu255) { - changed |= MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU25; + changed |= MegaUser::CHANGE_TYPE_SIG_PUBKEY_CU255; + } + if(user->changed.language) + { + changed |= MegaUser::CHANGE_TYPE_LANGUAGE; } } @@ -4019,6 +4023,10 @@ string MegaApiImpl::userAttributeToString(int type) case MegaApi::USER_ATTR_KEYRING: attrname = "*keyring"; break; + + case MegaApi::USER_ATTR_LANGUAGE: + attrname = "!lang"; + break; } return attrname; @@ -4049,6 +4057,10 @@ char MegaApiImpl::userAttributeToScope(int type) scope = '*'; break; + case MegaApi::USER_ATTR_LANGUAGE: + scope = '^'; + break; + default: LOG_err << "Getting invalid scope"; scope = 0; @@ -6336,7 +6348,7 @@ char *MegaApiImpl::unescapeFsIncompatible(const char *name) bool MegaApiImpl::createThumbnail(const char *imagePath, const char *dstPath) { - if (!gfxAccess) + if (!gfxAccess || !imagePath || !dstPath) { return false; } @@ -6350,7 +6362,8 @@ bool MegaApiImpl::createThumbnail(const char *imagePath, const char *dstPath) fsAccess->path2local(&utf8DstPath, &localDstPath); sdkMutex.lock(); - bool result = gfxAccess->savefa(&localImagePath, GfxProc::THUMBNAIL120X120, &localDstPath); + bool result = gfxAccess->savefa(&localImagePath, GfxProc::dimensions[GfxProc::THUMBNAIL120X120][0], + GfxProc::dimensions[GfxProc::THUMBNAIL120X120][1], &localDstPath); sdkMutex.unlock(); return result; @@ -6358,7 +6371,7 @@ bool MegaApiImpl::createThumbnail(const char *imagePath, const char *dstPath) bool MegaApiImpl::createPreview(const char *imagePath, const char *dstPath) { - if (!gfxAccess) + if (!gfxAccess || !imagePath || !dstPath) { return false; } @@ -6372,12 +6385,36 @@ bool MegaApiImpl::createPreview(const char *imagePath, const char *dstPath) fsAccess->path2local(&utf8DstPath, &localDstPath); sdkMutex.lock(); - bool result = gfxAccess->savefa(&localImagePath, GfxProc::PREVIEW1000x1000, &localDstPath); + bool result = gfxAccess->savefa(&localImagePath, GfxProc::dimensions[GfxProc::PREVIEW1000x1000][0], + GfxProc::dimensions[GfxProc::PREVIEW1000x1000][1], &localDstPath); sdkMutex.unlock(); return result; } +bool MegaApiImpl::createAvatar(const char *imagePath, const char *dstPath) +{ + if (!gfxAccess || !imagePath || !dstPath) + { + return false; + } + + string utf8ImagePath = imagePath; + string localImagePath; + fsAccess->path2local(&utf8ImagePath, &localImagePath); + + string utf8DstPath = dstPath; + string localDstPath; + fsAccess->path2local(&utf8DstPath, &localDstPath); + + sdkMutex.lock(); + bool result = gfxAccess->savefa(&localImagePath, GfxProc::dimensionsavatar[GfxProc::AVATAR250X250][0], + GfxProc::dimensionsavatar[GfxProc::AVATAR250X250][1], &localDstPath); + sdkMutex.unlock(); + + return result; +} + bool MegaApiImpl::isOnline() { return !client->httpio->noinetds; @@ -6776,6 +6813,17 @@ void MegaApiImpl::sendChatStats(const char *data, MegaRequestListener *listener) { MegaRequestPrivate *request = new MegaRequestPrivate(MegaRequest::TYPE_CHAT_STATS, listener); request->setName(data); + request->setParamType(1); + requestQueue.push(request); + waiter->notify(); +} + +void MegaApiImpl::sendChatLogs(const char *data, const char* aid, MegaRequestListener *listener) +{ + MegaRequestPrivate *request = new MegaRequestPrivate(MegaRequest::TYPE_CHAT_STATS, listener); + request->setName(data); + request->setSessionKey(aid); + request->setParamType(2); requestQueue.push(request); waiter->notify(); } @@ -7500,7 +7548,32 @@ void MegaApiImpl::changeApiUrl(const char *apiURL, bool disablepkp) bool MegaApiImpl::setLanguage(const char *languageCode) { - if (!languageCode) + string code; + if (!getLanguageCode(languageCode, &code)) + { + return false; + } + + bool val; + sdkMutex.lock(); + val = client->setlang(&code); + sdkMutex.unlock(); + return val; +} + +void MegaApiImpl::setLanguagePreference(const char *languageCode, MegaRequestListener *listener) +{ + setUserAttr(MegaApi::USER_ATTR_LANGUAGE, languageCode, listener); +} + +void MegaApiImpl::getLanguagePreference(MegaRequestListener *listener) +{ + getUserAttr(NULL, MegaApi::USER_ATTR_LANGUAGE, NULL, listener); +} + +bool MegaApiImpl::getLanguageCode(const char *languageCode, string *code) +{ + if (!languageCode || !code) { return false; } @@ -7511,120 +7584,121 @@ bool MegaApiImpl::setLanguage(const char *languageCode) return false; } + code->clear(); string s = languageCode; transform(s.begin(), s.end(), s.begin(), ::tolower); - JSON json; - string code; - nameid id = json.getnameid(s.c_str()); - switch (id) - { - // Regular language codes - case MAKENAMEID2('a', 'r'): - case MAKENAMEID2('b', 'g'): - case MAKENAMEID2('d', 'e'): - case MAKENAMEID2('e', 'n'): - case MAKENAMEID2('e', 's'): - case MAKENAMEID2('f', 'a'): - case MAKENAMEID2('f', 'i'): - case MAKENAMEID2('f', 'r'): - case MAKENAMEID2('h', 'e'): - case MAKENAMEID2('h', 'u'): - case MAKENAMEID2('i', 'd'): - case MAKENAMEID2('i', 't'): - case MAKENAMEID2('n', 'l'): - case MAKENAMEID2('p', 'l'): - case MAKENAMEID2('r', 'o'): - case MAKENAMEID2('r', 'u'): - case MAKENAMEID2('s', 'k'): - case MAKENAMEID2('s', 'l'): - case MAKENAMEID2('s', 'r'): - case MAKENAMEID2('t', 'h'): - case MAKENAMEID2('t', 'l'): - case MAKENAMEID2('t', 'r'): - case MAKENAMEID2('u', 'k'): - case MAKENAMEID2('v', 'i'): - - // Not used on apps - case MAKENAMEID2('c', 'z'): - case MAKENAMEID2('j', 'p'): - case MAKENAMEID2('k', 'r'): - case MAKENAMEID2('b', 'r'): - case MAKENAMEID2('s', 'e'): - case MAKENAMEID2('c', 'n'): - case MAKENAMEID2('c', 't'): - code = s; - break; + while (s.size() >= 2) + { + JSON json; + nameid id = json.getnameid(s.c_str()); + switch (id) + { + // Regular language codes + case MAKENAMEID2('a', 'r'): + case MAKENAMEID2('b', 'g'): + case MAKENAMEID2('d', 'e'): + case MAKENAMEID2('e', 'n'): + case MAKENAMEID2('e', 's'): + case MAKENAMEID2('f', 'a'): + case MAKENAMEID2('f', 'i'): + case MAKENAMEID2('f', 'r'): + case MAKENAMEID2('h', 'e'): + case MAKENAMEID2('h', 'u'): + case MAKENAMEID2('i', 'd'): + case MAKENAMEID2('i', 't'): + case MAKENAMEID2('n', 'l'): + case MAKENAMEID2('p', 'l'): + case MAKENAMEID2('r', 'o'): + case MAKENAMEID2('r', 'u'): + case MAKENAMEID2('s', 'k'): + case MAKENAMEID2('s', 'l'): + case MAKENAMEID2('s', 'r'): + case MAKENAMEID2('t', 'h'): + case MAKENAMEID2('t', 'l'): + case MAKENAMEID2('t', 'r'): + case MAKENAMEID2('u', 'k'): + case MAKENAMEID2('v', 'i'): + + // Not used on apps + case MAKENAMEID2('c', 'z'): + case MAKENAMEID2('j', 'p'): + case MAKENAMEID2('k', 'r'): + case MAKENAMEID2('b', 'r'): + case MAKENAMEID2('s', 'e'): + case MAKENAMEID2('c', 'n'): + case MAKENAMEID2('c', 't'): + *code = s; + break; - // Conversions - case MAKENAMEID2('c', 's'): - code = "cz"; - break; + // Conversions + case MAKENAMEID2('c', 's'): + *code = "cz"; + break; - case MAKENAMEID2('j', 'a'): - code = "jp"; - break; + case MAKENAMEID2('j', 'a'): + *code = "jp"; + break; - case MAKENAMEID2('k', 'o'): - code = "kr"; - break; + case MAKENAMEID2('k', 'o'): + *code = "kr"; + break; - case MAKENAMEID2('p', 't'): - case MAKENAMEID5('p', 't', '_', 'b', 'r'): - case MAKENAMEID5('p', 't', '-', 'b', 'r'): - case MAKENAMEID5('p', 't', '_', 'p', 't'): - case MAKENAMEID5('p', 't', '-', 'p', 't'): - code = "br"; - break; + case MAKENAMEID2('p', 't'): + case MAKENAMEID5('p', 't', '_', 'b', 'r'): + case MAKENAMEID5('p', 't', '-', 'b', 'r'): + case MAKENAMEID5('p', 't', '_', 'p', 't'): + case MAKENAMEID5('p', 't', '-', 'p', 't'): + *code = "br"; + break; - case MAKENAMEID2('s', 'v'): - code = "se"; - break; + case MAKENAMEID2('s', 'v'): + *code = "se"; + break; - case MAKENAMEID5('z', 'h', '_', 'c', 'n'): - case MAKENAMEID5('z', 'h', '-', 'c', 'n'): - case MAKENAMEID7('z', 'h', '_', 'h', 'a', 'n', 's'): - case MAKENAMEID7('z', 'h', '-', 'h', 'a', 'n', 's'): - code = "cn"; - break; + case MAKENAMEID5('z', 'h', '_', 'c', 'n'): + case MAKENAMEID5('z', 'h', '-', 'c', 'n'): + case MAKENAMEID7('z', 'h', '_', 'h', 'a', 'n', 's'): + case MAKENAMEID7('z', 'h', '-', 'h', 'a', 'n', 's'): + *code = "cn"; + break; - case MAKENAMEID5('z', 'h', '_', 't', 'w'): - case MAKENAMEID5('z', 'h', '-', 't', 'w'): - case MAKENAMEID7('z', 'h', '_', 'h', 'a', 'n', 't'): - case MAKENAMEID7('z', 'h', '-', 'h', 'a', 'n', 't'): - code = "ct"; - break; + case MAKENAMEID5('z', 'h', '_', 't', 'w'): + case MAKENAMEID5('z', 'h', '-', 't', 'w'): + case MAKENAMEID7('z', 'h', '_', 'h', 'a', 'n', 't'): + case MAKENAMEID7('z', 'h', '-', 'h', 'a', 'n', 't'): + *code = "ct"; + break; - case MAKENAMEID2('i', 'n'): - code = "id"; - break; + case MAKENAMEID2('i', 'n'): + *code = "id"; + break; - case MAKENAMEID2('i', 'w'): - code = "he"; - break; + case MAKENAMEID2('i', 'w'): + *code = "he"; + break; - // Not supported in the web - case MAKENAMEID2('e', 'e'): - case MAKENAMEID2('h', 'r'): - case MAKENAMEID2('k', 'a'): - break; + // Not supported in the web + case MAKENAMEID2('e', 'e'): + case MAKENAMEID2('h', 'r'): + case MAKENAMEID2('k', 'a'): + break; - default: - LOG_warn << "Unknown language code: " << languageCode; - return false; - } + default: + LOG_debug << "Unknown language code: " << s.c_str(); + break; + } - if (!code.size()) - { - LOG_debug << "Unsupported language code: " << languageCode; - return true; + if (code->size()) + { + return true; + } + + s.resize(s.size() - 1); } - bool val; - sdkMutex.lock(); - val = client->setlang(&code); - sdkMutex.unlock(); - return val; + LOG_debug << "Unsupported language code: " << languageCode; + return false; } void MegaApiImpl::retrySSLerrors(bool enable) @@ -10439,6 +10513,12 @@ void MegaApiImpl::putua_result(error e) } #endif + // if user just set the preferred language... change the GET param to the new language + if (request->getParamType() == MegaApi::USER_ATTR_LANGUAGE && e == API_OK) + { + setLanguage(request->getText()); + } + fireOnRequestFinish(request, megaError); } @@ -10499,6 +10579,7 @@ void MegaApiImpl::getua_result(byte* data, unsigned len) // null-terminated char arrays case MegaApi::USER_ATTR_FIRSTNAME: case MegaApi::USER_ATTR_LASTNAME: + case MegaApi::USER_ATTR_LANGUAGE: // it's a c-string in binary format, want the plain data { string str((const char*)data,len); request->setText(str.c_str()); @@ -13033,7 +13114,20 @@ void MegaApiImpl::sendPendingRequests() case MegaRequest::TYPE_REMOVE: { Node* node = client->nodebyhandle(request->getNodeHandle()); - if(!node) { e = API_EARGS; break; } + + if (!node) + { + e = API_ENOENT; + break; + } + + if (node->type == ROOTNODE + || node->type == INCOMINGNODE + || node->type == RUBBISHNODE) // rootnodes cannot be deleted + { + e = API_EACCESS; + break; + } e = client->unlink(node); break; @@ -13382,6 +13476,26 @@ void MegaApiImpl::sendPendingRequests() break; } + else if (scope == '^') + { + if (!value || type != ATTR_LANGUAGE) + { + e = API_EARGS; + break; + } + + string code; + if (!getLanguageCode(value, &code)) + { + e = API_ENOENT; + break; + } + + string valueB64; + Base64::btoa(code, valueB64); + + client->putua(type, (byte *)valueB64.data(), valueB64.length()); + } else // any other type of attribute { if (!value) @@ -14900,7 +15014,26 @@ void MegaApiImpl::sendPendingRequests() break; } - client->sendchatstats(json); + int type = request->getParamType(); + if (type == 1) + { + client->sendchatstats(json); + } + else if (type == 2) + { + const char *aid = request->getSessionKey(); + if (!aid) + { + e = API_EARGS; + break; + } + + client->sendchatlogs(json, aid); + } + else + { + e = API_EARGS; + } break; } #endif diff --git a/src/megaclient.cpp b/src/megaclient.cpp index 6c47719a82..0612cac552 100644 --- a/src/megaclient.cpp +++ b/src/megaclient.cpp @@ -37,7 +37,7 @@ string MegaClient::APIURL = "https://g.api.mega.co.nz/"; string MegaClient::GELBURL = "https://gelb.karere.mega.nz/"; // root URL for chat stats -string MegaClient::CHATSTATSURL = "https://stats.karere.mega.nz/msglog"; +string MegaClient::CHATSTATSURL = "https://stats.karere.mega.nz/"; // maximum number of concurrent transfers (uploads + downloads) const unsigned MegaClient::MAXTOTALTRANSFERS = 30; @@ -3152,8 +3152,22 @@ void MegaClient::sendchatstats(const char *json) req->maxretries = 0; pendinghttp[reqtag] = req; req->posturl = CHATSTATSURL; - //FIXME: aid per app? - req->posturl.append("?aid=kn-asdasdsdf&t=e"); + req->posturl.append("stats"); + req->protect = true; + req->out->assign(json); + req->post(this); +} + +void MegaClient::sendchatlogs(const char *json, const char *aid) +{ + GenericHttpReq *req = new GenericHttpReq(); + req->tag = reqtag; + req->maxretries = 0; + pendinghttp[reqtag] = req; + req->posturl = CHATSTATSURL; + req->posturl.append("msglog?aid="); + req->posturl.append(aid); + req->posturl.append("&t=e"); req->protect = true; req->out->assign(json); req->post(this); @@ -7035,6 +7049,7 @@ void MegaClient::mapuser(handle uh, const char* email) if (mit != umindex.end() && mit->second != hit->second && (users[mit->second].show != INACTIVE || users[mit->second].userhandle == me)) { // duplicated user: one by email, one by handle + discardnotifieduser(&users[mit->second]); assert(!users[mit->second].sharing.size()); users.erase(mit->second); } @@ -7092,6 +7107,8 @@ void MegaClient::discarduser(handle uh) u->pkrs.pop_front(); } + discardnotifieduser(u); + umindex.erase(u->email); users.erase(uhindex[uh]); uhindex.erase(uh); @@ -7117,6 +7134,8 @@ void MegaClient::discarduser(const char *email) u->pkrs.pop_front(); } + discardnotifieduser(u); + uhindex.erase(u->userhandle); users.erase(umindex[email]); umindex.erase(email); @@ -7145,6 +7164,19 @@ void MegaClient::mappcr(handle id, PendingContactRequest *pcr) pcrindex[id] = pcr; } +bool MegaClient::discardnotifieduser(User *u) +{ + for (user_vector::iterator it = usernotify.begin(); it != usernotify.end(); it++) + { + if (*it == u) + { + usernotify.erase(it); + return true; // no duplicated users in the notify vector + } + } + return false; +} + // sharekey distribution request - walk array consisting of {node,user+}+ handle tuples // and submit public key requests void MegaClient::procsr(JSON* j) @@ -7493,6 +7525,7 @@ error MegaClient::removecontact(const char* email, visibility_t show) * "*" - Private and encrypted. Use a TLV container (key-value) * "#" - Protected and plain text, accessible only by contacts. * "+" - Public and plain text, accessible by anyone knowing userhandle + * "^" - Private and non-encrypted. * * @param an Attribute name. * @param av Attribute value. diff --git a/src/posix/net.cpp b/src/posix/net.cpp index 8ef3f5853e..5dde86e1f2 100644 --- a/src/posix/net.cpp +++ b/src/posix/net.cpp @@ -1551,7 +1551,7 @@ void CurlHttpIO::post(HttpReq* req, const char* data, unsigned len) if (reset) { - LOG_err << "Error in c-ares. Reinitializing..."; + LOG_debug << "Error in c-ares. Reinitializing..."; reset = false; ares_destroy(ares); struct ares_options options; diff --git a/src/user.cpp b/src/user.cpp index e2e7b5bb4e..d5b2141a98 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -373,6 +373,10 @@ string User::attr2string(attr_t type) attrname = "birthyear"; break; + case ATTR_LANGUAGE: + attrname = "^!lang"; + break; + case ATTR_UNKNOWN: // empty string break; } @@ -438,6 +442,10 @@ attr_t User::string2attr(const char* name) { return ATTR_BIRTHYEAR; } + else if(!strcmp(name, "^!lang")) + { + return ATTR_LANGUAGE; + } else { return ATTR_UNKNOWN; // attribute not recognized @@ -455,6 +463,7 @@ bool User::needversioning(attr_t at) case ATTR_BIRTHDAY: case ATTR_BIRTHMONTH: case ATTR_BIRTHYEAR: + case ATTR_LANGUAGE: return 0; case ATTR_AUTHRING: @@ -487,6 +496,9 @@ char User::scope(attr_t at) case ATTR_SIG_CU255_PUBK: return '+'; + case ATTR_LANGUAGE: + return '^'; + default: return '0'; } @@ -557,6 +569,10 @@ bool User::setChanged(attr_t at) changed.birthday = true; break; + case ATTR_LANGUAGE: + changed.language = true; + break; + default: return false; } diff --git a/tests/sdk_test.cpp b/tests/sdk_test.cpp index fcbaa216d6..9b9441c7fb 100644 --- a/tests/sdk_test.cpp +++ b/tests/sdk_test.cpp @@ -537,10 +537,11 @@ void SdkTest::purgeTree(MegaNode *p) } } -bool SdkTest::waitForResponse(bool *responseReceived, int timeout) +bool SdkTest::waitForResponse(bool *responseReceived, unsigned int timeout) { timeout *= 1000000; // convert to micro-seconds - int tWaited = 0; // microseconds + unsigned int tWaited = 0; // microseconds + bool connRetried = false; while(!(*responseReceived)) { usleep(pollingT); @@ -552,6 +553,16 @@ bool SdkTest::waitForResponse(bool *responseReceived, int timeout) { return false; // timeout is expired } + // if no response after 2 minutes... + else if (!connRetried && tWaited > (pollingT * 240)) + { + megaApi[0]->retryPendingConnections(true); + if (megaApi[1] && megaApi[1]->isLoggedIn()) + { + megaApi[1]->retryPendingConnections(true); + } + connRetried = true; + } } } @@ -784,7 +795,7 @@ void MegaLoggerSDK::log(const char *time, int loglevel, const char *source, cons sdklog << message << " (" << source << ")" << endl; bool errorLevel = ((loglevel == logError) && !testingInvalidArgs); - ASSERT_FALSE(errorLevel) << "Test aborted due to an SDK error."; + ASSERT_FALSE(errorLevel) << "Test aborted due to an SDK error: " << message << " (" << source << ")"; } void SdkTest::setUserAttribute(int type, string value, int timeout) @@ -805,24 +816,24 @@ void SdkTest::setUserAttribute(int type, string value, int timeout) ASSERT_EQ(MegaError::API_OK, lastError[0]) << "User attribute setup failed (error: " << lastError[0] << ")"; } -void SdkTest::getUserAttribute(MegaUser *u, int type, int timeout) +void SdkTest::getUserAttribute(MegaUser *u, int type, int timeout, int accountIndex) { - requestFlags[1][MegaRequest::TYPE_GET_ATTR_USER] = false; + requestFlags[accountIndex][MegaRequest::TYPE_GET_ATTR_USER] = false; if (type == MegaApi::USER_ATTR_AVATAR) { - megaApi[1]->getUserAvatar(u, AVATARDST.data()); + megaApi[accountIndex]->getUserAvatar(u, AVATARDST.data()); } else { - megaApi[1]->getUserAttribute(u, type); + megaApi[accountIndex]->getUserAttribute(u, type); } - ASSERT_TRUE( waitForResponse(&requestFlags[1][MegaRequest::TYPE_GET_ATTR_USER], timeout) ) + ASSERT_TRUE( waitForResponse(&requestFlags[accountIndex][MegaRequest::TYPE_GET_ATTR_USER], timeout) ) << "User attribute retrieval not finished after " << timeout << " seconds"; - bool result = (lastError[1] == MegaError::API_OK) || (lastError[1] == MegaError::API_ENOENT); - ASSERT_TRUE(result) << "User attribute retrieval failed (error: " << lastError[1] << ")"; + bool result = (lastError[accountIndex] == MegaError::API_OK) || (lastError[accountIndex] == MegaError::API_ENOENT); + ASSERT_TRUE(result) << "User attribute retrieval failed (error: " << lastError[accountIndex] << ")"; } ///////////////////////////__ Tests using SdkTest __////////////////////////////////// @@ -1570,6 +1581,18 @@ TEST_F(SdkTest, SdkTestContacts) delete u; + + // --- Get language preference + + u = megaApi[0]->getMyUser(); + + string langCode = "es"; + ASSERT_NO_FATAL_FAILURE( setUserAttribute(MegaApi::USER_ATTR_LANGUAGE, langCode)); + ASSERT_NO_FATAL_FAILURE( getUserAttribute(u, MegaApi::USER_ATTR_LANGUAGE, maxTimeout, 0)); + string language = attributeValue; + ASSERT_TRUE(!strcmp(langCode.c_str(), language.c_str())) << "Language code is wrong"; + + // --- Load avatar --- userUpdated[1] = false; diff --git a/tests/sdk_test.h b/tests/sdk_test.h index 049fed4e6a..408bc1bd24 100644 --- a/tests/sdk_test.h +++ b/tests/sdk_test.h @@ -39,7 +39,7 @@ static const string USER_AGENT = "Unit Tests with GoogleTest framework"; // Set your login credentials as environment variables: $MEGA_EMAIL and $MEGA_PWD (and $MEGA_EMAIL_AUX / $MEGA_PWD_AUX for shares * contacts) static const unsigned int pollingT = 500000; // (microseconds) to check if response from server is received -static const unsigned int maxTimeout = 300; // Maximum time (seconds) to wait for response from server +static const unsigned int maxTimeout = 600; // Maximum time (seconds) to wait for response from server static const string PUBLICFILE = "file.txt"; static const string UPFILE = "file1.txt"; @@ -136,7 +136,7 @@ class SdkTest : public ::testing::Test, public MegaListener, MegaRequestListener void resumeSession(char *session, int timeout = maxTimeout); void purgeTree(MegaNode *p); - bool waitForResponse(bool *responseReceived, int timeout = maxTimeout); + bool waitForResponse(bool *responseReceived, unsigned int timeout = maxTimeout); void createFile(string filename, bool largeFile = true); size_t getFilesize(string filename); @@ -149,7 +149,7 @@ class SdkTest : public ::testing::Test, public MegaListener, MegaRequestListener void replyContact(MegaContactRequest *cr, int action, int timeout = maxTimeout); void removeContact(string email, int timeout = maxTimeout); void setUserAttribute(int type, string value, int timeout = maxTimeout); - void getUserAttribute(MegaUser *u, int type, int timeout = maxTimeout); + void getUserAttribute(MegaUser *u, int type, int timeout = maxTimeout, int accountIndex = 1); void shareFolder(MegaNode *n, const char *email, int action, int timeout = maxTimeout);